svelte-comp 1.3.5 → 1.3.6

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 (46) hide show
  1. package/LICENSE.md +21 -21
  2. package/README.md +101 -101
  3. package/dist/App.svelte +1046 -1046
  4. package/dist/Container.svelte +59 -59
  5. package/dist/app.css +234 -234
  6. package/dist/app.d.ts +10 -10
  7. package/dist/lib/Accordion.svelte +155 -155
  8. package/dist/lib/Badge.svelte +44 -44
  9. package/dist/lib/Button.svelte +185 -185
  10. package/dist/lib/Calendar.svelte +384 -384
  11. package/dist/lib/Card.svelte +103 -103
  12. package/dist/lib/Carousel.svelte +293 -293
  13. package/dist/lib/CheckBox.svelte +210 -210
  14. package/dist/lib/CodeView.svelte +308 -308
  15. package/dist/lib/ColorPicker.svelte +159 -159
  16. package/dist/lib/ContextMenu.svelte +328 -328
  17. package/dist/lib/DatePicker.svelte +246 -246
  18. package/dist/lib/Dialog.svelte +233 -233
  19. package/dist/lib/Field.svelte +299 -299
  20. package/dist/lib/FilePicker.svelte +295 -295
  21. package/dist/lib/Form.svelte +438 -438
  22. package/dist/lib/Hamburger.svelte +217 -217
  23. package/dist/lib/InstallPWA.svelte +94 -94
  24. package/dist/lib/Menu.svelte +623 -623
  25. package/dist/lib/NoticeBase.svelte +140 -140
  26. package/dist/lib/PaginatedCard.svelte +73 -73
  27. package/dist/lib/Pagination.svelte +119 -119
  28. package/dist/lib/PrimaryColorSelect.svelte +111 -111
  29. package/dist/lib/ProgressBar.svelte +141 -141
  30. package/dist/lib/ProgressCircle.svelte +190 -190
  31. package/dist/lib/Radio.svelte +189 -189
  32. package/dist/lib/SearchInput.svelte +104 -104
  33. package/dist/lib/Select.svelte +524 -524
  34. package/dist/lib/Slider.svelte +253 -253
  35. package/dist/lib/Splitter.svelte +159 -159
  36. package/dist/lib/Switch.svelte +168 -168
  37. package/dist/lib/Table.svelte +299 -299
  38. package/dist/lib/Tabs.svelte +213 -213
  39. package/dist/lib/ThemeToggle.svelte +128 -128
  40. package/dist/lib/TimePicker.svelte +312 -312
  41. package/dist/lib/TimePickerNew.svelte +634 -634
  42. package/dist/lib/Toast.svelte +123 -123
  43. package/dist/lib/Tooltip.svelte +110 -110
  44. package/dist/lib/Topbar.svelte +112 -112
  45. package/dist/styles.css +234 -234
  46. package/package.json +52 -52
