@marianmeres/stuic 3.182.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/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/README.md +217 -21
- 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/index.css +204 -0
- package/dist/components/Input/index.d.ts +3 -0
- package/dist/components/Input/index.js +3 -0
- package/docs/domains/actions.md +3 -3
- package/docs/domains/components.md +22 -21
- package/package.json +1 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slovak message catalog for `FieldSingleAsset`. Opt-in — English stays the built-in
|
|
3
|
+
* default, and this module is only pulled into a bundle when it is actually imported
|
|
4
|
+
* (the component itself never references it).
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```svelte
|
|
8
|
+
* <script>
|
|
9
|
+
* import {
|
|
10
|
+
* FieldSingleAsset,
|
|
11
|
+
* createFieldSingleAssetT,
|
|
12
|
+
* FIELD_SINGLE_ASSET_MESSAGES_SK,
|
|
13
|
+
* } from "@marianmeres/stuic";
|
|
14
|
+
* const t = createFieldSingleAssetT(FIELD_SINGLE_ASSET_MESSAGES_SK);
|
|
15
|
+
* </script>
|
|
16
|
+
*
|
|
17
|
+
* <FieldSingleAsset name="avatar" bind:value {processAsset} {t} />
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export const FIELD_SINGLE_ASSET_MESSAGES_SK = {
|
|
21
|
+
field_req_att: "Toto pole vyžaduje pozornosť. Skontrolujte ho a skúste to znova.",
|
|
22
|
+
pick_file: "Vybrať súbor",
|
|
23
|
+
replace_file: "Nahradiť {{name}}",
|
|
24
|
+
empty_hint: "Presuňte sem súbor alebo kliknite a vyberte ho",
|
|
25
|
+
remove: "Odstrániť",
|
|
26
|
+
removed: "Súbor {{name}} bol odstránený",
|
|
27
|
+
undo: "Vrátiť späť",
|
|
28
|
+
restored: "Súbor {{name}} bol obnovený",
|
|
29
|
+
preview: "Náhľad",
|
|
30
|
+
retry: "Skúsiť nahrať znova",
|
|
31
|
+
discard: "Zahodiť",
|
|
32
|
+
cancel_upload: "Zrušiť nahrávanie",
|
|
33
|
+
uploading: "Nahráva sa {{name}}",
|
|
34
|
+
uploading_short: "Nahráva sa…",
|
|
35
|
+
uploading_progress: "Nahráva sa… {{percent}} %",
|
|
36
|
+
uploaded: "Súbor {{name}} bol nahraný",
|
|
37
|
+
upload_failed: "Nahrávanie zlyhalo",
|
|
38
|
+
upload_failed_named: "Nahrávanie súboru {{name}} zlyhalo: {{error}}",
|
|
39
|
+
invalid_type: "Tento typ súboru nie je podporovaný. Povolené: „{{accept}}“.",
|
|
40
|
+
too_large: "Súbor je príliš veľký ({{size}}). Maximum je {{max}}.",
|
|
41
|
+
single_only: "Sem je možné umiestniť iba jeden súbor. Presuňte alebo prilepte jeden súbor.",
|
|
42
|
+
// AssetsPreview
|
|
43
|
+
unable_to_preview: "Tento súbor nie je možné zobraziť",
|
|
44
|
+
download: "Stiahnuť originál",
|
|
45
|
+
close: "Zavrieť náhľad",
|
|
46
|
+
zoom_in: "Priblížiť",
|
|
47
|
+
zoom_out: "Oddialiť",
|
|
48
|
+
delete: "Odstrániť",
|
|
49
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { TranslateFn } from "../../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The built-in (English) message catalog of `FieldSingleAsset`. Also the fallback of
|
|
4
|
+
* every other bundled locale, so a locale missing a key still renders text.
|
|
5
|
+
*
|
|
6
|
+
* Placeholders are mustache-style (`{{name}}`, `{{max}}`, ...). The last six keys are
|
|
7
|
+
* the ones the embedded `AssetsPreview` looks up, so one `t` serves both.
|
|
8
|
+
*/
|
|
9
|
+
export declare const FIELD_SINGLE_ASSET_MESSAGES_EN: {
|
|
10
|
+
field_req_att: string;
|
|
11
|
+
pick_file: string;
|
|
12
|
+
replace_file: string;
|
|
13
|
+
empty_hint: string;
|
|
14
|
+
remove: string;
|
|
15
|
+
removed: string;
|
|
16
|
+
undo: string;
|
|
17
|
+
restored: string;
|
|
18
|
+
preview: string;
|
|
19
|
+
retry: string;
|
|
20
|
+
discard: string;
|
|
21
|
+
cancel_upload: string;
|
|
22
|
+
uploading: string;
|
|
23
|
+
uploading_short: string;
|
|
24
|
+
uploading_progress: string;
|
|
25
|
+
uploaded: string;
|
|
26
|
+
upload_failed: string;
|
|
27
|
+
upload_failed_named: string;
|
|
28
|
+
invalid_type: string;
|
|
29
|
+
too_large: string;
|
|
30
|
+
single_only: string;
|
|
31
|
+
unable_to_preview: string;
|
|
32
|
+
download: string;
|
|
33
|
+
close: string;
|
|
34
|
+
zoom_in: string;
|
|
35
|
+
zoom_out: string;
|
|
36
|
+
delete: string;
|
|
37
|
+
};
|
|
38
|
+
/** Every message key `FieldSingleAsset` may look up. */
|
|
39
|
+
export type FieldSingleAssetMessageKey = keyof typeof FIELD_SINGLE_ASSET_MESSAGES_EN;
|
|
40
|
+
/** A (possibly partial) catalog for one locale. */
|
|
41
|
+
export type FieldSingleAssetMessages = Record<FieldSingleAssetMessageKey, string>;
|
|
42
|
+
/**
|
|
43
|
+
* Builds the `t` prop of `FieldSingleAsset` from a message catalog. Unknown or
|
|
44
|
+
* untranslated keys fall back to `fallbackMessages` (English by default), so a catalog
|
|
45
|
+
* may safely be partial and never renders a raw key.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```svelte
|
|
49
|
+
* <script>
|
|
50
|
+
* import {
|
|
51
|
+
* FieldSingleAsset,
|
|
52
|
+
* createFieldSingleAssetT,
|
|
53
|
+
* FIELD_SINGLE_ASSET_MESSAGES_SK,
|
|
54
|
+
* } from "@marianmeres/stuic";
|
|
55
|
+
*
|
|
56
|
+
* // full locale, plus a field specific tweak
|
|
57
|
+
* const t = createFieldSingleAssetT({
|
|
58
|
+
* ...FIELD_SINGLE_ASSET_MESSAGES_SK,
|
|
59
|
+
* empty_hint: "Sem presuňte fotku",
|
|
60
|
+
* });
|
|
61
|
+
* </script>
|
|
62
|
+
*
|
|
63
|
+
* <FieldSingleAsset name="avatar" bind:value {processAsset} {t} />
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function createFieldSingleAssetT(messages: Partial<FieldSingleAssetMessages> | Record<string, string>, fallbackMessages?: Partial<FieldSingleAssetMessages> | Record<string, string>): TranslateFn;
|
|
67
|
+
/** The component's built-in English `t`. */
|
|
68
|
+
export declare const t_default: TranslateFn;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { isPlainObject } from "../../utils/is-plain-object.js";
|
|
2
|
+
import { replaceMap } from "../../utils/replace-map.js";
|
|
3
|
+
/**
|
|
4
|
+
* The built-in (English) message catalog of `FieldSingleAsset`. Also the fallback of
|
|
5
|
+
* every other bundled locale, so a locale missing a key still renders text.
|
|
6
|
+
*
|
|
7
|
+
* Placeholders are mustache-style (`{{name}}`, `{{max}}`, ...). The last six keys are
|
|
8
|
+
* the ones the embedded `AssetsPreview` looks up, so one `t` serves both.
|
|
9
|
+
*/
|
|
10
|
+
export const FIELD_SINGLE_ASSET_MESSAGES_EN = {
|
|
11
|
+
field_req_att: "This field requires attention. Please review and try again.",
|
|
12
|
+
pick_file: "Choose a file",
|
|
13
|
+
replace_file: "Replace {{name}}",
|
|
14
|
+
empty_hint: "Drop a file here or click to browse",
|
|
15
|
+
remove: "Remove",
|
|
16
|
+
removed: "{{name}} removed",
|
|
17
|
+
undo: "Undo",
|
|
18
|
+
restored: "{{name}} restored",
|
|
19
|
+
preview: "Preview",
|
|
20
|
+
retry: "Retry upload",
|
|
21
|
+
discard: "Discard",
|
|
22
|
+
cancel_upload: "Cancel upload",
|
|
23
|
+
uploading: "Uploading {{name}}",
|
|
24
|
+
uploading_short: "Uploading…",
|
|
25
|
+
uploading_progress: "Uploading… {{percent}}%",
|
|
26
|
+
uploaded: "{{name}} uploaded",
|
|
27
|
+
upload_failed: "Upload failed",
|
|
28
|
+
upload_failed_named: "Upload of {{name}} failed: {{error}}",
|
|
29
|
+
invalid_type: 'This file type is not supported. Allowed: "{{accept}}".',
|
|
30
|
+
too_large: "The file is too large ({{size}}). The maximum is {{max}}.",
|
|
31
|
+
single_only: "Only one file can be placed here. Drop or paste a single file.",
|
|
32
|
+
// AssetsPreview
|
|
33
|
+
unable_to_preview: "This file cannot be previewed",
|
|
34
|
+
download: "Download original",
|
|
35
|
+
close: "Close preview window",
|
|
36
|
+
zoom_in: "Zoom in",
|
|
37
|
+
zoom_out: "Zoom out",
|
|
38
|
+
delete: "Delete",
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Builds the `t` prop of `FieldSingleAsset` from a message catalog. Unknown or
|
|
42
|
+
* untranslated keys fall back to `fallbackMessages` (English by default), so a catalog
|
|
43
|
+
* may safely be partial and never renders a raw key.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```svelte
|
|
47
|
+
* <script>
|
|
48
|
+
* import {
|
|
49
|
+
* FieldSingleAsset,
|
|
50
|
+
* createFieldSingleAssetT,
|
|
51
|
+
* FIELD_SINGLE_ASSET_MESSAGES_SK,
|
|
52
|
+
* } from "@marianmeres/stuic";
|
|
53
|
+
*
|
|
54
|
+
* // full locale, plus a field specific tweak
|
|
55
|
+
* const t = createFieldSingleAssetT({
|
|
56
|
+
* ...FIELD_SINGLE_ASSET_MESSAGES_SK,
|
|
57
|
+
* empty_hint: "Sem presuňte fotku",
|
|
58
|
+
* });
|
|
59
|
+
* </script>
|
|
60
|
+
*
|
|
61
|
+
* <FieldSingleAsset name="avatar" bind:value {processAsset} {t} />
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export function createFieldSingleAssetT(messages, fallbackMessages = FIELD_SINGLE_ASSET_MESSAGES_EN) {
|
|
65
|
+
return (k, values = null, fallback = "") => {
|
|
66
|
+
const out = messages[k] ??
|
|
67
|
+
fallbackMessages[k] ??
|
|
68
|
+
(typeof fallback === "string" ? fallback : k);
|
|
69
|
+
return isPlainObject(values)
|
|
70
|
+
? replaceMap(out, values)
|
|
71
|
+
: out;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** The component's built-in English `t`. */
|
|
75
|
+
export const t_default = createFieldSingleAssetT(FIELD_SINGLE_ASSET_MESSAGES_EN);
|
|
@@ -119,6 +119,25 @@
|
|
|
119
119
|
--stuic-field-table-col-min-checkbox: 3rem;
|
|
120
120
|
--stuic-field-table-col-min-date: 9.5rem;
|
|
121
121
|
--stuic-field-table-col-min-url: 12rem;
|
|
122
|
+
|
|
123
|
+
/* FieldSingleAsset */
|
|
124
|
+
--stuic-field-single-asset-size-sm: 5rem;
|
|
125
|
+
--stuic-field-single-asset-size-md: 8rem;
|
|
126
|
+
--stuic-field-single-asset-size-lg: 12rem;
|
|
127
|
+
--stuic-field-single-asset-wide-ratio: 16 / 9;
|
|
128
|
+
--stuic-field-single-asset-preview-bg: var(--stuic-color-muted);
|
|
129
|
+
--stuic-field-single-asset-preview-border: var(--stuic-color-border);
|
|
130
|
+
--stuic-field-single-asset-preview-border-hover: var(--stuic-color-ring);
|
|
131
|
+
--stuic-field-single-asset-placeholder-text: var(--stuic-color-muted-foreground);
|
|
132
|
+
--stuic-field-single-asset-meta-text: var(--stuic-color-muted-foreground);
|
|
133
|
+
--stuic-field-single-asset-control-bg: rgb(0 0 0 / 0.6);
|
|
134
|
+
--stuic-field-single-asset-control-bg-hover: rgb(0 0 0 / 0.8);
|
|
135
|
+
--stuic-field-single-asset-control-text: #fff;
|
|
136
|
+
--stuic-field-single-asset-overlay-bg: rgb(0 0 0 / 0.4);
|
|
137
|
+
--stuic-field-single-asset-error-color: var(--stuic-input-accent-error);
|
|
138
|
+
/* `--stuic-field-single-asset-size`, `-radius`, `-control-radius`, `-border-width`
|
|
139
|
+
and `-transition` are deliberately NOT declared: they are read as fallback
|
|
140
|
+
arguments at the usage site — see docs/conventions.md. */
|
|
122
141
|
}
|
|
123
142
|
|
|
124
143
|
@layer components {
|
|
@@ -1551,3 +1570,188 @@
|
|
|
1551
1570
|
}
|
|
1552
1571
|
}
|
|
1553
1572
|
}
|
|
1573
|
+
|
|
1574
|
+
/* ============================================================================
|
|
1575
|
+
FIELD SINGLE ASSET
|
|
1576
|
+
One tile (the preview, also the picker + drop target) with hover/focus
|
|
1577
|
+
actions, a meta column, and an inline Undo after a remove. Layout that a
|
|
1578
|
+
theme may want to change lives here; utility classes in the component only
|
|
1579
|
+
handle flex/gap.
|
|
1580
|
+
============================================================================ */
|
|
1581
|
+
@layer components {
|
|
1582
|
+
.stuic-field-single-asset-tile {
|
|
1583
|
+
--_size: var(
|
|
1584
|
+
--stuic-field-single-asset-size,
|
|
1585
|
+
var(--stuic-field-single-asset-size-md)
|
|
1586
|
+
);
|
|
1587
|
+
height: var(--_size);
|
|
1588
|
+
}
|
|
1589
|
+
.stuic-field-single-asset[data-size="sm"] .stuic-field-single-asset-tile {
|
|
1590
|
+
--_size: var(
|
|
1591
|
+
--stuic-field-single-asset-size,
|
|
1592
|
+
var(--stuic-field-single-asset-size-sm)
|
|
1593
|
+
);
|
|
1594
|
+
}
|
|
1595
|
+
.stuic-field-single-asset[data-size="lg"] .stuic-field-single-asset-tile {
|
|
1596
|
+
--_size: var(
|
|
1597
|
+
--stuic-field-single-asset-size,
|
|
1598
|
+
var(--stuic-field-single-asset-size-lg)
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
.stuic-field-single-asset-preview {
|
|
1603
|
+
position: relative;
|
|
1604
|
+
display: grid;
|
|
1605
|
+
place-content: center;
|
|
1606
|
+
overflow: hidden;
|
|
1607
|
+
height: 100%;
|
|
1608
|
+
width: auto;
|
|
1609
|
+
max-width: 100%;
|
|
1610
|
+
aspect-ratio: 1 / 1;
|
|
1611
|
+
padding: 0;
|
|
1612
|
+
background: var(--stuic-field-single-asset-preview-bg);
|
|
1613
|
+
color: var(--stuic-field-single-asset-placeholder-text);
|
|
1614
|
+
border-style: solid;
|
|
1615
|
+
border-width: var(--stuic-field-single-asset-border-width, var(--stuic-border-width));
|
|
1616
|
+
border-color: var(--stuic-field-single-asset-preview-border);
|
|
1617
|
+
border-radius: var(--stuic-field-single-asset-radius, var(--stuic-radius));
|
|
1618
|
+
cursor: pointer;
|
|
1619
|
+
transition: border-color
|
|
1620
|
+
var(--stuic-field-single-asset-transition, var(--stuic-transition));
|
|
1621
|
+
}
|
|
1622
|
+
.stuic-field-single-asset[data-shape="circle"] .stuic-field-single-asset-preview {
|
|
1623
|
+
border-radius: 9999px;
|
|
1624
|
+
}
|
|
1625
|
+
.stuic-field-single-asset[data-shape="wide"] .stuic-field-single-asset-preview {
|
|
1626
|
+
aspect-ratio: var(--stuic-field-single-asset-wide-ratio);
|
|
1627
|
+
}
|
|
1628
|
+
.stuic-field-single-asset[data-state="empty"] .stuic-field-single-asset-preview {
|
|
1629
|
+
border-style: dashed;
|
|
1630
|
+
}
|
|
1631
|
+
.stuic-field-single-asset[data-state="error"] .stuic-field-single-asset-preview {
|
|
1632
|
+
border-color: var(--stuic-field-single-asset-error-color);
|
|
1633
|
+
}
|
|
1634
|
+
.stuic-field-single-asset-preview:disabled {
|
|
1635
|
+
cursor: default;
|
|
1636
|
+
}
|
|
1637
|
+
.stuic-field-single-asset[data-state="loading"] .stuic-field-single-asset-preview {
|
|
1638
|
+
cursor: default;
|
|
1639
|
+
border-color: transparent;
|
|
1640
|
+
}
|
|
1641
|
+
.stuic-field-single-asset-preview:not(:disabled):hover {
|
|
1642
|
+
border-color: var(--stuic-field-single-asset-preview-border-hover);
|
|
1643
|
+
}
|
|
1644
|
+
.stuic-field-single-asset-preview:focus-visible {
|
|
1645
|
+
outline: 2px solid var(--stuic-color-ring);
|
|
1646
|
+
outline-offset: 2px;
|
|
1647
|
+
}
|
|
1648
|
+
/* the tile is `disabled` while the field only displays — keep it legible */
|
|
1649
|
+
.stuic-field-single-asset[data-state="filled"]
|
|
1650
|
+
.stuic-field-single-asset-preview:disabled {
|
|
1651
|
+
opacity: 1;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
.stuic-field-single-asset-img {
|
|
1655
|
+
position: absolute;
|
|
1656
|
+
inset: 0;
|
|
1657
|
+
width: 100%;
|
|
1658
|
+
height: 100%;
|
|
1659
|
+
object-fit: cover;
|
|
1660
|
+
}
|
|
1661
|
+
.stuic-field-single-asset[data-fit="contain"] .stuic-field-single-asset-img {
|
|
1662
|
+
object-fit: contain;
|
|
1663
|
+
padding: calc(var(--spacing) * 2);
|
|
1664
|
+
}
|
|
1665
|
+
.stuic-field-single-asset-icon {
|
|
1666
|
+
display: grid;
|
|
1667
|
+
place-content: center;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
.stuic-field-single-asset-overlay {
|
|
1671
|
+
position: absolute;
|
|
1672
|
+
inset: 0;
|
|
1673
|
+
display: grid;
|
|
1674
|
+
place-content: center;
|
|
1675
|
+
pointer-events: none;
|
|
1676
|
+
color: #fff;
|
|
1677
|
+
background: var(--stuic-field-single-asset-overlay-bg);
|
|
1678
|
+
}
|
|
1679
|
+
.stuic-field-single-asset-overlay[data-error] {
|
|
1680
|
+
background: color-mix(
|
|
1681
|
+
in oklab,
|
|
1682
|
+
var(--stuic-field-single-asset-error-color) 55%,
|
|
1683
|
+
transparent
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
/* Actions: hidden until the tile is hovered / focused (or on a failed upload,
|
|
1688
|
+
where Retry / Discard must be findable); pointer events gated the same way so
|
|
1689
|
+
an invisible control never intercepts a click meant for the tile. Keyboard
|
|
1690
|
+
users Tab to them regardless. Touch has no hover: always shown there. */
|
|
1691
|
+
.stuic-field-single-asset-actions {
|
|
1692
|
+
position: absolute;
|
|
1693
|
+
top: calc(var(--spacing) * 1);
|
|
1694
|
+
right: calc(var(--spacing) * 1);
|
|
1695
|
+
display: flex;
|
|
1696
|
+
gap: calc(var(--spacing) * 1);
|
|
1697
|
+
opacity: 0;
|
|
1698
|
+
pointer-events: none;
|
|
1699
|
+
transition: opacity
|
|
1700
|
+
var(--stuic-field-single-asset-transition, var(--stuic-transition));
|
|
1701
|
+
}
|
|
1702
|
+
.stuic-field-single-asset-tile:hover .stuic-field-single-asset-actions,
|
|
1703
|
+
.stuic-field-single-asset-tile:focus-within .stuic-field-single-asset-actions,
|
|
1704
|
+
.stuic-field-single-asset[data-state="error"] .stuic-field-single-asset-actions {
|
|
1705
|
+
opacity: 1;
|
|
1706
|
+
pointer-events: auto;
|
|
1707
|
+
}
|
|
1708
|
+
@media (hover: none) {
|
|
1709
|
+
.stuic-field-single-asset-actions {
|
|
1710
|
+
opacity: 1;
|
|
1711
|
+
pointer-events: auto;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
.stuic-field-single-asset-control {
|
|
1715
|
+
display: grid;
|
|
1716
|
+
place-content: center;
|
|
1717
|
+
padding: calc(var(--spacing) * 1);
|
|
1718
|
+
border-radius: var(
|
|
1719
|
+
--stuic-field-single-asset-control-radius,
|
|
1720
|
+
var(--stuic-radius-button)
|
|
1721
|
+
);
|
|
1722
|
+
background: var(--stuic-field-single-asset-control-bg);
|
|
1723
|
+
color: var(--stuic-field-single-asset-control-text);
|
|
1724
|
+
cursor: pointer;
|
|
1725
|
+
transition: background-color
|
|
1726
|
+
var(--stuic-field-single-asset-transition, var(--stuic-transition));
|
|
1727
|
+
}
|
|
1728
|
+
.stuic-field-single-asset-control:hover {
|
|
1729
|
+
background: var(--stuic-field-single-asset-control-bg-hover);
|
|
1730
|
+
}
|
|
1731
|
+
.stuic-field-single-asset-control:focus-visible {
|
|
1732
|
+
outline: 2px solid var(--stuic-color-ring);
|
|
1733
|
+
outline-offset: 1px;
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
.stuic-field-single-asset-meta {
|
|
1737
|
+
color: var(--stuic-field-single-asset-meta-text);
|
|
1738
|
+
}
|
|
1739
|
+
.stuic-field-single-asset-undo {
|
|
1740
|
+
display: inline-flex;
|
|
1741
|
+
align-items: center;
|
|
1742
|
+
gap: calc(var(--spacing) * 1);
|
|
1743
|
+
margin-left: calc(var(--spacing) * 2);
|
|
1744
|
+
color: var(--stuic-color-foreground);
|
|
1745
|
+
text-decoration: underline;
|
|
1746
|
+
text-underline-offset: 2px;
|
|
1747
|
+
cursor: pointer;
|
|
1748
|
+
}
|
|
1749
|
+
.stuic-field-single-asset-undo:focus-visible {
|
|
1750
|
+
outline: 2px solid var(--stuic-color-ring);
|
|
1751
|
+
outline-offset: 2px;
|
|
1752
|
+
border-radius: var(
|
|
1753
|
+
--stuic-field-single-asset-control-radius,
|
|
1754
|
+
var(--stuic-radius-button)
|
|
1755
|
+
);
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export * from "./types.js";
|
|
2
2
|
export { default as FieldAssets, type Props as FieldAssetsProps, type FieldAsset, type FieldAssetUrlObj, type FieldAssetWithBlobUrl, } from "./FieldAssets.svelte";
|
|
3
|
+
export { default as FieldSingleAsset, type Props as FieldSingleAssetProps, type FieldSingleAssetUploadContext, type FieldSingleAssetShape, type FieldSingleAssetFit, type FieldSingleAssetSize, type FieldSingleAssetFileCheck, } from "./FieldSingleAsset.svelte";
|
|
4
|
+
export { createFieldSingleAssetT, FIELD_SINGLE_ASSET_MESSAGES_EN, type FieldSingleAssetMessageKey, type FieldSingleAssetMessages, } from "./field-single-asset-i18n.js";
|
|
5
|
+
export { FIELD_SINGLE_ASSET_MESSAGES_SK } from "./field-single-asset-i18n-sk.js";
|
|
3
6
|
export { default as FieldCheckbox, type Props as FieldCheckboxProps, } from "./FieldCheckbox.svelte";
|
|
4
7
|
export { default as Honeypot, type Props as HoneypotProps } from "./Honeypot.svelte";
|
|
5
8
|
export { default as TimeTrap, type Props as TimeTrapProps, type TimeTrapSnapshot, } from "./TimeTrap.svelte";
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export * from "./types.js";
|
|
2
2
|
export { default as FieldAssets, } from "./FieldAssets.svelte";
|
|
3
|
+
export { default as FieldSingleAsset, } from "./FieldSingleAsset.svelte";
|
|
4
|
+
export { createFieldSingleAssetT, FIELD_SINGLE_ASSET_MESSAGES_EN, } from "./field-single-asset-i18n.js";
|
|
5
|
+
export { FIELD_SINGLE_ASSET_MESSAGES_SK } from "./field-single-asset-i18n-sk.js";
|
|
3
6
|
export { default as FieldCheckbox, } from "./FieldCheckbox.svelte";
|
|
4
7
|
export { default as Honeypot } from "./Honeypot.svelte";
|
|
5
8
|
export { default as TimeTrap, } from "./TimeTrap.svelte";
|
package/docs/domains/actions.md
CHANGED
|
@@ -121,7 +121,7 @@ Per the HTML spec, `<input type="hidden">` is _barred from constraint
|
|
|
121
121
|
validation_ — `validity.valueMissing` stays `false` regardless of the
|
|
122
122
|
`required` attribute, and native browser submit blocking is skipped. Several
|
|
123
123
|
STUIC field components (`FieldPhoneNumber`, `FieldCountry`, `FieldObject`,
|
|
124
|
-
`FieldAssets`, `FieldInputLocalized`, `FieldKeyValues`, `FieldLikeButton`,
|
|
124
|
+
`FieldAssets`, `FieldSingleAsset`, `FieldInputLocalized`, `FieldKeyValues`, `FieldLikeButton`,
|
|
125
125
|
`FieldDate`, `FieldDateRange`) use a hidden input to participate in `FormData`, so they each enforce
|
|
126
126
|
`required` themselves inside their `customValidator`:
|
|
127
127
|
|
|
@@ -153,12 +153,12 @@ Two element types are deliberately exempt from the synthetic dispatch:
|
|
|
153
153
|
group, which is wrong.
|
|
154
154
|
- **`type="file"`** — a file input's value is read-only to script, so a
|
|
155
155
|
synthetic `change` can't re-validate it; worse, it re-triggers any dropzone /
|
|
156
|
-
upload listener bound to the input. `FieldAssets`
|
|
156
|
+
upload listener bound to the input. `FieldAssets` (and `FieldSingleAsset`) wire their hidden
|
|
157
157
|
`<input type="file">` through `fileDropzone`, so a re-fired `change` would
|
|
158
158
|
re-run `processFiles` with the previously-picked file still in `inputEl.files`
|
|
159
159
|
— duplicating the asset and firing a real re-upload on every save. File inputs
|
|
160
160
|
are still read for native constraint validation (`required`); only the event
|
|
161
|
-
dispatch is skipped. (
|
|
161
|
+
dispatch is skipped. (Both additionally clear their file input after
|
|
162
162
|
consuming a selection, both as defense-in-depth and to allow re-selecting the
|
|
163
163
|
same file twice in a row.)
|
|
164
164
|
|
|
@@ -62,25 +62,26 @@
|
|
|
62
62
|
|
|
63
63
|
### Form
|
|
64
64
|
|
|
65
|
-
| Component | Purpose
|
|
66
|
-
| --------------------------------------------- |
|
|
67
|
-
| Input (FieldInput, FieldSelect, etc.) | Form fields
|
|
68
|
-
| FieldMoney | Money input storing integer minor units (e.g. cents)
|
|
69
|
-
| Calendar | Month grid for single-date / range picking: keyboard grid, min/max, dropdown caption, i18n
|
|
70
|
-
| FieldDate, FieldDateRange | Date / date-range fields around Calendar: trigger + dialog or embedded; ISO hidden inputs
|
|
71
|
-
| FieldPhoneNumber | International phone input with country picker
|
|
72
|
-
| FieldObject | Dual-mode JSON object editor (pretty-print/raw)
|
|
73
|
-
| CronInput | Cron expression editor with presets and validation
|
|
74
|
-
| Fieldset | Field grouping with legend
|
|
75
|
-
| FieldKeyValues | Key-value pair editor
|
|
76
|
-
| FieldTable | Rows × typed columns editor (text/number/select/checkbox/date/url cells, container layout)
|
|
77
|
-
| FieldsBuilder | Field-definition list editor ("what properties does a thing have?")
|
|
78
|
-
| FieldAssets | File/asset management
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
|
65
|
+
| Component | Purpose |
|
|
66
|
+
| --------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
67
|
+
| Input (FieldInput, FieldSelect, etc.) | Form fields |
|
|
68
|
+
| FieldMoney | Money input storing integer minor units (e.g. cents) |
|
|
69
|
+
| Calendar | Month grid for single-date / range picking: keyboard grid, min/max, dropdown caption, i18n |
|
|
70
|
+
| FieldDate, FieldDateRange | Date / date-range fields around Calendar: trigger + dialog or embedded; ISO hidden inputs |
|
|
71
|
+
| FieldPhoneNumber | International phone input with country picker |
|
|
72
|
+
| FieldObject | Dual-mode JSON object editor (pretty-print/raw) |
|
|
73
|
+
| CronInput | Cron expression editor with presets and validation |
|
|
74
|
+
| Fieldset | Field grouping with legend |
|
|
75
|
+
| FieldKeyValues | Key-value pair editor |
|
|
76
|
+
| FieldTable | Rows × typed columns editor (text/number/select/checkbox/date/url cells, container layout) |
|
|
77
|
+
| FieldsBuilder | Field-definition list editor ("what properties does a thing have?") |
|
|
78
|
+
| FieldAssets | File/asset management |
|
|
79
|
+
| FieldSingleAsset | One asset (avatar, logo, cover): replace-in-place tile, inline remove + undo, rollback on failure |
|
|
80
|
+
| LoginForm, LoginFormModal | Standalone login form with optional modal variant |
|
|
81
|
+
| RegisterForm | Standalone registration form with declarative extra fields |
|
|
82
|
+
| LoginOrRegisterForm, LoginOrRegisterFormModal | Composite login/register/verify form (3 modes, shared social-logins) |
|
|
83
|
+
| EmailVerifyForm | Post-registration email-verify form (OtpInput + resend cooldown) |
|
|
84
|
+
| OtpInput | Generic N-slot one-time-code input (numeric/alphanumeric, paste-distribute) |
|
|
84
85
|
|
|
85
86
|
### Display
|
|
86
87
|
|
|
@@ -157,7 +158,7 @@ failed `validate()` (imperative or event-driven) renders the inline error.
|
|
|
157
158
|
Use `validate={false}` to bypass stuic's validation entirely.
|
|
158
159
|
|
|
159
160
|
> **Why default-on?** Hidden-input field components (`FieldPhoneNumber`,
|
|
160
|
-
> `FieldCountry`, `FieldObject`, `FieldAssets`, `FieldInputLocalized`,
|
|
161
|
+
> `FieldCountry`, `FieldObject`, `FieldAssets`, `FieldSingleAsset`, `FieldInputLocalized`,
|
|
161
162
|
> `FieldKeyValues`, `FieldTable`, `FieldLikeButton`, `FieldDate`, `FieldDateRange`, `Rating`) _must_ be default-on because hidden
|
|
162
163
|
> inputs are excluded from native browser constraint validation — without the
|
|
163
164
|
> stuic action enforcing `required` in a `customValidator`, the attribute is a
|
|
@@ -167,7 +168,7 @@ Use `validate={false}` to bypass stuic's validation entirely.
|
|
|
167
168
|
### Per-field methods
|
|
168
169
|
|
|
169
170
|
Available on `FieldInput`, `FieldMoney`, `FieldTextarea`, `FieldCheckbox`,
|
|
170
|
-
`FieldSelect`, `FieldFile`, `FieldObject`, `FieldAssets`, `FieldInputLocalized`,
|
|
171
|
+
`FieldSelect`, `FieldFile`, `FieldObject`, `FieldAssets`, `FieldSingleAsset`, `FieldInputLocalized`,
|
|
171
172
|
`FieldKeyValues`, `FieldTable`, `FieldPhoneNumber`, `FieldCountry`, `FieldLikeButton`,
|
|
172
173
|
`FieldRadios`, `FieldSwitch`, `FieldOptions`, `FieldDate`, `FieldDateRange`, and
|
|
173
174
|
`Switch`:
|