@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,6 +1,4 @@
1
- <script lang="ts">
2
- import { afterUpdate } from 'svelte';
3
-
1
+ <script module lang="ts">
4
2
  export interface LogEntry {
5
3
  id?: string;
6
4
  timestamp: string;
@@ -10,15 +8,28 @@
10
8
  subject?: string;
11
9
  detail?: string;
12
10
  }
11
+ </script>
12
+
13
+ <script lang="ts">
14
+ interface Props {
15
+ entries?: LogEntry[];
16
+ height?: number;
17
+ defaultFollow?: boolean;
18
+ ariaLabel?: string;
19
+ className?: string;
20
+ }
13
21
 
14
- export let entries: LogEntry[] = [];
15
- export let height: number = 360;
16
- export let defaultFollow: boolean = true;
17
- export let ariaLabel: string = 'Log entries';
18
- export let className: string = '';
22
+ let {
23
+ entries = [],
24
+ height = 360,
25
+ defaultFollow = true,
26
+ ariaLabel = 'Log entries',
27
+ className = '',
28
+ }: Props = $props();
19
29
 
20
- let follow = defaultFollow;
21
- let bodyEl: HTMLDivElement;
30
+ // svelte-ignore state_referenced_locally
31
+ let follow = $state(defaultFollow);
32
+ let bodyEl = $state<HTMLDivElement | undefined>(undefined);
22
33
 
23
34
  const SEV_DOT: Record<string, string> = {
24
35
  error: '#F03A3A',
@@ -27,7 +38,11 @@
27
38
  debug: '#4A4B53',
28
39
  };
29
40
 
30
- afterUpdate(() => {
41
+ // Replaces `afterUpdate`: `$effect` runs after every DOM commit triggered
42
+ // by reactive dependencies. Reading `entries` ensures we re-scroll on
43
+ // every new batch.
44
+ $effect(() => {
45
+ void entries.length;
31
46
  if (follow && bodyEl) bodyEl.scrollTop = bodyEl.scrollHeight;
32
47
  });
33
48
  </script>
@@ -38,7 +53,7 @@
38
53
  <button
39
54
  type="button"
40
55
  class="lv__follow{follow ? ' lv__follow--on' : ''}"
41
- on:click={() => { follow = !follow; }}
56
+ onclick={() => { follow = !follow; }}
42
57
  aria-pressed={follow}
43
58
  >Follow</button>
44
59
  </div>
@@ -1,14 +1,26 @@
1
- <script lang="ts">
1
+ <script module lang="ts">
2
2
  export interface LollipopItem {
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
+ items?: LollipopItem[];
13
+ unit?: string;
14
+ color?: string;
15
+ ariaLabel?: string;
16
+ }
7
17
 
8
- export let items: LollipopItem[] = [];
9
- export let unit: string = '';
10
- export let color: string = '#006FFF';
11
- export let ariaLabel: string = 'Lollipop chart';
18
+ let {
19
+ items = [],
20
+ unit = '',
21
+ color = '#006FFF',
22
+ ariaLabel = 'Lollipop chart'
23
+ }: Props = $props();
12
24
 
13
25
  const VW = 340;
14
26
  const LABEL_W = 110;
@@ -21,9 +33,9 @@
21
33
  const AXIS_H = 18;
22
34
  const TICKS = 4;
23
35
 
24
- $: maxVal = Math.max(...items.map((it) => it.value), 1);
25
- $: svgH = PAD_T + items.length * ROW_H + AXIS_H;
26
- $: ticks = Array.from({ length: TICKS + 1 }, (_, i) => Math.round((i / TICKS) * maxVal));
36
+ let maxVal = $derived(Math.max(...items.map((it) => it.value), 1));
37
+ let svgH = $derived(PAD_T + items.length * ROW_H + AXIS_H);
38
+ let ticks = $derived(Array.from({ length: TICKS + 1 }, (_, i) => Math.round((i / TICKS) * maxVal)));
27
39
 
28
40
  function tx(v: number): number {
29
41
  return LABEL_W + (v / maxVal) * TRACK_W;
@@ -1,17 +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
- import { createEventDispatcher } from 'svelte';
6
+
7
7
 
8
- export let label: string | undefined = undefined;
9
- export let value: string = '00:00:00:00:00:00';
10
- export let disabled: boolean = false;
11
- let className = '';
12
- export { className as class };
8
+ interface Props {
9
+ label?: string | undefined;
10
+ value?: string;
11
+ disabled?: boolean;
12
+ class?: string;
13
+ onchange?: (payload: string) => void;
14
+ }
13
15
 
14
- const dispatch = createEventDispatcher<{ change: string }>();
16
+ let {
17
+ label = undefined,
18
+ value = $bindable('00:00:00:00:00:00'),
19
+ disabled = false,
20
+ class: className = '',
21
+ onchange,
22
+ }: Props = $props();
15
23
  const uid = `dash-ui-mac-${++counter}`;
16
24
 
17
25
  const HEX_RE = /^[0-9a-fA-F]{0,2}$/;
@@ -25,8 +33,8 @@
25
33
  ];
26
34
  }
27
35
 
28
- let pairs: [string, string, string, string, string, string] = parseMAC(value);
29
- let inputs: (HTMLInputElement | null)[] = [null, null, null, null, null, null];
36
+ let pairs: [string, string, string, string, string, string] = $state(parseMAC(value));
37
+ let inputs: (HTMLInputElement | null)[] = $state([null, null, null, null, null, null]);
30
38
 
31
39
  function focusAt(i: number) {
32
40
  const el = inputs[i];
@@ -38,7 +46,7 @@
38
46
  pairs[i] = raw.toUpperCase();
39
47
  pairs = pairs as [string, string, string, string, string, string];
40
48
  value = pairs.join(':');
41
- dispatch('change', value);
49
+ onchange?.(value);
42
50
  if (raw.length === 2 && i < 5) setTimeout(() => focusAt(i + 1), 0);
43
51
  }
44
52
 
@@ -63,7 +71,7 @@
63
71
  const normalized = text.replace(/-/g, ':').replace(/:/g, '').match(/.{1,2}/g)?.join(':') ?? text;
64
72
  pairs = normalized.split(':').map((p) => p.toUpperCase()) as [string, string, string, string, string, string];
65
73
  value = pairs.join(':');
66
- dispatch('change', value);
74
+ onchange?.(value);
67
75
  setTimeout(() => focusAt(5), 0);
68
76
  }