@@ -1,189 +1,189 @@
1
- <!-- src/lib/Radio.svelte -->
2
- <script lang="ts">
3
- /**
4
- * @component Radio
5
- * @description Single choice input with optional label, custom sizing and theme variants.
6
- *
7
- * @prop label {string} - Text label shown next to the radio
8
- *
9
- * @prop children {Snippet} - Custom label content
10
- *
11
- * @prop sz {SizeKey} - Size option
12
- * @options xs|sm|md|lg|xl
13
- * @default md
14
- *
15
- * @prop variant {ComponentVariant} - Visual style preset
16
- * @options default|neutral
17
- * @default default
18
- *
19
- * @prop checked {boolean} - Controlled checked state
20
- * @default false
21
- *
22
- * @prop group {unknown} - Native radio group binding (`bind:group`)
23
- *
24
- * @prop onChange {(checked: boolean) => void} - Fired when the radio toggles
25
- *
26
- * @prop class {string} - Extra classes applied to the root container
27
- * @default ""
28
- *
29
- * @prop describedBy {string} - ID of helper or error text for accessibility
30
- *
31
- * @prop value {string} - Radio value
32
- * @default "on"
33
- *
34
- * @note Fully supports native radio grouping through `bind:group`
35
- * @note Works as a controlled component when `checked` and `onChange` are used together
36
- * @note `children` takes priority over `label`
37
- * @note Size and variant affect circle size, dot size and colors
38
- * @note Hidden native input is focusable and exposes full accessibility attributes
39
- * @note Uses data-state attributes to enable custom styling
40
- */
41
- import type { Snippet } from "svelte";
42
- import type { HTMLInputAttributes } from "svelte/elements";
43
- import { type SizeKey, type ComponentVariant, TEXT } from "./types";
44
- import { cx, uid } from "../utils";
45
-
46
- type Props = HTMLInputAttributes & {
47
- label?: string;
48
- children?: Snippet;
49
- sz?: SizeKey;
50
- variant?: ComponentVariant;
51
- checked?: boolean;
52
- group?: unknown;
53
- onChange?: (checked: boolean) => void;
54
- class?: string;
55
- describedBy?: string;
56
- };
57
-
58
- let {
59
- label,
60
- children,
61
- sz = "md",
62
- variant = "default",
63
- checked = $bindable(false),
64
- group = $bindable<unknown>(undefined),
65
- onChange,
66
- class: externalClass = "",
67
- describedBy,
68
- value = "on",
69
- ...rest
70
- }: Props = $props();
71
-
72
- const inputId = $derived(rest.id ?? uid("rd-"));
73
-
74
- const sizeClasses = {
75
- xs: "w-3 h-3",
76
- sm: "w-3.5 h-3.5",
77
- md: "w-4 h-4",
78
- lg: "w-[18px] h-[18px]",
79
- xl: "w-5 h-5",
80
- } as const;
81
-
82
- const dotSizes: Record<SizeKey, string> = {
83
- xs: "w-1.5 h-1.5",
84
- sm: "w-2 h-2",
85
- md: "w-2.5 h-2.5",
86
- lg: "w-3 h-3",
87
- xl: "w-3.5 h-3.5",
88
- };
89
-
90
- const gapBySize: Record<SizeKey, string> = {
91
- xs: "gap-1.5",
92
- sm: "gap-2",
93
- md: "gap-2.5",
94
- lg: "gap-3",
95
- xl: "gap-3.5",
96
- };
97
-
98
- const variants = $derived(
99
- variant === "neutral"
100
- ? {
101
- checked: "bg-transparent border-[var(--border-color-strong)]",
102
- unchecked: "bg-transparent border-[var(--border-color-default)]",
103
- }
104
- : {
105
- checked: "bg-transparent border-[var(--color-bg-primary)]",
106
- unchecked: "bg-transparent border-[var(--border-color-default)]",
107
- }
108
- );
109
-
110
- const baseCircle =
111
- "rounded-full border border-solid cursor-pointer transition-all duration-[var(--transition-fast)] ease-[var(--timing-default)] flex items-center justify-center";
112
-
113
- const focusFromPeer =
114
- "peer-focus-visible:ring-2 peer-focus-visible:ring-[var(--border-color-focus)] peer-focus-visible:border-[var(--border-color-focus)]";
115
-
116
- const dotColor = $derived(
117
- variant === "neutral"
118
- ? "bg-[var(--border-color-strong)]"
119
- : "bg-[var(--color-bg-primary)]"
120
- );
121
-
122
- const isUsingGroup = $derived(typeof group !== "undefined");
123
- const isChecked = $derived(isUsingGroup ? group === value : checked);
124
- const state = $derived(isChecked ? "checked" : "unchecked");
125
-
126
- const rootClass = $derived(
127
- cx(
128
- "inline-flex items-center cursor-pointer select-none",
129
- gapBySize[sz],
130
- externalClass
131
- )
132
- );
133
-
134
- const radioClass = $derived(
135
- cx(
136
- baseCircle,
137
- focusFromPeer,
138
- sizeClasses[sz],
139
- isChecked && variants.checked,
140
- !isChecked && variants.unchecked,
141
- "peer-disabled:opacity-[var(--opacity-disabled)] peer-disabled:cursor-not-allowed"
142
- )
143
- );
144
-
145
- const dotClass = $derived(
146
- cx(
147
- "rounded-full transition-transform duration-[var(--transition-fast)] ease-[var(--timing-default)]",
148
- dotSizes[sz],
149
- dotColor,
150
- isChecked ? "scale-100 opacity-100" : "scale-50 opacity-0"
151
- )
152
- );
153
-
154
- const labelClass = $derived(
155
- cx(
156
- TEXT[sz],
157
- "[color:var(--color-text-muted)] font-medium peer-disabled:cursor-not-allowed"
158
- )
159
- );
160
- </script>
161
-
162
- <label class={rootClass} for={inputId}>
163
- <input
164
- id={inputId}
165
- type="radio"
166
- {value}
167
- bind:group
168
- checked={isChecked}
169
- {...rest}
170
- class="sr-only peer"
171
- aria-checked={isChecked}
172
- aria-describedby={describedBy}
173
- onchange={(event) => {
174
- const next = (event.currentTarget as HTMLInputElement).checked;
175
- checked = next;
176
- onChange?.(next);
177
- }}
178
- />
179
-
180
- <span data-state={state} class={radioClass} aria-hidden="true">
181
- <span class={dotClass}></span>
182
- </span>
183
-
184
- {#if children}
185
- <span class={labelClass}>{@render children?.()}</span>
186
- {:else if label}
187
- <span class={labelClass}>{label}</span>
188
- {/if}
189
- </label>
1
+ <!-- src/lib/Radio.svelte -->
2
+ <script lang="ts">
3
+ /**
4
+ * @component Radio
5
+ * @description Single choice input with optional label, custom sizing and theme variants.
6
+ *
7
+ * @prop label {string} - Text label shown next to the radio
8
+ *
9
+ * @prop children {Snippet} - Custom label content
10
+ *
11
+ * @prop sz {SizeKey} - Size option
12
+ * @options xs|sm|md|lg|xl
13
+ * @default md
14
+ *
15
+ * @prop variant {ComponentVariant} - Visual style preset
16
+ * @options default|neutral
17
+ * @default default
18
+ *
19
+ * @prop checked {boolean} - Controlled checked state
20
+ * @default false
21
+ *
22
+ * @prop group {unknown} - Native radio group binding (`bind:group`)
23
+ *
24
+ * @prop onChange {(checked: boolean) => void} - Fired when the radio toggles
25
+ *
26
+ * @prop class {string} - Extra classes applied to the root container
27
+ * @default ""
28
+ *
29
+ * @prop describedBy {string} - ID of helper or error text for accessibility
30
+ *
31
+ * @prop value {string} - Radio value
32
+ * @default "on"
33
+ *
34
+ * @note Fully supports native radio grouping through `bind:group`
35
+ * @note Works as a controlled component when `checked` and `onChange` are used together
36
+ * @note `children` takes priority over `label`
37
+ * @note Size and variant affect circle size, dot size and colors
38
+ * @note Hidden native input is focusable and exposes full accessibility attributes
39
+ * @note Uses data-state attributes to enable custom styling
40
+ */
41
+ import type { Snippet } from "svelte";
42
+ import type { HTMLInputAttributes } from "svelte/elements";
43
+ import { type SizeKey, type ComponentVariant, TEXT } from "./types";
44
+ import { cx, uid } from "../utils";
45
+
46
+ type Props = HTMLInputAttributes & {
47
+ label?: string;
48
+ children?: Snippet;
49
+ sz?: SizeKey;
50
+ variant?: ComponentVariant;
51
+ checked?: boolean;
52
+ group?: unknown;
53
+ onChange?: (checked: boolean) => void;
54
+ class?: string;
55
+ describedBy?: string;
56
+ };
57
+
58
+ let {
59
+ label,
60
+ children,
61
+ sz = "md",
62
+ variant = "default",
63
+ checked = $bindable(false),
64
+ group = $bindable<unknown>(undefined),
65
+ onChange,
66
+ class: externalClass = "",
67
+ describedBy,
68
+ value = "on",
69
+ ...rest
70
+ }: Props = $props();
71
+
72
+ const inputId = $derived(rest.id ?? uid("rd-"));
73
+
74
+ const sizeClasses = {
75
+ xs: "w-3 h-3",
76
+ sm: "w-3.5 h-3.5",
77
+ md: "w-4 h-4",
78
+ lg: "w-[18px] h-[18px]",
79
+ xl: "w-5 h-5",
80
+ } as const;
81
+
82
+ const dotSizes: Record<SizeKey, string> = {
83
+ xs: "w-1.5 h-1.5",
84
+ sm: "w-2 h-2",
85
+ md: "w-2.5 h-2.5",
86
+ lg: "w-3 h-3",
87
+ xl: "w-3.5 h-3.5",
88
+ };
89
+
90
+ const gapBySize: Record<SizeKey, string> = {
91
+ xs: "gap-1.5",
92
+ sm: "gap-2",
93
+ md: "gap-2.5",
94
+ lg: "gap-3",
95
+ xl: "gap-3.5",
96
+ };
97
+
98
+ const variants = $derived(
99
+ variant === "neutral"
100
+ ? {
101
+ checked: "bg-transparent border-[var(--border-color-strong)]",
102
+ unchecked: "bg-transparent border-[var(--border-color-default)]",
103
+ }
104
+ : {
105
+ checked: "bg-transparent border-[var(--color-bg-primary)]",
106
+ unchecked: "bg-transparent border-[var(--border-color-default)]",
107
+ }
108
+ );
109
+
110
+ const baseCircle =
111
+ "rounded-full border border-solid cursor-pointer transition-all duration-[var(--transition-fast)] ease-[var(--timing-default)] flex items-center justify-center";
112
+
113
+ const focusFromPeer =
114
+ "peer-focus-visible:ring-2 peer-focus-visible:ring-[var(--border-color-focus)] peer-focus-visible:border-[var(--border-color-focus)]";
115
+
116
+ const dotColor = $derived(
117
+ variant === "neutral"
118
+ ? "bg-[var(--border-color-strong)]"
119
+ : "bg-[var(--color-bg-primary)]"
120
+ );
121
+
122
+ const isUsingGroup = $derived(typeof group !== "undefined");
123
+ const isChecked = $derived(isUsingGroup ? group === value : checked);
124
+ const state = $derived(isChecked ? "checked" : "unchecked");
125
+
126
+ const rootClass = $derived(
127
+ cx(
128
+ "inline-flex items-center cursor-pointer select-none",
129
+ gapBySize[sz],
130
+ externalClass
131
+ )
132
+ );
133
+
134
+ const radioClass = $derived(
135
+ cx(
136
+ baseCircle,
137
+ focusFromPeer,
138
+ sizeClasses[sz],
139
+ isChecked && variants.checked,
140
+ !isChecked && variants.unchecked,
141
+ "peer-disabled:opacity-[var(--opacity-disabled)] peer-disabled:cursor-not-allowed"
142
+ )
143
+ );
144
+
145
+ const dotClass = $derived(
146
+ cx(
147
+ "rounded-full transition-transform duration-[var(--transition-fast)] ease-[var(--timing-default)]",
148
+ dotSizes[sz],
149
+ dotColor,
150
+ isChecked ? "scale-100 opacity-100" : "scale-50 opacity-0"
151
+ )
152
+ );
153
+
154
+ const labelClass = $derived(
155
+ cx(
156
+ TEXT[sz],
157
+ "[color:var(--color-text-muted)] font-medium peer-disabled:cursor-not-allowed"
158
+ )
159
+ );
160
+ </script>
161
+
162
+ <label class={rootClass} for={inputId}>
163
+ <input
164
+ id={inputId}
165
+ type="radio"
166
+ {value}
167
+ bind:group
168
+ checked={isChecked}
169
+ {...rest}
170
+ class="sr-only peer"
171
+ aria-checked={isChecked}
172
+ aria-describedby={describedBy}
173
+ onchange={(event) => {
174
+ const next = (event.currentTarget as HTMLInputElement).checked;
175
+ checked = next;
176
+ onChange?.(next);
177
+ }}
178
+ />
179
+
180
+ <span data-state={state} class={radioClass} aria-hidden="true">
181
+ <span class={dotClass}></span>
182
+ </span>
183
+
184
+ {#if children}
185
+ <span class={labelClass}>{@render children?.()}</span>
186
+ {:else if label}
187
+ <span class={labelClass}>{label}</span>
188
+ {/if}
189
+ </label>
@@ -1,104 +1,104 @@
1
- <script lang="ts">
2
- /**
3
- * @component SearchInput
4
- * @description Search input field with a leading search icon.
5
- *
6
- * @prop label {string} - Label text rendered above the field
7
- *
8
- * @prop placeholder {string} - Placeholder text (localized by default)
9
- *
10
- * @prop value {string} - Controlled field value (bindable)
11
- * @default ""
12
- *
13
- * @prop sz {SizeKey} - Size preset for spacing and typography
14
- * @options xs|sm|md|lg|xl
15
- * @default sm
16
- *
17
- * @prop variant {FieldVariant} - Visual style variant
18
- * @options default|filled|neutral
19
- * @default filled
20
- *
21
- * @prop class {string} - Additional classes applied to the Field root
22
- * @default ""
23
- *
24
- * @note Renders a leading search icon and uses `Field` with `type="search"` and `clearable`.
25
- */
26
- import Field from "./Field.svelte";
27
- import type { FieldVariant, SizeKey } from "./types";
28
- import { getComponentText, getLangContext, getLangKey } from "./lang-context";
29
-
30
- type Props = {
31
- label?: string;
32
- placeholder?: string;
33
- value?: string;
34
- sz?: SizeKey;
35
- variant?: FieldVariant;
36
- class?: string;
37
- [key: string]: unknown;
38
- };
39
-
40
- let {
41
- label,
42
- placeholder,
43
- value = $bindable(''),
44
- sz = 'sm',
45
- variant = 'filled',
46
- class: externalClass = '',
47
- ...rest
48
- }: Props = $props();
49
-
50
- const langCtx = getLangContext();
51
- const langKey = $derived(getLangKey(langCtx));
52
- const L = $derived(getComponentText("searchInput", langKey));
53
-
54
- const placeholderFinal = $derived(placeholder ?? L.placeholder);
55
- </script>
56
-
57
- {#snippet leading()}
58
- <span class="ml-1 inline-flex h-6 w-6 items-center justify-center text-[var(--color-text-muted)]">
59
- <svg
60
- xmlns="http://www.w3.org/2000/svg"
61
- width="20"
62
- height="20"
63
- viewBox="0 0 24 24"
64
- fill="none"
65
- stroke="currentColor"
66
- stroke-width="2"
67
- stroke-linecap="round"
68
- stroke-linejoin="round"
69
- class="lucide lucide-search-icon lucide-search"
70
- >
71
- <path d="m21 21-4.34-4.34" />
72
- <circle cx="11" cy="11" r="8" />
73
- </svg>
74
- </span>
75
- {/snippet}
76
-
77
- <Field
78
- {label}
79
- bind:value
80
- {sz}
81
- {variant}
82
- type="search"
83
- clearable={true}
84
- {leading}
85
- placeholder={placeholderFinal}
86
- class={`search-input w-full max-w-[520px] [&_input]:pl-10 ${externalClass}`}
87
- {...rest}
88
- />
89
-
90
- <style>
91
- :global(.search-input input[type="search"]) {
92
- -webkit-appearance: none;
93
- appearance: none;
94
- }
95
-
96
- :global(.search-input input[type="search"]::-webkit-search-cancel-button),
97
- :global(.search-input input[type="search"]::-webkit-search-decoration),
98
- :global(.search-input input[type="search"]::-webkit-search-results-button),
99
- :global(.search-input input[type="search"]::-webkit-search-results-decoration) {
100
- -webkit-appearance: none;
101
- appearance: none;
102
- display: none;
103
- }
104
- </style>
1
+ <script lang="ts">
2
+ /**
3
+ * @component SearchInput
4
+ * @description Search input field with a leading search icon.
5
+ *
6
+ * @prop label {string} - Label text rendered above the field
7
+ *
8
+ * @prop placeholder {string} - Placeholder text (localized by default)
9
+ *
10
+ * @prop value {string} - Controlled field value (bindable)
11
+ * @default ""
12
+ *
13
+ * @prop sz {SizeKey} - Size preset for spacing and typography
14
+ * @options xs|sm|md|lg|xl
15
+ * @default sm
16
+ *
17
+ * @prop variant {FieldVariant} - Visual style variant
18
+ * @options default|filled|neutral
19
+ * @default filled
20
+ *
21
+ * @prop class {string} - Additional classes applied to the Field root
22
+ * @default ""
23
+ *
24
+ * @note Renders a leading search icon and uses `Field` with `type="search"` and `clearable`.
25
+ */
26
+ import Field from "./Field.svelte";
27
+ import type { FieldVariant, SizeKey } from "./types";
28
+ import { getComponentText, getLangContext, getLangKey } from "./lang-context";
29
+
30
+ type Props = {
31
+ label?: string;
32
+ placeholder?: string;
33
+ value?: string;
34
+ sz?: SizeKey;
35
+ variant?: FieldVariant;
36
+ class?: string;
37
+ [key: string]: unknown;
38
+ };
39
+
40
+ let {
41
+ label,
42
+ placeholder,
43
+ value = $bindable(''),
44
+ sz = 'sm',
45
+ variant = 'filled',
46
+ class: externalClass = '',
47
+ ...rest
48
+ }: Props = $props();
49
+
50
+ const langCtx = getLangContext();
51
+ const langKey = $derived(getLangKey(langCtx));
52
+ const L = $derived(getComponentText("searchInput", langKey));
53
+
54
+ const placeholderFinal = $derived(placeholder ?? L.placeholder);
55
+ </script>
56
+
57
+ {#snippet leading()}
58
+ <span class="ml-1 inline-flex h-6 w-6 items-center justify-center text-[var(--color-text-muted)]">
59
+ <svg
60
+ xmlns="http://www.w3.org/2000/svg"
61
+ width="20"
62
+ height="20"
63
+ viewBox="0 0 24 24"
64
+ fill="none"
65
+ stroke="currentColor"
66
+ stroke-width="2"
67
+ stroke-linecap="round"
68
+ stroke-linejoin="round"
69
+ class="lucide lucide-search-icon lucide-search"
70
+ >
71
+ <path d="m21 21-4.34-4.34" />
72
+ <circle cx="11" cy="11" r="8" />
73
+ </svg>
74
+ </span>
75
+ {/snippet}
76
+
77
+ <Field
78
+ {label}
79
+ bind:value
80
+ {sz}
81
+ {variant}
82
+ type="search"
83
+ clearable={true}
84
+ {leading}
85
+ placeholder={placeholderFinal}
86
+ class={`search-input w-full max-w-[520px] [&_input]:pl-10 ${externalClass}`}
87
+ {...rest}
88
+ />
89
+
90
+ <style>
91
+ :global(.search-input input[type="search"]) {
92
+ -webkit-appearance: none;
93
+ appearance: none;
94
+ }
95
+
96
+ :global(.search-input input[type="search"]::-webkit-search-cancel-button),
97
+ :global(.search-input input[type="search"]::-webkit-search-decoration),
98
+ :global(.search-input input[type="search"]::-webkit-search-results-button),
99
+ :global(.search-input input[type="search"]::-webkit-search-results-decoration) {
100
+ -webkit-appearance: none;
101
+ appearance: none;
102
+ display: none;
103
+ }
104
+ </style>