@streamscloud/kit 0.21.1 → 0.22.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/dist/ui/date-picker/cmp.date-picker.svelte +7 -0
- package/dist/ui/date-picker/cmp.date-picker.svelte.d.ts +1 -0
- package/dist/ui/date-picker/cmp.date-time-picker.svelte +65 -0
- package/dist/ui/date-picker/cmp.date-time-picker.svelte.d.ts +28 -0
- package/dist/ui/date-picker/cmp.time-picker.svelte +88 -0
- package/dist/ui/date-picker/cmp.time-picker.svelte.d.ts +50 -0
- package/dist/ui/date-picker/index.d.ts +2 -0
- package/dist/ui/date-picker/index.js +2 -0
- package/dist/ui/select/cmp.multiselect.svelte.d.ts +1 -1
- package/package.json +1 -1
|
@@ -186,6 +186,7 @@ DatePicker — single-day calendar picker built on Floating UI for positioning.
|
|
|
186
186
|
| `--sc-kit--date-picker--background` | Trigger background | `var(--sc-kit--color--bg--field)` |
|
|
187
187
|
| `--sc-kit--date-picker--background--disabled` | Trigger background when disabled | `var(--sc-kit--color--bg--field-alt)` |
|
|
188
188
|
| `--sc-kit--date-picker--border-color` | Trigger border color | `var(--sc-kit--color--border--field)` |
|
|
189
|
+
| `--sc-kit--date-picker--border-color--hover` | Trigger border color on hover | `var(--sc-kit--color--border--strong)` |
|
|
189
190
|
| `--sc-kit--date-picker--border-color--error` | Trigger border color in error state | `var(--sc-kit--color--danger)` |
|
|
190
191
|
| `--sc-kit--date-picker--border-radius` | Trigger border radius | per size — `sm` 4px, `md`/`lg` 6px |
|
|
191
192
|
| `--sc-kit--date-picker--underline-color` | Inset bottom-underline indicator (transparent default, accent when open, danger on error) | `transparent` |
|
|
@@ -206,6 +207,7 @@ DatePicker — single-day calendar picker built on Floating UI for positioning.
|
|
|
206
207
|
--_dp--background: var(--sc-kit--date-picker--background, var(--sc-kit--color--bg--field));
|
|
207
208
|
--_dp--background-disabled: var(--sc-kit--date-picker--background--disabled, var(--sc-kit--color--bg--field-alt));
|
|
208
209
|
--_dp--border-color: var(--sc-kit--date-picker--border-color, var(--sc-kit--color--border--field));
|
|
210
|
+
--_dp--border-color-hover: var(--sc-kit--date-picker--border-color--hover, var(--sc-kit--color--border--strong));
|
|
209
211
|
--_dp--border-color-error: var(--sc-kit--date-picker--border-color--error, var(--sc-kit--color--danger));
|
|
210
212
|
--_dp--border-radius: var(--sc-kit--date-picker--border-radius, var(--_dp--size-border-radius, var(--sc-kit--field--border-radius--md)));
|
|
211
213
|
--_dp--underline-color: var(--sc-kit--date-picker--underline-color, transparent);
|
|
@@ -252,7 +254,11 @@ DatePicker — single-day calendar picker built on Floating UI for positioning.
|
|
|
252
254
|
--_dp--size-icon-size: var(--sc-kit--field--icon--size--lg);
|
|
253
255
|
--_dp--size-border-radius: var(--sc-kit--field--border-radius--md);
|
|
254
256
|
}
|
|
257
|
+
.date-picker:where(:hover:not(:focus-within)) {
|
|
258
|
+
--sc-kit--date-picker--border-color: var(--_dp--border-color-hover);
|
|
259
|
+
}
|
|
255
260
|
.date-picker--open {
|
|
261
|
+
--sc-kit--date-picker--border-color: unset;
|
|
256
262
|
--sc-kit--date-picker--underline-color: var(--sc-kit--color--accent);
|
|
257
263
|
}
|
|
258
264
|
.date-picker--error {
|
|
@@ -260,6 +266,7 @@ DatePicker — single-day calendar picker built on Floating UI for positioning.
|
|
|
260
266
|
--sc-kit--date-picker--underline-color: var(--sc-kit--color--danger);
|
|
261
267
|
}
|
|
262
268
|
.date-picker--disabled, .date-picker--readonly, .date-picker--inert {
|
|
269
|
+
--sc-kit--date-picker--border-color: unset;
|
|
263
270
|
--sc-kit--date-picker--underline-color: unset;
|
|
264
271
|
--_--input-affordance--opacity: 0;
|
|
265
272
|
--_--input-affordance--scale: 0;
|
|
@@ -68,6 +68,7 @@ type Props = ClearableProps | RequiredProps;
|
|
|
68
68
|
* | `--sc-kit--date-picker--background` | Trigger background | `var(--sc-kit--color--bg--field)` |
|
|
69
69
|
* | `--sc-kit--date-picker--background--disabled` | Trigger background when disabled | `var(--sc-kit--color--bg--field-alt)` |
|
|
70
70
|
* | `--sc-kit--date-picker--border-color` | Trigger border color | `var(--sc-kit--color--border--field)` |
|
|
71
|
+
* | `--sc-kit--date-picker--border-color--hover` | Trigger border color on hover | `var(--sc-kit--color--border--strong)` |
|
|
71
72
|
* | `--sc-kit--date-picker--border-color--error` | Trigger border color in error state | `var(--sc-kit--color--danger)` |
|
|
72
73
|
* | `--sc-kit--date-picker--border-radius` | Trigger border radius | per size — `sm` 4px, `md`/`lg` 6px |
|
|
73
74
|
* | `--sc-kit--date-picker--underline-color` | Inset bottom-underline indicator (transparent default, accent when open, danger on error) | `transparent` |
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script lang="ts">import DatePicker from './cmp.date-picker.svelte';
|
|
2
|
+
import TimePicker from './cmp.time-picker.svelte';
|
|
3
|
+
const { value, size = 'md', datePlaceholder = '', min, step = 30, on } = $props();
|
|
4
|
+
const DEFAULT_TIME = '12:00';
|
|
5
|
+
const pad = (n) => n.toString().padStart(2, '0');
|
|
6
|
+
const toTimeValue = (date) => `${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
7
|
+
const currentDate = $derived(value ? new Date(value) : null);
|
|
8
|
+
const timeValue = $derived(currentDate ? toTimeValue(currentDate) : DEFAULT_TIME);
|
|
9
|
+
const onDateChange = (next) => {
|
|
10
|
+
if (!next) {
|
|
11
|
+
on?.change?.(null);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const picked = new Date(next);
|
|
15
|
+
const combined = new Date(currentDate ?? picked);
|
|
16
|
+
if (!currentDate) {
|
|
17
|
+
const [hours, minutes] = DEFAULT_TIME.split(':').map(Number);
|
|
18
|
+
combined.setHours(hours, minutes, 0, 0);
|
|
19
|
+
}
|
|
20
|
+
combined.setFullYear(picked.getFullYear(), picked.getMonth(), picked.getDate());
|
|
21
|
+
on?.change?.(combined.toISOString());
|
|
22
|
+
};
|
|
23
|
+
const onTimeChange = (next) => {
|
|
24
|
+
if (!currentDate) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const [hours, minutes] = next.split(':').map(Number);
|
|
28
|
+
const combined = new Date(currentDate);
|
|
29
|
+
combined.setHours(hours, minutes, 0, 0);
|
|
30
|
+
on?.change?.(combined.toISOString());
|
|
31
|
+
};
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<div class="date-time" class:date-time--date-only={!currentDate}>
|
|
35
|
+
<DatePicker clearable size={size} value={value} placeholder={datePlaceholder} min={min} on={{ change: onDateChange }} />
|
|
36
|
+
{#if currentDate}
|
|
37
|
+
<TimePicker clearable={false} size={size} step={step} value={timeValue} on={{ change: onTimeChange }} />
|
|
38
|
+
{/if}
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<!--
|
|
42
|
+
@component
|
|
43
|
+
DateTimePicker — composes `DatePicker` + `TimePicker` into one ISO date-time field. The time row appears
|
|
44
|
+
only once a date is picked (defaulting to `12:00`); `size` and `step` thread down to both controls.
|
|
45
|
+
Emits an ISO 8601 string — or `null` when the date is cleared — via `on.change`.
|
|
46
|
+
|
|
47
|
+
### CSS Custom Properties
|
|
48
|
+
| Property | Description | Default |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `--sc-kit--date-time-picker--time-width` | Width of the time column | `6rem` |
|
|
51
|
+
| `--sc-kit--date-time-picker--gap` | Gap between the date and time fields | `var(--sc-kit--space--2)` |
|
|
52
|
+
-->
|
|
53
|
+
|
|
54
|
+
<style>.date-time {
|
|
55
|
+
--_dtp--time-width: var(--sc-kit--date-time-picker--time-width, 6rem);
|
|
56
|
+
--_dtp--gap: var(--sc-kit--date-time-picker--gap, var(--sc-kit--space--2));
|
|
57
|
+
display: grid;
|
|
58
|
+
grid-template-columns: minmax(0, 1fr) var(--_dtp--time-width);
|
|
59
|
+
gap: var(--_dtp--gap);
|
|
60
|
+
width: 100%;
|
|
61
|
+
max-width: 100%;
|
|
62
|
+
}
|
|
63
|
+
.date-time--date-only {
|
|
64
|
+
grid-template-columns: minmax(0, 1fr);
|
|
65
|
+
}</style>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { LikeDate } from './types';
|
|
2
|
+
type Props = {
|
|
3
|
+
value: string | null;
|
|
4
|
+
/** @default 'md' */
|
|
5
|
+
size?: 'sm' | 'md' | 'lg';
|
|
6
|
+
datePlaceholder?: string;
|
|
7
|
+
/** Earliest selectable date (inclusive). */
|
|
8
|
+
min?: LikeDate;
|
|
9
|
+
/** Minute interval for the time list. @default 30 */
|
|
10
|
+
step?: number;
|
|
11
|
+
on?: {
|
|
12
|
+
change?: (value: string | null) => void;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* DateTimePicker — composes `DatePicker` + `TimePicker` into one ISO date-time field. The time row appears
|
|
17
|
+
* only once a date is picked (defaulting to `12:00`); `size` and `step` thread down to both controls.
|
|
18
|
+
* Emits an ISO 8601 string — or `null` when the date is cleared — via `on.change`.
|
|
19
|
+
*
|
|
20
|
+
* ### CSS Custom Properties
|
|
21
|
+
* | Property | Description | Default |
|
|
22
|
+
* |---|---|---|
|
|
23
|
+
* | `--sc-kit--date-time-picker--time-width` | Width of the time column | `6rem` |
|
|
24
|
+
* | `--sc-kit--date-time-picker--gap` | Gap between the date and time fields | `var(--sc-kit--space--2)` |
|
|
25
|
+
*/
|
|
26
|
+
declare const Cmp: import("svelte").Component<Props, {}, "">;
|
|
27
|
+
type Cmp = ReturnType<typeof Cmp>;
|
|
28
|
+
export default Cmp;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<script lang="ts">import { Singleselect } from '../select';
|
|
2
|
+
const { size = 'md', step = 30, placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, id, name, 'aria-label': ariaLabel, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, ...mode } = $props();
|
|
3
|
+
const MINUTES_PER_DAY = 24 * 60;
|
|
4
|
+
const pad = (n) => n.toString().padStart(2, '0');
|
|
5
|
+
const stepOptions = $derived.by(() => {
|
|
6
|
+
const count = Math.max(1, Math.floor(MINUTES_PER_DAY / step));
|
|
7
|
+
return Array.from({ length: count }, (_, i) => {
|
|
8
|
+
const total = i * step;
|
|
9
|
+
const label = `${pad(Math.floor(total / 60))}:${pad(total % 60)}`;
|
|
10
|
+
return { label, value: label };
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
const options = $derived.by(() => {
|
|
14
|
+
const current = mode.value;
|
|
15
|
+
if (current && !stepOptions.some((option) => option.value === current)) {
|
|
16
|
+
return [...stepOptions, { label: current, value: current }].sort((a, b) => a.value.localeCompare(b.value));
|
|
17
|
+
}
|
|
18
|
+
return stepOptions;
|
|
19
|
+
});
|
|
20
|
+
const emit = (next) => {
|
|
21
|
+
if (mode.clearable) {
|
|
22
|
+
mode.on?.change?.(next);
|
|
23
|
+
}
|
|
24
|
+
else if (next !== null) {
|
|
25
|
+
mode.on?.change?.(next);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<div class="time-picker">
|
|
31
|
+
{#if mode.clearable}
|
|
32
|
+
<Singleselect
|
|
33
|
+
clearable
|
|
34
|
+
value={mode.value}
|
|
35
|
+
options={options}
|
|
36
|
+
size={size}
|
|
37
|
+
placeholder={placeholder}
|
|
38
|
+
disabled={disabled}
|
|
39
|
+
readonly={readonly}
|
|
40
|
+
inert={inert}
|
|
41
|
+
error={error}
|
|
42
|
+
borderless={borderless}
|
|
43
|
+
id={id}
|
|
44
|
+
name={name}
|
|
45
|
+
aria-label={ariaLabel}
|
|
46
|
+
aria-describedby={ariaDescribedby}
|
|
47
|
+
aria-required={ariaRequired}
|
|
48
|
+
on={{ change: emit }} />
|
|
49
|
+
{:else}
|
|
50
|
+
<Singleselect
|
|
51
|
+
clearable={false}
|
|
52
|
+
value={mode.value}
|
|
53
|
+
options={options}
|
|
54
|
+
size={size}
|
|
55
|
+
placeholder={placeholder}
|
|
56
|
+
disabled={disabled}
|
|
57
|
+
readonly={readonly}
|
|
58
|
+
inert={inert}
|
|
59
|
+
error={error}
|
|
60
|
+
borderless={borderless}
|
|
61
|
+
id={id}
|
|
62
|
+
name={name}
|
|
63
|
+
aria-label={ariaLabel}
|
|
64
|
+
aria-describedby={ariaDescribedby}
|
|
65
|
+
aria-required={ariaRequired}
|
|
66
|
+
on={{ change: emit }} />
|
|
67
|
+
{/if}
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<!--
|
|
71
|
+
@component
|
|
72
|
+
TimePicker — an `'HH:mm'` (24-hour) time field built on `Singleselect` over a time grid generated from
|
|
73
|
+
`step` (minutes). Discriminated by `clearable`: `true` allows clearing to `null` and shows an X button;
|
|
74
|
+
`false` requires a value. An out-of-grid `value` is injected into the list so it always renders. Emits
|
|
75
|
+
the picked `'HH:mm'` string via `on.change`.
|
|
76
|
+
|
|
77
|
+
### CSS Custom Properties
|
|
78
|
+
| Property | Description | Default |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `--sc-kit--time-picker--width` | Field width | `100%` |
|
|
81
|
+
-->
|
|
82
|
+
|
|
83
|
+
<style>.time-picker {
|
|
84
|
+
--_tp--width: var(--sc-kit--time-picker--width, 100%);
|
|
85
|
+
display: flex;
|
|
86
|
+
width: var(--_tp--width);
|
|
87
|
+
max-width: 100%;
|
|
88
|
+
}</style>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
type BaseProps = {
|
|
2
|
+
/** @default 'md' */
|
|
3
|
+
size?: 'sm' | 'md' | 'lg';
|
|
4
|
+
/** Minute interval between generated options. @default 30 */
|
|
5
|
+
step?: number;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
/** Focusable, value visible, but selection cannot change. */
|
|
9
|
+
readonly?: boolean;
|
|
10
|
+
/** Non-interactive, unstyled view-only mode. */
|
|
11
|
+
inert?: boolean;
|
|
12
|
+
error?: boolean;
|
|
13
|
+
borderless?: boolean;
|
|
14
|
+
id?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
'aria-label'?: string;
|
|
17
|
+
'aria-describedby'?: string;
|
|
18
|
+
'aria-required'?: boolean;
|
|
19
|
+
};
|
|
20
|
+
type ClearableProps = BaseProps & {
|
|
21
|
+
/** Value can be cleared to `null`; shows a clear (X) button when set. */
|
|
22
|
+
clearable: true;
|
|
23
|
+
value: string | null | undefined;
|
|
24
|
+
on?: {
|
|
25
|
+
change?: (value: string | null) => void;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
type RequiredProps = BaseProps & {
|
|
29
|
+
/** Value is required. No clear button. */
|
|
30
|
+
clearable: false;
|
|
31
|
+
value: string;
|
|
32
|
+
on?: {
|
|
33
|
+
change?: (value: string) => void;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
type Props = ClearableProps | RequiredProps;
|
|
37
|
+
/**
|
|
38
|
+
* TimePicker — an `'HH:mm'` (24-hour) time field built on `Singleselect` over a time grid generated from
|
|
39
|
+
* `step` (minutes). Discriminated by `clearable`: `true` allows clearing to `null` and shows an X button;
|
|
40
|
+
* `false` requires a value. An out-of-grid `value` is injected into the list so it always renders. Emits
|
|
41
|
+
* the picked `'HH:mm'` string via `on.change`.
|
|
42
|
+
*
|
|
43
|
+
* ### CSS Custom Properties
|
|
44
|
+
* | Property | Description | Default |
|
|
45
|
+
* |---|---|---|
|
|
46
|
+
* | `--sc-kit--time-picker--width` | Field width | `100%` |
|
|
47
|
+
*/
|
|
48
|
+
declare const Cmp: import("svelte").Component<Props, {}, "">;
|
|
49
|
+
type Cmp = ReturnType<typeof Cmp>;
|
|
50
|
+
export default Cmp;
|
|
@@ -5,7 +5,7 @@ export type MultiselectInstance = {
|
|
|
5
5
|
};
|
|
6
6
|
import { type MultiselectBaseProps, type SelectOption } from './types';
|
|
7
7
|
declare function $$render<T>(): {
|
|
8
|
-
props: Omit<MultiselectBaseProps<T>, "value" | "on" | "
|
|
8
|
+
props: Omit<MultiselectBaseProps<T>, "value" | "on" | "loadOptions" | "debounceMs" | "groupHeader" | "selectionMode" | "parentSource"> & {
|
|
9
9
|
/** Flat option list. Fuse filters in-memory on every keystroke — no debounce. */
|
|
10
10
|
options: SelectOption<T>[];
|
|
11
11
|
/** Current selection — array of values. Order is preserved (and editable when `reorderable`). */
|