@w5-ui/svelte 0.1.0 → 0.2.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.
Files changed (191) hide show
  1. package/package.json +4 -4
  2. package/src/lib/components/Accordion.svelte +9 -1
  3. package/src/lib/components/AccordionItem.svelte +11 -5
  4. package/src/lib/components/ActionMenu.svelte +19 -14
  5. package/src/lib/components/ActivityFeed.svelte +24 -11
  6. package/src/lib/components/Alert.svelte +9 -4
  7. package/src/lib/components/AnnotatedTimeSeries.svelte +40 -26
  8. package/src/lib/components/ArcDiagram.svelte +20 -8
  9. package/src/lib/components/AreaChart.svelte +26 -14
  10. package/src/lib/components/Avatar.svelte +20 -8
  11. package/src/lib/components/AvatarGroup.svelte +16 -7
  12. package/src/lib/components/Badge.svelte +24 -11
  13. package/src/lib/components/Banner.svelte +20 -9
  14. package/src/lib/components/BarChart.svelte +29 -17
  15. package/src/lib/components/BeeswarmChart.svelte +32 -18
  16. package/src/lib/components/BoxPlot.svelte +27 -15
  17. package/src/lib/components/Breadcrumb.svelte +12 -7
  18. package/src/lib/components/BubbleChart.svelte +39 -25
  19. package/src/lib/components/BulletChart.svelte +16 -9
  20. package/src/lib/components/BumpChart.svelte +15 -8
  21. package/src/lib/components/Button.svelte +32 -11
  22. package/src/lib/components/CIDRInput.svelte +27 -19
  23. package/src/lib/components/CalendarHeatmap.svelte +12 -5
  24. package/src/lib/components/Callout.svelte +9 -4
  25. package/src/lib/components/CandlestickChart.svelte +31 -16
  26. package/src/lib/components/Card.svelte +16 -6
  27. package/src/lib/components/Carousel.svelte +14 -11
  28. package/src/lib/components/Checkbox.svelte +37 -16
  29. package/src/lib/components/ChordDiagram.svelte +12 -5
  30. package/src/lib/components/CirclePacking.svelte +13 -6
  31. package/src/lib/components/CodeBlock.svelte +16 -7
  32. package/src/lib/components/ColorPicker.svelte +22 -11
  33. package/src/lib/components/ColumnToggle.svelte +18 -11
  34. package/src/lib/components/Combobox.svelte +44 -33
  35. package/src/lib/components/CommandPalette.svelte +41 -31
  36. package/src/lib/components/ConfirmDialog.svelte +66 -35
  37. package/src/lib/components/ContextMenu.svelte +46 -33
  38. package/src/lib/components/ContextualHelp.svelte +13 -9
  39. package/src/lib/components/ContourPlot.svelte +43 -28
  40. package/src/lib/components/CopyButton.svelte +8 -4
  41. package/src/lib/components/CorrelationMatrix.svelte +16 -7
  42. package/src/lib/components/CountUp.svelte +30 -13
  43. package/src/lib/components/CumulativeDistribution.svelte +32 -19
  44. package/src/lib/components/DatePicker.svelte +28 -21
  45. package/src/lib/components/DateRangePicker.svelte +39 -32
  46. package/src/lib/components/Dendrogram.svelte +18 -6
  47. package/src/lib/components/Donut.svelte +28 -14
  48. package/src/lib/components/DotPlot.svelte +31 -16
  49. package/src/lib/components/Drawer.svelte +28 -21
  50. package/src/lib/components/DualAxisChart.svelte +39 -26
  51. package/src/lib/components/DumbbellChart.svelte +24 -12
  52. package/src/lib/components/DurationInput.svelte +26 -17
  53. package/src/lib/components/EmptyState.svelte +16 -6
  54. package/src/lib/components/ErrorBandChart.svelte +28 -14
  55. package/src/lib/components/ExpandableRow.svelte +19 -6
  56. package/src/lib/components/Field.svelte +26 -12
  57. package/src/lib/components/FileUpload.svelte +29 -20
  58. package/src/lib/components/FilterBuilder.svelte +27 -17
  59. package/src/lib/components/FlameGraph.svelte +14 -7
  60. package/src/lib/components/ForceGraph.svelte +19 -7
  61. package/src/lib/components/FunnelChart.svelte +20 -13
  62. package/src/lib/components/GanttChart.svelte +14 -7
  63. package/src/lib/components/Gauge.svelte +26 -16
  64. package/src/lib/components/GroupedList.svelte +13 -6
  65. package/src/lib/components/HealthBar.svelte +14 -5
  66. package/src/lib/components/HeatMap.svelte +28 -17
  67. package/src/lib/components/HexbinChart.svelte +36 -22
  68. package/src/lib/components/Histogram.svelte +27 -14
  69. package/src/lib/components/HorizonChart.svelte +28 -16
  70. package/src/lib/components/HoverCard.svelte +24 -12
  71. package/src/lib/components/IPInput.svelte +24 -16
  72. package/src/lib/components/IcicleChart.svelte +14 -7
  73. package/src/lib/components/IconButton.svelte +27 -9
  74. package/src/lib/components/InlineEdit.svelte +22 -12
  75. package/src/lib/components/Input.svelte +67 -10
  76. package/src/lib/components/InputGroup.svelte +8 -3
  77. package/src/lib/components/JsonViewer.svelte +17 -6
  78. package/src/lib/components/JsonViewerNode.svelte +36 -18
  79. package/src/lib/components/KVTable.svelte +6 -2
  80. package/src/lib/components/KanbanBoard.svelte +24 -17
  81. package/src/lib/components/Kbd.svelte +8 -4
  82. package/src/lib/components/LineChart.svelte +29 -17
  83. package/src/lib/components/LogViewer.svelte +27 -12
  84. package/src/lib/components/LollipopChart.svelte +20 -8
  85. package/src/lib/components/MACInput.svelte +24 -16
  86. package/src/lib/components/MarimekkoChart.svelte +14 -7
  87. package/src/lib/components/MatrixChart.svelte +19 -9
  88. package/src/lib/components/Menubar.svelte +26 -19
  89. package/src/lib/components/MirroredBarChart.svelte +25 -10
  90. package/src/lib/components/Modal.svelte +46 -33
  91. package/src/lib/components/MultiSelect.svelte +49 -38
  92. package/src/lib/components/NightingaleChart.svelte +17 -10
  93. package/src/lib/components/NotificationPanel.svelte +48 -33
  94. package/src/lib/components/NumberInput.svelte +37 -23
  95. package/src/lib/components/OTPInput.svelte +28 -16
  96. package/src/lib/components/Pagination.svelte +16 -13
  97. package/src/lib/components/ParallelCoordinates.svelte +28 -16
  98. package/src/lib/components/ParetoChart.svelte +38 -24
  99. package/src/lib/components/PasswordInput.svelte +24 -14
  100. package/src/lib/components/PieChart.svelte +21 -13
  101. package/src/lib/components/Pill.svelte +17 -6
  102. package/src/lib/components/PolarHeatmap.svelte +32 -18
  103. package/src/lib/components/Popover.svelte +22 -11
  104. package/src/lib/components/ProgressBar.svelte +17 -8
  105. package/src/lib/components/PunchCard.svelte +31 -20
  106. package/src/lib/components/QuadrantChart.svelte +50 -30
  107. package/src/lib/components/RadarChart.svelte +30 -18
  108. package/src/lib/components/RadialBarChart.svelte +14 -7
  109. package/src/lib/components/RadioGroup.svelte +20 -8
  110. package/src/lib/components/RangeSlider.svelte +30 -18
  111. package/src/lib/components/RankedList.svelte +18 -6
  112. package/src/lib/components/ResizablePanel.svelte +33 -17
  113. package/src/lib/components/RidgelinePlot.svelte +33 -21
  114. package/src/lib/components/RowToggle.svelte +15 -5
  115. package/src/lib/components/SankeyDiagram.svelte +18 -6
  116. package/src/lib/components/ScatterPlot.svelte +34 -21
  117. package/src/lib/components/SearchBox.svelte +27 -5
  118. package/src/lib/components/SegmentedControl.svelte +11 -7
  119. package/src/lib/components/Select.svelte +37 -26
  120. package/src/lib/components/SelectionToolbar.svelte +25 -11
  121. package/src/lib/components/Sidebar.svelte +15 -9
  122. package/src/lib/components/Signal.svelte +6 -2
  123. package/src/lib/components/Skeleton.svelte +20 -10
  124. package/src/lib/components/SkipLink.svelte +9 -4
  125. package/src/lib/components/Slider.svelte +28 -14
  126. package/src/lib/components/SlopeChart.svelte +35 -21
  127. package/src/lib/components/SortHeader.svelte +20 -9
  128. package/src/lib/components/SortableList.svelte +20 -13
  129. package/src/lib/components/Sparkline.svelte +15 -6
  130. package/src/lib/components/SparklineMatrix.svelte +17 -10
  131. package/src/lib/components/Spinner.svelte +7 -3
  132. package/src/lib/components/SplitButton.svelte +28 -17
  133. package/src/lib/components/Spoiler.svelte +22 -11
  134. package/src/lib/components/StackedBarChart.svelte +35 -22
  135. package/src/lib/components/StackedProgress.svelte +21 -9
  136. package/src/lib/components/StarRating.svelte +22 -11
  137. package/src/lib/components/Stat.svelte +32 -10
  138. package/src/lib/components/StatusIndicator.svelte +7 -3
  139. package/src/lib/components/StepChart.svelte +27 -15
  140. package/src/lib/components/Stepper.svelte +10 -6
  141. package/src/lib/components/StreamGraph.svelte +19 -12
  142. package/src/lib/components/StripeChart.svelte +22 -12
  143. package/src/lib/components/SunburstChart.svelte +11 -4
  144. package/src/lib/components/SwitchPortGrid.svelte +13 -7
  145. package/src/lib/components/TabPanel.svelte +9 -4
  146. package/src/lib/components/Tabs.svelte +18 -10
  147. package/src/lib/components/Tag.svelte +9 -5
  148. package/src/lib/components/TagInput.svelte +28 -18
  149. package/src/lib/components/Textarea.svelte +37 -15
  150. package/src/lib/components/ThresholdAreaChart.svelte +34 -21
  151. package/src/lib/components/TimePicker.svelte +25 -17
  152. package/src/lib/components/TimeRange.svelte +19 -14
  153. package/src/lib/components/Timeline.svelte +8 -4
  154. package/src/lib/components/Toast.svelte +2 -2
  155. package/src/lib/components/Toggle.svelte +13 -7
  156. package/src/lib/components/ToggleGroup.svelte +19 -11
  157. package/src/lib/components/Tooltip.svelte +16 -6
  158. package/src/lib/components/Topbar.svelte +24 -10
  159. package/src/lib/components/TransferList.svelte +34 -27
  160. package/src/lib/components/TreeItem.svelte +23 -10
  161. package/src/lib/components/TreeMap.svelte +13 -6
  162. package/src/lib/components/TreeView.svelte +24 -12
  163. package/src/lib/components/UptimeTimeline.svelte +22 -15
  164. package/src/lib/components/VennDiagram.svelte +25 -13
  165. package/src/lib/components/ViolinPlot.svelte +31 -19
  166. package/src/lib/components/VirtualList.svelte +25 -13
  167. package/src/lib/components/WaffleChart.svelte +32 -18
  168. package/src/lib/components/WaterfallChart.svelte +33 -26
  169. package/src/lib/components/WordCloud.svelte +21 -14
  170. package/src/lib/icons/AlarmIcon.svelte +4 -1
  171. package/src/lib/icons/BellIcon.svelte +2 -1
  172. package/src/lib/icons/CaretIcon.svelte +5 -3
  173. package/src/lib/icons/ClientsIcon.svelte +4 -1
  174. package/src/lib/icons/CloseIcon.svelte +2 -1
  175. package/src/lib/icons/DashboardIcon.svelte +4 -1
  176. package/src/lib/icons/DevicesIcon.svelte +4 -1
  177. package/src/lib/icons/DownloadIcon.svelte +2 -1
  178. package/src/lib/icons/HelpIcon.svelte +2 -1
  179. package/src/lib/icons/InfraIcon.svelte +4 -1
  180. package/src/lib/icons/IntegrationsIcon.svelte +4 -1
  181. package/src/lib/icons/LogsIcon.svelte +4 -1
  182. package/src/lib/icons/PlusIcon.svelte +2 -1
  183. package/src/lib/icons/PortsIcon.svelte +4 -1
  184. package/src/lib/icons/SearchIcon.svelte +6 -4
  185. package/src/lib/icons/SecurityIcon.svelte +4 -1
  186. package/src/lib/icons/SettingsIcon.svelte +4 -1
  187. package/src/lib/icons/TopologyIcon.svelte +4 -1
  188. package/src/lib/icons/UpdatesIcon.svelte +2 -1
  189. package/src/lib/icons/VpnIcon.svelte +4 -1
  190. package/src/lib/icons/WifiIcon.svelte +4 -1
  191. package/src/lib/icons/WirelessIcon.svelte +4 -1
