rift-ds 1.1.0 → 1.3.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 +2 -2
- package/components/Chart/BarChart.js +1 -1
- package/components/Chart/ComboChart.js +1 -1
- package/components/Chart/Treemap.js +83 -6
- package/components/ColorPicker/ColorPicker.js +1 -1
- package/components/Composer/Composer.css +45 -3
- package/components/Composer/Composer.d.ts +14 -6
- package/components/Composer/Composer.js +25 -5
- package/components/DatePicker/DatePicker.css +1 -1
- package/components/EventCalendar/EventCalendar.css +2 -2
- package/components/FileInput/FileInput.css +1 -1
- package/components/Globe/Globe.d.ts +5 -3
- package/components/Globe/Globe.js +18 -2
- package/components/Inspector/Inspector.css +616 -0
- package/components/Inspector/InspectorColorPicker.d.ts +43 -0
- package/components/Inspector/InspectorColorPicker.js +51 -0
- package/components/Inspector/InspectorDropdown.d.ts +39 -0
- package/components/Inspector/InspectorDropdown.js +68 -0
- package/components/Inspector/InspectorInput.d.ts +32 -0
- package/components/Inspector/InspectorInput.js +52 -0
- package/components/Inspector/InspectorSection.d.ts +32 -0
- package/components/Inspector/InspectorSection.js +70 -0
- package/components/Inspector/InspectorSegmentedControl.d.ts +46 -0
- package/components/Inspector/InspectorSegmentedControl.js +62 -0
- package/components/Inspector/InspectorSlider.d.ts +41 -0
- package/components/Inspector/InspectorSlider.js +81 -0
- package/components/Inspector/InspectorToggleSwitch.d.ts +29 -0
- package/components/Inspector/InspectorToggleSwitch.js +51 -0
- package/components/Instructions/Instructions.css +4 -4
- package/components/Prose/Prose.css +27 -0
- package/components/SegmentedControl/SegmentedControl.css +7 -5
- package/components/Sparkline/Sparkline.css +2 -2
- package/components/Spinner/Spinner.css +1 -1
- package/components/Timeline/Timeline.css +1 -1
- package/components/WorldMap/land.d.ts +1 -1
- package/components/registry.json +69 -1
- package/components/registry.json.d.ts +69 -1
- package/components/registry.json.js +2 -2
- package/index.d.ts +7 -0
- package/index.js +14 -0
- package/package.json +1 -1
- package/tokens/motion.d.ts +2 -0
- package/tokens/motion.js +2 -0
- package/tokens/presets/contrast.css +2 -4
- package/tokens/presets/coral.css +2 -4
- package/tokens/presets/forest.css +2 -4
- package/tokens/presets/gold.css +4 -4
- package/tokens/presets/mono.css +0 -2
- package/tokens/presets/pink.css +4 -4
- package/tokens/presets/terminal.css +5 -4
- package/tokens/presets/violet.css +2 -4
- package/tokens/presets/warm.css +3 -4
- package/tokens/presets/zest.css +2 -4
- package/tokens/registry.json +1 -0
- package/tokens/registry.json.d.ts +1 -0
- package/tokens/registry.json.js +1 -1
- package/tokens/tokens-dark.css +8 -5
- package/tokens/tokens-light.css +4 -2
- package/tokens/tokens-motion.css +2 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { DropdownOption, DropdownOptionGroup } from '../Dropdown/Dropdown';
|
|
3
|
+
/** Props owned by InspectorDropdown itself — everything else falls through to the wrapper. */
|
|
4
|
+
type InspectorDropdownOwnProps = {
|
|
5
|
+
/** The setting's name, drawn inside the bar on the left. Also the dropdown's accessible name. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Currently selected value. */
|
|
8
|
+
value?: string;
|
|
9
|
+
/** Available options (flat list). Each option's `font` previews the face, as in Dropdown. */
|
|
10
|
+
options: DropdownOption[];
|
|
11
|
+
/** Optional grouped options. When provided, renders groups with labels and separators. */
|
|
12
|
+
groups?: DropdownOptionGroup[];
|
|
13
|
+
/** Shown on the right when nothing is selected. */
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
/** Whether the dropdown is disabled. */
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
/** Component size, matching Button: `default` is 40px tall, `compact` 32px. */
|
|
18
|
+
size?: 'default' | 'compact';
|
|
19
|
+
/** Called with the newly selected value. */
|
|
20
|
+
onValueChange?: (value: string) => void;
|
|
21
|
+
/** Additional CSS classes, applied to the wrapper. */
|
|
22
|
+
className?: string;
|
|
23
|
+
};
|
|
24
|
+
export interface InspectorDropdownProps extends InspectorDropdownOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof InspectorDropdownOwnProps | 'onChange'> {
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A one-row select for inspector panels: the name on the left, the chosen
|
|
28
|
+
* option and a chevron on the right. It is the library Dropdown with its
|
|
29
|
+
* trigger dressed as an inspector bar, so the menu, its keyboard model and
|
|
30
|
+
* its per-option font previews are Dropdown's own. The form counterpart,
|
|
31
|
+
* with a label above, is Dropdown itself.
|
|
32
|
+
*
|
|
33
|
+
* The name is an overlay the trigger reserves room for. It is measured,
|
|
34
|
+
* since names differ in width and a web font can change one after load,
|
|
35
|
+
* and it lets clicks through, so the whole bar opens the menu. Forwards a
|
|
36
|
+
* ref to the wrapper and spreads unrecognised props onto it.
|
|
37
|
+
*/
|
|
38
|
+
export declare const InspectorDropdown: React.ForwardRefExoticComponent<InspectorDropdownProps & React.RefAttributes<HTMLDivElement>>;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { useRef, useState, useLayoutEffect } from "react";
|
|
4
|
+
import { Dropdown } from "../Dropdown/Dropdown.js";
|
|
5
|
+
import "./Inspector.css";
|
|
6
|
+
const InspectorDropdown = React.forwardRef(
|
|
7
|
+
({
|
|
8
|
+
label,
|
|
9
|
+
value,
|
|
10
|
+
options,
|
|
11
|
+
groups,
|
|
12
|
+
placeholder,
|
|
13
|
+
disabled = false,
|
|
14
|
+
size = "default",
|
|
15
|
+
onValueChange,
|
|
16
|
+
className = "",
|
|
17
|
+
style,
|
|
18
|
+
...rest
|
|
19
|
+
}, ref) => {
|
|
20
|
+
const dropdownId = React.useId();
|
|
21
|
+
const labelRef = useRef(null);
|
|
22
|
+
const [labelWidth, setLabelWidth] = useState(0);
|
|
23
|
+
useLayoutEffect(() => {
|
|
24
|
+
const node = labelRef.current;
|
|
25
|
+
if (!node) return;
|
|
26
|
+
const measure = () => setLabelWidth(node.offsetWidth);
|
|
27
|
+
measure();
|
|
28
|
+
const observer = new ResizeObserver(measure);
|
|
29
|
+
observer.observe(node);
|
|
30
|
+
return () => observer.disconnect();
|
|
31
|
+
}, []);
|
|
32
|
+
const classes = [
|
|
33
|
+
"ds-inspector-dropdown",
|
|
34
|
+
size === "compact" ? "ds-inspector-dropdown--compact" : "",
|
|
35
|
+
className
|
|
36
|
+
].filter(Boolean).join(" ");
|
|
37
|
+
return /* @__PURE__ */ jsxs(
|
|
38
|
+
"div",
|
|
39
|
+
{
|
|
40
|
+
...rest,
|
|
41
|
+
ref,
|
|
42
|
+
className: classes,
|
|
43
|
+
style: { ...style, "--ds-inspector-label-width": `${labelWidth}px` },
|
|
44
|
+
children: [
|
|
45
|
+
/* @__PURE__ */ jsx("span", { ref: labelRef, className: "ds-inspector-dropdown__label", "aria-hidden": "true", children: label }),
|
|
46
|
+
/* @__PURE__ */ jsx(
|
|
47
|
+
Dropdown,
|
|
48
|
+
{
|
|
49
|
+
id: dropdownId,
|
|
50
|
+
"aria-label": label,
|
|
51
|
+
size,
|
|
52
|
+
value,
|
|
53
|
+
options,
|
|
54
|
+
groups,
|
|
55
|
+
placeholder,
|
|
56
|
+
disabled,
|
|
57
|
+
onValueChange
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
InspectorDropdown.displayName = "InspectorDropdown";
|
|
66
|
+
export {
|
|
67
|
+
InspectorDropdown
|
|
68
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by InspectorInput itself — everything else falls through to the <input>. */
|
|
3
|
+
type InspectorInputOwnProps = {
|
|
4
|
+
/** The setting's name, drawn inside the bar on the left, as the field's real <label>. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Current value. */
|
|
7
|
+
value?: string;
|
|
8
|
+
/** Input type: a curated subset of the single-line text types. */
|
|
9
|
+
type?: 'text' | 'email' | 'url' | 'search' | 'tel';
|
|
10
|
+
/** Component size, matching Button: `default` is 40px tall, `compact` 32px (not the native character-width `size` attribute). */
|
|
11
|
+
size?: 'default' | 'compact';
|
|
12
|
+
/**
|
|
13
|
+
* Convenience callback receiving the value directly.
|
|
14
|
+
* Fires alongside `onChange`, which keeps the standard React event signature
|
|
15
|
+
* so form libraries work unmodified.
|
|
16
|
+
*/
|
|
17
|
+
onValueChange?: (value: string) => void;
|
|
18
|
+
/** Additional CSS classes, applied to the bar rather than the <input>. */
|
|
19
|
+
className?: string;
|
|
20
|
+
};
|
|
21
|
+
export interface InspectorInputProps extends InspectorInputOwnProps, Omit<React.ComponentPropsWithoutRef<'input'>, keyof InspectorInputOwnProps> {
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A one-row text field for inspector panels: the name on the left, the
|
|
25
|
+
* typed value right-aligned in the rest of the bar. The form counterpart,
|
|
26
|
+
* with a label above and helper text below, is Input.
|
|
27
|
+
*
|
|
28
|
+
* Forwards a ref to the underlying <input> and spreads unrecognised props
|
|
29
|
+
* onto it, so `autoComplete`, `maxLength` and form registration all work.
|
|
30
|
+
*/
|
|
31
|
+
export declare const InspectorInput: React.ForwardRefExoticComponent<InspectorInputProps & React.RefAttributes<HTMLInputElement>>;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import "./Inspector.css";
|
|
5
|
+
const InspectorInput = React.forwardRef(
|
|
6
|
+
({
|
|
7
|
+
label,
|
|
8
|
+
value,
|
|
9
|
+
type = "text",
|
|
10
|
+
size = "default",
|
|
11
|
+
disabled = false,
|
|
12
|
+
onChange,
|
|
13
|
+
onValueChange,
|
|
14
|
+
className = "",
|
|
15
|
+
id,
|
|
16
|
+
...rest
|
|
17
|
+
}, ref) => {
|
|
18
|
+
const generatedId = React.useId();
|
|
19
|
+
const inputId = id ?? generatedId;
|
|
20
|
+
const classes = [
|
|
21
|
+
"ds-inspector-bar",
|
|
22
|
+
"ds-inspector-input",
|
|
23
|
+
size === "compact" ? "ds-inspector-bar--compact" : "",
|
|
24
|
+
disabled ? "ds-inspector-bar--disabled" : "",
|
|
25
|
+
className
|
|
26
|
+
].filter(Boolean).join(" ");
|
|
27
|
+
const handleChange = (e) => {
|
|
28
|
+
onChange?.(e);
|
|
29
|
+
onValueChange?.(e.target.value);
|
|
30
|
+
};
|
|
31
|
+
return /* @__PURE__ */ jsxs("div", { className: classes, children: [
|
|
32
|
+
/* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "ds-inspector-bar__label", children: label }),
|
|
33
|
+
/* @__PURE__ */ jsx(
|
|
34
|
+
"input",
|
|
35
|
+
{
|
|
36
|
+
...rest,
|
|
37
|
+
ref,
|
|
38
|
+
id: inputId,
|
|
39
|
+
className: "ds-inspector-input__field",
|
|
40
|
+
type,
|
|
41
|
+
value,
|
|
42
|
+
disabled,
|
|
43
|
+
onChange: handleChange
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
] });
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
InspectorInput.displayName = "InspectorInput";
|
|
50
|
+
export {
|
|
51
|
+
InspectorInput
|
|
52
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by InspectorSection itself — everything else falls through to the <section>. */
|
|
3
|
+
type InspectorSectionOwnProps = {
|
|
4
|
+
/** The section's heading, shown on its header row. Not the native tooltip `title` attribute. */
|
|
5
|
+
title: string;
|
|
6
|
+
/** Whether the section is expanded (controlled). Pair with `onOpenChange`. */
|
|
7
|
+
open?: boolean;
|
|
8
|
+
/** Whether an uncontrolled section starts expanded. */
|
|
9
|
+
defaultOpen?: boolean;
|
|
10
|
+
/** Called with the next expanded state when the header is pressed. */
|
|
11
|
+
onOpenChange?: (open: boolean) => void;
|
|
12
|
+
/** The section's controls, stacked one rhythm apart. */
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
/** Additional CSS classes, applied to the <section>. */
|
|
15
|
+
className?: string;
|
|
16
|
+
};
|
|
17
|
+
export interface InspectorSectionProps extends InspectorSectionOwnProps, Omit<React.ComponentPropsWithoutRef<'section'>, keyof InspectorSectionOwnProps> {
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A collapsible, titled run of inspector controls: the header row toggles
|
|
21
|
+
* it, and stacked sections are divided by a hairline. The general-purpose
|
|
22
|
+
* counterpart, a bordered set of content panels, is Accordion.
|
|
23
|
+
*
|
|
24
|
+
* Two behaviours separate it from Accordion. The body clips only while
|
|
25
|
+
* closed or animating, and goes `overflow: visible` once settled open, so
|
|
26
|
+
* a Dropdown menu inside can open past the section's edge. And a closed
|
|
27
|
+
* body is `inert`, so its controls leave the tab order rather than sitting
|
|
28
|
+
* focusable at zero height. Forwards a ref to the <section> and spreads
|
|
29
|
+
* unrecognised props onto it.
|
|
30
|
+
*/
|
|
31
|
+
export declare const InspectorSection: React.ForwardRefExoticComponent<InspectorSectionProps & React.RefAttributes<HTMLElement>>;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import "./Inspector.css";
|
|
5
|
+
import "../../fonts/material-symbols.css";
|
|
6
|
+
const InspectorSection = React.forwardRef(
|
|
7
|
+
({ title, open, defaultOpen = false, onOpenChange, children, className = "", ...rest }, ref) => {
|
|
8
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
9
|
+
const isOpen = open ?? uncontrolledOpen;
|
|
10
|
+
const [settled, setSettled] = useState(isOpen);
|
|
11
|
+
const baseId = React.useId();
|
|
12
|
+
const panelId = `${baseId}-panel`;
|
|
13
|
+
const headerId = `${baseId}-header`;
|
|
14
|
+
const toggle = () => {
|
|
15
|
+
const next = !isOpen;
|
|
16
|
+
setSettled(false);
|
|
17
|
+
if (open === void 0) setUncontrolledOpen(next);
|
|
18
|
+
onOpenChange?.(next);
|
|
19
|
+
};
|
|
20
|
+
const classes = [
|
|
21
|
+
"ds-inspector-section",
|
|
22
|
+
isOpen ? "ds-inspector-section--open" : "",
|
|
23
|
+
isOpen && settled ? "ds-inspector-section--settled" : "",
|
|
24
|
+
className
|
|
25
|
+
].filter(Boolean).join(" ");
|
|
26
|
+
return /* @__PURE__ */ jsxs("section", { ...rest, ref, className: classes, children: [
|
|
27
|
+
/* @__PURE__ */ jsxs(
|
|
28
|
+
"button",
|
|
29
|
+
{
|
|
30
|
+
type: "button",
|
|
31
|
+
id: headerId,
|
|
32
|
+
className: "ds-inspector-section__trigger",
|
|
33
|
+
"aria-expanded": isOpen,
|
|
34
|
+
"aria-controls": panelId,
|
|
35
|
+
onClick: toggle,
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ jsx("span", { children: title }),
|
|
38
|
+
/* @__PURE__ */ jsx(
|
|
39
|
+
"span",
|
|
40
|
+
{
|
|
41
|
+
className: "ds-inspector-section__icon material-symbols-rounded",
|
|
42
|
+
"aria-hidden": "true",
|
|
43
|
+
children: "expand_more"
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
),
|
|
49
|
+
/* @__PURE__ */ jsx(
|
|
50
|
+
"div",
|
|
51
|
+
{
|
|
52
|
+
id: panelId,
|
|
53
|
+
role: "region",
|
|
54
|
+
"aria-labelledby": headerId,
|
|
55
|
+
className: "ds-inspector-section__panel",
|
|
56
|
+
inert: !isOpen,
|
|
57
|
+
onTransitionEnd: (event) => {
|
|
58
|
+
if (event.target !== event.currentTarget) return;
|
|
59
|
+
if (isOpen) setSettled(true);
|
|
60
|
+
},
|
|
61
|
+
children: /* @__PURE__ */ jsx("div", { className: "ds-inspector-section__body", children })
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
] });
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
InspectorSection.displayName = "InspectorSection";
|
|
68
|
+
export {
|
|
69
|
+
InspectorSection
|
|
70
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** One choice in an InspectorSegmentedControl. */
|
|
3
|
+
export interface InspectorSegment {
|
|
4
|
+
/** The value reported when this segment is chosen. */
|
|
5
|
+
value: string;
|
|
6
|
+
/** Visible text. */
|
|
7
|
+
label: string;
|
|
8
|
+
/** Takes this one choice out of the set. */
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** Props owned by InspectorSegmentedControl itself — everything else falls through to the radiogroup. */
|
|
12
|
+
type InspectorSegmentedControlOwnProps = {
|
|
13
|
+
/** The setting's name, drawn inside the bar on the left. Names the radiogroup. */
|
|
14
|
+
label: string;
|
|
15
|
+
/** The choices, drawn left to right in the bar's end. */
|
|
16
|
+
options: InspectorSegment[];
|
|
17
|
+
/** The selected value (controlled). Leave unset and use `defaultValue` for an uncontrolled set. */
|
|
18
|
+
value?: string;
|
|
19
|
+
/** The starting selection for an uncontrolled set. */
|
|
20
|
+
defaultValue?: string;
|
|
21
|
+
/** The radios' shared `name`, for native form submission. Generated when unset. */
|
|
22
|
+
name?: string;
|
|
23
|
+
/** Takes the whole set out of use. */
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
/** Component size, matching Button: `default` is 40px tall, `compact` 32px. */
|
|
26
|
+
size?: 'default' | 'compact';
|
|
27
|
+
/** Called with the newly chosen value. */
|
|
28
|
+
onValueChange?: (value: string) => void;
|
|
29
|
+
/** Additional CSS classes, applied to the bar. */
|
|
30
|
+
className?: string;
|
|
31
|
+
};
|
|
32
|
+
export interface InspectorSegmentedControlProps extends InspectorSegmentedControlOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof InspectorSegmentedControlOwnProps> {
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A one-row choice of a few options for inspector panels: the name on the
|
|
36
|
+
* left, the options as chips on the right. The selected chip takes a
|
|
37
|
+
* neutral fill, never the action colour. The form-and-toolbar counterpart,
|
|
38
|
+
* a free-standing pill strip, is SegmentedControl.
|
|
39
|
+
*
|
|
40
|
+
* Each option is a native radio, so arrow keys move the selection, the set
|
|
41
|
+
* announces as one radiogroup, and it submits with a form. A native
|
|
42
|
+
* `onChange` on the root receives each radio's bubbled change event.
|
|
43
|
+
* Forwards a ref to the root and spreads unrecognised props onto it.
|
|
44
|
+
*/
|
|
45
|
+
export declare const InspectorSegmentedControl: React.ForwardRefExoticComponent<InspectorSegmentedControlProps & React.RefAttributes<HTMLDivElement>>;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import "./Inspector.css";
|
|
5
|
+
const InspectorSegmentedControl = React.forwardRef(
|
|
6
|
+
({
|
|
7
|
+
label,
|
|
8
|
+
options,
|
|
9
|
+
value,
|
|
10
|
+
defaultValue,
|
|
11
|
+
name,
|
|
12
|
+
disabled = false,
|
|
13
|
+
size = "default",
|
|
14
|
+
onValueChange,
|
|
15
|
+
className = "",
|
|
16
|
+
...rest
|
|
17
|
+
}, ref) => {
|
|
18
|
+
const generatedId = React.useId();
|
|
19
|
+
const groupName = name ?? generatedId;
|
|
20
|
+
const labelId = `${generatedId}-label`;
|
|
21
|
+
const classes = [
|
|
22
|
+
"ds-inspector-bar",
|
|
23
|
+
"ds-inspector-segmented-control",
|
|
24
|
+
size === "compact" ? "ds-inspector-bar--compact" : "",
|
|
25
|
+
disabled ? "ds-inspector-bar--disabled" : "",
|
|
26
|
+
className
|
|
27
|
+
].filter(Boolean).join(" ");
|
|
28
|
+
return /* @__PURE__ */ jsxs(
|
|
29
|
+
"div",
|
|
30
|
+
{
|
|
31
|
+
"aria-labelledby": labelId,
|
|
32
|
+
...rest,
|
|
33
|
+
ref,
|
|
34
|
+
className: classes,
|
|
35
|
+
role: "radiogroup",
|
|
36
|
+
"aria-disabled": disabled || void 0,
|
|
37
|
+
children: [
|
|
38
|
+
/* @__PURE__ */ jsx("span", { id: labelId, className: "ds-inspector-bar__label", children: label }),
|
|
39
|
+
/* @__PURE__ */ jsx("span", { className: "ds-inspector-segmented-control__segments", children: options.map((option) => /* @__PURE__ */ jsxs("label", { className: "ds-inspector-segmented-control__segment", children: [
|
|
40
|
+
/* @__PURE__ */ jsx(
|
|
41
|
+
"input",
|
|
42
|
+
{
|
|
43
|
+
className: "ds-inspector-segmented-control__radio",
|
|
44
|
+
type: "radio",
|
|
45
|
+
name: groupName,
|
|
46
|
+
value: option.value,
|
|
47
|
+
disabled: disabled || option.disabled,
|
|
48
|
+
...value !== void 0 ? { checked: option.value === value } : { defaultChecked: option.value === defaultValue },
|
|
49
|
+
onChange: () => onValueChange?.(option.value)
|
|
50
|
+
}
|
|
51
|
+
),
|
|
52
|
+
option.label
|
|
53
|
+
] }, option.value)) })
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
InspectorSegmentedControl.displayName = "InspectorSegmentedControl";
|
|
60
|
+
export {
|
|
61
|
+
InspectorSegmentedControl
|
|
62
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by InspectorSlider itself — everything else falls through to the <input type="range">. */
|
|
3
|
+
type InspectorSliderOwnProps = {
|
|
4
|
+
/** The setting's name, drawn inside the bar on the left. Also the range's accessible name. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Current value (controlled). Leave unset and use `defaultValue` for an uncontrolled slider. */
|
|
7
|
+
value?: number;
|
|
8
|
+
/** Starting value for an uncontrolled slider. Defaults to `min`. */
|
|
9
|
+
defaultValue?: number;
|
|
10
|
+
/** Minimum value. */
|
|
11
|
+
min?: number;
|
|
12
|
+
/** Maximum value. */
|
|
13
|
+
max?: number;
|
|
14
|
+
/** Step increment. Also sets how many decimals the reading shows (0.02 reads "0.50"). */
|
|
15
|
+
step?: number;
|
|
16
|
+
/** Formats the reading on the right, and the value a screen reader announces. Defaults to the step's precision. */
|
|
17
|
+
format?: (value: number) => string;
|
|
18
|
+
/** Component size, matching Button: `default` is 40px tall, `compact` 32px (not the native character-width `size` attribute). */
|
|
19
|
+
size?: 'default' | 'compact';
|
|
20
|
+
/**
|
|
21
|
+
* Convenience callback receiving the numeric value directly.
|
|
22
|
+
* Fires alongside `onChange`, which keeps the standard React event signature.
|
|
23
|
+
*/
|
|
24
|
+
onValueChange?: (value: number) => void;
|
|
25
|
+
/** Additional CSS classes, applied to the bar rather than the <input>. */
|
|
26
|
+
className?: string;
|
|
27
|
+
};
|
|
28
|
+
export interface InspectorSliderProps extends InspectorSliderOwnProps, Omit<React.ComponentPropsWithoutRef<'input'>, keyof InspectorSliderOwnProps | 'type'> {
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A one-row slider for inspector panels: the whole bar is the control, its
|
|
32
|
+
* fill is the value, and the name and reading sit inside it. The form
|
|
33
|
+
* counterpart, with a label above and a track, is Slider.
|
|
34
|
+
*
|
|
35
|
+
* A native range input covers the bar invisibly, so dragging anywhere,
|
|
36
|
+
* clicking to jump, the keyboard and the screen-reader semantics are the
|
|
37
|
+
* platform's. Forwards a ref to that input and spreads unrecognised props
|
|
38
|
+
* onto it.
|
|
39
|
+
*/
|
|
40
|
+
export declare const InspectorSlider: React.ForwardRefExoticComponent<InspectorSliderProps & React.RefAttributes<HTMLInputElement>>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { useState } from "react";
|
|
4
|
+
import "./Inspector.css";
|
|
5
|
+
const decimalsOf = (step) => {
|
|
6
|
+
const text = String(step);
|
|
7
|
+
const dot = text.indexOf(".");
|
|
8
|
+
return dot < 0 ? 0 : text.length - dot - 1;
|
|
9
|
+
};
|
|
10
|
+
const InspectorSlider = React.forwardRef(
|
|
11
|
+
({
|
|
12
|
+
label,
|
|
13
|
+
value,
|
|
14
|
+
defaultValue,
|
|
15
|
+
min = 0,
|
|
16
|
+
max = 100,
|
|
17
|
+
step = 1,
|
|
18
|
+
format,
|
|
19
|
+
size = "default",
|
|
20
|
+
disabled = false,
|
|
21
|
+
onChange,
|
|
22
|
+
onValueChange,
|
|
23
|
+
className = "",
|
|
24
|
+
id,
|
|
25
|
+
...rest
|
|
26
|
+
}, ref) => {
|
|
27
|
+
const generatedId = React.useId();
|
|
28
|
+
const inputId = id ?? generatedId;
|
|
29
|
+
const [uncontrolled, setUncontrolled] = useState(defaultValue ?? min);
|
|
30
|
+
const current = value ?? uncontrolled;
|
|
31
|
+
const pct = max === min ? 0 : (current - min) / (max - min) * 100;
|
|
32
|
+
const reading = format ? format(current) : current.toFixed(decimalsOf(step));
|
|
33
|
+
const classes = [
|
|
34
|
+
"ds-inspector-bar",
|
|
35
|
+
"ds-inspector-slider",
|
|
36
|
+
size === "compact" ? "ds-inspector-bar--compact" : "",
|
|
37
|
+
disabled ? "ds-inspector-bar--disabled" : "",
|
|
38
|
+
className
|
|
39
|
+
].filter(Boolean).join(" ");
|
|
40
|
+
const handleChange = (e) => {
|
|
41
|
+
const next = Number(e.target.value);
|
|
42
|
+
if (value === void 0) setUncontrolled(next);
|
|
43
|
+
onChange?.(e);
|
|
44
|
+
onValueChange?.(next);
|
|
45
|
+
};
|
|
46
|
+
return /* @__PURE__ */ jsxs(
|
|
47
|
+
"div",
|
|
48
|
+
{
|
|
49
|
+
className: classes,
|
|
50
|
+
style: { "--ds-inspector-pct": `${pct}%` },
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ jsx("span", { className: "ds-inspector-slider__fill", "aria-hidden": "true" }),
|
|
53
|
+
/* @__PURE__ */ jsx("span", { className: "ds-inspector-slider__grip", "aria-hidden": "true" }),
|
|
54
|
+
/* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "ds-inspector-bar__label", children: label }),
|
|
55
|
+
/* @__PURE__ */ jsx("span", { className: "ds-inspector-bar__value", "aria-hidden": "true", children: reading }),
|
|
56
|
+
/* @__PURE__ */ jsx(
|
|
57
|
+
"input",
|
|
58
|
+
{
|
|
59
|
+
"aria-valuetext": reading,
|
|
60
|
+
...rest,
|
|
61
|
+
ref,
|
|
62
|
+
id: inputId,
|
|
63
|
+
className: "ds-inspector-bar__native",
|
|
64
|
+
type: "range",
|
|
65
|
+
min,
|
|
66
|
+
max,
|
|
67
|
+
step,
|
|
68
|
+
value: current,
|
|
69
|
+
disabled,
|
|
70
|
+
onChange: handleChange
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
InspectorSlider.displayName = "InspectorSlider";
|
|
79
|
+
export {
|
|
80
|
+
InspectorSlider
|
|
81
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by InspectorToggleSwitch itself — everything else falls through to the <input type="checkbox">. */
|
|
3
|
+
type InspectorToggleSwitchOwnProps = {
|
|
4
|
+
/** The setting's name, drawn inside the bar on the left. Also the switch's accessible name. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Component size, matching Button: `default` is 40px tall, `compact` 32px (not the native character-width `size` attribute). */
|
|
7
|
+
size?: 'default' | 'compact';
|
|
8
|
+
/**
|
|
9
|
+
* Convenience callback receiving the checked state directly.
|
|
10
|
+
* Fires alongside `onChange`, which keeps the standard React event signature.
|
|
11
|
+
*/
|
|
12
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
13
|
+
/** Additional CSS classes, applied to the bar rather than the <input>. */
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
export interface InspectorToggleSwitchProps extends InspectorToggleSwitchOwnProps, Omit<React.ComponentPropsWithoutRef<'input'>, keyof InspectorToggleSwitchOwnProps | 'type'> {
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A one-row switch for inspector panels: the whole bar is the switch, with
|
|
20
|
+
* the name on the left and a small track on the right. The form
|
|
21
|
+
* counterpart, a standalone switch with its label beside it, is
|
|
22
|
+
* ToggleSwitch.
|
|
23
|
+
*
|
|
24
|
+
* A native checkbox with `role="switch"` covers the bar, and the paint
|
|
25
|
+
* reads its `:checked` state, so `checked` and `defaultChecked` both work.
|
|
26
|
+
* Forwards a ref to that input and spreads unrecognised props onto it.
|
|
27
|
+
*/
|
|
28
|
+
export declare const InspectorToggleSwitch: React.ForwardRefExoticComponent<InspectorToggleSwitchProps & React.RefAttributes<HTMLInputElement>>;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import "./Inspector.css";
|
|
5
|
+
const InspectorToggleSwitch = React.forwardRef(
|
|
6
|
+
({
|
|
7
|
+
label,
|
|
8
|
+
size = "default",
|
|
9
|
+
disabled = false,
|
|
10
|
+
onChange,
|
|
11
|
+
onCheckedChange,
|
|
12
|
+
className = "",
|
|
13
|
+
id,
|
|
14
|
+
...rest
|
|
15
|
+
}, ref) => {
|
|
16
|
+
const generatedId = React.useId();
|
|
17
|
+
const inputId = id ?? generatedId;
|
|
18
|
+
const classes = [
|
|
19
|
+
"ds-inspector-bar",
|
|
20
|
+
"ds-inspector-toggle-switch",
|
|
21
|
+
size === "compact" ? "ds-inspector-bar--compact" : "",
|
|
22
|
+
disabled ? "ds-inspector-bar--disabled" : "",
|
|
23
|
+
className
|
|
24
|
+
].filter(Boolean).join(" ");
|
|
25
|
+
const handleChange = (e) => {
|
|
26
|
+
onChange?.(e);
|
|
27
|
+
onCheckedChange?.(e.target.checked);
|
|
28
|
+
};
|
|
29
|
+
return /* @__PURE__ */ jsxs("div", { className: classes, children: [
|
|
30
|
+
/* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "ds-inspector-bar__label", children: label }),
|
|
31
|
+
/* @__PURE__ */ jsx("span", { className: "ds-inspector-toggle-switch__track", "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { className: "ds-inspector-toggle-switch__knob" }) }),
|
|
32
|
+
/* @__PURE__ */ jsx(
|
|
33
|
+
"input",
|
|
34
|
+
{
|
|
35
|
+
...rest,
|
|
36
|
+
ref,
|
|
37
|
+
id: inputId,
|
|
38
|
+
className: "ds-inspector-bar__native",
|
|
39
|
+
type: "checkbox",
|
|
40
|
+
role: "switch",
|
|
41
|
+
disabled,
|
|
42
|
+
onChange: handleChange
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
] });
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
InspectorToggleSwitch.displayName = "InspectorToggleSwitch";
|
|
49
|
+
export {
|
|
50
|
+
InspectorToggleSwitch
|
|
51
|
+
};
|
|
@@ -64,14 +64,14 @@
|
|
|
64
64
|
width: 32px;
|
|
65
65
|
height: 32px;
|
|
66
66
|
border-radius: var(--radius-pill);
|
|
67
|
-
border: var(--border-025) solid var(--color-
|
|
67
|
+
border: var(--border-025) solid var(--color-bg-container-border);
|
|
68
68
|
background-color: transparent;
|
|
69
69
|
flex-shrink: 0;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
.ds-instructions__badge .material-symbols-rounded {
|
|
73
73
|
--icon-size: var(--icon-size-600);
|
|
74
|
-
color: var(--color-
|
|
74
|
+
color: var(--color-icon-primary);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
.ds-instructions__number {
|
|
@@ -79,14 +79,14 @@
|
|
|
79
79
|
font-size: var(--font-paragraph-sm-size);
|
|
80
80
|
font-weight: var(--font-title-body-weight);
|
|
81
81
|
line-height: 1;
|
|
82
|
-
color: var(--color-
|
|
82
|
+
color: var(--color-text-secondary);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
.ds-instructions__dot {
|
|
86
86
|
width: 8px;
|
|
87
87
|
height: 8px;
|
|
88
88
|
border-radius: var(--radius-pill);
|
|
89
|
-
background-color: var(--color-
|
|
89
|
+
background-color: var(--color-icon-primary);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
.ds-instructions__connector {
|