@w5-ui/svelte 0.1.0 → 0.2.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.
Files changed (191) hide show
  1. package/package.json +6 -6
  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,17 +1,34 @@
1
1
  <script lang="ts">
2
2
  import { onMount, onDestroy } from 'svelte';
3
3
 
4
- export let from: number = 0;
5
- export let to: number;
6
- export let duration: number = 1200;
7
- export let decimals: number = 0;
8
- export let prefix: string = '';
9
- export let suffix: string = '';
10
- export let separator: string = ',';
11
- let klass: string = '';
12
- export { klass as class };
13
-
14
- let current = from;
4
+ interface Props {
5
+ from?: number;
6
+ to: number;
7
+ duration?: number;
8
+ decimals?: number;
9
+ prefix?: string;
10
+ suffix?: string;
11
+ separator?: string;
12
+ class?: string;
13
+ }
14
+
15
+ let {
16
+ from = 0,
17
+ to,
18
+ duration = 1200,
19
+ decimals = 0,
20
+ prefix = '',
21
+ suffix = '',
22
+ separator = ',',
23
+ class: klass = ''
24
+ }: Props = $props();
25
+
26
+
27
+ // `current` snapshots `from` once and then animates towards `to`. Live-
28
+ // tracking `from` would yank the animation back to the prop on every
29
+ // update.
30
+ // svelte-ignore state_referenced_locally
31
+ let current = $state(from);
15
32
  let rafId: number;
16
33
 
17
34
  function easeOut(t: number) { return 1 - Math.pow(1 - t, 3); }
@@ -24,8 +41,8 @@
24
41
  return dec !== undefined ? `${intFmt}.${dec}` : intFmt;
25
42
  }
26
43
 
27
- $: label = `${prefix}${fmt(to)}${suffix}`;
28
- $: display = `${prefix}${fmt(current)}${suffix}`;
44
+ let label = $derived(`${prefix}${fmt(to)}${suffix}`);
45
+ let display = $derived(`${prefix}${fmt(current)}${suffix}`);
29
46
 
30
47
  onMount(() => {
31
48
  const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
@@ -1,29 +1,42 @@
1
- <script lang="ts">
1
+ <script module lang="ts">
2
2
  export interface CdfSeries {
3
3
  label: string;
4
4
  color: string;
5
5
  values: number[];
6
6
  }
7
+ </script>
8
+
9
+ <script lang="ts">
10
+
11
+ interface Props {
12
+ series?: CdfSeries[];
13
+ guides?: number[];
14
+ height?: number;
15
+ unit?: string;
16
+ ariaLabel?: string;
17
+ }
7
18
 
8
- export let series: CdfSeries[] = [];
9
- export let guides: number[] = [50, 95];
10
- export let height: number = 160;
11
- export let unit: string = '';
12
- export let ariaLabel: string = 'Cumulative distribution chart';
19
+ let {
20
+ series = [],
21
+ guides = [50, 95],
22
+ height = 160,
23
+ unit = '',
24
+ ariaLabel = 'Cumulative distribution chart'
25
+ }: Props = $props();
13
26
 
14
27
  const W = 400, PL = 38, PR = 12, PT = 14, PB = 28;
15
28
 
16
- $: allVals = series.flatMap((s) => s.values);
17
- $: xMin = allVals.length ? Math.min(...allVals) : 0;
18
- $: xMax = allVals.length ? Math.max(...allVals) : 1;
19
- $: xRange = (xMax - xMin) || 1;
20
- $: cW = W - PL - PR;
21
- $: cH = height - PT - PB;
29
+ let allVals = $derived(series.flatMap((s) => s.values));
30
+ let xMin = $derived(allVals.length ? Math.min(...allVals) : 0);
31
+ let xMax = $derived(allVals.length ? Math.max(...allVals) : 1);
32
+ let xRange = $derived((xMax - xMin) || 1);
33
+ let cW = $derived(W - PL - PR);
34
+ let cH = $derived(height - PT - PB);
22
35
 
23
36
  function toX(v: number) { return PL + ((v - xMin) / xRange) * cW; }
24
37
  function toY(p: number) { return PT + (1 - p) * cH; }
25
38
 
26
- $: paths = series.map((s) => {
39
+ let paths = $derived(series.map((s) => {
27
40
  const sorted = [...s.values].sort((a, b) => a - b);
28
41
  const n = sorted.length;
29
42
  let d = `M${toX(xMin).toFixed(1)},${toY(0).toFixed(1)}`;
@@ -32,15 +45,15 @@
32
45
  });
33
46
  d += ` H${toX(xMax).toFixed(1)}`;
34
47
  return { label: s.label, color: s.color, d };
35
- });
48
+ }));
36
49
 
