@w5-ui/svelte 0.1.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 (195) hide show
  1. package/README.md +8 -0
  2. package/package.json +57 -0
  3. package/src/lib/components/Accordion.svelte +3 -0
  4. package/src/lib/components/AccordionItem.svelte +40 -0
  5. package/src/lib/components/ActionMenu.svelte +96 -0
  6. package/src/lib/components/ActivityFeed.svelte +60 -0
  7. package/src/lib/components/Alert.svelte +19 -0
  8. package/src/lib/components/AnnotatedTimeSeries.svelte +90 -0
  9. package/src/lib/components/ArcDiagram.svelte +74 -0
  10. package/src/lib/components/AreaChart.svelte +64 -0
  11. package/src/lib/components/Avatar.svelte +30 -0
  12. package/src/lib/components/AvatarGroup.svelte +35 -0
  13. package/src/lib/components/Badge.svelte +25 -0
  14. package/src/lib/components/Banner.svelte +37 -0
  15. package/src/lib/components/BarChart.svelte +52 -0
  16. package/src/lib/components/BeeswarmChart.svelte +88 -0
  17. package/src/lib/components/BoxPlot.svelte +66 -0
  18. package/src/lib/components/Breadcrumb.svelte +31 -0
  19. package/src/lib/components/BubbleChart.svelte +69 -0
  20. package/src/lib/components/BulletChart.svelte +70 -0
  21. package/src/lib/components/BumpChart.svelte +109 -0
  22. package/src/lib/components/Button.svelte +25 -0
  23. package/src/lib/components/CIDRInput.svelte +142 -0
  24. package/src/lib/components/CalendarHeatmap.svelte +86 -0
  25. package/src/lib/components/Callout.svelte +38 -0
  26. package/src/lib/components/CandlestickChart.svelte +66 -0
  27. package/src/lib/components/Card.svelte +11 -0
  28. package/src/lib/components/Carousel.svelte +64 -0
  29. package/src/lib/components/Checkbox.svelte +45 -0
  30. package/src/lib/components/ChordDiagram.svelte +90 -0
  31. package/src/lib/components/CirclePacking.svelte +119 -0
  32. package/src/lib/components/CodeBlock.svelte +49 -0
  33. package/src/lib/components/ColorPicker.svelte +91 -0
  34. package/src/lib/components/ColumnToggle.svelte +96 -0
  35. package/src/lib/components/Combobox.svelte +138 -0
  36. package/src/lib/components/CommandPalette.svelte +152 -0
  37. package/src/lib/components/ConfirmDialog.svelte +84 -0
  38. package/src/lib/components/ContextMenu.svelte +107 -0
  39. package/src/lib/components/ContextualHelp.svelte +73 -0
  40. package/src/lib/components/ContourPlot.svelte +164 -0
  41. package/src/lib/components/CopyButton.svelte +33 -0
  42. package/src/lib/components/CorrelationMatrix.svelte +90 -0
  43. package/src/lib/components/CountUp.svelte +49 -0
  44. package/src/lib/components/CumulativeDistribution.svelte +67 -0
  45. package/src/lib/components/DatePicker.svelte +201 -0
  46. package/src/lib/components/DateRangePicker.svelte +249 -0
  47. package/src/lib/components/Dendrogram.svelte +128 -0
  48. package/src/lib/components/Donut.svelte +49 -0
  49. package/src/lib/components/DotPlot.svelte +121 -0
  50. package/src/lib/components/Drawer.svelte +60 -0
  51. package/src/lib/components/DualAxisChart.svelte +80 -0
  52. package/src/lib/components/DumbbellChart.svelte +56 -0
  53. package/src/lib/components/DurationInput.svelte +118 -0
  54. package/src/lib/components/EmptyState.svelte +21 -0
  55. package/src/lib/components/ErrorBandChart.svelte +69 -0
  56. package/src/lib/components/ExpandableRow.svelte +42 -0
  57. package/src/lib/components/Field.svelte +40 -0
  58. package/src/lib/components/FileUpload.svelte +96 -0
  59. package/src/lib/components/FilterBuilder.svelte +160 -0
  60. package/src/lib/components/FlameGraph.svelte +88 -0
  61. package/src/lib/components/ForceGraph.svelte +104 -0
  62. package/src/lib/components/FunnelChart.svelte +50 -0
  63. package/src/lib/components/GanttChart.svelte +49 -0
  64. package/src/lib/components/Gauge.svelte +53 -0
  65. package/src/lib/components/GroupedList.svelte +87 -0
  66. package/src/lib/components/HealthBar.svelte +19 -0
  67. package/src/lib/components/HeatMap.svelte +64 -0
  68. package/src/lib/components/HexbinChart.svelte +100 -0
  69. package/src/lib/components/Histogram.svelte +93 -0
  70. package/src/lib/components/HorizonChart.svelte +71 -0
  71. package/src/lib/components/HoverCard.svelte +45 -0
  72. package/src/lib/components/IPInput.svelte +103 -0
  73. package/src/lib/components/IcicleChart.svelte +87 -0
  74. package/src/lib/components/IconButton.svelte +19 -0
  75. package/src/lib/components/InlineEdit.svelte +72 -0
  76. package/src/lib/components/Input.svelte +18 -0
  77. package/src/lib/components/InputGroup.svelte +14 -0
  78. package/src/lib/components/JsonViewer.svelte +15 -0
  79. package/src/lib/components/JsonViewerNode.svelte +59 -0
  80. package/src/lib/components/KVTable.svelte +18 -0
  81. package/src/lib/components/KanbanBoard.svelte +141 -0
  82. package/src/lib/components/Kbd.svelte +16 -0
  83. package/src/lib/components/LineChart.svelte +67 -0
  84. package/src/lib/components/LogViewer.svelte +84 -0
  85. package/src/lib/components/LollipopChart.svelte +79 -0
  86. package/src/lib/components/MACInput.svelte +98 -0
  87. package/src/lib/components/MarimekkoChart.svelte +108 -0
  88. package/src/lib/components/MatrixChart.svelte +55 -0
  89. package/src/lib/components/Menubar.svelte +131 -0
  90. package/src/lib/components/MirroredBarChart.svelte +120 -0
  91. package/src/lib/components/Modal.svelte +90 -0
  92. package/src/lib/components/MultiSelect.svelte +165 -0
  93. package/src/lib/components/NightingaleChart.svelte +63 -0
  94. package/src/lib/components/NotificationPanel.svelte +170 -0
  95. package/src/lib/components/NumberInput.svelte +93 -0
  96. package/src/lib/components/OTPInput.svelte +94 -0
  97. package/src/lib/components/Pagination.svelte +58 -0
  98. package/src/lib/components/ParallelCoordinates.svelte +98 -0
  99. package/src/lib/components/ParetoChart.svelte +88 -0
  100. package/src/lib/components/PasswordInput.svelte +62 -0
  101. package/src/lib/components/PieChart.svelte +91 -0
  102. package/src/lib/components/Pill.svelte +12 -0
  103. package/src/lib/components/PolarHeatmap.svelte +85 -0
  104. package/src/lib/components/Popover.svelte +89 -0
  105. package/src/lib/components/ProgressBar.svelte +29 -0
  106. package/src/lib/components/PunchCard.svelte +73 -0
  107. package/src/lib/components/QuadrantChart.svelte +122 -0
  108. package/src/lib/components/RadarChart.svelte +71 -0
  109. package/src/lib/components/RadialBarChart.svelte +76 -0
  110. package/src/lib/components/RadioGroup.svelte +48 -0
  111. package/src/lib/components/RangeSlider.svelte +68 -0
  112. package/src/lib/components/RankedList.svelte +49 -0
  113. package/src/lib/components/ResizablePanel.svelte +77 -0
  114. package/src/lib/components/RidgelinePlot.svelte +103 -0
  115. package/src/lib/components/RowToggle.svelte +19 -0
  116. package/src/lib/components/SankeyDiagram.svelte +100 -0
  117. package/src/lib/components/ScatterPlot.svelte +54 -0
  118. package/src/lib/components/SearchBox.svelte +11 -0
  119. package/src/lib/components/SegmentedControl.svelte +51 -0
  120. package/src/lib/components/Select.svelte +110 -0
  121. package/src/lib/components/SelectionToolbar.svelte +42 -0
  122. package/src/lib/components/Sidebar.svelte +44 -0
  123. package/src/lib/components/Signal.svelte +12 -0
  124. package/src/lib/components/Skeleton.svelte +23 -0
  125. package/src/lib/components/SkipLink.svelte +9 -0
  126. package/src/lib/components/Slider.svelte +48 -0
  127. package/src/lib/components/SlopeChart.svelte +91 -0
  128. package/src/lib/components/SortHeader.svelte +19 -0
  129. package/src/lib/components/SortableList.svelte +87 -0
  130. package/src/lib/components/Sparkline.svelte +32 -0
  131. package/src/lib/components/SparklineMatrix.svelte +84 -0
  132. package/src/lib/components/Spinner.svelte +6 -0
  133. package/src/lib/components/SplitButton.svelte +102 -0
  134. package/src/lib/components/Spoiler.svelte +41 -0
  135. package/src/lib/components/StackedBarChart.svelte +83 -0
  136. package/src/lib/components/StackedProgress.svelte +32 -0
  137. package/src/lib/components/StarRating.svelte +64 -0
  138. package/src/lib/components/Stat.svelte +24 -0
  139. package/src/lib/components/StatusIndicator.svelte +10 -0
  140. package/src/lib/components/StepChart.svelte +74 -0
  141. package/src/lib/components/Stepper.svelte +40 -0
  142. package/src/lib/components/StreamGraph.svelte +93 -0
  143. package/src/lib/components/StripeChart.svelte +52 -0
  144. package/src/lib/components/SunburstChart.svelte +80 -0
  145. package/src/lib/components/SwitchPortGrid.svelte +45 -0
  146. package/src/lib/components/TabPanel.svelte +17 -0
  147. package/src/lib/components/Tabs.svelte +45 -0
  148. package/src/lib/components/Tag.svelte +19 -0
  149. package/src/lib/components/TagInput.svelte +92 -0
  150. package/src/lib/components/Textarea.svelte +31 -0
  151. package/src/lib/components/ThresholdAreaChart.svelte +72 -0
  152. package/src/lib/components/TimePicker.svelte +116 -0
  153. package/src/lib/components/TimeRange.svelte +104 -0
  154. package/src/lib/components/Timeline.svelte +32 -0
  155. package/src/lib/components/Toast.svelte +52 -0
  156. package/src/lib/components/Toggle.svelte +23 -0
  157. package/src/lib/components/ToggleGroup.svelte +32 -0
  158. package/src/lib/components/Tooltip.svelte +16 -0
  159. package/src/lib/components/Topbar.svelte +63 -0
  160. package/src/lib/components/TransferList.svelte +184 -0
  161. package/src/lib/components/TreeItem.svelte +61 -0
  162. package/src/lib/components/TreeMap.svelte +90 -0
  163. package/src/lib/components/TreeView.svelte +130 -0
  164. package/src/lib/components/UptimeTimeline.svelte +86 -0
  165. package/src/lib/components/VennDiagram.svelte +91 -0
  166. package/src/lib/components/ViolinPlot.svelte +114 -0
  167. package/src/lib/components/VirtualList.svelte +38 -0
  168. package/src/lib/components/WaffleChart.svelte +68 -0
  169. package/src/lib/components/WaterfallChart.svelte +96 -0
  170. package/src/lib/components/WordCloud.svelte +103 -0
  171. package/src/lib/icons/AlarmIcon.svelte +5 -0
  172. package/src/lib/icons/BellIcon.svelte +6 -0
  173. package/src/lib/icons/CaretIcon.svelte +8 -0
  174. package/src/lib/icons/ClientsIcon.svelte +5 -0
  175. package/src/lib/icons/CloseIcon.svelte +6 -0
  176. package/src/lib/icons/DashboardIcon.svelte +7 -0
  177. package/src/lib/icons/DevicesIcon.svelte +5 -0
  178. package/src/lib/icons/DownloadIcon.svelte +6 -0
  179. package/src/lib/icons/HelpIcon.svelte +7 -0
  180. package/src/lib/icons/InfraIcon.svelte +7 -0
  181. package/src/lib/icons/IntegrationsIcon.svelte +5 -0
  182. package/src/lib/icons/LogsIcon.svelte +6 -0
  183. package/src/lib/icons/PlusIcon.svelte +6 -0
  184. package/src/lib/icons/PortsIcon.svelte +6 -0
  185. package/src/lib/icons/SearchIcon.svelte +10 -0
  186. package/src/lib/icons/SecurityIcon.svelte +4 -0
  187. package/src/lib/icons/SettingsIcon.svelte +5 -0
  188. package/src/lib/icons/TopologyIcon.svelte +7 -0
  189. package/src/lib/icons/UpdatesIcon.svelte +6 -0
  190. package/src/lib/icons/VpnIcon.svelte +5 -0
  191. package/src/lib/icons/WifiIcon.svelte +5 -0
  192. package/src/lib/icons/WirelessIcon.svelte +4 -0
  193. package/src/lib/icons.ts +22 -0
  194. package/src/lib/index.ts +275 -0
  195. package/src/lib/styles.css +2 -0
