sh3-core 0.13.0 → 0.13.1

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.
@@ -15,6 +15,7 @@
15
15
  size = 'md',
16
16
  required = false,
17
17
  autocomplete,
18
+ onchange,
18
19
  }: {
19
20
  value?: string;
20
21
  type?: 'text' | 'email' | 'password' | 'search' | 'url' | 'tel';
@@ -29,6 +30,7 @@
29
30
  size?: 'sm' | 'md';
30
31
  required?: boolean;
31
32
  autocomplete?: AutoFill;
33
+ onchange?: (next: string) => void;
32
34
  } = $props();
33
35
 
34
36
  const showError = $derived(invalid && !!error);
@@ -48,6 +50,7 @@
48
50
  {autocomplete}
49
51
  aria-invalid={invalid || undefined}
50
52
  bind:value
53
+ onblur={() => onchange?.(value)}
51
54
  />
52
55
  {#if suffix}<span class="sh3-field__affix">{@render suffix()}</span>{/if}
53
56
  </span>
@@ -13,6 +13,7 @@ type $$ComponentProps = {
13
13
  size?: 'sm' | 'md';
14
14
  required?: boolean;
15
15
  autocomplete?: AutoFill;
16
+ onchange?: (next: string) => void;
16
17
  };
17
18
  declare const Field: import("svelte").Component<$$ComponentProps, {}, "value">;
18
19
  type Field = ReturnType<typeof Field>;
@@ -9,6 +9,7 @@
9
9
  invalid = false,
10
10
  size = 'md',
11
11
  buttonLabel = 'Choose file...',
12
+ onchange,
12
13
  }: {
13
14
  value?: FilePickerValue;
14
15
  multiple?: boolean;
@@ -17,11 +18,13 @@
17
18
  invalid?: boolean;
18
19
  size?: 'sm' | 'md';
19
20
  buttonLabel?: string;
21
+ onchange?: (next: FilePickerValue) => void;
20
22
  } = $props();
21
23
 
22
- function onChange(e: Event) {
24
+ function onPick(e: Event) {
23
25
  const target = e.currentTarget as HTMLInputElement;
24
26
  value = extractValue(target.files, multiple);
27
+ onchange?.(value);
25
28
  }
26
29
 
27
30
  const display = $derived(displayName(value));
@@ -34,7 +37,7 @@
34
37
  {accept}
35
38
  {multiple}
36
39
  {disabled}
37
- onchange={onChange}
40
+ onchange={onPick}
38
41
  />
39
42
  <span class="sh3-fp__btn" tabindex="-1">{buttonLabel}</span>
40
43
  <span class="sh3-fp__name">{display || 'no file'}</span>
@@ -7,6 +7,7 @@ type $$ComponentProps = {
7
7
  invalid?: boolean;
8
8
  size?: 'sm' | 'md';
9
9
  buttonLabel?: string;
10
+ onchange?: (next: FilePickerValue) => void;
10
11
  };
11
12
  declare const FilePicker: import("svelte").Component<$$ComponentProps, {}, "value">;
12
13
  type FilePicker = ReturnType<typeof FilePicker>;
@@ -10,12 +10,14 @@
10
10
  multiple = false,
11
11
  disabled = false,
12
12
  size = 'md',
13
+ onchange,
13
14
  }: {
14
15
  options: Option[];
15
16
  value: string | string[];
16
17
  multiple?: boolean;
17
18
  disabled?: boolean;
18
19
  size?: 'sm' | 'md';
20
+ onchange?: (next: string | string[]) => void;
19
21
  } = $props();
20
22
 
21
23
  function isActive(v: string): boolean {
@@ -31,6 +33,7 @@
31
33
  } else {
32
34
  value = toggleSingle(typeof value === 'string' ? value : '', v);
33
35
  }
36
+ onchange?.(value);
34
37
  }
35
38
  </script>
36
39
 
@@ -10,6 +10,7 @@ type $$ComponentProps = {
10
10
  multiple?: boolean;
11
11
  disabled?: boolean;
12
12
  size?: 'sm' | 'md';
13
+ onchange?: (next: string | string[]) => void;
13
14
  };
14
15
  declare const IconToggleGroup: import("svelte").Component<$$ComponentProps, {}, "value">;
