@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,4 +1,4 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  export interface CommandItem {
3
3
  id: string;
4
4
  label: string;
@@ -8,26 +8,32 @@
8
8
  </script>
9
9
 
10
10
  <script lang="ts">
11
- import { createEventDispatcher, tick } from 'svelte';
11
+ import { tick } from 'svelte';
12
12
  import Kbd from './Kbd.svelte';
13
13
 
14
- export let open: boolean = false;
15
- export let items: CommandItem[] = [];
16
- export let placeholder: string = 'Search pages and actions…';
17
-
18
- const dispatch = createEventDispatcher<{ select: string; close: void }>();
14
+ interface Props {
15
+ open?: boolean;
16
+ items?: CommandItem[];
17
+ placeholder?: string;
18
+ onselect?: (payload: string) => void;
19
+ onclose?: () => void;
20
+ }
19
21
 
20
- let query = '';
21
- let activeIdx = 0;
22
- let inputEl: HTMLInputElement;
22
+ let { open = false, items = [], placeholder = 'Search pages and actions…',
23
+ onselect,
24
+ onclose,
25
+ }: Props = $props();
26
+ let query = $state('');
27
+ let activeIdx = $state(0);
28
+ let inputEl = $state<HTMLInputElement | undefined>(undefined);
23
29
  const listboxId = `cp-list-${Math.random().toString(36).slice(2)}`;
24
30
 
25
- $: filtered =
26
- query.trim() === ''
31
+ let filtered =
32
+ $derived(query.trim() === ''
27
33
  ? items
28
- : items.filter((i) => i.label.toLowerCase().includes(query.toLowerCase()));
34
+ : items.filter((i) => i.label.toLowerCase().includes(query.toLowerCase())));
29
35
 
30
- $: grouped = filtered.reduce(
36
+ let grouped = $derived(filtered.reduce(
31
37
  (acc, item) => {
32
38
  const g = item.group ?? '';
33
39
  const found = acc.find((a: { group: string }) => a.group === g);
@@ -36,15 +42,19 @@
36
42
  return acc;
37
43
  },
38
44
  [] as { group: string; items: CommandItem[] }[],
39
- );
45
+ ));
40
46
 
41
- $: if (open) {
42
- query = '';
43
- activeIdx = 0;
44
- tick().then(() => inputEl?.focus());
45
- }
47
+ $effect(() => {
48
+ if (open) {
49
+ query = '';
50
+ activeIdx = 0;
51
+ tick().then(() => inputEl?.focus());
52
+ }
53
+ });
46
54
 
47
- $: if (query !== undefined) activeIdx = 0;
55
+ $effect(() => {
56
+ if (query !== undefined) activeIdx = 0;
57
+ });
48
58
 
49
59
  function handleKey(e: KeyboardEvent) {
50
60
  if (e.key === 'ArrowDown') {
@@ -59,24 +69,24 @@
59
69
  if (item) commit(item.id);
60
70
  } else if (e.key === 'Escape') {
61
71
  e.preventDefault();
62
- dispatch('close');
72
+ onclose?.();
63
73
  }
64
74
  }
65
75
 
66
76
  function commit(id: string) {
67
- dispatch('select', id);
68
- dispatch('close');
77
+ onselect?.(id);
78
+ onclose?.();
69
79
  query = '';
70
80
  }
71
81
 
72
82
  function handleBackdrop(e: MouseEvent) {
73
- if (e.target === e.currentTarget) dispatch('close');
83
+ if (e.target === e.currentTarget) onclose?.();
74
84
  }
75
85
  </script>
76
86
 
77
87
  {#if open}
78
- <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
79
- <div class="cp-backdrop" role="presentation" on:click={handleBackdrop} on:keydown={handleKey}>
88
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
89
+ <div class="cp-backdrop" role="presentation" onclick={handleBackdrop} onkeydown={handleKey}>
80
90
  <div
81
91
  role="dialog"
82
92
  aria-modal="true"
@@ -110,7 +120,7 @@
110
120
  aria-controls={listboxId}
111
121
  {placeholder}
112
122
  bind:value={query}
113
- on:keydown={handleKey}
123
+ onkeydown={handleKey}
114
124
  />
115
125
  <span class="cp-kbd">Esc</span>
116
126
  </div>
@@ -125,15 +135,15 @@
125
135
  {/if}
126
136
  {#each groupItems as item}
127
137
  {@const idx = filtered.indexOf(item)}
128
- <!-- svelte-ignore a11y-click-events-have-key-events -->
138
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
129
139
  <div
130
140
  role="option"
131
141
  tabindex="-1"
132
142
  aria-selected={idx === activeIdx}
133
143
  data-active={idx === activeIdx ? 'true' : undefined}
134
144
  class="cp-item"
135
- on:click={() => commit(item.id)}
136
- on:mouseenter={() => (activeIdx = idx)}
145
+ onclick={() => commit(item.id)}
146
+ onmouseenter={() => (activeIdx = idx)}
137
147
  >
138
148
  {item.label}
139
149
  {#if item.shortcut}
@@ -1,16 +1,30 @@
1
1
  <script lang="ts">
2
- import { onDestroy, afterUpdate } from 'svelte';
2
+ import { onDestroy } from 'svelte';
3
3
 
4
- export let open = false;
5
- export let title = '';
6
- export let description: string | undefined = undefined;
7
- export let confirmLabel = 'Confirm';
8
- export let cancelLabel = 'Cancel';
9
- export let variant: 'danger' | 'warning' | 'info' = 'info';
10
- export let onConfirm: () => void = () => {};
11
- export let onCancel: () => void = () => {};
4
+ interface Props {
5
+ open?: boolean;
6
+ title?: string;
7
+ description?: string | undefined;
8
+ confirmLabel?: string;
9
+ cancelLabel?: string;
10
+ variant?: 'danger' | 'warning' | 'info';
11
+ onConfirm?: () => void;
12
+ onCancel?: () => void;
13
+ }
14
+
15
+ let {
16
+ open = false,
17
+ title = '',
18
+ description = undefined,
19
+ confirmLabel = 'Confirm',
20
+ cancelLabel = 'Cancel',
21
+ variant = 'info',
22
+ onConfirm = () => {},
23
+ onCancel = () => {},
24
+ }: Props = $props();
12
25
 
13
- const FOCUSABLE = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
26
+ const FOCUSABLE =
27
+ 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
14
28
 
15
29
  const VARIANT_CLASS: Record<string, string> = {
16
30
  danger: 'btn cd-confirm cd-confirm--danger',
@@ -18,49 +32,66 @@
18
32
  info: 'btn cd-confirm cd-confirm--info',
19
33
  };
20
34
 
21
- let dialogEl: HTMLDivElement;
35
+ let dialogEl = $state<HTMLDivElement | undefined>(undefined);
22
36
  let prev: HTMLElement | null = null;
23
37
  let prevOverflow = '';
24
38
 
25
39
  function onKey(e: KeyboardEvent) {
26
- if (e.key === 'Escape') { onCancel(); return; }
40
+ if (e.key === 'Escape') {
41
+ onCancel();
42
+ return;
43
+ }
27
44
  if (e.key !== 'Tab' || !dialogEl) return;
28
45
  const els = Array.from(dialogEl.querySelectorAll<HTMLElement>(FOCUSABLE));
29
- if (!els.length) { e.preventDefault(); return; }
46
+ if (!els.length) {
47
+ e.preventDefault();
48
+ return;
49
+ }
30
50
  const first = els[0]!;
31
51
  const last = els[els.length - 1]!;
32
52
  const active = document.activeElement;
33
- if (e.shiftKey && active === first) { e.preventDefault(); last.focus(); }
34
- else if (!e.shiftKey && active === last) { e.preventDefault(); first.focus(); }
35
- }
36
-
37
- $: if (open) {
38
- prev = document.activeElement as HTMLElement | null;
39
- prevOverflow = document.body.style.overflow;
40
- document.body.style.overflow = 'hidden';
41
- window.addEventListener('keydown', onKey);
53
+ if (e.shiftKey && active === first) {
54
+ e.preventDefault();
55
+ last.focus();
56
+ } else if (!e.shiftKey && active === last) {
57
+ e.preventDefault();
58
+ first.focus();
59
+ }
42
60
  }
43
61
 
44
- afterUpdate(() => {
45
- if (open && dialogEl) {
46
- const first = dialogEl.querySelector<HTMLElement>(FOCUSABLE);
47
- (first ?? dialogEl).focus();
62
+ // Replaces the old `$: if (open) { ... }` + `afterUpdate` combo. `$effect`
63
+ // runs after the DOM commits, so `dialogEl` is bound before we query it.
64
+ $effect(() => {
65
+ if (open) {
66
+ prev = document.activeElement as HTMLElement | null;
67
+ prevOverflow = document.body.style.overflow;
68
+ document.body.style.overflow = 'hidden';
69
+ window.addEventListener('keydown', onKey);
70
+ if (dialogEl) {
71
+ const firstFocusable = dialogEl.querySelector<HTMLElement>(FOCUSABLE);
72
+ (firstFocusable ?? dialogEl).focus();
73
+ }
74
+ return () => {
75
+ window.removeEventListener('keydown', onKey);
76
+ document.body.style.overflow = prevOverflow;
77
+ prev?.focus?.();
78
+ };
48
79
  }
49
80
  });
50
81
 
51
- $: if (!open) {
52
- window.removeEventListener('keydown', onKey);
53
- document.body.style.overflow = prevOverflow;
54
- prev?.focus?.();
55
- }
56
-
57
82
  onDestroy(() => {
58
83
  window.removeEventListener('keydown', onKey);
59
84
  document.body.style.overflow = prevOverflow;
60
85
  });
61
86
  </script>
62
87
 
63
- <div class="backdrop {open ? 'show' : ''}" role="presentation" on:click={(e) => { if (e.target === e.currentTarget) onCancel(); }}>
88
+ <div
89
+ class="backdrop {open ? 'show' : ''}"
90
+ role="presentation"
91
+ onclick={(e) => {
92
+ if (e.target === e.currentTarget) onCancel();
93
+ }}
94
+ >
64
95
  <div
65
96
  bind:this={dialogEl}
66
97
  class="modal cd-dialog"
@@ -77,8 +108,8 @@
77
108
  <div id="cd-desc" class="cd-body">{description}</div>
78
109
  {/if}
79
110
  <div class="modal-f">
80
- <button type="button" class="btn btn-ghost" on:click={onCancel}>{cancelLabel}</button>
81
- <button type="button" class={VARIANT_CLASS[variant]} on:click={onConfirm}>{confirmLabel}</button>
111
+ <button type="button" class="btn btn-ghost" onclick={onCancel}>{cancelLabel}</button>
112
+ <button type="button" class={VARIANT_CLASS[variant]} onclick={onConfirm}>{confirmLabel}</button>
82
113
  </div>
83
114
  </div>
84
115
  </div>
@@ -1,4 +1,4 @@
1
- <script lang="ts" context="module">
1
+ <script lang="ts" module>
2
2
  export interface ContextMenuItem {
3
3
  id: string;
4
4
  label: string;
@@ -9,36 +9,47 @@
9
9
  </script>
10
10
 
11
11
  <script lang="ts">
12
- import { onDestroy, tick, createEventDispatcher } from 'svelte';
12
+ import { onDestroy, tick } from 'svelte';
13
13
 
14
- export let items: ContextMenuEntry[] = [];
15
- export let x = 0;
16
- export let y = 0;
17
- export let open = false;
18
- export let label = 'Context menu';
19
-
20
- const dispatch = createEventDispatcher<{ close: void; action: string }>();
14
+ interface Props {
15
+ items?: ContextMenuEntry[];
16
+ x?: number;
17
+ y?: number;
18
+ open?: boolean;
19
+ label?: string;
20
+ onclose?: () => void;
21
+ onaction?: (payload: string) => void;
22
+ }
21
23
 
22
- let menuEl: HTMLUListElement;
23
- let activeIdx = 0;
24
+ let {
25
+ items = [],
26
+ x = 0,
27
+ y = 0,
28
+ open = false,
29
+ label = 'Context menu',
30
+ onclose,
31
+ onaction,
32
+ }: Props = $props();
33
+ let menuEl = $state<HTMLUListElement | undefined>(undefined);
34
+ let activeIdx = $state(0);
24
35
 
25
- $: actionItems = items.reduce<ContextMenuItem[]>((acc, e) => {
36
+ let actionItems = $derived(items.reduce<ContextMenuItem[]>((acc, e) => {
26
37
  if (!('separator' in e)) acc.push(e);
27
38
  return acc;
28
- }, []);
39
+ }, []));
29
40
 
30
41
  const menuW = 168;
31
- $: menuH = items.length * 30 + 8;
32
- $: cx = Math.min(x, (typeof window !== 'undefined' ? window.innerWidth : 1200) - menuW - 8);
33
- $: cy = Math.min(y, (typeof window !== 'undefined' ? window.innerHeight : 800) - menuH - 8);
42
+ let menuH = $derived(items.length * 30 + 8);
43
+ let cx = $derived(Math.min(x, (typeof window !== 'undefined' ? window.innerWidth : 1200) - menuW - 8));
44
+ let cy = $derived(Math.min(y, (typeof window !== 'undefined' ? window.innerHeight : 800) - menuH - 8));
34
45
 
35
46
  function activate(id: string) {
36
- dispatch('action', id);
37
- dispatch('close');
47
+ onaction?.(id);
48
+ onclose?.();
38
49
  }
39
50
 
40
51
  function handleKeyDown(e: KeyboardEvent) {
41
- if (e.key === 'Escape') { e.preventDefault(); dispatch('close'); }
52
+ if (e.key === 'Escape') { e.preventDefault(); onclose?.(); }
42
53
  else if (e.key === 'ArrowDown') { e.preventDefault(); activeIdx = Math.min(activeIdx + 1, actionItems.length - 1); }
43
54
  else if (e.key === 'ArrowUp') { e.preventDefault(); activeIdx = Math.max(activeIdx - 1, 0); }
44
55
  else if (e.key === 'Home') { e.preventDefault(); activeIdx = 0; }
@@ -48,20 +59,22 @@
48
59
  const item = actionItems[activeIdx];
49
60
  if (item && !item.disabled) activate(item.id);
50
61
  }
51
- else if (e.key === 'Tab') { dispatch('close'); }
62
+ else if (e.key === 'Tab') { onclose?.(); }
52
63
  }
53
64
 
54
65
  function handleOutside(e: MouseEvent) {
55
- if (!menuEl?.contains(e.target as Node)) dispatch('close');
66
+ if (!menuEl?.contains(e.target as Node)) onclose?.();
56
67
  }
57
68
 
58
- $: if (open) {
59
- activeIdx = 0;
60
- tick().then(() => menuEl?.focus());
61
- document.addEventListener('mousedown', handleOutside);
62
- } else {
63
- document.removeEventListener('mousedown', handleOutside);
64
- }
69
+ $effect(() => {
70
+ if (open) {
71
+ activeIdx = 0;
72
+ tick().then(() => menuEl?.focus());
73
+ document.addEventListener('mousedown', handleOutside);
74
+ } else {
75
+ document.removeEventListener('mousedown', handleOutside);
76
+ }
77
+ });
65
78
 
66
79
  onDestroy(() => {
67
80
  document.removeEventListener('mousedown', handleOutside);
@@ -74,7 +87,7 @@
74
87
  </script>
75
88
 
76
89
  {#if open}
77
- <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
90
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
78
91
  <ul
79
92
  bind:this={menuEl}
80
93
  role="menu"
@@ -82,13 +95,13 @@
82
95
  tabindex="-1"
83
96
  class="ctx-menu"
84
97
  style="left:{cx}px;top:{cy}px"
85
- on:keydown={handleKeyDown}
98
+ onkeydown={handleKeyDown}
86
99
  >
87
100
  {#each items as entry, i (i)}
88
101
  {#if 'separator' in entry}
89
102
  <li role="separator" class="ctx-menu-sep"></li>
90
103
  {:else}
91
- <!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
104
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
92
105
  <li
93
106
  role="menuitem"
94
107
  tabindex="-1"
@@ -96,8 +109,8 @@
96
109
  data-active={actionIndex(entry) === activeIdx ? 'true' : undefined}
97
110
  data-danger={entry.danger || undefined}
98
111
  class="ctx-menu-item"
99
- on:mouseenter={() => (activeIdx = actionIndex(entry))}
100
- on:mousedown|preventDefault={() => { if (!entry.disabled) activate(entry.id); }}
112
+ onmouseenter={() => (activeIdx = actionIndex(entry))}
113
+ onmousedown={(e) => { e.preventDefault(); (() => { if (!entry.disabled) activate(entry.id); })(); }}
101
114
  >
102
115
  {entry.label}
103
116
  </li>
@@ -1,21 +1,25 @@
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
6
  import { onMount, onDestroy, tick } from 'svelte';
7
7
 
8
- export let title: string;
9
- export let body: string;
10
- export let placement: 'top' | 'bottom' = 'top';
8
+ interface Props {
9
+ title: string;
10
+ body: string;
11
+ placement?: 'top' | 'bottom';
12
+ }
13
+
14
+ let { title, body, placement = 'top' }: Props = $props();
11
15
 
12
16
  const uid = `dash-ui-ch-${++counter}`;
13
17
  const titleId = `${uid}-title`;
14
18
 
15
- let open = false;
16
- let rootEl: HTMLSpanElement;
17
- let triggerEl: HTMLButtonElement;
18
- let panelEl: HTMLDivElement;
19
+ let open = $state(false);
20
+ let rootEl = $state<HTMLSpanElement | undefined>(undefined);
21
+ let triggerEl = $state<HTMLButtonElement | undefined>(undefined);
22
+ let panelEl = $state<HTMLDivElement | undefined>(undefined);
19
23
 
20
24
  async function toggle() {
21
25
  open = !open;
@@ -56,7 +60,7 @@
56
60
  aria-label="Help"
57
61
  aria-haspopup="dialog"
58
62
  aria-expanded={open}
59
- on:click={toggle}
63
+ onclick={toggle}
60
64
  >?</button>
61
65
  {#if open}
62
66
  <div
@@ -1,16 +1,31 @@
1
- <script lang="ts">
1
+ <script module lang="ts">
2
2
  export interface ContourPoint {
3
3
  x: number;
4
4
  y: number;
5
5
  }
6
+ </script>
6
7
 
7
- export let points: ContourPoint[] = [];
8
- export let xRange: [number, number] | undefined = undefined;
9
- export let yRange: [number, number] | undefined = undefined;
10
- export let height = 200;
11
- export let bandwidth = 3.5;
12
- export let color = '#006FFF';
13
- export let ariaLabel = 'Contour plot';
8
+ <script lang="ts">
9
+
10
+ interface Props {
11
+ points?: ContourPoint[];
12
+ xRange?: [number, number] | undefined;
13
+ yRange?: [number, number] | undefined;
14
+ height?: number;
15
+ bandwidth?: number;
16
+ color?: string;
17
+ ariaLabel?: string;
18
+ }
19
+
20
+ let {
21
+ points = [],
22
+ xRange = undefined,
23
+ yRange = undefined,
24
+ height = 200,
25
+ bandwidth = 3.5,
26
+ color = '#006FFF',
27
+ ariaLabel = 'Contour plot'
28
+ }: Props = $props();
14
29
 
15
30
  const VW = 340;
16
31
  const PAD_L = 28;
@@ -78,34 +93,34 @@
78
93
  return [];
79
94
  }
80
95
 
81
- $: PW = VW - PAD_L - PAD_R;
82
- $: PH = height - PAD_T - PAD_B;
83
- $: xs = points.map((p) => p.x);
84
- $: ys = points.map((p) => p.y);
85
- $: xMin = xRange ? xRange[0] : (xs.length ? Math.min(...xs) : 0);
86
- $: xMax = xRange ? xRange[1] : (xs.length ? Math.max(...xs) : 1);
87
- $: yMin = yRange ? yRange[0] : (ys.length ? Math.min(...ys) : 0);
88
- $: yMax = yRange ? yRange[1] : (ys.length ? Math.max(...ys) : 1);
89
- $: xSpan = xMax - xMin || 1;
90
- $: ySpan = yMax - yMin || 1;
91
-
92
- $: gridPts = points.map((p) => ({
96
+ let PW = $derived(VW - PAD_L - PAD_R);
97
+ let PH = $derived(height - PAD_T - PAD_B);
98
+ let xs = $derived(points.map((p) => p.x));
99
+ let ys = $derived(points.map((p) => p.y));
100
+ let xMin = $derived(xRange ? xRange[0] : (xs.length ? Math.min(...xs) : 0));
101
+ let xMax = $derived(xRange ? xRange[1] : (xs.length ? Math.max(...xs) : 1));
102
+ let yMin = $derived(yRange ? yRange[0] : (ys.length ? Math.min(...ys) : 0));
103
+ let yMax = $derived(yRange ? yRange[1] : (ys.length ? Math.max(...ys) : 1));
104
+ let xSpan = $derived(xMax - xMin || 1);
105
+ let ySpan = $derived(yMax - yMin || 1);
106
+
107
+ let gridPts = $derived(points.map((p) => ({
93
108
  gx: ((p.x - xMin) / xSpan) * GW,
94
109
  gy: (1 - (p.y - yMin) / ySpan) * GH,
95
- }));
96
- $: grid = buildGrid(gridPts, bandwidth);
97
- $: cellW = PW / GW;
98
- $: cellH = PH / GH;
110
+ })));
111
+ let grid = $derived(buildGrid(gridPts, bandwidth));
112
+ let cellW = $derived(PW / GW);
113
+ let cellH = $derived(PH / GH);
99
114
 
100
115
  function svgX(col: number, lx: number): number { return PAD_L + (col + lx) * cellW; }
101
116
  function svgY(row: number, ly: number): number { return PAD_T + (row + ly) * cellH; }
102
117
  function tyY(v: number): number { return PAD_T + (1 - (v - yMin) / ySpan) * PH; }
103
118
  function txX(v: number): number { return PAD_L + ((v - xMin) / xSpan) * PW; }
104
119
 
105
- $: yTicks = [yMin, (yMin + yMax) / 2, yMax];
106
- $: xTicks = [xMin, (xMin + xMax) / 2, xMax];
120
+ let yTicks = $derived([yMin, (yMin + yMax) / 2, yMax]);
121
+ let xTicks = $derived([xMin, (xMin + xMax) / 2, xMax]);
107
122
 
108
- $: levelLines = LEVELS.map((t, li) => {
123
+ let levelLines = $derived(LEVELS.map((t, li) => {
109
124
  const opacity = 0.28 + li * 0.18;
110
125
  const sw = 0.55 + li * 0.28;
111
126
  const lines: Array<{ key: string; x1: number; y1: number; x2: number; y2: number }> = [];
@@ -125,7 +140,7 @@
125
140
  }
126
141
  }
127
142
  return { opacity, sw, lines };
128
- });
143
+ }));
129
144
  </script>
130
145
 
131
146
  {#if points.length > 0}
@@ -1,8 +1,12 @@
1
1
  <script lang="ts">
2
- export let text: string;
3
- export let label: string = 'Copy';
2
+ interface Props {
3
+ text: string;
4
+ label?: string;
5
+ }
6
+
7
+ let { text, label = 'Copy' }: Props = $props();
4
8
 
5
- let copied = false;
9
+ let copied = $state(false);
6
10
  let timer: ReturnType<typeof setTimeout>;
7
11
 
8
12
  function handleCopy() {
@@ -18,7 +22,7 @@
18
22
  type="button"
19
23
  class="copy-btn {copied ? 'copy-btn--done' : ''}"
20
24
  aria-label={copied ? 'Copied!' : label}
21
- on:click={handleCopy}
25
+ onclick={handleCopy}
22
26
  >
23
27
  {#if copied}
24
28
  <svg viewBox="0 0 14 14" width="14" height="14" fill="none" aria-hidden="true" focusable="false">
@@ -1,8 +1,17 @@
1
1
  <script lang="ts">
2
- export let labels: string[] = [];
3
- export let data: number[][] = [];
4
- export let cellSize: number = 52;
5
- export let ariaLabel: string = 'Correlation matrix';
2
+ interface Props {
3
+ labels?: string[];
4
+ data?: number[][];
5
+ cellSize?: number;
6
+ ariaLabel?: string;
7
+ }
8
+
9
+ let {
10
+ labels = [],
11
+ data = [],
12
+ cellSize = 52,
13
+ ariaLabel = 'Correlation matrix'
14
+ }: Props = $props();
6
15
 
7
16
  const LABEL_W = 68;
8
17
  const LABEL_H = 26;
@@ -25,9 +34,9 @@
25
34
  return `rgb(${lerp(r0, r1, t)},${lerp(g0, g1, t)},${lerp(b0, b1, t)})`;
26
35
  }
27
36
 
28
- $: n = labels.length;
29
- $: svgW = LABEL_W + n * cellSize;
30
- $: svgH = LABEL_H + n * cellSize;
37
+ let n = $derived(labels.length);
38
+ let svgW = $derived(LABEL_W + n * cellSize);
39
+ let svgH = $derived(LABEL_H + n * cellSize);
31
40
  </script>
32
41
 
33
42
  <div role="img" aria-label={ariaLabel} style="width:100%;">