@marianmeres/stuic 3.187.0 → 3.189.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/API.md +47 -0
- package/README.md +2 -2
- package/dist/README.md +1 -0
- package/dist/components/ColorPicker/ColorPicker.svelte +26 -1
- package/dist/components/ColorPicker/ColorPicker.svelte.d.ts +9 -0
- package/dist/components/ColorPicker/README.md +19 -7
- package/dist/components/Gantt/Gantt.svelte +451 -0
- package/dist/components/Gantt/Gantt.svelte.d.ts +134 -0
- package/dist/components/Gantt/README.md +298 -0
- package/dist/components/Gantt/gantt-geometry.d.ts +131 -0
- package/dist/components/Gantt/gantt-geometry.js +214 -0
- package/dist/components/Gantt/index.css +496 -0
- package/dist/components/Gantt/index.d.ts +2 -0
- package/dist/components/Gantt/index.js +2 -0
- package/dist/components/Input/FieldColorPicker.svelte +201 -0
- package/dist/components/Input/FieldColorPicker.svelte.d.ts +59 -0
- package/dist/components/Input/README.md +45 -0
- package/dist/components/Input/index.css +21 -9
- package/dist/components/Input/index.d.ts +1 -0
- package/dist/components/Input/index.js +1 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/validate-fields.d.ts +1 -1
- package/docs/domains/components.md +64 -4
- package/package.json +1 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { default as Gantt, type Props as GanttProps, type GanttRow, type GanttBar, type GanttBarLabels, type GanttSelectDetail, } from "./Gantt.svelte";
|
|
2
|
+
export { buildGanttAxis, placeRange, placePoint, dayToFraction, boundsOf, isoWeekNumber, GANTT_MAX_COLUMNS, type GanttAxis, type GanttAxisOptions, type GanttColumn, type GanttGroup, type GanttPlacement, type GanttDateInput, type GanttUnit, } from "./gantt-geometry.js";
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { ValidateOptions } from "../../actions/validate.svelte.js";
|
|
4
|
+
import type { TranslateFn } from "../../types.js";
|
|
5
|
+
import type { ColorPickerCustom } from "../ColorPicker/ColorPicker.svelte";
|
|
6
|
+
import type { ColorPickerSwatch } from "../ColorPicker/palettes.js";
|
|
7
|
+
import type { THC } from "../Thc/Thc.svelte";
|
|
8
|
+
import type { InputWrapClassProps } from "./types.js";
|
|
9
|
+
|
|
10
|
+
type SnippetWithId = Snippet<[{ id: string }]>;
|
|
11
|
+
|
|
12
|
+
export interface Props extends InputWrapClassProps, Record<string, any> {
|
|
13
|
+
/** Current color (bindable). Any CSS color string; `""` = no color */
|
|
14
|
+
value?: string;
|
|
15
|
+
label?: SnippetWithId | THC;
|
|
16
|
+
description?: SnippetWithId | THC;
|
|
17
|
+
class?: string;
|
|
18
|
+
id?: string;
|
|
19
|
+
renderSize?: "sm" | "md" | "lg" | string;
|
|
20
|
+
required?: boolean;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
validate?: boolean | Omit<ValidateOptions, "setValidationResult">;
|
|
23
|
+
labelAfter?: SnippetWithId | THC;
|
|
24
|
+
inputBefore?: SnippetWithId | THC;
|
|
25
|
+
inputAfter?: SnippetWithId | THC;
|
|
26
|
+
inputBelow?: SnippetWithId | THC;
|
|
27
|
+
below?: SnippetWithId | THC;
|
|
28
|
+
labelLeft?: boolean;
|
|
29
|
+
labelLeftWidth?: "normal" | "wide";
|
|
30
|
+
labelLeftBreakpoint?: number;
|
|
31
|
+
/** Classes for the underlying <ColorPicker> root */
|
|
32
|
+
classInput?: string;
|
|
33
|
+
style?: string;
|
|
34
|
+
//
|
|
35
|
+
// Below: forwarded as-is to the underlying <ColorPicker>.
|
|
36
|
+
//
|
|
37
|
+
/** The swatches: color strings or `{ value, label }` objects */
|
|
38
|
+
palette?: ColorPickerSwatch[];
|
|
39
|
+
/** Cap the palette at this many swatches per row */
|
|
40
|
+
columns?: number;
|
|
41
|
+
/** Which custom-color controls to show (default `"both"`) */
|
|
42
|
+
custom?: ColorPickerCustom;
|
|
43
|
+
/** Offer clearing (the "no color" swatch, Delete / Backspace) */
|
|
44
|
+
allowClear?: boolean;
|
|
45
|
+
/** Form field name (hidden input) */
|
|
46
|
+
name?: string;
|
|
47
|
+
/** i18n translate function (see `createColorPickerT`) */
|
|
48
|
+
t?: TranslateFn;
|
|
49
|
+
/** Fires when the user commits a color (not while dragging the native picker) */
|
|
50
|
+
onchange?: (value: string) => void;
|
|
51
|
+
/** Class for every swatch button */
|
|
52
|
+
classSwatch?: string;
|
|
53
|
+
}
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<script lang="ts">
|
|
57
|
+
import type { ValidationResult } from "../../actions/validate.svelte.js";
|
|
58
|
+
import { getId } from "../../utils/get-id.js";
|
|
59
|
+
import { twMerge } from "../../utils/tw-merge.js";
|
|
60
|
+
import ColorPicker from "../ColorPicker/ColorPicker.svelte";
|
|
61
|
+
import InputWrap from "./_internal/InputWrap.svelte";
|
|
62
|
+
|
|
63
|
+
let {
|
|
64
|
+
value = $bindable(""),
|
|
65
|
+
label = "",
|
|
66
|
+
id = getId(),
|
|
67
|
+
description,
|
|
68
|
+
class: classProp,
|
|
69
|
+
renderSize = "md",
|
|
70
|
+
//
|
|
71
|
+
required = false,
|
|
72
|
+
disabled = false,
|
|
73
|
+
//
|
|
74
|
+
// Renamed local binding to avoid collision with `export function validate()` below.
|
|
75
|
+
validate: validateProp,
|
|
76
|
+
//
|
|
77
|
+
labelAfter,
|
|
78
|
+
inputBefore,
|
|
79
|
+
inputAfter,
|
|
80
|
+
inputBelow,
|
|
81
|
+
below,
|
|
82
|
+
//
|
|
83
|
+
labelLeft = false,
|
|
84
|
+
labelLeftWidth = "normal",
|
|
85
|
+
labelLeftBreakpoint = 480,
|
|
86
|
+
//
|
|
87
|
+
classInput,
|
|
88
|
+
//
|
|
89
|
+
palette,
|
|
90
|
+
columns,
|
|
91
|
+
custom,
|
|
92
|
+
allowClear,
|
|
93
|
+
name,
|
|
94
|
+
t,
|
|
95
|
+
onchange,
|
|
96
|
+
classSwatch,
|
|
97
|
+
//
|
|
98
|
+
classLabel,
|
|
99
|
+
classLabelBox,
|
|
100
|
+
classInputBox,
|
|
101
|
+
classInputBoxWrap,
|
|
102
|
+
classInputBoxWrapInvalid,
|
|
103
|
+
classDescBox,
|
|
104
|
+
classDescBoxToggle,
|
|
105
|
+
classBelowBox,
|
|
106
|
+
classValidationBox,
|
|
107
|
+
style = "",
|
|
108
|
+
//
|
|
109
|
+
...rest
|
|
110
|
+
}: Props = $props();
|
|
111
|
+
|
|
112
|
+
//
|
|
113
|
+
let validation: ValidationResult | undefined = $state();
|
|
114
|
+
const setValidationResult = (res: ValidationResult) => (validation = res);
|
|
115
|
+
|
|
116
|
+
// Delegate the imperative API to the inner ColorPicker.
|
|
117
|
+
let pickerRef: ColorPicker | undefined = $state();
|
|
118
|
+
|
|
119
|
+
/** Trigger validation now. Renders the inline message if invalid. */
|
|
120
|
+
export function validate(): ValidationResult | undefined {
|
|
121
|
+
pickerRef?.validate();
|
|
122
|
+
return validation;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Clear the inline validation message. */
|
|
126
|
+
export function clearValidation(): void {
|
|
127
|
+
pickerRef?.clearValidation?.();
|
|
128
|
+
validation = undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Current validation state. */
|
|
132
|
+
export function getValidation(): ValidationResult | undefined {
|
|
133
|
+
return validation;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Focus the swatch group's tab stop (or the first custom-color control). */
|
|
137
|
+
export function focus(): void {
|
|
138
|
+
pickerRef?.focus?.();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Scroll the field into view. Defaults to smooth + center. */
|
|
142
|
+
export function scrollIntoView(opts?: ScrollIntoViewOptions): void {
|
|
143
|
+
pickerRef?.scrollIntoView?.(opts);
|
|
144
|
+
}
|
|
145
|
+
</script>
|
|
146
|
+
|
|
147
|
+
<InputWrap
|
|
148
|
+
{description}
|
|
149
|
+
class={classProp}
|
|
150
|
+
size={renderSize}
|
|
151
|
+
{id}
|
|
152
|
+
{label}
|
|
153
|
+
{labelAfter}
|
|
154
|
+
{inputBefore}
|
|
155
|
+
{inputAfter}
|
|
156
|
+
{inputBelow}
|
|
157
|
+
{below}
|
|
158
|
+
{required}
|
|
159
|
+
{disabled}
|
|
160
|
+
{labelLeft}
|
|
161
|
+
{labelLeftWidth}
|
|
162
|
+
{labelLeftBreakpoint}
|
|
163
|
+
{classLabel}
|
|
164
|
+
{classLabelBox}
|
|
165
|
+
{classInputBox}
|
|
166
|
+
{classInputBoxWrapInvalid}
|
|
167
|
+
{classDescBox}
|
|
168
|
+
{classDescBoxToggle}
|
|
169
|
+
{classBelowBox}
|
|
170
|
+
{classValidationBox}
|
|
171
|
+
{validation}
|
|
172
|
+
classInputBoxWrap={twMerge("input-wrap-transparent", classInputBoxWrap)}
|
|
173
|
+
{style}
|
|
174
|
+
>
|
|
175
|
+
<!--
|
|
176
|
+
`labelledby` (not the InputWrap's `for={id}`) is what names the swatch group: a
|
|
177
|
+
radiogroup is a <div>, which a `for` cannot label. Matches InputWrap's own
|
|
178
|
+
`{id}-label`, and only when there is a label to point at — otherwise the picker
|
|
179
|
+
keeps its own `t("color")` name. The picker's string `label` prop is deliberately
|
|
180
|
+
not forwarded: here `label` is the visible one.
|
|
181
|
+
-->
|
|
182
|
+
<ColorPicker
|
|
183
|
+
bind:this={pickerRef}
|
|
184
|
+
bind:value
|
|
185
|
+
{palette}
|
|
186
|
+
{columns}
|
|
187
|
+
{custom}
|
|
188
|
+
{allowClear}
|
|
189
|
+
{name}
|
|
190
|
+
{t}
|
|
191
|
+
{onchange}
|
|
192
|
+
{classSwatch}
|
|
193
|
+
{required}
|
|
194
|
+
{disabled}
|
|
195
|
+
class={classInput}
|
|
196
|
+
labelledby={label ? `${id}-label` : undefined}
|
|
197
|
+
validate={validateProp}
|
|
198
|
+
{setValidationResult}
|
|
199
|
+
{...rest}
|
|
200
|
+
/>
|
|
201
|
+
</InputWrap>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { ValidateOptions } from "../../actions/validate.svelte.js";
|
|
3
|
+
import type { TranslateFn } from "../../types.js";
|
|
4
|
+
import type { ColorPickerCustom } from "../ColorPicker/ColorPicker.svelte";
|
|
5
|
+
import type { ColorPickerSwatch } from "../ColorPicker/palettes.js";
|
|
6
|
+
import type { THC } from "../Thc/Thc.svelte";
|
|
7
|
+
import type { InputWrapClassProps } from "./types.js";
|
|
8
|
+
type SnippetWithId = Snippet<[{
|
|
9
|
+
id: string;
|
|
10
|
+
}]>;
|
|
11
|
+
export interface Props extends InputWrapClassProps, Record<string, any> {
|
|
12
|
+
/** Current color (bindable). Any CSS color string; `""` = no color */
|
|
13
|
+
value?: string;
|
|
14
|
+
label?: SnippetWithId | THC;
|
|
15
|
+
description?: SnippetWithId | THC;
|
|
16
|
+
class?: string;
|
|
17
|
+
id?: string;
|
|
18
|
+
renderSize?: "sm" | "md" | "lg" | string;
|
|
19
|
+
required?: boolean;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
validate?: boolean | Omit<ValidateOptions, "setValidationResult">;
|
|
22
|
+
labelAfter?: SnippetWithId | THC;
|
|
23
|
+
inputBefore?: SnippetWithId | THC;
|
|
24
|
+
inputAfter?: SnippetWithId | THC;
|
|
25
|
+
inputBelow?: SnippetWithId | THC;
|
|
26
|
+
below?: SnippetWithId | THC;
|
|
27
|
+
labelLeft?: boolean;
|
|
28
|
+
labelLeftWidth?: "normal" | "wide";
|
|
29
|
+
labelLeftBreakpoint?: number;
|
|
30
|
+
/** Classes for the underlying <ColorPicker> root */
|
|
31
|
+
classInput?: string;
|
|
32
|
+
style?: string;
|
|
33
|
+
/** The swatches: color strings or `{ value, label }` objects */
|
|
34
|
+
palette?: ColorPickerSwatch[];
|
|
35
|
+
/** Cap the palette at this many swatches per row */
|
|
36
|
+
columns?: number;
|
|
37
|
+
/** Which custom-color controls to show (default `"both"`) */
|
|
38
|
+
custom?: ColorPickerCustom;
|
|
39
|
+
/** Offer clearing (the "no color" swatch, Delete / Backspace) */
|
|
40
|
+
allowClear?: boolean;
|
|
41
|
+
/** Form field name (hidden input) */
|
|
42
|
+
name?: string;
|
|
43
|
+
/** i18n translate function (see `createColorPickerT`) */
|
|
44
|
+
t?: TranslateFn;
|
|
45
|
+
/** Fires when the user commits a color (not while dragging the native picker) */
|
|
46
|
+
onchange?: (value: string) => void;
|
|
47
|
+
/** Class for every swatch button */
|
|
48
|
+
classSwatch?: string;
|
|
49
|
+
}
|
|
50
|
+
import type { ValidationResult } from "../../actions/validate.svelte.js";
|
|
51
|
+
declare const FieldColorPicker: import("svelte").Component<Props, {
|
|
52
|
+
validate: () => ValidationResult | undefined;
|
|
53
|
+
clearValidation: () => void;
|
|
54
|
+
getValidation: () => ValidationResult | undefined;
|
|
55
|
+
focus: () => void;
|
|
56
|
+
scrollIntoView: (opts?: ScrollIntoViewOptions) => void;
|
|
57
|
+
}, "value">;
|
|
58
|
+
type FieldColorPicker = ReturnType<typeof FieldColorPicker>;
|
|
59
|
+
export default FieldColorPicker;
|
|
@@ -15,6 +15,7 @@ A comprehensive form input system with multiple field components, validation sup
|
|
|
15
15
|
| `FieldCheckbox` | Single checkbox with label |
|
|
16
16
|
| `FieldRadios` | Radio button group |
|
|
17
17
|
| `FieldSwitch` | Toggle switch field |
|
|
18
|
+
| `FieldColorPicker` | Color picker (swatches + custom color) field — see below |
|
|
18
19
|
| `FieldFile` | File upload input |
|
|
19
20
|
| `FieldAssets` | Asset/image upload with preview |
|
|
20
21
|
| `FieldSingleAsset` | One asset (avatar, logo, cover, one document) — see below |
|
|
@@ -184,6 +185,50 @@ The visible label names the control via `aria-labelledby` (the switch is announc
|
|
|
184
185
|
`switch, on/off` with that name). Clicking the label text does not toggle — the switch's
|
|
185
186
|
own root is a `<label>`, so an HTML `for` association is not possible; click the switch.
|
|
186
187
|
|
|
188
|
+
### Color Picker
|
|
189
|
+
|
|
190
|
+
`FieldColorPicker` wraps a [`ColorPicker`](../ColorPicker/README.md) in the standard field
|
|
191
|
+
scaffolding — visible label, description, validation box, `labelLeft*`, every
|
|
192
|
+
`InputWrapClassProps` member — the way `FieldSwitch` wraps `Switch`.
|
|
193
|
+
|
|
194
|
+
```svelte
|
|
195
|
+
<script lang="ts">
|
|
196
|
+
import { FieldColorPicker } from "stuic";
|
|
197
|
+
|
|
198
|
+
let accent = $state("");
|
|
199
|
+
</script>
|
|
200
|
+
|
|
201
|
+
<FieldColorPicker
|
|
202
|
+
label="Page colour"
|
|
203
|
+
description="Used for buttons and links on the public page."
|
|
204
|
+
name="accent"
|
|
205
|
+
required
|
|
206
|
+
bind:value={accent}
|
|
207
|
+
/>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
| Prop | Goes to |
|
|
211
|
+
| ----------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
212
|
+
| `value` (bindable), `palette`, `columns`, `custom`, `allowClear`, `name`, `t`, `onchange` | the inner `<ColorPicker>` (same semantics, same defaults) |
|
|
213
|
+
| `classSwatch` | every swatch button |
|
|
214
|
+
| `classInput` | the inner `<ColorPicker>`'s root class |
|
|
215
|
+
| `required`, `disabled`, `validate` | both: the shell (asterisk, dimming, message) and the picker |
|
|
216
|
+
| `renderSize` | the surrounding field shell only — swatch size is a CSS token |
|
|
217
|
+
| everything else unrecognized (`...rest`) | the inner `<ColorPicker>` root |
|
|
218
|
+
|
|
219
|
+
- **Naming.** The visible label names the swatch radiogroup via `aria-labelledby` →
|
|
220
|
+
`{id}-label`, with no competing `aria-label`. Without a `label` the group keeps the
|
|
221
|
+
picker's own `t("color")` name. Clicking the label text focuses nothing (a radiogroup is
|
|
222
|
+
not labelable by `for`) — same as `FieldSwitch`. With `palette={[]}` and
|
|
223
|
+
`allowClear={false}` there is no radiogroup, so the label names nothing; the hex field
|
|
224
|
+
keeps its own "Hex value" name.
|
|
225
|
+
- **Validation.** The picker's hidden input runs the `validate` action; the result renders
|
|
226
|
+
in the field's validation box. `validate()`, `clearValidation()`, `getValidation()`,
|
|
227
|
+
`focus()` (the checked swatch — the group's tab stop) and `scrollIntoView()` are
|
|
228
|
+
available via `bind:this`, so `validateAllFields` / `scrollToFirstInvalidField` work.
|
|
229
|
+
- **Layout.** The input wrap is transparent (no border / focus ring — the picker draws its
|
|
230
|
+
own swatches and hex field). A disabled field dims once (the shell), not twice.
|
|
231
|
+
|
|
187
232
|
### Input with Addons
|
|
188
233
|
|
|
189
234
|
```svelte
|
|
@@ -144,12 +144,18 @@
|
|
|
144
144
|
/* ============================================================================
|
|
145
145
|
BASE INPUT ELEMENT STYLES
|
|
146
146
|
Replaces @tailwindcss/forms plugin for input elements
|
|
147
|
+
|
|
148
|
+
`:where(:not(.stuic-color-picker *))` (here, in the size variants and in the
|
|
149
|
+
iOS zoom guard) exempts a composite control that styles its own raw inputs:
|
|
150
|
+
FieldColorPicker's hex field and native picker would otherwise lose their
|
|
151
|
+
border, font and size to these rules. Inside `:where()`, so the specificity
|
|
152
|
+
every existing override was written against is unchanged.
|
|
147
153
|
============================================================================ */
|
|
148
154
|
|
|
149
155
|
.stuic-input
|
|
150
156
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
|
|
151
157
|
[type="file"]
|
|
152
|
-
),
|
|
158
|
+
):where(:not(.stuic-color-picker *)),
|
|
153
159
|
.stuic-input textarea,
|
|
154
160
|
.stuic-input select {
|
|
155
161
|
/* Reset browser defaults */
|
|
@@ -202,7 +208,7 @@
|
|
|
202
208
|
.stuic-input[data-size="sm"]
|
|
203
209
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
|
|
204
210
|
[type="file"]
|
|
205
|
-
),
|
|
211
|
+
):where(:not(.stuic-color-picker *)),
|
|
206
212
|
.stuic-input[data-size="sm"] textarea,
|
|
207
213
|
.stuic-input[data-size="sm"] select {
|
|
208
214
|
padding: var(--stuic-input-padding-y-sm) var(--stuic-input-padding-x-sm);
|
|
@@ -217,13 +223,13 @@
|
|
|
217
223
|
.stuic-input[data-size="md"]
|
|
218
224
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
|
|
219
225
|
[type="file"]
|
|
220
|
-
),
|
|
226
|
+
):where(:not(.stuic-color-picker *)),
|
|
221
227
|
.stuic-input[data-size="md"] textarea,
|
|
222
228
|
.stuic-input[data-size="md"] select,
|
|
223
229
|
.stuic-input:not([data-size])
|
|
224
230
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
|
|
225
231
|
[type="file"]
|
|
226
|
-
),
|
|
232
|
+
):where(:not(.stuic-color-picker *)),
|
|
227
233
|
.stuic-input:not([data-size]) textarea,
|
|
228
234
|
.stuic-input:not([data-size]) select {
|
|
229
235
|
padding: var(--stuic-input-padding-y-md) var(--stuic-input-padding-x-md);
|
|
@@ -239,7 +245,7 @@
|
|
|
239
245
|
.stuic-input[data-size="lg"]
|
|
240
246
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
|
|
241
247
|
[type="file"]
|
|
242
|
-
),
|
|
248
|
+
):where(:not(.stuic-color-picker *)),
|
|
243
249
|
.stuic-input[data-size="lg"] textarea,
|
|
244
250
|
.stuic-input[data-size="lg"] select {
|
|
245
251
|
padding: var(--stuic-input-padding-y-lg) var(--stuic-input-padding-x-lg);
|
|
@@ -329,6 +335,12 @@
|
|
|
329
335
|
box-shadow: none;
|
|
330
336
|
}
|
|
331
337
|
|
|
338
|
+
/* FieldColorPicker: a disabled shell already dims the wrap — dimming the picker
|
|
339
|
+
again would compound to 0.25 */
|
|
340
|
+
.stuic-input.disabled .stuic-color-picker[data-disabled] {
|
|
341
|
+
opacity: 1;
|
|
342
|
+
}
|
|
343
|
+
|
|
332
344
|
/* Size-specific input-wrap padding */
|
|
333
345
|
.stuic-input[data-size="lg"] .input-wrap {
|
|
334
346
|
padding: calc(var(--spacing) * 1);
|
|
@@ -841,7 +853,7 @@
|
|
|
841
853
|
.stuic-input[data-size="sm"]
|
|
842
854
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
|
|
843
855
|
[type="file"]
|
|
844
|
-
),
|
|
856
|
+
):where(:not(.stuic-color-picker *)),
|
|
845
857
|
.stuic-input[data-size="sm"] textarea,
|
|
846
858
|
.stuic-input[data-size="sm"] select {
|
|
847
859
|
font-size: max(
|
|
@@ -853,13 +865,13 @@
|
|
|
853
865
|
.stuic-input[data-size="md"]
|
|
854
866
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
|
|
855
867
|
[type="file"]
|
|
856
|
-
),
|
|
868
|
+
):where(:not(.stuic-color-picker *)),
|
|
857
869
|
.stuic-input[data-size="md"] textarea,
|
|
858
870
|
.stuic-input[data-size="md"] select,
|
|
859
871
|
.stuic-input:not([data-size])
|
|
860
872
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
|
|
861
873
|
[type="file"]
|
|
862
|
-
),
|
|
874
|
+
):where(:not(.stuic-color-picker *)),
|
|
863
875
|
.stuic-input:not([data-size]) textarea,
|
|
864
876
|
.stuic-input:not([data-size]) select {
|
|
865
877
|
font-size: max(
|
|
@@ -871,7 +883,7 @@
|
|
|
871
883
|
.stuic-input[data-size="lg"]
|
|
872
884
|
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not(
|
|
873
885
|
[type="file"]
|
|
874
|
-
),
|
|
886
|
+
):where(:not(.stuic-color-picker *)),
|
|
875
887
|
.stuic-input[data-size="lg"] textarea,
|
|
876
888
|
.stuic-input[data-size="lg"] select {
|
|
877
889
|
font-size: max(
|
|
@@ -4,6 +4,7 @@ export { default as FieldSingleAsset, type Props as FieldSingleAssetProps, type
|
|
|
4
4
|
export { createFieldSingleAssetT, FIELD_SINGLE_ASSET_MESSAGES_EN, type FieldSingleAssetMessageKey, type FieldSingleAssetMessages, } from "./field-single-asset-i18n.js";
|
|
5
5
|
export { FIELD_SINGLE_ASSET_MESSAGES_SK } from "./field-single-asset-i18n-sk.js";
|
|
6
6
|
export { default as FieldCheckbox, type Props as FieldCheckboxProps, } from "./FieldCheckbox.svelte";
|
|
7
|
+
export { default as FieldColorPicker, type Props as FieldColorPickerProps, } from "./FieldColorPicker.svelte";
|
|
7
8
|
export { default as Honeypot, type Props as HoneypotProps } from "./Honeypot.svelte";
|
|
8
9
|
export { default as TimeTrap, type Props as TimeTrapProps, type TimeTrapSnapshot, } from "./TimeTrap.svelte";
|
|
9
10
|
export { default as FieldFile, type Props as FieldFileProps } from "./FieldFile.svelte";
|
|
@@ -4,6 +4,7 @@ export { default as FieldSingleAsset, } from "./FieldSingleAsset.svelte";
|
|
|
4
4
|
export { createFieldSingleAssetT, FIELD_SINGLE_ASSET_MESSAGES_EN, } from "./field-single-asset-i18n.js";
|
|
5
5
|
export { FIELD_SINGLE_ASSET_MESSAGES_SK } from "./field-single-asset-i18n-sk.js";
|
|
6
6
|
export { default as FieldCheckbox, } from "./FieldCheckbox.svelte";
|
|
7
|
+
export { default as FieldColorPicker, } from "./FieldColorPicker.svelte";
|
|
7
8
|
export { default as Honeypot } from "./Honeypot.svelte";
|
|
8
9
|
export { default as TimeTrap, } from "./TimeTrap.svelte";
|
|
9
10
|
export { default as FieldFile } from "./FieldFile.svelte";
|
package/dist/index.css
CHANGED
|
@@ -103,6 +103,7 @@ In practice:
|
|
|
103
103
|
@import "./components/EmptyState/index.css";
|
|
104
104
|
@import "./components/FieldsBuilder/index.css";
|
|
105
105
|
@import "./components/Float/index.css";
|
|
106
|
+
@import "./components/Gantt/index.css";
|
|
106
107
|
@import "./components/H/index.css";
|
|
107
108
|
@import "./components/Header/index.css";
|
|
108
109
|
@import "./components/ImageCycler/index.css";
|
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ export * from "./components/EmailVerifyForm/index.js";
|
|
|
55
55
|
export * from "./components/EmptyState/index.js";
|
|
56
56
|
export * from "./components/FieldsBuilder/index.js";
|
|
57
57
|
export * from "./components/Float/index.js";
|
|
58
|
+
export * from "./components/Gantt/index.js";
|
|
58
59
|
export * from "./components/H/index.js";
|
|
59
60
|
export * from "./components/Header/index.js";
|
|
60
61
|
export * from "./components/ImageCycler/index.js";
|
package/dist/index.js
CHANGED
|
@@ -61,6 +61,7 @@ export * from "./components/EmailVerifyForm/index.js";
|
|
|
61
61
|
export * from "./components/EmptyState/index.js";
|
|
62
62
|
export * from "./components/FieldsBuilder/index.js";
|
|
63
63
|
export * from "./components/Float/index.js";
|
|
64
|
+
export * from "./components/Gantt/index.js";
|
|
64
65
|
export * from "./components/H/index.js";
|
|
65
66
|
export * from "./components/Header/index.js";
|
|
66
67
|
export * from "./components/ImageCycler/index.js";
|
|
@@ -7,7 +7,7 @@ import type { ValidationResult } from "../actions/validate.svelte.js";
|
|
|
7
7
|
* Every STUIC `Field*` component (FieldInput, FieldPhoneNumber, FieldCountry,
|
|
8
8
|
* FieldSelect, FieldCheckbox, FieldTextarea, FieldFile, FieldObject,
|
|
9
9
|
* FieldAssets, FieldInputLocalized, FieldKeyValues, FieldLikeButton,
|
|
10
|
-
* FieldRadios, FieldSwitch) satisfies this interface via `export function`.
|
|
10
|
+
* FieldRadios, FieldSwitch, FieldColorPicker) satisfies this interface via `export function`.
|
|
11
11
|
*/
|
|
12
12
|
export interface ValidatableField {
|
|
13
13
|
/** Run the validator now. Renders the inline error if invalid. */
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
| CronInput | Cron expression editor with presets and validation |
|
|
74
74
|
| Fieldset | Field grouping with legend |
|
|
75
75
|
| FieldKeyValues | Key-value pair editor |
|
|
76
|
+
| FieldColorPicker | ColorPicker in the field shell: visible label names the swatch group, description, validation box |
|
|
76
77
|
| FieldTable | Rows × typed columns editor (text/number/select/checkbox/date/url cells, container layout) |
|
|
77
78
|
| FieldsBuilder | Field-definition list editor ("what properties does a thing have?") |
|
|
78
79
|
| FieldAssets | File/asset management |
|
|
@@ -110,6 +111,7 @@
|
|
|
110
111
|
| Stat | KPI/stat card: label + value + delta with trend arrow and semantic coloring |
|
|
111
112
|
| DescriptionList | Term/value list (`<dl>`): stacked or two-column by container query, hairlines, truncation, totals |
|
|
112
113
|
| Timeline | Vertical event list on a rail: dot/icon/custom markers, inline or opposite time, alternate layout |
|
|
114
|
+
| Gantt | Horizontal schedule chart: day/week/month axis, bars, milestones, progress, today line |
|
|
113
115
|
| TrendChart | Svelte wrapper for `@marianmeres/trend-chart` (subpath-only: `@marianmeres/stuic/trend-chart`) |
|
|
114
116
|
| Tree | Hierarchical tree view with keyboard nav and drag-and-drop |
|
|
115
117
|
| X | Styled close/multiply SVG icon |
|
|
@@ -159,7 +161,7 @@ Use `validate={false}` to bypass stuic's validation entirely.
|
|
|
159
161
|
|
|
160
162
|
> **Why default-on?** Hidden-input field components (`FieldPhoneNumber`,
|
|
161
163
|
> `FieldCountry`, `FieldObject`, `FieldAssets`, `FieldSingleAsset`, `FieldInputLocalized`,
|
|
162
|
-
> `FieldKeyValues`, `FieldTable`, `FieldLikeButton`, `FieldDate`, `FieldDateRange`, `Rating`) _must_ be default-on because hidden
|
|
164
|
+
> `FieldKeyValues`, `FieldTable`, `FieldLikeButton`, `FieldDate`, `FieldDateRange`, `ColorPicker`, `FieldColorPicker`, `Rating`) _must_ be default-on because hidden
|
|
163
165
|
> inputs are excluded from native browser constraint validation — without the
|
|
164
166
|
> stuic action enforcing `required` in a `customValidator`, the attribute is a
|
|
165
167
|
> silent no-op. Plain-input field components were harmonized to the same
|
|
@@ -170,8 +172,8 @@ Use `validate={false}` to bypass stuic's validation entirely.
|
|
|
170
172
|
Available on `FieldInput`, `FieldMoney`, `FieldTextarea`, `FieldCheckbox`,
|
|
171
173
|
`FieldSelect`, `FieldFile`, `FieldObject`, `FieldAssets`, `FieldSingleAsset`, `FieldInputLocalized`,
|
|
172
174
|
`FieldKeyValues`, `FieldTable`, `FieldPhoneNumber`, `FieldCountry`, `FieldLikeButton`,
|
|
173
|
-
`FieldRadios`, `FieldSwitch`, `FieldOptions`, `FieldDate`, `FieldDateRange`,
|
|
174
|
-
`Switch`:
|
|
175
|
+
`FieldRadios`, `FieldSwitch`, `FieldColorPicker`, `FieldOptions`, `FieldDate`, `FieldDateRange`,
|
|
176
|
+
`Switch`, and `ColorPicker`:
|
|
175
177
|
|
|
176
178
|
| Method | Returns | Purpose |
|
|
177
179
|
| ----------------------- | ------------------------------- | ------------------------------------------------------------- |
|
|
@@ -928,7 +930,9 @@ Swatch values are **never parsed** — they go to CSS as `--stuic-color-picker-s
|
|
|
928
930
|
| `onchange` | `(value: string) => void` | — | User **commits** only (see below) |
|
|
929
931
|
| `t` | `TranslateFn` | English | Group label, swatch names, "no color", custom-color labels, required message |
|
|
930
932
|
|
|
931
|
-
Class slots: `class`, `classSwatch`.
|
|
933
|
+
Class slots: `class`, `classSwatch`. `labelledby` (an element id) names the swatch group via `aria-labelledby` instead of `label`'s `aria-label`.
|
|
934
|
+
|
|
935
|
+
**In a form layout** use `FieldColorPicker` (exported from `Input`): the same `InputWrap` shell as every `Field*` (visible label, description, validation box, `labelLeft*`, `InputWrapClassProps`), with the picker props forwarded. The visible label names the radiogroup via `labelledby`; `focus()` / `scrollIntoView()` join the imperative API so `scrollToFirstInvalidField` works. The Input stylesheet exempts inputs inside `.stuic-color-picker` from its field-input rules (`:where(:not(.stuic-color-picker *))`, zero specificity) — otherwise the hex field and native picker would lose their border, font and size inside the shell.
|
|
932
936
|
|
|
933
937
|
### Preview vs commit
|
|
934
938
|
|
|
@@ -1352,6 +1356,62 @@ Prefix: `--stuic-stepper-*`
|
|
|
1352
1356
|
|
|
1353
1357
|
---
|
|
1354
1358
|
|
|
1359
|
+
## Gantt
|
|
1360
|
+
|
|
1361
|
+
Horizontal schedule chart — the classic project plan (task per row, progress, milestones) and the resource lane view (many bars per row) in one component. Whole-day, inclusive-at-both-ends ranges throughout (`YYYY-MM-DD`, or a `Date` read as its local calendar date), so no timezone can shift a bar by a day. Columns are days, weeks or months; `week`/`month` snap the window outwards to whole units, and bars are positioned _through_ the columns, so an equal-width February column still holds 28 days. Read-only by design: no drag-to-reschedule, no dependency arrows (use `Timeline` for a vertical event list).
|
|
1362
|
+
|
|
1363
|
+
Layout is one scroll container holding a sticky two-tier header (groups over units), a sticky left label column and, for the body, a **single** absolutely-positioned grid layer (gridlines + weekend shading + today line) rather than a cell per row per column. The frame always fills its parent and `unitWidth` is a _minimum_: a narrow axis shares the spare width between its columns (no dead gutter, and the grid layer keeps matching the track because both grow by the same rule), a wide one scrolls. `unitWidth="fit"` drops the minimum so the chart never scrolls sideways. The track is `overflow: clip`, so a label positioned past its bar cannot put a scrollbar on a chart that fits.
|
|
1364
|
+
|
|
1365
|
+
### Exports
|
|
1366
|
+
|
|
1367
|
+
| Export | Kind | Description |
|
|
1368
|
+
| ------------------- | --------- | ------------------------------------------------------------------------------------------------------------- |
|
|
1369
|
+
| `Gantt` | component | Main component |
|
|
1370
|
+
| `GanttProps` | type | Props type |
|
|
1371
|
+
| `GanttRow` | type | `{ id?, label?, description?, bars, href?, data? }` |
|
|
1372
|
+
| `GanttBar` | type | `{ from, to?, label?, intent?, progress?, milestone?, inset?, href?, title?, disabled?, id?, class?, data? }` |
|
|
1373
|
+
| `GanttBarLabels` | type | `"inside" \| "after" \| "none"` |
|
|
1374
|
+
| `GanttSelectDetail` | type | `{ bar, row, rowIndex, barIndex, placement, point }` — `onSelect` / `renderBar` |
|
|
1375
|
+
| `GanttUnit` | type | `"day" \| "week" \| "month"` |
|
|
1376
|
+
| `GanttAxis` | type | `{ unit, from, to, start, end, columns, groups, totalDays }` |
|
|
1377
|
+
| `GanttColumn` | type | `{ date, days, offset, index, label, subLabel?, groupIndex, isWeekend, isToday }` |
|
|
1378
|
+
| `GanttGroup` | type | `{ key, label, span, from }` — a header group cell |
|
|
1379
|
+
| `GanttPlacement` | type | `{ start, end, clippedStart, clippedEnd, days }` — 0..1 track fractions |
|
|
1380
|
+
| `GanttDateInput` | type | `IsoDate \| Date` |
|
|
1381
|
+
| `GanttAxisOptions` | type | `{ unit?, weekStartsOn?, locale?, today? }` |
|
|
1382
|
+
| `buildGanttAxis` | function | `(from, to, options) => GanttAxis` — throws on a bad or too-wide window |
|
|
1383
|
+
| `placeRange` | function | `(from, to, axis) => GanttPlacement \| null` (`null` = misses the window) |
|
|
1384
|
+
| `placePoint` | function | `(date, axis) => number \| null` — the middle of that day, 0..1 |
|
|
1385
|
+
| `dayToFraction` | function | `(dayOffset, axis) => number` — column-aware, so month widths stay equal |
|
|
1386
|
+
| `boundsOf` | function | `(ranges) => { from, to } \| null` — the default window |
|
|
1387
|
+
| `isoWeekNumber` | function | `(iso) => number` — ISO-8601 week, used for the week header |
|
|
1388
|
+
| `GANTT_MAX_COLUMNS` | const | `2000` — over this `buildGanttAxis` throws instead of building the nodes |
|
|
1389
|
+
|
|
1390
|
+
### Key Props
|
|
1391
|
+
|
|
1392
|
+
| Prop | Type | Default | Description |
|
|
1393
|
+
| ------------- | ----------------------------- | ---------- | ----------------------------------------------------------- |
|
|
1394
|
+
| `rows` | `GanttRow[]` | required | The lanes, in display order |
|
|
1395
|
+
| `from` / `to` | `IsoDate \| Date` | bar extent | The window, inclusive at both ends |
|
|
1396
|
+
| `unit` | `GanttUnit` | `"day"` | Column granularity |
|
|
1397
|
+
| `unitWidth` | `number \| "fit"` | token | **Minimum** column px (the zoom); `"fit"` drops the minimum |
|
|
1398
|
+
| `today` | `IsoDate \| Date \| null` | today | The marker line's day; `null` removes it |
|
|
1399
|
+
| `labels` | `boolean` | auto | Left label column — on when any row has a `label` |
|
|
1400
|
+
| `barLabels` | `GanttBarLabels` | `"inside"` | Where a bar's own label is drawn |
|
|
1401
|
+
| `onSelect` | `(GanttSelectDetail) => void` | — | Bar click; also what turns bars into focusable `<button>`s |
|
|
1402
|
+
|
|
1403
|
+
Also `weekStartsOn`, `locale`, `formatColumn`, `formatGroup`, `formatBarAria`. Snippets: `renderBar`, `renderRowLabel`, `renderCorner`, `empty`. Class slots: `class`, `classHeader`, `classRow`, `classRowLabel`, `classTrack`, `classBar`.
|
|
1404
|
+
|
|
1405
|
+
A bar entirely outside the window is dropped (a hairline at the edge reads as "starts today"); one that overhangs is clipped and flagged `data-clipped-start` / `data-clipped-end`. `data-*` attributes survive `unstyled` — they describe the data, not the styling.
|
|
1406
|
+
|
|
1407
|
+
### CSS Tokens
|
|
1408
|
+
|
|
1409
|
+
Prefix: `--stuic-gantt-*`
|
|
1410
|
+
|
|
1411
|
+
`unit-width`, `label-width`, `row-height`, `max-height`, `bg`, `border-color`, `font-size`, `header-{bg,text,font-size,padding,sub-text}`, `grid-line-color`, `weekend-bg`, `today-color`, `today-width`, `row-bg-hover`, `label-{bg,padding,font-size,text}`, `description-{font-size,text}`, `bar-{height,height-inset,bg,text,font-size,padding-inline,progress-bg,opacity-disabled,radius}`, `milestone-{size,radius}`, `empty-padding`, `radius`, `border-width`, `transition`
|
|
1412
|
+
|
|
1413
|
+
---
|
|
1414
|
+
|
|
1355
1415
|
## Timeline
|
|
1356
1416
|
|
|
1357
1417
|
Vertical event list with markers on a rail — activity feeds, audit logs, order tracking, history pages. A real `<ol>` (explicit `role="list"`); every item has a marker (small dot, icon bubble when `item.icon` is set, or anything via `renderMarker`), an optional time label, title, description and footer. Data-driven (`items`), static by design — no "current" step (use `Stepper` vertical for progress flows). The list is a CSS grid with `subgrid` items, so the rail and the optional time column align across items without fixed widths; the rail line runs behind the markers and a background-colored ring separates them.
|