37
- $: yTicks = [0, 0.25, 0.5, 0.75, 1].map((p) => ({ y: toY(p), label: `${Math.round(p * 100)}%` }));
38
- $: xStep = xRange / 4;
39
- $: xTicks = Array.from({ length: 5 }, (_, i) => {
50
+ let yTicks = $derived([0, 0.25, 0.5, 0.75, 1].map((p) => ({ y: toY(p), label: `${Math.round(p * 100)}%` })));
51
+ let xStep = $derived(xRange / 4);
52
+ let xTicks = $derived(Array.from({ length: 5 }, (_, i) => {
40
53
  const v = xMin + xStep * i;
41
54
  return { x: toX(v), label: `${Math.round(v)}${unit}` };
42
- });
43
- $: guideLines = guides.map((g) => ({ p: g, y: toY(g / 100) }));
55
+ }));
56
+ let guideLines = $derived(guides.map((g) => ({ p: g, y: toY(g / 100) })));
44
57
  </script>
45
58
 
46
59
  {#if allVals.length}
@@ -1,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  let counter = 0;
3
3
  const DAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
4
4
  const MONTHS = [
@@ -36,27 +36,34 @@
36
36
  </script>
37
37
 
38
38
  <script lang="ts">
39
- import { createEventDispatcher, onMount, onDestroy, tick } from 'svelte';
39
+ import { onMount, onDestroy, tick } from 'svelte';
40
40
 
41
- export let value: Date | null = null;
42
- export let placeholder: string = 'Pick a date';
43
- export let disabled: boolean = false;
41
+ interface Props {
42
+ value?: Date | null;
43
+ placeholder?: string;
44
+ disabled?: boolean;
45
+ onchange?: (payload: Date) => void;
46
+ }
44
47
 
45
- const dispatch = createEventDispatcher<{ change: Date }>();
48
+ let { value = null, placeholder = 'Pick a date', disabled = false,
49
+ onchange,
50
+ }: Props = $props();
46
51
  const uid = `dash-ui-dp-${++counter}`;
47
52
  const calId = `${uid}-cal`;
48
53
  const today = new Date();
49
54
 
50
- let open = false;
51
- let viewYear = value?.getFullYear() ?? today.getFullYear();
52
- let viewMonth = value?.getMonth() ?? today.getMonth();
53
- let focusIdx = 0;
54
- let triggerEl: HTMLButtonElement;
55
- let calEl: HTMLDivElement;
56
- let dayEls: (HTMLButtonElement | null)[] = Array(42).fill(null);
55
+ let open = $state(false);
56
+ // svelte-ignore state_referenced_locally
57
+ let viewYear = $state(value?.getFullYear() ?? today.getFullYear());
58
+ // svelte-ignore state_referenced_locally
59
+ let viewMonth = $state(value?.getMonth() ?? today.getMonth());
60
+ let focusIdx = $state(0);
61
+ let triggerEl = $state<HTMLButtonElement | undefined>(undefined);
62
+ let calEl = $state<HTMLDivElement | undefined>(undefined);
63
+ let dayEls: (HTMLButtonElement | null)[] = $state(Array(42).fill(null));
57
64
 
58
- $: grid = buildGrid(viewYear, viewMonth);
59
- $: label = `${MONTHS[viewMonth]} ${viewYear}`;
65
+ let grid = $derived(buildGrid(viewYear, viewMonth));
66
+ let label = $derived(`${MONTHS[viewMonth]} ${viewYear}`);
60
67
 
61
68
  function openCal() {
62
69
  if (disabled) return;
@@ -74,7 +81,7 @@
74
81
  }
75
82
 
76
83
  function select(d: Date) {
77
- dispatch('change', d);
84
+ onchange?.(d);
78
85
  closeCal();
79
86
  }
80
87
 
@@ -129,7 +136,7 @@
129
136
  aria-expanded={open}
130
137
  aria-controls={open ? calId : undefined}
131
138
  {disabled}
132
- on:click={() => open ? closeCal() : openCal()}
139
+ onclick={() => open ? closeCal() : openCal()}
133
140
  >
134
141
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
135
142
  <rect x="1" y="2" width="12" height="11" rx="1.5" />
@@ -148,13 +155,13 @@
148
155
  class="dp-cal"
149
156
  >
150
157
  <div class="dp-header">
151
- <button type="button" class="dp-nav" on:click={prevMonth} aria-label="Previous month">
158
+ <button type="button" class="dp-nav" onclick={prevMonth} aria-label="Previous month">
152
159
  <svg width="8" height="12" viewBox="0 0 8 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
153
160
  <path d="M7 1L2 6l5 5" />
154
161
  </svg>
155
162
  </button>
156
163
  <span class="dp-month-label" aria-live="polite">{label}</span>
157
- <button type="button" class="dp-nav" on:click={nextMonth} aria-label="Next month">
164
+ <button type="button" class="dp-nav" onclick={nextMonth} aria-label="Next month">
158
165
  <svg width="8" height="12" viewBox="0 0 8 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
159
166
  <path d="M1 1l5 5-5 5" />
160
167
  </svg>
@@ -185,8 +192,8 @@
185
192
  tabindex={idx === focusIdx ? 0 : -1}
186
193
  class="dp-day{outside ? ' dp-day--outside' : ''}{isToday && !isSelected ? ' dp-day--today' : ''}{isSelected ? ' dp-day--selected' : ''}"
187
194
  aria-label={day.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })}