@@ -0,0 +1,86 @@
1
+ <script lang="ts">
2
+ export type UptimeStatus = 'up' | 'degraded' | 'down';
3
+
4
+ export interface UptimeSegment {
5
+ from: number;
6
+ to: number;
7
+ status: UptimeStatus;
8
+ }
9
+
10
+ export interface UptimeSeries {
11
+ label: string;
12
+ segments: UptimeSegment[];
13
+ }
14
+
15
+ export let series: UptimeSeries[] = [];
16
+ export let xLabels: string[] = [];
17
+ export let ariaLabel: string = 'Uptime timeline';
18
+
19
+ const VW = 400;
20
+ const LABEL_W = 88;
21
+ const PAD_R = 10;
22
+ const PAD_T = 6;
23
+ const ROW_H = 14;
24
+ const ROW_GAP = 8;
25
+ const XLBL_H = 16;
26
+ const LEG_H = 16;
27
+ const PAD_B = XLBL_H + LEG_H + 4;
28
+
29
+ const STATUS_COLOR: Record<UptimeStatus, string> = {
30
+ up: '#00C875',
31
+ degraded: '#F5A623',
32
+ down: '#F03E3E',
33
+ };
34
+
35
+ const LEGEND: { status: UptimeStatus; label: string }[] = [
36
+ { status: 'up', label: 'Up' },
37
+ { status: 'degraded', label: 'Degraded' },
38
+ { status: 'down', label: 'Down' },
39
+ ];
40
+
41
+ $: trackW = VW - LABEL_W - PAD_R;
42
+ $: rowsH = series.length * (ROW_H + ROW_GAP) - ROW_GAP;
43
+ $: totalH = PAD_T + rowsH + PAD_B;
44
+ $: xlblY = PAD_T + rowsH + XLBL_H;
45
+ $: legY = xlblY + LEG_H;
46
+
47
+ $: rows = series.map((s, si) => ({
48
+ label: s.label,
49
+ y: PAD_T + si * (ROW_H + ROW_GAP),
50
+ midY: PAD_T + si * (ROW_H + ROW_GAP) + ROW_H / 2 + 4,
51
+ segs: s.segments.map((seg) => ({
52
+ x: LABEL_W + seg.from * trackW,
53
+ w: (seg.to - seg.from) * trackW,
54
+ color: STATUS_COLOR[seg.status],
55
+ })),
56
+ }));
57
+
58
+ $: xlbls = xLabels.map((lbl, i) => ({
59
+ lbl,
60
+ x: LABEL_W + (xLabels.length > 1 ? i / (xLabels.length - 1) : 0) * trackW,
61
+ anchor: i === 0 ? 'start' : i === xLabels.length - 1 ? 'end' : 'middle',
62
+ }));
63
+ </script>
64
+
65
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
66
+ <svg viewBox="0 0 {VW} {totalH}" style="width:100%;height:auto;display:block;" aria-hidden="true" focusable="false">
67
+ {#each rows as row}
68
+ <text x={LABEL_W - 8} y={row.midY} text-anchor="end" fill="#A4A7B5" font-size="11" font-family="inherit">
69
+ {row.label}
70
+ </text>
71
+ <rect x={LABEL_W} y={row.y} width={trackW} height={ROW_H} fill="rgba(255,255,255,0.04)" rx="3" />
72
+ {#each row.segs as seg}
73
+ <rect x={seg.x} y={row.y} width={seg.w} height={ROW_H} fill={seg.color} rx="2" fill-opacity="0.85" />
74
+ {/each}
75
+ {/each}
76
+
77
+ {#each xlbls as { lbl, x, anchor }}
78
+ <text {x} y={xlblY} text-anchor={anchor} fill="#6E7079" font-size="10" font-family="inherit">{lbl}</text>
79
+ {/each}
80
+
81
+ {#each LEGEND as { status, label }, i}
82
+ <rect x={LABEL_W + i * 80} y={legY - 8} width="12" height="8" fill={STATUS_COLOR[status]} rx="2" fill-opacity="0.85" />
83
+ <text x={LABEL_W + i * 80 + 16} y={legY} fill="#6E7079" font-size="10" font-family="inherit">{label}</text>
84
+ {/each}
85
+ </svg>
86
+ </div>
@@ -0,0 +1,91 @@
1
+ <script lang="ts">
2
+ export interface VennSet {
3
+ id: string;
4
+ label: string;
5
+ value: number;
6
+ color?: string;
7
+ }
8
+ export interface VennIntersection {
9
+ sets: string[];
10
+ value: number;
11
+ }
12
+
13
+ export let sets: VennSet[] = [];
14
+ export let intersections: VennIntersection[] = [];
15
+ export let height = 240;
16
+ export let ariaLabel = 'Venn diagram';
17
+
18
+ const PALETTE = ['#006FFF', '#00C875', '#A78BFA'];
19
+ const VW = 340;
20
+
21
+ function fmt(n: number): string {
22
+ return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);
23
+ }
24
+
25
+ $: valid = sets.length >= 2 && sets.length <= 3;
26
+ $: is3 = sets.length === 3;
27
+ $: cx = VW / 2;
28
+ $: cy = height / 2;
29
+
30
+ $: circles = is3
31
+ ? [
32
+ { x: cx, y: cy - 40, r: 75 },
33
+ { x: cx - 65, y: cy + 50, r: 75 },
34
+ { x: cx + 65, y: cy + 50, r: 75 },
35
+ ]
36
+ : [
37
+ { x: cx - 58, y: cy, r: 85 },
38
+ { x: cx + 58, y: cy, r: 85 },
39
+ ];
40
+
41
+ $: exclusiveValues = sets.map((s) =>
42
+ Math.max(
43
+ 0,
44
+ s.value -
45
+ intersections
46
+ .filter((i) => i.sets.includes(s.id))
47
+ .reduce((sum, i) => sum + i.value, 0),
48
+ ),
49
+ );
50
+
51
+ function getPt(inter: VennIntersection): { x: number; y: number } | null {
52
+ const idxById: Record<string, number> = {};
53
+ sets.forEach((s, i) => { idxById[s.id] = i; });
54
+ const idxs = inter.sets
55
+ .map((id) => idxById[id])
56
+ .filter((v) => v !== undefined)
57
+ .sort((a, b) => a - b);
58
+ if (!is3) return { x: cx, y: cy };
59
+ if (idxs.length >= 3) return { x: cx, y: cy + 18 };
60
+ if (idxs[0] === 0 && idxs[1] === 1) return { x: cx - 33, y: cy + 4 };
61
+ if (idxs[0] === 0 && idxs[1] === 2) return { x: cx + 33, y: cy + 4 };
62
+ if (idxs[0] === 1 && idxs[1] === 2) return { x: cx, y: cy + 50 };
63
+ return null;
64
+ }
65
+ </script>
66
+
67
+ {#if valid}
68
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
69
+ <svg viewBox="0 0 {VW} {height}" style="width:100%;height:auto;display:block;" aria-hidden="true" focusable="false">
70
+ {#each sets as s, i}
71
+ {@const c = circles[i]}
72
+ {@const color = s.color ?? PALETTE[i % PALETTE.length]}
73
+ <circle cx={c.x} cy={c.y} r={c.r} fill={color} fill-opacity="0.15" stroke={color} stroke-opacity="0.55" stroke-width="1.5" />
74
+ {/each}
75
+
76
+ {#each sets as s, i}
77
+ {@const c = circles[i]}
78
+ {@const color = s.color ?? PALETTE[i % PALETTE.length]}
79
+ <text x={c.x} y={c.y - 8} fill={color} font-size="11" text-anchor="middle" font-family="inherit" font-weight="600">{s.label}</text>
80
+ <text x={c.x} y={c.y + 8} fill="#A4A7B5" font-size="10" text-anchor="middle" font-family="inherit">{fmt(exclusiveValues[i])}</text>
81
+ {/each}
82
+
83
+ {#each intersections as inter}
84
+ {@const pt = getPt(inter)}
85
+ {#if pt}
86
+ <text x={pt.x} y={pt.y} fill="rgba(255,255,255,0.65)" font-size="10" text-anchor="middle" font-family="inherit">{fmt(inter.value)}</text>
87
+ {/if}
88
+ {/each}
89
+ </svg>
90
+ </div>
91
+ {/if}
@@ -0,0 +1,114 @@
1
+ <script lang="ts">
2
+ export interface ViolinSeries {
3
+ label: string;
4
+ values: number[];
5
+ color?: string;
6
+ }
7
+
8
+ export let series: ViolinSeries[] = [];
9
+ export let yRange: [number, number] | undefined = undefined;
10
+ export let height: number = 160;
11
+ export let ariaLabel: string = 'Violin plot';
12
+
13
+ const COLORS = ['#006FFF', '#00C8C8', '#F5A623', '#7FB6FF', '#A878F5', '#F56342'];
14
+ const SQRT_TWO_PI = Math.sqrt(2 * Math.PI);
15
+ const NUM_PTS = 60;
16
+
17
+ function bw(vals: number[]): number {
18
+ const n = vals.length;
19
+ const m = vals.reduce((a, b) => a + b, 0) / n;
20
+ const s = Math.sqrt(vals.reduce((a, b) => a + (b - m) ** 2, 0) / n);
21
+ return Math.max(0.9 * s * Math.pow(n, -0.2), 0.5);
22
+ }
23
+
24
+ function kde(vals: number[], h: number, pts: number[]): number[] {
25
+ const n = vals.length;
26
+ const c = 1 / (n * h * SQRT_TWO_PI);
27
+ return pts.map(y => c * vals.reduce((acc, x) => {
28
+ const z = (y - x) / h;
29
+ return acc + Math.exp(-0.5 * z * z);
30
+ }, 0));
31
+ }
32
+
33
+ function med(vals: number[]): number {
34
+ const s = [...vals].sort((a, b) => a - b);
35
+ const m = Math.floor(s.length / 2);
36
+ return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
37
+ }
38
+
39
+ const VW = 380;
40
+ $: VH = height;
41
+ const PAD_L = 28;
42
+ const PAD_R = 8;
43
+ const PAD_T = 8;
44
+ const PAD_B = 20;
45
+
46
+ $: allVals = series.flatMap(s => s.values);
47
+ $: yMin = yRange ? yRange[0] : Math.min(...allVals);
48
+ $: yMax = yRange ? yRange[1] : Math.max(...allVals);
49
+
50
+ $: TRACK_W = VW - PAD_L - PAD_R;
51
+ $: TRACK_H = VH - PAD_T - PAD_B;
52
+ $: slotW = TRACK_W / series.length;
53
+ $: maxHalfW = slotW * 0.38;
54
+
55
+ $: evalPts = Array.from({ length: NUM_PTS }, (_, i) =>
56
+ yMin + (i / (NUM_PTS - 1)) * (yMax - yMin)
57
+ );
58
+
59
+ function ySvg(v: number): number {
60
+ return PAD_T + ((yMax - v) / (yMax - yMin)) * TRACK_H;
61
+ }
62
+
63
+ $: violins = series.map((s, si) => {
64
+ const h = bw(s.values);
65
+ const dens = kde(s.values, h, evalPts);
66
+ const maxD = Math.max(...dens, 1e-9);
67
+ const cx = PAD_L + si * slotW + slotW / 2;
68
+ const pts = evalPts.map((v, i) => ({ x: (dens[i] / maxD) * maxHalfW, y: ySvg(v) }));
69
+ const right = pts.map(p => `${(cx + p.x).toFixed(1)},${p.y.toFixed(1)}`);
70
+ const left = [...pts].reverse().map(p => `${(cx - p.x).toFixed(1)},${p.y.toFixed(1)}`);
71
+ const d = `M${cx},${ySvg(yMin)} L${right.join(' L')} L${left.join(' L')} Z`;
72
+ const median = med(s.values);
73
+ return {
74
+ d,
75
+ cx,
76
+ medY: ySvg(median),
77
+ maxHalfW,
78
+ color: s.color ?? COLORS[si % COLORS.length],
79
+ label: s.label,
80
+ };
81
+ });
82
+
83
+ $: ticks = [0, 0.25, 0.5, 0.75, 1].map(t => {
84
+ const v = yMin + t * (yMax - yMin);
85
+ return { v, y: ySvg(v) };
86
+ });
87
+ </script>
88
+
89
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
90
+ <svg
91
+ viewBox="0 0 {VW} {VH}"
92
+ style="width:100%;height:auto;display:block;"
93
+ aria-hidden="true"
94
+ focusable="false"
95
+ >
96
+ {#each ticks as tick (tick.v)}
97
+ <line x1={PAD_L} y1={tick.y} x2={VW - PAD_R} y2={tick.y} stroke="rgba(255,255,255,0.06)" stroke-width="1" />
98
+ <text x={PAD_L - 3} y={tick.y + 3} fill="#6E7079" font-size="8" text-anchor="end" font-family="inherit">{tick.v.toFixed(0)}</text>
99
+ {/each}
100
+ {#each violins as v, si (si)}
101
+ <path d={v.d} fill={v.color} opacity="0.72" />
102
+ <line
103
+ x1={v.cx - v.maxHalfW * 0.45}
104
+ y1={v.medY}
105
+ x2={v.cx + v.maxHalfW * 0.45}
106
+ y2={v.medY}
107
+ stroke="#fff"
108
+ stroke-width="1.5"
109
+ stroke-linecap="round"
110
+ />
111
+ <text x={v.cx} y={VH - 5} fill="#6E7079" font-size="8" text-anchor="middle" font-family="inherit">{v.label}</text>
112
+ {/each}
113
+ </svg>
114
+ </div>
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ export let items: unknown[] = [];
3
+ export let itemHeight: number = 48;
4
+ export let height: number = 400;
5
+ export let label: string | undefined = undefined;
6
+ export let overscan: number = 3;
7
+
8
+ let scrollTop = 0;
9
+
10
+ $: totalHeight = items.length * itemHeight;
11
+ $: firstVisible = Math.floor(scrollTop / itemHeight);
12
+ $: startIndex = Math.max(0, firstVisible - overscan);
13
+ $: endIndex = Math.min(items.length, firstVisible + Math.ceil(height / itemHeight) + overscan + 1);
14
+ $: visible = items.slice(startIndex, endIndex).map((item, i) => ({ item, index: startIndex + i }));
15
+ </script>
16
+
17
+ <div
18
+ role="list"
19
+ aria-label={label}
20
+ class="vl"
21
+ style:height="{height}px"
22
+ style:overflow-y="auto"
23
+ on:scroll={(e) => (scrollTop = e.currentTarget.scrollTop)}
24
+ >
25
+ <div style:height="{totalHeight}px" style:position="relative">
26
+ <div style:position="absolute" style:top="{startIndex * itemHeight}px" style:width="100%">
27
+ {#each visible as { item, index } (index)}
28
+ <div
29
+ role="listitem"
30
+ style:height="{itemHeight}px"
31
+ style:overflow="hidden"
32
+ >
33
+ <slot {item} {index} />
34
+ </div>
35
+ {/each}
36
+ </div>
37
+ </div>
38
+ </div>
@@ -0,0 +1,68 @@
1
+ <script lang="ts">
2
+ export interface WaffleSegment {
3
+ label: string;
4
+ value: number;
5
+ color?: string;
6
+ }
7
+
8
+ export let segments: WaffleSegment[] = [];
9
+ export let total: number | undefined = undefined;
10
+ export let cols: number = 10;
11
+ export let rows: number = 10;
12
+ export let gap: number = 2;
13
+ export let ariaLabel: string = 'Waffle chart';
14
+
15
+ const COLORS = ['#006FFF', '#00C7A8', '#F5A623', '#FF6B6B', '#A78BFA'];
16
+ const VW = 280;
17
+ const LEGEND_H = 24;
18
+
19
+ $: sum = total ?? segments.reduce((s, seg) => s + seg.value, 0);
20
+ $: cellSize = (VW - gap * (cols - 1)) / cols;
21
+ $: gridH = rows * cellSize + gap * (rows - 1);
22
+ $: svgH = gridH + LEGEND_H + 6;
23
+ $: totalCells = cols * rows;
24
+
25
+ $: cellMap = (() => {
26
+ const map: number[] = new Array(totalCells).fill(-1);
27
+ let cursor = 0;
28
+ segments.forEach((seg, si) => {
29
+ const count = Math.round((seg.value / sum) * totalCells);
30
+ for (let j = 0; j < count && cursor < totalCells; j++, cursor++) {
31
+ map[cursor] = si;
32
+ }
33
+ });
34
+ return map;
35
+ })();
36
+
37
+ $: cells = Array.from({ length: totalCells }, (_, i) => {
38
+ const col = i % cols;
39
+ const row = Math.floor(i / cols);
40
+ const x = col * (cellSize + gap);
41
+ const y = row * (cellSize + gap);
42
+ const si = cellMap[i];
43
+ const fill = si >= 0 ? (segments[si].color ?? COLORS[si % COLORS.length]) : 'rgba(255,255,255,0.06)';
44
+ return { x, y, fill, width: cellSize, height: cellSize };
45
+ });
46
+
47
+ $: legendItems = segments.map((seg, si) => ({
48
+ color: seg.color ?? COLORS[si % COLORS.length],
49
+ pct: Math.round((seg.value / sum) * 100),
50
+ label: seg.label,
51
+ lx: si * (VW / segments.length),
52
+ ly: gridH + 8,
53
+ }));
54
+ </script>
55
+
56
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
57
+ <svg viewBox="0 0 {VW} {svgH}" style="width:100%;height:auto;display:block;" aria-hidden="true" focusable="false">
58
+ {#each cells as cell}
59
+ <rect x={cell.x} y={cell.y} width={cell.width} height={cell.height} fill={cell.fill} rx="1" />
60
+ {/each}
61
+ {#each legendItems as item}
62
+ <rect x={item.lx} y={item.ly} width="8" height="8" fill={item.color} rx="1" />
63
+ <text x={item.lx + 11} y={item.ly + 7.5} fill="#A4A7B5" font-size="9" font-family="inherit">
64
+ {item.label} {item.pct}%
65
+ </text>
66
+ {/each}
67
+ </svg>
68
+ </div>
@@ -0,0 +1,96 @@
1
+ <script lang="ts">
2
+ export interface WaterfallBar {
3
+ label: string;
4
+ value: number;
5
+ type?: 'start' | 'delta' | 'total';
6
+ }
7
+
8
+ export let bars: WaterfallBar[] = [];
9
+ export let height: number = 160;
10
+ export let ariaLabel: string = 'Waterfall chart';
11
+
12
+ const VW = 320;
13
+ const PAD = { t: 12, r: 8, b: 24, l: 8 };
14
+ const COLOR_START = '#006FFF';
15
+ const COLOR_POS = '#00C875';
16
+ const COLOR_NEG = '#F04949';
17
+ const COLOR_TOTAL = '#A78BFA';
18
+
19
+ $: chartH = height - PAD.t - PAD.b;
20
+ $: chartW = VW - PAD.l - PAD.r;
21
+ $: n = bars.length;
22
+ $: colW = n > 0 ? chartW / n : chartW;
23
+ $: gap = colW * 0.15;
24
+ $: barW = colW - gap * 2;
25
+
26
+ $: cumBases = (() => {
27
+ const result: number[] = [];
28
+ let acc = 0;
29
+ for (const b of bars) {
30
+ if (b.type === 'start' || b.type === 'total') {
31
+ result.push(0);
32
+ acc = b.value;
33
+ } else {
34
+ result.push(acc);
35
+ acc += b.value;
36
+ }
37
+ }
38
+ return result;
39
+ })();
40
+
41
+ $: tops = bars.map((b, i) => {
42
+ if (b.type === 'start' || b.type === 'total') return b.value;
43
+ return cumBases[i] + b.value;
44
+ });
45
+
46
+ $: allVals = [0, ...cumBases, ...tops];
47
+ $: minV = allVals.length ? Math.min(...allVals) : 0;
48
+ $: maxV = allVals.length ? Math.max(...allVals) : 1;
49
+ $: range = maxV - minV || 1;
50
+
51
+ function toY(v: number): number {
52
+ return PAD.t + (1 - (v - minV) / range) * chartH;
53
+ }
54
+
55
+ $: bot = PAD.t + chartH;
56
+
57
+ $: rects = bars.map((b, i) => {
58
+ const base = cumBases[i];
59
+ const top = b.type === 'start' || b.type === 'total' ? b.value : base + b.value;
60
+ const y0 = toY(Math.max(base, top));
61
+ const y1 = toY(Math.min(base, top));
62
+ const x = PAD.l + i * colW + gap;
63
+ const color = b.type === 'start' ? COLOR_START : b.type === 'total' ? COLOR_TOTAL : b.value >= 0 ? COLOR_POS : COLOR_NEG;
64
+ return { x: x.toFixed(1), y: y0.toFixed(1), w: barW.toFixed(1), h: Math.max(y1 - y0, 1).toFixed(1), color };
65
+ });
66
+
67
+ $: connectors = rects.slice(0, -1).map((r, i) => {
68
+ const nextX = PAD.l + (i + 1) * colW + gap;
69
+ return { x1: parseFloat(r.x), x2: nextX + barW + gap, y: parseFloat(r.y) };
70
+ });
71
+
72
+ $: labels = bars.map((b, i) => ({
73
+ x: (PAD.l + (i + 0.5) * colW).toFixed(1),
74
+ y: (bot + 10).toFixed(1),
75
+ label: b.label,
76
+ }));
77
+
78
+ $: gridLines = [0.25, 0.5, 0.75, 1].map((f) => (PAD.t + (1 - f) * chartH).toFixed(1));
79
+ </script>
80
+
81
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
82
+ <svg viewBox="0 0 {VW} {height}" style="width:100%;height:auto;display:block;" aria-hidden="true" focusable="false">
83
+ {#each gridLines as y}
84
+ <line x1={PAD.l} y1={y} x2={VW - PAD.r} y2={y} stroke="rgba(255,255,255,0.06)" stroke-width="1" />
85
+ {/each}
86
+ {#each connectors as c}
87
+ <line x1={c.x1} y1={c.y} x2={c.x2} y2={c.y} stroke="rgba(255,255,255,0.2)" stroke-width="1" stroke-dasharray="2 2" />
88
+ {/each}
89
+ {#each rects as r, i}
90
+ <rect x={r.x} y={r.y} width={r.w} height={r.h} fill={r.color} fill-opacity="0.85" rx="2" />
91
+ {/each}
92
+ {#each labels as l}
93
+ <text x={l.x} y={l.y} text-anchor="middle" fill="#6E7079" font-size="9" font-family="inherit">{l.label}</text>
94
+ {/each}
95
+ </svg>
96
+ </div>
@@ -0,0 +1,103 @@
1
+ <script lang="ts">
2
+ export interface WordCloudItem {
3
+ word: string;
4
+ weight: number;
5
+ color?: string;
6
+ }
7
+
8
+ export let items: WordCloudItem[] = [];
9
+ export let height: number = 160;
10
+ export let ariaLabel: string = 'Word cloud';
11
+
12
+ const VW = 380;
13
+ const PAD = 14;
14
+ const MIN_FONT = 9;
15
+ const MAX_FONT = 28;
16
+ const GAP = 6;
17
+ const COLORS = ['#006FFF', '#00C8C8', '#F5A623', '#7FB6FF', '#A878F5', '#F56342', '#00C875', '#FF7BB1'];
18
+
19
+ $: sorted = [...items].sort((a, b) => b.weight - a.weight);
20
+ $: maxW = sorted[0]?.weight ?? 1;
21
+ $: minW = sorted[sorted.length - 1]?.weight ?? 0;
22
+ $: range = maxW - minW || 1;
23
+
24
+ $: words = sorted.map((item, i) => {
25
+ const t = (item.weight - minW) / range;
26
+ const fontSize = MIN_FONT + t * (MAX_FONT - MIN_FONT);
27
+ const approxW = item.word.length * fontSize * 0.56 + GAP * 2;
28
+ return {
29
+ word: item.word,
30
+ weight: item.weight,
31
+ fontSize,
32
+ approxW,
33
+ color: item.color ?? COLORS[i % COLORS.length],
34
+ bold: fontSize >= 16,
35
+ };
36
+ });
37
+
38
+ $: placed = (() => {
39
+ const usableW = VW - PAD * 2;
40
+ const rows: (typeof words)[] = [];
41
+ let row: typeof words = [];
42
+ let rowW = 0;
43
+ for (const w of words) {
44
+ if (rowW + w.approxW > usableW && row.length > 0) {
45
+ rows.push(row);
46
+ row = [w];
47
+ rowW = w.approxW;
48
+ } else {
49
+ row.push(w);
50
+ rowW += w.approxW;
51
+ }
52
+ }
53
+ if (row.length) rows.push(row);
54
+
55
+ const ROW_H = 32;
56
+ const totalH = rows.length * ROW_H + PAD * 2;
57
+ const svgH = Math.max(height, totalH);
58
+ const offsetY = PAD + (svgH - totalH) / 2;
59
+
60
+ return rows.flatMap((r, ri) => {
61
+ const rowUsed = r.reduce((s, w) => s + w.approxW, 0);
62
+ let x = PAD + (usableW - rowUsed) / 2;
63
+ const baseY = offsetY + ri * ROW_H;
64
+ return r.map((w) => {
65
+ const cx = x + w.approxW / 2;
66
+ x += w.approxW;
67
+ return { ...w, cx, cy: baseY + w.fontSize };
68
+ });
69
+ });
70
+ })();
71
+
72
+ $: svgH = (() => {
73
+ const ROW_H = 32;
74
+ const usableW = VW - PAD * 2;
75
+ let rows = 1; let rowW = 0;
76
+ for (const w of words) {
77
+ if (rowW + w.approxW > usableW && rowW > 0) { rows++; rowW = w.approxW; }
78
+ else rowW += w.approxW;
79
+ }
80
+ return Math.max(height, rows * ROW_H + PAD * 2);
81
+ })();
82
+ </script>
83
+
84
+ <div role="img" aria-label={ariaLabel} style="width:100%;">
85
+ <svg
86
+ viewBox="0 0 {VW} {svgH}"
87
+ style="width:100%;height:auto;display:block;"
88
+ aria-hidden="true"
89
+ focusable="false"
90
+ >
91
+ {#each placed as w (w.word)}
92
+ <text
93
+ x={w.cx}
94
+ y={w.cy}
95
+ text-anchor="middle"
96
+ fill={w.color}
97
+ font-size={w.fontSize}
98
+ font-weight={w.bold ? 600 : 400}
99
+ font-family="inherit"
100
+ >{w.word}</text>
101
+ {/each}
102
+ </svg>
103
+ </div>
@@ -0,0 +1,5 @@
1
+ <script lang="ts">export let size: number = 16;</script>
2
+ <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false">
3
+ <path d="m8 2 6 11H2L8 2Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round" />
4
+ <path d="M8 7v3M8 11.5h.01" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
5
+ </svg>
@@ -0,0 +1,6 @@
1
+ <script lang="ts">
2
+ export let size: number = 16;
3
+ </script>
4
+ <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false">
5
+ <path d="M4 6.5a4 4 0 0 1 8 0V9l1.2 2H2.8L4 9V6.5ZM6.5 12.5a1.5 1.5 0 0 0 3 0" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
6
+ </svg>
@@ -0,0 +1,8 @@
1
+ <script lang="ts">
2
+ let className = '';
3
+ export { className as class };
4
+ export let size: number = 14;
5
+ </script>
6
+ <svg width={size} height={size} viewBox="0 0 20 20" fill="none" aria-hidden="true" focusable="false" class={className}>
7
+ <path d="M5.5 8 10 12.5 14.5 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
8
+ </svg>
@@ -0,0 +1,5 @@
1
+ <script lang="ts">export let size: number = 16;</script>
2
+ <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false">
3
+ <circle cx="8" cy="6" r="2.5" stroke="currentColor" stroke-width="1.5" />
4
+ <path d="M3 13c0-2.5 2.2-4.5 5-4.5s5 2 5 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
5
+ </svg>
@@ -0,0 +1,6 @@
1
+ <script lang="ts">
2
+ export let size: number = 14;
3
+ </script>
4
+ <svg width={size} height={size} viewBox="0 0 14 14" fill="none" aria-hidden="true" focusable="false">
5
+ <path d="M3 3l8 8M11 3l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
6
+ </svg>
@@ -0,0 +1,7 @@
1
+ <script lang="ts">export let size: number = 16;</script>
2
+ <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false">
3
+ <rect x="2" y="2" width="5" height="5" rx="1" stroke="currentColor" stroke-width="1.5" />
4
+ <rect x="9" y="2" width="5" height="5" rx="1" stroke="currentColor" stroke-width="1.5" />
5
+ <rect x="2" y="9" width="5" height="5" rx="1" stroke="currentColor" stroke-width="1.5" />
6
+ <rect x="9" y="9" width="5" height="5" rx="1" stroke="currentColor" stroke-width="1.5" />
7
+ </svg>
@@ -0,0 +1,5 @@
1
+ <script lang="ts">export let size: number = 16;</script>
2
+ <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false">
3
+ <rect x="2.5" y="3.5" width="11" height="9" rx="1.5" stroke="currentColor" stroke-width="1.5" />
4
+ <line x1="2.5" y1="6.5" x2="13.5" y2="6.5" stroke="currentColor" stroke-width="1.5" />
5
+ </svg>
@@ -0,0 +1,6 @@
1
+ <script lang="ts">
2
+ export let size: number = 14;
3
+ </script>
4
+ <svg width={size} height={size} viewBox="0 0 14 14" fill="none" aria-hidden="true" focusable="false">
5
+ <path d="M7 1.5v7m0 0L4.5 6m2.5 2.5L9.5 6M2 11h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
6
+ </svg>
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ export let size: number = 16;
3
+ </script>
4
+ <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false">
5
+ <circle cx="8" cy="8" r="6" stroke="currentColor" stroke-width="1.5" />
6
+ <path d="M6.4 6.2c.2-1 1-1.5 1.9-1.5 1.1 0 1.9.7 1.9 1.7s-.6 1.4-1.4 1.8c-.6.3-1 .6-1 1.2v.3M8 11.6h0" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
7
+ </svg>