@marianmeres/stuic 2.65.0 → 3.0.0
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/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/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte +9 -10
- package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte.d.ts +3 -3
- package/dist/components/AlertConfirmPrompt/Current.svelte +15 -17
- package/dist/components/AlertConfirmPrompt/Current.svelte.d.ts +5 -3
- package/dist/components/AlertConfirmPrompt/acp-icons.js +5 -4
- package/dist/components/AlertConfirmPrompt/index.css +62 -0
- package/dist/components/AssetsPreview/AssetsPreview.svelte +92 -73
- package/dist/components/AssetsPreview/AssetsPreview.svelte.d.ts +1 -0
- package/dist/components/AssetsPreview/index.css +59 -0
- package/dist/components/Avatar/Avatar.svelte +32 -18
- package/dist/components/Avatar/Avatar.svelte.d.ts +1 -0
- package/dist/components/Avatar/README.md +166 -0
- package/dist/components/Avatar/index.css +128 -0
- package/dist/components/Backdrop/Backdrop.svelte +8 -2
- package/dist/components/Backdrop/Backdrop.svelte.d.ts +1 -0
- package/dist/components/Backdrop/README.md +71 -6
- package/dist/components/Backdrop/index.css +29 -0
- package/dist/components/Button/Button.svelte +117 -124
- package/dist/components/Button/Button.svelte.d.ts +35 -23
- package/dist/components/Button/README.md +87 -21
- package/dist/components/Button/index.css +473 -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 -38
- package/dist/components/ButtonGroupRadio/README.md +82 -4
- package/dist/components/ButtonGroupRadio/index.css +152 -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 +38 -0
- package/dist/components/CommandMenu/CommandMenu.svelte +13 -24
- package/dist/components/CommandMenu/README.md +39 -0
- package/dist/components/CommandMenu/index.css +45 -2
- package/dist/components/DismissibleMessage/DismissibleMessage.svelte +53 -50
- package/dist/components/DismissibleMessage/DismissibleMessage.svelte.d.ts +6 -5
- package/dist/components/DismissibleMessage/README.md +93 -11
- package/dist/components/DismissibleMessage/index.css +122 -8
- package/dist/components/DismissibleMessage/index.d.ts +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.svelte +14 -50
- package/dist/components/DropdownMenu/DropdownMenu.svelte.d.ts +6 -6
- package/dist/components/DropdownMenu/README.md +132 -0
- package/dist/components/DropdownMenu/index.css +231 -27
- 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 +1 -1
- package/dist/components/Input/FieldOptions.svelte +41 -38
- 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 +522 -127
- package/dist/components/ListItemButton/ListItemButton.svelte +37 -73
- package/dist/components/ListItemButton/ListItemButton.svelte.d.ts +1 -9
- package/dist/components/ListItemButton/README.md +100 -45
- package/dist/components/ListItemButton/index.css +175 -56
- package/dist/components/ListItemButton/index.d.ts +1 -1
- package/dist/components/ListItemButton/index.js +1 -1
- package/dist/components/Modal/Modal.svelte +2 -8
- package/dist/components/Modal/Modal.svelte.d.ts +1 -0
- package/dist/components/Modal/README.md +29 -0
- package/dist/components/Modal/index.css +36 -0
- package/dist/components/ModalDialog/ModalDialog.svelte +2 -21
- package/dist/components/ModalDialog/README.md +35 -0
- package/dist/components/ModalDialog/index.css +57 -0
- package/dist/components/Notifications/Notifications.svelte +44 -128
- package/dist/components/Notifications/Notifications.svelte.d.ts +9 -17
- package/dist/components/Notifications/README.md +186 -70
- package/dist/components/Notifications/index.css +212 -15
- package/dist/components/Progress/README.md +15 -0
- package/dist/components/Progress/_internal/Bar.svelte +2 -2
- package/dist/components/Progress/index.css +4 -4
- package/dist/components/Skeleton/Skeleton.svelte +3 -2
- package/dist/components/Skeleton/index.css +11 -14
- package/dist/components/Spinner/Spinner.svelte +2 -2
- package/dist/components/Spinner/SpinnerCircle.svelte +1 -1
- package/dist/components/Switch/README.md +15 -0
- package/dist/components/Switch/Switch.svelte +4 -7
- package/dist/components/Switch/Switch.svelte.d.ts +1 -1
- package/dist/components/Switch/SwitchButton.svelte +4 -5
- package/dist/components/Switch/index.css +3 -4
- package/dist/components/TabbedMenu/README.md +26 -21
- package/dist/components/TabbedMenu/TabbedMenu.svelte +5 -5
- package/dist/components/TabbedMenu/index.css +7 -22
- package/dist/components/ThemePreview/README.md +289 -0
- package/dist/components/ThemePreview/ThemePreview.svelte +341 -0
- package/dist/components/ThemePreview/ThemePreview.svelte.d.ts +33 -0
- package/dist/components/ThemePreview/index.css +493 -0
- package/dist/components/ThemePreview/index.d.ts +1 -0
- package/dist/components/ThemePreview/index.js +1 -0
- package/dist/components/TwCheck/TwCheck.svelte +4 -4
- package/dist/components/TwCheck/index.css +3 -2
- package/dist/components/TypeaheadInput/TypeaheadInput.svelte +1 -1
- package/dist/components/X/X.svelte +16 -4
- 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 +31 -16
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/themes/blue-orange.css +163 -0
- package/dist/themes/blue-orange.d.ts +6 -0
- package/dist/themes/blue-orange.js +151 -0
- package/dist/themes/cyan-red.css +163 -0
- package/dist/themes/cyan-red.d.ts +6 -0
- package/dist/themes/cyan-red.js +151 -0
- package/dist/themes/cyan-slate.css +163 -0
- package/dist/themes/cyan-slate.d.ts +6 -0
- package/dist/themes/cyan-slate.js +151 -0
- package/dist/themes/emerald-pink.css +163 -0
- package/dist/themes/emerald-pink.d.ts +6 -0
- package/dist/themes/emerald-pink.js +151 -0
- package/dist/themes/fuchsia-emerald.css +163 -0
- package/dist/themes/fuchsia-emerald.d.ts +6 -0
- package/dist/themes/fuchsia-emerald.js +151 -0
- package/dist/themes/gray.css +163 -0
- package/dist/themes/gray.d.ts +6 -0
- package/dist/themes/gray.js +151 -0
- package/dist/themes/indigo-amber.css +163 -0
- package/dist/themes/indigo-amber.d.ts +6 -0
- package/dist/themes/indigo-amber.js +151 -0
- package/dist/themes/neutral.css +163 -0
- package/dist/themes/neutral.d.ts +6 -0
- package/dist/themes/neutral.js +151 -0
- package/dist/themes/pink-emerald.css +163 -0
- package/dist/themes/pink-emerald.d.ts +6 -0
- package/dist/themes/pink-emerald.js +151 -0
- package/dist/themes/purple-yellow.css +163 -0
- package/dist/themes/purple-yellow.d.ts +6 -0
- package/dist/themes/purple-yellow.js +151 -0
- package/dist/themes/rainbow.css +163 -0
- package/dist/themes/rainbow.d.ts +6 -0
- package/dist/themes/rainbow.js +156 -0
- package/dist/themes/red-blue.css +163 -0
- package/dist/themes/red-blue.d.ts +6 -0
- package/dist/themes/red-blue.js +151 -0
- package/dist/themes/red-cyan.css +163 -0
- package/dist/themes/red-cyan.d.ts +6 -0
- package/dist/themes/red-cyan.js +151 -0
- package/dist/themes/rose-teal.css +163 -0
- package/dist/themes/rose-teal.d.ts +6 -0
- package/dist/themes/rose-teal.js +151 -0
- package/dist/themes/sky-amber.css +163 -0
- package/dist/themes/sky-amber.d.ts +6 -0
- package/dist/themes/sky-amber.js +151 -0
- package/dist/themes/slate-cyan.css +163 -0
- package/dist/themes/slate-cyan.d.ts +6 -0
- package/dist/themes/slate-cyan.js +151 -0
- package/dist/themes/tailwind-color-pairs.md +31 -0
- package/dist/themes/teal-rose.css +163 -0
- package/dist/themes/teal-rose.d.ts +6 -0
- package/dist/themes/teal-rose.js +151 -0
- package/dist/themes/violet-lime.css +163 -0
- package/dist/themes/violet-lime.d.ts +6 -0
- package/dist/themes/violet-lime.js +151 -0
- package/dist/utils/design-tokens.d.ts +43 -0
- package/dist/utils/design-tokens.js +100 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +22 -2
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
active?: boolean;
|
|
11
11
|
/** Whether this item is currently focused via keyboard navigation */
|
|
12
12
|
focused?: boolean;
|
|
13
|
-
/** Size preset affecting padding and min-height (sm, md, lg) */
|
|
13
|
+
/** Size preset affecting padding and min-height (sm, md, lg) or custom Tailwind classes */
|
|
14
14
|
size?: "sm" | "md" | "lg" | string;
|
|
15
15
|
/** Skip all default styling, use only custom classes */
|
|
16
16
|
unstyled?: boolean;
|
|
@@ -35,57 +35,6 @@
|
|
|
35
35
|
/** Bindable element reference */
|
|
36
36
|
el?: HTMLButtonElement | HTMLAnchorElement;
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
export interface ListItemButtonPresetClasses {
|
|
40
|
-
size: Record<string, string>;
|
|
41
|
-
touchFriendly: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const LIST_ITEM_BUTTON_STUIC_BASE_CLASSES = `
|
|
45
|
-
w-full
|
|
46
|
-
flex items-center gap-2
|
|
47
|
-
text-left
|
|
48
|
-
rounded-[var(--lib-radius)]
|
|
49
|
-
cursor-pointer
|
|
50
|
-
touch-action-manipulation
|
|
51
|
-
|
|
52
|
-
bg-lib-bg dark:bg-lib-bg-dark
|
|
53
|
-
text-lib-text dark:text-lib-text-dark
|
|
54
|
-
|
|
55
|
-
border border-lib-border dark:border-lib-border-dark
|
|
56
|
-
|
|
57
|
-
hover:bg-lib-hover-bg dark:hover:bg-lib-hover-bg-dark
|
|
58
|
-
hover:text-lib-hover-text dark:hover:text-lib-hover-text-dark
|
|
59
|
-
hover:border-lib-hover-border dark:hover:border-lib-hover-border-dark
|
|
60
|
-
|
|
61
|
-
focus:outline-none
|
|
62
|
-
focus-visible:bg-lib-focus-bg dark:focus-visible:bg-lib-focus-bg-dark
|
|
63
|
-
focus-visible:text-lib-focus-text dark:focus-visible:text-lib-focus-text-dark
|
|
64
|
-
focus-visible:border-lib-focus-border dark:focus-visible:border-lib-focus-border-dark
|
|
65
|
-
|
|
66
|
-
disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
|
|
67
|
-
`;
|
|
68
|
-
|
|
69
|
-
export const LIST_ITEM_BUTTON_STUIC_PRESET_CLASSES: ListItemButtonPresetClasses = {
|
|
70
|
-
size: {
|
|
71
|
-
sm: `px-2 py-1.5 text-sm min-h-[36px]`,
|
|
72
|
-
md: `px-2.5 py-2 text-base min-h-[40px]`,
|
|
73
|
-
lg: `px-3 py-2.5 text-base min-h-[44px]`,
|
|
74
|
-
},
|
|
75
|
-
touchFriendly: `min-h-[44px] py-2.5`,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
export const LIST_ITEM_BUTTON_ACTIVE_CLASSES = `
|
|
79
|
-
bg-lib-active-bg dark:bg-lib-active-bg-dark
|
|
80
|
-
text-lib-active-text dark:text-lib-active-text-dark
|
|
81
|
-
border-lib-active-border dark:border-lib-active-border-dark
|
|
82
|
-
`;
|
|
83
|
-
|
|
84
|
-
export const LIST_ITEM_BUTTON_FOCUSED_CLASSES = `
|
|
85
|
-
bg-lib-focus-bg dark:bg-lib-focus-bg-dark
|
|
86
|
-
text-lib-focus-text dark:text-lib-focus-text-dark
|
|
87
|
-
border-lib-focus-border dark:border-lib-focus-border-dark
|
|
88
|
-
`;
|
|
89
38
|
</script>
|
|
90
39
|
|
|
91
40
|
<script lang="ts">
|
|
@@ -115,31 +64,28 @@
|
|
|
115
64
|
|
|
116
65
|
const devicePointer = new DevicePointer();
|
|
117
66
|
|
|
118
|
-
|
|
119
|
-
const
|
|
67
|
+
// Check if size is a known preset
|
|
68
|
+
const isPresetSize = (s: string): s is "sm" | "md" | "lg" =>
|
|
69
|
+
["sm", "md", "lg"].includes(s);
|
|
120
70
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (touchFriendly ===
|
|
124
|
-
|
|
71
|
+
// Compute whether touch-friendly should be active
|
|
72
|
+
let isTouchFriendly = $derived.by(() => {
|
|
73
|
+
if (touchFriendly === true) return true;
|
|
74
|
+
if (touchFriendly === "auto" && devicePointer.isCoarse) return true;
|
|
75
|
+
return false;
|
|
125
76
|
});
|
|
126
77
|
|
|
78
|
+
// Build class string - styling is handled by CSS + data attributes
|
|
127
79
|
let _class = $derived(
|
|
128
|
-
|
|
129
|
-
"stuic-list-item-button",
|
|
130
|
-
size
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
!unstyled && _base,
|
|
134
|
-
!unstyled && size && _preset.size[size],
|
|
135
|
-
!unstyled && _touchClasses,
|
|
136
|
-
!unstyled && active && LIST_ITEM_BUTTON_ACTIVE_CLASSES,
|
|
137
|
-
!unstyled && focused && !active && LIST_ITEM_BUTTON_FOCUSED_CLASSES,
|
|
80
|
+
twMerge(
|
|
81
|
+
!unstyled && "stuic-list-item-button",
|
|
82
|
+
// Custom size classes when not using preset
|
|
83
|
+
!unstyled && !isPresetSize(size) && size,
|
|
84
|
+
// User-provided state classes
|
|
138
85
|
active && classActive,
|
|
139
86
|
focused && !active && classFocused,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
.join(" ")
|
|
87
|
+
classProp
|
|
88
|
+
)
|
|
143
89
|
);
|
|
144
90
|
</script>
|
|
145
91
|
|
|
@@ -160,11 +106,29 @@
|
|
|
160
106
|
{/snippet}
|
|
161
107
|
|
|
162
108
|
{#if href}
|
|
163
|
-
<a
|
|
109
|
+
<a
|
|
110
|
+
{href}
|
|
111
|
+
bind:this={el}
|
|
112
|
+
class={_class}
|
|
113
|
+
data-size={!unstyled && isPresetSize(size) ? size : undefined}
|
|
114
|
+
data-active={!unstyled && active ? "" : undefined}
|
|
115
|
+
data-focused={!unstyled && focused ? "" : undefined}
|
|
116
|
+
data-touch-friendly={!unstyled && isTouchFriendly ? "" : undefined}
|
|
117
|
+
{...rest as any}
|
|
118
|
+
>
|
|
164
119
|
{@render content()}
|
|
165
120
|
</a>
|
|
166
121
|
{:else}
|
|
167
|
-
<button
|
|
122
|
+
<button
|
|
123
|
+
bind:this={el}
|
|
124
|
+
class={_class}
|
|
125
|
+
type="button"
|
|
126
|
+
data-size={!unstyled && isPresetSize(size) ? size : undefined}
|
|
127
|
+
data-active={!unstyled && active ? "" : undefined}
|
|
128
|
+
data-focused={!unstyled && focused ? "" : undefined}
|
|
129
|
+
data-touch-friendly={!unstyled && isTouchFriendly ? "" : undefined}
|
|
130
|
+
{...rest}
|
|
131
|
+
>
|
|
168
132
|
{@render content()}
|
|
169
133
|
</button>
|
|
170
134
|
{/if}
|
|
@@ -8,7 +8,7 @@ export interface Props extends Omit<HTMLButtonAttributes, "children" | "class">
|
|
|
8
8
|
active?: boolean;
|
|
9
9
|
/** Whether this item is currently focused via keyboard navigation */
|
|
10
10
|
focused?: boolean;
|
|
11
|
-
/** Size preset affecting padding and min-height (sm, md, lg) */
|
|
11
|
+
/** Size preset affecting padding and min-height (sm, md, lg) or custom Tailwind classes */
|
|
12
12
|
size?: "sm" | "md" | "lg" | string;
|
|
13
13
|
/** Skip all default styling, use only custom classes */
|
|
14
14
|
unstyled?: boolean;
|
|
@@ -33,14 +33,6 @@ export interface Props extends Omit<HTMLButtonAttributes, "children" | "class">
|
|
|
33
33
|
/** Bindable element reference */
|
|
34
34
|
el?: HTMLButtonElement | HTMLAnchorElement;
|
|
35
35
|
}
|
|
36
|
-
export interface ListItemButtonPresetClasses {
|
|
37
|
-
size: Record<string, string>;
|
|
38
|
-
touchFriendly: string;
|
|
39
|
-
}
|
|
40
|
-
export declare const LIST_ITEM_BUTTON_STUIC_BASE_CLASSES = "\n\t\tw-full\n\t\tflex items-center gap-2\n\t\ttext-left\n\t\trounded-[var(--lib-radius)]\n\t\tcursor-pointer\n\t\ttouch-action-manipulation\n\n\t\tbg-lib-bg dark:bg-lib-bg-dark\n\t\ttext-lib-text dark:text-lib-text-dark\n\n\t\tborder border-lib-border dark:border-lib-border-dark\n\n\t\thover:bg-lib-hover-bg dark:hover:bg-lib-hover-bg-dark\n\t\thover:text-lib-hover-text dark:hover:text-lib-hover-text-dark\n\t\thover:border-lib-hover-border dark:hover:border-lib-hover-border-dark\n\n\t\tfocus:outline-none\n\t\tfocus-visible:bg-lib-focus-bg dark:focus-visible:bg-lib-focus-bg-dark\n\t\tfocus-visible:text-lib-focus-text dark:focus-visible:text-lib-focus-text-dark\n\t\tfocus-visible:border-lib-focus-border dark:focus-visible:border-lib-focus-border-dark\n\n\t\tdisabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none\n\t";
|
|
41
|
-
export declare const LIST_ITEM_BUTTON_STUIC_PRESET_CLASSES: ListItemButtonPresetClasses;
|
|
42
|
-
export declare const LIST_ITEM_BUTTON_ACTIVE_CLASSES = "\n\t\tbg-lib-active-bg dark:bg-lib-active-bg-dark\n\t\ttext-lib-active-text dark:text-lib-active-text-dark\n\t\tborder-lib-active-border dark:border-lib-active-border-dark\n\t";
|
|
43
|
-
export declare const LIST_ITEM_BUTTON_FOCUSED_CLASSES = "\n\t\tbg-lib-focus-bg dark:bg-lib-focus-bg-dark\n\t\ttext-lib-focus-text dark:text-lib-focus-text-dark\n\t\tborder-lib-focus-border dark:border-lib-focus-border-dark\n\t";
|
|
44
36
|
import "./index.css";
|
|
45
37
|
declare const ListItemButton: import("svelte").Component<Props, {}, "el">;
|
|
46
38
|
type ListItemButton = ReturnType<typeof ListItemButton>;
|
|
@@ -19,7 +19,7 @@ A versatile button component for list-like contexts such as dropdown menus, comm
|
|
|
19
19
|
| `children` | `Snippet` | - | Content displayed in the button |
|
|
20
20
|
| `active` | `boolean` | `false` | Whether this item is currently active/selected |
|
|
21
21
|
| `focused` | `boolean` | `false` | Whether this item is focused via keyboard navigation |
|
|
22
|
-
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Size preset
|
|
22
|
+
| `size` | `"sm" \| "md" \| "lg" \| string` | `"md"` | Size preset or custom Tailwind classes |
|
|
23
23
|
| `unstyled` | `boolean` | `false` | Skip all default styling, use only custom classes |
|
|
24
24
|
| `touchFriendly` | `boolean \| "auto"` | `false` | Enable touch-friendly sizing. `"auto"` detects coarse pointer. |
|
|
25
25
|
| `contentBefore` | `THC` | - | Icon/content displayed before the main content |
|
|
@@ -100,81 +100,136 @@ A versatile button component for list-like contexts such as dropdown menus, comm
|
|
|
100
100
|
|
|
101
101
|
## CSS Variables
|
|
102
102
|
|
|
103
|
-
All
|
|
103
|
+
All styling can be customized via CSS variables. Define them on a parent element or in `:root` to override defaults.
|
|
104
104
|
|
|
105
|
-
###
|
|
105
|
+
### Structure Tokens
|
|
106
106
|
|
|
107
107
|
| Variable | Default | Description |
|
|
108
108
|
|----------|---------|-------------|
|
|
109
|
-
| `--
|
|
109
|
+
| `--stuic-list-item-button-radius` | `var(--radius-md)` | Border radius |
|
|
110
|
+
| `--stuic-list-item-button-transition` | `150ms` | Transition duration |
|
|
111
|
+
| `--stuic-list-item-button-gap` | `0.5rem` | Gap between icon and content |
|
|
110
112
|
|
|
111
|
-
###
|
|
113
|
+
### Focus Ring Tokens
|
|
112
114
|
|
|
113
115
|
| Variable | Default | Description |
|
|
114
116
|
|----------|---------|-------------|
|
|
115
|
-
| `--
|
|
116
|
-
| `--
|
|
117
|
-
| `--
|
|
118
|
-
| `--color-lib-text-dark` | `neutral-100` | Text color (dark mode) |
|
|
119
|
-
| `--color-lib-border` | `transparent` | Border color |
|
|
120
|
-
| `--color-lib-border-dark` | `transparent` | Border color (dark mode) |
|
|
117
|
+
| `--stuic-list-item-button-ring-width` | `3px` | Focus ring width |
|
|
118
|
+
| `--stuic-list-item-button-ring-offset` | `0px` | Focus ring offset |
|
|
119
|
+
| `--stuic-list-item-button-ring-color` | `var(--stuic-color-ring)` | Focus ring color |
|
|
121
120
|
|
|
122
|
-
###
|
|
121
|
+
### Size Tokens: Small (`size="sm"`)
|
|
123
122
|
|
|
124
123
|
| Variable | Default | Description |
|
|
125
124
|
|----------|---------|-------------|
|
|
126
|
-
| `--
|
|
127
|
-
| `--
|
|
128
|
-
| `--
|
|
129
|
-
| `--
|
|
130
|
-
| `--color-lib-hover-border` | `transparent` | Hover border color |
|
|
131
|
-
| `--color-lib-hover-border-dark` | `transparent` | Hover border color (dark mode) |
|
|
125
|
+
| `--stuic-list-item-button-padding-x-sm` | `0.5rem` | Horizontal padding |
|
|
126
|
+
| `--stuic-list-item-button-padding-y-sm` | `0.375rem` | Vertical padding |
|
|
127
|
+
| `--stuic-list-item-button-font-size-sm` | `var(--text-sm)` | Font size |
|
|
128
|
+
| `--stuic-list-item-button-min-height-sm` | `2.25rem` | Minimum height (36px) |
|
|
132
129
|
|
|
133
|
-
###
|
|
130
|
+
### Size Tokens: Medium (`size="md"`)
|
|
134
131
|
|
|
135
132
|
| Variable | Default | Description |
|
|
136
133
|
|----------|---------|-------------|
|
|
137
|
-
| `--
|
|
138
|
-
| `--
|
|
139
|
-
| `--
|
|
140
|
-
| `--
|
|
141
|
-
| `--color-lib-active-border` | `transparent` | Active border color |
|
|
142
|
-
| `--color-lib-active-border-dark` | `transparent` | Active border color (dark mode) |
|
|
134
|
+
| `--stuic-list-item-button-padding-x-md` | `0.625rem` | Horizontal padding |
|
|
135
|
+
| `--stuic-list-item-button-padding-y-md` | `0.5rem` | Vertical padding |
|
|
136
|
+
| `--stuic-list-item-button-font-size-md` | `var(--text-base)` | Font size |
|
|
137
|
+
| `--stuic-list-item-button-min-height-md` | `2.5rem` | Minimum height (40px) |
|
|
143
138
|
|
|
144
|
-
###
|
|
139
|
+
### Size Tokens: Large (`size="lg"`)
|
|
145
140
|
|
|
146
141
|
| Variable | Default | Description |
|
|
147
142
|
|----------|---------|-------------|
|
|
148
|
-
| `--
|
|
149
|
-
| `--
|
|
150
|
-
| `--
|
|
151
|
-
| `--
|
|
152
|
-
|
|
153
|
-
|
|
143
|
+
| `--stuic-list-item-button-padding-x-lg` | `0.75rem` | Horizontal padding |
|
|
144
|
+
| `--stuic-list-item-button-padding-y-lg` | `0.625rem` | Vertical padding |
|
|
145
|
+
| `--stuic-list-item-button-font-size-lg` | `var(--text-base)` | Font size |
|
|
146
|
+
| `--stuic-list-item-button-min-height-lg` | `2.75rem` | Minimum height (44px) |
|
|
147
|
+
|
|
148
|
+
### Touch-Friendly Tokens
|
|
149
|
+
|
|
150
|
+
| Variable | Default | Description |
|
|
151
|
+
|----------|---------|-------------|
|
|
152
|
+
| `--stuic-list-item-button-min-height-touch` | `2.75rem` | Touch-friendly min height (44px) |
|
|
153
|
+
| `--stuic-list-item-button-padding-y-touch` | `0.625rem` | Touch-friendly vertical padding |
|
|
154
|
+
|
|
155
|
+
### Color Tokens: Base State
|
|
156
|
+
|
|
157
|
+
| Variable | Default | Description |
|
|
158
|
+
|----------|---------|-------------|
|
|
159
|
+
| `--stuic-list-item-button-bg` | `var(--stuic-color-muted)` | Background color |
|
|
160
|
+
| `--stuic-list-item-button-text` | `var(--stuic-color-foreground)` | Text color |
|
|
161
|
+
| `--stuic-list-item-button-border` | `transparent` | Border color |
|
|
162
|
+
|
|
163
|
+
### Color Tokens: Hover State
|
|
164
|
+
|
|
165
|
+
| Variable | Default | Description |
|
|
166
|
+
|----------|---------|-------------|
|
|
167
|
+
| `--stuic-list-item-button-bg-hover` | `var(--stuic-color-primary)` | Hover background |
|
|
168
|
+
| `--stuic-list-item-button-text-hover` | `var(--stuic-color-primary-foreground)` | Hover text color |
|
|
169
|
+
| `--stuic-list-item-button-border-hover` | `transparent` | Hover border color |
|
|
170
|
+
|
|
171
|
+
### Color Tokens: Active State (selected)
|
|
172
|
+
|
|
173
|
+
| Variable | Default | Description |
|
|
174
|
+
|----------|---------|-------------|
|
|
175
|
+
| `--stuic-list-item-button-bg-active` | `var(--stuic-color-primary)` | Active background |
|
|
176
|
+
| `--stuic-list-item-button-text-active` | `var(--stuic-color-primary-foreground)` | Active text color |
|
|
177
|
+
| `--stuic-list-item-button-border-active` | `transparent` | Active border color |
|
|
178
|
+
|
|
179
|
+
### Color Tokens: Focus State (keyboard navigation)
|
|
180
|
+
|
|
181
|
+
| Variable | Default | Description |
|
|
182
|
+
|----------|---------|-------------|
|
|
183
|
+
| `--stuic-list-item-button-bg-focus` | `var(--stuic-color-primary)` | Focus background |
|
|
184
|
+
| `--stuic-list-item-button-text-focus` | `var(--stuic-color-primary-foreground)` | Focus text color |
|
|
185
|
+
| `--stuic-list-item-button-border-focus` | `transparent` | Focus border color |
|
|
154
186
|
|
|
155
187
|
### Custom Theme Example
|
|
156
188
|
|
|
157
189
|
```svelte
|
|
158
190
|
<div style="
|
|
159
|
-
--
|
|
160
|
-
--
|
|
161
|
-
--color-lib-active-bg: var(--color-blue-600);
|
|
162
|
-
--color-lib-active-bg-dark: var(--color-blue-500);
|
|
191
|
+
--stuic-list-item-button-bg-hover: var(--color-blue-500);
|
|
192
|
+
--stuic-list-item-button-bg-active: var(--color-blue-600);
|
|
163
193
|
">
|
|
164
194
|
<ListItemButton>Blue theme</ListItemButton>
|
|
165
195
|
<ListItemButton active>Active blue</ListItemButton>
|
|
166
196
|
</div>
|
|
167
197
|
```
|
|
168
198
|
|
|
169
|
-
|
|
199
|
+
### Global Theme Override
|
|
200
|
+
|
|
201
|
+
```css
|
|
202
|
+
/* In your app.css */
|
|
203
|
+
:root {
|
|
204
|
+
--stuic-list-item-button-radius: 0;
|
|
205
|
+
--stuic-list-item-button-bg-hover: var(--color-indigo-500);
|
|
206
|
+
--stuic-list-item-button-text-hover: white;
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Data Attributes
|
|
211
|
+
|
|
212
|
+
The component uses data attributes for styling states. These are automatically applied based on props:
|
|
213
|
+
|
|
214
|
+
| Attribute | Applied When | CSS Selector |
|
|
215
|
+
|-----------|--------------|--------------|
|
|
216
|
+
| `data-size="sm\|md\|lg"` | When `size` is a preset value | `.stuic-list-item-button[data-size="md"]` |
|
|
217
|
+
| `data-active` | When `active={true}` | `.stuic-list-item-button[data-active]` |
|
|
218
|
+
| `data-focused` | When `focused={true}` | `.stuic-list-item-button[data-focused]` |
|
|
219
|
+
| `data-touch-friendly` | When `touchFriendly={true}` or auto-detected | `.stuic-list-item-button[data-touch-friendly]` |
|
|
220
|
+
|
|
221
|
+
### Custom Styling via Data Attributes
|
|
170
222
|
|
|
171
|
-
|
|
223
|
+
```css
|
|
224
|
+
/* Example: Custom active state styling */
|
|
225
|
+
.stuic-list-item-button[data-active] {
|
|
226
|
+
background: var(--color-green-500);
|
|
227
|
+
color: white;
|
|
228
|
+
}
|
|
172
229
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
LIST_ITEM_BUTTON_FOCUSED_CLASSES,
|
|
179
|
-
} from "stuic";
|
|
230
|
+
/* Example: Different padding for all sizes */
|
|
231
|
+
.stuic-list-item-button[data-size] {
|
|
232
|
+
padding-left: 1rem;
|
|
233
|
+
padding-right: 1rem;
|
|
234
|
+
}
|
|
180
235
|
```
|
|
@@ -1,58 +1,177 @@
|
|
|
1
|
-
/*
|
|
1
|
+
/* =============================================================================
|
|
2
|
+
LIST ITEM BUTTON COMPONENT TOKENS
|
|
3
|
+
Override globally: :root { --stuic-list-item-button-radius: 0; }
|
|
4
|
+
Override locally: <ListItemButton style="--stuic-list-item-button-radius: 9999px;">
|
|
5
|
+
============================================================================= */
|
|
6
|
+
|
|
2
7
|
:root {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
--
|
|
15
|
-
--
|
|
16
|
-
|
|
17
|
-
--
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
--
|
|
21
|
-
|
|
22
|
-
--
|
|
23
|
-
--
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
--
|
|
29
|
-
--
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
--
|
|
33
|
-
--
|
|
34
|
-
|
|
35
|
-
/*
|
|
36
|
-
--
|
|
37
|
-
--
|
|
38
|
-
--
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
--
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
--
|
|
47
|
-
--
|
|
48
|
-
--
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
--
|
|
53
|
-
--
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
8
|
+
/* Structure tokens */
|
|
9
|
+
--stuic-list-item-button-radius: var(--radius-md);
|
|
10
|
+
--stuic-list-item-button-transition: 150ms;
|
|
11
|
+
--stuic-list-item-button-gap: 0.5rem;
|
|
12
|
+
|
|
13
|
+
/* Focus ring */
|
|
14
|
+
--stuic-list-item-button-ring-width: 3px;
|
|
15
|
+
--stuic-list-item-button-ring-offset: 0px;
|
|
16
|
+
--stuic-list-item-button-ring-color: var(--stuic-color-ring);
|
|
17
|
+
|
|
18
|
+
/* Size: sm */
|
|
19
|
+
--stuic-list-item-button-padding-x-sm: 0.5rem;
|
|
20
|
+
--stuic-list-item-button-padding-y-sm: 0.375rem;
|
|
21
|
+
--stuic-list-item-button-font-size-sm: var(--text-sm);
|
|
22
|
+
--stuic-list-item-button-min-height-sm: 2.25rem; /* 36px */
|
|
23
|
+
|
|
24
|
+
/* Size: md */
|
|
25
|
+
--stuic-list-item-button-padding-x-md: 0.625rem;
|
|
26
|
+
--stuic-list-item-button-padding-y-md: 0.5rem;
|
|
27
|
+
--stuic-list-item-button-font-size-md: var(--text-base);
|
|
28
|
+
--stuic-list-item-button-min-height-md: 2.5rem; /* 40px */
|
|
29
|
+
|
|
30
|
+
/* Size: lg */
|
|
31
|
+
--stuic-list-item-button-padding-x-lg: 0.75rem;
|
|
32
|
+
--stuic-list-item-button-padding-y-lg: 0.625rem;
|
|
33
|
+
--stuic-list-item-button-font-size-lg: var(--text-base);
|
|
34
|
+
--stuic-list-item-button-min-height-lg: 2.75rem; /* 44px - Apple HIG minimum */
|
|
35
|
+
|
|
36
|
+
/* Touch-friendly modifier */
|
|
37
|
+
--stuic-list-item-button-min-height-touch: 2.75rem; /* 44px */
|
|
38
|
+
--stuic-list-item-button-padding-y-touch: 0.625rem;
|
|
39
|
+
|
|
40
|
+
/* Color tokens: Base state */
|
|
41
|
+
--stuic-list-item-button-bg: var(--stuic-color-muted);
|
|
42
|
+
--stuic-list-item-button-text: var(--stuic-color-foreground);
|
|
43
|
+
--stuic-list-item-button-border: transparent;
|
|
44
|
+
|
|
45
|
+
/* Color tokens: Hover state */
|
|
46
|
+
--stuic-list-item-button-bg-hover: var(--stuic-color-primary);
|
|
47
|
+
--stuic-list-item-button-text-hover: var(--stuic-color-primary-foreground);
|
|
48
|
+
--stuic-list-item-button-border-hover: transparent;
|
|
49
|
+
|
|
50
|
+
/* Color tokens: Active/Selected state */
|
|
51
|
+
--stuic-list-item-button-bg-active: var(--stuic-color-primary);
|
|
52
|
+
--stuic-list-item-button-text-active: var(--stuic-color-primary-foreground);
|
|
53
|
+
--stuic-list-item-button-border-active: transparent;
|
|
54
|
+
|
|
55
|
+
/* Color tokens: Focus state (keyboard navigation) */
|
|
56
|
+
--stuic-list-item-button-bg-focus: var(--stuic-color-primary);
|
|
57
|
+
--stuic-list-item-button-text-focus: var(--stuic-color-primary-foreground);
|
|
58
|
+
--stuic-list-item-button-border-focus: transparent;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* =============================================================================
|
|
62
|
+
BASE STYLES
|
|
63
|
+
============================================================================= */
|
|
64
|
+
|
|
65
|
+
.stuic-list-item-button {
|
|
66
|
+
/* Layout */
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
gap: var(--stuic-list-item-button-gap);
|
|
70
|
+
width: 100%;
|
|
71
|
+
|
|
72
|
+
/* Typography */
|
|
73
|
+
text-align: left;
|
|
74
|
+
text-decoration: none;
|
|
75
|
+
|
|
76
|
+
/* Box model */
|
|
77
|
+
border-width: 1px;
|
|
78
|
+
border-style: solid;
|
|
79
|
+
border-radius: var(--stuic-list-item-button-radius);
|
|
80
|
+
|
|
81
|
+
/* Colors */
|
|
82
|
+
background: var(--stuic-list-item-button-bg);
|
|
83
|
+
color: var(--stuic-list-item-button-text);
|
|
84
|
+
border-color: var(--stuic-list-item-button-border);
|
|
85
|
+
|
|
86
|
+
/* Interaction */
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
user-select: none;
|
|
89
|
+
-webkit-tap-highlight-color: transparent;
|
|
90
|
+
touch-action: manipulation;
|
|
91
|
+
transition:
|
|
92
|
+
background var(--stuic-list-item-button-transition),
|
|
93
|
+
color var(--stuic-list-item-button-transition),
|
|
94
|
+
border-color var(--stuic-list-item-button-transition);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* =============================================================================
|
|
98
|
+
STATE STYLES
|
|
99
|
+
============================================================================= */
|
|
100
|
+
|
|
101
|
+
/* Hover state */
|
|
102
|
+
.stuic-list-item-button:hover:not(:disabled):not([data-active]) {
|
|
103
|
+
background: var(--stuic-list-item-button-bg-hover);
|
|
104
|
+
color: var(--stuic-list-item-button-text-hover);
|
|
105
|
+
border-color: var(--stuic-list-item-button-border-hover);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Focus styles */
|
|
109
|
+
.stuic-list-item-button:focus {
|
|
110
|
+
outline: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.stuic-list-item-button:focus-visible:not([data-active]) {
|
|
114
|
+
background: var(--stuic-list-item-button-bg-focus);
|
|
115
|
+
color: var(--stuic-list-item-button-text-focus);
|
|
116
|
+
border-color: var(--stuic-list-item-button-border-focus);
|
|
117
|
+
outline: var(--stuic-list-item-button-ring-width) solid
|
|
118
|
+
var(--stuic-list-item-button-ring-color);
|
|
119
|
+
outline-offset: var(--stuic-list-item-button-ring-offset);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Active/Selected state (via data attribute) */
|
|
123
|
+
.stuic-list-item-button[data-active] {
|
|
124
|
+
background: var(--stuic-list-item-button-bg-active);
|
|
125
|
+
color: var(--stuic-list-item-button-text-active);
|
|
126
|
+
border-color: var(--stuic-list-item-button-border-active);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* Focused state (keyboard navigation highlight, distinct from focus-visible) */
|
|
130
|
+
.stuic-list-item-button[data-focused]:not([data-active]) {
|
|
131
|
+
background: var(--stuic-list-item-button-bg-focus);
|
|
132
|
+
color: var(--stuic-list-item-button-text-focus);
|
|
133
|
+
border-color: var(--stuic-list-item-button-border-focus);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Disabled state */
|
|
137
|
+
.stuic-list-item-button:disabled {
|
|
138
|
+
opacity: 0.5;
|
|
139
|
+
cursor: not-allowed;
|
|
140
|
+
pointer-events: none;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* =============================================================================
|
|
144
|
+
SIZE VARIANTS
|
|
145
|
+
============================================================================= */
|
|
146
|
+
|
|
147
|
+
.stuic-list-item-button[data-size="sm"] {
|
|
148
|
+
padding: var(--stuic-list-item-button-padding-y-sm)
|
|
149
|
+
var(--stuic-list-item-button-padding-x-sm);
|
|
150
|
+
font-size: var(--stuic-list-item-button-font-size-sm);
|
|
151
|
+
min-height: var(--stuic-list-item-button-min-height-sm);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.stuic-list-item-button[data-size="md"] {
|
|
155
|
+
padding: var(--stuic-list-item-button-padding-y-md)
|
|
156
|
+
var(--stuic-list-item-button-padding-x-md);
|
|
157
|
+
font-size: var(--stuic-list-item-button-font-size-md);
|
|
158
|
+
min-height: var(--stuic-list-item-button-min-height-md);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.stuic-list-item-button[data-size="lg"] {
|
|
162
|
+
padding: var(--stuic-list-item-button-padding-y-lg)
|
|
163
|
+
var(--stuic-list-item-button-padding-x-lg);
|
|
164
|
+
font-size: var(--stuic-list-item-button-font-size-lg);
|
|
165
|
+
min-height: var(--stuic-list-item-button-min-height-lg);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* =============================================================================
|
|
169
|
+
TOUCH-FRIENDLY MODIFIER
|
|
170
|
+
Ensures minimum 44px touch target per Apple HIG guidelines
|
|
171
|
+
============================================================================= */
|
|
172
|
+
|
|
173
|
+
.stuic-list-item-button[data-touch-friendly] {
|
|
174
|
+
min-height: var(--stuic-list-item-button-min-height-touch);
|
|
175
|
+
padding-top: var(--stuic-list-item-button-padding-y-touch);
|
|
176
|
+
padding-bottom: var(--stuic-list-item-button-padding-y-touch);
|
|
58
177
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as ListItemButton, type Props as ListItemButtonProps,
|
|
1
|
+
export { default as ListItemButton, type Props as ListItemButtonProps, } from "./ListItemButton.svelte";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as ListItemButton,
|
|
1
|
+
export { default as ListItemButton, } from "./ListItemButton.svelte";
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
<script lang="ts">
|
|
28
28
|
import ModalDialog from "../ModalDialog/ModalDialog.svelte";
|
|
29
29
|
import { twMerge } from "../../utils/tw-merge.js";
|
|
30
|
+
import "./index.css";
|
|
30
31
|
|
|
31
32
|
let {
|
|
32
33
|
visible = $bindable(false),
|
|
@@ -103,9 +104,8 @@
|
|
|
103
104
|
>
|
|
104
105
|
<div
|
|
105
106
|
class={twMerge(
|
|
106
|
-
"
|
|
107
|
+
"stuic-modal",
|
|
107
108
|
"flex flex-col overflow-hidden",
|
|
108
|
-
"rounded-none md:rounded-md",
|
|
109
109
|
"w-full flex-1",
|
|
110
110
|
classProp
|
|
111
111
|
)}
|
|
@@ -126,9 +126,3 @@
|
|
|
126
126
|
</div>
|
|
127
127
|
</div>
|
|
128
128
|
</ModalDialog>
|
|
129
|
-
|
|
130
|
-
<style>
|
|
131
|
-
.main {
|
|
132
|
-
scrollbar-width: thin;
|
|
133
|
-
}
|
|
134
|
-
</style>
|
|
@@ -20,6 +20,7 @@ export interface Props {
|
|
|
20
20
|
/** Disable body scroll lock when modal is open */
|
|
21
21
|
noScrollLock?: boolean;
|
|
22
22
|
}
|
|
23
|
+
import "./index.css";
|
|
23
24
|
declare const Modal: import("svelte").Component<Props, {
|
|
24
25
|
close: () => void;
|
|
25
26
|
open: (openerOrEvent?: null | HTMLElement | MouseEvent) => void;
|