@robr0/design-system 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +9 -3
  2. package/components/Banner/Banner.css +110 -0
  3. package/components/Banner/Banner.d.ts +36 -0
  4. package/components/Banner/Banner.js +59 -0
  5. package/components/ContributionGraph/ContributionGraph.css +7 -1
  6. package/components/ContributionGraph/ContributionGraph.d.ts +9 -1
  7. package/components/ContributionGraph/ContributionGraph.js +59 -43
  8. package/components/EmptyState/EmptyState.css +5 -0
  9. package/components/FunnelChart/FunnelChart.css +3 -2
  10. package/components/FunnelChart/FunnelChart.d.ts +12 -4
  11. package/components/FunnelChart/FunnelChart.js +48 -28
  12. package/components/Gauge/Gauge.css +30 -13
  13. package/components/Gauge/Gauge.d.ts +16 -8
  14. package/components/Gauge/Gauge.js +78 -62
  15. package/components/HoverCard/HoverCard.css +97 -0
  16. package/components/HoverCard/HoverCard.d.ts +29 -0
  17. package/components/HoverCard/HoverCard.js +83 -0
  18. package/components/ImageCompare/ImageCompare.css +112 -0
  19. package/components/ImageCompare/ImageCompare.d.ts +40 -0
  20. package/components/ImageCompare/ImageCompare.js +134 -0
  21. package/components/LinkList/LinkList.d.ts +3 -1
  22. package/components/LinkList/LinkList.js +4 -3
  23. package/components/Meter/Meter.css +89 -0
  24. package/components/Meter/Meter.d.ts +36 -0
  25. package/components/Meter/Meter.js +48 -0
  26. package/components/NotificationCenter/NotificationCenter.css +11 -3
  27. package/components/Rating/Rating.css +74 -0
  28. package/components/Rating/Rating.d.ts +41 -0
  29. package/components/Rating/Rating.js +124 -0
  30. package/components/Sparkline/Sparkline.d.ts +5 -3
  31. package/components/Sparkline/Sparkline.js +30 -1
  32. package/components/SplitButton/SplitButton.css +93 -0
  33. package/components/SplitButton/SplitButton.d.ts +43 -0
  34. package/components/SplitButton/SplitButton.js +66 -0
  35. package/components/StreamingText/StreamingText.d.ts +27 -9
  36. package/components/StreamingText/StreamingText.js +17 -29
  37. package/components/StreamingText/useStreamReveal.d.ts +70 -0
  38. package/components/StreamingText/useStreamReveal.js +121 -0
  39. package/components/registry.json +48 -0
  40. package/components/registry.json.d.ts +48 -0
  41. package/components/registry.json.js +1 -1
  42. package/index.d.ts +6 -0
  43. package/index.js +15 -0
  44. package/package.json +5 -1
  45. package/tokens/motion.d.ts +9 -4
  46. package/tokens/motion.js +5 -1
