@r2digisolutions/components 0.6.0 → 0.6.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.
- package/dist/components/molecules/Combobox/Combobox.stories.d.ts +6 -0
- package/dist/components/molecules/Combobox/Combobox.stories.js +5 -2
- package/dist/components/molecules/Combobox/Combobox.svelte +155 -64
- package/dist/components/molecules/Combobox/Combobox.svelte.d.ts +15 -0
- package/dist/components/molecules/Combobox/ComboboxStory.svelte +25 -12
- package/dist/components/molecules/Combobox/ComboboxStory.svelte.d.ts +1 -0
- package/dist/components/molecules/Combobox/combobox-context.d.ts +12 -0
- package/dist/components/molecules/Combobox/combobox-context.js +10 -0
- package/dist/components/molecules/ComboboxItem/ComboboxItem.stories.d.ts +9 -0
- package/dist/components/molecules/ComboboxItem/ComboboxItem.stories.js +8 -0
- package/dist/components/molecules/ComboboxItem/ComboboxItem.svelte +121 -0
- package/dist/components/molecules/ComboboxItem/ComboboxItem.svelte.d.ts +33 -0
- package/dist/components/molecules/ComboboxItem/ComboboxItemStory.svelte +54 -0
- package/dist/components/molecules/ComboboxItem/ComboboxItemStory.svelte.d.ts +3 -0
- package/dist/components/molecules/Form/Form.svelte +36 -10
- package/dist/components/molecules/FormField/FormField.svelte +56 -19
- package/dist/components/molecules/FormField/FormField.svelte.d.ts +21 -6
- package/dist/components/molecules/FormPasswordInput/FormPasswordInput.svelte +38 -9
- package/dist/components/molecules/FormPasswordInput/FormPasswordInput.svelte.d.ts +8 -1
- package/dist/components/organisms/BlogEditor/BlogEditorStory.svelte +1 -1
- package/dist/components/organisms/FileUploader/FileUploader.svelte +7 -3
- package/dist/components/organisms/InvoicePage/InvoicePage.svelte +1 -1
- package/dist/components/organisms/ProfileHeaderUploader/ProfileHeaderUploader.svelte +30 -10
- package/dist/components/organisms/ProfileHeaderUploader/ProfileHeaderUploader.svelte.d.ts +4 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +3 -1
- package/dist/styles.css +6 -0
- package/dist/utils/formContext.d.ts +58 -0
- package/dist/utils/formContext.js +79 -1
- package/package.json +24 -24
package/dist/index.d.ts
CHANGED
|
@@ -210,7 +210,10 @@ export type { TimeFormat } from './components/molecules/TimePicker/TimePicker.sv
|
|
|
210
210
|
export { default as DateTimePicker } from './components/molecules/DateTimePicker/DateTimePicker.svelte';
|
|
211
211
|
export { default as DateRangePicker } from './components/molecules/DateRangePicker/DateRangePicker.svelte';
|
|
212
212
|
export { default as Combobox } from './components/molecules/Combobox/Combobox.svelte';
|
|
213
|
-
export type { ComboboxOption } from './components/molecules/Combobox/Combobox.svelte';
|
|
213
|
+
export type { ComboboxOption, ComboboxItemState } from './components/molecules/Combobox/Combobox.svelte';
|
|
214
|
+
export { default as ComboboxItem } from './components/molecules/ComboboxItem/ComboboxItem.svelte';
|
|
215
|
+
export { COMBOBOX_CONTEXT, COMBOBOX_CREATE_KEY, getComboboxContext, setComboboxContext } from './components/molecules/Combobox/combobox-context.js';
|
|
216
|
+
export type { ComboboxContext } from './components/molecules/Combobox/combobox-context.js';
|
|
214
217
|
export { default as MultiSelect } from './components/molecules/MultiSelect/MultiSelect.svelte';
|
|
215
218
|
export type { MultiSelectOption } from './components/molecules/MultiSelect/MultiSelect.svelte';
|
|
216
219
|
export { default as ConfirmDialog } from './components/molecules/ConfirmDialog/ConfirmDialog.svelte';
|
|
@@ -306,8 +309,8 @@ export type { FilterChip } from './components/molecules/FilterBar/FilterBar.svel
|
|
|
306
309
|
export { default as SortableList } from './components/molecules/SortableList/SortableList.svelte';
|
|
307
310
|
export type { SortableItem } from './components/molecules/SortableList/SortableList.svelte';
|
|
308
311
|
export { default as Form } from './components/molecules/Form/Form.svelte';
|
|
309
|
-
export { getFormContext, FORM_CONTEXT_KEY, remoteIssuesToErrors, isRemoteForm, fieldPath, resolveFormFieldState, applyFormDataSync, sameStringArray } from './utils/formContext.js';
|
|
310
|
-
export type { FormErrors, FormContext, FormDataValues, FormFieldStatus, FormRemote,
|
|
312
|
+
export { getFormContext, FORM_CONTEXT_KEY, remoteIssuesToErrors, isRemoteForm, fieldPath, resolveFormFieldState, resolveRemoteInputProps, parseRemoteFieldName, remoteAsProps, getRemoteFormId, applyFormDataSync, sameStringArray } from './utils/formContext.js';
|
|
313
|
+
export type { FormErrors, FormContext, FormDataValues, FormFieldStatus, FormRemote, ResolvedRemoteInputProps, ParsedRemoteFieldName,
|
|
311
314
|
/** @deprecated Use `FormRemote` */
|
|
312
315
|
RemoteFormSpread, RemoteForm, RemoteFormInput, RemoteFormIssue } from './utils/formContext.js';
|
|
313
316
|
export { validateForm, isFormDirty, firstFormError } from './utils/formValidate.js';
|
package/dist/index.js
CHANGED
|
@@ -166,6 +166,8 @@ export { default as TimePicker } from './components/molecules/TimePicker/TimePic
|
|
|
166
166
|
export { default as DateTimePicker } from './components/molecules/DateTimePicker/DateTimePicker.svelte';
|
|
167
167
|
export { default as DateRangePicker } from './components/molecules/DateRangePicker/DateRangePicker.svelte';
|
|
168
168
|
export { default as Combobox } from './components/molecules/Combobox/Combobox.svelte';
|
|
169
|
+
export { default as ComboboxItem } from './components/molecules/ComboboxItem/ComboboxItem.svelte';
|
|
170
|
+
export { COMBOBOX_CONTEXT, COMBOBOX_CREATE_KEY, getComboboxContext, setComboboxContext } from './components/molecules/Combobox/combobox-context.js';
|
|
169
171
|
export { default as MultiSelect } from './components/molecules/MultiSelect/MultiSelect.svelte';
|
|
170
172
|
export { default as ConfirmDialog } from './components/molecules/ConfirmDialog/ConfirmDialog.svelte';
|
|
171
173
|
export { default as ContextMenu } from './components/molecules/ContextMenu/ContextMenu.svelte';
|
|
@@ -233,7 +235,7 @@ export { default as TableOfContents } from './components/molecules/TableOfConten
|
|
|
233
235
|
export { default as FilterBar } from './components/molecules/FilterBar/FilterBar.svelte';
|
|
234
236
|
export { default as SortableList } from './components/molecules/SortableList/SortableList.svelte';
|
|
235
237
|
export { default as Form } from './components/molecules/Form/Form.svelte';
|
|
236
|
-
export { getFormContext, FORM_CONTEXT_KEY, remoteIssuesToErrors, isRemoteForm, fieldPath, resolveFormFieldState, applyFormDataSync, sameStringArray } from './utils/formContext.js';
|
|
238
|
+
export { getFormContext, FORM_CONTEXT_KEY, remoteIssuesToErrors, isRemoteForm, fieldPath, resolveFormFieldState, resolveRemoteInputProps, parseRemoteFieldName, remoteAsProps, getRemoteFormId, applyFormDataSync, sameStringArray } from './utils/formContext.js';
|
|
237
239
|
export { validateForm, isFormDirty, firstFormError } from './utils/formValidate.js';
|
|
238
240
|
export { UI_DICTIONARIES, resolveLocaleTag, getDictionary, formatMessage } from './utils/i18n.js';
|
|
239
241
|
export { i18n } from './utils/i18n.svelte.js';
|
package/dist/styles.css
CHANGED
|
@@ -234,4 +234,10 @@
|
|
|
234
234
|
.text-primary { color: var(--text-primary); }
|
|
235
235
|
.text-secondary { color: var(--text-secondary); }
|
|
236
236
|
.text-muted { color: var(--text-muted); }
|
|
237
|
+
|
|
238
|
+
/* SVG chart labels — Tailwind fill-* needs these (text-* alone does not paint <text>) */
|
|
239
|
+
.fill-primary { fill: var(--text-primary); }
|
|
240
|
+
.fill-secondary { fill: var(--text-secondary); }
|
|
241
|
+
.fill-muted { fill: var(--text-muted); }
|
|
242
|
+
.stroke-border { stroke: var(--border); }
|
|
237
243
|
}
|
|
@@ -30,6 +30,13 @@ export interface FormContext<TData extends FormDataValues = FormDataValues, TRes
|
|
|
30
30
|
disabled: boolean;
|
|
31
31
|
/** Last result from a remote form / submit handler, if any */
|
|
32
32
|
result: TResult | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Full Kit `RemoteForm` when `<Form remote={...}>` received one
|
|
35
|
+
* (not an `.enhance(...)` return). Used by fields to call `.as()`.
|
|
36
|
+
*/
|
|
37
|
+
remote: RemoteForm<any, any> | null;
|
|
38
|
+
/** Stable Kit form id (`1p9kxmo/login_user`) for encoding input names */
|
|
39
|
+
remoteFormId: string | null;
|
|
33
40
|
setError: (name: string, message: string) => void;
|
|
34
41
|
clearError: (name: string) => void;
|
|
35
42
|
clearErrors: () => void;
|
|
@@ -37,6 +44,57 @@ export interface FormContext<TData extends FormDataValues = FormDataValues, TRes
|
|
|
37
44
|
getError: (name: string) => string | undefined;
|
|
38
45
|
getData: <K extends keyof TData & string>(name: K) => TData[K] | undefined;
|
|
39
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Props safe to spread onto library `<Input>` / `<PasswordInput>` for Kit remote forms.
|
|
49
|
+
* Omits Kit `value` getters/setters so they do not fight `bind:value`.
|
|
50
|
+
*/
|
|
51
|
+
export type ResolvedRemoteInputProps = {
|
|
52
|
+
name?: string;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Extract Kit remote form id from `remote.action` (`?/remote=<id>`).
|
|
56
|
+
* Pass `untrack(() => remote.action)` from callers inside effects/derived.
|
|
57
|
+
*/
|
|
58
|
+
export declare function getRemoteFormId(action: string | undefined | null): string | null;
|
|
59
|
+
/**
|
|
60
|
+
* Resolve HTML input props for a field inside a Kit remote form.
|
|
61
|
+
* Prefer a precomputed `formId` string so fields never touch Kit proxies.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveRemoteInputProps(formId: string | null | undefined, logicalName: string | undefined, type?: string): ResolvedRemoteInputProps;
|
|
64
|
+
export type ParsedRemoteFieldName = {
|
|
65
|
+
/** Field path for errors / `form.data` (`email`, `items[0].name`) */
|
|
66
|
+
logicalName: string | undefined;
|
|
67
|
+
/** Exact HTML `name` to put on the input (Kit-encoded or plain) */
|
|
68
|
+
htmlName: string | undefined;
|
|
69
|
+
/** True when `name` already includes `/formId` (from Kit `.as()`) */
|
|
70
|
+
isEncoded: boolean;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Split a Kit-encoded HTML `name` (`email/1p9kxmo/login_user`, `n:age/...`)
|
|
74
|
+
* into logical + html parts. Plain names pass through unchanged.
|
|
75
|
+
*
|
|
76
|
+
* When `formId` is known, uses Kit’s suffix rule (`/${formId}`).
|
|
77
|
+
* Otherwise treats the first `/` after an optional `n:`/`b:` prefix as the form-id boundary
|
|
78
|
+
* (logical paths use `.` / `[n]`, never `/`).
|
|
79
|
+
*/
|
|
80
|
+
export declare function parseRemoteFieldName(name: string | undefined, formId?: string | null): ParsedRemoteFieldName;
|
|
81
|
+
/**
|
|
82
|
+
* Safe props to spread onto `FormField` / `FormPasswordInput` from Kit `.as(...)`.
|
|
83
|
+
* Keeps `name` (+ `type`) and drops Kit `value` / `defaultValue` accessors that
|
|
84
|
+
* fight library `$bindable` and can cause `effect_update_depth_exceeded`.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```svelte
|
|
88
|
+
* <FormField {...remoteAsProps(login_user.fields.email.as('email'))} label="Email" />
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function remoteAsProps(asProps: {
|
|
92
|
+
name: string;
|
|
93
|
+
type?: string;
|
|
94
|
+
}): {
|
|
95
|
+
name: string;
|
|
96
|
+
type?: string;
|
|
97
|
+
};
|
|
40
98
|
/**
|
|
41
99
|
* Access the nearest `<Form>` context from a child component.
|
|
42
100
|
* Returns `null` when used outside a Form.
|
|
@@ -7,6 +7,83 @@ export const FORM_CONTEXT_KEY = 'r2-form';
|
|
|
7
7
|
export function fieldPath(...segments) {
|
|
8
8
|
return segments.map(String).filter((s) => s.length > 0).join('.');
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Extract Kit remote form id from `remote.action` (`?/remote=<id>`).
|
|
12
|
+
* Pass `untrack(() => remote.action)` from callers inside effects/derived.
|
|
13
|
+
*/
|
|
14
|
+
export function getRemoteFormId(action) {
|
|
15
|
+
if (!action)
|
|
16
|
+
return null;
|
|
17
|
+
const match = action.match(/\/remote=([^&]+)/);
|
|
18
|
+
return match ? decodeURIComponent(match[1]) : null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve HTML input props for a field inside a Kit remote form.
|
|
22
|
+
* Prefer a precomputed `formId` string so fields never touch Kit proxies.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveRemoteInputProps(formId, logicalName, type = 'text') {
|
|
25
|
+
if (!logicalName)
|
|
26
|
+
return {};
|
|
27
|
+
if (!formId)
|
|
28
|
+
return { name: logicalName };
|
|
29
|
+
let prefix = '';
|
|
30
|
+
if (type === 'number' || type === 'range')
|
|
31
|
+
prefix = 'n:';
|
|
32
|
+
else if (type === 'checkbox' || type === 'boolean')
|
|
33
|
+
prefix = 'b:';
|
|
34
|
+
return { name: `${prefix}${logicalName}/${formId}` };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Split a Kit-encoded HTML `name` (`email/1p9kxmo/login_user`, `n:age/...`)
|
|
38
|
+
* into logical + html parts. Plain names pass through unchanged.
|
|
39
|
+
*
|
|
40
|
+
* When `formId` is known, uses Kit’s suffix rule (`/${formId}`).
|
|
41
|
+
* Otherwise treats the first `/` after an optional `n:`/`b:` prefix as the form-id boundary
|
|
42
|
+
* (logical paths use `.` / `[n]`, never `/`).
|
|
43
|
+
*/
|
|
44
|
+
export function parseRemoteFieldName(name, formId) {
|
|
45
|
+
if (!name) {
|
|
46
|
+
return { logicalName: undefined, htmlName: undefined, isEncoded: false };
|
|
47
|
+
}
|
|
48
|
+
const htmlName = name;
|
|
49
|
+
if (formId && name.endsWith(`/${formId}`)) {
|
|
50
|
+
let logical = name.slice(0, -(formId.length + 1));
|
|
51
|
+
if (logical.startsWith('n:') || logical.startsWith('b:'))
|
|
52
|
+
logical = logical.slice(2);
|
|
53
|
+
if (logical.endsWith('[]'))
|
|
54
|
+
logical = logical.slice(0, -2);
|
|
55
|
+
return { logicalName: logical, htmlName, isEncoded: true };
|
|
56
|
+
}
|
|
57
|
+
// Heuristic without formId: Kit-encoded names contain `/`
|
|
58
|
+
if (name.includes('/')) {
|
|
59
|
+
let rest = name;
|
|
60
|
+
if (rest.startsWith('n:') || rest.startsWith('b:'))
|
|
61
|
+
rest = rest.slice(2);
|
|
62
|
+
const slash = rest.indexOf('/');
|
|
63
|
+
if (slash !== -1) {
|
|
64
|
+
let logical = rest.slice(0, slash);
|
|
65
|
+
if (logical.endsWith('[]'))
|
|
66
|
+
logical = logical.slice(0, -2);
|
|
67
|
+
return { logicalName: logical, htmlName, isEncoded: true };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { logicalName: name, htmlName: name, isEncoded: false };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Safe props to spread onto `FormField` / `FormPasswordInput` from Kit `.as(...)`.
|
|
74
|
+
* Keeps `name` (+ `type`) and drops Kit `value` / `defaultValue` accessors that
|
|
75
|
+
* fight library `$bindable` and can cause `effect_update_depth_exceeded`.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```svelte
|
|
79
|
+
* <FormField {...remoteAsProps(login_user.fields.email.as('email'))} label="Email" />
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export function remoteAsProps(asProps) {
|
|
83
|
+
return asProps.type != null
|
|
84
|
+
? { name: asProps.name, type: asProps.type }
|
|
85
|
+
: { name: asProps.name };
|
|
86
|
+
}
|
|
10
87
|
/**
|
|
11
88
|
* Access the nearest `<Form>` context from a child component.
|
|
12
89
|
* Returns `null` when used outside a Form.
|
|
@@ -42,7 +119,8 @@ export function remoteIssuesToErrors(issues) {
|
|
|
42
119
|
}
|
|
43
120
|
/** True when the spread value is a full `RemoteForm` (has `fields` / `pending`). */
|
|
44
121
|
export function isRemoteForm(remote) {
|
|
45
|
-
|
|
122
|
+
// Avoid reading `.fields` (client getter allocates a proxy and can loop in `$derived`).
|
|
123
|
+
return !!remote && 'fields' in remote;
|
|
46
124
|
}
|
|
47
125
|
/**
|
|
48
126
|
* Shared resolution for form-aware controls (error / status / disabled).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@r2digisolutions/components",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "R2DigiSolutions Svelte 5 component library — Atomic Design, Tailwind 4, Light/Dark mode",
|
|
6
6
|
"license": "MIT",
|
|
@@ -66,40 +66,40 @@
|
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@eslint/js": "^10.0.1",
|
|
69
|
-
"@lucide/svelte": "^1.
|
|
70
|
-
"@playwright/test": "^1.
|
|
71
|
-
"@storybook/addon-a11y": "^
|
|
69
|
+
"@lucide/svelte": "^1.33.0",
|
|
70
|
+
"@playwright/test": "^1.62.1",
|
|
71
|
+
"@storybook/addon-a11y": "^10.5.10",
|
|
72
72
|
"@storybook/addon-essentials": "^8.6.18",
|
|
73
73
|
"@storybook/addon-svelte-csf": "^5.1.2",
|
|
74
|
-
"@storybook/addon-themes": "^
|
|
75
|
-
"@storybook/svelte": "^
|
|
76
|
-
"@storybook/sveltekit": "^
|
|
74
|
+
"@storybook/addon-themes": "^10.5.10",
|
|
75
|
+
"@storybook/svelte": "^10.5.10",
|
|
76
|
+
"@storybook/sveltekit": "^10.5.10",
|
|
77
77
|
"@sveltejs/adapter-static": "next",
|
|
78
78
|
"@sveltejs/kit": "next",
|
|
79
79
|
"@sveltejs/package": "^2.5.8",
|
|
80
|
-
"@sveltejs/vite-plugin-svelte": "^7.
|
|
80
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
81
81
|
"@tailwindcss/vite": "^4.3.3",
|
|
82
|
-
"@types/node": "^
|
|
83
|
-
"@vitest/browser-playwright": "^4.1.
|
|
84
|
-
"bumpp": "^
|
|
85
|
-
"eslint": "^10.
|
|
82
|
+
"@types/node": "^26.2.0",
|
|
83
|
+
"@vitest/browser-playwright": "^4.1.11",
|
|
84
|
+
"bumpp": "^12.1.1",
|
|
85
|
+
"eslint": "^10.8.1",
|
|
86
86
|
"eslint-config-prettier": "^10.1.8",
|
|
87
|
-
"eslint-plugin-svelte": "^3.
|
|
88
|
-
"globals": "^17.
|
|
87
|
+
"eslint-plugin-svelte": "^3.23.0",
|
|
88
|
+
"globals": "^17.11.0",
|
|
89
89
|
"mdsvex": "^0.12.8",
|
|
90
|
-
"playwright": "^1.
|
|
90
|
+
"playwright": "^1.62.1",
|
|
91
91
|
"prettier": "^3.9.6",
|
|
92
92
|
"prettier-plugin-svelte": "^4.1.1",
|
|
93
93
|
"prettier-plugin-tailwindcss": "^0.8.1",
|
|
94
|
-
"publint": "^0.3.
|
|
95
|
-
"storybook": "^
|
|
96
|
-
"svelte": "^5.56.
|
|
97
|
-
"svelte-check": "^4.7.
|
|
94
|
+
"publint": "^0.3.24",
|
|
95
|
+
"storybook": "^10.5.10",
|
|
96
|
+
"svelte": "^5.56.9",
|
|
97
|
+
"svelte-check": "^4.7.6",
|
|
98
98
|
"tailwindcss": "^4.3.3",
|
|
99
|
-
"typescript": "
|
|
100
|
-
"typescript-eslint": "^8.
|
|
101
|
-
"vite": "^8.
|
|
102
|
-
"vitest": "^4.1.
|
|
99
|
+
"typescript": "6.0.3",
|
|
100
|
+
"typescript-eslint": "^8.67.0",
|
|
101
|
+
"vite": "^8.2.2",
|
|
102
|
+
"vitest": "^4.1.11",
|
|
103
103
|
"vitest-browser-svelte": "^3.0.0"
|
|
104
104
|
},
|
|
105
105
|
"keywords": [
|
|
@@ -111,6 +111,6 @@
|
|
|
111
111
|
"atomic-design"
|
|
112
112
|
],
|
|
113
113
|
"dependencies": {
|
|
114
|
-
"@xyflow/svelte": "^1.6.
|
|
114
|
+
"@xyflow/svelte": "^1.6.3"
|
|
115
115
|
}
|
|
116
116
|
}
|