15
16
  type IconToggleGroup = ReturnType<typeof IconToggleGroup>;
@@ -14,6 +14,7 @@
14
14
  disabled = false,
15
15
  invalid = false,
16
16
  size = 'md',
17
+ onchange,
17
18
  }: {
18
19
  value?: number;
19
20
  min?: number;
@@ -26,6 +27,7 @@
26
27
  disabled?: boolean;
27
28
  invalid?: boolean;
28
29
  size?: 'sm' | 'md';
30
+ onchange?: (next: number) => void;
29
31
  } = $props();
30
32
 
31
33
  const display = $derived(formatNumber(value, precision));
@@ -41,8 +43,10 @@
41
43
 
42
44
  let holdTimer: ReturnType<typeof setTimeout> | null = null;
43
45
  let holdInterval: ReturnType<typeof setInterval> | null = null;
46
+ let bumping = false;
44
47
  function startHold(direction: 1 | -1) {
45
48
  if (disabled) return;
49
+ bumping = true;
46
50
  bump(direction);
47
51
  holdTimer = setTimeout(() => {
48
52
  let elapsed = 0;
@@ -59,6 +63,10 @@
59
63
  function stopHold() {
60
64
  if (holdTimer) { clearTimeout(holdTimer); holdTimer = null; }
61
65
  if (holdInterval) { clearInterval(holdInterval); holdInterval = null; }
66
+ if (bumping) {
67
+ bumping = false;
68
+ onchange?.(value);
69
+ }
62
70
  }
63
71
  </script>
64
72
 
@@ -76,6 +84,7 @@
76
84
  aria-invalid={invalid || undefined}
77
85
  value={display}
78
86
  oninput={(e) => commit(parseFloat((e.currentTarget as HTMLInputElement).value))}
87
+ onblur={() => onchange?.(value)}
79
88
  />
80
89
  {#if suffix}<span class="sh3-num__affix">{@render suffix()}</span>{/if}
81
90
  <span class="sh3-num__steppers">
@@ -11,6 +11,7 @@ type $$ComponentProps = {
11
11
  disabled?: boolean;
12
12
  invalid?: boolean;
13
13
  size?: 'sm' | 'md';
14
+ onchange?: (next: number) => void;
14
15
  };
15
16
  declare const NumberInput: import("svelte").Component<$$ComponentProps, {}, "value">;
16
17
  type NumberInput = ReturnType<typeof NumberInput>;
@@ -10,6 +10,7 @@
10
10
  disabled = false,
11
11
  invalid = false,
12
12
  size = 'md',
13
+ onchange,
13
14
  }: {
14
15
  value?: Pair;
15
16
  min?: number;
@@ -18,6 +19,7 @@
18
19
  disabled?: boolean;
19
20
  invalid?: boolean;
20
21
  size?: 'sm' | 'md';
22
+ onchange?: (next: Pair) => void;
21
23
  } = $props();
22
24
 
23
25
  const lowPct = $derived(valueToPercent(value[0], min, max));
@@ -36,11 +38,13 @@
36
38
  <input type="range" class="sh3-range__native sh3-range__native--low"
37
39
  {min} {max} {step} {disabled}
38
40
  value={value[0]}
39
- oninput={(e) => setLow(parseFloat((e.currentTarget as HTMLInputElement).value))} />
41
+ oninput={(e) => setLow(parseFloat((e.currentTarget as HTMLInputElement).value))}
42
+ onchange={() => onchange?.(value)} />
40
43
  <input type="range" class="sh3-range__native sh3-range__native--high"
41
44
  {min} {max} {step} {disabled}
42
45
  value={value[1]}
43
- oninput={(e) => setHigh(parseFloat((e.currentTarget as HTMLInputElement).value))} />
46
+ oninput={(e) => setHigh(parseFloat((e.currentTarget as HTMLInputElement).value))}
47
+ onchange={() => onchange?.(value)} />
44
48
  </div>
45
49
 
46
50
  <style>
@@ -7,6 +7,7 @@ type $$ComponentProps = {
7
7
  disabled?: boolean;
8
8
  invalid?: boolean;
9
9
  size?: 'sm' | 'md';
10
+ onchange?: (next: Pair) => void;
10
11
  };
11
12
  declare const RangeSlider: import("svelte").Component<$$ComponentProps, {}, "value">;
12
13
  type RangeSlider = ReturnType<typeof RangeSlider>;
@@ -6,13 +6,20 @@
6
6
  value = $bindable(),
7
7
  size = 'md',
8
8
  disabled = false,
9
+ onchange,
9
10
  }: {
10
11
  options: SegmentedOption[];
11
12
  value: string;
12
13
  size?: 'sm' | 'md';
13
14
  disabled?: boolean;
15
+ onchange?: (next: string) => void;
14
16
  } = $props();
15
17
 
18
+ function commit(next: string) {
19
+ value = next;
20
+ onchange?.(next);
21
+ }
22
+
16
23
  function onKey(e: KeyboardEvent) {
17
24
  if (disabled) return;
18
25
  let next: string | undefined;
@@ -24,7 +31,7 @@
24
31
  default: return;
25
32
  }
26
33
  e.preventDefault();
27
- if (next !== undefined) value = next;
34
+ if (next !== undefined) commit(next);
28
35
  }
29
36
  </script>
30
37
 
@@ -37,7 +44,7 @@
37
44
  tabindex={value === opt.value ? 0 : -1}
38
45
  disabled={disabled || opt.disabled}
39
46
  class:sh3-seg__btn--active={value === opt.value}
40
- onclick={() => { if (!opt.disabled && !disabled) value = opt.value; }}
47
+ onclick={() => { if (!opt.disabled && !disabled) commit(opt.value); }}
41
48
  >{opt.label}</button>
42
49
  {/each}
43
50
  </div>
@@ -4,6 +4,7 @@ type $$ComponentProps = {
4
4
  value: string;
5
5
  size?: 'sm' | 'md';
6
6
  disabled?: boolean;
7
+ onchange?: (next: string) => void;
7
8
  };
8
9
  declare const Segmented: import("svelte").Component<$$ComponentProps, {}, "value">;
9
10
  type Segmented = ReturnType<typeof Segmented>;
@@ -13,6 +13,7 @@
13
13
  disabled = false,
14
14
  invalid = false,
15
15
  size = 'md',
16
+ onchange,
16
17
  }: {
17
18
  options: SelectOption[];
18
19
  value?: string | string[];
@@ -22,6 +23,7 @@
22
23
  disabled?: boolean;
23
24
  invalid?: boolean;
24
25
  size?: 'sm' | 'md';
26
+ onchange?: (next: string | string[]) => void;
25
27
  } = $props();