@@ -1,54 +1,65 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  let counter = 0;
3
3
  export interface MultiSelectOption { value: string; label: string; }
4
4
  </script>
5
5
 
6
6
  <script lang="ts">
7
- import { createEventDispatcher, onMount, onDestroy } from 'svelte';
7
+ import { onMount, onDestroy } from 'svelte';
8
8
 
9
- export let options: MultiSelectOption[] = [];
10
- export let value: string[] = [];
11
- export let label: string | undefined = undefined;
12
- export let placeholder: string = 'Select…';
13
- export let id: string | undefined = undefined;
14
- export let disabled: boolean = false;
15
- let className = '';
16
- export { className as class };
17
-
18
- const uid = `dash-ui-ms-${++counter}`;
19
- $: inputId = id ?? uid;
20
- $: listboxId = `${inputId}-lb`;
9
+ interface Props {
10
+ options?: MultiSelectOption[];
11
+ value?: string[];
12
+ label?: string | undefined;
13
+ placeholder?: string;
14
+ id?: string | undefined;
15
+ disabled?: boolean;
16
+ class?: string;
17
+ onchange?: (payload: string[]) => void;
18
+ }
21
19
 
22
- const dispatch = createEventDispatcher<{ change: string[] }>();
20
+ let {
21
+ options = [],
22
+ value = [],
23
+ label = undefined,
24
+ placeholder = 'Select…',
25
+ id = undefined,
26
+ disabled = false,
27
+ class: className = '',
28
+ onchange,
29
+ }: Props = $props();
30
+
23
31
 
