@robr0/design-system 0.7.0 → 0.9.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/README.md +4 -4
- package/components/Accordion/Accordion.js +1 -0
- package/components/AgentPlan/AgentPlan.css +231 -0
- package/components/AgentPlan/AgentPlan.d.ts +41 -0
- package/components/AgentPlan/AgentPlan.js +100 -0
- package/components/AgentStatus/AgentStatus.js +1 -0
- package/components/AiButton/AiButton.js +1 -0
- package/components/AlertDialog/AlertDialog.js +1 -0
- package/components/AnchorNav/AnchorNav.css +63 -0
- package/components/AnchorNav/AnchorNav.d.ts +33 -0
- package/components/AnchorNav/AnchorNav.js +82 -0
- package/components/AppLayout/AppLayout.js +1 -0
- package/components/AppSidebar/AppSidebar.js +1 -0
- package/components/Avatar/Avatar.js +1 -0
- package/components/Button/Button.js +1 -0
- package/components/Card/Card.js +1 -0
- package/components/Carousel/Carousel.js +1 -0
- package/components/ChatThread/ChatThread.js +1 -0
- package/components/Checkbox/Checkbox.js +1 -0
- package/components/CodeBlock/CodeBlock.js +1 -0
- package/components/CodeDiff/CodeDiff.css +175 -0
- package/components/CodeDiff/CodeDiff.d.ts +58 -0
- package/components/CodeDiff/CodeDiff.js +114 -0
- package/components/ColorPicker/ColorPicker.js +1 -0
- package/components/Combobox/Combobox.js +1 -0
- package/components/CommandPalette/CommandPalette.js +1 -0
- package/components/Composer/Composer.js +1 -0
- package/components/ContactCard/ContactCard.js +1 -0
- package/components/ContextMenu/ContextMenu.js +1 -0
- package/components/DataTable/DataTable.css +105 -0
- package/components/DataTable/DataTable.d.ts +81 -0
- package/components/DataTable/DataTable.js +236 -0
- package/components/DateInput/DateInput.js +1 -0
- package/components/DatePicker/DatePicker.js +1 -0
- package/components/Dialog/Dialog.js +1 -0
- package/components/Drawer/Drawer.js +1 -0
- package/components/Dropdown/Dropdown.js +1 -0
- package/components/DropdownMenu/DropdownMenu.css +1 -1
- package/components/DropdownMenu/DropdownMenu.js +1 -0
- package/components/EventCalendar/EventCalendar.css +328 -0
- package/components/EventCalendar/EventCalendar.d.ts +51 -0
- package/components/EventCalendar/EventCalendar.js +214 -0
- package/components/Field/Field.js +1 -0
- package/components/Field/FieldContext.js +1 -0
- package/components/FileInput/FileInput.js +1 -0
- package/components/Input/Input.js +1 -0
- package/components/InterruptCard/InterruptCard.css +11 -21
- package/components/InterruptCard/InterruptCard.d.ts +5 -6
- package/components/MessageCard/MessageCard.css +1 -2
- package/components/ModelPicker/ModelPicker.css +240 -0
- package/components/ModelPicker/ModelPicker.d.ts +60 -0
- package/components/ModelPicker/ModelPicker.js +218 -0
- package/components/NavList/NavList.js +1 -0
- package/components/NotificationCenter/NotificationCenter.css +262 -0
- package/components/NotificationCenter/NotificationCenter.d.ts +72 -0
- package/components/NotificationCenter/NotificationCenter.js +129 -0
- package/components/NumberInput/NumberInput.css +154 -0
- package/components/NumberInput/NumberInput.d.ts +44 -0
- package/components/NumberInput/NumberInput.js +147 -0
- package/components/Pagination/Pagination.js +1 -0
- package/components/PinInput/PinInput.css +92 -0
- package/components/PinInput/PinInput.d.ts +46 -0
- package/components/PinInput/PinInput.js +161 -0
- package/components/Popover/Popover.css +5 -6
- package/components/Popover/Popover.js +1 -0
- package/components/RadioButton/RadioButton.js +1 -0
- package/components/Reasoning/Reasoning.js +1 -0
- package/components/SegmentedControl/SegmentedControl.js +1 -0
- package/components/SelectionCard/SelectionCard.js +1 -0
- package/components/ShaderField/ShaderField.js +1 -0
- package/components/ShaderField/field.glsl.d.ts +11 -5
- package/components/ShaderField/field.glsl.js +4 -3
- package/components/ShaderField/useShaderField.d.ts +19 -2
- package/components/ShaderField/useShaderField.js +18 -3
- package/components/Slider/Slider.js +1 -0
- package/components/Sparkline/Sparkline.css +52 -0
- package/components/Sparkline/Sparkline.d.ts +49 -0
- package/components/Sparkline/Sparkline.js +86 -0
- package/components/Stepper/Stepper.css +207 -0
- package/components/Stepper/Stepper.d.ts +41 -0
- package/components/Stepper/Stepper.js +61 -0
- package/components/Tabs/Tabs.js +1 -0
- package/components/TagInput/TagInput.css +160 -0
- package/components/TagInput/TagInput.d.ts +43 -0
- package/components/TagInput/TagInput.js +137 -0
- package/components/Textarea/Textarea.js +1 -0
- package/components/TimePicker/TimePicker.css +230 -0
- package/components/TimePicker/TimePicker.d.ts +46 -0
- package/components/TimePicker/TimePicker.js +246 -0
- package/components/Timeline/Timeline.css +17 -0
- package/components/Timeline/Timeline.d.ts +2 -0
- package/components/Timeline/Timeline.js +1 -0
- package/components/Toast/Toast.js +1 -0
- package/components/ToggleGroup/ToggleGroup.js +1 -0
- package/components/ToggleSwitch/ToggleSwitch.js +1 -0
- package/components/ToolCall/ToolCall.css +7 -11
- package/components/ToolCall/ToolCall.js +1 -0
- package/components/Tooltip/Tooltip.js +1 -0
- package/components/TreeView/TreeView.css +119 -0
- package/components/TreeView/TreeView.d.ts +45 -0
- package/components/TreeView/TreeView.js +232 -0
- package/components/registry.d.ts +22 -6
- package/components/registry.js +3 -1
- package/components/registry.json +246 -20
- package/components/registry.json.d.ts +246 -20
- package/components/registry.json.js +2 -2
- package/index.d.ts +16 -2
- package/index.js +32 -1
- package/package.json +1 -1
|
@@ -13,10 +13,16 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Coordinate space is chosen to match a CSS blob layer exactly, so a fallback
|
|
15
15
|
* built from absolutely-positioned discs lines up with it: origin at the
|
|
16
|
-
* container centre (`left`/`top: 50%`), one unit =
|
|
17
|
-
* vw-sized, and CSS percentage margins — top included —
|
|
18
|
-
* containing block's width). Centres are therefore
|
|
19
|
-
* re-uploading on resize.
|
|
16
|
+
* container centre (`left`/`top: 50%`), one unit = the field's reference
|
|
17
|
+
* width (discs are vw-sized, and CSS percentage margins — top included —
|
|
18
|
+
* resolve against the containing block's width). Centres are therefore
|
|
19
|
+
* constants that never need re-uploading on resize.
|
|
20
|
+
*
|
|
21
|
+
* That reference width is the container's own width until `crop` holds it
|
|
22
|
+
* back on a narrow viewport, where the field keeps more of the scale it was
|
|
23
|
+
* composed at and the viewport crops into it instead. The hook resolves it to
|
|
24
|
+
* `u_unit`, in drawing-buffer pixels, so the shader itself never has to know
|
|
25
|
+
* which of the two it is looking at.
|
|
20
26
|
*
|
|
21
27
|
* Colours arrive already converted to linear RGB (the hook does the sRGB
|
|
22
28
|
* decode once per theme change); the shader only encodes back at the end.
|
|
@@ -30,4 +36,4 @@
|
|
|
30
36
|
*/
|
|
31
37
|
export declare const BLOB_COUNT = 8;
|
|
32
38
|
export declare const vertexSource = "#version 300 es\n// Fullscreen triangle \u2014 no buffers, three vertices from gl_VertexID.\nvoid main() {\n vec2 p = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2);\n gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);\n}\n";
|
|
33
|
-
export declare const fragmentSource = "#version 300 es\nprecision highp float;\n\nuniform vec2 u_resolution; // drawing-buffer size in pixels\nuniform float u_time; // field time, seconds (speed applied JS-side)\nuniform vec3 u_color[8]; // linear RGB per blob\nuniform vec4 u_blob[8]; // xy = centre, z = sigma, w = emission weight\nuniform vec4 u_motion[8]; // xy = angular speeds, zw = phases\nuniform float u_intensity; // peak-alpha ceiling\nuniform float u_warp; // domain-warp strength\nuniform float u_scale; // noise frequency\nuniform float u_grain; // film-grain strength\nuniform float u_streak; // anisotropic stretch: 0 = blobs, 1 = light streams\nuniform vec2 u_mouse; // pointer in field coordinates (smoothed JS-side)\nuniform float u_mvel; // smoothed pointer speed, width units/s\nuniform float u_react; // cursor-reactivity strength\n\nout vec4 outColor;\n\n// Integer hash \u2014 WebGL2 has real uint ops, so no fract(sin()) precision\n// lottery on mobile GPUs.\nuint ihash(uvec2 p) {\n p = p * uvec2(73333u, 7777u) ^ (p.yx >> 3u);\n uint h = p.x ^ (p.y * 2654435761u);\n h ^= h >> 15u;\n h *= 2246822519u;\n h ^= h >> 13u;\n return h;\n}\n\nfloat rnd(ivec2 p) {\n return float(ihash(uvec2(p)) >> 8) * (1.0 / 16777216.0);\n}\n\nfloat vnoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n ivec2 c = ivec2(i);\n return mix(\n mix(rnd(c), rnd(c + ivec2(1, 0)), u.x),\n mix(rnd(c + ivec2(0, 1)), rnd(c + ivec2(1, 1)), u.x),\n u.y\n );\n}\n\n// 3 octaves; a 4th is invisible at this softness.\nfloat fbm(vec2 p) {\n float s = 0.0;\n float a = 0.5;\n for (int i = 0; i < 3; i++) {\n s += a * vnoise(p);\n p = p * 2.02 + vec2(17.0, 9.0);\n a *= 0.5;\n }\n return s;\n}\n\nvoid main() {\n // CSS coordinate space: origin at container centre, one unit =
|
|
39
|
+
export declare const fragmentSource = "#version 300 es\nprecision highp float;\n\nuniform vec2 u_resolution; // drawing-buffer size in pixels\nuniform float u_unit; // pixels per field unit (see coordinate space)\nuniform float u_time; // field time, seconds (speed applied JS-side)\nuniform vec3 u_color[8]; // linear RGB per blob\nuniform vec4 u_blob[8]; // xy = centre, z = sigma, w = emission weight\nuniform vec4 u_motion[8]; // xy = angular speeds, zw = phases\nuniform float u_intensity; // peak-alpha ceiling\nuniform float u_warp; // domain-warp strength\nuniform float u_scale; // noise frequency\nuniform float u_grain; // film-grain strength\nuniform float u_streak; // anisotropic stretch: 0 = blobs, 1 = light streams\nuniform vec2 u_mouse; // pointer in field coordinates (smoothed JS-side)\nuniform float u_mvel; // smoothed pointer speed, width units/s\nuniform float u_react; // cursor-reactivity strength\n\nout vec4 outColor;\n\n// Integer hash \u2014 WebGL2 has real uint ops, so no fract(sin()) precision\n// lottery on mobile GPUs.\nuint ihash(uvec2 p) {\n p = p * uvec2(73333u, 7777u) ^ (p.yx >> 3u);\n uint h = p.x ^ (p.y * 2654435761u);\n h ^= h >> 15u;\n h *= 2246822519u;\n h ^= h >> 13u;\n return h;\n}\n\nfloat rnd(ivec2 p) {\n return float(ihash(uvec2(p)) >> 8) * (1.0 / 16777216.0);\n}\n\nfloat vnoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n ivec2 c = ivec2(i);\n return mix(\n mix(rnd(c), rnd(c + ivec2(1, 0)), u.x),\n mix(rnd(c + ivec2(0, 1)), rnd(c + ivec2(1, 1)), u.x),\n u.y\n );\n}\n\n// 3 octaves; a 4th is invisible at this softness.\nfloat fbm(vec2 p) {\n float s = 0.0;\n float a = 0.5;\n for (int i = 0; i < 3; i++) {\n s += a * vnoise(p);\n p = p * 2.02 + vec2(17.0, 9.0);\n a *= 0.5;\n }\n return s;\n}\n\nvoid main() {\n // CSS coordinate space: origin at container centre, one unit = the\n // reference width the hook resolved, y running downward.\n vec2 p = (gl_FragCoord.xy - 0.5 * u_resolution) / u_unit;\n p.y = -p.y;\n\n // Light-stream axis: a fixed diagonal. Distances across the axis are\n // magnified before the Gaussian, so every source stretches along it and\n // the field reads as rays instead of discs.\n float ca = cos(0.5);\n float sa = sin(0.5);\n mat2 toStreak = mat2(ca, -sa, sa, ca);\n float squeeze = 1.0 + u_streak * 4.0;\n\n // Domain warp: the field flows rather than drifts. The noise is sampled\n // in the same anisotropic space, so the flow lines follow the streams.\n float t = u_time;\n vec2 ps = toStreak * p;\n ps.y *= squeeze;\n vec2 q = vec2(\n fbm(ps * u_scale + vec2(0.0, t * 0.030)),\n fbm(ps * u_scale + vec2(5.2, 1.3) - t * 0.024)\n );\n vec2 w = p + u_warp * (q - 0.5);\n\n // Cursor wake: a smooth vortex around the pointer, amplified by speed.\n // The displacement is built from the *unnormalised* offset so it falls to\n // zero at the cursor itself. Normalising here (md/mr) made the direction\n // spin through 360 degrees at full strength across the centre pixel, which\n // rendered as a pinch \u2014 a cone converging to a point.\n vec2 md = p - u_mouse;\n float mr2 = dot(md, md);\n float minf = exp(-mr2 / (2.0 * 0.22 * 0.22));\n vec2 swirl = vec2(-md.y, md.x);\n // smoothstep, not min(): a hard clamp stepped visibly as speed crossed it.\n float stir = 0.25 + 1.3 * smoothstep(0.0, 0.8, u_mvel);\n w += u_react * minf * stir * (swirl * 0.9 + md * 0.35);\n\n // Accumulate true Gaussians in linear space. Positive weights emit;\n // negative weights absorb (shadows \u2014 the eclipse disc).\n vec3 acc = vec3(0.0);\n float cov = 0.0;\n float shade = 0.0;\n for (int i = 0; i < 8; i++) {\n vec2 c = u_blob[i].xy + 0.045 * vec2(\n cos(u_motion[i].x * t + u_motion[i].z),\n sin(u_motion[i].y * t + u_motion[i].w)\n );\n vec2 d = toStreak * (w - c);\n d.y *= squeeze;\n float s = u_blob[i].z;\n float g = exp(-dot(d, d) / (2.0 * s * s));\n float wgt = u_blob[i].w;\n if (wgt >= 0.0) {\n acc += u_color[i] * (g * wgt);\n cov += g * wgt;\n } else {\n shade += g * -wgt;\n }\n }\n\n // Glow trail: wider and softer than the swirl, and mostly velocity-driven,\n // so a resting cursor does not park a bright dot on the field.\n //\n // The wake brightens whatever colour it is passing over rather than adding\n // one of its own. Injecting u_color[0] meant the trail always wore the\n // first blob's token \u2014 gold in the site palette, violet in beam \u2014 which\n // read as a stray colour with no relationship to the field beneath it.\n // Weighting by the local hue keeps the wake colour-neutral: it reads as\n // light falling on the field, and it stays correct for any palette.\n vec3 local = acc / max(cov, 1e-4);\n float gfall = exp(-mr2 / (2.0 * 0.3 * 0.3));\n float glow = u_react * gfall * (0.12 + 0.5 * smoothstep(0.0, 0.8, u_mvel));\n acc += local * glow;\n cov += glow;\n\n vec3 lin = acc / max(cov, 1e-4);\n float lit = max(cov - shade, 0.0);\n float alpha = u_intensity * (1.0 - exp(-lit * 0.9));\n\n vec3 srgb = pow(max(lin, vec3(0.0)), vec3(1.0 / 2.2));\n\n // Film grain: animated hash noise. At u_grain 0 this degenerates to the\n // \u00B11/255 dither that kills banding, so the two share one lookup.\n uvec2 gp = uvec2(gl_FragCoord.xy) + uvec2(\n uint(fract(t * 7.31) * 1024.0) * 7919u,\n uint(fract(t * 3.17) * 1024.0) * 104729u\n );\n float gr = float(ihash(gp) & 255u) / 255.0 - 0.5;\n srgb += gr * (1.0 / 255.0 + u_grain * 0.35);\n // A small grain-driven alpha floor lets the sparkle read even where the\n // field itself is empty (the reference's grainy dark scene).\n float grainFloor = u_grain * 0.1 * (gr + 0.5);\n alpha = clamp(alpha * (1.0 + gr * u_grain * 0.5) + grainFloor, 0.0, 1.0);\n srgb = clamp(srgb, 0.0, 1.0);\n\n // Premultiplied output (context is created with premultipliedAlpha: true).\n outColor = vec4(srgb * alpha, alpha);\n}\n";
|
|
@@ -15,6 +15,7 @@ const fragmentSource = (
|
|
|
15
15
|
precision highp float;
|
|
16
16
|
|
|
17
17
|
uniform vec2 u_resolution; // drawing-buffer size in pixels
|
|
18
|
+
uniform float u_unit; // pixels per field unit (see coordinate space)
|
|
18
19
|
uniform float u_time; // field time, seconds (speed applied JS-side)
|
|
19
20
|
uniform vec3 u_color[${BLOB_COUNT}]; // linear RGB per blob
|
|
20
21
|
uniform vec4 u_blob[${BLOB_COUNT}]; // xy = centre, z = sigma, w = emission weight
|
|
@@ -70,9 +71,9 @@ float fbm(vec2 p) {
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
void main() {
|
|
73
|
-
// CSS coordinate space: origin at container centre, one unit =
|
|
74
|
-
// y running downward.
|
|
75
|
-
vec2 p = (gl_FragCoord.xy - 0.5 * u_resolution) /
|
|
74
|
+
// CSS coordinate space: origin at container centre, one unit = the
|
|
75
|
+
// reference width the hook resolved, y running downward.
|
|
76
|
+
vec2 p = (gl_FragCoord.xy - 0.5 * u_resolution) / u_unit;
|
|
76
77
|
p.y = -p.y;
|
|
77
78
|
|
|
78
79
|
// Light-stream axis: a fixed diagonal. Distances across the axis are
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RefObject } from 'react';
|
|
2
|
-
/** The
|
|
2
|
+
/** The eight tuneable properties of the field. */
|
|
3
3
|
export interface ShaderParams {
|
|
4
4
|
/** Overall opacity of the field, 0.1–1. */
|
|
5
5
|
intensity: number;
|
|
@@ -19,6 +19,23 @@ export interface ShaderParams {
|
|
|
19
19
|
* with them the loop's step up from 30fps to 60fps while a wake is alive.
|
|
20
20
|
*/
|
|
21
21
|
react: number;
|
|
22
|
+
/**
|
|
23
|
+
* How much the composition resists shrinking with the container, 0–1.
|
|
24
|
+
*
|
|
25
|
+
* At 0 — the default, and the behaviour a CSS blob layer has — the whole
|
|
26
|
+
* field is fitted to whatever width it is given, so a phone shows the
|
|
27
|
+
* entire composition at phone scale: every source small, and more of them
|
|
28
|
+
* crowded into view than the look was built for. At 1 the field holds the
|
|
29
|
+
* scale it was composed at (`REFERENCE_WIDTH`) and a narrower container
|
|
30
|
+
* crops into it instead. Values between blend the two geometrically,
|
|
31
|
+
* keeping some of the shrink so colours still bleed together on a small
|
|
32
|
+
* screen. Above the reference width it does nothing.
|
|
33
|
+
*
|
|
34
|
+
* Raise it for a full-viewport background, which is read on a phone as a
|
|
35
|
+
* scene rather than a diagram; leave it at 0 wherever the point is to see
|
|
36
|
+
* the whole composition, such as a small demo tile.
|
|
37
|
+
*/
|
|
38
|
+
crop: number;
|
|
22
39
|
}
|
|
23
40
|
/**
|
|
24
41
|
* One light source in the field.
|
|
@@ -52,7 +69,7 @@ export interface ShaderBlob {
|
|
|
52
69
|
weight: number;
|
|
53
70
|
}
|
|
54
71
|
/**
|
|
55
|
-
* The shipped look:
|
|
72
|
+
* The shipped look: eight parameters tuned by eye, cursor wake off. Spread it
|
|
56
73
|
* and override the one or two you want rather than restating the set.
|
|
57
74
|
*/
|
|
58
75
|
export declare const DEFAULT_SHADER_PARAMS: ShaderParams;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { useState, useRef, useEffect } from "react";
|
|
2
3
|
import { BLOB_COUNT, vertexSource, fragmentSource } from "./field.glsl.js";
|
|
3
4
|
const DEFAULT_SHADER_PARAMS = {
|
|
@@ -7,7 +8,8 @@ const DEFAULT_SHADER_PARAMS = {
|
|
|
7
8
|
speed: 2,
|
|
8
9
|
grain: 0.1,
|
|
9
10
|
streak: 0.4,
|
|
10
|
-
react: 0
|
|
11
|
+
react: 0,
|
|
12
|
+
crop: 0.5
|
|
11
13
|
};
|
|
12
14
|
const DEFAULT_SHADER_BLOBS = [
|
|
13
15
|
{ token: "--color-core-accent-gold", size: 0.45, cx: 0.175, cy: 0.125, period: 18, phase: 0, weight: 1 },
|
|
@@ -20,6 +22,11 @@ const DEFAULT_SHADER_BLOBS = [
|
|
|
20
22
|
{ token: "--color-core-ui-secondary", size: 0.75, cx: -0.125, cy: -0.025, period: 20, phase: 0.7, weight: 1 }
|
|
21
23
|
];
|
|
22
24
|
const RENDER_SCALE = 0.5;
|
|
25
|
+
const REFERENCE_WIDTH = 1440;
|
|
26
|
+
function fieldUnit(cssWidth, crop) {
|
|
27
|
+
if (cssWidth <= 0) return 1;
|
|
28
|
+
return cssWidth * Math.pow(Math.max(REFERENCE_WIDTH / cssWidth, 1), crop);
|
|
29
|
+
}
|
|
23
30
|
const FRAME_MS = 1e3 / 30;
|
|
24
31
|
const FRAME_MS_ACTIVE = 1e3 / 60;
|
|
25
32
|
const WAKE_IDLE = 0.015;
|
|
@@ -113,6 +120,7 @@ function useShaderField(canvasRef, params, enabled = true) {
|
|
|
113
120
|
loc = {};
|
|
114
121
|
for (const name of [
|
|
115
122
|
"u_resolution",
|
|
123
|
+
"u_unit",
|
|
116
124
|
"u_time",
|
|
117
125
|
"u_color[0]",
|
|
118
126
|
"u_blob[0]",
|
|
@@ -176,10 +184,12 @@ function useShaderField(canvasRef, params, enabled = true) {
|
|
|
176
184
|
colorTarget.set(colorCurrent);
|
|
177
185
|
let bufWidth = 0;
|
|
178
186
|
let bufHeight = 0;
|
|
187
|
+
let cssWidth = 0;
|
|
179
188
|
function resize() {
|
|
180
189
|
if (!gl) return;
|
|
181
190
|
const c = canvas;
|
|
182
191
|
const dpr = window.devicePixelRatio || 1;
|
|
192
|
+
cssWidth = c.clientWidth;
|
|
183
193
|
const w = Math.max(1, Math.round(c.clientWidth * dpr * RENDER_SCALE));
|
|
184
194
|
const h = Math.max(1, Math.round(c.clientHeight * dpr * RENDER_SCALE));
|
|
185
195
|
if (w === bufWidth && h === bufHeight) return;
|
|
@@ -200,8 +210,9 @@ function useShaderField(canvasRef, params, enabled = true) {
|
|
|
200
210
|
const c = canvas;
|
|
201
211
|
const rect = c.getBoundingClientRect();
|
|
202
212
|
if (rect.width === 0) return;
|
|
203
|
-
const
|
|
204
|
-
const
|
|
213
|
+
const unit = fieldUnit(rect.width, paramsRef.current.crop);
|
|
214
|
+
const x = (e.clientX - rect.left - rect.width / 2) / unit;
|
|
215
|
+
const y = (e.clientY - rect.top - rect.height / 2) / unit;
|
|
205
216
|
if (mouseTarget.x < 5) {
|
|
206
217
|
moveAccum += Math.hypot(x - mouseTarget.x, y - mouseTarget.y);
|
|
207
218
|
}
|
|
@@ -234,6 +245,10 @@ function useShaderField(canvasRef, params, enabled = true) {
|
|
|
234
245
|
}
|
|
235
246
|
const p = paramsRef.current;
|
|
236
247
|
gl.uniform3fv(loc["u_color[0]"], colorCurrent);
|
|
248
|
+
gl.uniform1f(
|
|
249
|
+
loc["u_unit"],
|
|
250
|
+
bufWidth * (fieldUnit(cssWidth, p.crop) / Math.max(cssWidth, 1))
|
|
251
|
+
);
|
|
237
252
|
gl.uniform1f(loc["u_time"], fieldTime);
|
|
238
253
|
gl.uniform1f(loc["u_intensity"], p.intensity);
|
|
239
254
|
gl.uniform1f(loc["u_warp"], p.warp);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
SPARKLINE COMPONENT
|
|
3
|
+
Inline trend line for stats and table cells.
|
|
4
|
+
Colour flows through `color` — the line, fill
|
|
5
|
+
and dot all draw with currentColor, so a tone
|
|
6
|
+
is one custom property swap.
|
|
7
|
+
============================================ */
|
|
8
|
+
|
|
9
|
+
/* Base */
|
|
10
|
+
|
|
11
|
+
.ds-sparkline {
|
|
12
|
+
display: inline-block;
|
|
13
|
+
vertical-align: middle;
|
|
14
|
+
flex-shrink: 0;
|
|
15
|
+
color: var(--color-action-primary-bg);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Parts */
|
|
19
|
+
|
|
20
|
+
.ds-sparkline__line {
|
|
21
|
+
fill: none;
|
|
22
|
+
stroke: currentColor;
|
|
23
|
+
stroke-linecap: round;
|
|
24
|
+
stroke-linejoin: round;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.ds-sparkline__fill {
|
|
28
|
+
fill: currentColor;
|
|
29
|
+
opacity: 0.15;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.ds-sparkline__dot {
|
|
33
|
+
fill: currentColor;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Tones */
|
|
37
|
+
|
|
38
|
+
.ds-sparkline--accent {
|
|
39
|
+
color: var(--color-action-primary-bg);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.ds-sparkline--positive {
|
|
43
|
+
color: var(--color-status-positive-text);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.ds-sparkline--negative {
|
|
47
|
+
color: var(--color-status-error-text);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.ds-sparkline--neutral {
|
|
51
|
+
color: var(--color-text-secondary);
|
|
52
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by Sparkline itself — everything else falls through to the SVG node. */
|
|
3
|
+
type SparklineOwnProps = {
|
|
4
|
+
/** The series to plot, in order. Values are normalised into the viewBox. */
|
|
5
|
+
data: number[];
|
|
6
|
+
/** Rendering treatment — a bare line, or a line with a soft fill underneath. */
|
|
7
|
+
variant?: 'line' | 'area';
|
|
8
|
+
/**
|
|
9
|
+
* Colour role for the line and end dot. `accent` follows the chart palette's
|
|
10
|
+
* lead colour; `positive`/`negative` map to the status text tokens; `neutral`
|
|
11
|
+
* recedes to secondary text.
|
|
12
|
+
*/
|
|
13
|
+
tone?: 'accent' | 'positive' | 'negative' | 'neutral';
|
|
14
|
+
/** Marks the final point with a small dot. */
|
|
15
|
+
showDot?: boolean;
|
|
16
|
+
/** Line thickness in viewBox units — an SVG geometry attribute, not a token. */
|
|
17
|
+
strokeWidth?: number;
|
|
18
|
+
/**
|
|
19
|
+
* ViewBox width. Also the default rendered width; the SVG scales to its
|
|
20
|
+
* container when sized externally via CSS. Intentionally shadows the native
|
|
21
|
+
* SVG `width` attribute, which it sets.
|
|
22
|
+
*/
|
|
23
|
+
width?: number;
|
|
24
|
+
/**
|
|
25
|
+
* ViewBox height. Also the default rendered height; the SVG scales to its
|
|
26
|
+
* container when sized externally via CSS. Intentionally shadows the native
|
|
27
|
+
* SVG `height` attribute, which it sets.
|
|
28
|
+
*/
|
|
29
|
+
height?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Accessible description of the trend, e.g. "Revenue, trending up". When
|
|
32
|
+
* omitted the SVG is decorative and hidden from assistive technology.
|
|
33
|
+
*/
|
|
34
|
+
label?: string;
|
|
35
|
+
/** Additional CSS classes */
|
|
36
|
+
className?: string;
|
|
37
|
+
};
|
|
38
|
+
export interface SparklineProps extends SparklineOwnProps, Omit<React.ComponentPropsWithoutRef<'svg'>, keyof SparklineOwnProps | 'children'> {
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Sparkline — an inline trend line for stats and table cells, drawn without
|
|
42
|
+
* axes or chrome. Pure SVG computed from props: no charting library, no hooks,
|
|
43
|
+
* no dependencies, so it renders from a Server Component and costs nothing in
|
|
44
|
+
* a dense table. Degenerate data never breaks the path: an all-equal series
|
|
45
|
+
* renders a horizontal midline, and fewer than two points render just the
|
|
46
|
+
* end dot, or nothing.
|
|
47
|
+
*/
|
|
48
|
+
export declare const Sparkline: React.ForwardRefExoticComponent<SparklineProps & React.RefAttributes<SVGSVGElement>>;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import "./Sparkline.css";
|
|
4
|
+
const round = (n) => Math.round(n * 100) / 100;
|
|
5
|
+
const Sparkline = React.forwardRef(
|
|
6
|
+
({
|
|
7
|
+
data,
|
|
8
|
+
variant = "line",
|
|
9
|
+
tone = "accent",
|
|
10
|
+
showDot = true,
|
|
11
|
+
strokeWidth = 2,
|
|
12
|
+
width = 120,
|
|
13
|
+
height = 32,
|
|
14
|
+
label,
|
|
15
|
+
className = "",
|
|
16
|
+
...rest
|
|
17
|
+
}, ref) => {
|
|
18
|
+
const baseClass = "ds-sparkline";
|
|
19
|
+
const classes = [
|
|
20
|
+
baseClass,
|
|
21
|
+
`${baseClass}--${variant}`,
|
|
22
|
+
`${baseClass}--${tone}`,
|
|
23
|
+
className
|
|
24
|
+
].filter(Boolean).join(" ");
|
|
25
|
+
const dotRadius = strokeWidth * 1.5;
|
|
26
|
+
const pad = dotRadius + strokeWidth / 2;
|
|
27
|
+
const innerWidth = Math.max(width - pad * 2, 0);
|
|
28
|
+
const innerHeight = Math.max(height - pad * 2, 0);
|
|
29
|
+
const min = Math.min(...data);
|
|
30
|
+
const max = Math.max(...data);
|
|
31
|
+
const range = max - min;
|
|
32
|
+
const points = data.map((value, i) => ({
|
|
33
|
+
x: round(
|
|
34
|
+
data.length < 2 ? pad + innerWidth : pad + i / (data.length - 1) * innerWidth
|
|
35
|
+
),
|
|
36
|
+
// A flat series (range 0) draws a horizontal midline instead of dividing by zero.
|
|
37
|
+
y: round(
|
|
38
|
+
range === 0 ? pad + innerHeight / 2 : pad + (1 - (value - min) / range) * innerHeight
|
|
39
|
+
)
|
|
40
|
+
}));
|
|
41
|
+
const lastPoint = points.length > 0 ? points[points.length - 1] : void 0;
|
|
42
|
+
const hasLine = points.length >= 2;
|
|
43
|
+
const linePath = hasLine ? `M ${points.map((p) => `${p.x} ${p.y}`).join(" L ")}` : void 0;
|
|
44
|
+
const baseline = round(height - pad);
|
|
45
|
+
const areaPath = hasLine && variant === "area" ? `${linePath} L ${points[points.length - 1].x} ${baseline} L ${points[0].x} ${baseline} Z` : void 0;
|
|
46
|
+
return /* @__PURE__ */ jsxs(
|
|
47
|
+
"svg",
|
|
48
|
+
{
|
|
49
|
+
...rest,
|
|
50
|
+
ref,
|
|
51
|
+
className: classes,
|
|
52
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
53
|
+
width,
|
|
54
|
+
height,
|
|
55
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
56
|
+
role: label ? "img" : void 0,
|
|
57
|
+
"aria-label": label,
|
|
58
|
+
"aria-hidden": label ? void 0 : true,
|
|
59
|
+
children: [
|
|
60
|
+
areaPath && /* @__PURE__ */ jsx("path", { className: `${baseClass}__fill`, d: areaPath }),
|
|
61
|
+
linePath && /* @__PURE__ */ jsx(
|
|
62
|
+
"path",
|
|
63
|
+
{
|
|
64
|
+
className: `${baseClass}__line`,
|
|
65
|
+
d: linePath,
|
|
66
|
+
strokeWidth
|
|
67
|
+
}
|
|
68
|
+
),
|
|
69
|
+
showDot && lastPoint && /* @__PURE__ */ jsx(
|
|
70
|
+
"circle",
|
|
71
|
+
{
|
|
72
|
+
className: `${baseClass}__dot`,
|
|
73
|
+
cx: lastPoint.x,
|
|
74
|
+
cy: lastPoint.y,
|
|
75
|
+
r: dotRadius
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
Sparkline.displayName = "Sparkline";
|
|
84
|
+
export {
|
|
85
|
+
Sparkline
|
|
86
|
+
};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
STEPPER COMPONENT
|
|
3
|
+
Step-by-step progress indicator for wizards
|
|
4
|
+
and multi-stage flows
|
|
5
|
+
============================================ */
|
|
6
|
+
|
|
7
|
+
/* Base */
|
|
8
|
+
|
|
9
|
+
.ds-stepper {
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: flex-start;
|
|
12
|
+
list-style: none;
|
|
13
|
+
margin: 0;
|
|
14
|
+
padding: 0;
|
|
15
|
+
width: 100%;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.ds-stepper__step {
|
|
19
|
+
position: relative;
|
|
20
|
+
flex: 1 1 0;
|
|
21
|
+
min-width: 0;
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Shared inner layout — a <button> when the step is clickable,
|
|
27
|
+
a <span> otherwise */
|
|
28
|
+
.ds-stepper__content {
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
align-items: center;
|
|
32
|
+
gap: var(--gap-sm); /* 8px */
|
|
33
|
+
padding: 0;
|
|
34
|
+
border: none;
|
|
35
|
+
background-color: transparent;
|
|
36
|
+
font-family: inherit;
|
|
37
|
+
text-align: center;
|
|
38
|
+
color: inherit;
|
|
39
|
+
min-width: 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
button.ds-stepper__content {
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
button.ds-stepper__content:focus-visible {
|
|
47
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
48
|
+
outline-offset: 2px;
|
|
49
|
+
border-radius: var(--radius-sm);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* ============================================
|
|
53
|
+
INDICATOR
|
|
54
|
+
32px circle — check for complete, number
|
|
55
|
+
for active and upcoming
|
|
56
|
+
============================================ */
|
|
57
|
+
|
|
58
|
+
.ds-stepper__indicator {
|
|
59
|
+
--icon-size: var(--icon-size-sm);
|
|
60
|
+
display: inline-flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
width: 32px;
|
|
64
|
+
height: 32px;
|
|
65
|
+
flex-shrink: 0;
|
|
66
|
+
border: var(--border-xs) solid transparent;
|
|
67
|
+
border-radius: var(--radius-full);
|
|
68
|
+
font-family: var(--font-paragraph-sm-em-family);
|
|
69
|
+
font-size: var(--font-paragraph-sm-em-size);
|
|
70
|
+
font-weight: var(--font-paragraph-sm-em-weight);
|
|
71
|
+
line-height: var(--font-paragraph-sm-em-line-height);
|
|
72
|
+
letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
|
|
73
|
+
transition:
|
|
74
|
+
background-color var(--motion-duration-base) var(--motion-ease-standard),
|
|
75
|
+
border-color var(--motion-duration-base) var(--motion-ease-standard),
|
|
76
|
+
color var(--motion-duration-base) var(--motion-ease-standard);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* States */
|
|
80
|
+
|
|
81
|
+
.ds-stepper__step--complete .ds-stepper__indicator {
|
|
82
|
+
border-color: var(--color-action-primary-border-secondary);
|
|
83
|
+
color: var(--color-action-primary-text-tertiary);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.ds-stepper__step--active .ds-stepper__indicator {
|
|
87
|
+
background-color: var(--color-action-primary-bg);
|
|
88
|
+
border-color: var(--color-action-primary-bg);
|
|
89
|
+
color: var(--color-action-primary-text);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.ds-stepper__step--upcoming .ds-stepper__indicator {
|
|
93
|
+
border-color: var(--color-bg-container-border);
|
|
94
|
+
color: var(--color-text-tertiary);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
button.ds-stepper__content:hover .ds-stepper__indicator {
|
|
98
|
+
background-color: var(--color-action-passive-bg-hover);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.ds-stepper__step--active button.ds-stepper__content:hover .ds-stepper__indicator {
|
|
102
|
+
background-color: var(--color-action-primary-bg-hover);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* ============================================
|
|
106
|
+
LABEL + DESCRIPTION
|
|
107
|
+
============================================ */
|
|
108
|
+
|
|
109
|
+
.ds-stepper__text {
|
|
110
|
+
display: flex;
|
|
111
|
+
flex-direction: column;
|
|
112
|
+
gap: var(--gap-xxs); /* 2px */
|
|
113
|
+
min-width: 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.ds-stepper__label {
|
|
117
|
+
font-family: var(--font-paragraph-sm-em-family);
|
|
118
|
+
font-size: var(--font-paragraph-sm-em-size);
|
|
119
|
+
font-weight: var(--font-paragraph-sm-em-weight);
|
|
120
|
+
line-height: var(--font-paragraph-sm-em-line-height);
|
|
121
|
+
letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
|
|
122
|
+
color: var(--color-text-secondary);
|
|
123
|
+
transition: color var(--motion-duration-base) var(--motion-ease-standard);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.ds-stepper__step--active .ds-stepper__label {
|
|
127
|
+
color: var(--color-text-primary);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.ds-stepper__step--upcoming .ds-stepper__label {
|
|
131
|
+
color: var(--color-text-tertiary);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
button.ds-stepper__content:hover .ds-stepper__label {
|
|
135
|
+
color: var(--color-text-primary);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.ds-stepper__description {
|
|
139
|
+
font-family: var(--font-paragraph-sm-family);
|
|
140
|
+
font-size: var(--font-paragraph-sm-size);
|
|
141
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
142
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
143
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
144
|
+
color: var(--color-text-tertiary);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* ============================================
|
|
148
|
+
CONNECTOR
|
|
149
|
+
Drawn between an indicator and the next;
|
|
150
|
+
turns action-coloured behind completed steps
|
|
151
|
+
============================================ */
|
|
152
|
+
|
|
153
|
+
.ds-stepper__connector {
|
|
154
|
+
position: absolute;
|
|
155
|
+
top: 16px; /* vertical centre of the 32px indicator */
|
|
156
|
+
left: calc(50% + 24px);
|
|
157
|
+
right: calc(-50% + 24px);
|
|
158
|
+
height: var(--border-md);
|
|
159
|
+
transform: translateY(-50%);
|
|
160
|
+
background-color: var(--color-divider);
|
|
161
|
+
transition: background-color var(--motion-duration-base) var(--motion-ease-standard);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.ds-stepper__step--complete .ds-stepper__connector {
|
|
165
|
+
background-color: var(--color-action-primary-border-secondary);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* ============================================
|
|
169
|
+
VERTICAL
|
|
170
|
+
============================================ */
|
|
171
|
+
|
|
172
|
+
.ds-stepper--vertical {
|
|
173
|
+
flex-direction: column;
|
|
174
|
+
align-items: stretch;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.ds-stepper--vertical .ds-stepper__step {
|
|
178
|
+
flex: none;
|
|
179
|
+
justify-content: flex-start;
|
|
180
|
+
padding-bottom: var(--gap-lg); /* 20px */
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.ds-stepper--vertical .ds-stepper__step:last-child {
|
|
184
|
+
padding-bottom: 0;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.ds-stepper--vertical .ds-stepper__content {
|
|
188
|
+
flex-direction: row;
|
|
189
|
+
align-items: flex-start;
|
|
190
|
+
gap: var(--gap-sm-md); /* 12px */
|
|
191
|
+
text-align: left;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* Centre the first label line on the 32px indicator */
|
|
195
|
+
.ds-stepper--vertical .ds-stepper__text {
|
|
196
|
+
padding-top: calc((32px - var(--font-paragraph-sm-em-line-height)) / 2);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.ds-stepper--vertical .ds-stepper__connector {
|
|
200
|
+
top: calc(32px + var(--gap-xs));
|
|
201
|
+
bottom: var(--gap-xs);
|
|
202
|
+
left: 16px; /* horizontal centre of the 32px indicator */
|
|
203
|
+
right: auto;
|
|
204
|
+
width: var(--border-md);
|
|
205
|
+
height: auto;
|
|
206
|
+
transform: translateX(-50%);
|
|
207
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** A single step in a Stepper flow. */
|
|
3
|
+
export type StepperStep = {
|
|
4
|
+
/** Step label shown beside or below the indicator */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Optional supporting line rendered under the label */
|
|
7
|
+
description?: string;
|
|
8
|
+
};
|
|
9
|
+
/** Props owned by Stepper itself — everything else falls through to the `<ol>`. */
|
|
10
|
+
type StepperOwnProps = {
|
|
11
|
+
/** Ordered list of steps in the flow */
|
|
12
|
+
steps: StepperStep[];
|
|
13
|
+
/**
|
|
14
|
+
* Index of the active step. Steps before it render as complete (check
|
|
15
|
+
* icon), steps after it as upcoming (step number). Pass `steps.length`
|
|
16
|
+
* to mark the whole flow complete.
|
|
17
|
+
*/
|
|
18
|
+
activeStep: number;
|
|
19
|
+
/**
|
|
20
|
+
* Callback with the clicked step's index. When provided, completed steps
|
|
21
|
+
* and the active step become buttons so the reader can revisit an earlier
|
|
22
|
+
* stage; upcoming steps stay non-interactive either way.
|
|
23
|
+
*/
|
|
24
|
+
onStepClick?: (index: number) => void;
|
|
25
|
+
/** Layout direction */
|
|
26
|
+
orientation?: 'horizontal' | 'vertical';
|
|
27
|
+
/** Additional CSS classes */
|
|
28
|
+
className?: string;
|
|
29
|
+
};
|
|
30
|
+
export interface StepperProps extends StepperOwnProps, Omit<React.ComponentPropsWithoutRef<'ol'>, keyof StepperOwnProps> {
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Stepper component — step-by-step progress indicator for wizards and
|
|
34
|
+
* multi-stage flows. Renders an ordered list of steps with CSS-drawn
|
|
35
|
+
* connectors: completed steps show a check, the active step carries
|
|
36
|
+
* `aria-current="step"`, and upcoming steps show their number.
|
|
37
|
+
*
|
|
38
|
+
* Forwards a ref to the `<ol>` and spreads unrecognised props onto it.
|
|
39
|
+
*/
|
|
40
|
+
export declare const Stepper: React.ForwardRefExoticComponent<StepperProps & React.RefAttributes<HTMLOListElement>>;
|
|
41
|
+
export {};
|