26
28
 
27
29
  let trigger = $state<HTMLButtonElement | undefined>(undefined);
@@ -54,6 +56,7 @@
54
56
  } else {
55
57
  value = v;
56
58
  }
59
+ onchange?.(value);
57
60
  },
58
61
  // Listbox calls this on its own close paths (selection in
59
62
  // single mode, Escape inside the listbox). Outside-click and
@@ -90,6 +93,7 @@
90
93
  } else {
91
94
  value = nativeRef.value;
92
95
  }
96
+ onchange?.(value);
93
97
  }
94
98
  </script>
95
99
 
@@ -8,6 +8,7 @@ type $$ComponentProps = {
8
8
  disabled?: boolean;
9
9
  invalid?: boolean;
10
10
  size?: 'sm' | 'md';
11
+ onchange?: (next: string | string[]) => void;
11
12
  };
12
13
  declare const Select: import("svelte").Component<$$ComponentProps, {}, "value">;
13
14
  type Select = ReturnType<typeof Select>;
@@ -12,6 +12,7 @@
12
12
  invalid = false,
13
13
  size = 'md',
14
14
  orientation = 'horizontal',
15
+ onchange,
15
16
  }: {
16
17
  value?: number;
17
18
  min?: number;
@@ -23,6 +24,7 @@
23
24
  invalid?: boolean;
24
25
  size?: 'sm' | 'md';
25
26
  orientation?: 'horizontal' | 'vertical';
27
+ onchange?: (next: number) => void;
26
28
  } = $props();
27
29
 
28
30
  const pct = $derived(valueToPercent(value, min, max));
@@ -48,6 +50,7 @@
48
50
  {disabled}
49
51
  aria-invalid={invalid || undefined}
50
52
  bind:value
53
+ onchange={() => onchange?.(value)}
51
54
  />