188
- on:keydown={(e) => onGridKey(e, idx)}
189
- on:click={() => select(day)}
195
+ onkeydown={(e) => onGridKey(e, idx)}
196
+ onclick={() => select(day)}
190
197
  >
191
198
  {day.getDate()}
192
199
  </button>
@@ -1,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  let counter = 0;
3
3
  const DAYS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
4
4
  const MONTHS = [
@@ -33,37 +33,42 @@
33
33
  }
34
34
  return grid;
35
35
  }
36
- </script>
37
-
38
- <script lang="ts">
39
- import { createEventDispatcher, onMount, onDestroy } from 'svelte';
40
36
 
41
37
  export interface DateRange {
42
38
  start: Date | null;
43
39
  end: Date | null;
44
40
  }
41
+ </script>
45
42
 
46
- export let value: DateRange = { start: null, end: null };
47
- export let placeholder: string = 'Select date range';
48
- export let disabled: boolean = false;
43
+ <script lang="ts">
44
+ import { onMount, onDestroy } from 'svelte';
45
+
46
+ interface Props {
47
+ value?: DateRange;
48
+ placeholder?: string;
49
+ disabled?: boolean;
50
+ onchange?: (payload: DateRange) => void;
51
+ }
49
52
 
50
- const dispatch = createEventDispatcher<{ change: DateRange }>();
53
+ let { value = { start: null, end: null }, placeholder = 'Select date range', disabled = false,
54
+ onchange,
55
+ }: Props = $props();
51
56
  const uid = `dash-ui-drp-${++counter}`;
52
57
  const dlgId = `${uid}-dlg`;
53
58
  const today = new Date();
54
59
 
