@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.
- package/package.json +6 -6
- package/src/lib/components/Accordion.svelte +9 -1
- package/src/lib/components/AccordionItem.svelte +11 -5
- package/src/lib/components/ActionMenu.svelte +19 -14
- package/src/lib/components/ActivityFeed.svelte +24 -11
- package/src/lib/components/Alert.svelte +9 -4
- package/src/lib/components/AnnotatedTimeSeries.svelte +40 -26
- package/src/lib/components/ArcDiagram.svelte +20 -8
- package/src/lib/components/AreaChart.svelte +26 -14
- package/src/lib/components/Avatar.svelte +20 -8
- package/src/lib/components/AvatarGroup.svelte +16 -7
- package/src/lib/components/Badge.svelte +24 -11
- package/src/lib/components/Banner.svelte +20 -9
- package/src/lib/components/BarChart.svelte +29 -17
- package/src/lib/components/BeeswarmChart.svelte +32 -18
- package/src/lib/components/BoxPlot.svelte +27 -15
- package/src/lib/components/Breadcrumb.svelte +12 -7
- package/src/lib/components/BubbleChart.svelte +39 -25
- package/src/lib/components/BulletChart.svelte +16 -9
- package/src/lib/components/BumpChart.svelte +15 -8
- package/src/lib/components/Button.svelte +32 -11
- package/src/lib/components/CIDRInput.svelte +27 -19
- package/src/lib/components/CalendarHeatmap.svelte +12 -5
- package/src/lib/components/Callout.svelte +9 -4
- package/src/lib/components/CandlestickChart.svelte +31 -16
- package/src/lib/components/Card.svelte +16 -6
- package/src/lib/components/Carousel.svelte +14 -11
- package/src/lib/components/Checkbox.svelte +37 -16
- package/src/lib/components/ChordDiagram.svelte +12 -5
- package/src/lib/components/CirclePacking.svelte +13 -6
- package/src/lib/components/CodeBlock.svelte +16 -7
- package/src/lib/components/ColorPicker.svelte +22 -11
- package/src/lib/components/ColumnToggle.svelte +18 -11
- package/src/lib/components/Combobox.svelte +44 -33
- package/src/lib/components/CommandPalette.svelte +41 -31
- package/src/lib/components/ConfirmDialog.svelte +66 -35
- package/src/lib/components/ContextMenu.svelte +46 -33
- package/src/lib/components/ContextualHelp.svelte +13 -9
- package/src/lib/components/ContourPlot.svelte +43 -28
- package/src/lib/components/CopyButton.svelte +8 -4
- package/src/lib/components/CorrelationMatrix.svelte +16 -7
- package/src/lib/components/CountUp.svelte +30 -13
- package/src/lib/components/CumulativeDistribution.svelte +32 -19
- package/src/lib/components/DatePicker.svelte +28 -21
- package/src/lib/components/DateRangePicker.svelte +39 -32
- package/src/lib/components/Dendrogram.svelte +18 -6
- package/src/lib/components/Donut.svelte +28 -14
- package/src/lib/components/DotPlot.svelte +31 -16
- package/src/lib/components/Drawer.svelte +28 -21
- package/src/lib/components/DualAxisChart.svelte +39 -26
- package/src/lib/components/DumbbellChart.svelte +24 -12
- package/src/lib/components/DurationInput.svelte +26 -17
- package/src/lib/components/EmptyState.svelte +16 -6
- package/src/lib/components/ErrorBandChart.svelte +28 -14
- package/src/lib/components/ExpandableRow.svelte +19 -6
- package/src/lib/components/Field.svelte +26 -12
- package/src/lib/components/FileUpload.svelte +29 -20
- package/src/lib/components/FilterBuilder.svelte +27 -17
- package/src/lib/components/FlameGraph.svelte +14 -7
- package/src/lib/components/ForceGraph.svelte +19 -7
- package/src/lib/components/FunnelChart.svelte +20 -13
- package/src/lib/components/GanttChart.svelte +14 -7
- package/src/lib/components/Gauge.svelte +26 -16
- package/src/lib/components/GroupedList.svelte +13 -6
- package/src/lib/components/HealthBar.svelte +14 -5
- package/src/lib/components/HeatMap.svelte +28 -17
- package/src/lib/components/HexbinChart.svelte +36 -22
- package/src/lib/components/Histogram.svelte +27 -14
- package/src/lib/components/HorizonChart.svelte +28 -16
- package/src/lib/components/HoverCard.svelte +24 -12
- package/src/lib/components/IPInput.svelte +24 -16
- package/src/lib/components/IcicleChart.svelte +14 -7
- package/src/lib/components/IconButton.svelte +27 -9
- package/src/lib/components/InlineEdit.svelte +22 -12
- package/src/lib/components/Input.svelte +67 -10
- package/src/lib/components/InputGroup.svelte +8 -3
- package/src/lib/components/JsonViewer.svelte +17 -6
- package/src/lib/components/JsonViewerNode.svelte +36 -18
- package/src/lib/components/KVTable.svelte +6 -2
- package/src/lib/components/KanbanBoard.svelte +24 -17
- package/src/lib/components/Kbd.svelte +8 -4
- package/src/lib/components/LineChart.svelte +29 -17
- package/src/lib/components/LogViewer.svelte +27 -12
- package/src/lib/components/LollipopChart.svelte +20 -8
- package/src/lib/components/MACInput.svelte +24 -16
- package/src/lib/components/MarimekkoChart.svelte +14 -7
- package/src/lib/components/MatrixChart.svelte +19 -9
- package/src/lib/components/Menubar.svelte +26 -19
- package/src/lib/components/MirroredBarChart.svelte +25 -10
- package/src/lib/components/Modal.svelte +46 -33
- package/src/lib/components/MultiSelect.svelte +49 -38
- package/src/lib/components/NightingaleChart.svelte +17 -10
- package/src/lib/components/NotificationPanel.svelte +48 -33
- package/src/lib/components/NumberInput.svelte +37 -23
- package/src/lib/components/OTPInput.svelte +28 -16
- package/src/lib/components/Pagination.svelte +16 -13
- package/src/lib/components/ParallelCoordinates.svelte +28 -16
- package/src/lib/components/ParetoChart.svelte +38 -24
- package/src/lib/components/PasswordInput.svelte +24 -14
- package/src/lib/components/PieChart.svelte +21 -13
- package/src/lib/components/Pill.svelte +17 -6
- package/src/lib/components/PolarHeatmap.svelte +32 -18
- package/src/lib/components/Popover.svelte +22 -11
- package/src/lib/components/ProgressBar.svelte +17 -8
- package/src/lib/components/PunchCard.svelte +31 -20
- package/src/lib/components/QuadrantChart.svelte +50 -30
- package/src/lib/components/RadarChart.svelte +30 -18
- package/src/lib/components/RadialBarChart.svelte +14 -7
- package/src/lib/components/RadioGroup.svelte +20 -8
- package/src/lib/components/RangeSlider.svelte +30 -18
- package/src/lib/components/RankedList.svelte +18 -6
- package/src/lib/components/ResizablePanel.svelte +33 -17
- package/src/lib/components/RidgelinePlot.svelte +33 -21
- package/src/lib/components/RowToggle.svelte +15 -5
- package/src/lib/components/SankeyDiagram.svelte +18 -6
- package/src/lib/components/ScatterPlot.svelte +34 -21
- package/src/lib/components/SearchBox.svelte +27 -5
- package/src/lib/components/SegmentedControl.svelte +11 -7
- package/src/lib/components/Select.svelte +37 -26
- package/src/lib/components/SelectionToolbar.svelte +25 -11
- package/src/lib/components/Sidebar.svelte +15 -9
- package/src/lib/components/Signal.svelte +6 -2
- package/src/lib/components/Skeleton.svelte +20 -10
- package/src/lib/components/SkipLink.svelte +9 -4
- package/src/lib/components/Slider.svelte +28 -14
- package/src/lib/components/SlopeChart.svelte +35 -21
- package/src/lib/components/SortHeader.svelte +20 -9
- package/src/lib/components/SortableList.svelte +20 -13
- package/src/lib/components/Sparkline.svelte +15 -6
- package/src/lib/components/SparklineMatrix.svelte +17 -10
- package/src/lib/components/Spinner.svelte +7 -3
- package/src/lib/components/SplitButton.svelte +28 -17
- package/src/lib/components/Spoiler.svelte +22 -11
- package/src/lib/components/StackedBarChart.svelte +35 -22
- package/src/lib/components/StackedProgress.svelte +21 -9
- package/src/lib/components/StarRating.svelte +22 -11
- package/src/lib/components/Stat.svelte +32 -10
- package/src/lib/components/StatusIndicator.svelte +7 -3
- package/src/lib/components/StepChart.svelte +27 -15
- package/src/lib/components/Stepper.svelte +10 -6
- package/src/lib/components/StreamGraph.svelte +19 -12
- package/src/lib/components/StripeChart.svelte +22 -12
- package/src/lib/components/SunburstChart.svelte +11 -4
- package/src/lib/components/SwitchPortGrid.svelte +13 -7
- package/src/lib/components/TabPanel.svelte +9 -4
- package/src/lib/components/Tabs.svelte +18 -10
- package/src/lib/components/Tag.svelte +9 -5
- package/src/lib/components/TagInput.svelte +28 -18
- package/src/lib/components/Textarea.svelte +37 -15
- package/src/lib/components/ThresholdAreaChart.svelte +34 -21
- package/src/lib/components/TimePicker.svelte +25 -17
- package/src/lib/components/TimeRange.svelte +19 -14
- package/src/lib/components/Timeline.svelte +8 -4
- package/src/lib/components/Toast.svelte +2 -2
- package/src/lib/components/Toggle.svelte +13 -7
- package/src/lib/components/ToggleGroup.svelte +19 -11
- package/src/lib/components/Tooltip.svelte +16 -6
- package/src/lib/components/Topbar.svelte +24 -10
- package/src/lib/components/TransferList.svelte +34 -27
- package/src/lib/components/TreeItem.svelte +23 -10
- package/src/lib/components/TreeMap.svelte +13 -6
- package/src/lib/components/TreeView.svelte +24 -12
- package/src/lib/components/UptimeTimeline.svelte +22 -15
- package/src/lib/components/VennDiagram.svelte +25 -13
- package/src/lib/components/ViolinPlot.svelte +31 -19
- package/src/lib/components/VirtualList.svelte +25 -13
- package/src/lib/components/WaffleChart.svelte +32 -18
- package/src/lib/components/WaterfallChart.svelte +33 -26
- package/src/lib/components/WordCloud.svelte +21 -14
- package/src/lib/icons/AlarmIcon.svelte +4 -1
- package/src/lib/icons/BellIcon.svelte +2 -1
- package/src/lib/icons/CaretIcon.svelte +5 -3
- package/src/lib/icons/ClientsIcon.svelte +4 -1
- package/src/lib/icons/CloseIcon.svelte +2 -1
- package/src/lib/icons/DashboardIcon.svelte +4 -1
- package/src/lib/icons/DevicesIcon.svelte +4 -1
- package/src/lib/icons/DownloadIcon.svelte +2 -1
- package/src/lib/icons/HelpIcon.svelte +2 -1
- package/src/lib/icons/InfraIcon.svelte +4 -1
- package/src/lib/icons/IntegrationsIcon.svelte +4 -1
- package/src/lib/icons/LogsIcon.svelte +4 -1
- package/src/lib/icons/PlusIcon.svelte +2 -1
- package/src/lib/icons/PortsIcon.svelte +4 -1
- package/src/lib/icons/SearchIcon.svelte +6 -4
- package/src/lib/icons/SecurityIcon.svelte +4 -1
- package/src/lib/icons/SettingsIcon.svelte +4 -1
- package/src/lib/icons/TopologyIcon.svelte +4 -1
- package/src/lib/icons/UpdatesIcon.svelte +2 -1
- package/src/lib/icons/VpnIcon.svelte +4 -1
- package/src/lib/icons/WifiIcon.svelte +4 -1
- 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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
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
|
|
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 {
|
|
39
|
+
import { onMount, onDestroy, tick } from 'svelte';
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
interface Props {
|
|
42
|
+
value?: Date | null;
|
|
43
|
+
placeholder?: string;
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
onchange?: (payload: Date) => void;
|
|
46
|
+
}
|
|
44
47
|
|
|
45
|
-
|
|
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
|
-
|
|
52
|
-
let
|
|
53
|
-
|
|
54
|
-
let
|
|
55
|
-
let
|
|
56
|
-
let
|
|
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
|
-
|
|
59
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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"
|
|
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"
|
|
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
|
-
|
|
189
|
-
|
|
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
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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
|
|
61
|
-
let dlgEl
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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"
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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"
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
38
|
-
|
|
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
|
-
|
|
6
|
-
|
|
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
|
|
11
|
-
let prev: HTMLElement | null = null;
|
|
12
|
-
let wasOpen = false;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
wasOpen
|
|
22
|
-
|
|
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
|
|
44
|
+
<svelte:window onkeydown={onKeydown} />
|
|
38
45
|
|
|
39
46
|
<div
|
|
40
47
|
class="drawer-overlay {open ? 'show' : ''}"
|
|
41
|
-
|
|
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"
|
|
62
|
+
<IconButton title="Close" onclick={() => (open = false)}>
|
|
56
63
|
<CloseIcon />
|
|
57
64
|
</IconButton>
|
|
58
65
|
</div>
|
|
59
|
-
<div class="drawer-b"
|
|
66
|
+
<div class="drawer-b">{@render children?.()}</div>
|
|
60
67
|
</div>
|