52
55
  {#if showValue}
53
56
  <output class="sh3-slider__value" style:--pct="{pct}%">{value}</output>
@@ -9,6 +9,7 @@ type $$ComponentProps = {
9
9
  invalid?: boolean;
10
10
  size?: 'sm' | 'md';
11
11
  orientation?: 'horizontal' | 'vertical';
12
+ onchange?: (next: number) => void;
12
13
  };
13
14
  declare const Slider: import("svelte").Component<$$ComponentProps, {}, "value">;
14
15
  type Slider = ReturnType<typeof Slider>;
@@ -10,6 +10,7 @@
10
10
  showValues = false,
11
11
  disabled = false,
12
12
  size = 'md',
13
+ onchange,
13
14
  }: {
14
15
  orientation?: 'horizontal' | 'vertical';
15
16
  channels: Channel[];
@@ -17,6 +18,7 @@
17
18
  showValues?: boolean;
18
19
  disabled?: boolean;
19
20
  size?: 'sm' | 'md';
21
+ onchange?: (next: Record<string, number>) => void;
20
22
  } = $props();
21
23
  </script>
22
24
 
@@ -36,6 +38,7 @@
36
38
  () => values[ch.id] ?? 0,
37
39
  (n: number) => values = { ...values, [ch.id]: n }
38
40
  }
41
+ onchange={() => onchange?.(values)}
39
42
  />
40
43
  </div>
41
44
  {/each}
@@ -12,6 +12,7 @@ type $$ComponentProps = {
12
12
  showValues?: boolean;
13
13
  disabled?: boolean;
14
14
  size?: 'sm' | 'md';
15
+ onchange?: (next: Record<string, number>) => void;
15
16
  };
16
17
  declare const SliderGroup: import("svelte").Component<$$ComponentProps, {}, "values">;
17
18
  type SliderGroup = ReturnType<typeof SliderGroup>;
@@ -11,6 +11,7 @@
11
11
  required = false,
12
12
  rows = 3,
13
13
  resize = 'vertical',
14
+ onchange,
14
15
  }: {
15
16
  value?: string;
16
17
  label?: string;
@@ -23,6 +24,7 @@
23
24
  required?: boolean;
24
25
  rows?: number;
25
26
  resize?: 'none' | 'vertical' | 'both';
27
+ onchange?: (next: string) => void;
26
28
  } = $props();
27
29
 
28
30
  const showError = $derived(invalid && !!error);
@@ -40,6 +42,7 @@
40
42
  {rows}
41
43
  aria-invalid={invalid || undefined}
42
44
  bind:value
45
+ onblur={() => onchange?.(value)}
43
46
  ></textarea>
44
47
  {#if helperText}<span class="sh3-textarea__helper" class:sh3-textarea__helper--error={showError}>{helperText}</span>{/if}
45
48
  </label>
@@ -10,6 +10,7 @@ type $$ComponentProps = {
10
10
  required?: boolean;
11
11
  rows?: number;
12
12
  resize?: 'none' | 'vertical' | 'both';
13
+ onchange?: (next: string) => void;
13
14
  };
14
15
  declare const Textarea: import("svelte").Component<$$ComponentProps, {}, "value">;
15
16
  type Textarea = ReturnType<typeof Textarea>;
package/dist/tokens.css CHANGED
@@ -99,8 +99,10 @@
99
99
  --shell-track-border: var(--shell-border);
100
100
  --shell-track-fill: var(--shell-accent);
101
101
 
102
- /* Slider thumbs */
103
- --shell-thumb-bg: var(--shell-fg);
102
+ /* Slider thumbs — pinned to a fixed near-white instead of var(--shell-fg)
103
+ so light themes don't render a dark thumb. Themes that want a different
104
+ thumb override --shell-thumb-bg directly. */
105
+ --shell-thumb-bg: #e4e6eb;
104
106
  --shell-thumb-border: var(--shell-accent);
105
107
  --shell-thumb-shadow: var(--shell-shadow-sm);
106
108
 
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Auto-generated from package.json — do not edit manually. */
2
- export declare const VERSION = "0.13.0";
2
+ export declare const VERSION = "0.13.1";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Auto-generated from package.json — do not edit manually. */
2
- export const VERSION = '0.13.0';
2
+ export const VERSION = '0.13.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh3-core",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"