@simplysm/solid 13.0.84 → 13.0.86
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/README.md +143 -28
- package/dist/components/data/list/ListItem.d.ts.map +1 -1
- package/dist/components/data/list/ListItem.js +11 -4
- package/dist/components/data/list/ListItem.js.map +2 -2
- package/dist/components/data/list/ListItem.styles.d.ts +2 -0
- package/dist/components/data/list/ListItem.styles.d.ts.map +1 -1
- package/dist/components/data/list/ListItem.styles.js +11 -1
- package/dist/components/data/list/ListItem.styles.js.map +1 -1
- 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 +10 -5
- package/dist/components/features/crud-sheet/CrudSheet.js.map +2 -2
- package/dist/components/features/data-select-button/DataSelectButton.d.ts.map +1 -1
- package/dist/components/features/data-select-button/DataSelectButton.js +30 -26
- package/dist/components/features/data-select-button/DataSelectButton.js.map +2 -2
- package/dist/components/features/permission-table/PermissionTable.js +5 -1
- package/dist/components/features/permission-table/PermissionTable.js.map +2 -2
- 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/DropdownTrigger.styles.js +1 -1
- 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/combobox/Combobox.d.ts +19 -5
- package/dist/components/form-control/combobox/Combobox.d.ts.map +1 -1
- package/dist/components/form-control/combobox/Combobox.js +2 -4
- package/dist/components/form-control/combobox/Combobox.js.map +1 -1
- package/dist/components/form-control/date-range-picker/DateRangePicker.d.ts +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 +11 -3
- package/dist/components/form-control/date-range-picker/DateRangePicker.js.map +2 -2
- package/dist/components/form-control/editor/RichTextEditor.d.ts +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/DatePicker.d.ts +2 -2
- package/dist/components/form-control/field/DatePicker.d.ts.map +1 -1
- package/dist/components/form-control/field/DatePicker.js.map +1 -1
- package/dist/components/form-control/field/DateTimePicker.d.ts +2 -2
- package/dist/components/form-control/field/DateTimePicker.d.ts.map +1 -1
- package/dist/components/form-control/field/DateTimePicker.js.map +1 -1
- package/dist/components/form-control/field/Field.styles.d.ts +6 -7
- package/dist/components/form-control/field/Field.styles.d.ts.map +1 -1
- package/dist/components/form-control/field/Field.styles.js.map +1 -1
- package/dist/components/form-control/field/NumberInput.d.ts +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/TextInput.d.ts +2 -2
- package/dist/components/form-control/field/TextInput.d.ts.map +1 -1
- package/dist/components/form-control/field/TextInput.js.map +1 -1
- package/dist/components/form-control/field/Textarea.d.ts +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/field/TimePicker.d.ts +2 -2
- package/dist/components/form-control/field/TimePicker.d.ts.map +1 -1
- package/dist/components/form-control/field/TimePicker.js.map +1 -1
- package/dist/components/form-control/numpad/Numpad.d.ts.map +1 -1
- package/dist/components/form-control/numpad/Numpad.js +4 -17
- package/dist/components/form-control/numpad/Numpad.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 +29 -15
- package/dist/components/form-control/select/Select.js.map +2 -2
- package/dist/components/form-control/state-preset/StatePreset.d.ts +1 -3
- package/dist/components/form-control/state-preset/StatePreset.d.ts.map +1 -1
- package/dist/components/form-control/state-preset/StatePreset.js +69 -95
- package/dist/components/form-control/state-preset/StatePreset.js.map +2 -2
- package/dist/components/layout/FormGroup.js +1 -1
- package/dist/components/layout/FormGroup.js.map +1 -1
- package/dist/components/layout/FormTable.js +3 -3
- package/dist/components/layout/FormTable.js.map +1 -1
- package/dist/components/layout/sidebar/Sidebar.d.ts.map +1 -1
- package/dist/components/layout/sidebar/Sidebar.js +3 -6
- package/dist/components/layout/sidebar/Sidebar.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/i18n/locales/en.d.ts +2 -3
- package/dist/providers/i18n/locales/en.d.ts.map +1 -1
- package/dist/providers/i18n/locales/en.js +3 -4
- package/dist/providers/i18n/locales/en.js.map +1 -1
- package/dist/providers/i18n/locales/ko.d.ts +2 -3
- package/dist/providers/i18n/locales/ko.d.ts.map +1 -1
- package/dist/providers/i18n/locales/ko.js +3 -4
- package/dist/providers/i18n/locales/ko.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/docs/display-feedback.md +279 -0
- package/docs/features.md +357 -213
- package/docs/form-controls.md +261 -403
- package/docs/layout-data.md +386 -0
- package/docs/providers-hooks.md +411 -0
- package/package.json +5 -5
- package/src/components/data/list/ListItem.styles.ts +14 -2
- package/src/components/data/list/ListItem.tsx +13 -4
- 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 +12 -5
- package/src/components/features/data-select-button/DataSelectButton.tsx +39 -32
- package/src/components/features/permission-table/PermissionTable.tsx +1 -1
- package/src/components/feedback/busy/BusyContainer.tsx +12 -18
- package/src/components/form-control/DropdownTrigger.styles.ts +1 -1
- package/src/components/form-control/checkbox/SelectableBase.tsx +10 -16
- package/src/components/form-control/combobox/Combobox.tsx +42 -16
- package/src/components/form-control/date-range-picker/DateRangePicker.tsx +7 -8
- package/src/components/form-control/editor/RichTextEditor.tsx +14 -16
- package/src/components/form-control/field/DatePicker.tsx +3 -2
- package/src/components/form-control/field/DateTimePicker.tsx +3 -2
- package/src/components/form-control/field/Field.styles.ts +6 -8
- package/src/components/form-control/field/NumberInput.tsx +9 -10
- package/src/components/form-control/field/TextInput.tsx +3 -2
- package/src/components/form-control/field/Textarea.tsx +14 -12
- package/src/components/form-control/field/TimePicker.tsx +3 -2
- package/src/components/form-control/numpad/Numpad.tsx +16 -18
- package/src/components/form-control/select/Select.tsx +41 -13
- package/src/components/form-control/state-preset/StatePreset.tsx +39 -71
- package/src/components/layout/FormGroup.tsx +1 -1
- package/src/components/layout/FormTable.tsx +3 -3
- package/src/components/layout/sidebar/Sidebar.tsx +2 -3
- 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/i18n/locales/en.ts +2 -3
- package/src/providers/i18n/locales/ko.ts +2 -3
- package/src/providers/shared-data/SharedDataProvider.tsx +0 -1
- package/tests/components/features/crud-detail/CrudDetail.spec.tsx +49 -0
- package/tests/components/features/data-select-button/DataSelectButton.spec.tsx +62 -7
- package/tests/components/form-control/combobox/Combobox.spec.tsx +3 -3
- package/tests/components/form-control/date-range-picker/DateRangePicker.spec.tsx +56 -0
- package/tests/components/form-control/select/SelectItem.spec.tsx +5 -0
- package/tests/providers/shared-data/SharedDataProvider.spec.tsx +0 -104
- package/docs/data.md +0 -204
- package/docs/disclosure.md +0 -146
- package/docs/display.md +0 -125
- package/docs/feedback.md +0 -156
- package/docs/helpers.md +0 -173
- package/docs/hooks.md +0 -146
- package/docs/layout.md +0 -94
- package/docs/providers.md +0 -180
|
@@ -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()}>
|
|
@@ -348,6 +348,14 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, unknown>>(
|
|
|
348
348
|
|
|
349
349
|
setSelectedKeys(merged);
|
|
350
350
|
setSelection(newSelection);
|
|
351
|
+
|
|
352
|
+
// Auto-confirm for single selection mode in dialog
|
|
353
|
+
if (isInDialog && local.selectionMode === "single" && newSelection.length > 0) {
|
|
354
|
+
local.onSelect?.({
|
|
355
|
+
items: newSelection,
|
|
356
|
+
keys: [...merged],
|
|
357
|
+
});
|
|
358
|
+
}
|
|
351
359
|
}
|
|
352
360
|
|
|
353
361
|
function clearSelection() {
|
|
@@ -369,13 +377,13 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, unknown>>(
|
|
|
369
377
|
|
|
370
378
|
// -- Keyboard Shortcuts --
|
|
371
379
|
createEventListener(document, "keydown", async (e: KeyboardEvent) => {
|
|
372
|
-
if (!isActiveCrud(crudId)) return;
|
|
373
|
-
if (e.
|
|
380
|
+
if (!e.ctrlKey || !isActiveCrud(crudId)) return;
|
|
381
|
+
if (e.key === "s" && !isSelectMode()) {
|
|
374
382
|
e.preventDefault();
|
|
375
383
|
e.stopImmediatePropagation();
|
|
376
384
|
formRef?.requestSubmit();
|
|
377
385
|
}
|
|
378
|
-
if (e.
|
|
386
|
+
if (e.altKey && e.key === "l") {
|
|
379
387
|
e.preventDefault();
|
|
380
388
|
e.stopImmediatePropagation();
|
|
381
389
|
if (!checkIgnoreChanges()) return;
|
|
@@ -402,7 +410,6 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, unknown>>(
|
|
|
402
410
|
<>
|
|
403
411
|
<Show when={canEdit() && local.inlineEdit}>
|
|
404
412
|
<Button
|
|
405
|
-
size="lg"
|
|
406
413
|
variant="ghost"
|
|
407
414
|
theme="primary"
|
|
408
415
|
onClick={() => formRef?.requestSubmit()}
|
|
@@ -411,7 +418,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, unknown>>(
|
|
|
411
418
|
{i18n.t("crudSheet.save")}
|
|
412
419
|
</Button>
|
|
413
420
|
</Show>
|
|
414
|
-
<Button
|
|
421
|
+
<Button variant="ghost" theme="info" onClick={handleRefresh}>
|
|
415
422
|
<Icon icon={IconRefresh} class="mr-1" />
|
|
416
423
|
{i18n.t("crudSheet.refresh")}
|
|
417
424
|
</Button>
|
|
@@ -149,7 +149,6 @@ export function DataSelectButton<
|
|
|
149
149
|
"onValueChange",
|
|
150
150
|
"load",
|
|
151
151
|
"dialog",
|
|
152
|
-
"dialogProps",
|
|
153
152
|
"dialogOptions",
|
|
154
153
|
"renderItem",
|
|
155
154
|
"multiple",
|
|
@@ -174,9 +173,9 @@ export function DataSelectButton<
|
|
|
174
173
|
// Controlled/uncontrolled pattern
|
|
175
174
|
type ValueType = TKey | TKey[] | undefined;
|
|
176
175
|
const [getValue, setValue] = createControllableSignal<ValueType>({
|
|
177
|
-
value: () => local.value,
|
|
176
|
+
value: () => local.value as ValueType,
|
|
178
177
|
onChange: () => local.onValueChange as ((v: ValueType) => void) | undefined,
|
|
179
|
-
}
|
|
178
|
+
});
|
|
180
179
|
|
|
181
180
|
// Track keys for loading
|
|
182
181
|
const [loadKeys, setLoadKeys] = createSignal<TKey[]>(normalizeKeys(local.value));
|
|
@@ -216,27 +215,38 @@ export function DataSelectButton<
|
|
|
216
215
|
return local.validate?.(v);
|
|
217
216
|
});
|
|
218
217
|
|
|
218
|
+
// Dialog open state for aria-expanded
|
|
219
|
+
const [isDialogOpen, setIsDialogOpen] = createSignal(false);
|
|
220
|
+
|
|
219
221
|
// Open dialog
|
|
220
222
|
const handleOpenDialog = async () => {
|
|
221
223
|
if (local.disabled) return;
|
|
222
224
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
225
|
+
setIsDialogOpen(true);
|
|
226
|
+
try {
|
|
227
|
+
const dialogProps =
|
|
228
|
+
(props as { dialogProps?: Record<string, unknown> }).dialogProps ?? {};
|
|
229
|
+
const showProps = {
|
|
230
|
+
...dialogProps,
|
|
227
231
|
selectionMode: local.multiple ? "multiple" : "single",
|
|
228
232
|
selectedKeys: normalizeKeys(getValue()) as (string | number)[],
|
|
229
|
-
},
|
|
230
|
-
|
|
231
|
-
|
|
233
|
+
} as Omit<TDialogProps, "close">;
|
|
234
|
+
const result = (await dialog.show(
|
|
235
|
+
local.dialog as Component<SelectDialogBaseProps<TKey>>,
|
|
236
|
+
showProps as Omit<SelectDialogBaseProps<TKey>, "close">,
|
|
237
|
+
local.dialogOptions,
|
|
238
|
+
));
|
|
232
239
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
240
|
+
if (result) {
|
|
241
|
+
const newKeys = result.selectedKeys;
|
|
242
|
+
if (local.multiple) {
|
|
243
|
+
setValue(newKeys);
|
|
244
|
+
} else {
|
|
245
|
+
setValue(newKeys.length > 0 ? newKeys[0] : undefined);
|
|
246
|
+
}
|
|
239
247
|
}
|
|
248
|
+
} finally {
|
|
249
|
+
setIsDialogOpen(false);
|
|
240
250
|
}
|
|
241
251
|
};
|
|
242
252
|
|
|
@@ -283,23 +293,17 @@ export function DataSelectButton<
|
|
|
283
293
|
return (
|
|
284
294
|
<Invalid message={errorMsg()} variant="border" lazyValidation={local.lazyValidation}>
|
|
285
295
|
<div data-data-select-button class="group inline-flex items-center">
|
|
286
|
-
<
|
|
287
|
-
|
|
296
|
+
<button
|
|
297
|
+
type="button"
|
|
298
|
+
data-trigger
|
|
288
299
|
aria-haspopup="dialog"
|
|
289
|
-
aria-expanded={
|
|
290
|
-
aria-disabled={local.disabled || undefined}
|
|
300
|
+
aria-expanded={isDialogOpen()}
|
|
291
301
|
aria-required={local.required || undefined}
|
|
292
|
-
|
|
293
|
-
class={triggerClassName()}
|
|
294
|
-
|
|
295
|
-
if (local.disabled) return;
|
|
296
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
297
|
-
e.preventDefault();
|
|
298
|
-
void handleOpenDialog();
|
|
299
|
-
}
|
|
300
|
-
}}
|
|
302
|
+
disabled={local.disabled || undefined}
|
|
303
|
+
class={twMerge("appearance-none font-inherit text-inherit text-left", triggerClassName())}
|
|
304
|
+
onClick={() => void handleOpenDialog()}
|
|
301
305
|
>
|
|
302
|
-
<div class="flex-1
|
|
306
|
+
<div class="flex-1 whitespace-nowrap">{renderSelectedDisplay()}</div>
|
|
303
307
|
<div class={clsx("flex items-center", gap.sm)}>
|
|
304
308
|
<Show when={clearable()}>
|
|
305
309
|
<button
|
|
@@ -318,7 +322,10 @@ export function DataSelectButton<
|
|
|
318
322
|
type="button"
|
|
319
323
|
data-search-button
|
|
320
324
|
class={twMerge(actionButtonClass, text.muted, "hover:text-primary-500")}
|
|
321
|
-
onClick={() =>
|
|
325
|
+
onClick={(e) => {
|
|
326
|
+
e.stopPropagation();
|
|
327
|
+
void handleOpenDialog();
|
|
328
|
+
}}
|
|
322
329
|
tabIndex={-1}
|
|
323
330
|
aria-label={i18n.t("dataSelectButton.search")}
|
|
324
331
|
>
|
|
@@ -326,7 +333,7 @@ export function DataSelectButton<
|
|
|
326
333
|
</button>
|
|
327
334
|
</Show>
|
|
328
335
|
</div>
|
|
329
|
-
</
|
|
336
|
+
</button>
|
|
330
337
|
</div>
|
|
331
338
|
</Invalid>
|
|
332
339
|
);
|
|
@@ -288,7 +288,7 @@ export const PermissionTable: Component<PermissionTableProps> = (props) => {
|
|
|
288
288
|
</DataSheet.Column>
|
|
289
289
|
<For each={allPerms()}>
|
|
290
290
|
{(perm) => (
|
|
291
|
-
<DataSheet.Column key={`perm-${perm}`} header={perm} sortable={false} resizable={false}>
|
|
291
|
+
<DataSheet.Column key={`perm-${perm}`} header={(() => { const key = `permissionTable.${perm}`; const translated = i18n.t(key); return translated === key ? perm : translated; })()} sortable={false} resizable={false}>
|
|
292
292
|
{(ctx) => {
|
|
293
293
|
const item = ctx.item as AppPerm;
|
|
294
294
|
return (
|
|
@@ -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>
|