@marianmeres/stuic 3.181.0 → 3.183.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 +1 -1
- package/dist/components/FieldsBuilder/FieldsBuilder.svelte +101 -150
- package/dist/components/FieldsBuilder/FieldsBuilder.svelte.d.ts +10 -1
- package/dist/components/FieldsBuilder/README.md +82 -3
- package/dist/components/FieldsBuilder/_internal/ColumnsEditor.svelte +624 -0
- package/dist/components/FieldsBuilder/_internal/ColumnsEditor.svelte.d.ts +41 -0
- package/dist/components/FieldsBuilder/_internal/ExtrasEditor.svelte +174 -0
- package/dist/components/FieldsBuilder/_internal/ExtrasEditor.svelte.d.ts +20 -0
- package/dist/components/FieldsBuilder/_internal/column-meta.d.ts +27 -0
- package/dist/components/FieldsBuilder/_internal/column-meta.js +15 -0
- package/dist/components/FieldsBuilder/i18n-sk.js +17 -0
- package/dist/components/FieldsBuilder/i18n.d.ts +17 -0
- package/dist/components/FieldsBuilder/i18n.js +17 -0
- package/dist/components/FieldsBuilder/index.css +20 -0
- package/dist/components/FieldsBuilder/index.d.ts +2 -2
- package/dist/components/FieldsBuilder/types.d.ts +39 -0
- package/dist/components/FieldsBuilder/utils.d.ts +36 -1
- package/dist/components/FieldsBuilder/utils.js +180 -55
- package/dist/components/Input/FieldAssets.svelte +9 -132
- package/dist/components/Input/FieldSingleAsset.svelte +876 -0
- package/dist/components/Input/FieldSingleAsset.svelte.d.ts +135 -0
- package/dist/components/Input/FieldTable.svelte +907 -0
- package/dist/components/Input/FieldTable.svelte.d.ts +98 -0
- package/dist/components/Input/README.md +467 -20
- package/dist/components/Input/_internal/asset-helpers.d.ts +16 -0
- package/dist/components/Input/_internal/asset-helpers.js +46 -0
- package/dist/components/Input/_internal/paste-target.d.ts +15 -0
- package/dist/components/Input/_internal/paste-target.js +114 -0
- package/dist/components/Input/field-single-asset-i18n-sk.d.ts +21 -0
- package/dist/components/Input/field-single-asset-i18n-sk.js +49 -0
- package/dist/components/Input/field-single-asset-i18n.d.ts +68 -0
- package/dist/components/Input/field-single-asset-i18n.js +75 -0
- package/dist/components/Input/field-table-i18n-sk.d.ts +21 -0
- package/dist/components/Input/field-table-i18n-sk.js +41 -0
- package/dist/components/Input/field-table-i18n.d.ts +60 -0
- package/dist/components/Input/field-table-i18n.js +66 -0
- package/dist/components/Input/field-table-number.d.ts +48 -0
- package/dist/components/Input/field-table-number.js +86 -0
- package/dist/components/Input/index.css +801 -0
- package/dist/components/Input/index.d.ts +7 -0
- package/dist/components/Input/index.js +7 -0
- package/docs/domains/actions.md +3 -3
- package/docs/domains/components.md +45 -38
- package/package.json +1 -1
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
INTERNAL to FieldsBuilder — not exported from the package.
|
|
3
|
+
|
|
4
|
+
The controls of one `extras` bag (`Record<string, unknown>`), one per
|
|
5
|
+
declared `FieldTypeExtraDef` (boolean / string / select). Rendered by a
|
|
6
|
+
field row for the palette entry's extras and by a column line for the
|
|
7
|
+
column type's extras — the same bag rule applies to both.
|
|
8
|
+
|
|
9
|
+
Every arm displays the ACTUAL bag value only (no `?? ex.default` fallback):
|
|
10
|
+
defaults are materialized into the bag on add / type change, but a def
|
|
11
|
+
loaded without the key must not render as if it held the default while
|
|
12
|
+
emitting nothing — the control must always match what `value` says.
|
|
13
|
+
|
|
14
|
+
"Empty means absent": `undefined` REMOVES the key, and an emptied bag
|
|
15
|
+
removes `extras` itself — "no value" must have exactly one representation
|
|
16
|
+
downstream. A consumer reading `extras.unit` to decide whether to render a
|
|
17
|
+
suffix should never have to special-case `""`, nor a `{}` that means
|
|
18
|
+
nothing.
|
|
19
|
+
-->
|
|
20
|
+
<script lang="ts">
|
|
21
|
+
import { twMerge } from "../../../utils/tw-merge.js";
|
|
22
|
+
import type { FieldTypeExtraDef, LocalizedText } from "../types.js";
|
|
23
|
+
import { getLocalizedText } from "../utils.js";
|
|
24
|
+
|
|
25
|
+
interface Props {
|
|
26
|
+
extras?: Record<string, unknown>;
|
|
27
|
+
/** The declarations (the palette entry's `extras`). */
|
|
28
|
+
defs: FieldTypeExtraDef[];
|
|
29
|
+
/** Display fallback chain for the declarations' labels / placeholders. */
|
|
30
|
+
displayLanguages?: string[];
|
|
31
|
+
/** Unique prefix for the control ids (label association). */
|
|
32
|
+
idPrefix: string;
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
tabindex?: number;
|
|
35
|
+
/** Rendered below the controls; also marks the string inputs invalid. */
|
|
36
|
+
error?: string;
|
|
37
|
+
class?: string;
|
|
38
|
+
/** Fired after any change to `extras`. */
|
|
39
|
+
onChange?: () => void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let {
|
|
43
|
+
// no fallback on purpose — the parent binds a possibly-undefined bag
|
|
44
|
+
extras = $bindable(),
|
|
45
|
+
defs,
|
|
46
|
+
displayLanguages,
|
|
47
|
+
idPrefix,
|
|
48
|
+
disabled = false,
|
|
49
|
+
tabindex = 0,
|
|
50
|
+
error,
|
|
51
|
+
class: classProp,
|
|
52
|
+
onChange,
|
|
53
|
+
}: Props = $props();
|
|
54
|
+
|
|
55
|
+
const errId = $derived(`${idPrefix}-extras-err`);
|
|
56
|
+
|
|
57
|
+
function displayText(text: LocalizedText | null | undefined): string {
|
|
58
|
+
return getLocalizedText(text, displayLanguages);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function setExtra(key: string, value: unknown) {
|
|
62
|
+
const next = { ...(extras ?? {}) };
|
|
63
|
+
if (value === undefined) delete next[key];
|
|
64
|
+
else next[key] = value;
|
|
65
|
+
extras = Object.keys(next).length ? next : undefined;
|
|
66
|
+
onChange?.();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Display value of a string/select extra (a non-string is shown, not eaten). */
|
|
70
|
+
function extraText(key: string): string {
|
|
71
|
+
const v = extras?.[key];
|
|
72
|
+
return v == null ? "" : String(v);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// while typing, the RAW value is stored (trimming here would fight the
|
|
76
|
+
// caret: a written-back trimmed value makes a trailing space untypable) —
|
|
77
|
+
// only the emptiness test is trimmed; `onchange` normalizes on commit
|
|
78
|
+
function onStringInput(key: string, raw: string) {
|
|
79
|
+
setExtra(key, raw.trim() ? raw : undefined);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function onStringChange(key: string, raw: string) {
|
|
83
|
+
setExtra(key, raw.trim() || undefined);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const INPUT_CLS = [
|
|
87
|
+
"rounded bg-(--stuic-color-input)",
|
|
88
|
+
"border border-(--stuic-color-border)",
|
|
89
|
+
"focus:border-(--stuic-color-border-hover)",
|
|
90
|
+
"focus:outline-none focus:ring-0",
|
|
91
|
+
"focus-visible:outline-none focus-visible:ring-0",
|
|
92
|
+
].join(" ");
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<div class={twMerge("fb-extras fb-field flex flex-col gap-2.5", classProp)}>
|
|
96
|
+
{#each defs as ex, exIdx (ex.key)}
|
|
97
|
+
{#if ex.type === "string" || ex.type === "select"}
|
|
98
|
+
{@const exId = `${idPrefix}-extra-${exIdx}`}
|
|
99
|
+
{@const exValue = extraText(ex.key)}
|
|
100
|
+
<div class="fb-extra">
|
|
101
|
+
<label class="fb-sub-label" for={exId}>
|
|
102
|
+
{displayText(ex.label)}
|
|
103
|
+
</label>
|
|
104
|
+
{#if ex.type === "string"}
|
|
105
|
+
<input
|
|
106
|
+
id={exId}
|
|
107
|
+
type="text"
|
|
108
|
+
class={twMerge(INPUT_CLS, "fb-extra-input w-full")}
|
|
109
|
+
value={exValue}
|
|
110
|
+
maxlength={ex.maxlength}
|
|
111
|
+
placeholder={displayText(ex.placeholder) || undefined}
|
|
112
|
+
oninput={(e) => onStringInput(ex.key, e.currentTarget.value)}
|
|
113
|
+
onchange={(e) => onStringChange(ex.key, e.currentTarget.value)}
|
|
114
|
+
{disabled}
|
|
115
|
+
{tabindex}
|
|
116
|
+
aria-invalid={!!error || undefined}
|
|
117
|
+
aria-describedby={error ? errId : undefined}
|
|
118
|
+
/>
|
|
119
|
+
{:else}
|
|
120
|
+
<select
|
|
121
|
+
id={exId}
|
|
122
|
+
class={twMerge(INPUT_CLS, "fb-extra-input w-full")}
|
|
123
|
+
value={exValue}
|
|
124
|
+
onchange={(e) => setExtra(ex.key, e.currentTarget.value || undefined)}
|
|
125
|
+
{disabled}
|
|
126
|
+
{tabindex}
|
|
127
|
+
>
|
|
128
|
+
<option value="">
|
|
129
|
+
{displayText(ex.placeholder)}
|
|
130
|
+
</option>
|
|
131
|
+
{#each ex.options as opt (opt.value)}
|
|
132
|
+
<option value={opt.value}>
|
|
133
|
+
{displayText(opt.label)}
|
|
134
|
+
</option>
|
|
135
|
+
{/each}
|
|
136
|
+
<!-- a stored value outside the declared list stays visible and
|
|
137
|
+
round-trips (same stance as an unknown field type) -->
|
|
138
|
+
{#if exValue && !ex.options.some((o) => o.value === exValue)}
|
|
139
|
+
<option value={exValue}>{exValue}</option>
|
|
140
|
+
{/if}
|
|
141
|
+
</select>
|
|
142
|
+
{/if}
|
|
143
|
+
{#if ex.description}
|
|
144
|
+
<div class="fb-hint text-xs mt-0.5">
|
|
145
|
+
{displayText(ex.description)}
|
|
146
|
+
</div>
|
|
147
|
+
{/if}
|
|
148
|
+
</div>
|
|
149
|
+
{:else}
|
|
150
|
+
<label class="stuic-checkbox fb-extra flex items-start gap-2 cursor-pointer">
|
|
151
|
+
<input
|
|
152
|
+
type="checkbox"
|
|
153
|
+
checked={!!extras?.[ex.key]}
|
|
154
|
+
onchange={(e) => setExtra(ex.key, e.currentTarget.checked)}
|
|
155
|
+
{disabled}
|
|
156
|
+
{tabindex}
|
|
157
|
+
/>
|
|
158
|
+
<span class="text-sm">
|
|
159
|
+
{displayText(ex.label)}
|
|
160
|
+
{#if ex.description}
|
|
161
|
+
<span class="fb-hint block text-xs">
|
|
162
|
+
{displayText(ex.description)}
|
|
163
|
+
</span>
|
|
164
|
+
{/if}
|
|
165
|
+
</span>
|
|
166
|
+
</label>
|
|
167
|
+
{/if}
|
|
168
|
+
{/each}
|
|
169
|
+
{#if error}
|
|
170
|
+
<div id={errId} class="fb-error-text text-sm">
|
|
171
|
+
{error}
|
|
172
|
+
</div>
|
|
173
|
+
{/if}
|
|
174
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FieldTypeExtraDef } from "../types.js";
|
|
2
|
+
interface Props {
|
|
3
|
+
extras?: Record<string, unknown>;
|
|
4
|
+
/** The declarations (the palette entry's `extras`). */
|
|
5
|
+
defs: FieldTypeExtraDef[];
|
|
6
|
+
/** Display fallback chain for the declarations' labels / placeholders. */
|
|
7
|
+
displayLanguages?: string[];
|
|
8
|
+
/** Unique prefix for the control ids (label association). */
|
|
9
|
+
idPrefix: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
tabindex?: number;
|
|
12
|
+
/** Rendered below the controls; also marks the string inputs invalid. */
|
|
13
|
+
error?: string;
|
|
14
|
+
class?: string;
|
|
15
|
+
/** Fired after any change to `extras`. */
|
|
16
|
+
onChange?: () => void;
|
|
17
|
+
}
|
|
18
|
+
declare const ExtrasEditor: import("svelte").Component<Props, {}, "extras">;
|
|
19
|
+
type ExtrasEditor = ReturnType<typeof ExtrasEditor>;
|
|
20
|
+
export default ExtrasEditor;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { FieldColumnDef } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* INTERNAL to FieldsBuilder — not exported from the package.
|
|
4
|
+
*
|
|
5
|
+
* Per-column editing state, index-aligned with `FieldDef.columns` and kept in
|
|
6
|
+
* lockstep by `ColumnsEditor`. It lives on the parent's `Row` (not inside the
|
|
7
|
+
* editor) on purpose: the row body — and so the editor — is unmounted while a
|
|
8
|
+
* row is collapsed, and a mount-time snapshot would freeze the key of a column
|
|
9
|
+
* added this session, and lose the stored/new distinction the veto hooks
|
|
10
|
+
* depend on, the moment the user collapsed and re-expanded the row.
|
|
11
|
+
*/
|
|
12
|
+
export interface ColumnMeta {
|
|
13
|
+
/** Stable render id (columns have no identity of their own). */
|
|
14
|
+
cid: string;
|
|
15
|
+
/** Key at (re)load time; `undefined` = column added this session. */
|
|
16
|
+
initialKey?: string;
|
|
17
|
+
/** Type at (re)load time (drives the warning and the veto). */
|
|
18
|
+
initialType?: string;
|
|
19
|
+
/** Key derivation from the label stops once true. Loaded columns: true. */
|
|
20
|
+
keyTouched: boolean;
|
|
21
|
+
/** The options / extras sub-block is open. */
|
|
22
|
+
expanded: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Meta of a column present in `value` at (re)load time. */
|
|
25
|
+
export declare function loadedColumnMeta(column: FieldColumnDef): ColumnMeta;
|
|
26
|
+
/** Meta of a column added in this editing session. */
|
|
27
|
+
export declare function newColumnMeta(expanded?: boolean): ColumnMeta;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { getId } from "../../../utils/get-id.js";
|
|
2
|
+
/** Meta of a column present in `value` at (re)load time. */
|
|
3
|
+
export function loadedColumnMeta(column) {
|
|
4
|
+
return {
|
|
5
|
+
cid: getId(),
|
|
6
|
+
initialKey: column.key || undefined,
|
|
7
|
+
initialType: column.type || undefined,
|
|
8
|
+
keyTouched: true,
|
|
9
|
+
expanded: false,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/** Meta of a column added in this editing session. */
|
|
13
|
+
export function newColumnMeta(expanded = false) {
|
|
14
|
+
return { cid: getId(), keyTouched: false, expanded };
|
|
15
|
+
}
|
|
@@ -41,6 +41,19 @@ export const FIELDS_BUILDER_MESSAGES_SK = {
|
|
|
41
41
|
option_value_hint: "Uložená strojová hodnota tejto možnosti",
|
|
42
42
|
remove_option: "Odstrániť možnosť",
|
|
43
43
|
removed_option: "Odstránená možnosť: {{label}}",
|
|
44
|
+
columns_label: "Stĺpce",
|
|
45
|
+
add_column: "Pridať stĺpec",
|
|
46
|
+
empty_columns_message: "Nie sú definované žiadne stĺpce",
|
|
47
|
+
untitled_column: "Nepomenovaný stĺpec",
|
|
48
|
+
column_label_placeholder: "Názov stĺpca",
|
|
49
|
+
column_key_placeholder: "kľúč",
|
|
50
|
+
column_key_hint: "Uložený strojový kľúč tohto stĺpca",
|
|
51
|
+
column_type_label: "Typ stĺpca",
|
|
52
|
+
column_settings: "Nastavenia stĺpca",
|
|
53
|
+
remove_column: "Odstrániť stĺpec",
|
|
54
|
+
removed_column: "Odstránený stĺpec: {{label}}",
|
|
55
|
+
column_type_change_warning: "Zmena typu existujúceho stĺpca nemusí sedieť s hodnotami, ktoré sú v jeho bunkách už uložené.",
|
|
56
|
+
unknown_column_type_warning: "Tento stĺpec má typ, ktorý tento editor nepozná. Zostáva nezmenený a nedá sa tu upravovať.",
|
|
44
57
|
advanced_label: "Rozšírené",
|
|
45
58
|
key_label: "Kľúč",
|
|
46
59
|
key_hint: "Jedinečný strojový identifikátor tohto poľa. Vypĺňa sa automaticky z názvu.",
|
|
@@ -61,6 +74,10 @@ export const FIELDS_BUILDER_MESSAGES_SK = {
|
|
|
61
74
|
err_option_value_duplicate: "Hodnoty možností musia byť jedinečné",
|
|
62
75
|
err_extra_maxlength: "{{label}} — hodnota je príliš dlhá (max. {{max}} znakov)",
|
|
63
76
|
err_max_fields: "Maximálny počet polí je {{max}}",
|
|
77
|
+
err_columns_required: "Pridajte aspoň jeden stĺpec",
|
|
78
|
+
err_max_columns: "Maximálny počet stĺpcov je {{max}}",
|
|
79
|
+
err_column: "Stĺpec {{position}}: {{message}}",
|
|
80
|
+
err_column_key_duplicate: "Tento kľúč už používa iný stĺpec",
|
|
64
81
|
};
|
|
65
82
|
/**
|
|
66
83
|
* Slovak counterpart of `FIELDS_BUILDER_DEFAULT_TYPES` — the `types` palette is
|
|
@@ -35,6 +35,19 @@ export declare const FIELDS_BUILDER_MESSAGES_EN: {
|
|
|
35
35
|
option_value_hint: string;
|
|
36
36
|
remove_option: string;
|
|
37
37
|
removed_option: string;
|
|
38
|
+
columns_label: string;
|
|
39
|
+
add_column: string;
|
|
40
|
+
empty_columns_message: string;
|
|
41
|
+
untitled_column: string;
|
|
42
|
+
column_label_placeholder: string;
|
|
43
|
+
column_key_placeholder: string;
|
|
44
|
+
column_key_hint: string;
|
|
45
|
+
column_type_label: string;
|
|
46
|
+
column_settings: string;
|
|
47
|
+
remove_column: string;
|
|
48
|
+
removed_column: string;
|
|
49
|
+
column_type_change_warning: string;
|
|
50
|
+
unknown_column_type_warning: string;
|
|
38
51
|
advanced_label: string;
|
|
39
52
|
key_label: string;
|
|
40
53
|
key_hint: string;
|
|
@@ -55,6 +68,10 @@ export declare const FIELDS_BUILDER_MESSAGES_EN: {
|
|
|
55
68
|
err_option_value_duplicate: string;
|
|
56
69
|
err_extra_maxlength: string;
|
|
57
70
|
err_max_fields: string;
|
|
71
|
+
err_columns_required: string;
|
|
72
|
+
err_max_columns: string;
|
|
73
|
+
err_column: string;
|
|
74
|
+
err_column_key_duplicate: string;
|
|
58
75
|
};
|
|
59
76
|
/** Every message key `FieldsBuilder` (and its internals) may look up. */
|
|
60
77
|
export type FieldsBuilderMessageKey = keyof typeof FIELDS_BUILDER_MESSAGES_EN;
|
|
@@ -36,6 +36,19 @@ export const FIELDS_BUILDER_MESSAGES_EN = {
|
|
|
36
36
|
option_value_hint: "Stored machine value of this choice",
|
|
37
37
|
remove_option: "Remove choice",
|
|
38
38
|
removed_option: "Removed choice: {{label}}",
|
|
39
|
+
columns_label: "Columns",
|
|
40
|
+
add_column: "Add column",
|
|
41
|
+
empty_columns_message: "No columns defined",
|
|
42
|
+
untitled_column: "Untitled column",
|
|
43
|
+
column_label_placeholder: "Column name",
|
|
44
|
+
column_key_placeholder: "key",
|
|
45
|
+
column_key_hint: "Stored machine key of this column",
|
|
46
|
+
column_type_label: "Column type",
|
|
47
|
+
column_settings: "Column settings",
|
|
48
|
+
remove_column: "Remove column",
|
|
49
|
+
removed_column: "Removed column: {{label}}",
|
|
50
|
+
column_type_change_warning: "Changing the type of an existing column may not fit values already stored in its cells.",
|
|
51
|
+
unknown_column_type_warning: "This column has a type this editor does not recognize. It is kept unchanged and cannot be edited here.",
|
|
39
52
|
advanced_label: "Advanced",
|
|
40
53
|
key_label: "Key",
|
|
41
54
|
key_hint: "Unique machine identifier of this field. Filled in automatically from the label.",
|
|
@@ -56,6 +69,10 @@ export const FIELDS_BUILDER_MESSAGES_EN = {
|
|
|
56
69
|
err_option_value_duplicate: "Choice values must be unique",
|
|
57
70
|
err_extra_maxlength: "{{label}} is too long (max {{max}} characters)",
|
|
58
71
|
err_max_fields: "Maximum number of fields is {{max}}",
|
|
72
|
+
err_columns_required: "Add at least one column",
|
|
73
|
+
err_max_columns: "Maximum number of columns is {{max}}",
|
|
74
|
+
err_column: "Column {{position}}: {{message}}",
|
|
75
|
+
err_column_key_duplicate: "This key is already used by another column",
|
|
59
76
|
};
|
|
60
77
|
/**
|
|
61
78
|
* Builds the `t` prop of `FieldsBuilder` from a message catalog. Unknown or
|
|
@@ -167,6 +167,26 @@
|
|
|
167
167
|
border-top: 1px dashed var(--stuic-fields-builder-row-border);
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
/* =============================================================================
|
|
171
|
+
COLUMNS EDITOR (`supportsColumns` types)
|
|
172
|
+
============================================================================= */
|
|
173
|
+
|
|
174
|
+
.stuic-fields-builder .fb-column-divider {
|
|
175
|
+
border-top: 1px dashed var(--stuic-fields-builder-row-border);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* the per-column options / extras sub-block sits under its line, indented
|
|
179
|
+
past the move buttons and marked by a thin left rule */
|
|
180
|
+
.stuic-fields-builder .fb-column-settings {
|
|
181
|
+
margin-left: calc(var(--spacing) * 5);
|
|
182
|
+
padding-left: calc(var(--spacing) * 2);
|
|
183
|
+
border-left: 2px solid var(--stuic-fields-builder-row-border);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.stuic-fields-builder .fb-column-settings .fb-sub-label {
|
|
187
|
+
margin-top: calc(var(--spacing) * 0.5);
|
|
188
|
+
}
|
|
189
|
+
|
|
170
190
|
/* =============================================================================
|
|
171
191
|
PREVIEW PANE
|
|
172
192
|
============================================================================= */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default as FieldsBuilder, type Props as FieldsBuilderProps, } from "./FieldsBuilder.svelte";
|
|
2
|
-
export type { FieldDef, FieldLock, FieldOptionDef, FieldTypeDef, FieldTypeExtraBaseDef, FieldTypeExtraBooleanDef, FieldTypeExtraDef, FieldTypeExtraSelectDef, FieldTypeExtraStringDef, LocalizedText, } from "./types.js";
|
|
3
|
-
export { DEFAULT_FIELD_TYPES as FIELDS_BUILDER_DEFAULT_TYPES, DEFAULT_KEY_PATTERN as FIELDS_BUILDER_DEFAULT_KEY_PATTERN, getLocalizedText, slugifyKey, uniqueKey, validateFieldDefs, type FieldDefRowErrors, type FieldDefsValidationResult, type ValidateFieldDefsOptions, } from "./utils.js";
|
|
2
|
+
export type { FieldColumnDef, FieldDef, FieldLock, FieldOptionDef, FieldTypeDef, FieldTypeExtraBaseDef, FieldTypeExtraBooleanDef, FieldTypeExtraDef, FieldTypeExtraSelectDef, FieldTypeExtraStringDef, LocalizedText, } from "./types.js";
|
|
3
|
+
export { DEFAULT_FIELD_TYPES as FIELDS_BUILDER_DEFAULT_TYPES, DEFAULT_KEY_PATTERN as FIELDS_BUILDER_DEFAULT_KEY_PATTERN, getLocalizedText, slugifyKey, uniqueKey, validateFieldDefs, type FieldColumnErrors, type FieldDefRowErrors, type FieldDefsValidationResult, type ValidateFieldDefsOptions, } from "./utils.js";
|
|
4
4
|
export { createFieldsBuilderT, FIELDS_BUILDER_MESSAGES_EN, type FieldsBuilderMessageKey, type FieldsBuilderMessages, } from "./i18n.js";
|
|
5
5
|
export { FIELDS_BUILDER_MESSAGES_SK, FIELDS_BUILDER_DEFAULT_TYPES_SK, } from "./i18n-sk.js";
|
|
@@ -12,12 +12,31 @@ export interface FieldOptionDef {
|
|
|
12
12
|
value: string;
|
|
13
13
|
label: LocalizedText;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* One column of a field whose palette entry declares `supportsColumns` — a
|
|
17
|
+
* field in miniature: key, type, label, and the column type's options /
|
|
18
|
+
* extras. There is deliberately no per-column description, required flag or
|
|
19
|
+
* lock (each is additive later without changing the existing members).
|
|
20
|
+
*/
|
|
21
|
+
export interface FieldColumnDef {
|
|
22
|
+
/** Machine key. Unique within the field's columns (not across fields). */
|
|
23
|
+
key: string;
|
|
24
|
+
/** One of the entry's column palette types (`columnTypes`). */
|
|
25
|
+
type: string;
|
|
26
|
+
label: LocalizedText;
|
|
27
|
+
/** Edited for column types declaring `supportsOptions`. Kept when the type changes. */
|
|
28
|
+
options?: FieldOptionDef[];
|
|
29
|
+
/** Per column-type extras, driven by that column type's `extras`. Kept when the type changes. */
|
|
30
|
+
extras?: Record<string, unknown>;
|
|
31
|
+
}
|
|
15
32
|
/** What the user may NOT change on a field. Absent flag = editable. */
|
|
16
33
|
export interface FieldLock {
|
|
17
34
|
key?: boolean;
|
|
18
35
|
type?: boolean;
|
|
19
36
|
required?: boolean;
|
|
20
37
|
options?: boolean;
|
|
38
|
+
/** Render the column list read-only (the counterpart of `options`). */
|
|
39
|
+
columns?: boolean;
|
|
21
40
|
/** Cannot be removed from the list. */
|
|
22
41
|
delete?: boolean;
|
|
23
42
|
/** Cannot be dragged, and other fields cannot be moved past it. */
|
|
@@ -51,6 +70,14 @@ export interface FieldDef {
|
|
|
51
70
|
* extras of a previous type are RETAINED when the type changes.
|
|
52
71
|
*/
|
|
53
72
|
extras?: Record<string, unknown>;
|
|
73
|
+
/**
|
|
74
|
+
* Edited and validated only for palette entries declaring
|
|
75
|
+
* `supportsColumns`. Like `options`, RETAINED on the def when the field's
|
|
76
|
+
* type changes away (never silently drop data; switching back restores
|
|
77
|
+
* them) — consumers compiling the list should ignore `columns` on types
|
|
78
|
+
* without `supportsColumns`.
|
|
79
|
+
*/
|
|
80
|
+
columns?: FieldColumnDef[];
|
|
54
81
|
/** What the user may NOT change. Absent = fully editable. */
|
|
55
82
|
lock?: FieldLock;
|
|
56
83
|
}
|
|
@@ -112,6 +139,18 @@ export interface FieldTypeDef {
|
|
|
112
139
|
supportsOptions?: boolean;
|
|
113
140
|
/** Extra per-field controls, rendered into `FieldDef.extras[key]`. */
|
|
114
141
|
extras?: FieldTypeExtraDef[];
|
|
142
|
+
/** Renders the column editor and allows `FieldDef.columns`. */
|
|
143
|
+
supportsColumns?: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* The palette a column may take. Default: the component's `types` without
|
|
146
|
+
* the entries that `supportsColumns` themselves. Columns do not nest: the
|
|
147
|
+
* column editor ignores `supportsColumns` on any entry listed here. A
|
|
148
|
+
* column palette entry's `supportsOptions` / `extras` work exactly as they
|
|
149
|
+
* do per field — so leave off the extras that only make sense per field.
|
|
150
|
+
*/
|
|
151
|
+
columnTypes?: FieldTypeDef[];
|
|
152
|
+
/** Most columns one field of this type may declare. */
|
|
153
|
+
maxColumns?: number;
|
|
115
154
|
/** Optional live preview of a single field of this type. */
|
|
116
155
|
preview?: Snippet<[FieldDef]>;
|
|
117
156
|
}
|
|
@@ -25,12 +25,30 @@ export declare function slugifyKey(input: string, maxLength?: number): string;
|
|
|
25
25
|
*/
|
|
26
26
|
export declare function uniqueKey(base: string, isTaken: (key: string) => boolean, maxLength?: number): string;
|
|
27
27
|
export declare function isKeyReserved(key: string, reservedKeys?: string[] | ((key: string) => boolean)): boolean;
|
|
28
|
+
/** Errors of one column of a `supportsColumns` field. */
|
|
29
|
+
export interface FieldColumnErrors {
|
|
30
|
+
label?: string;
|
|
31
|
+
key?: string;
|
|
32
|
+
options?: string;
|
|
33
|
+
/** First offending extra of the column (its label is in the message). */
|
|
34
|
+
extras?: string;
|
|
35
|
+
}
|
|
28
36
|
export interface FieldDefRowErrors {
|
|
29
37
|
label?: string;
|
|
30
38
|
key?: string;
|
|
31
39
|
options?: string;
|
|
40
|
+
/**
|
|
41
|
+
* The column-list summary: no columns / over `maxColumns`, else the first
|
|
42
|
+
* column-level message already prefixed with its position ("Column 2: …").
|
|
43
|
+
*/
|
|
44
|
+
columns?: string;
|
|
32
45
|
/** First offending extra of the row (its label is in the message). */
|
|
33
46
|
extras?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Index-aligned with `def.columns`; `null` = that column has no errors.
|
|
49
|
+
* Present only when at least one column has an error.
|
|
50
|
+
*/
|
|
51
|
+
columnErrors?: (FieldColumnErrors | null)[];
|
|
34
52
|
}
|
|
35
53
|
export interface FieldDefsValidationResult {
|
|
36
54
|
valid: boolean;
|
|
@@ -39,6 +57,20 @@ export interface FieldDefsValidationResult {
|
|
|
39
57
|
/** Index-aligned with the input defs. `null` = row has no errors. */
|
|
40
58
|
rowErrors: (FieldDefRowErrors | null)[];
|
|
41
59
|
}
|
|
60
|
+
/** The slice of a palette entry `validateFieldDefs` reads. */
|
|
61
|
+
export type ValidateFieldDefsTypeDef = Pick<FieldTypeDef, "type" | "supportsOptions" | "extras" | "supportsColumns" | "columnTypes" | "maxColumns">;
|
|
62
|
+
/**
|
|
63
|
+
* The palette a column of `entry` may take: its own `columnTypes`, else the
|
|
64
|
+
* component's `types` without every entry that `supportsColumns` itself
|
|
65
|
+
* (columns never nest).
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolveColumnTypes<T extends Pick<FieldTypeDef, "supportsColumns">>(entry: Pick<FieldTypeDef, "columnTypes">, types: T[] | null | undefined): (T | FieldTypeDef)[];
|
|
68
|
+
/**
|
|
69
|
+
* Materialize the `default` of every declared extra that the bag does not
|
|
70
|
+
* hold yet. Returns the same bag when nothing was seeded (so `undefined`
|
|
71
|
+
* stays `undefined` for a type without defaults).
|
|
72
|
+
*/
|
|
73
|
+
export declare function seedExtraDefaults(extras: Record<string, unknown> | undefined, entry: Pick<FieldTypeDef, "extras"> | undefined): Record<string, unknown> | undefined;
|
|
42
74
|
export interface ValidateFieldDefsOptions {
|
|
43
75
|
/**
|
|
44
76
|
* The type palette. When provided, defs with a `type` not present here are
|
|
@@ -46,7 +78,7 @@ export interface ValidateFieldDefsOptions {
|
|
|
46
78
|
* must never block the rest of the list), but their keys still count toward
|
|
47
79
|
* uniqueness.
|
|
48
80
|
*/
|
|
49
|
-
types?:
|
|
81
|
+
types?: ValidateFieldDefsTypeDef[];
|
|
50
82
|
keyPattern?: RegExp;
|
|
51
83
|
keyMaxLength?: number;
|
|
52
84
|
reservedKeys?: string[] | ((key: string) => boolean);
|
|
@@ -66,6 +98,9 @@ export interface ValidateFieldDefsOptions {
|
|
|
66
98
|
* Validate a list of field defs: label non-empty, key present/pattern/length/
|
|
67
99
|
* unique/not-reserved, choice types have at least one option with non-empty
|
|
68
100
|
* unique values, string extras within `maxlength`, `maxFields` not exceeded.
|
|
101
|
+
* A `supportsColumns` type additionally needs at least one column, at most
|
|
102
|
+
* `maxColumns`, and every column (of a known column type) passes the label /
|
|
103
|
+
* key (unique within the field) / options / extras rules above.
|
|
69
104
|
*
|
|
70
105
|
* This is client-side convenience only — a consumer persisting the list MUST
|
|
71
106
|
* re-validate server-side; this function is not a security boundary.
|