55
- let open = false;
56
- let picking: Date | null = null;
57
- let hoverDate: Date | null = null;
58
- let viewYear = today.getFullYear();
59
- let viewMonth = today.getMonth();
60
- let triggerEl: HTMLButtonElement;
61
- let dlgEl: HTMLDivElement;
60
+ let open = $state(false);
61
+ let picking: Date | null = $state(null);
62
+ let hoverDate: Date | null = $state(null);
63
+ let viewYear = $state(today.getFullYear());
64
+ let viewMonth = $state(today.getMonth());
65
+ let triggerEl = $state<HTMLButtonElement | undefined>(undefined);
66
+ let dlgEl = $state<HTMLDivElement | undefined>(undefined);
62
67
 
63
- $: rightMonth = viewMonth === 11 ? 0 : viewMonth + 1;
64
- $: rightYear = viewMonth === 11 ? viewYear + 1 : viewYear;
65
- $: leftGrid = buildGrid(viewYear, viewMonth);
66
- $: rightGrid = buildGrid(rightYear, rightMonth);
68
+ let rightMonth = $derived(viewMonth === 11 ? 0 : viewMonth + 1);
69
+ let rightYear = $derived(viewMonth === 11 ? viewYear + 1 : viewYear);
70
+ let leftGrid = $derived(buildGrid(viewYear, viewMonth));
71
+ let rightGrid = $derived(buildGrid(rightYear, rightMonth));
67
72
 
68
73
  function prevMonth() {
69
74
  if (viewMonth === 0) { viewYear -= 1; viewMonth = 11; }
@@ -78,12 +83,12 @@
78
83
  function handleDayClick(day: Date) {
79
84
  if (!picking) {
80
85
  picking = day;
81
- dispatch('change', { start: day, end: null });
86
+ onchange?.({ start: day, end: null });
82
87
  } else {
83
88
  const [s, e] = day < picking ? [day, picking] : [picking, day];
84
89
  picking = null;
85
90
  hoverDate = null;
86
- dispatch('change', { start: s, end: e });
91
+ onchange?.({ start: s, end: e });
87
92
  open = false;
88
93
  triggerEl?.focus();
89
94
  }
@@ -134,7 +139,7 @@
134
139
  aria-expanded={open}
135
140
  aria-controls={open ? dlgId : undefined}
136
141
  {disabled}
137
- on:click={() => { if (open) { open = false; picking = null; } else open = true; }}
142
+ onclick={() => { if (open) { open = false; picking = null; } else open = true; }}
138
143
  >
139
144
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
140
145
  <rect x="1" y="2" width="12" height="11" rx="1.5" />
@@ -144,14 +149,16 @@
144
149
  </button>
145
150
 
146
151
  {#if open}
152
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions - dialog uses keyboard listener for Escape -->
147
153
  <div
148
154
  id={dlgId}
149
155
  bind:this={dlgEl}
150
156
  role="dialog"
151
157
  aria-modal="true"
152
158
  aria-label="Select date range"
159
+ tabindex="-1"
153
160
  class="drp-cal"
154
- on:keydown={(e) => {
161
+ onkeydown={(e) => {
155
162
  if (e.key === 'Escape') { e.preventDefault(); open = false; picking = null; triggerEl?.focus(); }
156
163
  }}
157
164
  >
@@ -159,7 +166,7 @@
159
166
  <!-- Left calendar -->
160
167
  <div class="drp-month">
161
168
  <div class="dp-header">
162
- <button type="button" class="dp-nav" on:click={prevMonth} aria-label="Previous month">
169
+ <button type="button" class="dp-nav" onclick={prevMonth} aria-label="Previous month">
163
170
  <svg width="8" height="12" viewBox="0 0 8 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
164
171
  <path d="M7 1L2 6l5 5" />
165
172
  </svg>
@@ -187,9 +194,9 @@
187
194
  type="button"
188
195
  class="dp-day{outside ? ' dp-day--outside' : ''}{isTodayDay && !start && !end ? ' dp-day--today' : ''}{start ? ' dp-day--start' : ''}{end ? ' dp-day--end' : ''}{inRange ? ' dp-day--in-range' : ''}"
189
196
  aria-label={day.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })}
190
- on:click={() => handleDayClick(day)}
191
- on:mouseenter={() => { if (picking) hoverDate = day; }}
192
- on:mouseleave={() => { if (picking) hoverDate = null; }}
197
+ onclick={() => handleDayClick(day)}
198
+ onmouseenter={() => { if (picking) hoverDate = day; }}
199
+ onmouseleave={() => { if (picking) hoverDate = null; }}
193
200
  >{day.getDate()}</button>
194
201
  </td>
195
202
  {/each}
@@ -203,7 +210,7 @@
203
210
  <div class="dp-header">
204
211
  <span style="width:28px;display:inline-block;" aria-hidden="true"></span>
205
212
  <span class="dp-month-label" aria-live="polite">{MONTHS[rightMonth]} {rightYear}</span>
206
- <button type="button" class="dp-nav" on:click={nextMonth} aria-label="Next month">
213
+ <button type="button" class="dp-nav" onclick={nextMonth} aria-label="Next month">
207
214
  <svg width="8" height="12" viewBox="0 0 8 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
208
215
  <path d="M1 1l5 5-5 5" />
209
216
  </svg>
@@ -229,9 +236,9 @@
229
236
  type="button"
230
237
  class="dp-day{outside ? ' dp-day--outside' : ''}{isTodayDay && !start && !end ? ' dp-day--today' : ''}{start ? ' dp-day--start' : ''}{end ? ' dp-day--end' : ''}{inRange ? ' dp-day--in-range' : ''}"
231
238
  aria-label={day.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })}
232
- on:click={() => handleDayClick(day)}
233
- on:mouseenter={() => { if (picking) hoverDate = day; }}
234
- on:mouseleave={() => { if (picking) hoverDate = null; }}
239
+ onclick={() => handleDayClick(day)}
240
+ onmouseenter={() => { if (picking) hoverDate = day; }}
241
+ onmouseleave={() => { if (picking) hoverDate = null; }}
235
242
  >{day.getDate()}</button>
236
243
  </td>
237
244
  {/each}
@@ -1,10 +1,13 @@
1
- <script lang="ts">
1
+ <script module lang="ts">
2
2
  export interface DendrogramNode {
3
3
  id: string;
4
4
  label: string;
5
5
  children?: DendrogramNode[];
6
6
  color?: string;
7
7
  }
8
+ </script>
9
+
10
+ <script lang="ts">
8
11
 
9
12
  interface PlacedNode {
10
13
  id: string;
@@ -90,12 +93,21 @@
90
93
  }));