24
- let open = false;
25
- let query = '';
26
- let activeIdx = -1;
27
- let inputEl: HTMLInputElement;
28
- let wrapperEl: HTMLDivElement;
32
+ const uid = `dash-ui-ms-${++counter}`;
33
+ let inputId = $derived(id ?? uid);
34
+ let listboxId = $derived(`${inputId}-lb`);
35
+ let open = $state(false);
36
+ let query = $state('');
37
+ let activeIdx = $state(-1);
38
+ let inputEl = $state<HTMLInputElement | undefined>(undefined);
39
+ let wrapperEl = $state<HTMLDivElement | undefined>(undefined);
29
40
 
30
- $: selectedSet = new Set(value);
41
+ let selectedSet = $derived(new Set(value));
31
42
 
32
- $: filtered =
33
- query.trim() === ''
43
+ let filtered =
44
+ $derived(query.trim() === ''
34
45
  ? options
35
- : options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase()));
46
+ : options.filter((o) => o.label.toLowerCase().includes(query.toLowerCase())));
36
47
 
37
- $: activeOptionId =
38
- activeIdx >= 0 && filtered[activeIdx] ? `${listboxId}-opt-${activeIdx}` : undefined;
48
+ let activeOptionId =
49
+ $derived(activeIdx >= 0 && filtered[activeIdx] ? `${listboxId}-opt-${activeIdx}` : undefined);
39
50
 