69
77
  }
@@ -85,10 +93,10 @@
85
93
  {disabled}
86
94
  maxlength={2}
87
95
  class="mac-input__pair"
88
- on:input={(e) => commitPair(i, e.currentTarget.value)}
89
- on:keydown={(e) => handleKey(i, e)}
90
- on:paste={handlePaste}
91
- on:focus={(e) => e.currentTarget.select()}
96
+ oninput={(e) => commitPair(i, e.currentTarget.value)}
97
+ onkeydown={(e) => handleKey(i, e)}
98
+ onpaste={handlePaste}
99
+ onfocus={(e) => e.currentTarget.select()}
92
100
  />
93
101
  {#if i < 5}
94
102
  <span class="mac-input__colon" aria-hidden="true">:</span>
@@ -1,18 +1,25 @@
1
- <script lang="ts">
1
+ <script module lang="ts">
2
2
  export interface MarimekkoSegment {
3
3
  label: string;
4
4
  value: number;
5
5
  color?: string;
6
6
  }
7
-
8
7
  export interface MarimekkoColumn {
9
8
  label: string;
10
9
  segments: MarimekkoSegment[];
11
10
  }
11
+ </script>
12
+
13
+ <script lang="ts">
14
+
15
+
16
+ interface Props {
17
+ columns: MarimekkoColumn[];
18
+ height?: number;
19
+ ariaLabel?: string;
20
+ }
12
21
 
13
- export let columns: MarimekkoColumn[];
14
- export let height = 160;
15
- export let ariaLabel = 'Marimekko chart';
22
+ let { columns, height = 160, ariaLabel = 'Marimekko chart' }: Props = $props();
16
23
 
17
24
  const PALETTE = ['#006FFF', '#00C875', '#F5A623', '#A78BFA', '#FF7B7B', '#00C8C8', '#FB923C'];
18
25
  const VW = 340;
@@ -22,7 +29,7 @@
22
29
  interface Cell { x: number; y: number; w: number; h: number; color: string; label: string; }
23
30
  interface Header { x: number; w: number; label: string; }
24
31
 
25
- $: layout = (() => {
32
+ let layout = $derived((() => {
26
33
  const colTotals = columns.map(col => col.segments.reduce((s, seg) => s + seg.value, 0));
27
34
  const grandTotal = colTotals.reduce((s, t) => s + t, 0);
28
35
  if (grandTotal === 0) return { cells: [] as Cell[], headers: [] as Header[] };
@@ -50,7 +57,7 @@
50
57
  cx += colW;
51
58
  });
52
59
  return { cells, headers };
53
- })();
60
+ })());
54
61
  </script>