@@ -15,9 +15,9 @@ type GaugeOwnProps = {
15
15
  /** Upper bound of the dial. */
16
16
  max?: number;
17
17
  /**
18
- * Colour role for the value arc and reading. Ignored while a threshold
19
- * matches thresholds exist so the dial recolours itself as the reading
20
- * crosses them.
18
+ * Colour role for the value arc. `accent` (the default) follows the chart
19
+ * palette's lead colour. Ignored while a threshold matches thresholds
20
+ * exist so the dial recolours itself as the reading crosses them.
21
21
  */
22
22
  tone?: 'accent' | 'positive' | 'warning' | 'error' | 'neutral';
23
23
  /**
@@ -35,7 +35,13 @@ type GaugeOwnProps = {
35
35
  * accessible name, e.g. "CPU usage".
36
36
  */
37
37
  label?: string;
38
- /** Rendered diameter in pixels. The arc geometry scales with it. */
38
+ /** Chart title, in the shared chart header. */
39
+ title?: string;
40
+ /** Description text below the title. */
41
+ subtitle?: string;
42
+ /** Strip the card chrome (border, padding, fill) when the chart sits inside another panel that supplies the surface */
43
+ bare?: boolean;
44
+ /** Rendered dial diameter in pixels. The arc geometry scales with it. */
39
45
  size?: number;
40
46
  /** Arc thickness in pixels. */
41
47
  strokeWidth?: number;
@@ -47,10 +53,12 @@ export interface GaugeProps extends GaugeOwnProps, Omit<React.ComponentPropsWith
47
53
  /**
48
54
  * Gauge — a radial dial for a single bounded reading: capacity, usage, a
49
55
  * score against a target. Pure SVG computed from props — no charting library,
50
- * no hooks — so it renders from a Server Component and drops straight into a
51
- * Panel or Stat row. Thresholds recolour the dial through the status roles as
52
- * the reading crosses them, and the arc animates between readings via a CSS
53
- * transition. Announced as a `meter` with the label as its accessible name.
56
+ * no hooks — so it renders from a Server Component. It wears the chart
57
+ * family's card chrome (title, subtitle, padding) and takes `bare` to drop
58
+ * it inside a Panel, like every other chart. Thresholds recolour the dial
59
+ * through the status roles as the reading crosses them, and the arc animates
60
+ * between readings via a CSS transition. The dial is announced as a `meter`
61
+ * with the label as its accessible name.
54
62
  */
55
63
  export declare const Gauge: React.ForwardRefExoticComponent<GaugeProps & React.RefAttributes<HTMLDivElement>>;
56
64
  export {};
@@ -1,5 +1,6 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import React from "react";
3
+ import "../Chart/Chart.css";
3
4
  import "./Gauge.css";
4
5
  const SWEEP_UNITS = 75;
5
6
  const Gauge = React.forwardRef(
@@ -12,81 +13,96 @@ const Gauge = React.forwardRef(
12
13
  showValue = true,
13
14
  formatValue,
14
15
  label,
16
+ title,
17
+ subtitle,
18
+ bare = false,
15
19
  size = 120,
16
- strokeWidth = 10,
20
+ strokeWidth = 12,
17
21
  className = "",
18
22
  ...rest
19
23
  }, ref) => {
20
24
  const baseClass = "ds-gauge";
25
+ const chartClass = "ds-chart";
21
26
  const range = max - min;
22
27
  const fraction = range > 0 ? Math.min(Math.max((value - min) / range, 0), 1) : 0;
23
28
  const activeThreshold = thresholds?.filter((t) => value >= t.value).sort((a, b) => b.value - a.value)[0];
24
29
  const resolvedTone = activeThreshold?.tone ?? tone;
25
- const classes = [baseClass, `${baseClass}--${resolvedTone}`, className].filter(Boolean).join(" ");
30
+ const classes = [
31
+ chartClass,
32
+ bare && `${chartClass}--bare`,
33
+ baseClass,
34
+ `${baseClass}--${resolvedTone}`,
35
+ className
36
+ ].filter(Boolean).join(" ");
26
37
  const radius = (size - strokeWidth) / 2;
27
38
  const center = size / 2;
28
39
  const valueUnits = Math.round(SWEEP_UNITS * fraction * 100) / 100;
29
40
  const displayValue = formatValue ? formatValue(value) : String(Math.round(value));
30
- return /* @__PURE__ */ jsxs(
31
- "div",
32
- {
33
- ...rest,
34
- ref,
35
- className: classes,
36
- style: { width: size, height: size, ...rest.style },
37
- role: "meter",
38
- "aria-valuenow": value,
39
- "aria-valuemin": min,
40
- "aria-valuemax": max,
41
- "aria-valuetext": displayValue,
42
- "aria-label": label ?? rest["aria-label"],
43
- children: [
44
- /* @__PURE__ */ jsxs(
45
- "svg",
46
- {
47
- className: `${baseClass}__svg`,
48
- viewBox: `0 0 ${size} ${size}`,
49
- width: size,
50
- height: size,
51
- xmlns: "http://www.w3.org/2000/svg",
52
- "aria-hidden": "true",
53
- children: [
54
- /* @__PURE__ */ jsx(
55
- "circle",
56
- {
57
- className: `${baseClass}__track`,
58
- cx: center,
59
- cy: center,
60
- r: radius,
61
- pathLength: 100,
62
- strokeWidth,
63
- strokeDasharray: `${SWEEP_UNITS} ${100 - SWEEP_UNITS}`,
64
- transform: `rotate(135 ${center} ${center})`
65
- }
66
- ),
67
- valueUnits > 0 && /* @__PURE__ */ jsx(
68
- "circle",
69
- {
70
- className: `${baseClass}__arc`,
71
- cx: center,
72
- cy: center,
73
- r: radius,
74
- pathLength: 100,
75
- strokeWidth,
76
- strokeDasharray: `${valueUnits} ${100 - valueUnits}`,
77
- transform: `rotate(135 ${center} ${center})`
78
- }
79
- )
80
- ]
81
- }
82
- ),
83
- (showValue || label) && /* @__PURE__ */ jsxs("div", { className: `${baseClass}__center`, children: [
84
- showValue && /* @__PURE__ */ jsx("span", { className: `${baseClass}__value`, children: displayValue }),
85
- label && /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: label })
86
- ] })
87
- ]
88
- }
89
- );
41
+ const { "aria-label": restAriaLabel, ...restProps } = rest;
42
+ return /* @__PURE__ */ jsxs("div", { ...restProps, ref, className: classes, children: [
43
+ (title || subtitle) && /* @__PURE__ */ jsx("div", { className: `${chartClass}__header`, children: /* @__PURE__ */ jsxs("div", { className: `${chartClass}__header-text`, children: [
44
+ title && /* @__PURE__ */ jsx("h3", { className: `${chartClass}__title`, children: title }),
45
+ subtitle && /* @__PURE__ */ jsx("p", { className: `${chartClass}__subtitle`, children: subtitle })
46
+ ] }) }),
47
+ /* @__PURE__ */ jsx("div", { className: `${chartClass}__body ${baseClass}__body`, children: /* @__PURE__ */ jsxs(
48
+ "div",
49
+ {
50
+ className: `${baseClass}__dial`,
51
+ style: { width: size, height: size },
52
+ role: "meter",
53
+ "aria-valuenow": value,
54
+ "aria-valuemin": min,
55
+ "aria-valuemax": max,
56
+ "aria-valuetext": displayValue,
57
+ "aria-label": label ?? restAriaLabel,
58
+ children: [
59
+ /* @__PURE__ */ jsxs(
60
+ "svg",
61
+ {
62
+ className: `${baseClass}__svg`,
63
+ viewBox: `0 0 ${size} ${size}`,
64
+ width: size,
65
+ height: size,
66
+ xmlns: "http://www.w3.org/2000/svg",
67
+ "aria-hidden": "true",
68
+ children: [
69
+ /* @__PURE__ */ jsx(
70
+ "circle",
71
+ {
72
+ className: `${baseClass}__track`,
73
+ cx: center,
74
+ cy: center,
75
+ r: radius,
76
+ pathLength: 100,
77
+ strokeWidth,
78
+ strokeDasharray: `${SWEEP_UNITS} ${100 - SWEEP_UNITS}`,
79
+ transform: `rotate(135 ${center} ${center})`
80
+ }
81
+ ),
82
+ valueUnits > 0 && /* @__PURE__ */ jsx(
83
+ "circle",
84
+ {
85
+ className: `${baseClass}__arc`,
86
+ cx: center,
87
+ cy: center,
88
+ r: radius,
89
+ pathLength: 100,
90
+ strokeWidth,
91
+ strokeDasharray: `${valueUnits} ${100 - valueUnits}`,
92
+ transform: `rotate(135 ${center} ${center})`
93
+ }
94
+ )
95
+ ]
96
+ }
97
+ ),
98
+ (showValue || label) && /* @__PURE__ */ jsxs("div", { className: `${baseClass}__center`, children: [
99
+ showValue && /* @__PURE__ */ jsx("span", { className: `${baseClass}__value`, children: displayValue }),
100
+ label && /* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: label })
101
+ ] })
102
+ ]
103
+ }
104
+ ) })
105
+ ] });
90
106
  }
91
107
  );
92
108
  Gauge.displayName = "Gauge";
@@ -0,0 +1,97 @@
1
+ /* ============================================
2
+ HOVER CARD COMPONENT
3
+ Rich preview panel on hover / focus
4
+ ============================================ */
5
+
6
+ .ds-hover-card {
7
+ position: relative;
8
+ display: inline-flex;
9
+ }
10
+
11
+ /* ============================================
12
+ PANEL
13
+ Dresses like the other floating panels:
14
+ page-primary fill, hairline, radius-sm,
15
+ floating shadow (see Popover).
16
+ ============================================ */
17
+
18
+ .ds-hover-card__panel {
19
+ /* Rendered as a <span> so the card survives inside a <p>; absolute
20
+ positioning already computes display to block, stated here anyway. */
21
+ display: block;
22
+ position: absolute;
23
+ z-index: 50;
24
+ min-width: 240px;
25
+ max-width: 320px;
26
+ padding: var(--padding-md);
27
+ border-radius: var(--radius-sm);
28
+ background-color: var(--color-bg-page-primary);
29
+ border: var(--border-xs) solid var(--color-bg-container-border);
30
+ box-shadow: var(--shadow-floating);
31
+ color: var(--color-text-primary);
32
+ font-family: var(--font-paragraph-sm-family);
33
+ font-size: var(--font-paragraph-sm-size);
34
+ font-weight: var(--font-paragraph-sm-weight);
35
+ line-height: var(--font-paragraph-sm-line-height);
36
+ /* visibility keeps the hidden panel out of the accessibility tree and
37
+ tab order; opacity + transform carry the entrance. */
38
+ visibility: hidden;
39
+ opacity: 0;
40
+ transition:
41
+ opacity var(--motion-duration-fast) var(--motion-ease-standard),
42
+ transform var(--motion-duration-fast) var(--motion-ease-standard),
43
+ visibility var(--motion-duration-fast) var(--motion-ease-standard);
44
+ }
45
+
46
+ .ds-hover-card__panel--visible {
47
+ visibility: visible;
48
+ opacity: 1;
49
+ }
50
+
51
+ /* ============================================
52
+ POSITIONS
53
+ ============================================ */
54
+
55
+ .ds-hover-card__panel--top {
56
+ bottom: 100%;
57
+ left: 50%;
58
+ transform: translateX(-50%) translateY(4px);
59
+ margin-bottom: var(--gap-xs);
60
+ }
61
+
62
+ .ds-hover-card__panel--top.ds-hover-card__panel--visible {
63
+ transform: translateX(-50%) translateY(0);
64
+ }
65
+
66
+ .ds-hover-card__panel--bottom {
67
+ top: 100%;
68
+ left: 50%;
69
+ transform: translateX(-50%) translateY(-4px);
70
+ margin-top: var(--gap-xs);
71
+ }
72
+
73
+ .ds-hover-card__panel--bottom.ds-hover-card__panel--visible {
74
+ transform: translateX(-50%) translateY(0);
75
+ }
76
+
77
+ .ds-hover-card__panel--left {
78
+ right: 100%;
79
+ top: 50%;
80
+ transform: translateY(-50%) translateX(4px);
81
+ margin-right: var(--gap-xs);
82
+ }
83
+
84
+ .ds-hover-card__panel--left.ds-hover-card__panel--visible {
85
+ transform: translateY(-50%) translateX(0);
86
+ }
87
+
88
+ .ds-hover-card__panel--right {
89
+ left: 100%;
90
+ top: 50%;
91
+ transform: translateY(-50%) translateX(-4px);
92
+ margin-left: var(--gap-xs);
93
+ }
94
+
95
+ .ds-hover-card__panel--right.ds-hover-card__panel--visible {
96
+ transform: translateY(-50%) translateX(0);
97
+ }
@@ -0,0 +1,29 @@
1
+ import { default as React } from 'react';
2
+ type HoverCardOwnProps = {
3
+ /** Trigger element */
4
+ children?: React.ReactNode;
5
+ /** Panel content — arbitrary elements, unlike Tooltip's plain text. In running text inside a `<p>`, keep it phrasing-level (spans): a block element would end the paragraph mid-parse. */
6
+ content: React.ReactNode;
7
+ /** Preferred position */
8
+ position?: 'top' | 'bottom' | 'left' | 'right';
9
+ /** Delay before showing (in ms) */
10
+ showDelay?: number;
11
+ /** Delay before hiding (in ms) */
12
+ hideDelay?: number;
13
+ /** Additional CSS classes */
14
+ className?: string;
15
+ };
16
+ export interface HoverCardProps extends HoverCardOwnProps, Omit<React.ComponentPropsWithoutRef<'span'>, keyof HoverCardOwnProps> {
17
+ }
18
+ /**
19
+ * Rich preview panel that opens from hover or focus — a profile card behind
20
+ * a username, a component summary behind a link. Where Tooltip names a
21
+ * control in a line of text, HoverCard previews a destination; its panel is
22
+ * interactive, stays open while the pointer is inside it, and dresses like
23
+ * the other floating panels (Popover, the menus).
24
+ *
25
+ * The hidden panel is `visibility: hidden`, so it stays out of the
26
+ * accessibility tree and tab order until shown. Escape dismisses it.
27
+ */
28
+ export declare const HoverCard: React.ForwardRefExoticComponent<HoverCardProps & React.RefAttributes<HTMLSpanElement>>;
29
+ export {};
@@ -0,0 +1,83 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import React, { useState, useRef, useId, useEffect } from "react";
4
+ import "./HoverCard.css";
5
+ import { MOTION_HOVER_SHOW_DELAY_MS, MOTION_HOVER_HIDE_DELAY_MS } from "../../tokens/motion.js";
6
+ const HoverCard = React.forwardRef(
7
+ ({
8
+ children,
9
+ content,
10
+ position = "bottom",
11
+ showDelay = MOTION_HOVER_SHOW_DELAY_MS,
12
+ hideDelay = MOTION_HOVER_HIDE_DELAY_MS,
13
+ className = "",
14
+ ...rest
15
+ }, ref) => {
16
+ const [visible, setVisible] = useState(false);
17
+ const showTimeoutRef = useRef(void 0);
18
+ const hideTimeoutRef = useRef(void 0);
19
+ const panelId = useId();
20
+ const baseClass = "ds-hover-card";
21
+ const show = () => {
22
+ clearTimeout(hideTimeoutRef.current);
23
+ showTimeoutRef.current = setTimeout(() => setVisible(true), showDelay);
24
+ };
25
+ const hide = () => {
26
+ clearTimeout(showTimeoutRef.current);
27
+ hideTimeoutRef.current = setTimeout(() => setVisible(false), hideDelay);
28
+ };
29
+ useEffect(() => {
30
+ return () => {
31
+ clearTimeout(showTimeoutRef.current);
32
+ clearTimeout(hideTimeoutRef.current);
33
+ };
34
+ }, []);
35
+ useEffect(() => {
36
+ if (!visible) return;
37
+ const onKeyDown = (e) => {
38
+ if (e.key === "Escape") {
39
+ clearTimeout(showTimeoutRef.current);
40
+ clearTimeout(hideTimeoutRef.current);
41
+ setVisible(false);
42
+ }
43
+ };
44
+ document.addEventListener("keydown", onKeyDown);
45
+ return () => document.removeEventListener("keydown", onKeyDown);
46
+ }, [visible]);
47
+ const handleBlur = (event) => {
48
+ if (!event.currentTarget.contains(event.relatedTarget)) {
49
+ hide();
50
+ }
51
+ };
52
+ const trigger = React.isValidElement(children) ? React.cloneElement(children, {
53
+ "aria-expanded": visible,
54
+ "aria-controls": visible ? panelId : void 0
55
+ }) : children;
56
+ const containerClasses = [baseClass, className].filter(Boolean).join(" ");
57
+ const panelClasses = [
58
+ `${baseClass}__panel`,
59
+ `${baseClass}__panel--${position}`,
60
+ visible ? `${baseClass}__panel--visible` : ""
61
+ ].filter(Boolean).join(" ");
62
+ return /* @__PURE__ */ jsxs(
63
+ "span",
64
+ {
65
+ ...rest,
66
+ ref,
67
+ className: containerClasses,
68
+ onMouseEnter: show,
69
+ onMouseLeave: hide,
70
+ onFocus: show,
71
+ onBlur: handleBlur,
72
+ children: [
73
+ trigger,
74
+ /* @__PURE__ */ jsx("span", { className: panelClasses, id: panelId, children: content })
75
+ ]
76
+ }
77
+ );
78
+ }
79
+ );
80
+ HoverCard.displayName = "HoverCard";
81
+ export {
82
+ HoverCard
83
+ };
@@ -0,0 +1,112 @@
1
+ /* ============================================
2
+ IMAGE COMPARE COMPONENT
3
+ Before-and-after images behind one divider
4
+ ============================================ */
5
+
6
+ .ds-image-compare {
7
+ position: relative;
8
+ width: 100%;
9
+ overflow: hidden;
10
+ border-radius: var(--radius-lg);
11
+ border: var(--border-xs) solid var(--color-bg-container-border);
12
+ background-color: var(--color-bg-container-secondary);
13
+ /* pan-y keeps the page scrollable over the frame on touch; horizontal
14
+ drags stay with the slider. */
15
+ touch-action: pan-y;
16
+ user-select: none;
17
+ cursor: col-resize;
18
+ }
19
+
20
+ /* ============================================
21
+ IMAGES
22
+ ============================================ */
23
+
24
+ .ds-image-compare__after,
25
+ .ds-image-compare__before {
26
+ position: absolute;
27
+ inset: 0;
28
+ width: 100%;
29
+ height: 100%;
30
+ object-fit: cover;
31
+ display: block;
32
+ }
33
+
34
+ /* The before layer sits on top at full frame size and is clipped to the
35
+ left of the divider. clip-path leaves the image's own geometry alone,
36
+ so the two layers stay pixel-aligned as the split moves. */
37
+ .ds-image-compare__before-clip {
38
+ position: absolute;
39
+ inset: 0;
40
+ clip-path: inset(0 calc(100% - var(--ds-image-compare-position, 50%)) 0 0);
41
+ }
42
+
43
+ /* ============================================
44
+ LABELS
45
+ ============================================ */
46
+
47
+ .ds-image-compare__label {
48
+ position: absolute;
49
+ top: var(--gap-md);
50
+ z-index: 2;
51
+ padding: var(--padding-xxxs) var(--padding-sm);
52
+ border-radius: var(--radius-full);
53
+ background-color: var(--color-bg-container-inverse);
54
+ color: var(--color-text-on-inverse);
55
+ font-family: var(--font-paragraph-sm-em-family);
56
+ font-size: var(--font-paragraph-sm-em-size);
57
+ font-weight: var(--font-paragraph-sm-em-weight);
58
+ line-height: var(--font-paragraph-sm-em-line-height);
59
+ pointer-events: none;
60
+ }
61
+
62
+ .ds-image-compare__label--before {
63
+ left: var(--gap-md);
64
+ }
65
+
66
+ .ds-image-compare__label--after {
67
+ right: var(--gap-md);
68
+ }
69
+
70
+ /* ============================================
71
+ DIVIDER + HANDLE
72
+ ============================================ */
73
+
74
+ .ds-image-compare__divider {
75
+ position: absolute;
76
+ top: 0;
77
+ bottom: 0;
78
+ left: var(--ds-image-compare-position);
79
+ width: var(--border-md);
80
+ transform: translateX(-50%);
81
+ background-color: var(--color-bg-page-primary);
82
+ z-index: 1;
83
+ pointer-events: none;
84
+ }
85
+
86
+ .ds-image-compare__handle {
87
+ position: absolute;
88
+ top: 50%;
89
+ left: var(--ds-image-compare-position);
90
+ transform: translate(-50%, -50%);
91
+ z-index: 3;
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ width: 32px;
96
+ height: 32px;
97
+ border-radius: var(--radius-full);
98
+ background-color: var(--color-bg-page-primary);
99
+ color: var(--color-icon-primary);
100
+ border: var(--border-xs) solid var(--color-bg-container-border);
101
+ box-shadow: var(--shadow-floating);
102
+ cursor: col-resize;
103
+ }
104
+
105
+ .ds-image-compare__handle .material-symbols-rounded {
106
+ --icon-size: var(--icon-size-sm);
107
+ }
108
+
109
+ .ds-image-compare__handle:focus-visible {
110
+ outline: 2px solid var(--color-action-primary-bg);
111
+ outline-offset: 2px;
112
+ }
@@ -0,0 +1,40 @@
1
+ import { default as React } from 'react';
2
+ /** Props owned by ImageCompare itself — everything else falls through to the root node. */
3
+ type ImageCompareOwnProps = {
4
+ /** Source of the image revealed on the left of the divider */
5
+ beforeSrc: string;
6
+ /** Source of the image revealed on the right of the divider */
7
+ afterSrc: string;
8
+ /** Alt text for the before image */
9
+ beforeAlt: string;
10
+ /** Alt text for the after image */
11
+ afterAlt: string;
12
+ /** Corner label over the before side */
13
+ beforeLabel?: string;
14
+ /** Corner label over the after side */
15
+ afterLabel?: string;
16
+ /** Whether the corner labels render */
17
+ showLabels?: boolean;
18
+ /** Divider position as a percentage from the left (controlled) */
19
+ position?: number;
20
+ /** Initial divider position for uncontrolled use */
21
+ defaultPosition?: number;
22
+ /** Convenience callback receiving the divider position on every change */
23
+ onPositionChange?: (position: number) => void;
24
+ /** CSS aspect-ratio of the frame (both images are sized to cover it) */
25
+ aspectRatio?: string;
26
+ /** Additional CSS classes */
27
+ className?: string;
28
+ };
29
+ export interface ImageCompareProps extends ImageCompareOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof ImageCompareOwnProps> {
30
+ }
31
+ /**
32
+ * Before-and-after comparison of two images sharing one frame. Dragging the
33
+ * divider (or clicking anywhere in the frame) sweeps the split; the handle is
34
+ * a `role="slider"` with arrow-key, Home/End and PageUp/PageDown control, so
35
+ * the comparison works without a pointer.
36
+ *
37
+ * Forwards a ref to the root element and spreads unrecognised props onto it.
38
+ */
39
+ export declare const ImageCompare: React.ForwardRefExoticComponent<ImageCompareProps & React.RefAttributes<HTMLDivElement>>;
40
+ export {};