lutra 0.1.68 → 0.1.70
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/AspectRatio.svelte +19 -9
- package/dist/components/AspectRatio.svelte.d.ts +2 -1
- package/dist/components/Avatar.svelte +5 -8
- package/dist/components/Close.svelte +24 -27
- package/dist/components/Close.svelte.d.ts +2 -0
- package/dist/components/ContextTip.svelte +3 -2
- package/dist/components/DataList.svelte +111 -0
- package/dist/components/DataList.svelte.d.ts +10 -0
- package/dist/components/DataListTypes.d.ts +14 -0
- package/dist/components/DataListTypes.js +1 -0
- package/dist/components/Dialog.svelte +38 -0
- package/dist/components/Icon.svelte +2 -2
- package/dist/components/IconButton.svelte +10 -22
- package/dist/components/Image.svelte +2 -2
- package/dist/components/Indicator.svelte +2 -1
- package/dist/components/Inset.svelte +13 -0
- package/dist/components/Layout.svelte +7 -3
- package/dist/components/Layout.svelte.d.ts +3 -2
- package/dist/components/MenuDropdown.svelte +12 -2
- package/dist/components/MenuItem.svelte +30 -14
- package/dist/components/MenuItem.svelte.d.ts +6 -0
- package/dist/components/Modal.svelte +36 -20
- package/dist/components/Popover.svelte +43 -13
- package/dist/components/TabbedContent.svelte +1 -1
- package/dist/components/TabbedContentItem.svelte +14 -0
- package/dist/components/TabbedContentItem.svelte.d.ts +4 -0
- package/dist/components/Table.svelte +69 -0
- package/dist/components/Table.svelte.d.ts +7 -0
- package/dist/components/Tabs.svelte +44 -36
- package/dist/components/Tag.svelte +53 -13
- package/dist/components/Tag.svelte.d.ts +4 -0
- package/dist/components/Theme.svelte +121 -94
- package/dist/components/Theme.svelte.d.ts +7 -6
- package/dist/components/Toast.svelte +11 -8
- package/dist/components/Tooltip.svelte +17 -10
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/css/1-props.css +197 -163
- package/dist/css/2-init.css +519 -0
- package/dist/css/{2-base.css → 3-base.css} +42 -131
- package/dist/css/{3-typo.css → 4-typo.css} +3 -1
- package/dist/css/lutra.css +7 -6
- package/dist/css/themes/DefaultTheme.css +26 -4
- package/dist/form/Button.svelte +20 -0
- package/dist/form/Button.svelte.d.ts +9 -0
- package/dist/form/Datepicker.svelte +13 -0
- package/dist/form/Datepicker.svelte.d.ts +3 -0
- package/dist/form/FieldContent.svelte +20 -11
- package/dist/form/FieldError.svelte +1 -1
- package/dist/form/FieldGroup.svelte +84 -0
- package/dist/form/FieldGroup.svelte.d.ts +20 -0
- package/dist/form/Fieldset.svelte +19 -11
- package/dist/form/Form.svelte +137 -63
- package/dist/form/Form.svelte.d.ts +21 -0
- package/dist/form/FormActions.svelte +21 -3
- package/dist/form/FormActions.svelte.d.ts +3 -0
- package/dist/form/FormSection.svelte +22 -20
- package/dist/form/ImageUpload.svelte +50 -30
- package/dist/form/ImageUpload.svelte.d.ts +14 -0
- package/dist/form/Input.svelte +62 -30
- package/dist/form/Input.svelte.d.ts +0 -1
- package/dist/form/InputLength.svelte +5 -5
- package/dist/form/Label.svelte +6 -6
- package/dist/form/LogoUpload.svelte +24 -10
- package/dist/form/Select.svelte +23 -10
- package/dist/form/Select.svelte.d.ts +6 -6
- package/dist/form/Textarea.svelte +11 -1
- package/dist/form/Toggle.svelte +162 -0
- package/dist/form/Toggle.svelte.d.ts +31 -17
- package/dist/form/client.svelte.js +0 -2
- package/dist/form/index.d.ts +1 -0
- package/dist/form/index.js +1 -0
- package/dist/state/Persisted.svelte.d.ts +6 -0
- package/dist/state/Persisted.svelte.js +29 -0
- package/dist/state/theme.svelte.d.ts +7 -0
- package/dist/state/theme.svelte.js +14 -0
- package/dist/types.d.ts +6 -23
- package/dist/types.js +0 -17
- package/dist/util/color.js +2 -2
- package/package.json +5 -4
- package/dist/config.d.ts +0 -30
- package/dist/config.js +0 -18
- /package/dist/css/{4-layout.css → 5-layout.css} +0 -0
- /package/dist/css/{5-media.css → 6-media.css} +0 -0
|
@@ -1,130 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Base DOM setup
|
|
3
|
-
* Initializes shorthand variables and foundational sizing
|
|
4
3
|
*/
|
|
5
|
-
:root {
|
|
6
|
-
/* Base size for all sizing */
|
|
7
|
-
--base-size: 16px;
|
|
8
|
-
|
|
9
|
-
/* Spacing scale */
|
|
10
|
-
--space-base: 1em;
|
|
11
|
-
--space-025: calc(var(--space-base) * 0.25);
|
|
12
|
-
--space-050: calc(var(--space-base) * 0.5);
|
|
13
|
-
--space-075: calc(var(--space-base) * 0.75);
|
|
14
|
-
--space-100: calc(var(--space-base) * 1);
|
|
15
|
-
--space-125: calc(var(--space-base) * 1.25);
|
|
16
|
-
--space-150: calc(var(--space-base) * 1.5);
|
|
17
|
-
--space-175: calc(var(--space-base) * 1.75);
|
|
18
|
-
--space-200: calc(var(--space-base) * 2);
|
|
19
|
-
--space-225: calc(var(--space-base) * 2.25);
|
|
20
|
-
--space-250: calc(var(--space-base) * 2.5);
|
|
21
|
-
--space-300: calc(var(--space-base) * 3);
|
|
22
|
-
--space-350: calc(var(--space-base) * 3.5);
|
|
23
|
-
--space-400: calc(var(--space-base) * 4);
|
|
24
|
-
--space-450: calc(var(--space-base) * 4.5);
|
|
25
|
-
--space-500: calc(var(--space-base) * 5);
|
|
26
|
-
--space-550: calc(var(--space-base) * 5.5);
|
|
27
|
-
--space-600: calc(var(--space-base) * 6);
|
|
28
|
-
--space-700: calc(var(--space-base) * 7);
|
|
29
|
-
--space-800: calc(var(--space-base) * 8);
|
|
30
|
-
--space-900: calc(var(--space-base) * 9);
|
|
31
|
-
--space-1000: calc(var(--space-base) * 10);
|
|
32
|
-
|
|
33
|
-
--space-xxs: var(--space-025);
|
|
34
|
-
--space-xs: var(--space-050);
|
|
35
|
-
--space-sm: var(--space-075);
|
|
36
|
-
--space-md: var(--space-100);
|
|
37
|
-
--space-lg: var(--space-150);
|
|
38
|
-
--space-xl: var(--space-200);
|
|
39
|
-
--space-xxl: var(--space-300);
|
|
40
|
-
--space-xxxl: var(--space-400);
|
|
41
|
-
|
|
42
|
-
--font-scale: 1.175;
|
|
43
|
-
--font-size-base: 1em;
|
|
44
|
-
|
|
45
|
-
--font-size-xs: calc(var(--font-size-base) * pow(var(--font-scale), -2));
|
|
46
|
-
--font-size-sm: calc(var(--font-size-base) * pow(var(--font-scale), -1));
|
|
47
|
-
--font-size-p: var(--font-size-base);
|
|
48
|
-
--font-size-h6: var(--font-size-base);
|
|
49
|
-
--font-size-h5: calc(var(--font-size-base) * pow(var(--font-scale), 1));
|
|
50
|
-
--font-size-h4: calc(var(--font-size-base) * pow(var(--font-scale), 2));
|
|
51
|
-
--font-size-h3: calc(var(--font-size-base) * pow(var(--font-scale), 3));
|
|
52
|
-
--font-size-h2: calc(var(--font-size-base) * pow(var(--font-scale), 4));
|
|
53
|
-
--font-size-h1: calc(var(--font-size-base) * pow(var(--font-scale), 5));
|
|
54
|
-
--font-size-hero: calc(var(--font-size-base) * pow(var(--font-scale), 6));
|
|
55
|
-
--font-size-jumbo: calc(var(--font-size-base) * pow(var(--font-scale), 7));
|
|
56
|
-
|
|
57
|
-
--text-color-h1: var(--text-color-heading);
|
|
58
|
-
--text-color-h2: var(--text-color-heading);
|
|
59
|
-
--text-color-h3: var(--text-color-heading);
|
|
60
|
-
--text-color-h4: var(--text-color-heading);
|
|
61
|
-
--text-color-h5: var(--text-color-heading);
|
|
62
|
-
--text-color-h6: var(--text-color-heading);
|
|
63
|
-
--field-color: var(--text-color-p);
|
|
64
|
-
|
|
65
|
-
--border-radius-scale: 1.2;
|
|
66
|
-
--border-size-thin: 1px;
|
|
67
|
-
--border-size-thick: 2px;
|
|
68
|
-
|
|
69
|
-
--border-radius-base: calc(var(--border-radius-scale) * 0.25em);
|
|
70
|
-
--border-radius-sm: calc(var(--border-radius-scale) * 0.5em);
|
|
71
|
-
--border-radius-lg: calc(var(--border-radius-scale) * 2em);
|
|
72
|
-
|
|
73
|
-
--form-border-radius: var(--border-radius-base);
|
|
74
|
-
--form-border-size: var(--border-size-thin);
|
|
75
|
-
--form-border-style: var(--border-style);
|
|
76
|
-
--form-border-color: var(--border-color);
|
|
77
|
-
|
|
78
|
-
--field-border-radius: var(--border-radius-base);
|
|
79
|
-
--field-border-size: var(--border-size-thin);
|
|
80
|
-
--field-border-style: var(--border-style);
|
|
81
|
-
--field-border-color: var(--border-color);
|
|
82
|
-
|
|
83
|
-
--button-border-radius: var(--border-radius-base);
|
|
84
|
-
--button-border-size: var(--border-size-thin);
|
|
85
|
-
--button-border-style: var(--border-style);
|
|
86
|
-
--button-border-color: var(--border-color);
|
|
87
|
-
|
|
88
|
-
--link-color-visited: var(--link-color);
|
|
89
|
-
--link-color-active: var(--link-color);
|
|
90
|
-
|
|
91
|
-
/* Shorthand compound variables */
|
|
92
|
-
--field-padding: var(--field-padding-block) var(--field-padding-inline);
|
|
93
|
-
--field-border: var(--field-border-size) var(--field-border-style) var(--field-border-color);
|
|
94
|
-
|
|
95
|
-
--button-padding: var(--button-padding-block) var(--button-padding-inline);
|
|
96
|
-
--button-border: var(--button-border-size) var(--button-border-style) var(--button-submit-border-color);
|
|
97
|
-
--button-icon-size: 1em;
|
|
98
|
-
|
|
99
|
-
/* Focus ring compound */
|
|
100
|
-
--focus-ring: var(--focus-ring-size) solid var(--focus-ring-color);
|
|
101
|
-
|
|
102
|
-
/* Shadows */
|
|
103
|
-
--shadow-base: var(--shadow-base);
|
|
104
|
-
--shadow-sm: var(--shadow-sm);
|
|
105
|
-
--shadow-md: var(--shadow-md);
|
|
106
|
-
--shadow-lg: var(--shadow-lg);
|
|
107
|
-
--shadow-xl: var(--shadow-xl);
|
|
108
|
-
--shadow-2xl: var(--shadow-2xl);
|
|
109
|
-
|
|
110
|
-
--tooltip-background: var(--surface-background);
|
|
111
|
-
--tooltip-color: var(--text-color-p);
|
|
112
|
-
--tooltip-border: var(--surface-border);
|
|
113
|
-
--tooltip-border-radius: var(--surface-border-radius);
|
|
114
|
-
--tooltip-shadow: var(--surface-shadow);
|
|
115
|
-
|
|
116
|
-
/* Table compound variables */
|
|
117
|
-
--table-border: var(--table-border-size) var(--table-border-style) var(--table-border-color);
|
|
118
|
-
--table-cell-padding: var(--table-cell-padding-block) var(--table-cell-padding-inline);
|
|
119
|
-
|
|
120
|
-
/* Modal compound variables */
|
|
121
|
-
--modal-border: var(--modal-border-size) var(--modal-border-style) var(--modal-border-color);
|
|
122
|
-
--modal-padding: var(--modal-padding-block) var(--modal-padding-inline);
|
|
123
|
-
--modal-actions-padding: var(--modal-actions-padding-block) var(--modal-actions-padding-inline);
|
|
124
|
-
|
|
125
|
-
--mix-target: light-dark(black, white);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
4
|
body {
|
|
129
5
|
text-rendering: optimizeLegibility;
|
|
130
6
|
-webkit-font-smoothing: antialiased;
|
|
@@ -141,16 +17,53 @@ body {
|
|
|
141
17
|
width: 100%;
|
|
142
18
|
min-height: 0;
|
|
143
19
|
scrollbar-gutter: stable;
|
|
20
|
+
-webkit-text-size-adjust: 100%;
|
|
21
|
+
-ms-overflow-style: -ms-autohiding-scrollbar;
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
border-collapse: collapse;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
html {
|
|
27
|
+
color-scheme: light dark;
|
|
28
|
+
&:not(.light) {
|
|
29
|
+
@media (prefers-color-scheme: dark) {
|
|
30
|
+
color-scheme: only dark;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
html.light {
|
|
36
|
+
color-scheme: only light;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
html.dark {
|
|
40
|
+
color-scheme: only dark;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
html,
|
|
44
|
+
body {
|
|
45
|
+
height: 100%;
|
|
46
|
+
width: 100%;
|
|
144
47
|
}
|
|
145
48
|
|
|
146
|
-
|
|
49
|
+
* {
|
|
147
50
|
margin: 0;
|
|
148
51
|
padding: 0;
|
|
149
52
|
box-sizing: border-box;
|
|
53
|
+
scrollbar-width: thin;
|
|
54
|
+
scrollbar-color: var(--scrollbar-color) transparent;
|
|
150
55
|
}
|
|
151
56
|
|
|
152
|
-
|
|
153
|
-
|
|
57
|
+
.visually-hidden {
|
|
58
|
+
border: 0;
|
|
59
|
+
clip: rect(0 0 0 0);
|
|
60
|
+
height: auto;
|
|
61
|
+
margin: 0;
|
|
62
|
+
overflow: hidden;
|
|
63
|
+
padding: 0;
|
|
64
|
+
position: absolute;
|
|
65
|
+
width: 1px;
|
|
66
|
+
white-space: nowrap;
|
|
154
67
|
}
|
|
155
68
|
|
|
156
69
|
input, textarea, select, button {
|
|
@@ -229,12 +142,10 @@ input, textarea, select, .button, ::file-selector-button, .Field {
|
|
|
229
142
|
background-image var(--transition-duration-fast) var(--transition-timing-function),
|
|
230
143
|
background-color var(--transition-duration-fast) var(--transition-timing-function),
|
|
231
144
|
color var(--transition-duration-fast) var(--transition-timing-function),
|
|
232
|
-
box-shadow var(--transition-duration-fast) var(--transition-timing-function)
|
|
233
|
-
outline var(--transition-duration-fast) var(--transition-timing-function),
|
|
234
|
-
outline-offset var(--transition-duration-fast) var(--transition-timing-function);
|
|
145
|
+
box-shadow var(--transition-duration-fast) var(--transition-timing-function);
|
|
235
146
|
}
|
|
236
147
|
|
|
237
|
-
input:focus-visible, textarea:focus-visible, select:focus-visible, button:focus-visible {
|
|
148
|
+
input:focus-visible, textarea:focus-visible, select:focus-visible, button:focus-visible, a:focus-visible {
|
|
238
149
|
outline: var(--focus-ring-size) solid var(--focus-ring-color);
|
|
239
150
|
outline-offset: var(--focus-ring-offset);
|
|
240
151
|
border-color: var(--focus-ring-color);
|
|
@@ -16,13 +16,15 @@ small {
|
|
|
16
16
|
line-height: var(--font-line-height-tight);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
small.smaller
|
|
19
|
+
small.smaller,
|
|
20
|
+
small small {
|
|
20
21
|
font-size: var(--font-size-xs);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/* Form elements inherit base typography */
|
|
24
25
|
input, textarea, select, button {
|
|
25
26
|
font-family: var(--font-family);
|
|
27
|
+
font-size: inherit;
|
|
26
28
|
line-height: var(--font-line-height);
|
|
27
29
|
}
|
|
28
30
|
|
package/dist/css/lutra.css
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
@layer l-
|
|
1
|
+
@layer l-props, l-init, l-base, l-typo, typo, l-layout, l-media, l-default, theme, media, misc;
|
|
2
2
|
|
|
3
|
-
@import "./1-props.css";
|
|
4
|
-
@import "./2-
|
|
5
|
-
@import "./3-
|
|
6
|
-
@import "./4-
|
|
7
|
-
@import "./5-
|
|
3
|
+
@import "./1-props.css" layer(l-props);
|
|
4
|
+
@import "./2-init.css" layer(l-init);
|
|
5
|
+
@import "./3-base.css" layer(l-base);
|
|
6
|
+
@import "./4-typo.css" layer(l-typo);
|
|
7
|
+
@import "./5-layout.css" layer(l-layout);
|
|
8
|
+
@import "./6-media.css" layer(l-media);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
@layer theme
|
|
1
|
+
@layer l-props, l-init, l-base, l-typo, typo, l-layout, l-media, l-default, theme, media, misc;
|
|
2
|
+
|
|
3
|
+
@layer l-default {
|
|
2
4
|
:root {
|
|
3
5
|
--hue: 240deg;
|
|
4
6
|
--chroma: 0.5;
|
|
@@ -170,9 +172,20 @@
|
|
|
170
172
|
--checkbox-border-color-checked: var(--button-submit-base-color);
|
|
171
173
|
--checkbox-indicator-color: light-dark(#ffffff, #ffffff);
|
|
172
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Toggle
|
|
177
|
+
*/
|
|
178
|
+
|
|
179
|
+
--toggle-background: var(--border-color);
|
|
180
|
+
--toggle-background-checked: var(--checkbox-background-checked);
|
|
181
|
+
--toggle-border-color: var(--toggle-background);
|
|
182
|
+
--toggle-border-color-checked: var(--toggle-background-checked);
|
|
183
|
+
--toggle-thumb-color: var(--checkbox-indicator-color);
|
|
184
|
+
|
|
173
185
|
--field-label-color: var(--text-color-p);
|
|
174
186
|
|
|
175
|
-
--form-background
|
|
187
|
+
--form-background: var(--background-body);
|
|
188
|
+
--form-background-actions: color-mix(in oklch, var(--theme-surface-interactive) 35%, transparent);
|
|
176
189
|
|
|
177
190
|
/**
|
|
178
191
|
* Borders
|
|
@@ -201,12 +214,20 @@
|
|
|
201
214
|
--link-color-hover: var(--button-submit-base-color-hover);
|
|
202
215
|
--link-color-active: var(--button-submit-base-color-hover);
|
|
203
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Status Colors
|
|
219
|
+
*/
|
|
220
|
+
|
|
221
|
+
--status-default-color: light-dark(#111111, #e0e0e0);
|
|
222
|
+
|
|
204
223
|
/**
|
|
205
224
|
* Menus
|
|
206
225
|
*/
|
|
207
226
|
|
|
208
227
|
--menu-background-color: var(--surface-background);
|
|
209
|
-
--menu-background-color-hover: color-mix(in
|
|
228
|
+
--menu-background-color-hover: color-mix(in oklch, var(--theme-surface-interactive) 35%, transparent);
|
|
229
|
+
--menu-text-color: var(--text-color-p);
|
|
230
|
+
--menu-text-color-subtle: var(--text-color-p-subtle);
|
|
210
231
|
--menu-border-color: var(--border-color-subtle);
|
|
211
232
|
--menu-border-size: var(--border-size-thin);
|
|
212
233
|
--menu-border-style: var(--border-style);
|
|
@@ -221,7 +242,7 @@
|
|
|
221
242
|
--table-header-color: var(--text-color-heading);
|
|
222
243
|
--table-row-background: transparent;
|
|
223
244
|
--table-row-background-even: transparent;
|
|
224
|
-
--table-row-background-hover: color-mix(in
|
|
245
|
+
--table-row-background-hover: color-mix(in oklch, var(--theme-surface-interactive) 60%, transparent);
|
|
225
246
|
--table-cell-color: var(--text-color-p);
|
|
226
247
|
|
|
227
248
|
/**
|
|
@@ -270,6 +291,7 @@
|
|
|
270
291
|
--toast-border: var(--surface-border);
|
|
271
292
|
--toast-border-radius: var(--surface-border-radius);
|
|
272
293
|
--toast-shadow: var(--surface-shadow);
|
|
294
|
+
--toast-title-color: var(--text-color-heading);
|
|
273
295
|
|
|
274
296
|
/**
|
|
275
297
|
* Scrim/Backdrop
|
package/dist/form/Button.svelte
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
import { getContext, type Component, type Snippet } from 'svelte';
|
|
4
4
|
import type { LutraForm } from './types.js';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @description
|
|
8
|
+
* A polymorphic form button that renders as a `<button>` or `<a>` depending on whether `href` is set.
|
|
9
|
+
* Automatically disables itself while its parent form is in a loading state.
|
|
10
|
+
* Inherits the alignment context set by a parent `FormActions` component.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <Button type="submit" kind="default">Save</Button>
|
|
14
|
+
* <Button href="/cancel" kind="secondary">Cancel</Button>
|
|
15
|
+
* <Button kind="warn" icon={TrashIcon}>Delete</Button>
|
|
16
|
+
*/
|
|
6
17
|
let {
|
|
7
18
|
href,
|
|
8
19
|
type = 'button',
|
|
@@ -14,14 +25,23 @@
|
|
|
14
25
|
onclick,
|
|
15
26
|
children,
|
|
16
27
|
}: {
|
|
28
|
+
/** When set, renders as an `<a>` link instead of a `<button>`. */
|
|
17
29
|
href?: string;
|
|
30
|
+
/** The button type attribute. */
|
|
18
31
|
type?: 'button' | 'submit' | 'reset';
|
|
32
|
+
/** Visual style variant. */
|
|
19
33
|
kind?: 'default' | 'outlined' | 'secondary' | 'warn';
|
|
34
|
+
/** Size variant. */
|
|
20
35
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
36
|
+
/** Additional CSS class names. */
|
|
21
37
|
class?: string;
|
|
38
|
+
/** Whether the button is disabled. Also disabled automatically when the parent form is loading. */
|
|
22
39
|
disabled?: boolean;
|
|
40
|
+
/** Icon component or string to render before the label. */
|
|
23
41
|
icon?: string | Component;
|
|
42
|
+
/** Click event handler. */
|
|
24
43
|
onclick?: (event: MouseEvent) => void;
|
|
44
|
+
/** Button label content. */
|
|
25
45
|
children: Snippet;
|
|
26
46
|
} = $props();
|
|
27
47
|
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { type Component, type Snippet } from 'svelte';
|
|
2
2
|
type $$ComponentProps = {
|
|
3
|
+
/** When set, renders as an `<a>` link instead of a `<button>`. */
|
|
3
4
|
href?: string;
|
|
5
|
+
/** The button type attribute. */
|
|
4
6
|
type?: 'button' | 'submit' | 'reset';
|
|
7
|
+
/** Visual style variant. */
|
|
5
8
|
kind?: 'default' | 'outlined' | 'secondary' | 'warn';
|
|
9
|
+
/** Size variant. */
|
|
6
10
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
11
|
+
/** Additional CSS class names. */
|
|
7
12
|
class?: string;
|
|
13
|
+
/** Whether the button is disabled. Also disabled automatically when the parent form is loading. */
|
|
8
14
|
disabled?: boolean;
|
|
15
|
+
/** Icon component or string to render before the label. */
|
|
9
16
|
icon?: string | Component;
|
|
17
|
+
/** Click event handler. */
|
|
10
18
|
onclick?: (event: MouseEvent) => void;
|
|
19
|
+
/** Button label content. */
|
|
11
20
|
children: Snippet;
|
|
12
21
|
};
|
|
13
22
|
declare const Button: Component<$$ComponentProps, {}, "">;
|
|
@@ -4,11 +4,24 @@
|
|
|
4
4
|
import UiContent from "../components/UIContent.svelte";
|
|
5
5
|
import { getLocaleFirstDayOfWeek } from "../util/locale.js";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* @description
|
|
9
|
+
* A custom date/time range picker with year, month and day grids.
|
|
10
|
+
* Renders start and end `datetime-local` inputs alongside visual selection components
|
|
11
|
+
* for year, month and day. Respects the user's locale for first day of week.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <Datepicker />
|
|
15
|
+
* <Datepicker range={{ min: new Date('2024-01-01'), max: new Date('2025-12-31') }} />
|
|
16
|
+
*/
|
|
7
17
|
let {
|
|
8
18
|
range
|
|
9
19
|
}: {
|
|
20
|
+
/** Optional date range constraints. */
|
|
10
21
|
range?: {
|
|
22
|
+
/** Minimum selectable date. */
|
|
11
23
|
min?: Date;
|
|
24
|
+
/** Maximum selectable date. */
|
|
12
25
|
max?: Date;
|
|
13
26
|
}
|
|
14
27
|
} = $props();
|
|
@@ -7,7 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @description
|
|
10
|
-
*
|
|
10
|
+
* Internal wrapper used by Input, Select and Textarea to render the label, field
|
|
11
|
+
* border, prefix/suffix decorations, help text and error messages in a consistent layout.
|
|
12
|
+
*
|
|
13
|
+
* @cssprop --field-background -- Background color of the field container.
|
|
14
|
+
* @cssprop --field-border-size -- Border width of the field container.
|
|
15
|
+
* @cssprop --field-border-style -- Border style of the field container.
|
|
16
|
+
* @cssprop --field-border-color -- Border color of the field container.
|
|
17
|
+
* @cssprop --field-border-radius -- Border radius of the field container.
|
|
11
18
|
*/
|
|
12
19
|
let {
|
|
13
20
|
id,
|
|
@@ -62,8 +69,7 @@
|
|
|
62
69
|
{#if contained}
|
|
63
70
|
<div
|
|
64
71
|
class="Field"
|
|
65
|
-
|
|
66
|
-
class:hasSuffix={suffix}
|
|
72
|
+
|
|
67
73
|
class:invalid={field?.tainted && issue?.code}
|
|
68
74
|
>
|
|
69
75
|
{#if prefix}
|
|
@@ -105,13 +111,15 @@
|
|
|
105
111
|
.FieldContentContainer {
|
|
106
112
|
display: flex;
|
|
107
113
|
flex-direction: column;
|
|
108
|
-
gap: var(--form-field-gap
|
|
114
|
+
gap: var(--form-field-inside-gap);
|
|
115
|
+
min-width: 0;
|
|
109
116
|
}
|
|
110
117
|
.FieldContent {
|
|
111
118
|
display: flex;
|
|
112
119
|
gap: var(--form-label-gap, var(--space-xs));
|
|
113
120
|
flex-direction: column;
|
|
114
121
|
font-size: 1em;
|
|
122
|
+
min-width: 0;
|
|
115
123
|
}
|
|
116
124
|
.FieldContent.row {
|
|
117
125
|
flex-direction: row-reverse;
|
|
@@ -124,6 +132,7 @@
|
|
|
124
132
|
border: var(--field-border-size) var(--field-border-style) var(--field-border-color);
|
|
125
133
|
border-radius: var(--field-border-radius);
|
|
126
134
|
display: flex;
|
|
135
|
+
min-width: 0;
|
|
127
136
|
}
|
|
128
137
|
.Field.invalid {
|
|
129
138
|
border-color: var(--field-border-color-invalid);
|
|
@@ -138,7 +147,7 @@
|
|
|
138
147
|
padding-inline: var(--form-field-gap, var(--space-md));
|
|
139
148
|
font-size: 1em;
|
|
140
149
|
text-box: trim-both cap alphabetic;
|
|
141
|
-
color: var(--text-subtle);
|
|
150
|
+
color: var(--text-color-p-subtle);
|
|
142
151
|
}
|
|
143
152
|
.Suffix {
|
|
144
153
|
padding-inline-start: 0;
|
|
@@ -158,21 +167,21 @@
|
|
|
158
167
|
outline-color: var(--focus-ring-color-invalid);
|
|
159
168
|
border-color: var(--focus-ring-color-invalid);
|
|
160
169
|
}
|
|
161
|
-
.Field.
|
|
170
|
+
.Field:has(.Prefix) :global(input) {
|
|
162
171
|
padding-inline-start: var(--space-xxs);
|
|
163
172
|
}
|
|
164
173
|
.Field :global(button) {
|
|
165
|
-
margin-
|
|
174
|
+
margin-inline-end: var(--space-xxs);
|
|
166
175
|
}
|
|
167
176
|
.Field :global(button:focus-visible) {
|
|
168
|
-
outline: var(--focus-
|
|
177
|
+
outline: var(--focus-ring);
|
|
169
178
|
outline-offset: 3px;
|
|
170
|
-
border-radius: calc(var(--field-radius) - 2px);
|
|
179
|
+
border-radius: calc(var(--field-border-radius) - 2px);
|
|
171
180
|
}
|
|
172
181
|
.Help {
|
|
173
|
-
font-size:
|
|
182
|
+
font-size: var(--font-size-sm);
|
|
174
183
|
line-height: var(--font-line-height-tight);
|
|
175
184
|
color: var(--text-color-p-subtle);
|
|
176
|
-
font-weight: var(--font-weight-
|
|
185
|
+
font-weight: var(--font-weight-light);
|
|
177
186
|
}
|
|
178
187
|
</style>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import Label from "./Label.svelte";
|
|
4
|
+
import StringOrSnippet from "../util/StringOrSnippet.svelte";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @description
|
|
8
|
+
* Groups related form fields (checkboxes, radios, toggles) under a shared label
|
|
9
|
+
* with a tighter gap than the default form field spacing.
|
|
10
|
+
*
|
|
11
|
+
* @cssprop --field-group-gap -- Gap between items within the group.
|
|
12
|
+
* @cssprop --form-label-gap -- Gap between the group label and the items.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <FieldGroup label="Permissions">
|
|
16
|
+
* <Input name="read" type="checkbox" label="Read" />
|
|
17
|
+
* <Input name="write" type="checkbox" label="Write" />
|
|
18
|
+
* <Input name="admin" type="checkbox" label="Admin" />
|
|
19
|
+
* </FieldGroup>
|
|
20
|
+
*/
|
|
21
|
+
let {
|
|
22
|
+
id = crypto.randomUUID(),
|
|
23
|
+
label,
|
|
24
|
+
labelHelp,
|
|
25
|
+
labelTip,
|
|
26
|
+
help,
|
|
27
|
+
required,
|
|
28
|
+
children,
|
|
29
|
+
}: {
|
|
30
|
+
/** A unique id for the group. Auto-generated if not provided. */
|
|
31
|
+
id?: string;
|
|
32
|
+
/** The group label. */
|
|
33
|
+
label?: string | Snippet;
|
|
34
|
+
/** Help text to display alongside the label. */
|
|
35
|
+
labelHelp?: string | Snippet;
|
|
36
|
+
/** Context tooltip for the label. */
|
|
37
|
+
labelTip?: string | Snippet;
|
|
38
|
+
/** Help text to display below the group. */
|
|
39
|
+
help?: string | Snippet;
|
|
40
|
+
/** Whether the group is required. */
|
|
41
|
+
required?: boolean;
|
|
42
|
+
/** The grouped fields to render. */
|
|
43
|
+
children: Snippet;
|
|
44
|
+
} = $props();
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<div
|
|
48
|
+
class="FieldGroup"
|
|
49
|
+
role="group"
|
|
50
|
+
aria-labelledby={label ? `fg-${id}` : undefined}
|
|
51
|
+
>
|
|
52
|
+
{#if label}
|
|
53
|
+
<div id="fg-{id}">
|
|
54
|
+
<Label {label} tip={labelTip} help={labelHelp} {required} />
|
|
55
|
+
</div>
|
|
56
|
+
{/if}
|
|
57
|
+
<div class="FieldGroupContent">
|
|
58
|
+
{@render children()}
|
|
59
|
+
</div>
|
|
60
|
+
{#if help}
|
|
61
|
+
<div class="Help">
|
|
62
|
+
<StringOrSnippet content={help} />
|
|
63
|
+
</div>
|
|
64
|
+
{/if}
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<style>
|
|
68
|
+
.FieldGroup {
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
gap: var(--form-label-gap, var(--space-xs));
|
|
72
|
+
}
|
|
73
|
+
.FieldGroupContent {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
gap: var(--field-group-gap);
|
|
77
|
+
}
|
|
78
|
+
.Help {
|
|
79
|
+
font-size: var(--font-size-sm);
|
|
80
|
+
line-height: var(--font-line-height-tight);
|
|
81
|
+
color: var(--text-color-p-subtle);
|
|
82
|
+
font-weight: var(--font-weight-light);
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
/** A unique id for the group. Auto-generated if not provided. */
|
|
4
|
+
id?: string;
|
|
5
|
+
/** The group label. */
|
|
6
|
+
label?: string | Snippet;
|
|
7
|
+
/** Help text to display alongside the label. */
|
|
8
|
+
labelHelp?: string | Snippet;
|
|
9
|
+
/** Context tooltip for the label. */
|
|
10
|
+
labelTip?: string | Snippet;
|
|
11
|
+
/** Help text to display below the group. */
|
|
12
|
+
help?: string | Snippet;
|
|
13
|
+
/** Whether the group is required. */
|
|
14
|
+
required?: boolean;
|
|
15
|
+
/** The grouped fields to render. */
|
|
16
|
+
children: Snippet;
|
|
17
|
+
};
|
|
18
|
+
declare const FieldGroup: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
19
|
+
type FieldGroup = ReturnType<typeof FieldGroup>;
|
|
20
|
+
export default FieldGroup;
|
|
@@ -3,14 +3,19 @@
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @description
|
|
6
|
-
* A fieldset is a group of related form elements
|
|
6
|
+
* A fieldset is a group of related form elements. Supports responsive column
|
|
7
|
+
* layouts via container queries, optional contained styling with padding,
|
|
8
|
+
* and rounded borders.
|
|
9
|
+
*
|
|
10
|
+
* @cssprop --form-field-gap -- Gap between fields within the fieldset.
|
|
11
|
+
* @cssprop --form-padding-block -- Block padding when contained.
|
|
12
|
+
* @cssprop --form-padding-inline -- Inline padding when contained.
|
|
13
|
+
* @cssprop --field-label-font-size -- Font size for the legend.
|
|
14
|
+
*
|
|
7
15
|
* @example
|
|
8
|
-
* <
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* <Fieldset legend="Personal Information">
|
|
12
|
-
* <Input label="First Name" />
|
|
13
|
-
* <Input label="Last Name" />
|
|
16
|
+
* <Fieldset legend="Personal Information" columns={2}>
|
|
17
|
+
* <Input label="First Name" name="first" />
|
|
18
|
+
* <Input label="Last Name" name="last" />
|
|
14
19
|
* </Fieldset>
|
|
15
20
|
*/
|
|
16
21
|
|
|
@@ -76,16 +81,19 @@
|
|
|
76
81
|
}
|
|
77
82
|
fieldset {
|
|
78
83
|
display: grid;
|
|
84
|
+
border: none;
|
|
85
|
+
margin: 0;
|
|
86
|
+
padding: 0;
|
|
79
87
|
width: var(--width, fit-content);
|
|
80
88
|
grid-template-columns: repeat(var(--lg-cols), 1fr);
|
|
81
|
-
gap: var(--gap
|
|
89
|
+
gap: var(--form-field-gap);
|
|
82
90
|
}
|
|
83
91
|
legend {
|
|
84
|
-
font-weight:
|
|
85
|
-
font-size: var(--font-size
|
|
92
|
+
font-weight: var(--font-weight-normal);
|
|
93
|
+
font-size: var(--field-label-font-size);
|
|
86
94
|
}
|
|
87
95
|
fieldset.contained {
|
|
88
|
-
padding:
|
|
96
|
+
padding: var(--form-padding-block) var(--form-padding-inline);
|
|
89
97
|
}
|
|
90
98
|
fieldset.fullWidth {
|
|
91
99
|
width: 100%;
|