@heyramzi/ui 6.1.0 → 8.0.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.
- package/COMPONENTS.md +32 -40
- package/README.md +10 -4
- package/package.json +31 -29
- package/scripts/sync-shadcn.mjs +29 -16
- package/scripts/sync-transitions.mjs +11 -11
- package/src/ai/ai-button/AiButton.svelte +86 -0
- package/src/ai/ai-button/index.ts +4 -0
- package/src/ai/confirmation/Confirmation.svelte +8 -8
- package/src/ai/confirmation/confirmation-context.svelte.ts +2 -2
- package/src/ai/generation-progress/GenerationProgress.svelte +354 -0
- package/src/ai/generation-progress/index.ts +7 -0
- package/src/ai/index.ts +16 -24
- package/src/ai/prompt-input/PromptInput.svelte +19 -1
- package/src/ai/prompt-input/PromptInputSubmit.svelte +9 -3
- package/src/ai/reasoning/Reasoning.svelte +11 -8
- package/src/ambient.d.ts +4 -0
- package/src/animations/README.md +17 -17
- package/src/animations/index.css +3 -14
- package/src/animations/upstream-coverage.test.ts +1 -1
- package/src/components/copy/clipboard.test.ts +206 -0
- package/src/components/copy/clipboard.ts +49 -0
- package/src/components/copy/copied.svelte.ts +39 -0
- package/src/components/copy/copy-button.svelte +175 -0
- package/src/components/copy/copy-button.test.ts +110 -0
- package/src/components/copy/index.ts +3 -0
- package/src/components/data-table/data-table.test.ts +134 -0
- package/src/components/data-table/data-table.ts +77 -0
- package/src/components/data-table/index.ts +20 -0
- package/src/components/data-table/infinite-scroll.svelte +69 -0
- package/src/components/data-table/pagination.svelte +62 -0
- package/src/components/data-table/row-arrow.svelte +28 -0
- package/src/components/data-table/row-context-menu.svelte +106 -0
- package/src/components/data-table/row-context-menu.test.ts +18 -0
- package/src/components/data-table/sortable-head.svelte +56 -0
- package/src/components/data-table/table-skeleton.svelte +83 -0
- package/src/components/hold-to-confirm/hold-to-confirm.svelte +232 -0
- package/src/components/hold-to-confirm/index.ts +1 -0
- package/src/components/icon/icon.svelte +23 -0
- package/src/components/icon/index.ts +1 -0
- package/src/components/language-flag/index.ts +1 -0
- package/src/components/language-flag/language-flag.svelte +60 -0
- package/src/components/list-page/detail-empty.svelte +50 -0
- package/src/components/list-page/detail-header.svelte +107 -0
- package/src/components/list-page/detail-panel.svelte +90 -0
- package/src/components/list-page/detail-row.svelte +36 -0
- package/src/components/list-page/detail-stack.svelte +33 -0
- package/src/components/list-page/empty-state.svelte +91 -0
- package/src/components/list-page/filter-item.svelte +49 -0
- package/src/components/list-page/filter-popover.svelte +88 -0
- package/src/components/list-page/filter-section.ts +12 -0
- package/src/components/list-page/grouped-list.svelte +116 -0
- package/src/components/list-page/index.ts +28 -0
- package/src/components/list-page/list-page-shell.svelte +195 -0
- package/src/components/list-page/list-table.ts +19 -0
- package/src/components/list-page/master-detail.svelte +206 -0
- package/src/components/list-page/master-detail.test.ts +37 -0
- package/src/components/list-page/notice-bar.svelte +68 -0
- package/src/components/list-page/prev-next.svelte +104 -0
- package/src/components/list-page/queue-rail.ts +25 -0
- package/src/components/list-page/rail-body.svelte +29 -0
- package/src/components/list-page/rail-empty.svelte +51 -0
- package/src/components/list-page/rail-head.svelte +49 -0
- package/src/components/list-page/rail-row.svelte +163 -0
- package/src/components/list-page/section-host.ts +24 -0
- package/src/components/list-page/section-label.svelte +39 -0
- package/src/components/list-page/step.test.ts +21 -0
- package/src/components/list-page/step.ts +10 -0
- package/src/components/list-page/toolbar-search.svelte +63 -0
- package/src/components/list-page/toolbar-trigger.ts +23 -0
- package/src/components/list-page/types.ts +1 -0
- package/src/components/locale-switch/index.ts +1 -0
- package/src/components/locale-switch/locale-switch.svelte +59 -0
- package/src/components/mark/index.ts +1 -0
- package/src/components/mark/mark.svelte +70 -0
- package/src/components/open-in/index.ts +6 -0
- package/src/components/open-in/open-in.svelte +106 -0
- package/src/components/picker/index.ts +4 -0
- package/src/components/picker/mark-picker.svelte +84 -0
- package/src/components/picker/picker.svelte +143 -0
- package/src/components/picker/trigger.ts +42 -0
- package/src/components/picker/types.ts +26 -0
- package/src/components/segmented/animated-tabs.svelte +175 -0
- package/src/components/segmented/collapse.test.ts +49 -0
- package/src/components/segmented/collapse.ts +39 -0
- package/src/components/segmented/index.ts +41 -0
- package/src/components/segmented/section-runs.svelte +79 -0
- package/src/components/segmented/segment.svelte +106 -0
- package/src/components/segmented/segmented-filter.svelte +125 -0
- package/src/components/segmented/segmented-nav.svelte +82 -0
- package/src/components/segmented/segmented-overflow.svelte +85 -0
- package/src/components/segmented/segmented-track.svelte +181 -0
- package/src/components/segmented/segmented.test.ts +20 -0
- package/src/components/segmented/segmented.ts +80 -0
- package/src/components/star-rating-input/index.ts +9 -0
- package/src/components/star-rating-input/star-rating-input.svelte +256 -0
- package/src/components/svg/index.ts +1 -0
- package/src/components/svg/svg.svelte +9 -0
- package/src/effects/border-beam/BorderBeam.svelte +1 -1
- package/src/effects/image-comparison/ImageComparison.css +42 -8
- package/src/effects/image-comparison/ImageComparison.svelte +138 -21
- package/src/effects/image-comparison/compare.test.ts +17 -0
- package/src/effects/image-comparison/compare.ts +5 -0
- package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +338 -0
- package/src/effects/magic-card/MagicCard.css +47 -0
- package/src/effects/magic-card/MagicCard.svelte +57 -0
- package/src/effects/marquee/Marquee.css +27 -1
- package/src/effects/marquee/Marquee.svelte +67 -3
- package/src/effects/reveal/index.ts +2 -1
- package/src/effects/reveal/observe.test.ts +60 -0
- package/src/effects/reveal/observe.ts +33 -1
- package/src/effects/reveal/types.ts +7 -0
- package/src/effects/theme-toggle/ThemeToggle.css +199 -6
- package/src/effects/theme-toggle/ThemeToggle.svelte +51 -26
- package/src/gallery.test.ts +52 -0
- package/src/index.ts +5 -1
- package/src/lib/panel.ts +7 -1
- package/src/lib/sliding-pill.ts +68 -0
- package/src/lib/theme-transition.ts +41 -13
- package/src/lib/tone.ts +48 -0
- package/src/shadcn/accordion/accordion-trigger.svelte +15 -6
- package/src/shadcn/alert/alert.svelte +3 -1
- package/src/shadcn/badge/badge.svelte +8 -7
- package/src/shadcn/breadcrumb/breadcrumb-ellipsis.svelte +2 -2
- package/src/shadcn/breadcrumb/breadcrumb-separator.svelte +2 -2
- package/src/shadcn/calendar/calendar-month-select.svelte +2 -2
- package/src/shadcn/calendar/calendar-next-button.svelte +2 -2
- package/src/shadcn/calendar/calendar-prev-button.svelte +2 -2
- package/src/shadcn/calendar/calendar-year-select.svelte +2 -2
- package/src/shadcn/calendar/calendar.svelte +6 -0
- package/src/shadcn/code-block/code-block-actions.svelte +23 -0
- package/src/shadcn/code-block/code-block-content.svelte +55 -0
- package/src/shadcn/code-block/code-block-copy-button.svelte +10 -0
- package/src/shadcn/code-block/code-block-footer.svelte +20 -0
- package/src/shadcn/code-block/code-block-header.svelte +23 -0
- package/src/shadcn/code-block/code-block-line.svelte +71 -0
- package/src/shadcn/code-block/code-block-title.svelte +23 -0
- package/src/shadcn/code-block/code-block.svelte +47 -0
- package/src/shadcn/code-block/index.ts +42 -0
- package/src/shadcn/command/index.ts +3 -0
- package/src/shadcn/field/index.ts +3 -0
- package/src/shadcn/field/simple-field.svelte +71 -0
- package/src/shadcn/field/simple-field.test.ts +47 -0
- package/src/shadcn/hooks/highlighter.ts +132 -0
- package/src/shadcn/hooks/use-highlighted-code.svelte.ts +98 -0
- package/src/shadcn/kbd/index.ts +10 -0
- package/src/shadcn/kbd/kbd-group.svelte +20 -0
- package/src/shadcn/kbd/kbd.svelte +23 -0
- package/src/shadcn/message-scroller/index.ts +28 -0
- package/src/shadcn/message-scroller/message-scroller-button.svelte +52 -0
- package/src/shadcn/message-scroller/message-scroller-content.svelte +17 -0
- package/src/shadcn/message-scroller/message-scroller-item.svelte +22 -0
- package/src/shadcn/message-scroller/message-scroller-provider.svelte +7 -0
- package/src/shadcn/message-scroller/message-scroller-viewport.svelte +20 -0
- package/src/shadcn/message-scroller/message-scroller.svelte +20 -0
- package/src/shadcn/radio-group/radio-group-item.svelte +3 -2
- package/src/shadcn/sheet/sheet-content.svelte +1 -0
- package/src/shadcn/sheet/sheet.css +48 -0
- package/src/shadcn/sonner/sonner.svelte +7 -10
- package/src/shadcn/tabs/tabs-list.svelte +13 -2
- package/src/shadcn/tabs/tabs-trigger.svelte +1 -1
- package/src/shadcn/toggle-group/toggle-group.svelte +10 -3
- package/src/shadcn/trace/index.ts +29 -0
- package/src/shadcn/trace/trace-collapsible-content.svelte +29 -0
- package/src/shadcn/trace/trace-collapsible-trigger.svelte +29 -0
- package/src/shadcn/trace/trace-collapsible.svelte +20 -0
- package/src/shadcn/trace/trace-description.svelte +20 -0
- package/src/shadcn/trace/trace-icon.svelte +24 -0
- package/src/shadcn/trace/trace-line.svelte +31 -0
- package/src/shadcn/trace/trace-title.svelte +20 -0
- package/src/shadcn/trace/trace.svelte +23 -0
- package/src/ai/composer/Composer.css +0 -108
- package/src/ai/composer/Composer.svelte +0 -111
- package/src/ai/composer/index.ts +0 -10
- package/src/ai/conversation/Conversation.svelte +0 -28
- package/src/ai/conversation/ConversationContent.svelte +0 -35
- package/src/ai/conversation/ConversationEmptyState.svelte +0 -46
- package/src/ai/conversation/ConversationScrollButton.svelte +0 -51
- package/src/ai/conversation/index.ts +0 -33
- package/src/ai/conversation/stick-to-bottom-context.svelte.ts +0 -131
- package/src/animations/accordion.css +0 -58
- package/src/animations/icon-swap.css +0 -43
- package/src/animations/notification-badge.css +0 -81
- package/src/animations/panel.css +0 -86
- package/src/animations/reasoning-stream.css +0 -49
- package/src/animations/skeleton-reveal.css +0 -97
- package/src/animations/streaming-text.css +0 -31
- package/src/animations/tabs-sliding.css +0 -83
- package/src/animations/texts-reveal.css +0 -70
- package/src/animations/tooltip.css +0 -72
- package/src/animations/view-transition-reveal.ts +0 -74
- package/src/charts/animated-value.css +0 -7
- package/src/charts/animated-value.svelte +0 -110
- package/src/charts/area-chart.css +0 -29
- package/src/charts/area-chart.svelte +0 -195
- package/src/charts/bar-chart.css +0 -119
- package/src/charts/bar-chart.svelte +0 -269
- package/src/charts/charts.css +0 -201
- package/src/charts/crosshair.svelte +0 -35
- package/src/charts/donut-chart.css +0 -56
- package/src/charts/donut-chart.svelte +0 -158
- package/src/charts/edge-fade.svelte +0 -43
- package/src/charts/edge-fade.ts +0 -16
- package/src/charts/figure.css +0 -100
- package/src/charts/figure.svelte +0 -122
- package/src/charts/gauge-chart.css +0 -94
- package/src/charts/gauge-chart.svelte +0 -303
- package/src/charts/hover-band.test.ts +0 -30
- package/src/charts/hover-band.ts +0 -21
- package/src/charts/hover-focus.svelte +0 -85
- package/src/charts/index.ts +0 -30
- package/src/charts/legend.css +0 -131
- package/src/charts/legend.svelte +0 -112
- package/src/charts/line-chart.css +0 -26
- package/src/charts/line-chart.svelte +0 -256
- package/src/charts/motion.ts +0 -19
- package/src/charts/number-chart.css +0 -168
- package/src/charts/number-chart.svelte +0 -177
- package/src/charts/primitives/chart-container.svelte +0 -57
- package/src/charts/primitives/chart-style.svelte +0 -36
- package/src/charts/primitives/chart-tooltip.svelte +0 -161
- package/src/charts/primitives/chart-utils.ts +0 -54
- package/src/charts/primitives/index.ts +0 -11
- package/src/charts/reveal.svelte +0 -61
- package/src/charts/ring-chart.css +0 -96
- package/src/charts/ring-chart.svelte +0 -158
- package/src/charts/sparkline.css +0 -45
- package/src/charts/sparkline.svelte +0 -140
- package/src/charts/stat-card.css +0 -103
- package/src/charts/stat-card.svelte +0 -267
- package/src/charts/time-series-chart.css +0 -28
- package/src/charts/time-series-chart.svelte +0 -179
- package/src/charts/trend-pill.css +0 -38
- package/src/charts/trend-pill.svelte +0 -48
- package/src/lib/hooks/is-mobile.svelte.ts +0 -11
- package/src/lib/utils.ts +0 -45
- package/src/showcase/AiSection.svelte +0 -157
- package/src/showcase/AnimationsSection.svelte +0 -1658
- package/src/showcase/ChartsSection.svelte +0 -458
- package/src/showcase/EffectsSection.svelte +0 -152
- package/src/showcase/ShadcnSection.svelte +0 -27
- package/src/showcase/ShowcaseImport.svelte +0 -126
- package/src/showcase/ShowcaseList.svelte +0 -132
- package/src/showcase/ShowcaseNav.svelte +0 -247
- package/src/showcase/ShowcaseSection.svelte +0 -112
- package/src/showcase/ShowcaseShell.svelte +0 -55
- package/src/showcase/ShowcaseStage.svelte +0 -342
- package/src/showcase/ShowcaseVariant.svelte +0 -109
- package/src/showcase/assets/image-reveal/art-1.jpg +0 -0
- package/src/showcase/assets/image-reveal/art-2.jpg +0 -0
- package/src/showcase/assets/image-reveal/art-3.jpg +0 -0
- package/src/showcase/check.svg +0 -1
- package/src/showcase/chevron-arms.svg +0 -2
- package/src/showcase/chevron-down.svg +0 -1
- package/src/showcase/copy.svg +0 -2
- package/src/showcase/demos/ai/confirmation.svelte +0 -59
- package/src/showcase/demos/ai/conversation.svelte +0 -59
- package/src/showcase/demos/ai/loading-state.svelte +0 -19
- package/src/showcase/demos/ai/prompt-input.svelte +0 -57
- package/src/showcase/demos/ai/reasoning.svelte +0 -19
- package/src/showcase/demos/ai/thinking-dots.svelte +0 -15
- package/src/showcase/demos/ai/voice-waveform.svelte +0 -24
- package/src/showcase/demos/effects/animated-beam.svelte +0 -50
- package/src/showcase/demos/effects/animated-group.svelte +0 -47
- package/src/showcase/demos/effects/border-beam-default.svelte +0 -20
- package/src/showcase/demos/effects/border-beam-line.svelte +0 -20
- package/src/showcase/demos/effects/border-beam-mono.svelte +0 -20
- package/src/showcase/demos/effects/border-beam-sunset.svelte +0 -20
- package/src/showcase/demos/effects/image-comparison.svelte +0 -25
- package/src/showcase/demos/effects/image-reveal.svelte +0 -49
- package/src/showcase/demos/effects/in-view.svelte +0 -41
- package/src/showcase/demos/effects/integrations-hub.svelte +0 -82
- package/src/showcase/demos/effects/magnetic.svelte +0 -31
- package/src/showcase/demos/effects/marquee.svelte +0 -33
- package/src/showcase/demos/effects/progressive-blur.svelte +0 -47
- package/src/showcase/demos/effects/spotlight.svelte +0 -40
- package/src/showcase/demos/effects/text-effect.svelte +0 -55
- package/src/showcase/demos/shadcn/accordion.svelte +0 -45
- package/src/showcase/demos/shadcn/alert-dialog.svelte +0 -23
- package/src/showcase/demos/shadcn/alert.svelte +0 -30
- package/src/showcase/demos/shadcn/attachment.svelte +0 -71
- package/src/showcase/demos/shadcn/avatar.svelte +0 -30
- package/src/showcase/demos/shadcn/badge.svelte +0 -26
- package/src/showcase/demos/shadcn/breadcrumb.svelte +0 -34
- package/src/showcase/demos/shadcn/bubble.svelte +0 -36
- package/src/showcase/demos/shadcn/button.svelte +0 -11
- package/src/showcase/demos/shadcn/calendar.svelte +0 -8
- package/src/showcase/demos/shadcn/card.svelte +0 -39
- package/src/showcase/demos/shadcn/checkbox.svelte +0 -39
- package/src/showcase/demos/shadcn/collapsible.svelte +0 -20
- package/src/showcase/demos/shadcn/command.svelte +0 -48
- package/src/showcase/demos/shadcn/context-menu.svelte +0 -54
- package/src/showcase/demos/shadcn/demo-harness.svelte +0 -12
- package/src/showcase/demos/shadcn/demos.test.ts +0 -20
- package/src/showcase/demos/shadcn/dialog.svelte +0 -38
- package/src/showcase/demos/shadcn/dropdown-menu.svelte +0 -59
- package/src/showcase/demos/shadcn/empty.svelte +0 -29
- package/src/showcase/demos/shadcn/field.svelte +0 -115
- package/src/showcase/demos/shadcn/hover-card.svelte +0 -32
- package/src/showcase/demos/shadcn/index.ts +0 -358
- package/src/showcase/demos/shadcn/input-otp.svelte +0 -19
- package/src/showcase/demos/shadcn/input.svelte +0 -5
- package/src/showcase/demos/shadcn/label.svelte +0 -11
- package/src/showcase/demos/shadcn/marker.svelte +0 -30
- package/src/showcase/demos/shadcn/message.svelte +0 -75
- package/src/showcase/demos/shadcn/popover.svelte +0 -36
- package/src/showcase/demos/shadcn/progress.svelte +0 -13
- package/src/showcase/demos/shadcn/radio-group.svelte +0 -19
- package/src/showcase/demos/shadcn/scroll-area.svelte +0 -18
- package/src/showcase/demos/shadcn/select.svelte +0 -29
- package/src/showcase/demos/shadcn/separator.svelte +0 -12
- package/src/showcase/demos/shadcn/sheet.svelte +0 -48
- package/src/showcase/demos/shadcn/skeleton.svelte +0 -11
- package/src/showcase/demos/shadcn/slider.svelte +0 -7
- package/src/showcase/demos/shadcn/sonner.svelte +0 -18
- package/src/showcase/demos/shadcn/spinner.svelte +0 -11
- package/src/showcase/demos/shadcn/switch.svelte +0 -9
- package/src/showcase/demos/shadcn/table.svelte +0 -76
- package/src/showcase/demos/shadcn/tabs.svelte +0 -62
- package/src/showcase/demos/shadcn/textarea.svelte +0 -5
- package/src/showcase/demos/shadcn/toggle-group.svelte +0 -18
- package/src/showcase/demos/shadcn/toggle.svelte +0 -14
- package/src/showcase/demos/shadcn/tooltip.svelte +0 -13
- package/src/showcase/heart.svg +0 -1
- package/src/showcase/index.ts +0 -38
- package/src/showcase/kit.test.ts +0 -72
- package/src/showcase/kit.ts +0 -17
- package/src/showcase/plus.svg +0 -1
- package/src/showcase/showcase-shell.css +0 -91
- package/src/showcase/stacked-section.css +0 -15
- package/src/showcase/success-check.svg +0 -1
- package/src/showcase/types.ts +0 -29
- package/src/svg-raw.d.ts +0 -7
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
/**
|
|
3
|
-
* Which way a metric has to move to be good news.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/*
|
|
7
|
-
* `neutral` is the honest answer for a figure that is neither on its own: spend is not a win or a loss until the return is beside it.
|
|
8
|
-
*/
|
|
9
|
-
export type NumberDirection = "up-good" | "down-good" | "neutral";
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
<script lang="ts">
|
|
13
|
-
// =========================
|
|
14
|
-
// IMPORTS
|
|
15
|
-
// =========================
|
|
16
|
-
import "./number-chart.css";
|
|
17
|
-
import { Minus, TrendDown, TrendUp } from "phosphor-svelte";
|
|
18
|
-
import { cn } from "@heyramzi/utils";
|
|
19
|
-
import type { Snippet } from "svelte";
|
|
20
|
-
import AnimatedValue from "./animated-value.svelte";
|
|
21
|
-
|
|
22
|
-
// =========================
|
|
23
|
-
// TYPES
|
|
24
|
-
// =========================
|
|
25
|
-
type Props = {
|
|
26
|
-
/** Metric name, above the figure. */
|
|
27
|
-
label: string;
|
|
28
|
-
/**
|
|
29
|
-
* The figure.
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
/*
|
|
33
|
-
* A number counts up and is formatted here; a string is taken as already formatted and is printed as it stands, which is the only way to draw a total
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
/*
|
|
37
|
-
* that mixes two currencies.
|
|
38
|
-
*/
|
|
39
|
-
value: number | string;
|
|
40
|
-
/** Formatter for a numeric `value`. Wins over `formatOptions`. */
|
|
41
|
-
format?: (v: number) => string;
|
|
42
|
-
/** Intl options for a numeric `value` (currency, compact, percent). */
|
|
43
|
-
formatOptions?: Intl.NumberFormatOptions;
|
|
44
|
-
/** BCP-47 locale for `formatOptions`. */
|
|
45
|
-
locale?: string;
|
|
46
|
-
/**
|
|
47
|
-
* Change against the period before this one, as a percentage. `null` is
|
|
48
|
-
* "nothing to compare against", which is not zero and is drawn as a dash.
|
|
49
|
-
*/
|
|
50
|
-
delta?: number | null;
|
|
51
|
-
/** Which way `delta` has to point to be good news. */
|
|
52
|
-
direction?: NumberDirection;
|
|
53
|
-
/** Movement below this many points is noise and draws as a dash. */
|
|
54
|
-
deltaThreshold?: number;
|
|
55
|
-
/**
|
|
56
|
-
* The chart. A fraction from 0 to 1 that gives the figure its scale: a share of a total, a run against a target, a rate against its ceiling.
|
|
57
|
-
*/
|
|
58
|
-
|
|
59
|
-
/*
|
|
60
|
-
* Omitted, the number stands on its own and no track is drawn.
|
|
61
|
-
*/
|
|
62
|
-
share?: number;
|
|
63
|
-
/** What the track measures, e.g. "of revenue". Only with `share`. */
|
|
64
|
-
shareLabel?: string;
|
|
65
|
-
/** Track colour. Defaults to the first series token. */
|
|
66
|
-
color?: string;
|
|
67
|
-
/** md is a figure in a row; lg is the one figure the screen exists to answer. */
|
|
68
|
-
size?: "md" | "lg";
|
|
69
|
-
/** A quiet line under the figure: the window it covers, or why it is a dash. */
|
|
70
|
-
caption?: string;
|
|
71
|
-
/**
|
|
72
|
-
* Drop the card chrome. For a figure that sits in a band or a panel of its
|
|
73
|
-
* own, where a second border would draw a box inside a box.
|
|
74
|
-
*/
|
|
75
|
-
bare?: boolean;
|
|
76
|
-
/** Leading icon before the label. */
|
|
77
|
-
icon?: Snippet;
|
|
78
|
-
/** Rendered at the right of the label row. */
|
|
79
|
-
trailing?: Snippet;
|
|
80
|
-
class?: string;
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// =========================
|
|
84
|
-
// PROPS
|
|
85
|
-
// =========================
|
|
86
|
-
let {
|
|
87
|
-
label,
|
|
88
|
-
value,
|
|
89
|
-
format,
|
|
90
|
-
formatOptions,
|
|
91
|
-
locale,
|
|
92
|
-
delta = null,
|
|
93
|
-
direction = "neutral",
|
|
94
|
-
deltaThreshold = 0.5,
|
|
95
|
-
share,
|
|
96
|
-
shareLabel,
|
|
97
|
-
color = "var(--chart-1)",
|
|
98
|
-
size = "md",
|
|
99
|
-
caption,
|
|
100
|
-
bare = false,
|
|
101
|
-
icon,
|
|
102
|
-
trailing,
|
|
103
|
-
class: className,
|
|
104
|
-
}: Props = $props();
|
|
105
|
-
|
|
106
|
-
// =========================
|
|
107
|
-
// DERIVED
|
|
108
|
-
// =========================
|
|
109
|
-
// Under half a point either way is noise, not a movement, and eight figures
|
|
110
|
-
// each reporting a 0% move is eight pieces of chrome saying nothing.
|
|
111
|
-
const move = $derived(delta != null && Math.abs(delta) >= deltaThreshold ? delta : null);
|
|
112
|
-
// The arrow follows the sign and the colour follows the news, because a cost
|
|
113
|
-
// that fell is a green figure with a down arrow. One glyph cannot say both.
|
|
114
|
-
const tone = $derived.by(() => {
|
|
115
|
-
if (move == null || direction === "neutral") return "flat";
|
|
116
|
-
const good = direction === "up-good" ? move > 0 : move < 0;
|
|
117
|
-
return good ? "up" : "down";
|
|
118
|
-
});
|
|
119
|
-
const pct = $derived(share == null ? null : Math.max(0, Math.min(1, share)));
|
|
120
|
-
</script>
|
|
121
|
-
|
|
122
|
-
<!-- =========================== -->
|
|
123
|
-
<!-- NUMBER CHART -->
|
|
124
|
-
<!-- =========================== -->
|
|
125
|
-
<div class={cn("hr-number-chart", className)} data-size={size} data-bare={bare ? "" : undefined}>
|
|
126
|
-
<p class="hr-number-label">
|
|
127
|
-
{#if icon}<span class="hr-number-icon" style:color>{@render icon()}</span>{/if}
|
|
128
|
-
<span class="hr-number-label-text">{label}</span>
|
|
129
|
-
{#if trailing}<span class="hr-number-trailing">{@render trailing()}</span>{/if}
|
|
130
|
-
</p>
|
|
131
|
-
|
|
132
|
-
<div class="hr-number-row">
|
|
133
|
-
<span class="hr-number-value">
|
|
134
|
-
{#if typeof value === "number"}
|
|
135
|
-
<AnimatedValue {value} {format} {formatOptions} {locale} duration={600} />
|
|
136
|
-
{:else}
|
|
137
|
-
{value}
|
|
138
|
-
{/if}
|
|
139
|
-
</span>
|
|
140
|
-
{#if move != null}
|
|
141
|
-
<span class="hr-number-delta" data-tone={tone}>
|
|
142
|
-
{#if move > 0}
|
|
143
|
-
<TrendUp class="hr-number-arrow" weight="bold" />
|
|
144
|
-
{:else}
|
|
145
|
-
<TrendDown class="hr-number-arrow" weight="bold" />
|
|
146
|
-
{/if}
|
|
147
|
-
<span class="hr-number-delta-text">{Math.abs(move).toFixed(0)}%</span>
|
|
148
|
-
</span>
|
|
149
|
-
{:else}
|
|
150
|
-
<span class="hr-number-delta" data-tone="none" aria-hidden="true">
|
|
151
|
-
<Minus class="hr-number-arrow" />
|
|
152
|
-
</span>
|
|
153
|
-
{/if}
|
|
154
|
-
</div>
|
|
155
|
-
|
|
156
|
-
{#if pct != null}
|
|
157
|
-
<!-- WHY the number gets a rail and not a sparkline: one figure has no series to plot, and the question a lone number cannot answer is "out of -->
|
|
158
|
-
<!-- what". The rail answers exactly that and nothing else. -->
|
|
159
|
-
<div
|
|
160
|
-
class="hr-number-track"
|
|
161
|
-
role="img"
|
|
162
|
-
aria-label="{label}: {Math.round(pct * 100)}% {shareLabel ?? 'of the total'}"
|
|
163
|
-
>
|
|
164
|
-
<span class="hr-number-fill" style:width="{pct * 100}%" style:background={color}></span>
|
|
165
|
-
</div>
|
|
166
|
-
{/if}
|
|
167
|
-
|
|
168
|
-
{#if shareLabel && pct != null}
|
|
169
|
-
<p class="hr-number-caption">
|
|
170
|
-
<span class="hr-number-share">{Math.round(pct * 100)}%</span>
|
|
171
|
-
{shareLabel}
|
|
172
|
-
</p>
|
|
173
|
-
{/if}
|
|
174
|
-
{#if caption}
|
|
175
|
-
<p class="hr-number-caption">{caption}</p>
|
|
176
|
-
{/if}
|
|
177
|
-
</div>
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
-
import { cn, type WithElementRef } from "@heyramzi/utils";
|
|
4
|
-
import ChartStyle from "./chart-style.svelte";
|
|
5
|
-
import { type ChartConfig, setChartContext } from "./chart-utils.js";
|
|
6
|
-
|
|
7
|
-
const uid = $props.id();
|
|
8
|
-
|
|
9
|
-
let {
|
|
10
|
-
ref = $bindable(null),
|
|
11
|
-
id = uid,
|
|
12
|
-
class: className,
|
|
13
|
-
children,
|
|
14
|
-
config,
|
|
15
|
-
...restProps
|
|
16
|
-
}: WithElementRef<HTMLAttributes<HTMLElement>> & {
|
|
17
|
-
config: ChartConfig;
|
|
18
|
-
} = $props();
|
|
19
|
-
|
|
20
|
-
const chartId = $derived(`chart-${id || uid.replace(/:/g, "")}`);
|
|
21
|
-
|
|
22
|
-
setChartContext({
|
|
23
|
-
get config() {
|
|
24
|
-
return config;
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
</script>
|
|
28
|
-
|
|
29
|
-
<div
|
|
30
|
-
bind:this={ref}
|
|
31
|
-
data-chart={chartId}
|
|
32
|
-
data-slot="chart"
|
|
33
|
-
class={cn(
|
|
34
|
-
"flex aspect-video justify-center overflow-visible text-xs",
|
|
35
|
-
"[&_.stroke-white]:stroke-transparent",
|
|
36
|
-
"[&_.lc-line]:stroke-border/50",
|
|
37
|
-
"[&_.lc-highlight-line]:stroke-0",
|
|
38
|
-
"[&_.lc-area-path]:opacity-100 [&_.lc-highlight-line]:opacity-100 [&_.lc-highlight-point]:opacity-100 [&_.lc-spline-path]:opacity-100 [&_.lc-text-svg]:overflow-visible [&_.lc-text]:text-xs",
|
|
39
|
-
"[&_.lc-axis-tick]:stroke-0",
|
|
40
|
-
"[&_.lc-rule-x-line:not(.lc-grid-x-rule)]:stroke-0 [&_.lc-rule-y-line:not(.lc-grid-y-rule)]:stroke-0",
|
|
41
|
-
"[&_.lc-grid-x-radial-line]:stroke-border [&_.lc-grid-x-radial-circle]:stroke-border",
|
|
42
|
-
"[&_.lc-grid-y-radial-line]:stroke-border [&_.lc-grid-y-radial-circle]:stroke-border",
|
|
43
|
-
"[&_.lc-legend-swatch-button]:items-center [&_.lc-legend-swatch-button]:gap-1.5",
|
|
44
|
-
"[&_.lc-legend-swatch-group]:items-center [&_.lc-legend-swatch-group]:gap-4",
|
|
45
|
-
"[&_.lc-legend-swatch]:size-2.5 [&_.lc-legend-swatch]:rounded-[2px]",
|
|
46
|
-
"[&_.lc-labels-text:not([fill])]:fill-foreground [&_text]:stroke-transparent",
|
|
47
|
-
"[&_.lc-axis-tick-label]:fill-muted-foreground [&_.lc-axis-tick-label]:font-normal",
|
|
48
|
-
"[&_.lc-tooltip-rects-g]:fill-transparent",
|
|
49
|
-
"[&_.lc-layout-svg-g]:fill-transparent",
|
|
50
|
-
"[&_.lc-root-container]:w-full",
|
|
51
|
-
className,
|
|
52
|
-
)}
|
|
53
|
-
{...restProps}
|
|
54
|
-
>
|
|
55
|
-
<ChartStyle id={chartId} {config} />
|
|
56
|
-
{@render children?.()}
|
|
57
|
-
</div>
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { type ChartConfig, THEMES } from "./chart-utils.js";
|
|
3
|
-
|
|
4
|
-
let { id, config }: { id: string; config: ChartConfig } = $props();
|
|
5
|
-
|
|
6
|
-
const colorConfig = $derived(
|
|
7
|
-
config ? Object.entries(config).filter(([, c]) => c.theme || c.color) : null,
|
|
8
|
-
);
|
|
9
|
-
|
|
10
|
-
const themeContents = $derived.by(() => {
|
|
11
|
-
if (!colorConfig || !colorConfig.length) return;
|
|
12
|
-
|
|
13
|
-
const blocks: string[] = [];
|
|
14
|
-
for (const [_theme, prefix] of Object.entries(THEMES)) {
|
|
15
|
-
let content = `${prefix} [data-chart=${id}] {\n`;
|
|
16
|
-
const color = colorConfig.map(([key, itemConfig]) => {
|
|
17
|
-
const theme = _theme as keyof typeof itemConfig.theme;
|
|
18
|
-
const value = itemConfig.theme?.[theme] || itemConfig.color;
|
|
19
|
-
return value ? `\t--color-${key}: ${value};` : null;
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
content += `${color.join("\n")}\n}`;
|
|
23
|
-
blocks.push(content);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return blocks.join("\n");
|
|
27
|
-
});
|
|
28
|
-
</script>
|
|
29
|
-
|
|
30
|
-
{#if themeContents}
|
|
31
|
-
{#key id}
|
|
32
|
-
<svelte:element this={"style"}>
|
|
33
|
-
{themeContents}
|
|
34
|
-
</svelte:element>
|
|
35
|
-
{/key}
|
|
36
|
-
{/if}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { getChartContext, Tooltip as TooltipPrimitive } from "layerchart";
|
|
3
|
-
import type { Snippet } from "svelte";
|
|
4
|
-
import type { HTMLAttributes } from "svelte/elements";
|
|
5
|
-
import { cn, type WithElementRef, type WithoutChildren } from "@heyramzi/utils";
|
|
6
|
-
import {
|
|
7
|
-
getPayloadConfigFromPayload,
|
|
8
|
-
type TooltipSeriesItem,
|
|
9
|
-
useChart,
|
|
10
|
-
} from "./chart-utils.js";
|
|
11
|
-
|
|
12
|
-
function defaultFormatter(value: unknown, _series: TooltipSeriesItem[]) {
|
|
13
|
-
return `${value}`;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
let {
|
|
17
|
-
ref = $bindable(null),
|
|
18
|
-
class: className,
|
|
19
|
-
hideLabel = false,
|
|
20
|
-
indicator = "dot",
|
|
21
|
-
hideIndicator = false,
|
|
22
|
-
labelKey,
|
|
23
|
-
label,
|
|
24
|
-
labelFormatter = defaultFormatter,
|
|
25
|
-
labelClassName,
|
|
26
|
-
formatter,
|
|
27
|
-
nameKey,
|
|
28
|
-
color,
|
|
29
|
-
...restProps
|
|
30
|
-
}: WithoutChildren<WithElementRef<HTMLAttributes<HTMLDivElement>>> & {
|
|
31
|
-
hideLabel?: boolean;
|
|
32
|
-
label?: string;
|
|
33
|
-
indicator?: "line" | "dot" | "dashed";
|
|
34
|
-
nameKey?: string;
|
|
35
|
-
labelKey?: string;
|
|
36
|
-
hideIndicator?: boolean;
|
|
37
|
-
labelClassName?: string;
|
|
38
|
-
labelFormatter?:
|
|
39
|
-
| ((value: unknown, series: TooltipSeriesItem[]) => string | number | Snippet)
|
|
40
|
-
| null;
|
|
41
|
-
formatter?: Snippet<
|
|
42
|
-
[
|
|
43
|
-
{
|
|
44
|
-
value: unknown;
|
|
45
|
-
name: string;
|
|
46
|
-
item: TooltipSeriesItem;
|
|
47
|
-
index: number;
|
|
48
|
-
series: TooltipSeriesItem[];
|
|
49
|
-
},
|
|
50
|
-
]
|
|
51
|
-
>;
|
|
52
|
-
} = $props();
|
|
53
|
-
|
|
54
|
-
const chart = useChart();
|
|
55
|
-
const ctx = getChartContext();
|
|
56
|
-
|
|
57
|
-
const tooltipSeries = $derived(ctx.tooltip.series as TooltipSeriesItem[]);
|
|
58
|
-
|
|
59
|
-
const formattedLabel = $derived.by(() => {
|
|
60
|
-
if (hideLabel || !tooltipSeries?.length) return null;
|
|
61
|
-
|
|
62
|
-
const [item] = tooltipSeries;
|
|
63
|
-
const key = labelKey ?? item?.label ?? item?.key ?? "value";
|
|
64
|
-
|
|
65
|
-
const itemConfig = getPayloadConfigFromPayload(chart.config, item, key);
|
|
66
|
-
|
|
67
|
-
const value =
|
|
68
|
-
!labelKey && typeof label === "string"
|
|
69
|
-
? (chart.config[label as keyof typeof chart.config]?.label ?? label)
|
|
70
|
-
: (itemConfig?.label ?? item.label);
|
|
71
|
-
|
|
72
|
-
if (value === undefined) return null;
|
|
73
|
-
if (!labelFormatter) return value;
|
|
74
|
-
return labelFormatter(value, tooltipSeries);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const nestLabel = $derived(tooltipSeries.length === 1 && indicator !== "dot");
|
|
78
|
-
</script>
|
|
79
|
-
|
|
80
|
-
{#snippet TooltipLabel()}
|
|
81
|
-
{#if formattedLabel}
|
|
82
|
-
<div class={cn("font-medium", labelClassName)}>
|
|
83
|
-
{#if typeof formattedLabel === "function"}
|
|
84
|
-
{@render formattedLabel()}
|
|
85
|
-
{:else}
|
|
86
|
-
{formattedLabel}
|
|
87
|
-
{/if}
|
|
88
|
-
</div>
|
|
89
|
-
{/if}
|
|
90
|
-
{/snippet}
|
|
91
|
-
|
|
92
|
-
<TooltipPrimitive.Root variant="none">
|
|
93
|
-
<div
|
|
94
|
-
class={cn(
|
|
95
|
-
"border-border/50 bg-background grid min-w-[9rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
|
|
96
|
-
className,
|
|
97
|
-
)}
|
|
98
|
-
{...restProps}
|
|
99
|
-
>
|
|
100
|
-
{#if !nestLabel}
|
|
101
|
-
{@render TooltipLabel()}
|
|
102
|
-
{/if}
|
|
103
|
-
<div class="grid gap-1.5">
|
|
104
|
-
{#each tooltipSeries as item, i (item.key + i)}
|
|
105
|
-
{@const key = `${nameKey || item.key || "value"}`}
|
|
106
|
-
{@const itemConfig = getPayloadConfigFromPayload(chart.config, item, key)}
|
|
107
|
-
{@const indicatorColor = color || item.color}
|
|
108
|
-
<div
|
|
109
|
-
class={cn(
|
|
110
|
-
"[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:size-2.5",
|
|
111
|
-
indicator === "dot" && "items-center",
|
|
112
|
-
)}
|
|
113
|
-
>
|
|
114
|
-
{#if formatter && item.value !== undefined && item.key}
|
|
115
|
-
{@render formatter({
|
|
116
|
-
value: item.value,
|
|
117
|
-
name: item.label || item.key,
|
|
118
|
-
item,
|
|
119
|
-
index: i,
|
|
120
|
-
series: tooltipSeries,
|
|
121
|
-
})}
|
|
122
|
-
{:else}
|
|
123
|
-
{#if itemConfig?.icon}
|
|
124
|
-
<itemConfig.icon />
|
|
125
|
-
{:else if !hideIndicator}
|
|
126
|
-
<div
|
|
127
|
-
style="--color-bg: {indicatorColor}; --color-border: {indicatorColor};"
|
|
128
|
-
class={cn("border-(--color-border) bg-(--color-bg) shrink-0 rounded-[2px]", {
|
|
129
|
-
"size-2.5": indicator === "dot",
|
|
130
|
-
"h-full w-1": indicator === "line",
|
|
131
|
-
"w-0 border-[1.5px] border-dashed bg-transparent": indicator === "dashed",
|
|
132
|
-
"my-0.5": nestLabel && indicator === "dashed",
|
|
133
|
-
})}
|
|
134
|
-
></div>
|
|
135
|
-
{/if}
|
|
136
|
-
<div
|
|
137
|
-
class={cn(
|
|
138
|
-
"flex flex-1 shrink-0 justify-between leading-none",
|
|
139
|
-
nestLabel ? "items-end" : "items-center",
|
|
140
|
-
)}
|
|
141
|
-
>
|
|
142
|
-
<div class="grid gap-1.5">
|
|
143
|
-
{#if nestLabel}
|
|
144
|
-
{@render TooltipLabel()}
|
|
145
|
-
{/if}
|
|
146
|
-
<span class="text-muted-foreground">
|
|
147
|
-
{itemConfig?.label || item.label || item.key}
|
|
148
|
-
</span>
|
|
149
|
-
</div>
|
|
150
|
-
{#if item.value !== undefined}
|
|
151
|
-
<span class="text-foreground font-mono font-medium tabular-nums">
|
|
152
|
-
{typeof item.value === "number" ? item.value.toLocaleString() : item.value}
|
|
153
|
-
</span>
|
|
154
|
-
{/if}
|
|
155
|
-
</div>
|
|
156
|
-
{/if}
|
|
157
|
-
</div>
|
|
158
|
-
{/each}
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
</TooltipPrimitive.Root>
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { type Component, getContext, setContext } from "svelte";
|
|
2
|
-
|
|
3
|
-
export const THEMES = { light: "", dark: ".dark" } as const;
|
|
4
|
-
|
|
5
|
-
export type ChartConfig = {
|
|
6
|
-
[k in string]: {
|
|
7
|
-
label?: string;
|
|
8
|
-
icon?: Component;
|
|
9
|
-
} & (
|
|
10
|
-
| { color?: string; theme?: never }
|
|
11
|
-
| { color?: never; theme: Record<keyof typeof THEMES, string> }
|
|
12
|
-
);
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export type TooltipSeriesItem = {
|
|
16
|
-
key: string;
|
|
17
|
-
label: string;
|
|
18
|
-
value: unknown;
|
|
19
|
-
color: string | undefined;
|
|
20
|
-
visible: boolean;
|
|
21
|
-
config: unknown;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export function getPayloadConfigFromPayload(
|
|
25
|
-
config: ChartConfig,
|
|
26
|
-
item: TooltipSeriesItem,
|
|
27
|
-
key: string,
|
|
28
|
-
) {
|
|
29
|
-
if (typeof item !== "object" || item === null) return undefined;
|
|
30
|
-
|
|
31
|
-
let configLabelKey: string = key;
|
|
32
|
-
|
|
33
|
-
if (item.key === key) {
|
|
34
|
-
configLabelKey = item.key;
|
|
35
|
-
} else if (item.label === key) {
|
|
36
|
-
configLabelKey = item.label;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
type ChartContextValue = {
|
|
43
|
-
config: ChartConfig;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const chartContextKey = Symbol("chart-context");
|
|
47
|
-
|
|
48
|
-
export function setChartContext(value: ChartContextValue) {
|
|
49
|
-
return setContext(chartContextKey, value);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function useChart() {
|
|
53
|
-
return getContext<ChartContextValue>(chartContextKey);
|
|
54
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export { default as ChartContainer } from "./chart-container.svelte";
|
|
2
|
-
export { default as ChartTooltip } from "./chart-tooltip.svelte";
|
|
3
|
-
export { default as ChartStyle } from "./chart-style.svelte";
|
|
4
|
-
export {
|
|
5
|
-
type ChartConfig,
|
|
6
|
-
type TooltipSeriesItem,
|
|
7
|
-
getPayloadConfigFromPayload,
|
|
8
|
-
useChart,
|
|
9
|
-
setChartContext,
|
|
10
|
-
THEMES,
|
|
11
|
-
} from "./chart-utils.js";
|
package/src/charts/reveal.svelte
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
// =========================
|
|
3
|
-
// IMPORTS
|
|
4
|
-
// =========================
|
|
5
|
-
import { getChartContext } from "layerchart";
|
|
6
|
-
import { onMount, type Snippet } from "svelte";
|
|
7
|
-
import { expoInOut } from "svelte/easing";
|
|
8
|
-
import { prefersReducedMotion, Tween } from "svelte/motion";
|
|
9
|
-
import { REVEAL_MS, tokenMs } from "./motion.js";
|
|
10
|
-
|
|
11
|
-
// =========================
|
|
12
|
-
// TYPES
|
|
13
|
-
// =========================
|
|
14
|
-
type Props = {
|
|
15
|
-
children: Snippet;
|
|
16
|
-
/** Headroom around the plot so a stroke at the series max is not cut. */
|
|
17
|
-
bleed?: number;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
// =========================
|
|
21
|
-
// PROPS
|
|
22
|
-
// =========================
|
|
23
|
-
let { children, bleed = 6 }: Props = $props();
|
|
24
|
-
|
|
25
|
-
// =========================
|
|
26
|
-
// STATE
|
|
27
|
-
// =========================
|
|
28
|
-
const ctx = getChartContext();
|
|
29
|
-
const id = `hr-reveal-${Math.random().toString(36).slice(2, 8)}`;
|
|
30
|
-
const progress = new Tween(0, { easing: expoInOut });
|
|
31
|
-
let rect = $state<SVGRectElement>();
|
|
32
|
-
|
|
33
|
-
// =========================
|
|
34
|
-
// LIFECYCLE
|
|
35
|
-
// =========================
|
|
36
|
-
onMount(() => {
|
|
37
|
-
const duration =
|
|
38
|
-
prefersReducedMotion.current || !rect ? 0 : tokenMs(rect, "--chart-motion-reveal", REVEAL_MS);
|
|
39
|
-
progress.set(1, { duration });
|
|
40
|
-
});
|
|
41
|
-
</script>
|
|
42
|
-
|
|
43
|
-
<!-- =========================== -->
|
|
44
|
-
<!-- REVEAL -->
|
|
45
|
-
<!-- =========================== -->
|
|
46
|
-
<!-- WHY a tweened width and not scaleX: scaleX needs a transform origin, and the
|
|
47
|
-
rect has to keep tracking the plot width through a resize. -->
|
|
48
|
-
<defs>
|
|
49
|
-
<clipPath {id}>
|
|
50
|
-
<rect
|
|
51
|
-
bind:this={rect}
|
|
52
|
-
x={-bleed}
|
|
53
|
-
y={-bleed}
|
|
54
|
-
width={Math.max(0, (ctx.width + bleed * 2) * progress.current)}
|
|
55
|
-
height={ctx.height + bleed * 2}
|
|
56
|
-
/>
|
|
57
|
-
</clipPath>
|
|
58
|
-
</defs>
|
|
59
|
-
<g clip-path="url(#{id})">
|
|
60
|
-
{@render children()}
|
|
61
|
-
</g>
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/* Styles for RingChart. Plain stylesheet (see area-chart.css for why).
|
|
2
|
-
Selectors are namespaced under `.hr-ring` (the generic ones below would
|
|
3
|
-
otherwise collide with GaugeChart's identical names once they are no longer
|
|
4
|
-
Svelte-scoped). */
|
|
5
|
-
|
|
6
|
-
.hr-ring {
|
|
7
|
-
position: relative;
|
|
8
|
-
display: inline-grid;
|
|
9
|
-
place-items: center;
|
|
10
|
-
aspect-ratio: 1;
|
|
11
|
-
container-type: size;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.hr-ring svg {
|
|
15
|
-
grid-area: 1 / 1;
|
|
16
|
-
width: 100%;
|
|
17
|
-
height: 100%;
|
|
18
|
-
overflow: visible;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.hr-ring .track {
|
|
22
|
-
opacity: 0.14;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.hr-ring .fill {
|
|
26
|
-
stroke-dasharray: 100;
|
|
27
|
-
cursor: pointer;
|
|
28
|
-
outline: none;
|
|
29
|
-
transition:
|
|
30
|
-
stroke-dashoffset var(--chart-motion-slow, 1.1s)
|
|
31
|
-
var(--chart-ease-out, cubic-bezier(0.22, 1, 0.36, 1)),
|
|
32
|
-
opacity 200ms ease;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.hr-ring .fill.animate {
|
|
36
|
-
animation: hr-ring-sweep var(--chart-motion-reveal, 1100ms)
|
|
37
|
-
var(--chart-ease-reveal, cubic-bezier(0.85, 0, 0.15, 1)) both;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.hr-ring.glow .fill:hover {
|
|
41
|
-
filter: drop-shadow(0 0 5px var(--ring-color));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@keyframes hr-ring-sweep {
|
|
45
|
-
from {
|
|
46
|
-
stroke-dashoffset: 100;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.hr-ring .center {
|
|
51
|
-
grid-area: 1 / 1;
|
|
52
|
-
display: flex;
|
|
53
|
-
flex-direction: column;
|
|
54
|
-
align-items: center;
|
|
55
|
-
justify-content: center;
|
|
56
|
-
/* WHY: keep the readout inside the innermost ring's clear center so the
|
|
57
|
-
number never collides with the green ring. */
|
|
58
|
-
max-width: 40cqmin;
|
|
59
|
-
pointer-events: none;
|
|
60
|
-
text-align: center;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.hr-ring .value {
|
|
64
|
-
font-size: max(0.75rem, 9.5cqmin);
|
|
65
|
-
font-weight: 650;
|
|
66
|
-
line-height: 1;
|
|
67
|
-
letter-spacing: -0.02em;
|
|
68
|
-
font-variant-numeric: tabular-nums;
|
|
69
|
-
color: var(--foreground);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.hr-ring .label {
|
|
73
|
-
margin-top: 1.5cqmin;
|
|
74
|
-
font-size: max(0.5rem, 5cqmin);
|
|
75
|
-
font-weight: 500;
|
|
76
|
-
color: var(--muted-foreground);
|
|
77
|
-
animation: hr-ring-label-in 180ms ease-out both;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
@keyframes hr-ring-label-in {
|
|
81
|
-
from {
|
|
82
|
-
opacity: 0;
|
|
83
|
-
transform: translateY(2px);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
@media (prefers-reduced-motion: reduce) {
|
|
88
|
-
.hr-ring .fill,
|
|
89
|
-
.hr-ring .fill.animate {
|
|
90
|
-
transition: opacity 120ms ease;
|
|
91
|
-
animation: none;
|
|
92
|
-
}
|
|
93
|
-
.hr-ring .label {
|
|
94
|
-
animation: none;
|
|
95
|
-
}
|
|
96
|
-
}
|