@seekalfred/primitives 0.6.0 → 0.7.3
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/README.md +214 -15
- package/dist/activity-heatmap/activity-heatmap.d.ts +92 -0
- package/dist/activity-heatmap/activity-heatmap.js +699 -0
- package/dist/activity-heatmap/activity-heatmap.js.map +1 -0
- package/dist/activity-heatmap/index.d.ts +2 -0
- package/dist/activity-heatmap/index.js +2 -0
- package/dist/alert/alert.d.ts +53 -4
- package/dist/alert/alert.js +100 -11
- package/dist/alert/alert.js.map +1 -1
- package/dist/alert/index.d.ts +2 -2
- package/dist/alert/index.js +2 -2
- package/dist/alert-dialog/alert-dialog.d.ts +58 -18
- package/dist/alert-dialog/alert-dialog.js +152 -9
- package/dist/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/alert-dialog/index.d.ts +2 -2
- package/dist/alert-dialog/index.js +2 -2
- package/dist/animated-counter/animated-counter.d.ts +38 -0
- package/dist/animated-counter/animated-counter.js +230 -0
- package/dist/animated-counter/animated-counter.js.map +1 -0
- package/dist/animated-counter/index.d.ts +2 -0
- package/dist/animated-counter/index.js +2 -0
- package/dist/announcement-bar/announcement-bar.d.ts +67 -0
- package/dist/announcement-bar/announcement-bar.js +364 -0
- package/dist/announcement-bar/announcement-bar.js.map +1 -0
- package/dist/announcement-bar/index.d.ts +2 -0
- package/dist/announcement-bar/index.js +2 -0
- package/dist/badge/badge.d.ts +1 -1
- package/dist/bar-chart/bar-chart.d.ts +51 -0
- package/dist/bar-chart/bar-chart.js +565 -0
- package/dist/bar-chart/bar-chart.js.map +1 -0
- package/dist/bar-chart/index.d.ts +2 -0
- package/dist/bar-chart/index.js +2 -0
- package/dist/breadcrumb/breadcrumb.d.ts +2 -2
- package/dist/breadcrumb/breadcrumb.js +12 -3
- package/dist/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/brush-chart/brush-chart.d.ts +64 -0
- package/dist/brush-chart/brush-chart.js +1056 -0
- package/dist/brush-chart/brush-chart.js.map +1 -0
- package/dist/brush-chart/index.d.ts +2 -0
- package/dist/brush-chart/index.js +2 -0
- package/dist/button/button.d.ts +1 -1
- package/dist/button/button.js +31 -21
- package/dist/button/button.js.map +1 -1
- package/dist/button-group/button-group.js +3 -4
- package/dist/button-group/button-group.js.map +1 -1
- package/dist/calendar/calendar.d.ts +1 -1
- package/dist/card/card.d.ts +22 -1
- package/dist/card/card.js +60 -7
- package/dist/card/card.js.map +1 -1
- package/dist/card-stack/card-stack.d.ts +54 -0
- package/dist/card-stack/card-stack.js +492 -0
- package/dist/card-stack/card-stack.js.map +1 -0
- package/dist/card-stack/index.d.ts +2 -0
- package/dist/card-stack/index.js +2 -0
- package/dist/carousel/carousel.d.ts +77 -0
- package/dist/carousel/carousel.js +415 -0
- package/dist/carousel/carousel.js.map +1 -0
- package/dist/carousel/index.d.ts +2 -0
- package/dist/carousel/index.js +2 -0
- package/dist/checkbox/checkbox.js +4 -4
- package/dist/checkbox/checkbox.js.map +1 -1
- package/dist/chip-group/chip-group.d.ts +37 -0
- package/dist/chip-group/chip-group.js +148 -0
- package/dist/chip-group/chip-group.js.map +1 -0
- package/dist/chip-group/index.d.ts +2 -0
- package/dist/chip-group/index.js +2 -0
- package/dist/copy-button/copy-button.d.ts +18 -2
- package/dist/copy-button/copy-button.js +29 -8
- package/dist/copy-button/copy-button.js.map +1 -1
- package/dist/countdown/countdown.d.ts +45 -0
- package/dist/countdown/countdown.js +298 -0
- package/dist/countdown/countdown.js.map +1 -0
- package/dist/countdown/index.d.ts +2 -0
- package/dist/countdown/index.js +2 -0
- package/dist/date-picker/picker-parts.js +1 -1
- package/dist/date-picker/picker-parts.js.map +1 -1
- package/dist/dialog/dialog.js +1 -1
- package/dist/dialog/dialog.js.map +1 -1
- package/dist/donut-chart/donut-chart.d.ts +86 -0
- package/dist/donut-chart/donut-chart.js +593 -0
- package/dist/donut-chart/donut-chart.js.map +1 -0
- package/dist/donut-chart/index.d.ts +2 -0
- package/dist/donut-chart/index.js +2 -0
- package/dist/empty-state/empty-state.d.ts +42 -10
- package/dist/empty-state/empty-state.js +44 -26
- package/dist/empty-state/empty-state.js.map +1 -1
- package/dist/empty-state/index.d.ts +2 -2
- package/dist/empty-state/index.js +2 -2
- package/dist/file-drop-zone/file-drop-zone.js +1 -1
- package/dist/file-drop-zone/file-drop-zone.js.map +1 -1
- package/dist/filter-bar/filter-bar.d.ts +50 -26
- package/dist/filter-bar/filter-bar.js +317 -157
- package/dist/filter-bar/filter-bar.js.map +1 -1
- package/dist/gauge/gauge.d.ts +45 -0
- package/dist/gauge/gauge.js +219 -0
- package/dist/gauge/gauge.js.map +1 -0
- package/dist/gauge/index.d.ts +2 -0
- package/dist/gauge/index.js +2 -0
- package/dist/in-view-title/in-view-title.d.ts +33 -0
- package/dist/in-view-title/in-view-title.js +119 -0
- package/dist/in-view-title/in-view-title.js.map +1 -0
- package/dist/in-view-title/index.d.ts +2 -0
- package/dist/in-view-title/index.js +2 -0
- package/dist/index.d.ts +53 -10
- package/dist/index.js +52 -12
- package/dist/input/input.js +4 -4
- package/dist/input/input.js.map +1 -1
- package/dist/lib/cn.js +11 -1
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/field-message.js +28 -10
- package/dist/lib/field-message.js.map +1 -1
- package/dist/lib/field-shell.js +10 -3
- package/dist/lib/field-shell.js.map +1 -1
- package/dist/lib/field-surface.js +31 -9
- package/dist/lib/field-surface.js.map +1 -1
- package/dist/lib/flag-emoji.js +50 -0
- package/dist/lib/flag-emoji.js.map +1 -0
- package/dist/lib/flip.js +11 -3
- package/dist/lib/flip.js.map +1 -1
- package/dist/lib/menu-highlight.js +64 -0
- package/dist/lib/menu-highlight.js.map +1 -0
- package/dist/lib/motion.js +9 -2
- package/dist/lib/motion.js.map +1 -1
- package/dist/lib/rolling-value.js +1 -1
- package/dist/lib/rolling-value.js.map +1 -1
- package/dist/lib/spring-tween.js +500 -0
- package/dist/lib/spring-tween.js.map +1 -0
- package/dist/lib/swap-text.js +3 -1
- package/dist/lib/swap-text.js.map +1 -1
- package/dist/lib/use-copy-feedback.js +17 -3
- package/dist/lib/use-copy-feedback.js.map +1 -1
- package/dist/line-chart/index.d.ts +2 -0
- package/dist/line-chart/index.js +2 -0
- package/dist/line-chart/line-chart.d.ts +116 -0
- package/dist/line-chart/line-chart.js +740 -0
- package/dist/line-chart/line-chart.js.map +1 -0
- package/dist/mention-input/index.d.ts +2 -0
- package/dist/mention-input/index.js +2 -0
- package/dist/mention-input/mention-input.d.ts +98 -0
- package/dist/mention-input/mention-input.js +576 -0
- package/dist/mention-input/mention-input.js.map +1 -0
- package/dist/menu/menu.d.ts +2 -0
- package/dist/menu/menu.js +23 -12
- package/dist/menu/menu.js.map +1 -1
- package/dist/money-input/index.d.ts +2 -0
- package/dist/money-input/index.js +2 -0
- package/dist/money-input/money-input.d.ts +86 -0
- package/dist/money-input/money-input.js +613 -0
- package/dist/money-input/money-input.js.map +1 -0
- package/dist/morph-select/index.d.ts +2 -0
- package/dist/morph-select/index.js +2 -0
- package/dist/morph-select/morph-select.d.ts +89 -0
- package/dist/morph-select/morph-select.js +712 -0
- package/dist/morph-select/morph-select.js.map +1 -0
- package/dist/multi-select/index.d.ts +2 -0
- package/dist/multi-select/index.js +2 -0
- package/dist/multi-select/multi-select.d.ts +77 -0
- package/dist/multi-select/multi-select.js +209 -0
- package/dist/multi-select/multi-select.js.map +1 -0
- package/dist/number-field/index.d.ts +2 -0
- package/dist/number-field/index.js +2 -0
- package/dist/number-field/number-field.d.ts +42 -0
- package/dist/number-field/number-field.js +199 -0
- package/dist/number-field/number-field.js.map +1 -0
- package/dist/onboarding-checklist/index.d.ts +2 -0
- package/dist/onboarding-checklist/index.js +2 -0
- package/dist/onboarding-checklist/onboarding-checklist.d.ts +55 -0
- package/dist/onboarding-checklist/onboarding-checklist.js +577 -0
- package/dist/onboarding-checklist/onboarding-checklist.js.map +1 -0
- package/dist/password-field/password-field.d.ts +16 -0
- package/dist/password-field/password-field.js +39 -10
- package/dist/password-field/password-field.js.map +1 -1
- package/dist/phone-input/index.d.ts +3 -0
- package/dist/phone-input/index.js +3 -0
- package/dist/phone-input/phone-countries.d.ts +29 -0
- package/dist/phone-input/phone-countries.js +170 -0
- package/dist/phone-input/phone-countries.js.map +1 -0
- package/dist/phone-input/phone-input.d.ts +66 -0
- package/dist/phone-input/phone-input.js +440 -0
- package/dist/phone-input/phone-input.js.map +1 -0
- package/dist/popover/index.d.ts +2 -2
- package/dist/popover/index.js +2 -2
- package/dist/popover/popover.d.ts +51 -2
- package/dist/popover/popover.js +59 -8
- package/dist/popover/popover.js.map +1 -1
- package/dist/progress/progress.d.ts +16 -2
- package/dist/progress/progress.js +16 -9
- package/dist/progress/progress.js.map +1 -1
- package/dist/radio-group/index.d.ts +2 -2
- package/dist/radio-group/index.js +2 -2
- package/dist/radio-group/radio-group.d.ts +33 -3
- package/dist/radio-group/radio-group.js +110 -10
- package/dist/radio-group/radio-group.js.map +1 -1
- package/dist/reactions/index.d.ts +2 -0
- package/dist/reactions/index.js +2 -0
- package/dist/reactions/reactions.d.ts +50 -0
- package/dist/reactions/reactions.js +315 -0
- package/dist/reactions/reactions.js.map +1 -0
- package/dist/rich-text-editor/index.d.ts +3 -0
- package/dist/rich-text-editor/index.js +2 -0
- package/dist/rich-text-editor/rich-text-editor.d.ts +70 -0
- package/dist/rich-text-editor/rich-text-editor.js +909 -0
- package/dist/rich-text-editor/rich-text-editor.js.map +1 -0
- package/dist/rich-text-editor/rich-text-engine.d.ts +16 -0
- package/dist/rich-text-editor/rich-text-engine.js +366 -0
- package/dist/rich-text-editor/rich-text-engine.js.map +1 -0
- package/dist/rich-text-editor/rich-text-html.js +174 -0
- package/dist/rich-text-editor/rich-text-html.js.map +1 -0
- package/dist/rich-text-editor/rich-text-icons.js +43 -0
- package/dist/rich-text-editor/rich-text-icons.js.map +1 -0
- package/dist/ridgeline/index.d.ts +2 -0
- package/dist/ridgeline/index.js +2 -0
- package/dist/ridgeline/ridgeline.d.ts +55 -0
- package/dist/ridgeline/ridgeline.js +701 -0
- package/dist/ridgeline/ridgeline.js.map +1 -0
- package/dist/scroll-area/index.d.ts +2 -2
- package/dist/scroll-area/index.js +2 -2
- package/dist/scroll-area/scroll-area.d.ts +68 -31
- package/dist/scroll-area/scroll-area.js +212 -62
- package/dist/scroll-area/scroll-area.js.map +1 -1
- package/dist/scrub-input/evaluate.d.ts +14 -0
- package/dist/scrub-input/evaluate.js +72 -0
- package/dist/scrub-input/evaluate.js.map +1 -0
- package/dist/scrub-input/index.d.ts +3 -0
- package/dist/scrub-input/index.js +3 -0
- package/dist/scrub-input/scrub-input.d.ts +74 -0
- package/dist/scrub-input/scrub-input.js +486 -0
- package/dist/scrub-input/scrub-input.js.map +1 -0
- package/dist/search-field/search-field.d.ts +24 -2
- package/dist/search-field/search-field.js +24 -9
- package/dist/search-field/search-field.js.map +1 -1
- package/dist/select/select.d.ts +3 -1
- package/dist/select/select.js +28 -14
- package/dist/select/select.js.map +1 -1
- package/dist/separator/separator.d.ts +22 -10
- package/dist/separator/separator.js +33 -11
- package/dist/separator/separator.js.map +1 -1
- package/dist/sheet/sheet.js +2 -1
- package/dist/sheet/sheet.js.map +1 -1
- package/dist/shortcut-recorder/index.d.ts +3 -0
- package/dist/shortcut-recorder/index.js +3 -0
- package/dist/shortcut-recorder/shortcut-model.d.ts +27 -0
- package/dist/shortcut-recorder/shortcut-model.js +206 -0
- package/dist/shortcut-recorder/shortcut-model.js.map +1 -0
- package/dist/shortcut-recorder/shortcut-recorder.d.ts +93 -0
- package/dist/shortcut-recorder/shortcut-recorder.js +489 -0
- package/dist/shortcut-recorder/shortcut-recorder.js.map +1 -0
- package/dist/slider/index.d.ts +2 -2
- package/dist/slider/slider.d.ts +46 -14
- package/dist/slider/slider.js +151 -67
- package/dist/slider/slider.js.map +1 -1
- package/dist/slope-chart/index.d.ts +2 -0
- package/dist/slope-chart/index.js +2 -0
- package/dist/slope-chart/slope-chart.d.ts +54 -0
- package/dist/slope-chart/slope-chart.js +568 -0
- package/dist/slope-chart/slope-chart.js.map +1 -0
- package/dist/sparkline/index.d.ts +2 -0
- package/dist/sparkline/index.js +2 -0
- package/dist/sparkline/sparkline.d.ts +46 -0
- package/dist/sparkline/sparkline.js +390 -0
- package/dist/sparkline/sparkline.js.map +1 -0
- package/dist/split-bar/index.d.ts +2 -0
- package/dist/split-bar/index.js +2 -0
- package/dist/split-bar/split-bar.d.ts +62 -0
- package/dist/split-bar/split-bar.js +513 -0
- package/dist/split-bar/split-bar.js.map +1 -0
- package/dist/split-button/split-button.d.ts +1 -1
- package/dist/split-button/split-button.js +12 -11
- package/dist/split-button/split-button.js.map +1 -1
- package/dist/stat-card/index.d.ts +2 -2
- package/dist/stat-card/index.js +2 -2
- package/dist/stat-card/stat-card.d.ts +58 -5
- package/dist/stat-card/stat-card.js +144 -17
- package/dist/stat-card/stat-card.js.map +1 -1
- package/dist/stepper/index.d.ts +2 -0
- package/dist/stepper/index.js +2 -0
- package/dist/stepper/stepper.d.ts +51 -0
- package/dist/stepper/stepper.js +215 -0
- package/dist/stepper/stepper.js.map +1 -0
- package/dist/streamgraph/index.d.ts +2 -0
- package/dist/streamgraph/index.js +2 -0
- package/dist/streamgraph/streamgraph.d.ts +70 -0
- package/dist/streamgraph/streamgraph.js +613 -0
- package/dist/streamgraph/streamgraph.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/swipe-actions/index.d.ts +2 -0
- package/dist/swipe-actions/index.js +2 -0
- package/dist/swipe-actions/swipe-actions.d.ts +67 -0
- package/dist/swipe-actions/swipe-actions.js +552 -0
- package/dist/swipe-actions/swipe-actions.js.map +1 -0
- package/dist/switch/switch.js +2 -2
- package/dist/switch/switch.js.map +1 -1
- package/dist/table/index.d.ts +2 -2
- package/dist/table/index.js +2 -2
- package/dist/table/table.d.ts +55 -3
- package/dist/table/table.js +340 -165
- package/dist/table/table.js.map +1 -1
- package/dist/tabs/tabs.js +2 -2
- package/dist/tabs/tabs.js.map +1 -1
- package/dist/tag-input/index.d.ts +2 -0
- package/dist/tag-input/index.js +2 -0
- package/dist/tag-input/tag-input.d.ts +40 -0
- package/dist/tag-input/tag-input.js +269 -0
- package/dist/tag-input/tag-input.js.map +1 -0
- package/dist/text-morph/index.d.ts +2 -0
- package/dist/text-morph/index.js +2 -0
- package/dist/text-morph/text-morph.d.ts +23 -0
- package/dist/text-morph/text-morph.js +21 -0
- package/dist/text-morph/text-morph.js.map +1 -0
- package/dist/text-reveal/index.d.ts +2 -0
- package/dist/text-reveal/index.js +2 -0
- package/dist/text-reveal/text-reveal.d.ts +27 -0
- package/dist/text-reveal/text-reveal.js +51 -0
- package/dist/text-reveal/text-reveal.js.map +1 -0
- package/dist/text-shimmer/index.d.ts +2 -0
- package/dist/text-shimmer/index.js +2 -0
- package/dist/text-shimmer/text-shimmer.d.ts +29 -0
- package/dist/text-shimmer/text-shimmer.js +29 -0
- package/dist/text-shimmer/text-shimmer.js.map +1 -0
- package/dist/time-picker/time-picker.d.ts +36 -1
- package/dist/time-picker/time-picker.js +35 -7
- package/dist/time-picker/time-picker.js.map +1 -1
- package/dist/toast/index.d.ts +2 -2
- package/dist/toast/index.js +2 -2
- package/dist/toast/toast.d.ts +7 -1
- package/dist/toast/toast.js +82 -40
- package/dist/toast/toast.js.map +1 -1
- package/dist/tooltip/tooltip.d.ts +9 -2
- package/dist/tooltip/tooltip.js +7 -7
- package/dist/tooltip/tooltip.js.map +1 -1
- package/dist/treemap/index.d.ts +2 -0
- package/dist/treemap/index.js +2 -0
- package/dist/treemap/treemap.d.ts +53 -0
- package/dist/treemap/treemap.js +699 -0
- package/dist/treemap/treemap.js.map +1 -0
- package/dist/usage-meter/index.d.ts +2 -0
- package/dist/usage-meter/index.js +2 -0
- package/dist/usage-meter/usage-meter.d.ts +80 -0
- package/dist/usage-meter/usage-meter.js +458 -0
- package/dist/usage-meter/usage-meter.js.map +1 -0
- package/dist/waffle-chart/index.d.ts +2 -0
- package/dist/waffle-chart/index.js +2 -0
- package/dist/waffle-chart/waffle-chart.d.ts +57 -0
- package/dist/waffle-chart/waffle-chart.js +426 -0
- package/dist/waffle-chart/waffle-chart.js.map +1 -0
- package/package.json +165 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ridgeline.js","names":[],"sources":["../../src/ridgeline/ridgeline.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type PointerEvent,\n} from \"react\";\n\nimport { cn } from \"../lib/cn.js\";\nimport { mergeRefs } from \"../lib/merge-refs.js\";\nimport { prefersReducedMotion, useIsomorphicLayoutEffect } from \"../lib/motion.js\";\nimport { REVEAL, SWELL, tween } from \"../lib/spring-tween.js\";\n\n/**\n * Ridgeline: compare the shape of many distributions at once, such as daily\n * temperatures by month or response times by region. Each series is one ridge, a\n * smoothed density of its raw values, drawn top to bottom and overlapping the row\n * behind it; the ridges share one value axis.\n *\n * The ridges roll in from the top row down once the chart is in view. New data\n * morphs every ridge from the shape on screen, and the axis follows. Hovering,\n * touching or the arrow keys lift one ridge above its neighbours with its middle\n * half shaded and its median marked, step the others back, and show a tooltip with\n * the median, the middle half and the range. Moving along the values shows how\n * much of the series sits at or below that value. Each ridge is shaded by its\n * median, from a light tint to the full first series colour, with the scale\n * under the axis.\n *\n * Plain SVG written straight to the DOM by one small spring tween.\n */\nexport interface RidgelineSeries {\n /** Stable identity. A ridge that survives a data change morphs into its new shape. */\n id: string;\n label: string;\n /** Raw observations. The ridge is a smoothed density of these values. */\n values: number[];\n}\n\nexport interface RidgelineProps {\n /** One ridge per series, drawn top to bottom. */\n series: RidgelineSeries[];\n /** What is measured, such as \"Daily highs in Zurich\". Names the chart for assistive technology. */\n label: string;\n /** Unit after each value, such as \"°C\". */\n unit?: string;\n formatValue?: (value: number) => string;\n /** Value range of the axis. Defaults to the data with a little room on each side. */\n domain?: [number, number];\n /** How far a ridge may rise into the rows above, in row heights. @default 2.4 */\n overlap?: number;\n /** Height of one row in pixels. @default 30 */\n rowHeight?: number;\n /** Smoothing in value units. Defaults to Silverman's rule per series. */\n bandwidth?: number;\n /** Shades each ridge by its median, from a light tint to the full first series colour, and shows the scale under the axis. @default true */\n tint?: boolean;\n /** Controlled id of the lifted ridge. */\n active?: string | null;\n defaultActive?: string | null;\n onActiveChange?: (id: string | null) => void;\n /** @default \"No data yet\" */\n emptyLabel?: string;\n /** Extra classes for the root. Merged last. */\n className?: string;\n}\n\ntype Stats = { q1: number; median: number; q3: number; min: number; max: number; n: number; sorted: number[] };\ntype Shape = { xs: number[]; ys: number[]; row: number; q1: number; median: number; q3: number };\n\n/** Points along each ridge, the axis strip, the gap between the tooltip and what it describes, and how far the lifted ridge rises, in pixels. */\nconst SAMPLES = 96;\nconst AXIS = 28;\nconst TIP = 14;\nconst LIFT = 6;\nconst GROUPED = new Intl.NumberFormat(\"en-US\", { maximumFractionDigits: 1 });\nconst PERCENT = new Intl.NumberFormat(\"en-US\", { style: \"percent\", maximumFractionDigits: 0 });\nconst clamp = (value: number, low: number, high: number) => Math.min(high, Math.max(low, value));\nconst mix = (a: number, b: number, t: number) => a + (b - a) * t;\n\nfunction quantile(sorted: number[], q: number) {\n if (!sorted.length) return 0;\n const at = (sorted.length - 1) * q;\n const low = Math.floor(at);\n const high = Math.ceil(at);\n return sorted[low]! + (sorted[high]! - sorted[low]!) * (at - low);\n}\nfunction statsOf(values: number[]): Stats {\n const sorted = values.filter(Number.isFinite).sort((a, b) => a - b);\n return {\n sorted,\n n: sorted.length,\n min: sorted[0] ?? 0,\n max: sorted[sorted.length - 1] ?? 0,\n q1: quantile(sorted, 0.25),\n median: quantile(sorted, 0.5),\n q3: quantile(sorted, 0.75),\n };\n}\n/** Silverman's rule of thumb for the smoothing of a Gaussian kernel. */\nfunction silverman(stats: Stats) {\n if (stats.n < 2) return 1;\n const mean = stats.sorted.reduce((sum, value) => sum + value, 0) / stats.n;\n const sd = Math.sqrt(stats.sorted.reduce((sum, value) => sum + (value - mean) ** 2, 0) / (stats.n - 1));\n const spread = Math.min(sd, (stats.q3 - stats.q1) / 1.34 || sd);\n return Math.max(1e-6, 0.9 * (spread || 1) * Math.pow(stats.n, -0.2));\n}\nfunction niceStep(span: number, count: number) {\n const raw = span / Math.max(1, count) || 1;\n const power = Math.pow(10, Math.floor(Math.log10(raw)));\n const unit = raw / power;\n return (unit >= 5 ? 5 : unit >= 2 ? 2 : 1) * power;\n}\n/** Samples a Gaussian kernel density across the domain. */\nfunction density(stats: Stats, lo: number, hi: number, bandwidth: number) {\n const xs: number[] = [];\n const ys: number[] = [];\n const norm = 1 / (Math.max(1, stats.n) * bandwidth * Math.sqrt(2 * Math.PI));\n for (let i = 0; i < SAMPLES; i++) {\n const x = lo + ((hi - lo) * i) / (SAMPLES - 1);\n let sum = 0;\n for (const value of stats.sorted) {\n const u = (x - value) / bandwidth;\n if (u > -5 && u < 5) sum += Math.exp(-0.5 * u * u);\n }\n xs.push(x);\n ys.push(sum * norm);\n }\n return { xs, ys };\n}\nconst heightAt = (shape: Shape, x: number) => {\n const { xs, ys } = shape;\n if (x <= xs[0]! || x >= xs[xs.length - 1]!) return 0;\n let i = 1;\n while (i < xs.length - 1 && xs[i]! < x) i++;\n const t = (x - xs[i - 1]!) / (xs[i]! - xs[i - 1]! || 1);\n return mix(ys[i - 1]!, ys[i]!, t);\n};\n/** Ridge tone: one hue, the first series colour, from a light tint (low median) to full strength (high median), so the scale never passes through a muddy middle. */\nconst toneOf = (t: number) => `color-mix(in oklab, var(--color-chart-1) ${Math.round(38 + clamp(t, 0, 1) * 62)}%, var(--color-surface))`;\n\nexport const Ridgeline = forwardRef<HTMLElement, RidgelineProps>(function Ridgeline(\n {\n series,\n label,\n unit = \"\",\n formatValue,\n domain,\n overlap = 2.4,\n rowHeight = 30,\n bandwidth,\n tint = true,\n active,\n defaultActive = null,\n onActiveChange,\n emptyLabel = \"No data yet\",\n className,\n },\n ref,\n) {\n const figure = useRef<HTMLElement | null>(null);\n const refs = useMemo(() => mergeRefs(ref, figure), [ref]);\n const plot = useRef<HTMLDivElement>(null);\n const tip = useRef<HTMLDivElement>(null);\n const cross = useRef<HTMLDivElement>(null);\n // A true minus sign keeps negative values tight and lined up with the tabular digits.\n const format = (value: number) => (formatValue ? formatValue(value) : `${GROUPED.format(value).replace(\"-\", \"−\")}${unit}`);\n\n const [width, setWidth] = useState(0);\n useIsomorphicLayoutEffect(() => {\n const node = plot.current;\n if (!node || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(() => setWidth(node.clientWidth));\n observer.observe(node);\n setWidth(node.clientWidth);\n return () => observer.disconnect();\n }, []);\n\n // Targets: one density per series on a shared domain, scaled so the tallest peak of all rises `overlap` rows.\n const signature = JSON.stringify([series, domain, bandwidth]);\n const model = useMemo(() => {\n const stats = series.map((entry) => statsOf(entry.values));\n const widths = stats.map((entry) => bandwidth ?? silverman(entry));\n const filled = stats.map((entry, index) => ({ entry, room: 2.5 * widths[index]! })).filter(({ entry }) => entry.n);\n let lo = domain?.[0] ?? Math.min(...filled.map(({ entry, room }) => entry.min - room));\n let hi = domain?.[1] ?? Math.max(...filled.map(({ entry, room }) => entry.max + room));\n if (!Number.isFinite(lo) || !Number.isFinite(hi) || lo === hi) {\n lo = 0;\n hi = 1;\n }\n if (!domain) {\n const step = niceStep(hi - lo, 5);\n lo = Math.floor(lo / step) * step;\n hi = Math.ceil(hi / step) * step;\n }\n const curves = stats.map((entry, index) =>\n entry.n\n ? density(entry, lo, hi, widths[index]!)\n : { xs: Array.from({ length: SAMPLES }, (_, i) => lo + ((hi - lo) * i) / (SAMPLES - 1)), ys: new Array<number>(SAMPLES).fill(0) },\n );\n const peak = Math.max(1e-9, ...curves.flatMap((curve) => curve.ys));\n const shapes = new Map<string, Shape>(\n series.map((entry, index) => {\n const curve = curves[index]!;\n const stat = stats[index]!;\n return [entry.id, { xs: curve.xs, ys: curve.ys.map((y) => y / peak), row: index, q1: stat.q1, median: stat.median, q3: stat.q3 }];\n }),\n );\n return { stats: new Map(series.map((entry, index) => [entry.id, stats[index]!])), shapes, lo, hi };\n // The signature stands for the series, the domain and the bandwidth.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [signature]);\n\n const [ownActive, setOwnActive] = useState<string | null>(defaultActive);\n const current = active !== undefined ? active : ownActive;\n const setCurrent = (id: string | null) => {\n if (active === undefined) setOwnActive(id);\n if (id !== current) onActiveChange?.(id);\n };\n const [cursor, setCursor] = useState<{ value: number; pointerY: number | null } | null>(null);\n\n const narrow = width > 0 && width < 420;\n const gutter = narrow ? 36 : 52;\n const top = Math.ceil((overlap - 1) * rowHeight) + LIFT + 8;\n const height = top + series.length * rowHeight + AXIS;\n const plotWidth = Math.max(40, width - gutter - 4);\n const baselineOf = (row: number) => top + (row + 1) * rowHeight;\n\n // Drawn geometry lives outside React; a spring interpolates it from what is on screen to the new targets.\n const drawn = useRef({ shapes: new Map<string, Shape>(), lo: 0, hi: 1 });\n const geometry = useRef({ gutter, plotWidth, rowHeight, overlap, top, current });\n const xOf = (value: number) => {\n const d = drawn.current;\n return gutter + ((value - d.lo) / (d.hi - d.lo || 1)) * plotWidth;\n };\n\n const paint = () => {\n const root = plot.current;\n if (!root) return;\n const d = drawn.current;\n const g = geometry.current;\n const sx = (value: number) => g.gutter + ((value - d.lo) / (d.hi - d.lo || 1)) * g.plotWidth;\n const lift = g.rowHeight * g.overlap;\n /** A ridge as a path; `from` and `to` cut it to a stretch of the axis (the middle half). */\n const curvePath = (shape: Shape, closed: boolean, from = -Infinity, to = Infinity) => {\n const base = g.top + (shape.row + 1) * g.rowHeight;\n const points: string[] = [];\n const push = (x: number, y: number) => points.push(`${sx(x).toFixed(2)},${(base - y * lift).toFixed(2)}`);\n if (from > -Infinity) push(from, heightAt(shape, from));\n shape.xs.forEach((x, i) => {\n if (x > from && x < to) push(x, shape.ys[i]!);\n });\n if (to < Infinity) push(to, heightAt(shape, to));\n if (!points.length) return \"\";\n const first = from > -Infinity ? from : shape.xs[0]!;\n const last = to < Infinity ? to : shape.xs[shape.xs.length - 1]!;\n return closed ? `M${sx(first).toFixed(2)},${base}L${points.join(\"L\")}L${sx(last).toFixed(2)},${base}Z` : `M${points.join(\"L\")}`;\n };\n const mark = (node: Element | null, shape: Shape) => {\n if (!node) return;\n const x = sx(shape.median).toFixed(2);\n const base = g.top + (shape.row + 1) * g.rowHeight;\n node.setAttribute(\"x1\", x);\n node.setAttribute(\"x2\", x);\n node.setAttribute(\"y1\", String(base));\n node.setAttribute(\"y2\", (base - heightAt(shape, shape.median) * lift).toFixed(2));\n };\n for (const [id, shape] of d.shapes) {\n const group = root.querySelector(`[data-ridge=\"${CSS.escape(id)}\"]`);\n group?.querySelector(\"[data-part=fill]\")?.setAttribute(\"d\", curvePath(shape, true));\n group?.querySelector(\"[data-part=line]\")?.setAttribute(\"d\", curvePath(shape, false));\n mark(group?.querySelector(\"[data-part=median]\") ?? null, shape);\n }\n const shape = g.current ? d.shapes.get(g.current) : undefined;\n if (shape) {\n const lens = root.querySelector(\"[data-part=lens]\");\n lens?.querySelector(\"[data-part=lens-fill]\")?.setAttribute(\"d\", curvePath(shape, true));\n lens?.querySelector(\"[data-part=lens-line]\")?.setAttribute(\"d\", curvePath(shape, false));\n lens?.querySelector(\"[data-part=lens-band]\")?.setAttribute(\"d\", curvePath(shape, true, shape.q1, shape.q3));\n mark(lens?.querySelector(\"[data-part=lens-median]\") ?? null, shape);\n }\n for (const node of root.querySelectorAll<HTMLElement>(\"[data-tick]\")) {\n node.style.transform = `translate3d(${sx(Number(node.dataset.tick)).toFixed(2)}px, 0, 0)`;\n }\n };\n const paintRef = useRef(paint);\n useIsomorphicLayoutEffect(() => {\n geometry.current = { gutter, plotWidth, rowHeight, overlap, top, current };\n paintRef.current = paint;\n paint();\n });\n\n // The ridges roll in once a third of the chart is in view.\n const [shown, setShown] = useState(false);\n useEffect(() => {\n const node = figure.current;\n if (!node || prefersReducedMotion() || typeof IntersectionObserver === \"undefined\") {\n setShown(true);\n return;\n }\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (!entry?.isIntersecting) return;\n observer.disconnect();\n setShown(true);\n },\n { threshold: 0.3 },\n );\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n // New data morphs every ridge, and the axis, from what is on screen; the first time, ridges grow from flat, a beat apart from the top row down.\n useEffect(() => {\n if (!shown) return;\n const d = drawn.current;\n const first = d.shapes.size === 0;\n const from = new Map<string, Shape>();\n for (const [id, target] of model.shapes) {\n const now = d.shapes.get(id);\n from.set(id, now ? { ...now, xs: [...now.xs], ys: [...now.ys] } : { ...target, ys: target.ys.map(() => 0), q1: target.median, q3: target.median });\n }\n const fromLo = first ? model.lo : d.lo;\n const fromHi = first ? model.hi : d.hi;\n const settle = () => {\n d.shapes = new Map([...model.shapes].map(([id, shape]) => [id, { ...shape }]));\n d.lo = model.lo;\n d.hi = model.hi;\n paintRef.current();\n };\n d.shapes = new Map([...from].map(([id, shape]) => [id, { ...shape, xs: [...shape.xs], ys: [...shape.ys] }]));\n return tween(\n first ? SWELL : REVEAL,\n (t) => {\n d.lo = mix(fromLo, model.lo, t);\n d.hi = mix(fromHi, model.hi, t);\n for (const [id, to] of model.shapes) {\n const f = from.get(id)!;\n const out = d.shapes.get(id)!;\n const local = first ? clamp((t - to.row * 0.025) / (1 - Math.min(0.5, model.shapes.size * 0.025)), 0, 1) : t;\n for (let i = 0; i < SAMPLES; i++) {\n out.xs[i] = mix(f.xs[i]!, to.xs[i]!, local);\n out.ys[i] = mix(f.ys[i]!, to.ys[i]!, local);\n }\n out.row = mix(f.row, to.row, local);\n out.q1 = mix(f.q1, to.q1, local);\n out.median = mix(f.median, to.median, local);\n out.q3 = mix(f.q3, to.q3, local);\n }\n paintRef.current();\n },\n settle,\n );\n }, [shown, model]);\n\n // Axis ticks for the target domain; their positions follow the drawn domain every frame.\n const tickCount = Math.max(2, Math.floor(plotWidth / 72));\n const step = niceStep(model.hi - model.lo, tickCount);\n const ticks: number[] = [];\n for (let value = Math.ceil(model.lo / step) * step; value <= model.hi + 1e-9; value += step) ticks.push(Math.round(value * 1e6) / 1e6 || 0);\n\n const activeStats = current ? model.stats.get(current) : undefined;\n const activeSeries = current ? series.find((entry) => entry.id === current) : undefined;\n const reading =\n cursor && activeStats\n ? { value: cursor.value, below: activeStats.n ? activeStats.sorted.filter((value) => value <= cursor.value).length / activeStats.n : 0 }\n : null;\n // The tooltip keeps its last content while it fades out, so it never collapses to an empty box on leave.\n const [held, setHeld] = useState<{ id: string; value: number | null } | null>(null);\n if (current && (held?.id !== current || held.value !== (reading?.value ?? null))) setHeld({ id: current, value: reading?.value ?? null });\n const tipSeries = held ? series.find((entry) => entry.id === held.id) : undefined;\n const tipStats = held ? model.stats.get(held.id) : undefined;\n const tipBelow = held && held.value !== null && tipStats?.n ? tipStats.sorted.filter((value) => value <= held.value!).length / tipStats.n : 0;\n\n // The tooltip trails the pointer or the keyboard cursor and stays inside the chart; it glides between ridges once showing.\n const shownBefore = useRef(false);\n useIsomorphicLayoutEffect(() => {\n const bubble = tip.current;\n const shape = current ? model.shapes.get(current) : undefined;\n if (cross.current) cross.current.style.transform = `translate3d(${reading ? xOf(reading.value).toFixed(2) : 0}px, 0, 0)`;\n if (!bubble || !shape || !width) {\n shownBefore.current = false;\n return;\n }\n const tw = bubble.offsetWidth;\n const th = bubble.offsetHeight;\n const ax = reading ? xOf(reading.value) : xOf(shape.median);\n const ay = cursor?.pointerY ?? baselineOf(shape.row) - heightAt(shape, shape.median) * rowHeight * overlap - LIFT;\n let left = ax + TIP;\n if (left + tw > width) left = ax - TIP - tw;\n let y = ay - th - TIP;\n if (y < 0) y = ay + TIP;\n if (!shownBefore.current) bubble.style.transition = \"none\";\n bubble.style.translate = `${clamp(left, 0, Math.max(0, width - tw))}px ${clamp(y, 0, Math.max(0, height - th))}px`;\n if (!shownBefore.current) {\n void bubble.offsetWidth;\n bubble.style.transition = \"\";\n }\n shownBefore.current = true;\n });\n\n const valueAt = (x: number) => {\n const d = drawn.current;\n return d.lo + clamp((x - gutter) / plotWidth, 0, 1) * (d.hi - d.lo);\n };\n /** The ridge under the pointer: the front-most one whose outline holds it, else the row it is in. */\n const pick = (x: number, y: number) => {\n const value = valueAt(x);\n const lift = rowHeight * overlap;\n let best: Shape | null = null;\n let bestId: string | null = null;\n for (const [id, shape] of drawn.current.shapes) {\n const base = baselineOf(shape.row);\n const h = heightAt(shape, value) * lift;\n if (y <= base + 2 && y >= base - h - 4 && (!best || shape.row > best.row)) {\n best = shape;\n bestId = id;\n }\n }\n if (!bestId) {\n const row = clamp(Math.floor((y - top) / rowHeight), 0, series.length - 1);\n bestId = series[row]?.id ?? null;\n }\n return { id: bestId, value };\n };\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n const rect = event.currentTarget.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n if (x < gutter - 8 || y > height - AXIS + 4) {\n if (event.pointerType === \"mouse\") {\n setCurrent(null);\n setCursor(null);\n }\n return;\n }\n const hit = pick(x, y);\n setCurrent(hit.id);\n setCursor({ value: hit.value, pointerY: y });\n };\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const at = current ? series.findIndex((entry) => entry.id === current) : -1;\n const choose = (index: number) => {\n event.preventDefault();\n const next = series[clamp(index, 0, series.length - 1)];\n if (!next) return;\n setCurrent(next.id);\n setCursor({ value: cursor?.value ?? model.stats.get(next.id)?.median ?? model.lo, pointerY: null });\n };\n const nudge = (direction: number) => {\n event.preventDefault();\n if (!current) {\n choose(0);\n return;\n }\n const base = cursor?.value ?? model.stats.get(current)?.median ?? model.lo;\n setCursor({ value: clamp((Math.round(base / step) + direction) * step, model.lo, model.hi), pointerY: null });\n };\n if (event.key === \"ArrowDown\") choose(at + 1);\n else if (event.key === \"ArrowUp\") choose(at < 0 ? 0 : at - 1);\n else if (event.key === \"Home\") choose(0);\n else if (event.key === \"End\") choose(series.length - 1);\n else if (event.key === \"ArrowRight\") nudge(1);\n else if (event.key === \"ArrowLeft\") nudge(-1);\n else if (event.key === \"Escape\" && current) {\n event.preventDefault();\n setCurrent(null);\n setCursor(null);\n }\n };\n\n const empty = !series.length || series.every((entry) => !entry.values.length);\n const ridgeColor = (value: number) => (tint ? toneOf((value - model.lo) / (model.hi - model.lo || 1)) : \"var(--color-chart-1)\");\n const describe = (entry: RidgelineSeries) => {\n const s = model.stats.get(entry.id)!;\n return `${entry.label}: median ${format(s.median)}, middle half ${format(s.q1)} to ${format(s.q3)}, range ${format(s.min)} to ${format(s.max)}, ${s.n} values`;\n };\n const spoken = activeSeries ? `${describe(activeSeries)}${reading ? `. ${PERCENT.format(reading.below)} at or below ${format(reading.value)}` : \"\"}` : \"\";\n const summary = empty ? `${label}. ${emptyLabel}.` : `${label}. ${series.map(describe).join(\". \")}.`;\n\n return (\n <figure ref={refs} data-slot=\"ridgeline\" aria-label={label} className={cn(\"ridgeline box-border font-sans text-foreground\", className)}>\n <div\n ref={plot}\n data-slot=\"ridgeline-plot\"\n data-active={current ? \"\" : undefined}\n data-scrubbing={current ? \"\" : undefined}\n data-cursor={reading ? \"\" : undefined}\n role={empty ? undefined : \"slider\"}\n tabIndex={empty ? undefined : 0}\n aria-label={empty ? undefined : `${label}, choose a ridge`}\n aria-orientation={empty ? undefined : \"vertical\"}\n aria-valuemin={empty ? undefined : 1}\n aria-valuemax={empty ? undefined : series.length}\n aria-valuenow={empty ? undefined : (activeSeries ? series.indexOf(activeSeries) : 0) + 1}\n aria-valuetext={empty ? undefined : spoken || summary}\n className=\"ridgeline-plot\"\n style={{ height }}\n onPointerMove={onPointerMove}\n onPointerDown={onPointerMove}\n onPointerLeave={(event) => {\n if (event.pointerType === \"mouse\") {\n setCurrent(null);\n setCursor(null);\n }\n }}\n onKeyDown={onKeyDown}\n onBlur={() => {\n setCurrent(null);\n setCursor(null);\n }}\n >\n <div aria-hidden=\"true\" className=\"pointer-events-none absolute inset-x-0 top-0\" style={{ height: height - AXIS + 22 }}>\n {ticks.map((value) => (\n <div key={value} data-tick={value} className=\"ridgeline-tick motion-safe:animate-fade-in\" style={{ top: top - rowHeight * 0.5 }}>\n <span className=\"ridgeline-tick-label\">{format(value)}</span>\n </div>\n ))}\n </div>\n <div ref={cross} aria-hidden=\"true\" className=\"ridgeline-crosshair\" style={{ top: top - rowHeight * 0.5, height: height - AXIS - top + rowHeight * 0.5 }} />\n <svg width={width || undefined} height={height} viewBox={`0 0 ${Math.max(1, width)} ${height}`} aria-hidden=\"true\" focusable=\"false\" className=\"absolute inset-0 block overflow-visible\">\n {series.map((entry) => (\n <g\n key={entry.id}\n data-ridge={entry.id}\n data-dim={(current !== null && current !== entry.id) || undefined}\n data-lifted={current === entry.id || undefined}\n className=\"ridgeline-ridge\"\n style={{ \"--ridge\": ridgeColor(model.stats.get(entry.id)?.median ?? model.lo) } as CSSProperties}\n >\n <path data-part=\"fill\" className=\"ridgeline-fill\" />\n <line data-part=\"median\" className=\"ridgeline-median\" />\n <path data-part=\"line\" className=\"ridgeline-line\" />\n </g>\n ))}\n <g\n data-part=\"lens\"\n data-on={current ? \"\" : undefined}\n className=\"ridgeline-lens\"\n style={tipStats ? ({ \"--ridge\": ridgeColor(tipStats.median) } as CSSProperties) : undefined}\n >\n <path data-part=\"lens-fill\" className=\"ridgeline-lens-fill\" />\n <path data-part=\"lens-band\" className=\"ridgeline-lens-band\" />\n <line data-part=\"lens-median\" className=\"ridgeline-lens-median\" />\n <path data-part=\"lens-line\" className=\"ridgeline-lens-line\" />\n </g>\n </svg>\n <div aria-hidden=\"true\" className=\"pointer-events-none absolute inset-0\">\n {series.map((entry, index) => (\n <span key={entry.id} data-active={current === entry.id || undefined} className=\"ridgeline-row-label\" style={{ top: baselineOf(index) - 18, width: gutter - 10 }}>\n {entry.label}\n </span>\n ))}\n </div>\n {empty ? <p className=\"pointer-events-none absolute inset-0 m-0 grid place-items-center text-sm text-muted-foreground\">{emptyLabel}</p> : null}\n <div ref={tip} aria-hidden=\"true\" data-slot=\"ridgeline-tooltip\" className=\"line-chart-tooltip\">\n {tipSeries && tipStats ? (\n <>\n <p className=\"m-0 mb-0.5 text-xs text-text-secondary\">{tipSeries.label}</p>\n <p className=\"ridgeline-tip-row text-sm font-medium\">\n <span className=\"text-xs font-normal text-muted-foreground\">Median</span>\n <span>{format(tipStats.median)}</span>\n </p>\n <p className=\"ridgeline-tip-row text-xs\">\n <span className=\"text-muted-foreground\">Middle half</span>\n <span>\n {format(tipStats.q1)} to {format(tipStats.q3)}\n </span>\n </p>\n <p className=\"ridgeline-tip-row text-xs\">\n <span className=\"text-muted-foreground\">Range</span>\n <span>\n {format(tipStats.min)} to {format(tipStats.max)}\n </span>\n </p>\n {held?.value != null ? (\n <p className=\"m-0 mt-1 text-xs tabular-nums text-muted-foreground\">\n {PERCENT.format(tipBelow)} at or below {format(held.value)}\n </p>\n ) : null}\n </>\n ) : null}\n </div>\n </div>\n {tint && !empty ? (\n <div aria-hidden=\"true\" className=\"mt-3 flex flex-wrap items-center justify-end gap-2 text-xs tabular-nums text-muted-foreground\">\n <span className=\"me-1 text-text-secondary\">Median</span>\n <span>{format(model.lo)}</span>\n <span className=\"inline-flex gap-0.5\">\n {[0, 0.25, 0.5, 0.75, 1].map((at) => (\n <span key={at} className=\"ridgeline-step\" style={{ \"--ridge\": toneOf(at) } as CSSProperties} />\n ))}\n </span>\n <span>{format(model.hi)}</span>\n </div>\n ) : null}\n <p className=\"sr-only\">{summary}</p>\n <p className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n {spoken}\n </p>\n {empty ? null : (\n <div className=\"sr-only\">\n <table>\n <caption>{label}</caption>\n <thead>\n <tr>\n <th scope=\"col\">Series</th>\n <th scope=\"col\">Median</th>\n <th scope=\"col\">First quartile</th>\n <th scope=\"col\">Third quartile</th>\n <th scope=\"col\">Lowest</th>\n <th scope=\"col\">Highest</th>\n <th scope=\"col\">Count</th>\n </tr>\n </thead>\n <tbody>\n {series.map((entry) => {\n const s = model.stats.get(entry.id)!;\n return (\n <tr key={entry.id}>\n <th scope=\"row\">{entry.label}</th>\n <td>{format(s.median)}</td>\n <td>{format(s.q1)}</td>\n <td>{format(s.q3)}</td>\n <td>{format(s.min)}</td>\n <td>{format(s.max)}</td>\n <td>{s.n}</td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n )}\n </figure>\n );\n});\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ScrollArea, ScrollAreaProps, scrollAreaVariants } from "./scroll-area.js";
|
|
2
|
-
export { ScrollArea, type ScrollAreaProps, scrollAreaVariants };
|
|
1
|
+
import { ScrollArea, ScrollAreaProps, scrollAreaRootVariants, scrollAreaVariants } from "./scroll-area.js";
|
|
2
|
+
export { ScrollArea, type ScrollAreaProps, scrollAreaRootVariants, scrollAreaVariants };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ScrollArea, scrollAreaVariants } from "./scroll-area.js";
|
|
2
|
-
export { ScrollArea, scrollAreaVariants };
|
|
1
|
+
import { ScrollArea, scrollAreaRootVariants, scrollAreaVariants } from "./scroll-area.js";
|
|
2
|
+
export { ScrollArea, scrollAreaRootVariants, scrollAreaVariants };
|
|
@@ -1,38 +1,44 @@
|
|
|
1
1
|
import { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
2
|
//#region src/scroll-area/scroll-area.d.ts
|
|
3
3
|
/**
|
|
4
|
-
* ScrollArea
|
|
5
|
-
*
|
|
4
|
+
* ScrollArea: a native scroll container with thin overlay scrollbars and edge
|
|
5
|
+
* fades. React Aria has no equivalent, so the scrolling stays the browser's --
|
|
6
|
+
* keyboard, touch momentum and scroll snap all behave as the platform expects --
|
|
7
|
+
* and only the scrollbar is drawn here.
|
|
6
8
|
*
|
|
7
|
-
* Census: fourteen paths match, thirteen are counted, ELEVEN render
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `orientation="horizontal"` has zero call sites.
|
|
9
|
+
* Census: fourteen paths match, thirteen are counted, ELEVEN render anything,
|
|
10
|
+
* and across them 17 uses. Every one passes `className` and nothing else, and 13
|
|
11
|
+
* of the 17 are a height or flex constraint plus padding. The legacy Radix one
|
|
12
|
+
* cannot be scrolled by keyboard at all.
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* `ScrollArea` cannot be scrolled by keyboard at all.
|
|
14
|
+
* The native scrollbar is hidden and replaced by an overlay pill that appears
|
|
15
|
+
* while scrolling or hovering and fades away at rest (or stays, with
|
|
16
|
+
* `scrollbars="always"`). It is written straight to the DOM on each scroll
|
|
17
|
+
* frame, so scrolling never re-renders React. The pill can be dragged, and
|
|
18
|
+
* pressing its track pages toward the pointer.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* WHERE THINGS LAND. `className`, `style` and the rest go on the ROOT, the box
|
|
21
|
+
* that carries the height and the optional card. `ref` and `viewportClassName`
|
|
22
|
+
* go on the VIEWPORT, the element that really scrolls -- so a caller can call
|
|
23
|
+
* `ref.current.scrollTo(...)` or `scrollBy(...)` for a "back to top" or an
|
|
24
|
+
* arrow button, and put padding on the content without moving the scrollbar
|
|
25
|
+
* inside it.
|
|
23
26
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* those but is non-standard and Firefox has never supported it. This
|
|
28
|
-
* component uses the standard properties only.
|
|
27
|
+
* The font is declared here: the reset in @seekalfred/styles is OPT-IN, so a
|
|
28
|
+
* consumer may load none, and a scroll area's content (a list of plain
|
|
29
|
+
* paragraphs) would render in the browser's serif.
|
|
29
30
|
*/
|
|
30
|
-
export declare const
|
|
31
|
+
export declare const scrollAreaRootVariants: (props?: ({
|
|
32
|
+
framed?: boolean | null | undefined;
|
|
33
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
34
|
+
export declare const scrollAreaVariants: (props?: ({
|
|
35
|
+
orientation?: "vertical" | "horizontal" | "both" | null | undefined;
|
|
36
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
31
37
|
/**
|
|
32
38
|
* A scrolling region.
|
|
33
39
|
*
|
|
34
40
|
* @example
|
|
35
|
-
* <ScrollArea label="
|
|
41
|
+
* <ScrollArea label="Activity" className="h-64" framed fade={28}>...</ScrollArea>
|
|
36
42
|
*/
|
|
37
43
|
export interface ScrollAreaProps extends ComponentPropsWithoutRef<"div"> {
|
|
38
44
|
children?: ReactNode;
|
|
@@ -41,7 +47,7 @@ export interface ScrollAreaProps extends ComponentPropsWithoutRef<"div"> {
|
|
|
41
47
|
*
|
|
42
48
|
* **Required**, and it took a failing test to get here. A focusable
|
|
43
49
|
* element with no role fails axe `focus-order-semantics`, so the
|
|
44
|
-
* keyboard fix
|
|
50
|
+
* keyboard fix cannot ship without a role -- and a role with no
|
|
45
51
|
* accessible name is a violation of its own. Naming it is the only
|
|
46
52
|
* combination that is actually correct.
|
|
47
53
|
*
|
|
@@ -53,26 +59,56 @@ export interface ScrollAreaProps extends ComponentPropsWithoutRef<"div"> {
|
|
|
53
59
|
* jump to it is the point.
|
|
54
60
|
*/
|
|
55
61
|
label: string;
|
|
62
|
+
/**
|
|
63
|
+
* Which axes scroll.
|
|
64
|
+
*
|
|
65
|
+
* @default "vertical"
|
|
66
|
+
*/
|
|
67
|
+
orientation?: "vertical" | "horizontal" | "both";
|
|
56
68
|
/**
|
|
57
69
|
* Fade the content out at an edge by exactly as much as there is content hidden
|
|
58
70
|
* past it, up to this many pixels: the fade grows in with the first pixels of
|
|
59
|
-
* scroll and is gone at the ends
|
|
60
|
-
*
|
|
61
|
-
*
|
|
71
|
+
* scroll and is gone at the ends, so an edge fades only while content
|
|
72
|
+
* overflows past it. `0` turns it off, and the default leaves the area as it
|
|
73
|
+
* was. Written on each scroll frame straight to the element, so scrolling
|
|
74
|
+
* never re-renders.
|
|
62
75
|
*
|
|
63
76
|
* @default 0
|
|
64
77
|
*/
|
|
65
78
|
fade?: number;
|
|
79
|
+
/**
|
|
80
|
+
* `auto` shows the scrollbar while scrolling or hovering and fades it away at
|
|
81
|
+
* rest; `always` keeps it visible whenever the content overflows.
|
|
82
|
+
*
|
|
83
|
+
* @default "auto"
|
|
84
|
+
*/
|
|
85
|
+
scrollbars?: "auto" | "always";
|
|
86
|
+
/**
|
|
87
|
+
* How long the scrollbar lingers after scrolling stops, in ms.
|
|
88
|
+
*
|
|
89
|
+
* @default 900
|
|
90
|
+
*/
|
|
91
|
+
hideDelay?: number;
|
|
92
|
+
/**
|
|
93
|
+
* Draws the area as a white card: the panel radius and a light border. The
|
|
94
|
+
* content is clipped to it, so an edge fade and the scrollbar sit inside.
|
|
95
|
+
*
|
|
96
|
+
* @default false
|
|
97
|
+
*/
|
|
98
|
+
framed?: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Classes for the viewport, the element that scrolls. Padding for the
|
|
101
|
+
* content goes here.
|
|
102
|
+
*/
|
|
103
|
+
viewportClassName?: string;
|
|
66
104
|
/**
|
|
67
105
|
* Change this when the contents change, and the region scrolls back to the
|
|
68
106
|
* top.
|
|
69
107
|
*
|
|
70
|
-
* This stays a declarative prop even though a `ref`
|
|
108
|
+
* This stays a declarative prop even though a `ref` exists: reaching
|
|
71
109
|
* for it would mean the caller writes `ref.current.scrollTop = 0` in their
|
|
72
110
|
* own effect on every content change, which is worse ergonomics than a
|
|
73
|
-
* prop that says "reset when this value changes."
|
|
74
|
-
* independent of whether a ref is available, not a consequence of one
|
|
75
|
-
* being withheld.
|
|
111
|
+
* prop that says "reset when this value changes."
|
|
76
112
|
*
|
|
77
113
|
* Sheet forwards its own `scrollResetKey` straight through: going a level
|
|
78
114
|
* deeper in a panel and landing halfway down the new view is disorienting,
|
|
@@ -80,6 +116,7 @@ export interface ScrollAreaProps extends ComponentPropsWithoutRef<"div"> {
|
|
|
80
116
|
*/
|
|
81
117
|
scrollResetKey?: string | number;
|
|
82
118
|
}
|
|
119
|
+
/** The `ref` reaches the VIEWPORT, the element that scrolls. `onScroll` runs on its scroll events. */
|
|
83
120
|
export declare const ScrollArea: import("react").ForwardRefExoticComponent<ScrollAreaProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
84
121
|
//#endregion
|
|
85
122
|
//# sourceMappingURL=scroll-area.d.ts.map
|
|
@@ -1,87 +1,237 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { cnAll } from "../lib/cn.js";
|
|
2
|
+
import { cn, cnAll } from "../lib/cn.js";
|
|
3
3
|
import { mergeRefs } from "../lib/merge-refs.js";
|
|
4
|
+
import { prefersReducedMotion, useIsomorphicLayoutEffect } from "../lib/motion.js";
|
|
4
5
|
import { cva } from "class-variance-authority";
|
|
5
|
-
import { forwardRef, useEffect, useMemo, useRef } from "react";
|
|
6
|
-
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { forwardRef, useCallback, useEffect, useMemo, useRef } from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
8
|
//#region src/scroll-area/scroll-area.tsx
|
|
8
9
|
/**
|
|
9
|
-
* ScrollArea
|
|
10
|
-
*
|
|
10
|
+
* ScrollArea: a native scroll container with thin overlay scrollbars and edge
|
|
11
|
+
* fades. React Aria has no equivalent, so the scrolling stays the browser's --
|
|
12
|
+
* keyboard, touch momentum and scroll snap all behave as the platform expects --
|
|
13
|
+
* and only the scrollbar is drawn here.
|
|
11
14
|
*
|
|
12
|
-
* Census: fourteen paths match, thirteen are counted, ELEVEN render
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `orientation="horizontal"` has zero call sites.
|
|
15
|
+
* Census: fourteen paths match, thirteen are counted, ELEVEN render anything,
|
|
16
|
+
* and across them 17 uses. Every one passes `className` and nothing else, and 13
|
|
17
|
+
* of the 17 are a height or flex constraint plus padding. The legacy Radix one
|
|
18
|
+
* cannot be scrolled by keyboard at all.
|
|
17
19
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* `ScrollArea` cannot be scrolled by keyboard at all.
|
|
20
|
+
* The native scrollbar is hidden and replaced by an overlay pill that appears
|
|
21
|
+
* while scrolling or hovering and fades away at rest (or stays, with
|
|
22
|
+
* `scrollbars="always"`). It is written straight to the DOM on each scroll
|
|
23
|
+
* frame, so scrolling never re-renders React. The pill can be dragged, and
|
|
24
|
+
* pressing its track pages toward the pointer.
|
|
24
25
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* WHERE THINGS LAND. `className`, `style` and the rest go on the ROOT, the box
|
|
27
|
+
* that carries the height and the optional card. `ref` and `viewportClassName`
|
|
28
|
+
* go on the VIEWPORT, the element that really scrolls -- so a caller can call
|
|
29
|
+
* `ref.current.scrollTo(...)` or `scrollBy(...)` for a "back to top" or an
|
|
30
|
+
* arrow button, and put padding on the content without moving the scrollbar
|
|
31
|
+
* inside it.
|
|
28
32
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* those but is non-standard and Firefox has never supported it. This
|
|
33
|
-
* component uses the standard properties only.
|
|
33
|
+
* The font is declared here: the reset in @seekalfred/styles is OPT-IN, so a
|
|
34
|
+
* consumer may load none, and a scroll area's content (a list of plain
|
|
35
|
+
* paragraphs) would render in the browser's serif.
|
|
34
36
|
*/
|
|
37
|
+
const scrollAreaRootVariants = cva(["scroll-area relative flex min-h-0 min-w-0 flex-col overflow-hidden box-border font-sans"], {
|
|
38
|
+
variants: {
|
|
39
|
+
/** The area is a white card: the panel radius and a hairline border. */
|
|
40
|
+
framed: {
|
|
41
|
+
true: "rounded-panel border-(length:--border-width) border-border bg-surface",
|
|
42
|
+
false: ""
|
|
43
|
+
} },
|
|
44
|
+
defaultVariants: { framed: false }
|
|
45
|
+
});
|
|
35
46
|
const scrollAreaVariants = cva([
|
|
36
|
-
"
|
|
37
|
-
"box-border",
|
|
38
|
-
"scrollbar-thin scrollbar-thumb-border scrollbar-track-transparent",
|
|
47
|
+
"scroll-area-viewport min-h-0 min-w-0 flex-1 overscroll-contain box-border",
|
|
39
48
|
"outline-none",
|
|
40
|
-
"focus-visible:outline-solid",
|
|
49
|
+
"focus-visible:not-data-[fade]:outline-solid",
|
|
41
50
|
"focus-visible:outline-(length:--focus-ring-width)",
|
|
42
|
-
"focus-visible
|
|
43
|
-
"focus-visible:outline-(--color-ring)"
|
|
44
|
-
]
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
"focus-visible:-outline-offset-(--focus-ring-width)",
|
|
52
|
+
"focus-visible:outline-(--color-ring)",
|
|
53
|
+
"rounded-[inherit]"
|
|
54
|
+
], {
|
|
55
|
+
variants: { orientation: {
|
|
56
|
+
vertical: "overflow-x-hidden overflow-y-auto",
|
|
57
|
+
horizontal: "overflow-x-auto overflow-y-hidden",
|
|
58
|
+
both: "overflow-auto"
|
|
59
|
+
} },
|
|
60
|
+
defaultVariants: { orientation: "vertical" }
|
|
61
|
+
});
|
|
62
|
+
/** The shortest a scrollbar thumb gets, so a very long list still leaves something to grab. */
|
|
63
|
+
const MIN_THUMB = 28;
|
|
64
|
+
/** The `ref` reaches the VIEWPORT, the element that scrolls. `onScroll` runs on its scroll events. */
|
|
65
|
+
const ScrollArea = forwardRef(function ScrollArea({ className, children, label, scrollResetKey, orientation = "vertical", fade = 0, scrollbars = "auto", hideDelay = 900, framed = false, viewportClassName, onScroll, ...props }, ref) {
|
|
66
|
+
const root = useRef(null);
|
|
67
|
+
const viewport = useRef(null);
|
|
68
|
+
const tracks = useRef({
|
|
69
|
+
x: null,
|
|
70
|
+
y: null
|
|
71
|
+
});
|
|
72
|
+
const thumbs = useRef({
|
|
73
|
+
x: null,
|
|
74
|
+
y: null
|
|
75
|
+
});
|
|
76
|
+
const hideTimer = useRef(void 0);
|
|
77
|
+
const drag = useRef(null);
|
|
78
|
+
const vertical = orientation !== "horizontal";
|
|
79
|
+
const horizontal = orientation !== "vertical";
|
|
47
80
|
useEffect(() => {
|
|
48
|
-
if (
|
|
81
|
+
if (viewport.current) viewport.current.scrollTop = 0;
|
|
49
82
|
}, [scrollResetKey]);
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const node =
|
|
53
|
-
if (!node
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
83
|
+
const viewportRef = useMemo(() => mergeRefs(ref, viewport), [ref]);
|
|
84
|
+
const sync = useCallback(() => {
|
|
85
|
+
const node = viewport.current;
|
|
86
|
+
if (!node) return;
|
|
87
|
+
const { scrollTop, scrollHeight, clientHeight, scrollWidth, clientWidth } = node;
|
|
88
|
+
const maxY = Math.max(0, scrollHeight - clientHeight);
|
|
89
|
+
const maxX = Math.max(0, scrollWidth - clientWidth);
|
|
90
|
+
const left = Math.abs(node.scrollLeft);
|
|
91
|
+
if (fade > 0) {
|
|
92
|
+
node.style.setProperty("--fade-top", `${vertical ? Math.min(fade, scrollTop) : 0}px`);
|
|
93
|
+
node.style.setProperty("--fade-bottom", `${vertical ? Math.min(fade, Math.max(0, maxY - scrollTop)) : 0}px`);
|
|
94
|
+
node.style.setProperty("--fade-left", `${horizontal ? Math.min(fade, left) : 0}px`);
|
|
95
|
+
node.style.setProperty("--fade-right", `${horizontal ? Math.min(fade, Math.max(0, maxX - left)) : 0}px`);
|
|
96
|
+
}
|
|
97
|
+
const place = (axis, scroll, max, client, total) => {
|
|
98
|
+
const track = tracks.current[axis];
|
|
99
|
+
const thumb = thumbs.current[axis];
|
|
100
|
+
if (!track || !thumb) return;
|
|
101
|
+
const overflowing = max > .5;
|
|
102
|
+
track.toggleAttribute("data-hidden", !overflowing);
|
|
103
|
+
if (!overflowing) return;
|
|
104
|
+
const length = axis === "y" ? track.clientHeight : track.clientWidth;
|
|
105
|
+
const size = Math.max(MIN_THUMB, length * client / total);
|
|
106
|
+
const offset = (length - size) * (scroll / max);
|
|
107
|
+
const sign = axis === "x" && getComputedStyle(node).direction === "rtl" ? -1 : 1;
|
|
108
|
+
thumb.style[axis === "y" ? "height" : "width"] = `${size}px`;
|
|
109
|
+
thumb.style.transform = axis === "y" ? `translate3d(0, ${offset}px, 0)` : `translate3d(${offset * sign}px, 0, 0)`;
|
|
110
|
+
};
|
|
111
|
+
if (vertical) place("y", scrollTop, maxY, clientHeight, scrollHeight);
|
|
112
|
+
if (horizontal) place("x", left, maxX, clientWidth, scrollWidth);
|
|
113
|
+
root.current?.toggleAttribute("data-overflow", maxY > .5 || maxX > .5);
|
|
114
|
+
}, [
|
|
115
|
+
fade,
|
|
116
|
+
horizontal,
|
|
117
|
+
vertical
|
|
118
|
+
]);
|
|
119
|
+
useIsomorphicLayoutEffect(() => {
|
|
120
|
+
const node = viewport.current;
|
|
121
|
+
if (!node) return;
|
|
122
|
+
sync();
|
|
62
123
|
if (typeof ResizeObserver === "undefined") return;
|
|
63
|
-
const observer = new ResizeObserver(
|
|
124
|
+
const observer = new ResizeObserver(() => sync());
|
|
64
125
|
observer.observe(node);
|
|
65
126
|
for (const child of Array.from(node.children)) observer.observe(child);
|
|
66
127
|
return () => observer.disconnect();
|
|
67
|
-
}, [
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"data-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
128
|
+
}, [sync, children]);
|
|
129
|
+
useEffect(() => () => window.clearTimeout(hideTimer.current), []);
|
|
130
|
+
const wake = () => {
|
|
131
|
+
const el = root.current;
|
|
132
|
+
if (!el) return;
|
|
133
|
+
el.setAttribute("data-scrolling", "");
|
|
134
|
+
window.clearTimeout(hideTimer.current);
|
|
135
|
+
hideTimer.current = window.setTimeout(() => el.removeAttribute("data-scrolling"), hideDelay);
|
|
136
|
+
};
|
|
137
|
+
const onThumbDown = (event, axis) => {
|
|
138
|
+
const node = viewport.current;
|
|
139
|
+
const track = tracks.current[axis];
|
|
140
|
+
const thumb = thumbs.current[axis];
|
|
141
|
+
if (!node || !track || !thumb || event.button !== 0) return;
|
|
142
|
+
event.preventDefault();
|
|
143
|
+
event.stopPropagation();
|
|
144
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
145
|
+
const length = axis === "y" ? track.clientHeight : track.clientWidth;
|
|
146
|
+
const size = axis === "y" ? thumb.offsetHeight : thumb.offsetWidth;
|
|
147
|
+
const max = axis === "y" ? node.scrollHeight - node.clientHeight : node.scrollWidth - node.clientWidth;
|
|
148
|
+
drag.current = {
|
|
149
|
+
axis,
|
|
150
|
+
start: axis === "y" ? event.clientY : event.clientX,
|
|
151
|
+
scroll: axis === "y" ? node.scrollTop : node.scrollLeft,
|
|
152
|
+
ratio: max / Math.max(1, length - size),
|
|
153
|
+
sign: axis === "x" && getComputedStyle(node).direction === "rtl" ? -1 : 1
|
|
154
|
+
};
|
|
155
|
+
root.current?.setAttribute("data-dragging", axis);
|
|
156
|
+
};
|
|
157
|
+
const onThumbMove = (event) => {
|
|
158
|
+
const state = drag.current;
|
|
159
|
+
const node = viewport.current;
|
|
160
|
+
if (!state || !node) return;
|
|
161
|
+
const travel = (state.axis === "y" ? event.clientY : event.clientX) - state.start;
|
|
162
|
+
const to = state.scroll + travel * state.ratio * state.sign;
|
|
163
|
+
if (state.axis === "y") node.scrollTop = to;
|
|
164
|
+
else node.scrollLeft = to;
|
|
165
|
+
};
|
|
166
|
+
const onThumbUp = (event) => {
|
|
167
|
+
if (!drag.current) return;
|
|
168
|
+
drag.current = null;
|
|
169
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
170
|
+
root.current?.removeAttribute("data-dragging");
|
|
171
|
+
wake();
|
|
172
|
+
};
|
|
173
|
+
const onTrackDown = (event, axis) => {
|
|
174
|
+
const node = viewport.current;
|
|
175
|
+
const thumb = thumbs.current[axis];
|
|
176
|
+
if (!node || !thumb || event.button !== 0 || event.target !== event.currentTarget) return;
|
|
177
|
+
const box = thumb.getBoundingClientRect();
|
|
178
|
+
const before = axis === "y" ? event.clientY < box.top : event.clientX < box.left;
|
|
179
|
+
const page = (axis === "y" ? node.clientHeight : node.clientWidth) * .9 * (before ? -1 : 1);
|
|
180
|
+
node.scrollBy({
|
|
181
|
+
[axis === "y" ? "top" : "left"]: page,
|
|
182
|
+
behavior: prefersReducedMotion() ? "auto" : "smooth"
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
const bar = (axis) => /* @__PURE__ */ jsx("div", {
|
|
186
|
+
ref: (node) => {
|
|
187
|
+
tracks.current[axis] = node;
|
|
79
188
|
},
|
|
80
|
-
|
|
81
|
-
|
|
189
|
+
"data-slot": "scroll-area-track",
|
|
190
|
+
"data-axis": axis,
|
|
191
|
+
"data-hidden": "",
|
|
192
|
+
"aria-hidden": "true",
|
|
193
|
+
onPointerDown: (event) => onTrackDown(event, axis),
|
|
194
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
195
|
+
ref: (node) => {
|
|
196
|
+
thumbs.current[axis] = node;
|
|
197
|
+
},
|
|
198
|
+
"data-slot": "scroll-area-thumb",
|
|
199
|
+
onPointerDown: (event) => onThumbDown(event, axis),
|
|
200
|
+
onPointerMove: onThumbMove,
|
|
201
|
+
onPointerUp: onThumbUp,
|
|
202
|
+
onPointerCancel: onThumbUp
|
|
203
|
+
})
|
|
204
|
+
});
|
|
205
|
+
const fadeClass = orientation === "vertical" ? "scroll-fade-y" : orientation === "horizontal" ? "scroll-fade-x" : "scroll-fade-both";
|
|
206
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
207
|
+
...props,
|
|
208
|
+
ref: root,
|
|
209
|
+
"data-slot": "scroll-area-root",
|
|
210
|
+
"data-orientation": orientation,
|
|
211
|
+
"data-scrollbars": scrollbars,
|
|
212
|
+
className: cn(scrollAreaRootVariants({ framed }), className),
|
|
213
|
+
children: [
|
|
214
|
+
/* @__PURE__ */ jsx("div", {
|
|
215
|
+
ref: viewportRef,
|
|
216
|
+
tabIndex: 0,
|
|
217
|
+
role: "region",
|
|
218
|
+
"aria-label": label,
|
|
219
|
+
"data-slot": "scroll-area",
|
|
220
|
+
"data-fade": fade > 0 ? "" : void 0,
|
|
221
|
+
onScroll: (event) => {
|
|
222
|
+
sync();
|
|
223
|
+
wake();
|
|
224
|
+
onScroll?.(event);
|
|
225
|
+
},
|
|
226
|
+
className: cn(cnAll(scrollAreaVariants({ orientation }), fade > 0 && fadeClass), viewportClassName),
|
|
227
|
+
children
|
|
228
|
+
}),
|
|
229
|
+
vertical ? bar("y") : null,
|
|
230
|
+
horizontal ? bar("x") : null
|
|
231
|
+
]
|
|
82
232
|
});
|
|
83
233
|
});
|
|
84
234
|
//#endregion
|
|
85
|
-
export { ScrollArea, scrollAreaVariants };
|
|
235
|
+
export { ScrollArea, scrollAreaRootVariants, scrollAreaVariants };
|
|
86
236
|
|
|
87
237
|
//# sourceMappingURL=scroll-area.js.map
|