@simplysm/solid 13.0.84 → 13.0.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
- package/dist/components/data/sheet/DataSheet.js +6 -9
- package/dist/components/data/sheet/DataSheet.js.map +2 -2
- package/dist/components/data/sheet/hooks/createDataSheetExpansion.d.ts.map +1 -1
- package/dist/components/data/sheet/hooks/createDataSheetExpansion.js +15 -17
- package/dist/components/data/sheet/hooks/createDataSheetExpansion.js.map +1 -1
- package/dist/components/data/sheet/hooks/createDataSheetReorder.d.ts.map +1 -1
- package/dist/components/data/sheet/hooks/createDataSheetReorder.js +12 -12
- package/dist/components/data/sheet/hooks/createDataSheetReorder.js.map +1 -1
- package/dist/components/data/sheet/hooks/createDataSheetSelection.d.ts.map +1 -1
- package/dist/components/data/sheet/hooks/createDataSheetSelection.js +9 -3
- package/dist/components/data/sheet/hooks/createDataSheetSelection.js.map +1 -1
- package/dist/components/disclosure/Dialog.d.ts.map +1 -1
- package/dist/components/disclosure/Dialog.js +3 -21
- package/dist/components/disclosure/Dialog.js.map +2 -2
- package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
- package/dist/components/disclosure/Dropdown.js +1 -11
- package/dist/components/disclosure/Dropdown.js.map +2 -2
- package/dist/components/disclosure/Tabs.d.ts.map +1 -1
- package/dist/components/disclosure/Tabs.js +1 -3
- package/dist/components/disclosure/Tabs.js.map +2 -2
- package/dist/components/features/crud-detail/CrudDetail.js +103 -102
- package/dist/components/features/crud-detail/CrudDetail.js.map +2 -2
- package/dist/components/features/crud-sheet/CrudSheet.d.ts.map +1 -1
- package/dist/components/features/crud-sheet/CrudSheet.js +3 -5
- package/dist/components/features/crud-sheet/CrudSheet.js.map +1 -1
- package/dist/components/feedback/busy/BusyContainer.d.ts.map +1 -1
- package/dist/components/feedback/busy/BusyContainer.js +1 -6
- package/dist/components/feedback/busy/BusyContainer.js.map +2 -2
- package/dist/components/form-control/checkbox/SelectableBase.d.ts.map +1 -1
- package/dist/components/form-control/checkbox/SelectableBase.js +2 -4
- package/dist/components/form-control/checkbox/SelectableBase.js.map +2 -2
- package/dist/components/form-control/date-range-picker/DateRangePicker.d.ts.map +1 -1
- package/dist/components/form-control/date-range-picker/DateRangePicker.js +1 -2
- package/dist/components/form-control/date-range-picker/DateRangePicker.js.map +2 -2
- package/dist/components/form-control/editor/RichTextEditor.d.ts.map +1 -1
- package/dist/components/form-control/editor/RichTextEditor.js +2 -4
- package/dist/components/form-control/editor/RichTextEditor.js.map +2 -2
- package/dist/components/form-control/field/NumberInput.d.ts.map +1 -1
- package/dist/components/form-control/field/NumberInput.js +7 -7
- package/dist/components/form-control/field/NumberInput.js.map +2 -2
- package/dist/components/form-control/field/Textarea.d.ts.map +1 -1
- package/dist/components/form-control/field/Textarea.js +1 -3
- package/dist/components/form-control/field/Textarea.js.map +2 -2
- package/dist/components/form-control/select/Select.d.ts +2 -0
- package/dist/components/form-control/select/Select.d.ts.map +1 -1
- package/dist/components/form-control/select/Select.js +11 -10
- package/dist/components/form-control/select/Select.js.map +2 -2
- package/dist/components/form-control/state-preset/StatePreset.d.ts.map +1 -1
- package/dist/components/form-control/state-preset/StatePreset.js +3 -7
- package/dist/components/form-control/state-preset/StatePreset.js.map +2 -2
- package/dist/components/layout/topbar/Topbar.js +1 -3
- package/dist/components/layout/topbar/Topbar.js.map +2 -2
- package/dist/hooks/createControllableStore.d.ts.map +1 -1
- package/dist/hooks/createControllableStore.js +8 -5
- package/dist/hooks/createControllableStore.js.map +1 -1
- package/dist/hooks/useLocalStorage.d.ts.map +1 -1
- package/dist/hooks/useLocalStorage.js +3 -2
- package/dist/hooks/useLocalStorage.js.map +1 -1
- package/dist/hooks/useSyncConfig.d.ts.map +1 -1
- package/dist/hooks/useSyncConfig.js +5 -4
- package/dist/hooks/useSyncConfig.js.map +1 -1
- package/dist/providers/shared-data/SharedDataProvider.d.ts.map +1 -1
- package/dist/providers/shared-data/SharedDataProvider.js +0 -1
- package/dist/providers/shared-data/SharedDataProvider.js.map +1 -1
- package/package.json +5 -5
- package/src/components/data/sheet/DataSheet.tsx +6 -10
- package/src/components/data/sheet/hooks/createDataSheetExpansion.ts +17 -18
- package/src/components/data/sheet/hooks/createDataSheetReorder.ts +12 -13
- package/src/components/data/sheet/hooks/createDataSheetSelection.ts +9 -3
- package/src/components/disclosure/Dialog.tsx +45 -59
- package/src/components/disclosure/Dropdown.tsx +4 -14
- package/src/components/disclosure/Tabs.tsx +12 -17
- package/src/components/features/crud-detail/CrudDetail.tsx +4 -4
- package/src/components/features/crud-sheet/CrudSheet.tsx +4 -5
- package/src/components/feedback/busy/BusyContainer.tsx +12 -18
- package/src/components/form-control/checkbox/SelectableBase.tsx +10 -16
- package/src/components/form-control/date-range-picker/DateRangePicker.tsx +1 -4
- package/src/components/form-control/editor/RichTextEditor.tsx +11 -12
- package/src/components/form-control/field/NumberInput.tsx +6 -8
- package/src/components/form-control/field/Textarea.tsx +11 -10
- package/src/components/form-control/select/Select.tsx +23 -9
- package/src/components/form-control/state-preset/StatePreset.tsx +15 -22
- package/src/components/layout/topbar/Topbar.tsx +2 -2
- package/src/hooks/createControllableStore.ts +8 -4
- package/src/hooks/useLocalStorage.ts +3 -2
- package/src/hooks/useSyncConfig.ts +5 -4
- package/src/providers/shared-data/SharedDataProvider.tsx +0 -1
- package/tests/components/features/crud-detail/CrudDetail.spec.tsx +49 -0
- package/tests/components/form-control/select/SelectItem.spec.tsx +5 -0
- package/tests/providers/shared-data/SharedDataProvider.spec.tsx +0 -104
|
@@ -368,7 +368,6 @@ const DataSheetInner = <TItem,>(props: DataSheetProps<TItem>) => {
|
|
|
368
368
|
);
|
|
369
369
|
|
|
370
370
|
// #region Display
|
|
371
|
-
const displayItems = flatItems;
|
|
372
371
|
|
|
373
372
|
// #region Selection
|
|
374
373
|
const {
|
|
@@ -387,7 +386,7 @@ const DataSheetInner = <TItem,>(props: DataSheetProps<TItem>) => {
|
|
|
387
386
|
get onSelectionChange() { return local.onSelectionChange; },
|
|
388
387
|
get isItemSelectable() { return local.isItemSelectable; },
|
|
389
388
|
},
|
|
390
|
-
|
|
389
|
+
flatItems,
|
|
391
390
|
);
|
|
392
391
|
|
|
393
392
|
// #region AutoSelect
|
|
@@ -408,7 +407,7 @@ const DataSheetInner = <TItem,>(props: DataSheetProps<TItem>) => {
|
|
|
408
407
|
get onItemsReorder() { return local.onItemsReorder; },
|
|
409
408
|
get itemChildren() { return local.itemChildren; },
|
|
410
409
|
},
|
|
411
|
-
|
|
410
|
+
flatItems,
|
|
412
411
|
);
|
|
413
412
|
|
|
414
413
|
// #region Keyboard Navigation (move rows with Enter/Shift+Enter)
|
|
@@ -428,11 +427,8 @@ const DataSheetInner = <TItem,>(props: DataSheetProps<TItem>) => {
|
|
|
428
427
|
if (!tbody) return;
|
|
429
428
|
|
|
430
429
|
const rows = tbody.rows;
|
|
431
|
-
const rowIndex =
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const cellIndex = Array.from(tr.cells).indexOf(td);
|
|
435
|
-
if (cellIndex < 0) return;
|
|
430
|
+
const rowIndex = tr.sectionRowIndex;
|
|
431
|
+
const cellIndex = td.cellIndex;
|
|
436
432
|
|
|
437
433
|
const targetRowIndex = e.shiftKey ? rowIndex - 1 : rowIndex + 1;
|
|
438
434
|
if (targetRowIndex < 0 || targetRowIndex >= rows.length) return;
|
|
@@ -784,7 +780,7 @@ const DataSheetInner = <TItem,>(props: DataSheetProps<TItem>) => {
|
|
|
784
780
|
<div class={featureCellClickableClass} onClick={() => toggleSelectAll()}>
|
|
785
781
|
<Checkbox
|
|
786
782
|
checked={(() => {
|
|
787
|
-
const selectableItems =
|
|
783
|
+
const selectableItems = flatItems()
|
|
788
784
|
.map((flat) => flat.item)
|
|
789
785
|
.filter((item) => getItemSelectable(item) === true);
|
|
790
786
|
return (
|
|
@@ -829,7 +825,7 @@ const DataSheetInner = <TItem,>(props: DataSheetProps<TItem>) => {
|
|
|
829
825
|
{renderSummaryRow()}
|
|
830
826
|
</thead>
|
|
831
827
|
<tbody>
|
|
832
|
-
<For each={
|
|
828
|
+
<For each={flatItems()}>
|
|
833
829
|
{(flat) => (
|
|
834
830
|
<tr
|
|
835
831
|
data-selected={selection().includes(flat.item) ? "" : undefined}
|
|
@@ -37,20 +37,6 @@ export function createDataSheetExpansion<TItem>(
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
function toggleExpandAll(): void {
|
|
41
|
-
if (!props.itemChildren) return;
|
|
42
|
-
const indexMap = originalIndexMap();
|
|
43
|
-
const allExpandable = collectAllExpandable(
|
|
44
|
-
pagedItems(),
|
|
45
|
-
props.itemChildren,
|
|
46
|
-
(item) => indexMap.get(item) ?? -1,
|
|
47
|
-
);
|
|
48
|
-
const isAllCurrentlyExpanded = allExpandable.every((item) =>
|
|
49
|
-
expandedItems().includes(item),
|
|
50
|
-
);
|
|
51
|
-
setExpandedItems(isAllCurrentlyExpanded ? [] : allExpandable);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
40
|
const flatItems = createMemo((): FlatItem<TItem>[] => {
|
|
55
41
|
const indexMap = originalIndexMap();
|
|
56
42
|
return flattenTree(
|
|
@@ -61,16 +47,29 @@ export function createDataSheetExpansion<TItem>(
|
|
|
61
47
|
);
|
|
62
48
|
});
|
|
63
49
|
|
|
64
|
-
const
|
|
65
|
-
if (!props.itemChildren) return
|
|
50
|
+
const allExpandable = createMemo(() => {
|
|
51
|
+
if (!props.itemChildren) return [];
|
|
66
52
|
const indexMap = originalIndexMap();
|
|
67
|
-
|
|
53
|
+
return collectAllExpandable(
|
|
68
54
|
pagedItems(),
|
|
69
55
|
props.itemChildren,
|
|
70
56
|
(item) => indexMap.get(item) ?? -1,
|
|
71
57
|
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
function toggleExpandAll(): void {
|
|
61
|
+
const items = allExpandable();
|
|
62
|
+
if (items.length === 0) return;
|
|
63
|
+
const isAllCurrentlyExpanded = items.every((item) =>
|
|
64
|
+
expandedItems().includes(item),
|
|
65
|
+
);
|
|
66
|
+
setExpandedItems(isAllCurrentlyExpanded ? [] : items);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const isAllExpanded = createMemo(() => {
|
|
70
|
+
const items = allExpandable();
|
|
72
71
|
return (
|
|
73
|
-
|
|
72
|
+
items.length > 0 && items.every((item) => expandedItems().includes(item))
|
|
74
73
|
);
|
|
75
74
|
});
|
|
76
75
|
|
|
@@ -37,11 +37,13 @@ export function createDataSheetReorder<TItem>(
|
|
|
37
37
|
const tableEl = target.closest("table")!;
|
|
38
38
|
const tbody = tableEl.querySelector("tbody")!;
|
|
39
39
|
const rows = Array.from(tbody.rows);
|
|
40
|
+
const scrollContainer = tableEl.closest<HTMLElement>("[data-sheet-scroll]");
|
|
40
41
|
|
|
41
42
|
setDragState({ draggingItem: item, targetItem: null, position: null });
|
|
42
43
|
|
|
43
44
|
startPointerDrag(target, e.pointerId, {
|
|
44
45
|
onMove(ev) {
|
|
46
|
+
const items = displayItems();
|
|
45
47
|
let foundTarget: TItem | null = null;
|
|
46
48
|
let foundPosition: "before" | "after" | "inside" | null = null;
|
|
47
49
|
|
|
@@ -50,8 +52,8 @@ export function createDataSheetReorder<TItem>(
|
|
|
50
52
|
const rect = row.getBoundingClientRect();
|
|
51
53
|
if (ev.clientY < rect.top || ev.clientY > rect.bottom) continue;
|
|
52
54
|
|
|
53
|
-
if (i >=
|
|
54
|
-
const flat =
|
|
55
|
+
if (i >= items.length) break;
|
|
56
|
+
const flat = items[i];
|
|
55
57
|
if (flat.item === item) break;
|
|
56
58
|
|
|
57
59
|
// Cannot drop to child items of self
|
|
@@ -82,8 +84,8 @@ export function createDataSheetReorder<TItem>(
|
|
|
82
84
|
rows[i].removeAttribute("data-dragging");
|
|
83
85
|
rows[i].removeAttribute("data-drag-over");
|
|
84
86
|
|
|
85
|
-
if (i <
|
|
86
|
-
const flat =
|
|
87
|
+
if (i < items.length) {
|
|
88
|
+
const flat = items[i];
|
|
87
89
|
if (flat.item === item) {
|
|
88
90
|
rows[i].setAttribute("data-dragging", "");
|
|
89
91
|
}
|
|
@@ -94,22 +96,20 @@ export function createDataSheetReorder<TItem>(
|
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
// before/after indicator
|
|
97
|
-
const indicatorEl =
|
|
98
|
-
.closest("[data-sheet-scroll]")
|
|
99
|
+
const indicatorEl = scrollContainer
|
|
99
100
|
?.querySelector("[data-reorder-indicator]") as HTMLElement | null;
|
|
100
101
|
if (indicatorEl) {
|
|
101
102
|
if (foundTarget != null && foundPosition != null && foundPosition !== "inside") {
|
|
102
|
-
const targetIdx =
|
|
103
|
+
const targetIdx = items.findIndex((f) => f.item === foundTarget);
|
|
103
104
|
if (targetIdx >= 0) {
|
|
104
105
|
const targetRow = rows[targetIdx];
|
|
105
|
-
const containerRect =
|
|
106
|
+
const containerRect = scrollContainer!.getBoundingClientRect();
|
|
106
107
|
const rowRect = targetRow.getBoundingClientRect();
|
|
107
|
-
const scrollEl = tableEl.closest("[data-sheet-scroll]") as HTMLElement;
|
|
108
108
|
|
|
109
109
|
const top =
|
|
110
110
|
foundPosition === "before"
|
|
111
|
-
? rowRect.top - containerRect.top +
|
|
112
|
-
: rowRect.bottom - containerRect.top +
|
|
111
|
+
? rowRect.top - containerRect.top + scrollContainer!.scrollTop
|
|
112
|
+
: rowRect.bottom - containerRect.top + scrollContainer!.scrollTop;
|
|
113
113
|
|
|
114
114
|
indicatorEl.style.display = "block";
|
|
115
115
|
indicatorEl.style.top = `${top}px`;
|
|
@@ -134,8 +134,7 @@ export function createDataSheetReorder<TItem>(
|
|
|
134
134
|
row.removeAttribute("data-dragging");
|
|
135
135
|
row.removeAttribute("data-drag-over");
|
|
136
136
|
}
|
|
137
|
-
const indicatorEl =
|
|
138
|
-
.closest("[data-sheet-scroll]")
|
|
137
|
+
const indicatorEl = scrollContainer
|
|
139
138
|
?.querySelector("[data-reorder-indicator]") as HTMLElement | null;
|
|
140
139
|
if (indicatorEl) {
|
|
141
140
|
indicatorEl.style.display = "none";
|
|
@@ -57,7 +57,8 @@ export function createDataSheetSelection<TItem>(
|
|
|
57
57
|
const selectableItems = displayItems()
|
|
58
58
|
.map((flat) => flat.item)
|
|
59
59
|
.filter((item) => getItemSelectable(item) === true);
|
|
60
|
-
const
|
|
60
|
+
const selectionSet = new Set(selection());
|
|
61
|
+
const isAllSelected = selectableItems.every((item) => selectionSet.has(item));
|
|
61
62
|
setSelection(isAllSelected ? [] : selectableItems);
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -74,13 +75,18 @@ export function createDataSheetSelection<TItem>(
|
|
|
74
75
|
.filter((item) => getItemSelectable(item) === true);
|
|
75
76
|
|
|
76
77
|
if (lastClickAction() === "select") {
|
|
78
|
+
const selectionSet = new Set(selection());
|
|
77
79
|
const newItems = [...selection()];
|
|
78
80
|
for (const item of rangeItems) {
|
|
79
|
-
if (!
|
|
81
|
+
if (!selectionSet.has(item)) {
|
|
82
|
+
newItems.push(item);
|
|
83
|
+
selectionSet.add(item);
|
|
84
|
+
}
|
|
80
85
|
}
|
|
81
86
|
setSelection(newItems);
|
|
82
87
|
} else {
|
|
83
|
-
|
|
88
|
+
const rangeSet = new Set(rangeItems);
|
|
89
|
+
setSelection(selection().filter((item) => !rangeSet.has(item)));
|
|
84
90
|
}
|
|
85
91
|
}
|
|
86
92
|
|
|
@@ -478,70 +478,38 @@ const DialogInner: ParentComponent<DialogProps> = (props) => {
|
|
|
478
478
|
return style;
|
|
479
479
|
};
|
|
480
480
|
|
|
481
|
-
// Animation class
|
|
482
|
-
const animationClass = () => {
|
|
483
|
-
const base = clsx("transition-[opacity,transform]", "duration-200", "ease-out");
|
|
484
|
-
if (animating()) {
|
|
485
|
-
return clsx(base, "translate-y-0 opacity-100");
|
|
486
|
-
} else {
|
|
487
|
-
return clsx(base, "-translate-y-4 opacity-0");
|
|
488
|
-
}
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
// Wrapper class
|
|
492
|
-
const wrapperClass = () =>
|
|
493
|
-
// eslint-disable-next-line tailwindcss/enforces-shorthand -- inset-0 not supported in Chrome 84
|
|
494
|
-
clsx(
|
|
495
|
-
"fixed bottom-0 left-0 right-0 top-0",
|
|
496
|
-
"flex flex-col items-center",
|
|
497
|
-
local.mode !== "fill" && "pt-[calc(3rem+0.5rem)]",
|
|
498
|
-
local.mode === "float" && "pointer-events-none",
|
|
499
|
-
);
|
|
500
|
-
|
|
501
|
-
// Backdrop class
|
|
502
|
-
const backdropClass = () =>
|
|
503
|
-
// eslint-disable-next-line tailwindcss/enforces-shorthand -- inset-0 not supported in Chrome 84
|
|
504
|
-
clsx(
|
|
505
|
-
"absolute bottom-0 left-0 right-0 top-0",
|
|
506
|
-
"bg-black/30",
|
|
507
|
-
"dark:bg-black/50",
|
|
508
|
-
"transition-opacity",
|
|
509
|
-
"duration-200",
|
|
510
|
-
"ease-out",
|
|
511
|
-
animating() ? "opacity-100" : "opacity-0",
|
|
512
|
-
);
|
|
513
|
-
|
|
514
|
-
// Dialog class
|
|
515
|
-
const dialogBaseClass = () =>
|
|
516
|
-
clsx(
|
|
517
|
-
"relative",
|
|
518
|
-
"mx-auto",
|
|
519
|
-
"w-fit min-w-[200px]",
|
|
520
|
-
bg.surface,
|
|
521
|
-
local.mode === "float"
|
|
522
|
-
? clsx("shadow-md dark:shadow-black/30", "border", border.subtle)
|
|
523
|
-
: "shadow-2xl dark:shadow-black/40",
|
|
524
|
-
local.mode === "fill" ? "rounded-none border-none" : "rounded-lg",
|
|
525
|
-
"overflow-hidden",
|
|
526
|
-
"flex flex-col",
|
|
527
|
-
"focus:outline-none",
|
|
528
|
-
local.mode === "float" && "pointer-events-auto",
|
|
529
|
-
animationClass(),
|
|
530
|
-
);
|
|
531
|
-
|
|
532
|
-
// Header class
|
|
533
|
-
const headerClass = () =>
|
|
534
|
-
clsx("flex items-center gap-2", "px-3 py-1", "select-none", "border-b", border.subtle);
|
|
535
|
-
|
|
536
481
|
return (
|
|
537
482
|
<Show when={mounted()}>
|
|
538
483
|
<Portal>
|
|
539
484
|
<HeaderProvider>
|
|
540
485
|
<ActionProvider>
|
|
541
|
-
<div
|
|
486
|
+
<div
|
|
487
|
+
ref={setWrapperRef}
|
|
488
|
+
data-dialog
|
|
489
|
+
// eslint-disable-next-line tailwindcss/enforces-shorthand -- inset-0 not supported in Chrome 84
|
|
490
|
+
class={clsx(
|
|
491
|
+
"fixed bottom-0 left-0 right-0 top-0",
|
|
492
|
+
"flex flex-col items-center",
|
|
493
|
+
local.mode !== "fill" && "pt-[calc(3rem+0.5rem)]",
|
|
494
|
+
local.mode === "float" && "pointer-events-none",
|
|
495
|
+
)}
|
|
496
|
+
>
|
|
542
497
|
{/* Backdrop */}
|
|
543
498
|
<Show when={local.mode !== "float"}>
|
|
544
|
-
<div
|
|
499
|
+
<div
|
|
500
|
+
data-dialog-backdrop
|
|
501
|
+
// eslint-disable-next-line tailwindcss/enforces-shorthand -- inset-0 not supported in Chrome 84
|
|
502
|
+
class={clsx(
|
|
503
|
+
"absolute bottom-0 left-0 right-0 top-0",
|
|
504
|
+
"bg-black/30",
|
|
505
|
+
"dark:bg-black/50",
|
|
506
|
+
"transition-opacity",
|
|
507
|
+
"duration-200",
|
|
508
|
+
"ease-out",
|
|
509
|
+
animating() ? "opacity-100" : "opacity-0",
|
|
510
|
+
)}
|
|
511
|
+
onClick={handleBackdropClick}
|
|
512
|
+
/>
|
|
545
513
|
</Show>
|
|
546
514
|
|
|
547
515
|
{/* Dialog */}
|
|
@@ -554,7 +522,25 @@ const DialogInner: ParentComponent<DialogProps> = (props) => {
|
|
|
554
522
|
aria-modal={local.mode === "float" ? undefined : true}
|
|
555
523
|
aria-labelledby={hasHeader() ? headerId : undefined}
|
|
556
524
|
tabIndex={0}
|
|
557
|
-
class={twMerge(
|
|
525
|
+
class={twMerge(
|
|
526
|
+
clsx(
|
|
527
|
+
"relative",
|
|
528
|
+
"mx-auto",
|
|
529
|
+
"w-fit min-w-[200px]",
|
|
530
|
+
bg.surface,
|
|
531
|
+
local.mode === "float"
|
|
532
|
+
? clsx("shadow-md dark:shadow-black/30", "border", border.subtle)
|
|
533
|
+
: "shadow-2xl dark:shadow-black/40",
|
|
534
|
+
local.mode === "fill" ? "rounded-none border-none" : "rounded-lg",
|
|
535
|
+
"overflow-hidden",
|
|
536
|
+
"flex flex-col",
|
|
537
|
+
"focus:outline-none",
|
|
538
|
+
local.mode === "float" && "pointer-events-auto",
|
|
539
|
+
"transition-[opacity,transform] duration-200 ease-out",
|
|
540
|
+
animating() ? "translate-y-0 opacity-100" : "-translate-y-4 opacity-0",
|
|
541
|
+
),
|
|
542
|
+
local.class,
|
|
543
|
+
)}
|
|
558
544
|
style={dialogStyle()}
|
|
559
545
|
onFocus={handleDialogFocus}
|
|
560
546
|
onTransitionEnd={handleTransitionEnd}
|
|
@@ -563,7 +549,7 @@ const DialogInner: ParentComponent<DialogProps> = (props) => {
|
|
|
563
549
|
<Show when={hasHeader()}>
|
|
564
550
|
<div
|
|
565
551
|
data-dialog-header
|
|
566
|
-
class={clsx(
|
|
552
|
+
class={clsx("flex items-center gap-2", "px-3 py-1", "select-none", "border-b", border.subtle, "touch-none")}
|
|
567
553
|
style={
|
|
568
554
|
typeof local.headerStyle === "string"
|
|
569
555
|
? mergeStyles(local.headerStyle)
|
|
@@ -402,19 +402,6 @@ const DropdownInner: ParentComponent<DropdownProps> = (props: DropdownProps) =>
|
|
|
402
402
|
|
|
403
403
|
const maxHeight = () => local.maxHeight ?? 300;
|
|
404
404
|
|
|
405
|
-
// Animation class (only transition opacity and transform, not position properties)
|
|
406
|
-
const animationClass = () => {
|
|
407
|
-
const base = "transition-[opacity,transform] duration-150 ease-out";
|
|
408
|
-
const visible = animating();
|
|
409
|
-
const dir = direction();
|
|
410
|
-
|
|
411
|
-
if (visible) {
|
|
412
|
-
return clsx(base, "translate-y-0 opacity-100");
|
|
413
|
-
} else {
|
|
414
|
-
return clsx(base, "opacity-0", dir === "down" ? "-translate-y-1" : "translate-y-1");
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
|
|
418
405
|
return (
|
|
419
406
|
<TriggerProvider>
|
|
420
407
|
<ContentProvider>
|
|
@@ -452,7 +439,10 @@ const DropdownInner: ParentComponent<DropdownProps> = (props: DropdownProps) =>
|
|
|
452
439
|
"shadow-lg dark:shadow-black/30",
|
|
453
440
|
"rounded-md",
|
|
454
441
|
"overflow-y-auto",
|
|
455
|
-
|
|
442
|
+
"transition-[opacity,transform] duration-150 ease-out",
|
|
443
|
+
animating()
|
|
444
|
+
? "translate-y-0 opacity-100"
|
|
445
|
+
: clsx("opacity-0", direction() === "down" ? "-translate-y-1" : "translate-y-1"),
|
|
456
446
|
),
|
|
457
447
|
local.class,
|
|
458
448
|
)}
|
|
@@ -39,21 +39,6 @@ function TabsTabInner(props: TabsTabProps) {
|
|
|
39
39
|
xl: "px-5 py-3 text-lg",
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
const sizeClasses = () => tabSizeClasses[ctx.size() ?? "md"];
|
|
43
|
-
|
|
44
|
-
const stateClass = () =>
|
|
45
|
-
isSelected()
|
|
46
|
-
? clsx(
|
|
47
|
-
"border-b-2 border-primary-500 dark:border-primary-400",
|
|
48
|
-
themeTokens.primary.text,
|
|
49
|
-
)
|
|
50
|
-
: clsx(
|
|
51
|
-
"border-b-2 border-transparent",
|
|
52
|
-
text.muted,
|
|
53
|
-
"hover:border-base-300 hover:text-base-700",
|
|
54
|
-
"dark:hover:border-base-600 dark:hover:text-base-200",
|
|
55
|
-
);
|
|
56
|
-
|
|
57
42
|
return (
|
|
58
43
|
<button
|
|
59
44
|
type="button"
|
|
@@ -63,8 +48,18 @@ function TabsTabInner(props: TabsTabProps) {
|
|
|
63
48
|
tabIndex={props.disabled ? -1 : 0}
|
|
64
49
|
class={twMerge(
|
|
65
50
|
"relative cursor-pointer select-none font-medium transition-colors -mb-px",
|
|
66
|
-
|
|
67
|
-
|
|
51
|
+
tabSizeClasses[ctx.size() ?? "md"],
|
|
52
|
+
isSelected()
|
|
53
|
+
? clsx(
|
|
54
|
+
"border-b-2 border-primary-500 dark:border-primary-400",
|
|
55
|
+
themeTokens.primary.text,
|
|
56
|
+
)
|
|
57
|
+
: clsx(
|
|
58
|
+
"border-b-2 border-transparent",
|
|
59
|
+
text.muted,
|
|
60
|
+
"hover:border-base-300 hover:text-base-700",
|
|
61
|
+
"dark:hover:border-base-600 dark:hover:text-base-200",
|
|
62
|
+
),
|
|
68
63
|
props.disabled && "opacity-50 pointer-events-none",
|
|
69
64
|
props.class,
|
|
70
65
|
)}
|
|
@@ -201,7 +201,6 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
|
|
|
201
201
|
<>
|
|
202
202
|
<Show when={showSave()}>
|
|
203
203
|
<Button
|
|
204
|
-
size="lg"
|
|
205
204
|
variant="ghost"
|
|
206
205
|
theme="primary"
|
|
207
206
|
onClick={() => formRef?.requestSubmit()}
|
|
@@ -213,7 +212,6 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
|
|
|
213
212
|
<Show when={showDelete()}>
|
|
214
213
|
{(_) => (
|
|
215
214
|
<Button
|
|
216
|
-
size="lg"
|
|
217
215
|
variant="ghost"
|
|
218
216
|
theme="danger"
|
|
219
217
|
onClick={() => void handleToggleDelete()}
|
|
@@ -223,7 +221,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
|
|
|
223
221
|
</Button>
|
|
224
222
|
)}
|
|
225
223
|
</Show>
|
|
226
|
-
<Button
|
|
224
|
+
<Button variant="ghost" theme="info" onClick={() => void handleRefresh()}>
|
|
227
225
|
<Icon icon={IconRefresh} class="mr-1" />
|
|
228
226
|
{i18n.t("crudDetail.refresh")}
|
|
229
227
|
</Button>
|
|
@@ -259,8 +257,9 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
|
|
|
259
257
|
<BusyContainer
|
|
260
258
|
ready={ready()}
|
|
261
259
|
busy={busyCount() > 0}
|
|
262
|
-
class={clsx("flex h-full flex-col
|
|
260
|
+
class={clsx("flex h-full flex-col", local.class)}
|
|
263
261
|
>
|
|
262
|
+
<div class="flex min-h-0 flex-1 flex-col gap-2">
|
|
264
263
|
{/* Toolbar */}
|
|
265
264
|
<Show when={(!isInDialog && !topbarCtx) || tools()}>
|
|
266
265
|
<div class="flex gap-2 pb-0">
|
|
@@ -318,6 +317,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
|
|
|
318
317
|
|
|
319
318
|
{/* After (outside form) */}
|
|
320
319
|
<Show when={after()}>{(afterSlot) => afterSlot().children}</Show>
|
|
320
|
+
</div>
|
|
321
321
|
|
|
322
322
|
{/* Dialog mode: bottom bar */}
|
|
323
323
|
<Show when={isInDialog && canEdit()}>
|
|
@@ -369,13 +369,13 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, unknown>>(
|
|
|
369
369
|
|
|
370
370
|
// -- Keyboard Shortcuts --
|
|
371
371
|
createEventListener(document, "keydown", async (e: KeyboardEvent) => {
|
|
372
|
-
if (!isActiveCrud(crudId)) return;
|
|
373
|
-
if (e.
|
|
372
|
+
if (!e.ctrlKey || !isActiveCrud(crudId)) return;
|
|
373
|
+
if (e.key === "s" && !isSelectMode()) {
|
|
374
374
|
e.preventDefault();
|
|
375
375
|
e.stopImmediatePropagation();
|
|
376
376
|
formRef?.requestSubmit();
|
|
377
377
|
}
|
|
378
|
-
if (e.
|
|
378
|
+
if (e.altKey && e.key === "l") {
|
|
379
379
|
e.preventDefault();
|
|
380
380
|
e.stopImmediatePropagation();
|
|
381
381
|
if (!checkIgnoreChanges()) return;
|
|
@@ -402,7 +402,6 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, unknown>>(
|
|
|
402
402
|
<>
|
|
403
403
|
<Show when={canEdit() && local.inlineEdit}>
|
|
404
404
|
<Button
|
|
405
|
-
size="lg"
|
|
406
405
|
variant="ghost"
|
|
407
406
|
theme="primary"
|
|
408
407
|
onClick={() => formRef?.requestSubmit()}
|
|
@@ -411,7 +410,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, unknown>>(
|
|
|
411
410
|
{i18n.t("crudSheet.save")}
|
|
412
411
|
</Button>
|
|
413
412
|
</Show>
|
|
414
|
-
<Button
|
|
413
|
+
<Button variant="ghost" theme="info" onClick={handleRefresh}>
|
|
415
414
|
<Icon icon={IconRefresh} class="mr-1" />
|
|
416
415
|
{i18n.t("crudSheet.refresh")}
|
|
417
416
|
</Button>
|
|
@@ -72,27 +72,21 @@ export const BusyContainer: ParentComponent<BusyContainerProps> = (props) => {
|
|
|
72
72
|
);
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
const screenClass = () =>
|
|
77
|
-
clsx(
|
|
78
|
-
"absolute inset-0 z-busy bg-white/70 transition-opacity duration-150 dark:bg-base-900/70",
|
|
79
|
-
animating() ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0",
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
// spinner: slide down animation
|
|
83
|
-
const rectClass = () => {
|
|
84
|
-
if (currVariant() !== "spinner") return "";
|
|
85
|
-
return clsx(
|
|
86
|
-
"transition-transform duration-100",
|
|
87
|
-
animating() ? "translate-y-0 ease-out" : "-translate-y-full ease-in",
|
|
88
|
-
);
|
|
89
|
-
};
|
|
90
|
-
|
|
91
75
|
return (
|
|
92
76
|
<div ref={containerRef} class={twMerge("relative size-full min-h-[70px] min-w-[70px] overflow-auto", local.class)} {...rest}>
|
|
93
77
|
<Show when={mounted()}>
|
|
94
|
-
<div
|
|
95
|
-
|
|
78
|
+
<div
|
|
79
|
+
class={clsx(
|
|
80
|
+
"absolute inset-0 z-busy bg-white/70 transition-opacity duration-150 dark:bg-base-900/70",
|
|
81
|
+
animating() ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0",
|
|
82
|
+
)}
|
|
83
|
+
onTransitionEnd={handleTransitionEnd}
|
|
84
|
+
>
|
|
85
|
+
<div
|
|
86
|
+
class={currVariant() === "spinner"
|
|
87
|
+
? clsx("transition-transform duration-100", animating() ? "translate-y-0 ease-out" : "-translate-y-full ease-in")
|
|
88
|
+
: ""}
|
|
89
|
+
>
|
|
96
90
|
<Show when={currVariant() === "spinner"}>
|
|
97
91
|
<div class="mx-auto mt-5 size-8 animate-spin rounded-full border-[6px] border-base-200 border-b-primary-500 shadow-md dark:border-base-700 dark:border-b-primary-400" />
|
|
98
92
|
</Show>
|
|
@@ -76,20 +76,6 @@ export const SelectableBase: ParentComponent<SelectableBaseProps & { config: Sel
|
|
|
76
76
|
}
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
-
const getWrapperClass = () =>
|
|
80
|
-
twMerge(
|
|
81
|
-
checkboxBaseClass,
|
|
82
|
-
checkboxSizeClasses[local.size ?? "md"],
|
|
83
|
-
local.inset && checkboxInsetClass,
|
|
84
|
-
local.inset && checkboxInsetSizeHeightClasses[local.size ?? "md"],
|
|
85
|
-
local.inline && checkboxInlineClass,
|
|
86
|
-
local.disabled && checkboxDisabledClass,
|
|
87
|
-
local.class,
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
const getIndicatorClass = () =>
|
|
91
|
-
twMerge(indicatorBaseClass, local.config.indicatorShape, checked() && checkedClass);
|
|
92
|
-
|
|
93
79
|
const errorMsg = createMemo(() => {
|
|
94
80
|
const v = local.checked ?? false;
|
|
95
81
|
if (local.required && !v) return i18n.t("validation.requiredSelection");
|
|
@@ -104,12 +90,20 @@ export const SelectableBase: ParentComponent<SelectableBaseProps & { config: Sel
|
|
|
104
90
|
role={local.config.role}
|
|
105
91
|
aria-checked={checked()}
|
|
106
92
|
tabIndex={local.disabled ? -1 : 0}
|
|
107
|
-
class={
|
|
93
|
+
class={twMerge(
|
|
94
|
+
checkboxBaseClass,
|
|
95
|
+
checkboxSizeClasses[local.size ?? "md"],
|
|
96
|
+
local.inset && checkboxInsetClass,
|
|
97
|
+
local.inset && checkboxInsetSizeHeightClasses[local.size ?? "md"],
|
|
98
|
+
local.inline && checkboxInlineClass,
|
|
99
|
+
local.disabled && checkboxDisabledClass,
|
|
100
|
+
local.class,
|
|
101
|
+
)}
|
|
108
102
|
style={local.style}
|
|
109
103
|
onClick={handleClick}
|
|
110
104
|
onKeyDown={handleKeyDown}
|
|
111
105
|
>
|
|
112
|
-
<div class={
|
|
106
|
+
<div class={twMerge(indicatorBaseClass, local.config.indicatorShape, checked() && checkedClass)}>
|
|
113
107
|
<Show when={checked()}>
|
|
114
108
|
{local.config.indicatorContent}
|
|
115
109
|
</Show>
|
|
@@ -153,11 +153,8 @@ export const DateRangePicker: Component<DateRangePickerProps> = (props) => {
|
|
|
153
153
|
setTo(newTo);
|
|
154
154
|
};
|
|
155
155
|
|
|
156
|
-
// Wrapper CSS class
|
|
157
|
-
const getWrapperClass = () => twMerge(clsx("inline-flex items-center", gap.md), local.class);
|
|
158
|
-
|
|
159
156
|
return (
|
|
160
|
-
<div {...rest} data-date-range-picker class={
|
|
157
|
+
<div {...rest} data-date-range-picker class={twMerge(clsx("inline-flex items-center", gap.md), local.class)} style={local.style}>
|
|
161
158
|
<Select
|
|
162
159
|
value={periodType()}
|
|
163
160
|
onValueChange={handlePeriodTypeChange}
|
|
@@ -146,18 +146,17 @@ export const RichTextEditor: Component<RichTextEditorProps> = (props) => {
|
|
|
146
146
|
editor()?.destroy();
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
-
const getWrapperClass = () =>
|
|
150
|
-
twMerge(
|
|
151
|
-
clsx("flex flex-col bg-primary-50 dark:bg-primary-950/30", text.default, "border", border.default, "rounded focus-within:border-primary-500"),
|
|
152
|
-
local.disabled && clsx(bg.muted, text.muted),
|
|
153
|
-
local.class,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
const getContentClass = () =>
|
|
157
|
-
twMerge("outline-none prose prose-sm max-w-none dark:prose-invert", editorContentSizeClasses[local.size ?? "md"]);
|
|
158
|
-
|
|
159
149
|
return (
|
|
160
|
-
<div
|
|
150
|
+
<div
|
|
151
|
+
{...rest}
|
|
152
|
+
data-rich-text-editor
|
|
153
|
+
class={twMerge(
|
|
154
|
+
clsx("flex flex-col bg-primary-50 dark:bg-primary-950/30", text.default, "border", border.default, "rounded focus-within:border-primary-500"),
|
|
155
|
+
local.disabled && clsx(bg.muted, text.muted),
|
|
156
|
+
local.class,
|
|
157
|
+
)}
|
|
158
|
+
style={local.style}
|
|
159
|
+
>
|
|
161
160
|
<Show when={editor()}>
|
|
162
161
|
{(instance) => (
|
|
163
162
|
<Show when={!local.disabled}>
|
|
@@ -165,7 +164,7 @@ export const RichTextEditor: Component<RichTextEditorProps> = (props) => {
|
|
|
165
164
|
</Show>
|
|
166
165
|
)}
|
|
167
166
|
</Show>
|
|
168
|
-
<div ref={editorRef} class={
|
|
167
|
+
<div ref={editorRef} class={twMerge("outline-none prose prose-sm max-w-none dark:prose-invert", editorContentSizeClasses[local.size ?? "md"])} />
|
|
169
168
|
</div>
|
|
170
169
|
);
|
|
171
170
|
};
|
|
@@ -19,13 +19,6 @@ import { useI18n } from "../../../providers/i18n/I18nProvider";
|
|
|
19
19
|
import { FieldShell } from "./FieldShell";
|
|
20
20
|
import clsx from "clsx";
|
|
21
21
|
|
|
22
|
-
// NumberInput-specific input style (right-aligned + spinner hidden)
|
|
23
|
-
const numberInputClass = clsx(
|
|
24
|
-
fieldInputClass,
|
|
25
|
-
"text-right",
|
|
26
|
-
"[&::-webkit-outer-spin-button]:appearance-none",
|
|
27
|
-
"[&::-webkit-inner-spin-button]:appearance-none",
|
|
28
|
-
);
|
|
29
22
|
|
|
30
23
|
const [NumberInputPrefixSlot, createNumberInputPrefixAccessor] = createSlot<{ children: JSX.Element }>();
|
|
31
24
|
export const NumberInputPrefix = NumberInputPrefixSlot;
|
|
@@ -331,7 +324,12 @@ const NumberInputInner = (props: NumberInputProps): JSX.Element => {
|
|
|
331
324
|
<input
|
|
332
325
|
type="text"
|
|
333
326
|
inputmode="numeric"
|
|
334
|
-
class={
|
|
327
|
+
class={clsx(
|
|
328
|
+
fieldInputClass,
|
|
329
|
+
"text-right",
|
|
330
|
+
"[&::-webkit-outer-spin-button]:appearance-none",
|
|
331
|
+
"[&::-webkit-inner-spin-button]:appearance-none",
|
|
332
|
+
)}
|
|
335
333
|
value={displayValue()}
|
|
336
334
|
placeholder={local.placeholder}
|
|
337
335
|
title={local.title}
|