svelora 3.0.1 → 3.0.2

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.
Files changed (107) hide show
  1. package/dist/Accordion/Accordion.svelte +66 -97
  2. package/dist/Alert/Alert.svelte +39 -64
  3. package/dist/Alert/Alert.svelte.d.ts +1 -1
  4. package/dist/Avatar/Avatar.svelte +35 -75
  5. package/dist/AvatarGroup/AvatarGroup.svelte +38 -55
  6. package/dist/Badge/Badge.svelte +28 -50
  7. package/dist/Banner/Banner.svelte +46 -41
  8. package/dist/Banner/Banner.svelte.d.ts +1 -1
  9. package/dist/Breadcrumb/Breadcrumb.svelte +32 -26
  10. package/dist/Button/Button.svelte +70 -138
  11. package/dist/Calendar/Calendar.svelte +94 -157
  12. package/dist/Calendar/Calendar.svelte.d.ts +1 -1
  13. package/dist/Card/Card.svelte +18 -31
  14. package/dist/Carousel/Carousel.svelte +118 -173
  15. package/dist/Checkbox/Checkbox.svelte +52 -97
  16. package/dist/CheckboxGroup/CheckboxGroup.svelte +62 -107
  17. package/dist/CheckboxGroup/CheckboxGroup.svelte.d.ts +1 -1
  18. package/dist/Chip/Chip.svelte +22 -34
  19. package/dist/CodeBlock/CodeBlock.svelte +42 -59
  20. package/dist/Collapsible/Collapsible.svelte +22 -38
  21. package/dist/Collapsible/Collapsible.svelte.d.ts +1 -1
  22. package/dist/Collapsible/CollapsibleTestWrapper.svelte +2 -5
  23. package/dist/Collapsible/CollapsibleTestWrapper.svelte.d.ts +1 -1
  24. package/dist/Command/Command.svelte +40 -77
  25. package/dist/Command/Command.svelte.d.ts +1 -1
  26. package/dist/Command/CommandTestWrapper.svelte +2 -10
  27. package/dist/Command/CommandTestWrapper.svelte.d.ts +1 -1
  28. package/dist/Container/Container.svelte +11 -14
  29. package/dist/ContextMenu/ContextMenu.svelte +51 -114
  30. package/dist/ContextMenu/ContextMenu.svelte.d.ts +1 -1
  31. package/dist/Drawer/Drawer.svelte +72 -110
  32. package/dist/Drawer/DrawerTriggerTestWrapper.svelte +1 -2
  33. package/dist/DropdownMenu/DropdownMenu.svelte +63 -124
  34. package/dist/DropdownMenu/DropdownMenu.svelte.d.ts +1 -1
  35. package/dist/DropdownMenu/DropdownMenuTriggerTestWrapper.svelte +2 -5
  36. package/dist/Editor/Editor.svelte +441 -576
  37. package/dist/Editor/Editor.svelte.d.ts +1 -1
  38. package/dist/Editor/EditorUrlPrompt.svelte +40 -53
  39. package/dist/Editor/SlashPopup.svelte +12 -24
  40. package/dist/Empty/Empty.svelte +32 -63
  41. package/dist/FieldGroup/FieldGroup.svelte +23 -38
  42. package/dist/FileUpload/FileUpload.svelte +242 -320
  43. package/dist/FileUpload/FileUpload.svelte.d.ts +1 -1
  44. package/dist/Fonts/Fonts.svelte +15 -37
  45. package/dist/Form/Form.svelte +112 -170
  46. package/dist/FormField/FormField.svelte +102 -135
  47. package/dist/Icon/Icon.svelte +7 -32
  48. package/dist/Input/Input.svelte +71 -141
  49. package/dist/Input/Input.svelte.d.ts +2 -2
  50. package/dist/Kbd/Kbd.svelte +18 -34
  51. package/dist/Link/Link.svelte +129 -196
  52. package/dist/LocaleButton/LocaleButton.svelte +165 -0
  53. package/dist/LocaleButton/LocaleButton.svelte.d.ts +5 -0
  54. package/dist/LocaleButton/index.d.ts +2 -0
  55. package/dist/LocaleButton/index.js +1 -0
  56. package/dist/LocaleButton/locale-button.types.d.ts +182 -0
  57. package/dist/LocaleButton/locale-button.types.js +1 -0
  58. package/dist/LocaleButton/locale-button.variants.d.ts +61 -0
  59. package/dist/LocaleButton/locale-button.variants.js +34 -0
  60. package/dist/Modal/Modal.svelte +52 -106
  61. package/dist/Modal/ModalTriggerTestWrapper.svelte +1 -2
  62. package/dist/Pagination/Pagination.svelte +48 -92
  63. package/dist/Pagination/pagination.variants.d.ts +1 -1
  64. package/dist/PinInput/PinInput.svelte +57 -111
  65. package/dist/PinInput/PinInput.svelte.d.ts +1 -1
  66. package/dist/Popover/Popover.svelte +28 -61
  67. package/dist/Popover/Popover.svelte.d.ts +1 -1
  68. package/dist/Progress/Progress.svelte +75 -94
  69. package/dist/RadioGroup/RadioGroup.svelte +54 -99
  70. package/dist/RadioGroup/RadioGroup.svelte.d.ts +1 -1
  71. package/dist/Select/Select.svelte +112 -269
  72. package/dist/Select/Select.svelte.d.ts +1 -1
  73. package/dist/SelectMenu/SelectMenu.svelte +211 -409
  74. package/dist/SelectMenu/SelectMenu.svelte.d.ts +1 -1
  75. package/dist/SelectMenu/SelectMenuFormFieldTestWrapper.svelte +3 -6
  76. package/dist/Separator/Separator.svelte +29 -44
  77. package/dist/Skeleton/Skeleton.svelte +11 -23
  78. package/dist/Slideover/Slideover.svelte +52 -106
  79. package/dist/Slideover/SlideoverTriggerTestWrapper.svelte +1 -2
  80. package/dist/Slider/Slider.svelte +48 -84
  81. package/dist/Slider/Slider.svelte.d.ts +1 -1
  82. package/dist/Stepper/Stepper.svelte +139 -132
  83. package/dist/Stepper/Stepper.svelte.d.ts +1 -1
  84. package/dist/Switch/Switch.svelte +62 -98
  85. package/dist/Table/Table.svelte +232 -283
  86. package/dist/Table/table.variants.d.ts +1 -1
  87. package/dist/Tabs/Tabs.svelte +96 -129
  88. package/dist/Tabs/Tabs.svelte.d.ts +1 -1
  89. package/dist/Textarea/Textarea.svelte +90 -173
  90. package/dist/Textarea/Textarea.svelte.d.ts +1 -1
  91. package/dist/ThemeModeButton/ThemeModeButton.svelte +16 -38
  92. package/dist/Timeline/Timeline.svelte +75 -54
  93. package/dist/Toast/Toaster.svelte +8 -25
  94. package/dist/Tooltip/Tooltip.svelte +34 -66
  95. package/dist/Tooltip/Tooltip.svelte.d.ts +1 -1
  96. package/dist/Tooltip/TooltipTestWrapper.svelte +2 -5
  97. package/dist/User/User.svelte +33 -49
  98. package/dist/docs/navigation.js +6 -0
  99. package/dist/hooks/HookContextProbe.svelte +2 -4
  100. package/dist/hooks/HookContextProvider.svelte +8 -6
  101. package/dist/hooks/HookEmitProbe.svelte +8 -11
  102. package/dist/i18n.d.ts +2 -0
  103. package/dist/i18n.js +19 -0
  104. package/dist/index.d.ts +1 -0
  105. package/dist/index.js +1 -0
  106. package/dist/mcp/svelora-docs.data.json +4 -2
  107. package/package.json +16 -8
