@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.
@@ -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;
@@ -1,2 +1,4 @@
1
1
  export { default as DatePicker } from './cmp.date-picker.svelte';
2
+ export { default as DateTimePicker } from './cmp.date-time-picker.svelte';
3
+ export { default as TimePicker } from './cmp.time-picker.svelte';
2
4
  export type { LikeDate } from './types';
@@ -1 +1,3 @@
1
1
  export { default as DatePicker } from './cmp.date-picker.svelte';
2
+ export { default as DateTimePicker } from './cmp.date-time-picker.svelte';
3
+ export { default as TimePicker } from './cmp.time-picker.svelte';
@@ -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" | "debounceMs" | "loadOptions" | "groupHeader" | "selectionMode" | "parentSource"> & {
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`). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.21.1",
3
+ "version": "0.22.0",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",