@marianmeres/stuic 2.66.0 → 3.0.1
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 +292 -4
- package/dist/README.md +41 -18
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/actions/popover/README.md +19 -0
- package/dist/actions/popover/index.css +6 -9
- package/dist/actions/popover/popover.svelte.js +2 -2
- package/dist/actions/tooltip/README.md +18 -0
- package/dist/actions/tooltip/index.css +5 -8
- package/dist/actions/tooltip/tooltip.svelte.js +1 -1
- package/dist/actions/typeahead.svelte.d.ts +53 -0
- package/dist/actions/typeahead.svelte.js +328 -0
- package/dist/base.css +17 -0
- package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte +10 -10
- package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte.d.ts +4 -3
- package/dist/components/AlertConfirmPrompt/Current.svelte +15 -18
- package/dist/components/AlertConfirmPrompt/Current.svelte.d.ts +4 -3
- package/dist/components/AlertConfirmPrompt/acp-icons.js +5 -4
- package/dist/components/AlertConfirmPrompt/index.css +66 -0
- package/dist/components/AssetsPreview/AssetsPreview.svelte +91 -73
- package/dist/components/AssetsPreview/index.css +61 -0
- package/dist/components/Avatar/Avatar.svelte +31 -18
- package/dist/components/Avatar/README.md +166 -0
- package/dist/components/Avatar/index.css +130 -0
- package/dist/components/Backdrop/Backdrop.svelte +7 -2
- package/dist/components/Backdrop/README.md +71 -6
- package/dist/components/Backdrop/index.css +31 -0
- package/dist/components/Button/Button.svelte +116 -124
- package/dist/components/Button/Button.svelte.d.ts +35 -24
- package/dist/components/Button/README.md +87 -21
- package/dist/components/Button/index.css +475 -9
- package/dist/components/Button/index.d.ts +1 -1
- package/dist/components/Button/index.js +1 -1
- package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte +7 -39
- package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte.d.ts +0 -1
- package/dist/components/ButtonGroupRadio/README.md +82 -4
- package/dist/components/ButtonGroupRadio/index.css +158 -14
- package/dist/components/Collapsible/Collapsible.svelte +7 -7
- package/dist/components/Collapsible/Collapsible.svelte.d.ts +2 -2
- package/dist/components/Collapsible/README.md +34 -2
- package/dist/components/Collapsible/index.css +40 -0
- package/dist/components/CommandMenu/CommandMenu.svelte +18 -26
- package/dist/components/CommandMenu/CommandMenu.svelte.d.ts +0 -1
- package/dist/components/CommandMenu/README.md +39 -0
- package/dist/components/CommandMenu/index.css +47 -2
- package/dist/components/DismissibleMessage/DismissibleMessage.svelte +53 -51
- package/dist/components/DismissibleMessage/DismissibleMessage.svelte.d.ts +6 -6
- package/dist/components/DismissibleMessage/README.md +93 -11
- package/dist/components/DismissibleMessage/index.css +128 -8
- package/dist/components/DismissibleMessage/index.d.ts +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.svelte +14 -51
- package/dist/components/DropdownMenu/DropdownMenu.svelte.d.ts +6 -7
- package/dist/components/DropdownMenu/README.md +132 -0
- package/dist/components/DropdownMenu/index.css +258 -52
- package/dist/components/Input/FieldAssets.svelte +8 -5
- package/dist/components/Input/FieldCheckbox.svelte +7 -44
- package/dist/components/Input/FieldFile.svelte +1 -6
- package/dist/components/Input/FieldInput.svelte +9 -1
- package/dist/components/Input/FieldInput.svelte.d.ts +2 -0
- package/dist/components/Input/FieldOptions.svelte +42 -39
- package/dist/components/Input/FieldRadios.svelte +7 -16
- package/dist/components/Input/FieldSelect.svelte +1 -1
- package/dist/components/Input/FieldSwitch.svelte +1 -5
- package/dist/components/Input/FieldTextarea.svelte +1 -1
- package/dist/components/Input/README.md +194 -0
- package/dist/components/Input/_internal/FieldRadioInternal.svelte +2 -40
- package/dist/components/Input/_internal/InputWrap.svelte +8 -48
- package/dist/components/Input/index.css +524 -116
- package/dist/components/KbdShortcut/KbdShortcut.svelte +4 -12
- package/dist/components/KbdShortcut/README.md +34 -0
- package/dist/components/KbdShortcut/index.css +55 -0
- package/dist/components/ListItemButton/ListItemButton.svelte +37 -74
- package/dist/components/ListItemButton/ListItemButton.svelte.d.ts +1 -10
- package/dist/components/ListItemButton/README.md +100 -45
- package/dist/components/ListItemButton/index.css +173 -52
- package/dist/components/ListItemButton/index.d.ts +1 -1
- package/dist/components/ListItemButton/index.js +1 -1
- package/dist/components/Modal/Modal.svelte +1 -8
- package/dist/components/Modal/README.md +29 -0
- package/dist/components/Modal/index.css +38 -0
- package/dist/components/ModalDialog/ModalDialog.svelte +2 -21
- package/dist/components/ModalDialog/README.md +35 -0
- package/dist/components/ModalDialog/index.css +59 -0
- package/dist/components/Nav/Nav.svelte +732 -0
- package/dist/components/Nav/Nav.svelte.d.ts +110 -0
- package/dist/components/Nav/README.md +334 -0
- package/dist/components/Nav/index.css +318 -0
- package/dist/components/Nav/index.d.ts +1 -0
- package/dist/components/Nav/index.js +1 -0
- package/dist/components/Notifications/Notifications.svelte +44 -129
- package/dist/components/Notifications/Notifications.svelte.d.ts +9 -18
- package/dist/components/Notifications/README.md +186 -70
- package/dist/components/Notifications/index.css +212 -15
- package/dist/components/Notifications/notifications-stack.svelte.d.ts +4 -0
- package/dist/components/Notifications/notifications-stack.svelte.js +8 -0
- package/dist/components/Progress/Progress.svelte +4 -2
- package/dist/components/Progress/Progress.svelte.d.ts +1 -0
- package/dist/components/Progress/README.md +97 -11
- package/dist/components/Progress/_internal/Bar.svelte +4 -15
- package/dist/components/Progress/_internal/Bar.svelte.d.ts +1 -1
- package/dist/components/Progress/_internal/Circle.svelte +30 -2
- package/dist/components/Progress/_internal/Circle.svelte.d.ts +1 -0
- package/dist/components/Progress/index.css +50 -4
- package/dist/components/Skeleton/README.md +152 -0
- package/dist/components/Skeleton/Skeleton.svelte +9 -9
- package/dist/components/Skeleton/Skeleton.svelte.d.ts +0 -1
- package/dist/components/Skeleton/index.css +72 -45
- package/dist/components/Spinner/README.md +149 -37
- package/dist/components/Spinner/Spinner.svelte +14 -38
- package/dist/components/Spinner/Spinner.svelte.d.ts +2 -1
- package/dist/components/Spinner/SpinnerCircle.svelte +6 -34
- package/dist/components/Spinner/SpinnerCircle.svelte.d.ts +1 -0
- package/dist/components/Spinner/SpinnerCircleOscillate.svelte +10 -5
- package/dist/components/Spinner/SpinnerUnicode.svelte +3 -1
- package/dist/components/Spinner/SpinnerUnicode.svelte.d.ts +1 -0
- package/dist/components/Spinner/index.css +104 -0
- package/dist/components/Switch/README.md +45 -14
- package/dist/components/Switch/Switch.svelte +23 -48
- package/dist/components/Switch/Switch.svelte.d.ts +4 -2
- package/dist/components/Switch/index.css +121 -4
- package/dist/components/Switch/index.d.ts +1 -2
- package/dist/components/Switch/index.js +1 -2
- package/dist/components/TabbedMenu/README.md +37 -21
- package/dist/components/TabbedMenu/TabbedMenu.svelte +5 -46
- package/dist/components/TabbedMenu/TabbedMenu.svelte.d.ts +0 -1
- package/dist/components/TabbedMenu/index.css +84 -17
- package/dist/components/ThemePreview/README.md +289 -0
- package/dist/components/ThemePreview/ThemePreview.svelte +394 -0
- package/dist/components/ThemePreview/ThemePreview.svelte.d.ts +35 -0
- package/dist/components/ThemePreview/index.css +509 -0
- package/dist/components/ThemePreview/index.d.ts +1 -0
- package/dist/components/ThemePreview/index.js +1 -0
- package/dist/components/TwCheck/README.md +32 -13
- package/dist/components/TwCheck/TwCheck.svelte +11 -9
- package/dist/components/TwCheck/TwCheck.svelte.d.ts +0 -1
- package/dist/components/TwCheck/index.css +17 -2
- package/dist/components/TypeaheadInput/TypeaheadInput.svelte +20 -188
- package/dist/components/TypeaheadInput/TypeaheadInput.svelte.d.ts +4 -2
- package/dist/components/X/X.svelte +12 -5
- package/dist/components/X/X.svelte.d.ts +1 -0
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.css +46 -26
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/themes/blue-orange.css +217 -0
- package/dist/themes/blue-orange.d.ts +6 -0
- package/dist/themes/blue-orange.js +175 -0
- package/dist/themes/cyan-red.css +217 -0
- package/dist/themes/cyan-red.d.ts +6 -0
- package/dist/themes/cyan-red.js +175 -0
- package/dist/themes/cyan-slate.css +217 -0
- package/dist/themes/cyan-slate.d.ts +6 -0
- package/dist/themes/cyan-slate.js +175 -0
- package/dist/themes/emerald-pink.css +217 -0
- package/dist/themes/emerald-pink.d.ts +6 -0
- package/dist/themes/emerald-pink.js +175 -0
- package/dist/themes/fuchsia-emerald.css +217 -0
- package/dist/themes/fuchsia-emerald.d.ts +6 -0
- package/dist/themes/fuchsia-emerald.js +175 -0
- package/dist/themes/gray.css +217 -0
- package/dist/themes/gray.d.ts +6 -0
- package/dist/themes/gray.js +175 -0
- package/dist/themes/indigo-amber.css +217 -0
- package/dist/themes/indigo-amber.d.ts +6 -0
- package/dist/themes/indigo-amber.js +175 -0
- package/dist/themes/neutral.css +217 -0
- package/dist/themes/neutral.d.ts +6 -0
- package/dist/themes/neutral.js +175 -0
- package/dist/themes/pink-emerald.css +217 -0
- package/dist/themes/pink-emerald.d.ts +6 -0
- package/dist/themes/pink-emerald.js +175 -0
- package/dist/themes/purple-yellow.css +217 -0
- package/dist/themes/purple-yellow.d.ts +6 -0
- package/dist/themes/purple-yellow.js +175 -0
- package/dist/themes/rainbow.css +217 -0
- package/dist/themes/rainbow.d.ts +6 -0
- package/dist/themes/rainbow.js +180 -0
- package/dist/themes/red-blue.css +217 -0
- package/dist/themes/red-blue.d.ts +6 -0
- package/dist/themes/red-blue.js +175 -0
- package/dist/themes/red-cyan.css +217 -0
- package/dist/themes/red-cyan.d.ts +6 -0
- package/dist/themes/red-cyan.js +175 -0
- package/dist/themes/rose-teal.css +217 -0
- package/dist/themes/rose-teal.d.ts +6 -0
- package/dist/themes/rose-teal.js +175 -0
- package/dist/themes/sky-amber.css +217 -0
- package/dist/themes/sky-amber.d.ts +6 -0
- package/dist/themes/sky-amber.js +175 -0
- package/dist/themes/slate-cyan.css +217 -0
- package/dist/themes/slate-cyan.d.ts +6 -0
- package/dist/themes/slate-cyan.js +175 -0
- package/dist/themes/tailwind-color-pairs.md +31 -0
- package/dist/themes/teal-rose.css +217 -0
- package/dist/themes/teal-rose.d.ts +6 -0
- package/dist/themes/teal-rose.js +175 -0
- package/dist/themes/violet-lime.css +217 -0
- package/dist/themes/violet-lime.d.ts +6 -0
- package/dist/themes/violet-lime.js +175 -0
- package/dist/utils/design-tokens.d.ts +43 -0
- package/dist/utils/design-tokens.js +127 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/storage-abstraction.js +1 -1
- package/package.json +14 -11
- package/dist/components/Switch/SwitchButton.svelte +0 -135
- package/dist/components/Switch/SwitchButton.svelte.d.ts +0 -21
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import type { HTMLInputAttributes } from "svelte/elements";
|
|
4
|
+
import type { TypeaheadOptions } from "../../actions/typeahead.svelte.js";
|
|
4
5
|
import type { ValidateOptions } from "../../actions/validate.svelte.js";
|
|
5
6
|
import type { THC } from "../Thc/Thc.svelte";
|
|
6
7
|
|
|
@@ -17,6 +18,7 @@
|
|
|
17
18
|
tabindex?: number;
|
|
18
19
|
renderSize?: "sm" | "md" | "lg" | string;
|
|
19
20
|
useTrim?: boolean;
|
|
21
|
+
useTypeahead?: boolean | Omit<TypeaheadOptions, "enabled">;
|
|
20
22
|
required?: boolean;
|
|
21
23
|
disabled?: boolean;
|
|
22
24
|
validate?: boolean | Omit<ValidateOptions, "setValidationResult">;
|
|
@@ -42,6 +44,7 @@
|
|
|
42
44
|
|
|
43
45
|
<script lang="ts">
|
|
44
46
|
import { trim } from "../../actions/trim.svelte.js";
|
|
47
|
+
import { typeahead } from "../../actions/typeahead.svelte.js";
|
|
45
48
|
import {
|
|
46
49
|
validate as validateAction,
|
|
47
50
|
type ValidationResult,
|
|
@@ -61,6 +64,7 @@
|
|
|
61
64
|
class: classProp,
|
|
62
65
|
renderSize = "md",
|
|
63
66
|
useTrim = true,
|
|
67
|
+
useTypeahead,
|
|
64
68
|
//
|
|
65
69
|
required = false,
|
|
66
70
|
disabled = false,
|
|
@@ -126,11 +130,15 @@
|
|
|
126
130
|
bind:this={input}
|
|
127
131
|
{type}
|
|
128
132
|
{id}
|
|
129
|
-
class={twMerge(
|
|
133
|
+
class={twMerge(classInput)}
|
|
130
134
|
use:trim={() => ({
|
|
131
135
|
enabled: useTrim,
|
|
132
136
|
setValue: (v: string) => useTrim && (value = v),
|
|
133
137
|
})}
|
|
138
|
+
use:typeahead={() => ({
|
|
139
|
+
enabled: !!useTypeahead,
|
|
140
|
+
...(typeof useTypeahead === "boolean" ? {} : useTypeahead),
|
|
141
|
+
})}
|
|
134
142
|
use:validateAction={() => ({
|
|
135
143
|
enabled: !!validate,
|
|
136
144
|
...(typeof validate === "boolean" ? {} : validate),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
2
|
import type { HTMLInputAttributes } from "svelte/elements";
|
|
3
|
+
import type { TypeaheadOptions } from "../../actions/typeahead.svelte.js";
|
|
3
4
|
import type { ValidateOptions } from "../../actions/validate.svelte.js";
|
|
4
5
|
import type { THC } from "../Thc/Thc.svelte";
|
|
5
6
|
type SnippetWithId = Snippet<[{
|
|
@@ -16,6 +17,7 @@ export interface Props extends HTMLInputAttributes, Record<string, any> {
|
|
|
16
17
|
tabindex?: number;
|
|
17
18
|
renderSize?: "sm" | "md" | "lg" | string;
|
|
18
19
|
useTrim?: boolean;
|
|
20
|
+
useTypeahead?: boolean | Omit<TypeaheadOptions, "enabled">;
|
|
19
21
|
required?: boolean;
|
|
20
22
|
disabled?: boolean;
|
|
21
23
|
validate?: boolean | Omit<ValidateOptions, "setValidationResult">;
|
|
@@ -228,10 +228,13 @@
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
function getIconThc(isSelected: boolean): { html: string } {
|
|
231
|
+
const size = 19;
|
|
231
232
|
if (isMultiple) {
|
|
232
|
-
return {
|
|
233
|
+
return {
|
|
234
|
+
html: isSelected ? iconCheckboxCheck({ size }) : iconCheckboxEmpty({ size }),
|
|
235
|
+
};
|
|
233
236
|
}
|
|
234
|
-
return { html: isSelected ? iconRadioCheck() : iconRadioEmpty() };
|
|
237
|
+
return { html: isSelected ? iconRadioCheck({ size }) : iconRadioEmpty({ size }) };
|
|
235
238
|
}
|
|
236
239
|
|
|
237
240
|
function sortFn(a: Item, b: Item) {
|
|
@@ -542,7 +545,7 @@
|
|
|
542
545
|
let extra = '';
|
|
543
546
|
if (vals.length > limit) {
|
|
544
547
|
vals = vals.slice(0, limit);
|
|
545
|
-
extra = `, ... <span class="text-sm
|
|
548
|
+
extra = `, ... <span class="text-sm stuic-field-options-muted">(+${(origLength - limit)})</span>`;
|
|
546
549
|
}
|
|
547
550
|
return vals.filter(v => v != null).map(_renderOptionLabel).join(", ") + extra;
|
|
548
551
|
} catch (e) {
|
|
@@ -558,7 +561,7 @@
|
|
|
558
561
|
bind:this={modalDialog}
|
|
559
562
|
preEscapeClose={escape}
|
|
560
563
|
classDialog="items-start"
|
|
561
|
-
class="w-full max-w-2xl bg-transparent pointer-events-none"
|
|
564
|
+
class={twMerge("w-full max-w-2xl bg-transparent! shadow-none! pointer-events-none")}
|
|
562
565
|
ariaLabelledby={id}
|
|
563
566
|
{noScrollLock}
|
|
564
567
|
>
|
|
@@ -569,8 +572,8 @@
|
|
|
569
572
|
class={twMerge("m-2 mb-12 shadow-xl", classModalField)}
|
|
570
573
|
classInputBoxWrap={twMerge(
|
|
571
574
|
// always look like focused
|
|
572
|
-
`border border-
|
|
573
|
-
`ring-
|
|
575
|
+
`border border-(--stuic-input-accent)`,
|
|
576
|
+
`ring-(--stuic-input-accent)/20 ring-4`
|
|
574
577
|
)}
|
|
575
578
|
{id}
|
|
576
579
|
{required}
|
|
@@ -580,7 +583,7 @@
|
|
|
580
583
|
bind:this={input}
|
|
581
584
|
{type}
|
|
582
585
|
{id}
|
|
583
|
-
class={twMerge(
|
|
586
|
+
class={twMerge(renderSize, classInput)}
|
|
584
587
|
tabindex={1}
|
|
585
588
|
{required}
|
|
586
589
|
{disabled}
|
|
@@ -599,16 +602,16 @@
|
|
|
599
602
|
/>
|
|
600
603
|
|
|
601
604
|
{#snippet inputBelow()}
|
|
602
|
-
<div
|
|
605
|
+
<div
|
|
606
|
+
class="h-full border-t p-2"
|
|
607
|
+
style="border-color: var(--stuic-field-options-divider);"
|
|
608
|
+
>
|
|
603
609
|
<div class="text-sm -mt-1 flex items-center">
|
|
604
610
|
{#if isMultiple}
|
|
605
611
|
<button
|
|
606
612
|
type="button"
|
|
607
613
|
onclick={() => _selectedColl.addMany(options.items)}
|
|
608
|
-
class=
|
|
609
|
-
"control flex items-center p-1 m-1 text-sm opacity-75 underline rounded",
|
|
610
|
-
"hover:opacity-100 focus-visible:outline-neutral-400 focus-visible:opacity-100"
|
|
611
|
-
)}
|
|
614
|
+
class="control flex items-center p-1 m-1 text-sm underline rounded stuic-field-options-control"
|
|
612
615
|
tabindex={4}
|
|
613
616
|
disabled={!options.size}
|
|
614
617
|
>
|
|
@@ -621,11 +624,8 @@
|
|
|
621
624
|
_selectedColl.clear();
|
|
622
625
|
input?.focus();
|
|
623
626
|
}}
|
|
624
|
-
class=
|
|
625
|
-
|
|
626
|
-
"hover:opacity-100 focus-visible:outline-neutral-400 focus-visible:opacity-100"
|
|
627
|
-
)}
|
|
628
|
-
class:opacity-20={!selected.items.length}
|
|
627
|
+
class="control flex items-center p-1 m-1 text-sm underline rounded stuic-field-options-control"
|
|
628
|
+
data-disabled={!selected.items.length || undefined}
|
|
629
629
|
tabindex={5}
|
|
630
630
|
disabled={!selected.items.length}
|
|
631
631
|
>
|
|
@@ -634,7 +634,7 @@
|
|
|
634
634
|
|
|
635
635
|
<span class="p-1 m-1 text-sm"> </span>
|
|
636
636
|
<span
|
|
637
|
-
class="flex-1 block justify-end
|
|
637
|
+
class="flex-1 block justify-end text-right text-xs p-1 pr-2 stuic-field-options-muted"
|
|
638
638
|
>
|
|
639
639
|
{selected.items.length}
|
|
640
640
|
{#if cardinality > 0 && cardinality < Infinity}
|
|
@@ -655,11 +655,15 @@
|
|
|
655
655
|
tabindex="-1"
|
|
656
656
|
>
|
|
657
657
|
{#if isFetching && !options.items.length}
|
|
658
|
-
<div
|
|
658
|
+
<div
|
|
659
|
+
class="flex text-sm h-full items-center justify-center stuic-field-options-placeholder"
|
|
660
|
+
>
|
|
659
661
|
<Spinner class="w-4" />
|
|
660
662
|
</div>
|
|
661
663
|
{:else if !options.items.length && !allowUnknown}
|
|
662
|
-
<div
|
|
664
|
+
<div
|
|
665
|
+
class="flex text-sm h-full items-center justify-center stuic-field-options-placeholder"
|
|
666
|
+
>
|
|
663
667
|
{@html t("no_results")}
|
|
664
668
|
</div>
|
|
665
669
|
{/if}
|
|
@@ -682,8 +686,7 @@
|
|
|
682
686
|
{#if _optgroup}
|
|
683
687
|
<div
|
|
684
688
|
class={twMerge(
|
|
685
|
-
"mb-1 p-1 text-xs font-semibold uppercase tracking-wide",
|
|
686
|
-
"text-neutral-500 dark:text-neutral-400",
|
|
689
|
+
"mb-1 p-1 text-xs font-semibold uppercase tracking-wide stuic-field-options-optgroup",
|
|
687
690
|
classOptgroup
|
|
688
691
|
)}
|
|
689
692
|
>
|
|
@@ -717,7 +720,9 @@
|
|
|
717
720
|
active={isSelected}
|
|
718
721
|
focused={active}
|
|
719
722
|
contentBefore={showIcons ? getIconThc(isSelected) : undefined}
|
|
720
|
-
classContentBefore={isSelected
|
|
723
|
+
classContentBefore={isSelected
|
|
724
|
+
? "stuic-field-options-icon stuic-field-options-icon--selected"
|
|
725
|
+
: "stuic-field-options-icon"}
|
|
721
726
|
class={classOption}
|
|
722
727
|
classActive={classOptionActive}
|
|
723
728
|
classFocused={classOptionActive}
|
|
@@ -734,7 +739,7 @@
|
|
|
734
739
|
</div>
|
|
735
740
|
<!-- {/if} -->
|
|
736
741
|
<div class="p-2 px-3 flex items-end justify-between">
|
|
737
|
-
<div class="text-xs
|
|
742
|
+
<div class="text-xs stuic-field-options-muted">
|
|
738
743
|
<!-- Use arrows to navigate. Spacebar and Enter to select and/or submit. -->
|
|
739
744
|
{#if allowUnknown}
|
|
740
745
|
{@html t("unknown_allowed")}
|
|
@@ -746,7 +751,7 @@
|
|
|
746
751
|
<Button
|
|
747
752
|
class="control"
|
|
748
753
|
type="button"
|
|
749
|
-
|
|
754
|
+
intent="primary"
|
|
750
755
|
onclick={async (e) => {
|
|
751
756
|
e.preventDefault();
|
|
752
757
|
try_submit(true);
|
|
@@ -761,22 +766,20 @@
|
|
|
761
766
|
{/snippet}
|
|
762
767
|
|
|
763
768
|
{#snippet inputAfter()}
|
|
764
|
-
<div
|
|
769
|
+
<div
|
|
770
|
+
class="flex pl-2 items-center justify-center stuic-field-options-placeholder"
|
|
771
|
+
>
|
|
765
772
|
{#if isFetching}
|
|
766
773
|
<Spinner class="w-4" />
|
|
767
774
|
{/if}
|
|
768
775
|
</div>
|
|
769
776
|
<div class="flex pl-2 pr-1 items-center justify-center">
|
|
770
|
-
<
|
|
777
|
+
<Button
|
|
778
|
+
x
|
|
779
|
+
variant="ghost"
|
|
780
|
+
roundedFull
|
|
771
781
|
type="button"
|
|
772
|
-
|
|
773
|
-
"opacity-75 rounded",
|
|
774
|
-
"hover:opacity-100 hover:bg-neutral-200 dark:hover:bg-neutral-800",
|
|
775
|
-
"focus-visible:opacity-100 focus-visible:outline-0",
|
|
776
|
-
"focus-visible:bg-neutral-200 dark:focus-visible:bg-neutral-800"
|
|
777
|
-
)}
|
|
778
|
-
use:tooltip
|
|
779
|
-
aria-label={t("x_close")}
|
|
782
|
+
tooltip={t("x_close")}
|
|
780
783
|
onclick={(e) => {
|
|
781
784
|
e.preventDefault();
|
|
782
785
|
if (innerValue.trim() == "") {
|
|
@@ -787,14 +790,14 @@
|
|
|
787
790
|
input?.focus();
|
|
788
791
|
}}
|
|
789
792
|
tabindex={2}
|
|
790
|
-
|
|
791
|
-
<X class="m-2 size-6" />
|
|
792
|
-
</button>
|
|
793
|
+
/>
|
|
793
794
|
</div>
|
|
794
795
|
{/snippet}
|
|
795
796
|
|
|
796
797
|
{#snippet inputBefore()}
|
|
797
|
-
<div
|
|
798
|
+
<div
|
|
799
|
+
class="flex flex-col items-center justify-center pl-3 stuic-field-options-muted"
|
|
800
|
+
>
|
|
798
801
|
{@html iconSearch({ size: 19, strokeWidth: 3 })}
|
|
799
802
|
</div>
|
|
800
803
|
{/snippet}
|
|
@@ -63,30 +63,23 @@
|
|
|
63
63
|
let validation = $state<ValidationResult | undefined>();
|
|
64
64
|
let invalid = $derived(validation && !validation?.valid);
|
|
65
65
|
|
|
66
|
-
//
|
|
67
|
-
let _classCommon = $derived(
|
|
68
|
-
[invalid && "invalid", disabled && "disabled", required && "required", renderSize]
|
|
69
|
-
.filter(Boolean)
|
|
70
|
-
.join(" ")
|
|
71
|
-
);
|
|
72
66
|
// $inspect(value);
|
|
73
67
|
</script>
|
|
74
68
|
|
|
75
69
|
{#if _options.length}
|
|
76
|
-
<div
|
|
70
|
+
<div
|
|
71
|
+
class={twMerge("stuic-radios", invalid && "invalid", disabled && "disabled")}
|
|
72
|
+
data-size={renderSize}
|
|
73
|
+
{style}
|
|
74
|
+
>
|
|
77
75
|
<div
|
|
78
76
|
class={twMerge(
|
|
79
77
|
"radios-box",
|
|
80
|
-
|
|
81
|
-
"gap-y-2 grid rounded-md p-2 mb-8",
|
|
82
|
-
"border border-neutral-300 dark:border-neutral-600",
|
|
83
|
-
"bg-neutral-100 dark:bg-neutral-700",
|
|
84
|
-
invalid && "border-input-accent-invalid dark:border-input-accent-invalid-dark",
|
|
78
|
+
"gap-y-2 grid p-2 mb-8",
|
|
85
79
|
classProp
|
|
86
80
|
)}
|
|
87
81
|
>
|
|
88
82
|
{#each _options as o, i}
|
|
89
|
-
<!-- value={o.value || o.label} -->
|
|
90
83
|
<FieldRadioInternal
|
|
91
84
|
{name}
|
|
92
85
|
bind:group={value}
|
|
@@ -114,9 +107,7 @@
|
|
|
114
107
|
transition:slide={{ duration: 150 }}
|
|
115
108
|
class={twMerge(
|
|
116
109
|
"validation-box",
|
|
117
|
-
|
|
118
|
-
`mt-1 px-2 text-sm text-input-accent dark:text-input-accent-dark
|
|
119
|
-
tracking-tight`,
|
|
110
|
+
"mt-1 px-2 text-sm tracking-tight",
|
|
120
111
|
classValidationBox
|
|
121
112
|
)}
|
|
122
113
|
>
|
|
@@ -111,14 +111,10 @@
|
|
|
111
111
|
{classLabel}
|
|
112
112
|
{classLabelBox}
|
|
113
113
|
{classInputBox}
|
|
114
|
-
classInputBoxWrap={twMerge(
|
|
115
|
-
"border-0 focus-within:border-0 focus-within:dark:border-0 focus-within:ring-0",
|
|
116
|
-
"bg-transparent dark:bg-transparent",
|
|
117
|
-
classInputBoxWrap
|
|
118
|
-
)}
|
|
119
114
|
{classDescBox}
|
|
120
115
|
{classBelowBox}
|
|
121
116
|
{validation}
|
|
117
|
+
classInputBoxWrap={twMerge("input-wrap-transparent", classInputBoxWrap)}
|
|
122
118
|
{style}
|
|
123
119
|
>
|
|
124
120
|
<Switch bind:checked {name} {required} {disabled} {validate} {setValidationResult} />
|
|
@@ -232,3 +232,197 @@ Validation is handled by the `validate` action. Pass `validate={true}` for defau
|
|
|
232
232
|
}}
|
|
233
233
|
/>
|
|
234
234
|
```
|
|
235
|
+
|
|
236
|
+
## CSS Variables
|
|
237
|
+
|
|
238
|
+
### Component Tokens
|
|
239
|
+
|
|
240
|
+
Override globally in `:root` or locally via `style` prop:
|
|
241
|
+
|
|
242
|
+
| Variable | Default | Description |
|
|
243
|
+
|----------|---------|-------------|
|
|
244
|
+
| `--stuic-input-radius` | `--radius-md` | Border radius |
|
|
245
|
+
| `--stuic-input-font-family` | `--font-sans` | Font family |
|
|
246
|
+
| `--stuic-input-transition` | `150ms` | Transition duration |
|
|
247
|
+
| `--stuic-input-ring-width` | `4px` | Focus ring width |
|
|
248
|
+
| `--stuic-input-ring-color` | `--stuic-color-ring` | Focus ring color |
|
|
249
|
+
| `--stuic-input-accent` | `--stuic-color-primary` | Accent color |
|
|
250
|
+
| `--stuic-input-accent-error` | `--stuic-color-destructive` | Error/validation color |
|
|
251
|
+
|
|
252
|
+
### Color Tokens
|
|
253
|
+
|
|
254
|
+
| Variable | Default | Description |
|
|
255
|
+
|----------|---------|-------------|
|
|
256
|
+
| `--stuic-input-bg` | `--stuic-color-input` | Background color |
|
|
257
|
+
| `--stuic-input-border` | `--stuic-color-border` | Border color |
|
|
258
|
+
| `--stuic-input-border-focus` | `--stuic-input-accent` | Border color on focus |
|
|
259
|
+
| `--stuic-input-text` | `--stuic-color-foreground` | Text color |
|
|
260
|
+
| `--stuic-input-placeholder` | `--stuic-color-muted-foreground` | Placeholder color |
|
|
261
|
+
|
|
262
|
+
### Size Tokens
|
|
263
|
+
|
|
264
|
+
Each size (sm, md, lg) has corresponding tokens:
|
|
265
|
+
|
|
266
|
+
| Variable | sm | md | lg |
|
|
267
|
+
|----------|----|----|-----|
|
|
268
|
+
| `--stuic-input-padding-x-{size}` | `calc(--spacing * 2.5)` | `calc(--spacing * 3)` | `calc(--spacing * 4)` |
|
|
269
|
+
| `--stuic-input-padding-y-{size}` | `calc(--spacing * 2)` | `calc(--spacing * 2.5)` | `calc(--spacing * 3)` |
|
|
270
|
+
| `--stuic-input-font-size-{size}` | `--text-sm` | `--text-base` | `--text-lg` |
|
|
271
|
+
| `--stuic-input-min-height-{size}` | `2.5rem` | `2.75rem` | `3rem` |
|
|
272
|
+
|
|
273
|
+
### Checkbox/Radio Tokens
|
|
274
|
+
|
|
275
|
+
| Variable | Default | Description |
|
|
276
|
+
|----------|---------|-------------|
|
|
277
|
+
| `--stuic-checkbox-size` | `1.25rem` | Checkbox size |
|
|
278
|
+
| `--stuic-checkbox-radius` | `--radius-sm` | Checkbox border radius |
|
|
279
|
+
| `--stuic-radio-size` | `1rem` | Radio button size |
|
|
280
|
+
| `--stuic-checkbox-bg` | `--stuic-color-muted` | Unchecked background |
|
|
281
|
+
| `--stuic-checkbox-border` | `--stuic-color-border` | Unchecked border |
|
|
282
|
+
| `--stuic-checkbox-checked-bg` | `--stuic-input-accent` | Checked background |
|
|
283
|
+
| `--stuic-checkbox-checked-border` | `--stuic-input-accent` | Checked border |
|
|
284
|
+
|
|
285
|
+
### Range Input Tokens
|
|
286
|
+
|
|
287
|
+
| Variable | Default | Description |
|
|
288
|
+
|----------|---------|-------------|
|
|
289
|
+
| `--stuic-input-range-thumb-size` | `18px` | Slider thumb size |
|
|
290
|
+
| `--stuic-input-range-track-height` | `4px` | Track height |
|
|
291
|
+
| `--stuic-input-range-track-radius` | `18px` | Track border radius |
|
|
292
|
+
| `--stuic-input-range-track-bg` | `--stuic-color-muted` | Track background |
|
|
293
|
+
|
|
294
|
+
### Customization Examples
|
|
295
|
+
|
|
296
|
+
```css
|
|
297
|
+
/* Global: Make all inputs have pill shape */
|
|
298
|
+
:root {
|
|
299
|
+
--stuic-input-radius: 9999px;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* Global: Custom accent color */
|
|
303
|
+
:root {
|
|
304
|
+
--stuic-input-accent: var(--color-violet-600);
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
```svelte
|
|
309
|
+
<!-- Local: Custom radius for one input -->
|
|
310
|
+
<FieldInput
|
|
311
|
+
label="Search"
|
|
312
|
+
style="--stuic-input-radius: 9999px;"
|
|
313
|
+
/>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Data Attributes
|
|
317
|
+
|
|
318
|
+
Components use data attributes for CSS styling:
|
|
319
|
+
|
|
320
|
+
- `data-size` - The size value ("sm", "md", "lg")
|
|
321
|
+
|
|
322
|
+
## Class Props
|
|
323
|
+
|
|
324
|
+
| Prop | Target |
|
|
325
|
+
|------|--------|
|
|
326
|
+
| `class` | Root container |
|
|
327
|
+
| `classInput` | Input element |
|
|
328
|
+
| `classLabel` | Label element |
|
|
329
|
+
| `classLabelBox` | Label container |
|
|
330
|
+
| `classInputBox` | Input container (outer) |
|
|
331
|
+
| `classInputBoxWrap` | Input wrapper (inner, has border) |
|
|
332
|
+
| `classInputBoxWrapInvalid` | Input wrapper when invalid |
|
|
333
|
+
| `classDescBox` | Description container |
|
|
334
|
+
| `classBelowBox` | Below slot container |
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## FieldOptions
|
|
339
|
+
|
|
340
|
+
A modal-based multi-select/single-select component with search functionality, typeahead support, and option grouping.
|
|
341
|
+
|
|
342
|
+
### Props
|
|
343
|
+
|
|
344
|
+
| Prop | Type | Default | Description |
|
|
345
|
+
|------|------|---------|-------------|
|
|
346
|
+
| `value` | `string` | `"[]"` | JSON array of selected items (bindable) |
|
|
347
|
+
| `name` | `string` | - | Form field name |
|
|
348
|
+
| `getOptions` | `(q: string, current: Item[]) => Promise<{found: Item[]}>` | - | Async function to fetch options |
|
|
349
|
+
| `cardinality` | `number` | `Infinity` | Max selections (-1 for unlimited) |
|
|
350
|
+
| `allowUnknown` | `boolean` | `false` | Allow typing custom values |
|
|
351
|
+
| `renderOptionLabel` | `(item: Item) => string` | - | Custom option label renderer |
|
|
352
|
+
| `renderOptionGroup` | `(s: string) => string` | - | Custom optgroup label renderer |
|
|
353
|
+
| `renderValue` | `(stringifiedItems: string) => string` | - | Custom value display renderer |
|
|
354
|
+
| `showIconsCheckbox` | `boolean` | `true` | Show checkbox icons in multi-select |
|
|
355
|
+
| `showIconsRadio` | `boolean` | `false` | Show radio icons in single-select |
|
|
356
|
+
| `searchPlaceholder` | `string` | - | Custom search placeholder |
|
|
357
|
+
| `itemIdPropName` | `string` | `"id"` | Property name for item ID |
|
|
358
|
+
| `notifications` | `NotificationsStack` | - | Notification handler for errors |
|
|
359
|
+
|
|
360
|
+
### Class Props
|
|
361
|
+
|
|
362
|
+
| Prop | Target |
|
|
363
|
+
|------|--------|
|
|
364
|
+
| `classOption` | Option item (ListItemButton) |
|
|
365
|
+
| `classOptionActive` | Active/selected option |
|
|
366
|
+
| `classOptgroup` | Option group label |
|
|
367
|
+
| `classModalField` | Modal field wrapper |
|
|
368
|
+
|
|
369
|
+
### CSS Variables
|
|
370
|
+
|
|
371
|
+
#### Component Tokens
|
|
372
|
+
|
|
373
|
+
| Variable | Default | Description |
|
|
374
|
+
|----------|---------|-------------|
|
|
375
|
+
| `--stuic-field-options-divider` | `--stuic-color-border` | Divider/separator color |
|
|
376
|
+
| `--stuic-field-options-control-text` | `--stuic-color-muted-foreground` | Control button text color |
|
|
377
|
+
| `--stuic-field-options-control-text-hover` | `--stuic-color-foreground` | Control button hover text color |
|
|
378
|
+
| `--stuic-field-options-control-ring` | `--stuic-color-ring` | Control button focus ring |
|
|
379
|
+
| `--stuic-field-options-muted-text` | `--stuic-color-muted-foreground` | Muted/secondary text color |
|
|
380
|
+
| `--stuic-field-options-optgroup-text` | `--stuic-color-muted-foreground` | Option group label color |
|
|
381
|
+
|
|
382
|
+
### Usage
|
|
383
|
+
|
|
384
|
+
```svelte
|
|
385
|
+
<script lang="ts">
|
|
386
|
+
import { FieldOptions } from 'stuic';
|
|
387
|
+
|
|
388
|
+
let value = $state('[]');
|
|
389
|
+
|
|
390
|
+
async function getOptions(query: string, current: any[]) {
|
|
391
|
+
const response = await fetch(`/api/search?q=${query}`);
|
|
392
|
+
const data = await response.json();
|
|
393
|
+
return { found: data.items };
|
|
394
|
+
}
|
|
395
|
+
</script>
|
|
396
|
+
|
|
397
|
+
<FieldOptions
|
|
398
|
+
label="Select Tags"
|
|
399
|
+
name="tags"
|
|
400
|
+
bind:value
|
|
401
|
+
{getOptions}
|
|
402
|
+
cardinality={5}
|
|
403
|
+
allowUnknown
|
|
404
|
+
/>
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Customization Examples
|
|
408
|
+
|
|
409
|
+
```css
|
|
410
|
+
/* Make optgroup labels more prominent */
|
|
411
|
+
:root {
|
|
412
|
+
--stuic-field-options-optgroup-text: var(--stuic-color-primary);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/* Custom control button colors */
|
|
416
|
+
:root {
|
|
417
|
+
--stuic-field-options-control-text: var(--stuic-color-primary);
|
|
418
|
+
--stuic-field-options-control-text-hover: var(--stuic-color-primary-hover);
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
```svelte
|
|
423
|
+
<!-- Local customization -->
|
|
424
|
+
<FieldOptions
|
|
425
|
+
style="--stuic-field-options-divider: var(--color-red-500);"
|
|
426
|
+
...
|
|
427
|
+
/>
|
|
428
|
+
```
|
|
@@ -69,21 +69,7 @@
|
|
|
69
69
|
let id = getId();
|
|
70
70
|
let idDesc = getId();
|
|
71
71
|
|
|
72
|
-
//
|
|
73
|
-
let _classCommon = $derived(
|
|
74
|
-
[invalid && "invalid", disabled && "disabled", renderSize].filter(Boolean).join(" ")
|
|
75
|
-
);
|
|
76
72
|
|
|
77
|
-
const _preset = {
|
|
78
|
-
labelBox: {
|
|
79
|
-
label: {
|
|
80
|
-
size: {
|
|
81
|
-
sm: "text-sm mt-0.5",
|
|
82
|
-
lg: "font-semibold",
|
|
83
|
-
} as any,
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
73
|
</script>
|
|
88
74
|
|
|
89
75
|
{#snippet snippetOrThc({ id, value }: { id: string; value?: SnippetWithId | THC })}
|
|
@@ -97,7 +83,6 @@
|
|
|
97
83
|
<label
|
|
98
84
|
class={twMerge(
|
|
99
85
|
"radio-box",
|
|
100
|
-
_classCommon,
|
|
101
86
|
"flex items-start cursor-pointer pr-1",
|
|
102
87
|
disabled && "cursor-not-allowed",
|
|
103
88
|
classRadioBox
|
|
@@ -106,7 +91,6 @@
|
|
|
106
91
|
<div
|
|
107
92
|
class={twMerge(
|
|
108
93
|
"input-box",
|
|
109
|
-
_classCommon,
|
|
110
94
|
"flex h-6 items-center ml-1",
|
|
111
95
|
classInputBox
|
|
112
96
|
)}
|
|
@@ -118,26 +102,7 @@
|
|
|
118
102
|
bind:group
|
|
119
103
|
{value}
|
|
120
104
|
{name}
|
|
121
|
-
class={twMerge(
|
|
122
|
-
_classCommon,
|
|
123
|
-
`size-4 rounded-full
|
|
124
|
-
bg-neutral-100
|
|
125
|
-
border-neutral-300
|
|
126
|
-
text-input-accent dark:text-input-accent-dark
|
|
127
|
-
cursor-pointer
|
|
128
|
-
|
|
129
|
-
checked:border-input-accent checked:bg-input-accent
|
|
130
|
-
checked:dark:border-input-accent-dark checked:dark:bg-input-accent-dark
|
|
131
|
-
|
|
132
|
-
focus:border-input-accent
|
|
133
|
-
focus:ring-4
|
|
134
|
-
focus:ring-offset-0
|
|
135
|
-
focus:ring-input-accent/20 focus:dark:ring-input-accent-dark/20
|
|
136
|
-
|
|
137
|
-
disabled:cursor-not-allowed`,
|
|
138
|
-
disabled && "cursor-not-allowed",
|
|
139
|
-
classInput
|
|
140
|
-
)}
|
|
105
|
+
class={twMerge(classInput)}
|
|
141
106
|
aria-describedby={description ? idDesc : undefined}
|
|
142
107
|
use:validateAction={() => ({
|
|
143
108
|
enabled: !!validate,
|
|
@@ -149,14 +114,12 @@
|
|
|
149
114
|
{...rest}
|
|
150
115
|
/>
|
|
151
116
|
</div>
|
|
152
|
-
<div class={twMerge("label-box",
|
|
117
|
+
<div class={twMerge("label-box", "ml-3 w-full", classLabelBox)}>
|
|
153
118
|
{#if label}
|
|
154
119
|
<div
|
|
155
120
|
class={twMerge(
|
|
156
121
|
"label",
|
|
157
|
-
_classCommon,
|
|
158
122
|
"block w-full cursor-pointer",
|
|
159
|
-
renderSize && _preset.labelBox.label.size[renderSize],
|
|
160
123
|
required && "after:content-['*'] after:opacity-40 after:pl-1",
|
|
161
124
|
classLabel
|
|
162
125
|
)}
|
|
@@ -173,7 +136,6 @@
|
|
|
173
136
|
id={idDesc}
|
|
174
137
|
class={twMerge(
|
|
175
138
|
"desc-box",
|
|
176
|
-
_classCommon,
|
|
177
139
|
"text-sm opacity-50 cursor-pointer font-normal",
|
|
178
140
|
disabled && "cursor-not-allowed",
|
|
179
141
|
classDescBox
|