@@ -0,0 +1,165 @@
1
+ <script lang="ts" module>export {};
2
+ </script>
3
+
4
+ <script lang="ts">import Button from "../Button/Button.svelte";
5
+ import { getComponentConfig, iconsDefaults } from "../config.js";
6
+ import DropdownMenu from "../DropdownMenu/DropdownMenu.svelte";
7
+ import Icon from "../Icon/Icon.svelte";
8
+ import Link from "../Link/Link.svelte";
9
+ import { localeButtonDefaults, localeButtonVariants } from "./locale-button.variants.js";
10
+ const config = getComponentConfig("localeButton", localeButtonDefaults);
11
+ const icons = getComponentConfig("icons", iconsDefaults);
12
+ let { locales = [], locale, variant = config.defaultVariants.variant ?? "outline", color = config.defaultVariants.color ?? "surface", size = config.defaultVariants.size ?? "md", loading = false, disabled = false, block = false, square = false, placeholder = "Select language", ariaLabel = "Change language", menuLabel = "Language", icon = "lucide:languages", chevronIcon = icons.chevronDown, showIcon = true, showChevron = true, showCode = true, showIndicator = true, disableCurrentLocale = true, closeOnSelect = true, getLocaleHref, onLocaleChange, open = $bindable(false), onOpenChange, side = "bottom", sideOffset = 4, align = "start", alignOffset = 0, avoidCollisions = true, collisionBoundary, collisionPadding = 8, sticky = "partial", hideWhenDetached = false, onEscapeKeydown, onInteractOutside, onCloseAutoFocus, forceMount, loop = true, portal = true, arrow = false, ui, children: triggerContent, class: className, ...restProps } = $props();
13
+ const slots = localeButtonVariants();
14
+ const classes = $derived({
15
+ base: slots.base({ class: [
16
+ config.slots.base,
17
+ className,
18
+ ui?.base
19
+ ] }),
20
+ triggerLabel: slots.triggerLabel({ class: [config.slots.triggerLabel, ui?.triggerLabel] }),
21
+ triggerIcon: slots.triggerIcon({ class: [config.slots.triggerIcon, ui?.triggerIcon] }),
22
+ triggerChevron: slots.triggerChevron({ class: [config.slots.triggerChevron, ui?.triggerChevron] }),
23
+ menu: slots.menu({ class: [config.slots.menu, ui?.menu] }),
24
+ menuLabel: slots.menuLabel({ class: [config.slots.menuLabel, ui?.menuLabel] }),
25
+ item: slots.item({ class: [config.slots.item, ui?.item] }),
26
+ itemIdle: slots.itemIdle({ class: [config.slots.itemIdle, ui?.itemIdle] }),
27
+ itemCurrent: slots.itemCurrent({ class: [config.slots.itemCurrent, ui?.itemCurrent] }),
28
+ itemLeading: slots.itemLeading({ class: [config.slots.itemLeading, ui?.itemLeading] }),
29
+ itemText: slots.itemText({ class: [config.slots.itemText, ui?.itemText] }),
30
+ itemLabel: slots.itemLabel({ class: [config.slots.itemLabel, ui?.itemLabel] }),
31
+ itemDescription: slots.itemDescription({ class: [config.slots.itemDescription, ui?.itemDescription] }),
32
+ itemCode: slots.itemCode({ class: [config.slots.itemCode, ui?.itemCode] }),
33
+ itemIndicator: slots.itemIndicator({ class: [config.slots.itemIndicator, ui?.itemIndicator] })
34
+ });
35
+ const currentLocale = $derived(locales.find((item) => item.code === locale) ?? locales[0]);
36
+ const triggerLabel = $derived(currentLocale?.shortLabel ?? currentLocale?.label ?? placeholder);
37
+ const triggerDisabled = $derived(disabled || loading || locales.length <= 1);
38
+ function isCurrentLocale(item) {
39
+ return item.code === currentLocale?.code;
40
+ }
41
+ function getResolvedHref(item) {
42
+ return item.href ?? getLocaleHref?.(item.code, item);
43
+ }
44
+ function isItemDisabled(item) {
45
+ return disabled || loading || item.disabled || disableCurrentLocale && isCurrentLocale(item);
46
+ }
47
+ async function handleItemClick(event, item, close) {
48
+ if (isItemDisabled(item)) {
49
+ event.preventDefault();
50
+ event.stopPropagation();
51
+ return;
52
+ }
53
+ if (onLocaleChange) {
54
+ await onLocaleChange(item.code, item);
55
+ }
56
+ if (!getResolvedHref(item) && closeOnSelect) {
57
+ close();
58
+ }
59
+ }
60
+ </script>
61
+
62
+ <DropdownMenu
63
+ bind:open
64
+ {onOpenChange}
65
+ {side}
66
+ {sideOffset}
67
+ {align}
68
+ {alignOffset}
69
+ {avoidCollisions}
70
+ {collisionBoundary}
71
+ {collisionPadding}
72
+ {sticky}
73
+ {hideWhenDetached}
74
+ {onEscapeKeydown}
75
+ {onInteractOutside}
76
+ {onCloseAutoFocus}
77
+ {forceMount}
78
+ {loop}
79
+ {portal}
80
+ {arrow}
81
+ >
82
+ {#snippet children({ open: isOpen, props })}
83
+ <Button
84
+ {...props}
85
+ {variant}
86
+ {color}
87
+ {size}
88
+ {loading}
89
+ disabled={triggerDisabled}
90
+ {block}
91
+ {square}
92
+ class={classes.base}
93
+ aria-label={ariaLabel}
94
+ {...restProps}
95
+ >
96
+ {#if triggerContent}
97
+ {@render triggerContent({ open: isOpen, currentLocale })}
98
+ {:else}
99
+ {#if showIcon}
100
+ <span class={classes.triggerIcon}>
101
+ <Icon name={icon} />
102
+ </span>
103
+ {/if}
104
+ <span class={classes.triggerLabel}>{triggerLabel}</span>
105
+ {#if showChevron}
106
+ <span class={classes.triggerChevron}>
107
+ <Icon name={chevronIcon} />
108
+ </span>
109
+ {/if}
110
+ {/if}
111
+ </Button>
112
+ {/snippet}
113
+
114
+ {#snippet content({ close })}
115
+ <div class={classes.menu}>
116
+ {#if menuLabel}
117
+ <p class={classes.menuLabel}>{menuLabel}</p>
118
+ {/if}
119
+
120
+ {#each locales as item (item.code)}
121
+ {@const current = isCurrentLocale(item)}
122
+ {@const href = getResolvedHref(item)}
123
+ {@const itemDisabled = isItemDisabled(item)}
124
+
125
+ <Link
126
+ href={href}
127
+ hreflang={item.hreflang ?? item.code}
128
+ raw
129
+ role="menuitemradio"
130
+ aria-checked={current}
131
+ disabled={itemDisabled}
132
+ class={[
133
+ classes.item,
134
+ current ? classes.itemCurrent : classes.itemIdle,
135
+ item.class
136
+ ]}
137
+ onclick={(event) => handleItemClick(event, item, close)}
138
+ >
139
+ <span class={classes.itemLeading}>
140
+ {#if item.icon}
141
+ <Icon name={item.icon} />
142
+ {/if}
143
+ <span class={classes.itemText}>
144
+ <span class={classes.itemLabel}>{item.label}</span>
145
+ {#if item.description}
146
+ <span class={classes.itemDescription}>{item.description}</span>
147
+ {/if}
148
+ </span>
149
+ </span>
150
+
151
+ <span class="flex items-center gap-2">
152
+ {#if showCode}
153
+ <span class={classes.itemCode}>{item.shortLabel ?? item.code}</span>
154
+ {/if}
155
+ {#if showIndicator && current}
156
+ <span class={classes.itemIndicator}>
157
+ <Icon name={icons.check} />
158
+ </span>
159
+ {/if}
160
+ </span>
161
+ </Link>
162
+ {/each}
163
+ </div>
164
+ {/snippet}
165
+ </DropdownMenu>
@@ -0,0 +1,5 @@
1
+ import type { LocaleButtonProps } from './locale-button.types.js';
2
+ export type Props = LocaleButtonProps;
3
+ declare const LocaleButton: import("svelte").Component<LocaleButtonProps, {}, "open">;
4
+ type LocaleButton = ReturnType<typeof LocaleButton>;
5
+ export default LocaleButton;
@@ -0,0 +1,2 @@
1
+ export { default as LocaleButton } from './LocaleButton.svelte';
2
+ export type { LocaleButtonLocale, LocaleButtonProps } from './locale-button.types.js';
@@ -0,0 +1 @@
1
+ export { default as LocaleButton } from './LocaleButton.svelte';
@@ -0,0 +1,182 @@
1
+ import type { DropdownMenuContentPropsWithoutHTML, DropdownMenuRootPropsWithoutHTML } from 'bits-ui';
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import type { ClassNameValue } from 'tailwind-merge';
5
+ import type { ButtonVariantProps } from '../Button/button.variants.js';
6
+ import type { LocaleButtonSlots } from './locale-button.variants.js';
7
+ export type LocaleButtonLocale = {
8
+ /**
9
+ * Locale code used by your i18n layer, for example `en` or `th`.
10
+ */
11
+ code: string;
12
+ /**
13
+ * Full label rendered in the dropdown menu.
14
+ */
15
+ label: string;
16
+ /**
17
+ * Optional short label for the trigger, such as `EN` or `TH`.
18
+ */
19
+ shortLabel?: string;
20
+ /**
21
+ * Optional helper text shown below the label.
22
+ */
23
+ description?: string;
24
+ /**
25
+ * Optional static href for this locale.
26
+ */
27
+ href?: string;
28
+ /**
29
+ * Optional language tag forwarded to anchor items.
30
+ */
31
+ hreflang?: string;
32
+ /**
33
+ * Optional leading icon for the locale item.
34
+ */
35
+ icon?: string;
36
+ /**
37
+ * Disables this locale in the dropdown.
38
+ * @default false
39
+ */
40
+ disabled?: boolean;
41
+ /**
42
+ * Additional CSS classes for the locale item.
43
+ */
44
+ class?: ClassNameValue;
45
+ };
46
+ type RootProps = Pick<DropdownMenuRootPropsWithoutHTML, 'open' | 'onOpenChange'>;
47
+ type ContentProps = Pick<DropdownMenuContentPropsWithoutHTML, 'side' | 'sideOffset' | 'align' | 'alignOffset' | 'avoidCollisions' | 'collisionBoundary' | 'collisionPadding' | 'sticky' | 'hideWhenDetached' | 'onEscapeKeydown' | 'onInteractOutside' | 'onCloseAutoFocus' | 'forceMount' | 'loop'>;
48
+ export type LocaleButtonProps = Omit<HTMLAttributes<HTMLElement>, 'children' | 'class' | 'color'> & RootProps & ContentProps & {
49
+ /**
50
+ * Available locales shown in the menu.
51
+ */
52
+ locales: LocaleButtonLocale[];
53
+ /**
54
+ * Current active locale code.
55
+ */
56
+ locale?: string;
57
+ /**
58
+ * Controls the visual style of the trigger button.
59
+ * @default 'outline'
60
+ */
61
+ variant?: NonNullable<ButtonVariantProps['variant']>;
62
+ /**
63
+ * Sets the color scheme of the trigger button.
64
+ * @default 'surface'
65
+ */
66
+ color?: NonNullable<ButtonVariantProps['color']>;
67
+ /**
68
+ * Controls the trigger button size.
69
+ * @default 'md'
70
+ */
71
+ size?: NonNullable<ButtonVariantProps['size']>;
72
+ /**
73
+ * Renders a loading spinner and disables interaction.
74
+ * @default false
75
+ */
76
+ loading?: boolean;
77
+ /**
78
+ * Disables the trigger and all locale actions.
79
+ * @default false
80
+ */
81
+ disabled?: boolean;
82
+ /**
83
+ * Stretches the trigger to fill the available width.
84
+ * @default false
85
+ */
86
+ block?: boolean;
87
+ /**
88
+ * Forces equal width and height for the trigger button.
89
+ * @default false
90
+ */
91
+ square?: boolean;
92
+ /**
93
+ * Fallback text shown when no current locale is matched.
94
+ * @default 'Select language'
95
+ */
96
+ placeholder?: string;
97
+ /**
98
+ * Accessible label for the trigger button.
99
+ * @default 'Change language'
100
+ */
101
+ ariaLabel?: string;
102
+ /**
103
+ * Optional heading rendered above the locale list.
104
+ * @default 'Language'
105
+ */
106
+ menuLabel?: string;
107
+ /**
108
+ * Leading icon displayed in the trigger.
109
+ * @default 'lucide:languages'
110
+ */
111
+ icon?: string;
112
+ /**
113
+ * Trailing chevron icon displayed in the trigger.
114
+ * @default Uses `icons.chevronDown` from app config
115
+ */
116
+ chevronIcon?: string;
117
+ /**
118
+ * Whether to render the leading trigger icon.
119
+ * @default true
120
+ */
121
+ showIcon?: boolean;
122
+ /**
123
+ * Whether to render the trailing chevron icon.
124
+ * @default true
125
+ */
126
+ showChevron?: boolean;
127
+ /**
128
+ * Whether to render the locale code badge inside the menu.
129
+ * @default true
130
+ */
131
+ showCode?: boolean;
132
+ /**
133
+ * Whether to render the selected locale check icon.
134
+ * @default true
135
+ */
136
+ showIndicator?: boolean;
137
+ /**
138
+ * Disables the currently active locale item.
139
+ * @default true
140
+ */
141
+ disableCurrentLocale?: boolean;
142
+ /**
143
+ * Closes the menu after selecting a locale without href navigation.
144
+ * @default true
145
+ */
146
+ closeOnSelect?: boolean;
147
+ /**
148
+ * Resolves a locale-specific href, useful for Paraglide URL strategies.
149
+ */
150
+ getLocaleHref?: (locale: string, item: LocaleButtonLocale) => string | undefined;
151
+ /**
152
+ * Called when a locale is selected.
153
+ * Use this for integrations like `setLocale(...)`.
154
+ */
155
+ onLocaleChange?: (locale: string, item: LocaleButtonLocale) => void | Promise<void>;
156
+ /**
157
+ * Render custom trigger content.
158
+ */
159
+ children?: Snippet<[{
160
+ open: boolean;
161
+ currentLocale: LocaleButtonLocale | undefined;
162
+ }]>;
163
+ /**
164
+ * Whether to render the menu in a portal.
165
+ * @default true
166
+ */
167
+ portal?: boolean;
168
+ /**
169
+ * Display an arrow alongside the dropdown.
170
+ * @default false
171
+ */
172
+ arrow?: boolean;
173
+ /**
174
+ * Additional CSS classes for the trigger element.
175
+ */
176
+ class?: ClassNameValue;
177
+ /**
178
+ * Override classes for LocaleButton slots.
179
+ */
180
+ ui?: Partial<Record<LocaleButtonSlots, ClassNameValue>>;
181
+ };
182
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ import { type VariantProps } from 'tailwind-variants';
2
+ import type { ButtonVariantProps } from '../Button/button.variants.js';
3
+ export declare const localeButtonVariants: import("tailwind-variants").TVReturnType<{}, {
4
+ base: string;
5
+ triggerLabel: string;
6
+ triggerIcon: string;
7
+ triggerChevron: string;
8
+ menu: string;
9
+ menuLabel: string;
10
+ item: string[];
11
+ itemIdle: string;
12
+ itemCurrent: string;
13
+ itemLeading: string;
14
+ itemText: string;
15
+ itemLabel: string;
16
+ itemDescription: string;
17
+ itemCode: string;
18
+ itemIndicator: string;
19
+ }, undefined, {}, {
20
+ base: string;
21
+ triggerLabel: string;
22
+ triggerIcon: string;
23
+ triggerChevron: string;
24
+ menu: string;
25
+ menuLabel: string;
26
+ item: string[];
27
+ itemIdle: string;
28
+ itemCurrent: string;
29
+ itemLeading: string;
30
+ itemText: string;
31
+ itemLabel: string;
32
+ itemDescription: string;
33
+ itemCode: string;
34
+ itemIndicator: string;
35
+ }, import("tailwind-variants").TVReturnType<{}, {
36
+ base: string;
37
+ triggerLabel: string;
38
+ triggerIcon: string;
39
+ triggerChevron: string;
40
+ menu: string;
41
+ menuLabel: string;
42
+ item: string[];
43
+ itemIdle: string;
44
+ itemCurrent: string;
45
+ itemLeading: string;
46
+ itemText: string;
47
+ itemLabel: string;
48
+ itemDescription: string;
49
+ itemCode: string;
50
+ itemIndicator: string;
51
+ }, undefined, unknown, unknown, undefined>>;
52
+ export type LocaleButtonVariantProps = VariantProps<typeof localeButtonVariants>;
53
+ export type LocaleButtonSlots = keyof ReturnType<typeof localeButtonVariants>;
54
+ export declare const localeButtonDefaults: {
55
+ defaultVariants: {
56
+ color: NonNullable<ButtonVariantProps["color"]>;
57
+ variant: NonNullable<ButtonVariantProps["variant"]>;
58
+ size: NonNullable<ButtonVariantProps["size"]>;
59
+ };
60
+ slots: Partial<Record<LocaleButtonSlots, string>>;
61
+ };
@@ -0,0 +1,34 @@
1
+ import { tv } from 'tailwind-variants';
2
+ export const localeButtonVariants = tv({
3
+ slots: {
4
+ base: '',
5
+ triggerLabel: 'truncate',
6
+ triggerIcon: 'shrink-0',
7
+ triggerChevron: 'shrink-0 opacity-70',
8
+ menu: 'min-w-52 space-y-1 rounded-xl p-1',
9
+ menuLabel: 'px-3 pt-2 pb-1 text-xs font-semibold tracking-[0.14em] text-on-surface-variant uppercase',
10
+ item: [
11
+ 'flex w-full items-center justify-between gap-3 rounded-lg px-3 py-2 text-left text-sm transition-colors',
12
+ 'focus-visible:ring-primary/40 focus-visible:outline-none focus-visible:ring-2'
13
+ ],
14
+ itemIdle: 'text-on-surface hover:bg-surface-container-high',
15
+ itemCurrent: 'bg-primary/10 text-primary',
16
+ itemLeading: 'flex min-w-0 items-start gap-2.5',
17
+ itemText: 'min-w-0 space-y-0.5',
18
+ itemLabel: 'truncate font-medium',
19
+ itemDescription: 'text-xs text-on-surface-variant',
20
+ itemCode: 'shrink-0 rounded-md bg-surface-container px-1.5 py-0.5 text-[11px] font-medium text-on-surface-variant uppercase',
21
+ itemIndicator: 'shrink-0 text-primary'
22
+ },
23
+ variants: {},
24
+ defaultVariants: {}
25
+ });
26
+ export const localeButtonDefaults = {
27
+ defaultVariants: {
28
+ ...localeButtonVariants.defaultVariants,
29
+ color: 'surface',
30
+ variant: 'outline',
31
+ size: 'md'
32
+ },
33
+ slots: {}
34
+ };
@@ -1,111 +1,57 @@
1
- <script lang="ts" module>
2
- import type { ModalProps } from './modal.types.js'
3
-
4
- export type Props = ModalProps
1
+ <script lang="ts" module>export {};
5
2
  </script>
6
3
 
7
- <script lang="ts">
8
- import { Dialog } from 'bits-ui'
9
- import Button from '../Button/Button.svelte'
10
- import { getComponentConfig } from '../config.js'
11
- import { modalDefaults, modalVariants } from './modal.variants.js'
12
-
13
- const config = getComponentConfig('modal', modalDefaults)
14
-
15
- let {
16
- open = $bindable(false),
17
- onOpenChange,
18
- onOpenChangeComplete,
19
- trapFocus = true,
20
- preventScroll = true,
21
- onOpenAutoFocus,
22
- onCloseAutoFocus,
23
- onEscapeKeydown,
24
- onInteractOutside,
25
- forceMount,
26
- restoreScrollDelay,
27
- title,
28
- description,
29
- overlay: showOverlay = config.defaultVariants.overlay ?? true,
30
- scrollable = config.defaultVariants.scrollable ?? false,
31
- transition = config.defaultVariants.transition ?? 'scale',
32
- size = config.defaultVariants.size ?? 'md',
33
- fullscreen = false,
34
- portal = true,
35
- close: closeProp = true,
36
- dismissible = true,
37
- ui,
38
- class: className,
39
- children,
40
- content: contentSlot,
41
- header: headerSlot,
42
- titleSlot,
43
- descriptionSlot,
44
- actions: actionsSlot,
45
- body: bodySlot,
46
- footer: footerSlot,
47
- closeSlot
48
- }: Props = $props()
49
-
50
- const resolvedSize = $derived(fullscreen ? 'full' : size)
51
- const resolvedTransition = $derived(
52
- transition === false ? 'none' : transition === true ? 'scale' : transition
53
- )
54
-
55
- const showClose = $derived(!!closeProp)
56
- const closeProps = $derived(typeof closeProp === 'object' ? closeProp : {})
57
-
58
- const hasTitle = $derived(!!title || !!titleSlot)
59
- const hasDescription = $derived(!!description || !!descriptionSlot)
60
- const hasHeading = $derived(hasTitle || hasDescription)
61
- const hasHeader = $derived(
62
- !!headerSlot || hasHeading || !!actionsSlot || showClose || !!closeSlot
63
- )
64
-
65
- const variantSlots = $derived(
66
- modalVariants({
67
- transition: resolvedTransition,
68
- size: resolvedSize,
69
- overlay: showOverlay,
70
- scrollable
71
- })
72
- )
73
-
74
- const classes = $derived({
75
- overlay: variantSlots.overlay({ class: [config.slots.overlay, ui?.overlay] }),
76
- content: variantSlots.content({ class: [config.slots.content, ui?.content] }),
77
- header: variantSlots.header({ class: [config.slots.header, ui?.header] }),
78
- wrapper: variantSlots.wrapper({ class: [config.slots.wrapper, ui?.wrapper] }),
79
- title: variantSlots.title({ class: [config.slots.title, ui?.title] }),
80
- description: variantSlots.description({
81
- class: [config.slots.description, ui?.description]
82
- }),
83
- actions: variantSlots.actions({ class: [config.slots.actions, ui?.actions] }),
84
- body: variantSlots.body({ class: [config.slots.body, ui?.body] }),
85
- footer: variantSlots.footer({ class: [config.slots.footer, ui?.footer] }),
86
- close: variantSlots.close({ class: [config.slots.close, ui?.close] })
87
- })
88
-
89
- const contentProps = $derived.by(() => {
90
- const behavior = dismissible ? ('close' as const) : ('ignore' as const)
91
- return {
92
- trapFocus,
93
- preventScroll,
94
- escapeKeydownBehavior: behavior,
95
- interactOutsideBehavior: behavior,
96
- onOpenAutoFocus,
97
- onCloseAutoFocus,
98
- onEscapeKeydown,
99
- onInteractOutside,
100
- forceMount,
101
- restoreScrollDelay
102
- }
103
- })
104
-
105
- function handleOpenChange(value: boolean) {
106
- open = value
107
- onOpenChange?.(value)
108
- }
4
+ <script lang="ts">import { Dialog } from "bits-ui";
5
+ import Button from "../Button/Button.svelte";
6
+ import { getComponentConfig } from "../config.js";
7
+ import { modalDefaults, modalVariants } from "./modal.variants.js";
8
+ const config = getComponentConfig("modal", modalDefaults);
9
+ let { open = $bindable(false), onOpenChange, onOpenChangeComplete, trapFocus = true, preventScroll = true, onOpenAutoFocus, onCloseAutoFocus, onEscapeKeydown, onInteractOutside, forceMount, restoreScrollDelay, title, description, overlay: showOverlay = config.defaultVariants.overlay ?? true, scrollable = config.defaultVariants.scrollable ?? false, transition = config.defaultVariants.transition ?? "scale", size = config.defaultVariants.size ?? "md", fullscreen = false, portal = true, close: closeProp = true, dismissible = true, ui, class: className, children, content: contentSlot, header: headerSlot, titleSlot, descriptionSlot, actions: actionsSlot, body: bodySlot, footer: footerSlot, closeSlot } = $props();
10
+ const resolvedSize = $derived(fullscreen ? "full" : size);
11
+ const resolvedTransition = $derived(transition === false ? "none" : transition === true ? "scale" : transition);
12
+ const showClose = $derived(!!closeProp);
13
+ const closeProps = $derived(typeof closeProp === "object" ? closeProp : {});
14
+ const hasTitle = $derived(!!title || !!titleSlot);
15
+ const hasDescription = $derived(!!description || !!descriptionSlot);
16
+ const hasHeading = $derived(hasTitle || hasDescription);
17
+ const hasHeader = $derived(!!headerSlot || hasHeading || !!actionsSlot || showClose || !!closeSlot);
18
+ const variantSlots = $derived(modalVariants({
19
+ transition: resolvedTransition,
20
+ size: resolvedSize,
21
+ overlay: showOverlay,
22
+ scrollable
23
+ }));
24
+ const classes = $derived({
25
+ overlay: variantSlots.overlay({ class: [config.slots.overlay, ui?.overlay] }),
26
+ content: variantSlots.content({ class: [config.slots.content, ui?.content] }),
27
+ header: variantSlots.header({ class: [config.slots.header, ui?.header] }),
28
+ wrapper: variantSlots.wrapper({ class: [config.slots.wrapper, ui?.wrapper] }),
29
+ title: variantSlots.title({ class: [config.slots.title, ui?.title] }),
30
+ description: variantSlots.description({ class: [config.slots.description, ui?.description] }),
31
+ actions: variantSlots.actions({ class: [config.slots.actions, ui?.actions] }),
32
+ body: variantSlots.body({ class: [config.slots.body, ui?.body] }),
33
+ footer: variantSlots.footer({ class: [config.slots.footer, ui?.footer] }),
34
+ close: variantSlots.close({ class: [config.slots.close, ui?.close] })
35
+ });
36
+ const contentProps = $derived.by(() => {
37
+ const behavior = dismissible ? "close" : "ignore";
38
+ return {
39
+ trapFocus,
40
+ preventScroll,
41
+ escapeKeydownBehavior: behavior,
42
+ interactOutsideBehavior: behavior,
43
+ onOpenAutoFocus,
44
+ onCloseAutoFocus,
45
+ onEscapeKeydown,
46
+ onInteractOutside,
47
+ forceMount,
48
+ restoreScrollDelay
49
+ };
50
+ });
51
+ function handleOpenChange(value) {
52
+ open = value;
53
+ onOpenChange?.(value);
54
+ }
109
55
  </script>
110
56
 
111
57
  {#snippet titleEl()}
@@ -1,5 +1,4 @@
1
- <script lang="ts">
2
- import Modal from './Modal.svelte'
1
+ <script lang="ts">import Modal from "./Modal.svelte";
3
2
  </script>
4
3
 
5
4
  <Modal title="Trigger test" description="D">