55
62
 
56
63
  {#if layout.cells.length > 0}
@@ -1,9 +1,19 @@
1
1
  <script lang="ts">
2
- export let rows: string[] = [];
3
- export let cols: string[] = [];
4
- export let values: number[][] = [];
5
- export let unit = '';
6
- export let ariaLabel = 'Matrix chart';
2
+ interface Props {
3
+ rows?: string[];
4
+ cols?: string[];
5
+ values?: number[][];
6
+ unit?: string;
7
+ ariaLabel?: string;
8
+ }
9
+
10
+ let {
11
+ rows = [],
12
+ cols = [],
13
+ values = [],
14
+ unit = '',
15
+ ariaLabel = 'Matrix chart'
16
+ }: Props = $props();
7
17
 
8
18
  const LEFT = 80;
9
19
  const TOP = 60;
@@ -19,10 +29,10 @@
19
29
  return String(n);
20
30
  }
21
31
 
22
- $: allVals = values.flat();
23
- $: max = Math.max(...allVals, 1);
24
- $: W = LEFT + cols.length * CELL;
25
- $: H = TOP + rows.length * CELL;
32
+ let allVals = $derived(values.flat());
33
+ let max = $derived(Math.max(...allVals, 1));
34
+ let W = $derived(LEFT + cols.length * CELL);
35
+ let H = $derived(TOP + rows.length * CELL);
26
36
  </script>
27
37
 
28
38
  <div role="img" aria-label={ariaLabel} style="width:100%;">
@@ -1,28 +1,35 @@
1
- <script context="module" lang="ts">
1
+ <script module lang="ts">
2
2
  let counter = 0;
3
3
  export interface MenubarItem { id: string; label: string; disabled?: boolean; separator?: boolean; }
4
4
  export interface MenubarMenu { id: string; label: string; items: MenubarItem[]; }
5
5
  </script>
6
6
 
7
7
  <script lang="ts">
8
- import { createEventDispatcher, onMount, onDestroy } from 'svelte';
8
+ import { onMount, onDestroy } from 'svelte';
9
9
 
10
- export let menus: MenubarMenu[] = [];
11
- export let label: string = 'Menu';
12
- let klass = '';
13
- export { klass as class };
10
+ interface Props {
11
+ menus?: MenubarMenu[];
12
+ label?: string;
13
+ class?: string;
14
+ onaction?: (payload: { menuId: string; itemId: string }) => void;
15
+ }
14
16
 
15
- const dispatch = createEventDispatcher<{ action: { menuId: string; itemId: string } }>();
17
+ let {
18
+ menus = [],
19
+ label = 'Menu',
20
+ class: klass = '',
21
+ onaction,
22
+ }: Props = $props();
16
23
  const uid = `dash-ui-mb-${++counter}`;
17
24
 
18
- let openIdx: number | null = null;
19
- let activeItemIdx = 0;
20
- let triggerEls: HTMLButtonElement[] = [];
21
- let rootEl: HTMLDivElement;
25
+ let openIdx: number | null = $state(null);
26
+ let activeItemIdx = $state(0);
27
+ let triggerEls: HTMLButtonElement[] = $state([]);
28
+ let rootEl = $state<HTMLDivElement | undefined>(undefined);
22
29
 
23
- $: currentEligible = openIdx !== null
30
+ let currentEligible = $derived(openIdx !== null
24
31
  ? menus[openIdx].items.filter((i) => !i.separator && !i.disabled)
25
- : [];
32
+ : []);
26
33
 