40
51
  function toggle(optValue: string) {
41
52
  const next = new Set(selectedSet);
42
53
  if (next.has(optValue)) next.delete(optValue);
43
54
  else next.add(optValue);
44
- dispatch('change', Array.from(next));
55
+ onchange?.(Array.from(next));
45
56
  }
46
57
 
47
58
  function onKeyDown(e: KeyboardEvent) {
48
59
  if (disabled) return;
49
60
  if (e.key === 'Escape') { open = false; query = ''; return; }
50
61
  if (e.key === 'Backspace' && query === '' && value.length > 0) {
51
- dispatch('change', value.slice(0, -1));
62
+ onchange?.(value.slice(0, -1));
52
63
  return;
53
64
  }
54
65
  if (!open) {
@@ -79,10 +90,10 @@
79
90
 
80
91
  <div class="multiselect-wrapper {className}" bind:this={wrapperEl}>
81
92
  {#if label}<label for={inputId} class="sr-only">{label}</label>{/if}
82
- <!-- svelte-ignore a11y-click-events-have-key-events a11y-no-static-element-interactions -->
93
+ <!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
83
94
  <div
84
95
  class="multiselect-field{open ? ' multiselect-field--open' : ''}"
85
- on:click={() => { if (!disabled) inputEl?.focus(); }}
96
+ onclick={() => { if (!disabled) inputEl?.focus(); }}
86
97
  >
87
98
  {#each value as v (v)}
88
99
  {@const opt = options.find((o) => o.value === v)}
@@ -93,7 +104,7 @@
93
104
  type="button"
94
105
  class="tag__remove"
95
106
  aria-label="Remove {opt.label} filter"
96
- on:click|stopPropagation={() => toggle(v)}
107
+ onclick={(e) => { e.stopPropagation(); (() => toggle(v))(); }}
97
108
  >
98
109
  <svg viewBox="0 0 10 10" width="10" height="10" fill="none" aria-hidden="true" focusable="false">
99
110
  <path d="M2 2l6 6M8 2l-6 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
@@ -116,9 +127,9 @@
116
127
  {disabled}
117
128
  placeholder={value.length === 0 ? placeholder : ''}
118
129
  value={query}
119
- on:input={onInput}
120
- on:focus={() => { if (!disabled) open = true; }}
121
- on:keydown={onKeyDown}
130
+ oninput={onInput}
131
+ onfocus={() => { if (!disabled) open = true; }}
132
+ onkeydown={onKeyDown}
122
133
  class="multiselect-input"
123
134
  />
124
135
  <button
@@ -126,7 +137,7 @@
126
137
  tabindex="-1"
127
138
  aria-hidden="true"
128
139
  class="combobox-chevron-btn"
129
- on:click|stopPropagation={() => { if (open) { open = false; query = ''; } else { inputEl?.focus(); open = true; } }}
140
+ onclick={(e) => { e.stopPropagation(); (() => { if (open) { open = false; query = ''; } else { inputEl?.focus(); open = true; } })(); }}
130
141
  >
131
142
  <svg class="select-chevron{open ? ' combobox-chevron-open' : ''}" viewBox="0 0 16 16" aria-hidden="true" focusable="false">
132
143
  <path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none" />
@@ -139,15 +150,15 @@
139
150
  <li class="combobox-empty">No results</li>
140
151
  {:else}
141
152
  {#each filtered as opt, idx (opt.value)}
142
- <!-- svelte-ignore a11y-click-events-have-key-events -->
153
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
143
154
  <li
144
155
  id="{listboxId}-opt-{idx}"
145
156
  role="option"
146
157
  aria-selected={selectedSet.has(opt.value)}
147
158
  data-active={idx === activeIdx ? 'true' : undefined}
148
159
  class="select-option multiselect-option"
149
- on:mousedown|preventDefault={() => toggle(opt.value)}
150
- on:mouseenter={() => { activeIdx = idx; }}
160
+ onmousedown={(e) => { e.preventDefault(); (() => toggle(opt.value))(); }}
161
+ onmouseenter={() => { activeIdx = idx; }}
151
162
  >
152
163
  <span class="multiselect-check" aria-hidden="true">
153
164
  {#if selectedSet.has(opt.value)}
@@ -1,13 +1,20 @@
1
- <script lang="ts">
1
+ <script module lang="ts">
2
2
  export interface NightingaleSegment {
3
3
  label: string;
4
4
  value: number;
5
5
  color?: string;
6
6
  }
7
+ </script>
8
+
9
+ <script lang="ts">
10
+
11
+ interface Props {
12
+ segments?: NightingaleSegment[];
13
+ color?: string;
14
+ ariaLabel?: string;
15
+ }
7
16
 
8
- export let segments: NightingaleSegment[] = [];
9
- export let color: string = '#006FFF';
10
- export let ariaLabel: string = 'Nightingale chart';
17
+ let { segments = [], color = '#006FFF', ariaLabel = 'Nightingale chart' }: Props = $props();
11
18
 
12
19
  const SIZE = 280;
13
20
  const CX = SIZE / 2;
@@ -24,11 +31,11 @@
24
31
  return `M ${CX} ${CY} L ${x1.toFixed(2)} ${y1.toFixed(2)} A ${r.toFixed(2)} ${r.toFixed(2)} 0 0 1 ${x2.toFixed(2)} ${y2.toFixed(2)} Z`;
25
32
  }
26
33
 
27
- $: n = segments.length;
28
- $: maxVal = n ? Math.max(...segments.map((s) => s.value), 1) : 1;
29
- $: step = n ? (2 * Math.PI) / n : 0;
30
- $: labelEvery = n <= 8 ? 1 : Math.round(n / 8);
31
- $: wedges = segments.map((seg, i) => {
34
+ let n = $derived(segments.length);
35
+ let maxVal = $derived(n ? Math.max(...segments.map((s) => s.value), 1) : 1);
36
+ let step = $derived(n ? (2 * Math.PI) / n : 0);
37
+ let labelEvery = $derived(n <= 8 ? 1 : Math.round(n / 8));
38
+ let wedges = $derived(segments.map((seg, i) => {
32
39
  const sa = -Math.PI / 2 + i * step;
33
40
  const ea = -Math.PI / 2 + (i + 1) * step;
34
41
  const r = MIN_R + (seg.value / maxVal) * (MAX_R - MIN_R);
@@ -42,7 +49,7 @@
42
49
  label: seg.label,
43
50
  showLabel: i % labelEvery === 0,
44
51
  };
45
- });
52
+ }));
46
53
  </script>
47
54
 
48
55
  {#if segments.length}
@@ -1,9 +1,6 @@
1
- <script lang="ts">
2
- import { onDestroy } from 'svelte';
3
-
1
+ <script module lang="ts">
4
2
  export type NotifType = 'alarm' | 'system' | 'update';
5
3
  export type NotifSeverity = 'danger' | 'warn' | 'info' | 'success';
6
-
7
4
  export interface Notification {
8
5
  id: string;
9
6
  type: NotifType;
@@ -13,16 +10,32 @@
13
10
  time: string;
14
11
  read: boolean;
15
12
  }
13
+ </script>
14
+
15
+ <script lang="ts">
16
+ import { onDestroy } from 'svelte';
16
17
 
17
- export let open: boolean = false;
18
- export let notifications: Notification[] = [];
19
- export let onClose: () => void = () => {};
20
- export let onMarkRead: ((id: string) => void) | undefined = undefined;
21
- export let onMarkAllRead: (() => void) | undefined = undefined;
22
18
 
23
- let filter: 'all' | NotifType = 'all';
24
- let panelEl: HTMLDivElement;
25
- let prevFocus: HTMLElement | null = null;
19
+
20
+ interface Props {
21
+ open?: boolean;
22
+ notifications?: Notification[];
23
+ onClose?: () => void;
24
+ onMarkRead?: ((id: string) => void) | undefined;
25
+ onMarkAllRead?: (() => void) | undefined;
26
+ }
27
+
28
+ let {
29
+ open = $bindable(false),
30
+ notifications = [],
31
+ onClose = () => {},
32
+ onMarkRead = undefined,
33
+ onMarkAllRead = undefined
34
+ }: Props = $props();
35
+
36
+ let filter: 'all' | NotifType = $state('all');
37
+ let panelEl = $state<HTMLDivElement | undefined>(undefined);
38
+ let prevFocus: HTMLElement | null = $state(null);
26
39
 
27
40
  const SEV_COLOR: Record<string, string> = {
28
41
  danger: '#F03A3A',
@@ -40,8 +53,8 @@
40
53
 
41
54
  function setFilter(f: string) { filter = f as 'all' | NotifType; }
42
55
 
43
- $: unread = notifications.filter((n) => !n.read).length;
44
- $: filtered = filter === 'all' ? notifications : notifications.filter((n) => n.type === filter);
56
+ let unread = $derived(notifications.filter((n) => !n.read).length);
57
+ let filtered = $derived(filter === 'all' ? notifications : notifications.filter((n) => n.type === filter));
45
58
 
46
59
  const FOCUSABLE =
47
60
  'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
@@ -58,18 +71,20 @@
58
71
  else if (!e.shiftKey && active === l) { e.preventDefault(); f.focus(); }
59
72
  }
60
73
 
61
- $: if (open) {
62
- prevFocus = document.activeElement as HTMLElement | null;
63
- setTimeout(() => {
64
- if (!panelEl) return;
65
- const first = panelEl.querySelector<HTMLElement>(FOCUSABLE);
66
- (first ?? panelEl)?.focus();
67
- }, 0);
68
- window.addEventListener('keydown', trapFocus);
69
- } else {
70
- window.removeEventListener('keydown', trapFocus);
71
- prevFocus?.focus?.();
72
- }
74
+ $effect(() => {
75
+ if (open) {
76
+ prevFocus = document.activeElement as HTMLElement | null;
77
+ setTimeout(() => {
78
+ if (!panelEl) return;
79
+ const first = panelEl.querySelector<HTMLElement>(FOCUSABLE);
80
+ (first ?? panelEl)?.focus();
81
+ }, 0);
82
+ window.addEventListener('keydown', trapFocus);
83
+ } else {
84
+ window.removeEventListener('keydown', trapFocus);
85
+ prevFocus?.focus?.();
86
+ }
87
+ });
73
88
 
74
89
  onDestroy(() => {
75
90
  window.removeEventListener('keydown', trapFocus);
@@ -78,12 +93,12 @@
78
93
  let titleId = 'np-title-' + Math.random().toString(36).slice(2);
79
94
  </script>
80
95
 
81
- <!-- svelte-ignore a11y-click-events-have-key-events a11y-no-static-element-interactions -->
96
+ <!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
82
97
  <div
83
98
  class="np-overlay{open ? ' np-overlay--show' : ''}"
84
- on:click={onClose}
99
+ onclick={onClose}
85
100
  aria-hidden="true"
86
- />
101
+ ></div>
87
102
  <div
88
103
  bind:this={panelEl}
89
104
  class="np-panel{open ? ' np-panel--show' : ''}"
@@ -102,11 +117,11 @@
102
117
  </h2>
103
118
  <div class="np-header-actions">
104
119
  {#if unread > 0 && onMarkAllRead}
105
- <button type="button" class="np-mark-all" on:click={onMarkAllRead}>
120
+ <button type="button" class="np-mark-all" onclick={onMarkAllRead}>
106
121
  Mark all read
107
122
  </button>
108
123
  {/if}
109
- <button type="button" class="icon-btn" on:click={onClose} aria-label="Close notifications">
124
+ <button type="button" class="icon-btn" onclick={onClose} aria-label="Close notifications">
110
125
  <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
111
126
  <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.75.75 0 1 1 1.06 1.06L9.06 8l3.22 3.22a.75.75 0 1 1-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 0 1-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06z"/>
112
127
  </svg>
@@ -120,7 +135,7 @@
120
135
  role="tab"
121
136
  aria-selected={filter === f}
122
137
  class="np-filter{filter === f ? ' np-filter--active' : ''}"
123
- on:click={() => setFilter(f)}
138
+ onclick={() => setFilter(f)}
124
139
  >
125
140
  {TYPE_LABEL[f] ?? f}
126
141
  </button>
@@ -158,7 +173,7 @@
158
173
  <button
159
174
  type="button"
160
175
  class="np-read-btn"
161
- on:click={() => onMarkRead?.(n.id)}
176
+ onclick={() => onMarkRead?.(n.id)}
162
177
  aria-label="Mark as read: {n.title}"
163
178
  title="Mark as read"
164
179
  >&#10003;</button>
@@ -1,26 +1,39 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  let counter = 0;
3
3
  </script>
4
4
 
5
5
  <script lang="ts">
6
- import { createEventDispatcher } from 'svelte';
6
+
7
7
 
8
- export let label: string | undefined = undefined;
9
- export let value: number = 0;
10
- export let min: number | undefined = undefined;
11
- export let max: number | undefined = undefined;
12
- export let step: number = 1;
13
- export let suffix: string | undefined = undefined;
14
- export let disabled: boolean = false;
15
- export let id: string | undefined = undefined;
16
- let className = '';
17
- export { className as class };
18
-
19
- const uid = `dash-ui-ni-${++counter}`;
20
- $: inputId = id ?? uid;
8
+ interface Props {
9
+ label?: string | undefined;
10
+ value?: number;
11
+ min?: number | undefined;
12
+ max?: number | undefined;
13
+ step?: number;
14
+ suffix?: string | undefined;
15
+ disabled?: boolean;
16
+ id?: string | undefined;
17
+ class?: string;
18
+ onchange?: (payload: number) => void;
19
+ }
21
20
 
22
- const dispatch = createEventDispatcher<{ change: number }>();
21
+ let {
22
+ label = undefined,
23
+ value = $bindable(0),
24
+ min = undefined,
25
+ max = undefined,
26
+ step = 1,
27
+ suffix = undefined,
28
+ disabled = false,
29
+ id = undefined,
30
+ class: className = '',
31
+ onchange,
32
+ }: Props = $props();
33
+
23
34
 
35
+ const uid = `dash-ui-ni-${++counter}`;
36
+ let inputId = $derived(id ?? uid);
24
37
  function clamp(n: number): number {
25
38
  let v = n;
26
39
  if (min !== undefined) v = Math.max(min, v);
@@ -30,7 +43,7 @@
30
43
 
31
44
  function commit(next: number) {
32
45
  value = clamp(next);
33
- dispatch('change', value);
46
+ onchange?.(value);
34
47
  }
35
48
 
36
49
  function handleKey(e: KeyboardEvent) {
@@ -47,8 +60,8 @@
47
60
  if (!isNaN(n)) commit(n);
48
61
  }
49
62
 
50
- $: canDecrement = !disabled && (min === undefined || value > min);
51
- $: canIncrement = !disabled && (max === undefined || value < max);
63
+ let canDecrement = $derived(!disabled && (min === undefined || value > min));
64
+ let canIncrement = $derived(!disabled && (max === undefined || value < max));
52
65
  </script>
53
66
 
54
67
  <div class="number-input {className}">
@@ -62,8 +75,9 @@
62
75
  aria-label="Decrement"
63
76
  tabindex="-1"
64
77
  disabled={!canDecrement}
65
- on:click={() => commit(value - step)}
78
+ onclick={() => commit(value - step)}
66
79
  >−</button>
80
+ <!-- svelte-ignore a11y_no_redundant_roles - role kept explicit for screen reader compat -->
67
81
  <input
68
82
  id={inputId}
69
83
  type="number"
@@ -75,8 +89,8 @@
75
89
  {value}
76
90
  {disabled}
77
91
  class="number-input__field"
78
- on:change={handleChange}
79
- on:keydown={handleKey}
92
+ onchange={handleChange}
93
+ onkeydown={handleKey}
80
94
  />
81
95
  {#if suffix}
82
96
  <span class="number-input__suffix" aria-hidden="true">{suffix}</span>
@@ -87,7 +101,7 @@
87
101
  aria-label="Increment"
88
102
  tabindex="-1"
89
103
  disabled={!canIncrement}
90
- on:click={() => commit(value + step)}
104
+ onclick={() => commit(value + step)}
91
105
  >+</button>
92
106
  </div>
93
107
  </div>
@@ -1,23 +1,35 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  let counter = 0;
3
3
  </script>
4
4
 
5
5
  <script lang="ts">
6
- import { createEventDispatcher } from 'svelte';
6
+
7
7
 
8
- export let label: string | undefined = undefined;
9
- export let length: number = 6;
10
- export let value: string = '';
11
- export let disabled: boolean = false;
12
- let className = '';
13
- export { className as class };
8
+ interface Props {
9
+ label?: string | undefined;
10
+ length?: number;
11
+ value?: string;
12
+ disabled?: boolean;
13
+ class?: string;
14
+ onchange?: (payload: string) => void;
15
+ }
14
16
 
15
- const dispatch = createEventDispatcher<{ change: string }>();
17
+ let {
18
+ label = undefined,
19
+ length = 6,
20
+ value = $bindable(''),
21
+ disabled = false,
22
+ class: className = '',
23
+ onchange,
24
+ }: Props = $props();
16
25
  const uid = `dash-ui-otp-${++counter}`;
17
26
 
18
- let digits: string[] = Array.from({ length }, (_, i) => value[i] ?? '');
19
- let inputs: (HTMLInputElement | null)[] = Array(length).fill(null);
27
+ // svelte-ignore state_referenced_locally
28
+ let digits: string[] = $state(Array.from({ length }, (_, i) => value[i] ?? ''));
29
+ // svelte-ignore state_referenced_locally
30
+ let inputs: (HTMLInputElement | null)[] = $state(Array(length).fill(null));
20
31
 
32
+ // svelte-ignore state_referenced_locally
21
33
  const half = Math.floor(length / 2);
22
34
 
23
35
  function focusAt(i: number) {
@@ -28,7 +40,7 @@
28
40
  function commit(next: string[]) {
29
41
  digits = next;
30
42
  value = next.join('');
31
- dispatch('change', value);
43
+ onchange?.(value);
32
44
  }
33
45
 
34
46
  function handleInput(i: number, raw: string) {
@@ -84,10 +96,10 @@
84
96
  {disabled}
85
97
  class="otp-input__digit"
86
98
  autocomplete={i === 0 ? 'one-time-code' : 'off'}
87
- on:input={(e) => handleInput(i, e.currentTarget.value)}
88
- on:keydown={(e) => handleKey(i, e)}
89
- on:paste={handlePaste}
90
- on:focus={(e) => e.currentTarget.select()}
99
+ oninput={(e) => handleInput(i, e.currentTarget.value)}
100
+ onkeydown={(e) => handleKey(i, e)}
101
+ onpaste={handlePaste}
102
+ onfocus={(e) => e.currentTarget.select()}
91
103
  />
92
104
  {/each}
93
105
  </div>
@@ -1,15 +1,16 @@
1
1
  <script lang="ts">
2
- import { createEventDispatcher } from 'svelte';
2
+
3
3
 
4
- export let page: number = 1;
5
- export let pageSize: number = 10;
6
- export let total: number = 0;
7
-
8
- const dispatch = createEventDispatcher<{ change: number }>();
9
-
10
- $: totalPages = Math.max(1, Math.ceil(total / pageSize));
11
- $: pages = getPageNumbers(page, totalPages);
4
+ interface Props {
5
+ page?: number;
6
+ pageSize?: number;
7
+ total?: number;
8
+ onchange?: (payload: number) => void;
9
+ }
12
10
 
11
+ let { page = 1, pageSize = 10, total = 0,
12
+ onchange,
13
+ }: Props = $props();
13
14
  function getPageNumbers(p: number, tp: number): (number | '...')[] {
14
15
  if (tp <= 7) return Array.from({ length: tp }, (_, i) => i + 1);
15
16
  const items: (number | '...')[] = [1];
@@ -22,7 +23,9 @@
22
23
  return items;
23
24
  }
24
25
 
25
- function go(p: number) { dispatch('change', p); }
26
+ function go(p: number) { onchange?.(p); }
27
+ let totalPages = $derived(Math.max(1, Math.ceil(total / pageSize)));
28
+ let pages = $derived(getPageNumbers(page, totalPages));
26
29
  </script>
27
30
 
28
31
  {#if totalPages > 1}
@@ -32,7 +35,7 @@
32
35
  class="pagination-btn"
33
36
  aria-label="Previous page"
34
37
  disabled={page <= 1}
35
- on:click={() => go(page - 1)}
38
+ onclick={() => go(page - 1)}
36
39
  >&#x2039;</button>
37
40
  {#each pages as p, i (typeof p === 'number' ? p : `e${i}`)}
38
41
  {#if p === '...'}
@@ -43,7 +46,7 @@
43
46
  class="pagination-btn{p === page ? ' active' : ''}"
44
47
  aria-label="Page {p}"
45
48
  aria-current={p === page ? 'page' : undefined}
46
- on:click={() => go(p)}
49
+ onclick={() => go(p)}
47
50
  >{p}</button>
48
51
  {/if}
49
52
  {/each}
@@ -52,7 +55,7 @@
52
55
  class="pagination-btn"
53
56
  aria-label="Next page"
54
57
  disabled={page >= totalPages}
55
- on:click={() => go(page + 1)}
58
+ onclick={() => go(page + 1)}
56
59
  >&#x203A;</button>
57
60
  </nav>
58
61
  {/if}
@@ -1,6 +1,4 @@
1
- <script lang="ts">
2
- const COLORS = ['#006FFF', '#00C8C8', '#F5A623', '#7FB6FF', '#A878F5', '#F56342'];
3
-
1
+ <script module lang="ts">
4
2
  export interface ParallelAxis {
5
3
  label: string;
6
4
  min: number;
@@ -8,28 +6,42 @@
8
6
  unit?: string;
9
7
  invert?: boolean;
10
8
  }
11
-
12
9
  export interface ParallelSeries {
13
10
  label: string;
14
11
  color?: string;
15
12
  values: number[];
16
13
  }
14
+ </script>
15
+
16
+ <script lang="ts">
17
+ const COLORS = ['#006FFF', '#00C8C8', '#F5A623', '#7FB6FF', '#A878F5', '#F56342'];
18
+
19
+
20
+
21
+ interface Props {
22
+ axes?: ParallelAxis[];
23
+ series?: ParallelSeries[];
24
+ height?: number;
25
+ ariaLabel?: string;
26
+ }
17
27
 
18
- export let axes: ParallelAxis[] = [];
19
- export let series: ParallelSeries[] = [];
20
- export let height: number = 200;
21
- export let ariaLabel: string = 'Parallel coordinates chart';
28
+ let {
29
+ axes = [],
30
+ series = [],
31
+ height = 200,
32
+ ariaLabel = 'Parallel coordinates chart'
33
+ }: Props = $props();
22
34
 
23
35
  const VW = 380;
24
- $: VH = height;
36
+ let VH = $derived(height);
25
37
  const PAD_L = 28;
26
38
  const PAD_R = 28;
27
39
  const PAD_T = 32;
28
40
  const PAD_B = 20;
29
41
 
30
- $: TRACK_W = VW - PAD_L - PAD_R;
31
- $: TRACK_H = VH - PAD_T - PAD_B;
32
- $: nAxes = axes.length;
42
+ let TRACK_W = $derived(VW - PAD_L - PAD_R);
43
+ let TRACK_H = $derived(VH - PAD_T - PAD_B);
44
+ let nAxes = $derived(axes.length);
33
45
 
34
46
  function axisX(i: number, tw: number, n: number): number {
35
47
  return PAD_L + (n > 1 ? i * (tw / (n - 1)) : tw / 2);
@@ -52,12 +64,12 @@
52
64
 
53
65
  const TICKS = [0, 0.5, 1];
54
66
 
55
- $: paths = series.map((s, si) => ({
67
+ let paths = $derived(series.map((s, si) => ({
56
68
  d: seriesPath(s, TRACK_W, TRACK_H, nAxes),
57
69
  stroke: s.color ?? COLORS[si % COLORS.length],
58
- }));
70
+ })));
59
71
 
60
- $: axisData = axes.map((axis, i) => {
72
+ let axisData = $derived(axes.map((axis, i) => {
61
73
  const x = axisX(i, TRACK_W, nAxes);
62
74
  const ticks = TICKS.map(t => {
63
75
  const v = axis.invert
@@ -67,7 +79,7 @@
67
79
  return { t, v, y };
68
80
  });
69
81
  return { axis, x, ticks };
70
- });
82
+ }));
71
83
  </script>
72
84
 
73
85
  <div role="img" aria-label={ariaLabel} style="width:100%;">