91
94
  }
92
95
 
93
- export let root: DendrogramNode;
94
- export let colWidth: number = 130;
95
- export let rowHeight: number = 28;
96
- export let ariaLabel: string = 'Dendrogram';
96
+ interface Props {
97
+ root: DendrogramNode;
98
+ colWidth?: number;
99
+ rowHeight?: number;
100
+ ariaLabel?: string;
101
+ }
102
+
103
+ let {
104
+ root,
105
+ colWidth = 130,
106
+ rowHeight = 28,
107
+ ariaLabel = 'Dendrogram'
108
+ }: Props = $props();
97
109
 
98
- $: ({ svgW, svgH, nodes, links } = compute(root, colWidth, rowHeight));
110
+ let { svgW, svgH, nodes, links } = $derived(compute(root, colWidth, rowHeight));
99
111
  </script>
100
112
 
101
113
  <div role="img" aria-label={ariaLabel} style="width:100%;overflow-x:auto">
@@ -1,18 +1,32 @@
1
- <script lang="ts">
1
+ <script module lang="ts">
2
2
  export interface DonutSegment { label: string; value: number; color: string }
3
- export let size: number = 96;
4
- export let segments: DonutSegment[] = [];
5
- export let centerValue: string | number;
6
- export let centerLabel: string;
7
- export let trackColor: string = 'rgba(255,255,255,0.06)';
8
- export let ariaLabel: string | undefined = undefined;
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ interface Props {
7
+ size?: number;
8
+ segments?: DonutSegment[];
9
+ centerValue: string | number;
10
+ centerLabel: string;
11
+ trackColor?: string;
12
+ ariaLabel?: string | undefined;
13
+ }
14
+
15
+ let {
16
+ size = 96,
17
+ segments = [],
18
+ centerValue,
19
+ centerLabel,
20
+ trackColor = 'rgba(255,255,255,0.06)',
21
+ ariaLabel = undefined
22
+ }: Props = $props();
9
23
 
