fuma 2.1.0 → 2.1.3

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 (47) hide show
  1. package/dist/_doc/DocExample.svelte +122 -0
  2. package/dist/_doc/DocExample.svelte.d.ts +10 -0
  3. package/dist/_doc/DocProps.svelte +61 -0
  4. package/dist/_doc/DocProps.svelte.d.ts +13 -0
  5. package/dist/_doc/DocSection.svelte +22 -0
  6. package/dist/_doc/DocSection.svelte.d.ts +9 -0
  7. package/dist/_doc/highlight.d.ts +2 -0
  8. package/dist/_doc/highlight.js +18 -0
  9. package/dist/_doc/index.d.ts +4 -0
  10. package/dist/_doc/index.js +3 -0
  11. package/dist/_doc/parse-props.d.ts +2 -0
  12. package/dist/_doc/parse-props.js +253 -0
  13. package/dist/index.d.ts +5 -0
  14. package/dist/index.js +5 -0
  15. package/dist/input/InputBoolean.svelte +3 -6
  16. package/dist/input/InputRadio.svelte +1 -1
  17. package/dist/input/InputSelectNative.svelte +1 -1
  18. package/dist/input/InputTextarea.svelte +1 -2
  19. package/dist/input/Issues.svelte +3 -4
  20. package/dist/input/Issues.svelte.d.ts +2 -2
  21. package/dist/popover/popover.svelte.js +0 -8
  22. package/dist/remote/index.d.ts +1 -0
  23. package/dist/remote/index.js +1 -0
  24. package/dist/remote/useForm.js +4 -1
  25. package/dist/search/Spans.svelte +2 -1
  26. package/dist/state/param.svelte.d.ts +6 -7
  27. package/dist/state/param.svelte.js +16 -18
  28. package/dist/ui/drawer/drawerFly.js +1 -1
  29. package/dist/ui/menu/DropDownMenu.svelte +3 -17
  30. package/dist/ui/menu/DropDownMenu.svelte.d.ts +0 -3
  31. package/dist/ui/range/RangePicker.svelte +1 -2
  32. package/dist/ui/table/Table.svelte +3 -6
  33. package/dist/ui/table/Table.svelte.d.ts +2 -3
  34. package/dist/ui/table/TableFieldsEdition.svelte +3 -2
  35. package/dist/ui/table/TableViewSelect.svelte +5 -13
  36. package/dist/ui/table/TableViewSelect.svelte.d.ts +0 -5
  37. package/dist/ui/table/cell/TableCellArray.svelte +1 -1
  38. package/dist/ui/table/field.d.ts +7 -7
  39. package/dist/ui/table/head/TableHeadDate.svelte +1 -5
  40. package/dist/ui/table/head/TableHeadNumber.svelte +0 -1
  41. package/dist/ui/table/head/TableHeadSelect.svelte +2 -2
  42. package/dist/validation/zod.js +2 -1
  43. package/package.json +16 -33
  44. package/dist/ui/table/type.d.ts +0 -2
  45. package/dist/ui/table/type.js +0 -1
  46. /package/dist/{data.d.ts → _doc/data.d.ts} +0 -0
  47. /package/dist/{data.js → _doc/data.js} +0 -0