27
34
  function openMenu(idx: number, focusLast = false) {
28
35
  const items = menus[idx].items.filter((i) => !i.separator && !i.disabled);
@@ -33,7 +40,7 @@
33
40
  function closeMenu() { openIdx = null; }
34
41
 
35
42
  function activate(menuId: string, itemId: string) {
36
- dispatch('action', { menuId, itemId });
43
+ onaction?.({ menuId, itemId });
37
44
  openIdx = null;
38
45
  }
39
46
 
@@ -101,8 +108,8 @@
101
108
  aria-expanded={isOpen}
102
109
  aria-controls={isOpen ? menuId : undefined}
103
110
  class={`menubar-trigger${isOpen ? ' is-open' : ''}`}
104
- on:click={() => { if (isOpen) closeMenu(); else openMenu(idx); }}
105
- on:keydown={(e) => handleTriggerKeyDown(e, idx)}
111
+ onclick={() => { if (isOpen) closeMenu(); else openMenu(idx); }}
112
+ onkeydown={(e) => handleTriggerKeyDown(e, idx)}
106
113
  >
107
114
  {menu.label}
108
115
  </button>
@@ -110,7 +117,7 @@
110
117
  <ul id={menuId} role="menu" aria-label={menu.label} class="menubar-dropdown">
111
118
  {#each menu.items as item (item.id)}
112
119
  {#if item.separator}
113
- <li role="separator" class="menubar-sep" aria-hidden="true" />
120
+ <li role="separator" class="menubar-sep" aria-hidden="true"></li>
114
121
  {:else}
115
122
  {@const eligIdx = elig.indexOf(item)}
116
123
  <li
@@ -119,8 +126,8 @@
119
126
  aria-disabled={item.disabled}
120
127
  data-active={eligIdx === activeItemIdx && !item.disabled ? 'true' : undefined}
121
128
  class="menubar-item"
122
- on:mouseenter={() => { if (!item.disabled) activeItemIdx = eligIdx; }}
123
- on:mousedown|preventDefault={() => { if (!item.disabled) activate(menu.id, item.id); }}
129
+ onmouseenter={() => { if (!item.disabled) activeItemIdx = eligIdx; }}
130
+ onmousedown={(e) => { e.preventDefault(); (() => { if (!item.disabled) activate(menu.id, item.id); })(); }}
124
131
  >{item.label}</li>
125
132
  {/if}
126
133
  {/each}
@@ -1,17 +1,32 @@
1
- <script lang="ts">
1
+ <script module lang="ts">
2
2
  export interface MirroredBarItem {
3
3
  label: string;
4
4
  left: number;
5
5
  right: number;
6
6
  }
7
+ </script>
8
+
9
+ <script lang="ts">
10
+
11
+ interface Props {
12
+ items?: MirroredBarItem[];
13
+ leftLabel?: string;
14
+ rightLabel?: string;
15
+ leftColor?: string;
16
+ rightColor?: string;
17
+ unit?: string;
18
+ ariaLabel?: string;
19
+ }
7
20
 
8
- export let items: MirroredBarItem[] = [];
9
- export let leftLabel: string = 'Download';
10
- export let rightLabel: string = 'Upload';
11
- export let leftColor: string = '#006FFF';
12
- export let rightColor: string = '#00C8C8';
13
- export let unit: string = '';
14
- export let ariaLabel: string = 'Mirrored bar chart';
21
+ let {
22
+ items = [],
23
+ leftLabel = 'Download',
24
+ rightLabel = 'Upload',
25
+ leftColor = '#006FFF',
26
+ rightColor = '#00C8C8',
27
+ unit = '',
28
+ ariaLabel = 'Mirrored bar chart'
29
+ }: Props = $props();
15
30
 
16
31
  const VW = 340;
17
32
  const LABEL_W = 80;
@@ -21,8 +36,8 @@
21
36
  const HALF_W = (VW - LABEL_W) / 2;
22
37
  const CX = VW / 2;
23
38
 
24
- $: svgH = PAD_T + items.length * ROW_H + PAD_B;
25
- $: maxVal = Math.max(...items.flatMap((it) => [it.left, it.right]), 1);
39
+ let svgH = $derived(PAD_T + items.length * ROW_H + PAD_B);
40
+ let maxVal = $derived(Math.max(...items.flatMap((it) => [it.left, it.right]), 1));
26
41
 
27
42
  function bw(val: number): number {
28
43
  return (val / maxVal) * HALF_W;
@@ -2,36 +2,49 @@
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
+ footer?: import('svelte').Snippet;
10
+ }
11
+
12
+ let {
13
+ open = $bindable(false),
14
+ title,
15
+ children,
16
+ footer
17
+ }: Props = $props();
7
18
  const titleId = `modal-title-${Math.random().toString(36).slice(2, 9)}`;
8
19
  const FOCUSABLE =
9
20
  'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
10
- let modalEl: HTMLDivElement;
11
- let previouslyFocused: HTMLElement | null = null;
12
- let prevOverflow = '';
13
- let wasOpen = false;
14
- let downOnBackdrop = false;
15
- $: if (open && !wasOpen) {
16
- previouslyFocused = (typeof document !== 'undefined'
17
- ? (document.activeElement as HTMLElement | null)
18
- : null);
19
- if (typeof document !== 'undefined') {
20
- prevOverflow = document.body.style.overflow;
21
- document.body.style.overflow = 'hidden';
21
+ let modalEl = $state<HTMLDivElement | undefined>(undefined);
22
+ let previouslyFocused: HTMLElement | null = $state(null);
23
+ let prevOverflow = $state('');
24
+ let wasOpen = $state(false);
25
+ let downOnBackdrop = $state(false);
26
+ $effect(() => {
27
+ if (open && !wasOpen) {
28
+ previouslyFocused = (typeof document !== 'undefined'
29
+ ? (document.activeElement as HTMLElement | null)
30
+ : null);
31
+ if (typeof document !== 'undefined') {
32
+ prevOverflow = document.body.style.overflow;
33
+ document.body.style.overflow = 'hidden';
34
+ }
35
+ wasOpen = true;
36
+ tick().then(() => {
37
+ const first = modalEl?.querySelector<HTMLElement>(FOCUSABLE);
38
+ (first ?? modalEl)?.focus();
39
+ });
40
+ } else if (!open && wasOpen) {
41
+ wasOpen = false;
42
+ if (typeof document !== 'undefined') {
43
+ document.body.style.overflow = prevOverflow;
44
+ }
45
+ previouslyFocused?.focus?.();
22
46
  }
23
- wasOpen = true;
24
- tick().then(() => {
25
- const first = modalEl?.querySelector<HTMLElement>(FOCUSABLE);
26
- (first ?? modalEl)?.focus();
27
- });
28
- } else if (!open && wasOpen) {
29
- wasOpen = false;
30
- if (typeof document !== 'undefined') {
31
- document.body.style.overflow = prevOverflow;
32
- }
33
- previouslyFocused?.focus?.();
34
- }
47
+ });
35
48
  function onKeydown(e: KeyboardEvent) {
36
49
  if (!open) return;
37
50
  if (e.key === 'Escape') {
@@ -57,12 +70,12 @@
57
70
  }
58
71
  </script>
59
72
 
60
- <svelte:window on:keydown={onKeydown} />
73
+ <svelte:window onkeydown={onKeydown} />
61
74
 
62
75
  <div
63
76
  class="backdrop {open ? 'show' : ''}"
64
- on:mousedown={(e) => (downOnBackdrop = e.target === e.currentTarget)}
65
- on:click={(e) => {
77
+ onmousedown={(e) => (downOnBackdrop = e.target === e.currentTarget)}
78
+ onclick={(e) => {
66
79
  if (downOnBackdrop && e.target === e.currentTarget) open = false;
67
80
  downOnBackdrop = false;
68
81
  }}
@@ -78,13 +91,13 @@
78
91
  >
79
92
  <div class="modal-h">
80
93
  <h2 id={titleId}>{title}</h2>
81
- <IconButton title="Close" on:click={() => (open = false)}>
94
+ <IconButton title="Close" onclick={() => (open = false)}>
82
95
  <CloseIcon />
83
96
  </IconButton>
84
97
  </div>
85
- <div class="modal-b"><slot /></div>
86
- {#if $$slots.footer}
87
- <div class="modal-f"><slot name="footer" /></div>
98
+ <div class="modal-b">{@render children?.()}</div>
99
+ {#if footer}
100
+ <div class="modal-f">{@render footer?.()}</div>
88
101
  {/if}
89
102
  </div>
90
103
  </div>