This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// components/Accordion.js
|
||||
import { h } from "sigpro";
|
||||
|
||||
export const Accordion = (props) => {
|
||||
export const Accordion = (props, children) => {
|
||||
const name = props.name || `accordion-${Math.random().toString(36).slice(2, 9)}`;
|
||||
|
||||
if (props.items && Array.isArray(props.items)) {
|
||||
@@ -9,7 +9,7 @@ export const Accordion = (props) => {
|
||||
props.items.map(item => h("div", { class: `collapse ${item.class ?? ''}` }, [
|
||||
h("input", { type: "radio", name, checked: item.open }),
|
||||
h("div", { class: "collapse-title text-xl font-medium" }, item.title),
|
||||
h("div", { class: "collapse-content" }, item.children)
|
||||
h("div", { class: "collapse-content" }, children)
|
||||
]))
|
||||
);
|
||||
}
|
||||
@@ -17,6 +17,6 @@ export const Accordion = (props) => {
|
||||
return h("div", { class: `collapse ${props.class ?? ''}` }, [
|
||||
h("input", { type: "radio", name, checked: props.open }),
|
||||
h("div", { class: "collapse-title text-xl font-medium" }, props.title),
|
||||
h("div", { class: "collapse-content" }, props.children)
|
||||
h("div", { class: "collapse-content" }, children)
|
||||
]);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
// components/Badge.js
|
||||
import { h } from "sigpro";
|
||||
|
||||
const colors = [""]
|
||||
export const Badge = (props, children) => {
|
||||
children === undefined && (children = props, props = {});
|
||||
return h("span", { ...props, class: `badge ${props.class ?? ''}` }, children);
|
||||
@@ -1,6 +1,6 @@
|
||||
// components/Datepicker.js
|
||||
import { $, h, when, watch } from "sigpro";
|
||||
import { Calendar } from "./calendar.js";
|
||||
import { Calendar } from "./Calendar.js";
|
||||
|
||||
export const Datepicker = (props) => {
|
||||
const isOpen = $(false);
|
||||
60
components/Input.js
Normal file
60
components/Input.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import { h, $, when, fx } from 'sigpro';
|
||||
import { get, cls, isFunc } from './_core.js';
|
||||
|
||||
export const Input = (props) => {
|
||||
const { label, icon, float, placeholder, value, left, right, content, ...rest } = props;
|
||||
|
||||
const showPassword = $(false);
|
||||
const isFocused = $(false);
|
||||
const isPassword = props.type === 'password';
|
||||
|
||||
const inputType = () => isPassword
|
||||
? (get(showPassword) ? 'text' : 'password')
|
||||
: (props.type || 'text');
|
||||
|
||||
return h("div", {
|
||||
class: "input-container",
|
||||
onfocusin: () => isFocused(true),
|
||||
onfocusout: (e) => {
|
||||
if (!e.currentTarget.contains(e.relatedTarget)) {
|
||||
isFocused(false);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
h('label', { class: "floating-label" }, [
|
||||
float ? h("span", {}, label) : null,
|
||||
h("label", {
|
||||
class: () => cls('input', props.class)
|
||||
}, [
|
||||
label && !float ? h('span', { class: 'label' }, label) : null,
|
||||
left ?? null,
|
||||
h('input', {
|
||||
...rest,
|
||||
type: inputType,
|
||||
class: 'grow',
|
||||
placeholder: placeholder || label || ' ',
|
||||
value: value
|
||||
}),
|
||||
right ?? null,
|
||||
|
||||
isPassword ? h('label', { class: 'swap swap-rotate ml-2' }, [
|
||||
h('input', {
|
||||
type: 'checkbox',
|
||||
onchange: (e) => showPassword(e.target.checked)
|
||||
}),
|
||||
h('span', { class: 'swap-on icon-[lucide--eye]' }),
|
||||
h('span', { class: 'swap-off icon-[lucide--eye-off]' })
|
||||
]) : null
|
||||
]),
|
||||
|
||||
when(isFocused, () => fx({ duration: 300, slide: true },
|
||||
h('div', {
|
||||
class: 'input-content',
|
||||
onmousedown: e => e.preventDefault()
|
||||
}, [
|
||||
isFunc(content) ? content(isFocused) : content
|
||||
])
|
||||
))
|
||||
])
|
||||
]);
|
||||
};
|
||||
58
components/InputBase.js
Normal file
58
components/InputBase.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import { h, $ } from 'sigpro.js';
|
||||
import { ui, cls, get } from './_core.js';
|
||||
|
||||
export const InputBase = ({
|
||||
loading = false,
|
||||
ui: uiOptions = '',
|
||||
class: className = '',
|
||||
type = 'text',
|
||||
value,
|
||||
onInput,
|
||||
...inputProps
|
||||
}) => {
|
||||
const isPassword = type === 'password';
|
||||
const showPassword = $(false);
|
||||
|
||||
const inputClasses = cls(
|
||||
ui('input', uiOptions),
|
||||
className,
|
||||
isPassword && 'pr-10',
|
||||
loading && 'loading loading-spinner loading-xs absolute right-2 top-1/2 -translate-y-1/2'
|
||||
);
|
||||
|
||||
let inputEl = h('input', {
|
||||
class: inputClasses + (isPassword ? ' pr-10' : ''),
|
||||
type: isPassword ? 'text' : 'password',
|
||||
value,
|
||||
oninput: onInput,
|
||||
...inputProps
|
||||
});
|
||||
|
||||
if (isPassword) {
|
||||
const toggle = h('label', {
|
||||
class: 'swap swap-rotate absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer'
|
||||
}, [
|
||||
h('input', {
|
||||
type: 'checkbox',
|
||||
checked: showPassword(),
|
||||
onchange: (e) => showPassword(e.target.checked)
|
||||
}),
|
||||
h('span', { class: 'swap-on icon-[lucide--eye]' }),
|
||||
h('span', { class: 'swap-off icon-[lucide--eye-off]' })
|
||||
]);
|
||||
inputEl = h('div', { class: 'relative w-full' }, [inputEl, toggle]);
|
||||
}
|
||||
|
||||
if (icon) {
|
||||
const isIconClass = icon.includes('-') || icon.includes('icon-');
|
||||
const iconElement = isIconClass
|
||||
? h('span', { class: icon })
|
||||
: h('span', { class: 'opacity-50' }, icon);
|
||||
content = h('label', { class: ui('input', uiOptions).replace('input-', '') }, [
|
||||
iconElement,
|
||||
h('span', { class: 'opacity-70' })
|
||||
]);
|
||||
}
|
||||
|
||||
return inputEl;
|
||||
};
|
||||
61
components/_core.js
Normal file
61
components/_core.js
Normal file
@@ -0,0 +1,61 @@
|
||||
// _core.js
|
||||
import { $, watch } from 'sigpro';
|
||||
|
||||
export const ui = (base, extras = '') => {
|
||||
if (!extras) return base;
|
||||
const extraClasses = extras
|
||||
.split(' ')
|
||||
.map(part => part.trim())
|
||||
.filter(Boolean)
|
||||
.map(part => part.startsWith(base + '-') ? part : `${base}-${part}`)
|
||||
.join(' ');
|
||||
return `${base} ${extraClasses}`.trim();
|
||||
};
|
||||
|
||||
export const get = val => typeof val === "function" ? val() : val;
|
||||
|
||||
export const filterBy = (items, query, field = 'label') => {
|
||||
const q = String(query).toLowerCase();
|
||||
if (!q) return get(items);
|
||||
return get(items).filter(item => {
|
||||
const text = typeof item === 'string' ? item : item[field];
|
||||
return String(text).toLowerCase().includes(q);
|
||||
});
|
||||
};
|
||||
|
||||
export const listKey = (items, isOpen) => {
|
||||
const cursor = $(-1);
|
||||
|
||||
watch([items, isOpen], () => {
|
||||
if (!get(isOpen)) cursor(-1);
|
||||
});
|
||||
|
||||
const onKey = (e, select) => {
|
||||
const list = get(items);
|
||||
if (!list.length) return;
|
||||
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
isOpen(true);
|
||||
cursor(Math.min(cursor() + 1, list.length - 1));
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
cursor(Math.max(cursor() - 1, 0));
|
||||
} else if (e.key === 'Enter' && cursor() >= 0) {
|
||||
e.preventDefault();
|
||||
select(list[cursor()]);
|
||||
} else if (e.key === 'Escape') {
|
||||
isOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
return { cursor, onKey };
|
||||
};
|
||||
|
||||
export const cls = (...classes) => classes.filter(Boolean).join(' ').trim();
|
||||
|
||||
export const getBy = (item, field = 'label') => {
|
||||
return typeof item === 'string' ? item : item[field];
|
||||
};
|
||||
|
||||
export const isFunc = f => typeof f === "function";
|
||||
@@ -3,4 +3,4 @@ import { h } from "sigpro";
|
||||
export const Button = (props, children) => {
|
||||
children === undefined && (children = props, props = {});
|
||||
return h("button", { ...props, class: `btn ${props.class ?? ''}` }, children);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// components/Input.js
|
||||
import { h } from "sigpro";
|
||||
|
||||
export const Input = (props) => h("input", { ...props, class: `input ${props.class ?? ''}` });
|
||||
|
||||
export const InputLabel = (props) => h("label", { class: `${props.float ? 'floating-label' : 'input'}` },
|
||||
[
|
||||
h("span", { class: props.float ? '' : 'label opacity-50' }, props.label),
|
||||
props.left ?? null,
|
||||
h("input", { ...props, class: `${props.float ? 'input' : ''} ${props.class ?? ''}` }),
|
||||
props.right ?? null
|
||||
]
|
||||
);
|
||||
Reference in New Issue
Block a user