10
- $: total = segments.reduce((s, x) => s + x.value, 0) || 1;
11
- $: r = (size - 20) / 2;
12
- $: c = 2 * Math.PI * r;
13
- $: segDesc = segments.map((s) => `${s.label} ${Math.round((s.value / total) * 100)}%`).join(', ');
14
- $: label = ariaLabel ?? `${centerValue} ${centerLabel}${segDesc ? `: ${segDesc}` : ''}`;
15
- $: arcs = (() => {
24
+ let total = $derived(segments.reduce((s, x) => s + x.value, 0) || 1);
25
+ let r = $derived((size - 20) / 2);
26
+ let c = $derived(2 * Math.PI * r);
27
+ let segDesc = $derived(segments.map((s) => `${s.label} ${Math.round((s.value / total) * 100)}%`).join(', '));
28
+ let label = $derived(ariaLabel ?? `${centerValue} ${centerLabel}${segDesc ? `: ${segDesc}` : ''}`);
29
+ let arcs = $derived((() => {
16
30
  let cum = 0;
17
31
  return segments.map((seg) => {
18
32
  const frac = seg.value / total;
@@ -21,7 +35,7 @@
21
35
  cum += frac;
22
36
  return { ...seg, offset, rotate };
23
37
  });
24
- })();
38
+ })());
25
39
  </script>
26
40
 
27
41
  <div role="img" aria-label={label} style="position:relative;width:{size}px;height:{size}px;flex-shrink:0;">
@@ -1,18 +1,33 @@
1
- <script lang="ts">
1
+ <script module lang="ts">
2
2
  export interface DotPlotItem {
3
3
  label: string;
4
4
  value: number;
5
5
  compare?: number;
6
6
  color?: string;
7
7
  }
8
+ </script>
9
+
10
+ <script lang="ts">
11
+
12
+ interface Props {
13
+ items?: DotPlotItem[];
14
+ min?: number;
15
+ max?: number | undefined;
16
+ unit?: string;
17
+ valueLegend?: string | undefined;
18
+ compareLegend?: string | undefined;
19
+ ariaLabel?: string;
20
+ }
8
21
 
9
- export let items: DotPlotItem[] = [];
10
- export let min: number = 0;
11
- export let max: number | undefined = undefined;
12
- export let unit: string = '';
13
- export let valueLegend: string | undefined = undefined;
14
- export let compareLegend: string | undefined = undefined;
15
- export let ariaLabel: string = 'Dot plot';
22
+ let {
23
+ items = [],
24
+ min = 0,
25
+ max = undefined,
26
+ unit = '',
27
+ valueLegend = undefined,
28
+ compareLegend = undefined,
29
+ ariaLabel = 'Dot plot'
30
+ }: Props = $props();
16
31
 
17
32
  const VW = 380;
18
33
  const LABEL_W = 132;
@@ -26,16 +41,16 @@
26
41
  const LEG_H = 18;
27
42
  const TICKS = 5;
28
43
 
29
- $: hasCompare = items.some((it) => it.compare !== undefined);
30
- $: maxVal = max ?? Math.max(...items.map((it) => Math.max(it.value, it.compare ?? 0)));
31
- $: range = Math.max(maxVal - min, 1);
32
- $: svgH =
33
- PAD_T +
44
+ let hasCompare = $derived(items.some((it) => it.compare !== undefined));
45
+ let maxVal = $derived(max ?? Math.max(...items.map((it) => Math.max(it.value, it.compare ?? 0))));
46
+ let range = $derived(Math.max(maxVal - min, 1));
47
+ let svgH =
48
+ $derived(PAD_T +
34
49
  items.length * ROW_H +
35
50
  AXIS_H +
36
- (hasCompare && (valueLegend || compareLegend) ? LEG_H + 4 : 0);
37
- $: ticks = Array.from({ length: TICKS }, (_, i) => min + (i / (TICKS - 1)) * range);
38
- $: legY = PAD_T + items.length * ROW_H + AXIS_H + 4;
51
+ (hasCompare && (valueLegend || compareLegend) ? LEG_H + 4 : 0));
52
+ let ticks = $derived(Array.from({ length: TICKS }, (_, i) => min + (i / (TICKS - 1)) * range));
53
+ let legY = $derived(PAD_T + items.length * ROW_H + AXIS_H + 4);
39
54
 