@@ -0,0 +1,122 @@
1
+ <script lang="ts">
2
+ import { type Snippet } from 'svelte'
3
+ import { ButtonCopy } from '../ui/copy/index.js'
4
+ import { useMode } from '../ui/mode/useMode.svelte.js'
5
+ import { highlight, transformPackageImports } from './highlight.ts'
6
+
7
+ let {
8
+ code,
9
+ title,
10
+ lang = 'svelte',
11
+ preview
12
+ }: {
13
+ code: string
14
+ title?: string
15
+ lang?: string
16
+ preview: Snippet
17
+ } = $props()
18
+
19
+ let mode = $derived(useMode({ light: 'fuma', dark: 'fuma-dark' }))
20
+ let displayCode = $derived(transformPackageImports(code.trim()))
21
+ let highlighted = $derived(highlight(displayCode, lang, mode.current))
22
+ let tab = $state<'preview' | 'code'>('code')
23
+
24
+ let leftWidth = $state(50)
25
+ let isDragging = $state(false)
26
+ let container = $state<HTMLDivElement>()
27
+
28
+ function setTab(t: 'preview' | 'code') {
29
+ tab = t
30
+ if (t === 'code') {
31
+ leftWidth = 70
32
+ } else {
33
+ leftWidth = 30
34
+ }
35
+ }
36
+
37
+ function startResize(e: MouseEvent) {
38
+ e.preventDefault()
39
+ isDragging = true
40
+ window.addEventListener('mousemove', onResize)
41
+ window.addEventListener('mouseup', stopResize)
42
+ }
43
+
44
+ function onResize(e: MouseEvent) {
45
+ if (!isDragging || !container) return
46
+ const rect = container.getBoundingClientRect()
47
+ const x = e.clientX - rect.left
48
+ const percent = (x / rect.width) * 100
49
+ leftWidth = Math.max(20, Math.min(80, percent))
50
+ tab = leftWidth >= 50 ? 'code' : 'preview'
51
+ }
52
+
53
+ function stopResize() {
54
+ isDragging = false
55
+ window.removeEventListener('mousemove', onResize)
56
+ window.removeEventListener('mouseup', stopResize)
57
+ }
58
+ </script>
59
+
60
+ <div class="not-prose my-6 overflow-hidden rounded-lg border">
61
+ <div class="flex items-center gap-2 border-b bg-base-200/50 px-4 py-2">
62
+ <span class="mr-auto text-sm font-semibold text-base-content/70">Example: {title}</span>
63
+
64
+ <div class="tabs-boxed tabs tabs-sm">
65
+ <button class="tab" class:tab-active={tab === 'code'} onclick={() => setTab('code')}>
66
+ Code
67
+ </button>
68
+ <button class="tab" class:tab-active={tab === 'preview'} onclick={() => setTab('preview')}>
69
+ Preview
70
+ </button>
71
+ </div>
72
+
73
+ <ButtonCopy value={displayCode} title="Copy code" class="btn btn-square btn-xs" />
74
+ </div>
75
+
76
+ <!-- Mobile: tabs -->
77
+ <div class="md:hidden">
78
+ {#if tab === 'code'}
79
+ <div class="overflow-hidden">
80
+ {#await highlighted then html}
81
+ <div class="overflow-auto text-sm">
82
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
83
+ {@html html}
84
+ </div>
85
+ {/await}
86
+ </div>
87
+ {:else}
88
+ <div class="bg-base-100 p-6">
89
+ {@render preview()}
90
+ </div>
91
+ {/if}
92
+ </div>
93
+
94
+ <!-- Desktop: side by side with resizer -->
95
+ <div class="hidden md:flex" bind:this={container}>
96
+ <div
97
+ class="overflow-hidden {isDragging ? '' : 'transition-[width] duration-300 ease-out'}"
98
+ style="width: {leftWidth}%"
99
+ >
100
+ {#await highlighted then html}
101
+ <div class="overflow-auto text-sm">
102
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
103
+ {@html html}
104
+ </div>
105
+ {/await}
106
+ </div>
107
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
108
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
109
+ <div
110
+ class="w-1.5 shrink-0 cursor-col-resize bg-base-300 transition-colors hover:bg-primary {isDragging
111
+ ? 'bg-primary'
112
+ : ''}"
113
+ onmousedown={startResize}
114
+ role="separator"
115
+ aria-label="Resize"
116
+ tabindex="0"
117
+ ></div>
118
+ <div class="min-w-0 flex-1 overflow-auto bg-base-100 p-6">
119
+ {@render preview()}
120
+ </div>
121
+ </div>
122
+ </div>
@@ -0,0 +1,10 @@
1
+ import { type Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ code: string;
4
+ title?: string;
5
+ lang?: string;
6
+ preview: Snippet;
7
+ };
8
+ declare const DocExample: import("svelte").Component<$$ComponentProps, {}, "">;
9
+ type DocExample = ReturnType<typeof DocExample>;
10
+ export default DocExample;
@@ -0,0 +1,61 @@
1
+ <script lang="ts" module>
2
+ export type PropDef = {
3
+ name: string
4
+ type: string
5
+ default?: string
6
+ required?: boolean
7
+ description?: string
8
+ }
9
+ </script>
10
+
11
+ <script lang="ts">
12
+ let {
13
+ props
14
+ }: {
15
+ props: PropDef[]
16
+ } = $props()
17
+ </script>
18
+
19
+ <div class="not-prose my-6">
20
+ <div class="collapse-arrow collapse rounded-lg border bg-base-100">
21
+ <input type="checkbox" />
22
+ <div class="collapse-title text-sm font-semibold">{props.length} Props</div>
23
+ <div class="collapse-content p-0">
24
+ <div class="overflow-x-auto">
25
+ <table class="table table-zebra table-sm">
26
+ <thead class="bg-base-200/80 text-sm">
27
+ <tr>
28
+ <th>Name</th>
29
+ <th>Type</th>
30
+ <th>Default</th>
31
+ <th>Description</th>
32
+ </tr>
33
+ </thead>
34
+ <tbody>
35
+ {#each props as prop (prop.name)}
36
+ <tr>
37
+ <td class="whitespace-nowrap">
38
+ <code class="font-mono text-sm">{prop.name}</code>
39
+ {#if prop.required}
40
+ <span class="ml-1 badge badge-xs badge-error">required</span>
41
+ {/if}
42
+ </td>
43
+ <td>
44
+ <code class="font-mono text-xs opacity-70">{prop.type}</code>
45
+ </td>
46
+ <td class="text-sm opacity-80">
47
+ {#if prop.default}
48
+ <code class="font-mono text-xs">{prop.default}</code>
49
+ {:else}
50
+ <span class="opacity-50">—</span>
51
+ {/if}
52
+ </td>
53
+ <td class="text-sm">{prop.description ?? ''}</td>
54
+ </tr>
55
+ {/each}
56
+ </tbody>
57
+ </table>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </div>
@@ -0,0 +1,13 @@
1
+ export type PropDef = {
2
+ name: string;
3
+ type: string;
4
+ default?: string;
5
+ required?: boolean;
6
+ description?: string;
7
+ };
8
+ type $$ComponentProps = {
9
+ props: PropDef[];
10
+ };
11
+ declare const DocProps: import("svelte").Component<$$ComponentProps, {}, "">;
12
+ type DocProps = ReturnType<typeof DocProps>;
13
+ export default DocProps;
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ import { type Snippet } from 'svelte'
3
+
4
+ let {
5
+ title,
6
+ description,
7
+ children
8
+ }: {
9
+ title?: string
10
+ description?: string
11
+ children: Snippet
12
+ } = $props()
13
+ </script>
14
+
15
+ <section class="mt-2 mb-12">
16
+ <h2 class="mb-2 text-2xl font-bold text-base-content">{title}</h2>
17
+ {#if description}
18
+ <p class="mb-4 text-base-content/70">{description}</p>
19
+ {/if}
20
+ <div class="divider mb-6"></div>
21
+ {@render children()}
22
+ </section>
@@ -0,0 +1,9 @@
1
+ import { type Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ title?: string;
4
+ description?: string;
5
+ children: Snippet;
6
+ };
7
+ declare const DocSection: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type DocSection = ReturnType<typeof DocSection>;
9
+ export default DocSection;
@@ -0,0 +1,2 @@
1
+ export declare function transformPackageImports(code: string): string;
2
+ export declare function highlight(code: string, lang?: string, theme?: 'light' | 'dark'): Promise<string>;
@@ -0,0 +1,18 @@
1
+ import { codeToHtml } from 'shiki';
2
+ export function transformPackageImports(code) {
3
+ return code
4
+ .replace(/from\s+['"]\$lib\/index\.ts['"]/g, "from 'fuma'")
5
+ .replace(/from\s+['"]\$lib\/ui\/[^'"]+['"]/g, "from 'fuma/ui'")
6
+ .replace(/from\s+['"]\$lib\/utils\/[^'"]+['"]/g, "from 'fuma/utils'")
7
+ .replace(/from\s+['"]\$lib\/state\/[^'"]+['"]/g, "from 'fuma/state'")
8
+ .replace(/from\s+['"]\$lib\/validation\/[^'"]+['"]/g, "from 'fuma/validation'")
9
+ .replace(/from\s+['"]\$lib\/action\/[^'"]+['"]/g, "from 'fuma/action'")
10
+ .replace(/from\s+['"]\$lib\/server\/[^'"]+['"]/g, "from 'fuma/server'");
11
+ }
12
+ export async function highlight(code, lang = 'svelte', theme = 'dark') {
13
+ return codeToHtml(code, {
14
+ lang,
15
+ theme: theme === 'dark' ? 'github-dark' : 'github-light',
16
+ rootStyle: 'padding: 0.5rem 1rem;'
17
+ });
18
+ }
@@ -0,0 +1,4 @@
1
+ export { default as DocExample } from './DocExample.svelte';
2
+ export type { PropDef } from './DocProps.svelte';
3
+ export { default as DocProps } from './DocProps.svelte';
4
+ export { default as DocSection } from './DocSection.svelte';
@@ -0,0 +1,3 @@
1
+ export { default as DocExample } from './DocExample.svelte';
2
+ export { default as DocProps } from './DocProps.svelte';
3
+ export { default as DocSection } from './DocSection.svelte';
@@ -0,0 +1,2 @@
1
+ import type { PropDef } from './DocProps.svelte';
2
+ export declare function parseProps(source: string): PropDef[];
@@ -0,0 +1,253 @@
1
+ export function parseProps(source) {
2
+ const script = extractScript(source);
3
+ if (!script)
4
+ return [];
5
+ // Try Svelte 5 $props() first
6
+ const declaration = findPropsDeclaration(script);
7
+ if (declaration) {
8
+ const destructured = parseDestructuring(declaration.destructuring);
9
+ const typed = parseType(declaration.type);
10
+ return mergeToPropDefs(destructured, typed);
11
+ }
12
+ // Fallback to Svelte 3/4 export let syntax
13
+ return parseExportLetProps(script);
14
+ }
15
+ function extractScript(source) {
16
+ const moduleMatch = source.match(/<script\s+lang="ts"\s+module>[\s\S]*?<\/script>/);
17
+ let cleaned = source;
18
+ if (moduleMatch && moduleMatch.index !== undefined) {
19
+ cleaned =
20
+ source.slice(0, moduleMatch.index) + source.slice(moduleMatch.index + moduleMatch[0].length);
21
+ }
22
+ const scriptMatch = cleaned.match(/<script\s+lang="ts"\s*(?:generics="[^"]*")?\s*>([\s\S]*?)<\/script>/);
23
+ if (scriptMatch)
24
+ return scriptMatch[1];
25
+ // Fallback for plain .ts files (no <script> tag)
26
+ if (!cleaned.includes('<script'))
27
+ return cleaned;
28
+ return null;
29
+ }
30
+ function findPropsDeclaration(script) {
31
+ const letIndex = script.indexOf('let {');
32
+ if (letIndex === -1)
33
+ return null;
34
+ let i = letIndex + 4;
35
+ let braceDepth = 0;
36
+ let destructuringEnd = -1;
37
+ for (; i < script.length; i++) {
38
+ if (script[i] === '{')
39
+ braceDepth++;
40
+ else if (script[i] === '}') {
41
+ braceDepth--;
42
+ if (braceDepth === 0) {
43
+ destructuringEnd = i;
44
+ break;
45
+ }
46
+ }
47
+ }
48
+ if (destructuringEnd === -1)
49
+ return null;
50
+ const destructuring = script.slice(letIndex + 5, destructuringEnd);
51
+ let j = destructuringEnd + 1;
52
+ while (j < script.length && /\s/.test(script[j]))
53
+ j++;
54
+ let type = null;
55
+ if (script[j] === ':') {
56
+ j++;
57
+ while (j < script.length && /\s/.test(script[j]))
58
+ j++;
59
+ const propsIndex = script.indexOf('= $props()', j);
60
+ if (propsIndex !== -1) {
61
+ type = script.slice(j, propsIndex).trim();
62
+ }
63
+ }
64
+ return { destructuring, type };
65
+ }
66
+ function parseDestructuring(str) {
67
+ const props = new Map();
68
+ const items = splitByComma(str);
69
+ for (const item of items) {
70
+ if (item.startsWith('...'))
71
+ continue;
72
+ const eqIndex = findTopLevel(item, ' = ');
73
+ const beforeEq = eqIndex >= 0 ? item.slice(0, eqIndex).trim() : item.trim();
74
+ const defaultValue = eqIndex >= 0 ? item.slice(eqIndex + 3).trim() : undefined;
75
+ const colonIndex = findTopLevel(beforeEq, ': ');
76
+ const name = colonIndex >= 0 ? beforeEq.slice(0, colonIndex).trim() : beforeEq;
77
+ props.set(name, { alias: name, defaultValue });
78
+ }
79
+ return props;
80
+ }
81
+ function parseType(typeStr) {
82
+ const props = new Map();
83
+ if (!typeStr)
84
+ return props;
85
+ const cleaned = removeComments(typeStr);
86
+ const firstBrace = cleaned.indexOf('{');
87
+ if (firstBrace === -1)
88
+ return props;
89
+ let depth = 0;
90
+ let start = -1;
91
+ let end = -1;
92
+ for (let i = 0; i < cleaned.length; i++) {
93
+ if (cleaned[i] === '{') {
94
+ if (depth === 0)
95
+ start = i;
96
+ depth++;
97
+ }
98
+ else if (cleaned[i] === '}') {
99
+ depth--;
100
+ if (depth === 0) {
101
+ end = i;
102
+ break;
103
+ }
104
+ }
105
+ }
106
+ if (start === -1 || end === -1)
107
+ return props;
108
+ const content = cleaned.slice(start + 1, end);
109
+ return parseTypeObject(content);
110
+ }
111
+ function parseTypeObject(content) {
112
+ const props = new Map();
113
+ const lines = content.split('\n');
114
+ const propStartRegex = /^([a-zA-Z_$][a-zA-Z0-9_$]*)(\??)\s*:\s*(.*)$/;
115
+ let currentName = null;
116
+ let currentOptional = false;
117
+ let currentType = '';
118
+ let currentDescription = '';
119
+ let depth = 0;
120
+ let pendingDescription = '';
121
+ for (let line of lines) {
122
+ line = line.trim();
123
+ if (!line)
124
+ continue;
125
+ const jsdocMatch = line.match(/\/\*\*\s*(.*?)\s*\*\//);
126
+ if (jsdocMatch) {
127
+ pendingDescription = jsdocMatch[1].trim();
128
+ continue;
129
+ }
130
+ const commentMatch = line.match(/\/\/\s*(.*)/);
131
+ if (commentMatch) {
132
+ pendingDescription = commentMatch[1].trim();
133
+ continue;
134
+ }
135
+ for (const char of line) {
136
+ if (char === '{' || char === '(' || char === '[')
137
+ depth++;
138
+ else if (char === '}' || char === ')' || char === ']')
139
+ depth--;
140
+ }
141
+ const match = line.match(propStartRegex);
142
+ if (match && depth === 0) {
143
+ if (currentName) {
144
+ props.set(currentName, {
145
+ type: currentType.trim(),
146
+ required: !currentOptional,
147
+ description: currentDescription || undefined
148
+ });
149
+ }
150
+ currentName = match[1];
151
+ currentOptional = match[2] === '?';
152
+ currentType = match[3];
153
+ currentDescription = pendingDescription;
154
+ pendingDescription = '';
155
+ }
156
+ else if (currentName && depth >= 0) {
157
+ currentType += ` ${line}`;
158
+ }
159
+ }
160
+ if (currentName) {
161
+ props.set(currentName, {
162
+ type: currentType.trim(),
163
+ required: !currentOptional,
164
+ description: currentDescription || undefined
165
+ });
166
+ }
167
+ return props;
168
+ }
169
+ function parseExportLetProps(script) {
170
+ const defs = [];
171
+ const regex = /export\s+let\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*(?::\s*([^=\n]+))?\s*(?:=\s*([^\n]+))?/g;
172
+ let match = null;
173
+ while (true) {
174
+ match = regex.exec(script);
175
+ if (match === null)
176
+ break;
177
+ const [, name, typeStr, defaultValue] = match;
178
+ defs.push({
179
+ name,
180
+ type: typeStr ? typeStr.trim() : 'unknown',
181
+ default: defaultValue ? defaultValue.trim() : undefined,
182
+ required: !defaultValue
183
+ });
184
+ }
185
+ return defs;
186
+ }
187
+ function mergeToPropDefs(destructured, typed) {
188
+ const defs = [];
189
+ for (const [name, { defaultValue }] of destructured) {
190
+ const typeInfo = typed.get(name);
191
+ let isRequired = typeInfo?.required ?? false;
192
+ let type = typeInfo?.type ?? 'unknown';
193
+ // Clean up union types starting with |
194
+ if (type.startsWith('| ')) {
195
+ type = type.slice(2).trim();
196
+ }
197
+ if (defaultValue) {
198
+ if (defaultValue.startsWith('$bindable')) {
199
+ // $bindable() means it's bindable but may still be required
200
+ // keep required as-is from type
201
+ }
202
+ else {
203
+ isRequired = false;
204
+ }
205
+ }
206
+ defs.push({
207
+ name,
208
+ type,
209
+ default: defaultValue && !defaultValue.startsWith('$bindable') ? defaultValue : undefined,
210
+ required: isRequired,
211
+ description: typeInfo?.description
212
+ });
213
+ }
214
+ return defs;
215
+ }
216
+ function splitByComma(str) {
217
+ const items = [];
218
+ let current = '';
219
+ let depth = 0;
220
+ for (const char of str) {
221
+ if (char === '{' || char === '(' || char === '[' || char === '<')
222
+ depth++;
223
+ else if (char === '}' || char === ')' || char === ']' || char === '>')
224
+ depth--;
225
+ else if (char === ',' && depth === 0) {
226
+ if (current.trim())
227
+ items.push(current.trim());
228
+ current = '';
229
+ continue;
230
+ }
231
+ current += char;
232
+ }
233
+ if (current.trim())
234
+ items.push(current.trim());
235
+ return items;
236
+ }
237
+ function findTopLevel(str, pattern) {
238
+ let depth = 0;
239
+ for (let i = 0; i <= str.length - pattern.length; i++) {
240
+ const char = str[i];
241
+ if (char === '{' || char === '(' || char === '[' || char === '<')
242
+ depth++;
243
+ else if (char === '}' || char === ')' || char === ']' || char === '>')
244
+ depth--;
245
+ else if (depth === 0 && str.slice(i, i + pattern.length) === pattern) {
246
+ return i;
247
+ }
248
+ }
249
+ return -1;
250
+ }
251
+ function removeComments(str) {
252
+ return str.replace(/\/\/.*$/gm, '');
253
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,9 @@
1
1
  export * from './action/index.ts';
2
+ export * from './command/index.ts';
3
+ export * from './input/index.ts';
4
+ export * from './popover/index.ts';
5
+ export * from './remote/index.ts';
6
+ export * from './search/index.ts';
2
7
  export * from './state/index.ts';
3
8
  export * from './ui/index.ts';
4
9
  export * from './utils/index.ts';
package/dist/index.js CHANGED
@@ -1,4 +1,9 @@
1
1
  export * from './action/index.ts';
2
+ export * from './command/index.ts';
3
+ export * from './input/index.ts';
4
+ export * from './popover/index.ts';
5
+ export * from './remote/index.ts';
6
+ export * from './search/index.ts';
2
7
  export * from './state/index.ts';
3
8
  export * from './ui/index.ts';
4
9
  export * from './utils/index.ts';
@@ -10,7 +10,6 @@
10
10
  checked = $bindable(),
11
11
  hint,
12
12
  variant = 'checkbox',
13
- class: klass,
14
13
  ...props
15
14
  }: {
16
15
  label: string
@@ -58,7 +57,8 @@
58
57
  </div>
59
58
 
60
59
  {#snippet variantCheckbox()}
61
- <div class={['squircle h-5 w-5 outline', 'bg-base-100']}>
60
+ <!-- https://developer.mozilla.org/en-US/docs/Web/CSS/corner-shape -->
61
+ <div class={['h-5 w-5 rounded-full outline', 'bg-base-100']} style="corner-shape: squircle;">
62
62
  <div
63
63
  class={[
64
64
  'squircle grid h-5 w-5 place-content-center',
@@ -66,6 +66,7 @@
66
66
  'ease scale-0 opacity-0',
67
67
  isChecked && 'scale-[80%] opacity-100'
68
68
  ]}
69
+ style="corner-shape: squircle"
69
70
  >
70
71
  <CheckIcon size={18} class={['stroke-base-100']} strokeWidth={4} />
71
72
  </div>
@@ -92,10 +93,6 @@
92
93
  transition-timing-function: cubic-bezier(0.275, 0.485, 0.515, 1.45);
93
94
  transition-duration: 200ms;
94
95
  }
95
- .squircle {
96
- corner-shape: squircle;
97
- border-radius: 100%;
98
- }
99
96
 
100
97
  label:has(input[aria-invalid='true']) {
101
98
  --input-color: var(--color-error);
@@ -21,7 +21,7 @@
21
21
  <div class="flex flex-col gap-1">
22
22
  <span class="label px-3 text-sm">{label}</span>
23
23
  <div class="join join-vertical">
24
- {#each options as option}
24
+ {#each options as option (option.value)}
25
25
  {@const { class: klass, ...props } = option}
26
26
  <label class="input join-item not-disabled:cursor-pointer not-disabled:hover:bg-base-200">
27
27
  {#if option.icon}
@@ -31,7 +31,7 @@
31
31
  bind:value
32
32
  {...props}
33
33
  >
34
- {#each options as option}
34
+ {#each options as option (option.value)}
35
35
  <option value={option.value} class={['', option.class]} disabled={option.disabled}>
36
36
  {#if option.icon}
37
37
  <option.icon size={18} opacity={0.8} />
@@ -22,8 +22,7 @@
22
22
  new TextareaAutosize({
23
23
  element: () => textarea,
24
24
  input: () => field?.value() || value || '',
25
- // svelte-ignore state_referenced_locally
26
- maxHeight
25
+ maxHeight: (() => maxHeight)()
27
26
  })
28
27
  </script>
29
28
 
@@ -1,18 +1,17 @@
1
1
  <script lang="ts">
2
- import type { RemoteFormField } from '@sveltejs/kit'
2
+ import type { RemoteFormField, RemoteFormFieldValue } from '@sveltejs/kit'
3
3
  import { slide } from 'svelte/transition'
4
4
 
5
5
  let {
6
6
  field
7
7
  }: {
8
- // biome-ignore lint/suspicious/noExplicitAny: Wathever then value type... we use just field.issues()
9
- field: RemoteFormField<any> | undefined
8
+ field: RemoteFormField<RemoteFormFieldValue> | undefined
10
9
  } = $props()
11
10
  </script>
12
11
 
13
12
  {#if field?.issues()?.length}
14
13
  <div class="my-1 flex flex-col text-xs text-error" transition:slide={{ duration: 200 }}>
15
- {#each field.issues() as issue}
14
+ {#each field.issues() as issue (issue.path)}
16
15
  <span>
17
16
  {issue.message}
18
17
  </span>
@@ -1,6 +1,6 @@
1
- import type { RemoteFormField } from '@sveltejs/kit';
1
+ import type { RemoteFormField, RemoteFormFieldValue } from '@sveltejs/kit';
2
2
  type $$ComponentProps = {
3
- field: RemoteFormField<any> | undefined;
3
+ field: RemoteFormField<RemoteFormFieldValue> | undefined;
4
4
  };
5
5
  declare const Issues: import("svelte").Component<$$ComponentProps, {}, "">;
6
6
  type Issues = ReturnType<typeof Issues>;