40
55
  function tx(v: number): number {
41
56
  return LABEL_W + ((v - min) / range) * TRACK_W;
@@ -2,25 +2,32 @@
2
2
  import { tick } from 'svelte';
3
3
  import IconButton from './IconButton.svelte';
4
4
  import CloseIcon from '../icons/CloseIcon.svelte';
5
- export let open: boolean = false;
6
- export let title: string;
5
+ interface Props {
6
+ open?: boolean;
7
+ title: string;
8
+ children?: import('svelte').Snippet;
9
+ }
10
+
11
+ let { open = $bindable(false), title, children }: Props = $props();
7
12
  const titleId = `drawer-title-${Math.random().toString(36).slice(2, 9)}`;
8
13
  const FOCUSABLE =
9
14
  'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
10
- let panelEl: HTMLDivElement;
11
- let prev: HTMLElement | null = null;
12
- let wasOpen = false;
13
- $: if (open && !wasOpen) {
14
- prev = typeof document !== 'undefined' ? (document.activeElement as HTMLElement | null) : null;
15
- wasOpen = true;
16
- tick().then(() => {
17
- const first = panelEl?.querySelector<HTMLElement>(FOCUSABLE);
18
- (first ?? panelEl)?.focus();
19
- });
20
- } else if (!open && wasOpen) {
21
- wasOpen = false;
22
- prev?.focus?.();
23
- }
15
+ let panelEl = $state<HTMLDivElement | undefined>(undefined);
16
+ let prev: HTMLElement | null = $state(null);
17
+ let wasOpen = $state(false);
18
+ $effect(() => {
19
+ if (open && !wasOpen) {
20
+ prev = typeof document !== 'undefined' ? (document.activeElement as HTMLElement | null) : null;
21
+ wasOpen = true;
22
+ tick().then(() => {
23
+ const first = panelEl?.querySelector<HTMLElement>(FOCUSABLE);
24
+ (first ?? panelEl)?.focus();
25
+ });
26
+ } else if (!open && wasOpen) {
27
+ wasOpen = false;
28
+ prev?.focus?.();
29
+ }
30
+ });
24
31
  function onKeydown(e: KeyboardEvent) {
25
32
  if (!open) return;
26
33
  if (e.key === 'Escape') { open = false; return; }
@@ -34,14 +41,14 @@
34
41
  }
35
42
  </script>
36
43
 
37
- <svelte:window on:keydown={onKeydown} />
44
+ <svelte:window onkeydown={onKeydown} />
38
45
 
39
46
  <div
40
47
  class="drawer-overlay {open ? 'show' : ''}"
41
- on:click={() => (open = false)}
48
+ onclick={() => (open = false)}
42
49
  aria-hidden="true"
43
50
  role="presentation"
44
- />
51
+ ></div>
45
52
  <div
46
53
  bind:this={panelEl}
47
54
  class="drawer-panel {open ? 'show' : ''}"
@@ -52,9 +59,9 @@
52
59
  >
53
60
  <div class="drawer-h">
54
61
  <h2 id={titleId}>{title}</h2>
55
- <IconButton title="Close" on:click={() => (open = false)}>
62
+ <IconButton title="Close" onclick={() => (open = false)}>
56
63
  <CloseIcon />
57
64
  </IconButton>
58
65
  </div>
59
- <div class="drawer-b"><slot /></div>
66
+ <div class="drawer-b">{@render children?.()}</div>
60
67
  </div>