@yarcl/react 0.1.0 → 0.2.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 +14 -2
- package/{src/apply.ts → dist/apply.d.ts} +4 -23
- package/dist/apply.js +37 -0
- package/dist/classes.d.ts +13 -0
- package/dist/classes.js +22 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +58 -0
- package/dist/color.js +49 -32
- package/dist/components/Accordion.d.ts +96 -0
- package/dist/components/Accordion.js +148 -0
- package/dist/components/Alert.d.ts +60 -0
- package/dist/components/Alert.js +61 -0
- package/dist/components/Avatar.d.ts +100 -0
- package/dist/components/Avatar.js +89 -0
- package/dist/components/Badge.d.ts +44 -0
- package/dist/components/Badge.js +43 -0
- package/dist/components/Breadcrumb.d.ts +77 -0
- package/dist/components/Breadcrumb.js +126 -0
- package/dist/components/Button.d.ts +18 -0
- package/dist/components/Button.js +33 -0
- package/dist/components/ButtonGroup.d.ts +29 -0
- package/dist/components/ButtonGroup.js +37 -0
- package/dist/components/Card.d.ts +36 -0
- package/dist/components/Card.js +26 -0
- package/dist/components/Checkbox.d.ts +28 -0
- package/dist/components/Checkbox.js +38 -0
- package/dist/components/Combobox.d.ts +75 -0
- package/dist/components/Combobox.js +362 -0
- package/dist/components/CommandPalette.d.ts +92 -0
- package/dist/components/CommandPalette.js +293 -0
- package/dist/components/DatePicker.d.ts +157 -0
- package/dist/components/DatePicker.js +230 -0
- package/dist/components/Dialog.d.ts +25 -0
- package/dist/components/Dialog.js +29 -0
- package/dist/components/Divider.d.ts +23 -0
- package/dist/components/Divider.js +25 -0
- package/dist/components/Drawer.d.ts +21 -0
- package/dist/components/Drawer.js +25 -0
- package/dist/components/EmptyState.d.ts +51 -0
- package/dist/components/EmptyState.js +47 -0
- package/dist/components/Field.d.ts +27 -0
- package/dist/components/Field.js +59 -0
- package/dist/components/Heading.d.ts +26 -0
- package/dist/components/Heading.js +25 -0
- package/dist/components/HoverCard.d.ts +47 -0
- package/dist/components/HoverCard.js +53 -0
- package/dist/components/IconButton.d.ts +19 -0
- package/dist/components/IconButton.js +32 -0
- package/dist/components/Inline.d.ts +21 -0
- package/dist/components/Inline.js +24 -0
- package/dist/components/Input.d.ts +19 -0
- package/dist/components/Input.js +25 -0
- package/dist/components/Label.d.ts +46 -0
- package/dist/components/Label.js +33 -0
- package/dist/components/Link.d.ts +27 -0
- package/dist/components/Link.js +26 -0
- package/dist/components/Menu.d.ts +73 -0
- package/dist/components/Menu.js +143 -0
- package/dist/components/Modal.d.ts +45 -0
- package/dist/components/Modal.js +110 -0
- package/dist/components/NumberInput.d.ts +49 -0
- package/dist/components/NumberInput.js +130 -0
- package/dist/components/Pagination.d.ts +86 -0
- package/dist/components/Pagination.js +119 -0
- package/dist/components/Popover.d.ts +72 -0
- package/dist/components/Popover.js +87 -0
- package/dist/components/Progress.d.ts +60 -0
- package/dist/components/Progress.js +59 -0
- package/dist/components/Radio.d.ts +32 -0
- package/dist/components/Radio.js +47 -0
- package/dist/components/RadioGroup.d.ts +57 -0
- package/dist/components/RadioGroup.js +68 -0
- package/dist/components/Select.d.ts +47 -0
- package/dist/components/Select.js +138 -0
- package/dist/components/Skeleton.d.ts +46 -0
- package/dist/components/Skeleton.js +40 -0
- package/dist/components/Slider.d.ts +126 -0
- package/dist/components/Slider.js +166 -0
- package/dist/components/Spinner.d.ts +23 -0
- package/dist/components/Spinner.js +23 -0
- package/dist/components/Stack.d.ts +35 -0
- package/dist/components/Stack.js +24 -0
- package/dist/components/Switch.d.ts +27 -0
- package/dist/components/Switch.js +33 -0
- package/dist/components/Table.d.ts +71 -0
- package/dist/components/Table.js +61 -0
- package/dist/components/Tabs.d.ts +66 -0
- package/dist/components/Tabs.js +109 -0
- package/dist/components/Text.d.ts +32 -0
- package/dist/components/Text.js +28 -0
- package/dist/components/Textarea.d.ts +15 -0
- package/dist/components/Textarea.js +24 -0
- package/dist/components/Toast.d.ts +90 -0
- package/dist/components/Toast.js +156 -0
- package/dist/components/ToggleGroup.d.ts +79 -0
- package/dist/components/ToggleGroup.js +101 -0
- package/dist/components/Tooltip.d.ts +46 -0
- package/dist/components/Tooltip.js +62 -0
- package/dist/components/VisuallyHidden.d.ts +18 -0
- package/dist/components/VisuallyHidden.js +22 -0
- package/dist/contrast.d.ts +32 -0
- package/dist/css.d.ts +2 -2
- package/dist/css.js +193 -157
- package/dist/define.d.ts +40 -15
- package/dist/define.js +30 -27
- package/dist/demo.d.ts +2 -0
- package/dist/demo.js +2 -0
- package/dist/esbuild.cjs +5 -0
- package/dist/esbuild.d.ts +4 -0
- package/dist/esbuild.js +6 -0
- package/dist/field-context.d.ts +16 -0
- package/dist/field-context.js +17 -0
- package/dist/floating.d.ts +12 -0
- package/dist/floating.js +52 -0
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.js +12 -0
- package/{src/index.ts → dist/index.d.ts} +11 -33
- package/dist/index.js +50 -0
- package/dist/init.d.ts +18 -0
- package/dist/init.js +224 -0
- package/dist/plugin.d.ts +10 -26
- package/dist/plugin.js +152 -78
- package/dist/reference/DemoYarcl.d.ts +12 -0
- package/dist/reference/DemoYarcl.js +312 -0
- package/dist/reference/DesignReference.d.ts +24 -0
- package/dist/reference/DesignReference.js +403 -0
- package/dist/reference/index.js +2 -0
- package/dist/rollup.cjs +5 -0
- package/dist/rollup.d.ts +4 -0
- package/dist/rollup.js +6 -0
- package/dist/rspack.cjs +5 -0
- package/dist/rspack.d.ts +4 -0
- package/dist/rspack.js +6 -0
- package/dist/runtime.d.ts +13 -0
- package/dist/runtime.js +30 -0
- package/dist/setup.d.ts +6 -0
- package/dist/setup.js +33 -0
- package/{src → dist}/styles.css +224 -106
- package/dist/themes/bloom.d.ts +295 -0
- package/dist/themes/bloom.js +202 -0
- package/dist/themes/brutalist.d.ts +277 -0
- package/dist/themes/brutalist.js +199 -0
- package/dist/themes/compact.d.ts +274 -0
- package/dist/themes/compact.js +200 -0
- package/dist/themes/contract.d.ts +23 -0
- package/dist/themes/editorial.d.ts +277 -0
- package/dist/themes/editorial.js +183 -0
- package/dist/themes/index.d.ts +1425 -0
- package/dist/themes/index.js +45 -0
- package/{src/types.ts → dist/types.d.ts} +40 -37
- package/dist/vite.cjs +5 -0
- package/dist/vite.d.ts +4 -0
- package/dist/vite.js +6 -0
- package/dist/webpack.cjs +5 -0
- package/dist/webpack.d.ts +4 -0
- package/dist/webpack.js +6 -0
- package/dist/yarcl.config.d.ts +276 -0
- package/dist/yarcl.config.js +273 -0
- package/package.json +69 -17
- package/src/classes.ts +0 -23
- package/src/color.ts +0 -48
- package/src/components/Accordion.tsx +0 -274
- package/src/components/Alert.tsx +0 -85
- package/src/components/Badge.tsx +0 -79
- package/src/components/Breadcrumb.tsx +0 -239
- package/src/components/Button.tsx +0 -58
- package/src/components/ButtonGroup.tsx +0 -61
- package/src/components/Card.tsx +0 -50
- package/src/components/Checkbox.tsx +0 -49
- package/src/components/Combobox.tsx +0 -522
- package/src/components/CommandPalette.tsx +0 -452
- package/src/components/DatePicker.tsx +0 -432
- package/src/components/Dialog.tsx +0 -39
- package/src/components/Divider.tsx +0 -34
- package/src/components/Drawer.tsx +0 -31
- package/src/components/Field.tsx +0 -61
- package/src/components/Heading.tsx +0 -40
- package/src/components/HoverCard.tsx +0 -108
- package/src/components/IconButton.tsx +0 -59
- package/src/components/Inline.tsx +0 -42
- package/src/components/Input.tsx +0 -28
- package/src/components/Label.tsx +0 -58
- package/src/components/Link.tsx +0 -41
- package/src/components/Menu.tsx +0 -207
- package/src/components/Modal.tsx +0 -164
- package/src/components/NumberInput.tsx +0 -208
- package/src/components/Pagination.tsx +0 -227
- package/src/components/Popover.tsx +0 -140
- package/src/components/Progress.tsx +0 -122
- package/src/components/Radio.tsx +0 -59
- package/src/components/RadioGroup.tsx +0 -114
- package/src/components/Select.tsx +0 -197
- package/src/components/Skeleton.tsx +0 -95
- package/src/components/Slider.tsx +0 -315
- package/src/components/Spinner.tsx +0 -38
- package/src/components/Stack.tsx +0 -57
- package/src/components/Switch.tsx +0 -42
- package/src/components/Table.tsx +0 -99
- package/src/components/Tabs.tsx +0 -159
- package/src/components/Text.tsx +0 -67
- package/src/components/Textarea.tsx +0 -26
- package/src/components/Toast.tsx +0 -190
- package/src/components/ToggleGroup.tsx +0 -227
- package/src/components/Tooltip.tsx +0 -78
- package/src/contrast.ts +0 -82
- package/src/css.ts +0 -228
- package/src/define.check.ts +0 -259
- package/src/define.ts +0 -379
- package/src/field-context.ts +0 -31
- package/src/floating.tsx +0 -61
- package/src/hooks.ts +0 -19
- package/src/plugin.ts +0 -94
- package/src/reference/DesignReference.tsx +0 -374
- package/src/runtime.ts +0 -38
- package/src/themes/bloom.ts +0 -72
- package/src/themes/brutalist.ts +0 -63
- package/src/themes/compact.ts +0 -63
- package/src/themes/contract.ts +0 -24
- package/src/themes/editorial.ts +0 -55
- package/src/themes/index.ts +0 -47
- package/src/yarcl.config.ts +0 -104
- /package/{src/reference/index.ts → dist/reference/index.d.ts} +0 -0
- /package/{src → dist}/reference/reference.css +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useDefaults } from "../runtime.js";
|
|
2
|
+
import { colorClass, cx, sizeClass } from "../classes.js";
|
|
3
|
+
import { useRadioGroup } from "./RadioGroup.js";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/Radio.tsx
|
|
6
|
+
/**
|
|
7
|
+
* A radio button with an optional label. Place inside a {@link RadioGroup}, or group standalone
|
|
8
|
+
* radios with the same `name`.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <RadioGroup label="Plan" defaultValue="pro">
|
|
13
|
+
* <Radio value="free">Free</Radio>
|
|
14
|
+
* <Radio value="pro">Pro</Radio>
|
|
15
|
+
* </RadioGroup>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
function Radio({ children, size, color, value, className, style, onChange, ...props }) {
|
|
19
|
+
const own = useDefaults("Radio");
|
|
20
|
+
const group = useRadioGroup();
|
|
21
|
+
const groupProps = group && {
|
|
22
|
+
name: group.name,
|
|
23
|
+
checked: value !== void 0 && group.value === value,
|
|
24
|
+
"aria-invalid": group.invalid || void 0,
|
|
25
|
+
onChange: (event) => {
|
|
26
|
+
onChange?.(event);
|
|
27
|
+
if (event.target.checked && value !== void 0) group.select(value);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
31
|
+
className: cx("yarcl-radio", sizeClass(size ?? group?.size ?? own.size, "Radio"), colorClass(color ?? group?.color ?? own.color), className),
|
|
32
|
+
style,
|
|
33
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
34
|
+
type: "radio",
|
|
35
|
+
className: "yarcl-radio-input",
|
|
36
|
+
value,
|
|
37
|
+
onChange,
|
|
38
|
+
...props,
|
|
39
|
+
...groupProps
|
|
40
|
+
}), children != null && /* @__PURE__ */ jsx("span", {
|
|
41
|
+
className: "yarcl-radio-label",
|
|
42
|
+
children
|
|
43
|
+
})]
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { Radio };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
|
+
import type { Color, ComponentSize, Size } from '../types';
|
|
3
|
+
interface RadioGroupContextValue {
|
|
4
|
+
name: string;
|
|
5
|
+
value: string | null;
|
|
6
|
+
select: (value: string) => void;
|
|
7
|
+
size?: Size;
|
|
8
|
+
color?: Color;
|
|
9
|
+
invalid: boolean;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function useRadioGroup(): RadioGroupContextValue | null;
|
|
13
|
+
/** Props for {@link RadioGroup}. */
|
|
14
|
+
export interface RadioGroupProps extends Omit<ComponentProps<'fieldset'>, 'defaultValue' | 'onChange' | 'color'> {
|
|
15
|
+
/** Visible group label, rendered as the `<legend>`. */
|
|
16
|
+
label: ReactNode;
|
|
17
|
+
/** Helper text shown below the options. */
|
|
18
|
+
description?: ReactNode;
|
|
19
|
+
/** Error message. Marks the options invalid and styles them with `defaults.errorColor`. */
|
|
20
|
+
error?: ReactNode;
|
|
21
|
+
/** Form field name shared by the radios. Generated when omitted. */
|
|
22
|
+
name?: string;
|
|
23
|
+
/** Controlled selected value. */
|
|
24
|
+
value?: string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Initially selected value when uncontrolled.
|
|
27
|
+
* @default null
|
|
28
|
+
*/
|
|
29
|
+
defaultValue?: string | null;
|
|
30
|
+
/** Called with the selected radio's `value`. */
|
|
31
|
+
onValueChange?: (value: string) => void;
|
|
32
|
+
/** Size of every radio, from the `sizes` config. */
|
|
33
|
+
size?: ComponentSize<'Radio'>;
|
|
34
|
+
/** Color of every radio, from the `colors` config. */
|
|
35
|
+
color?: Color;
|
|
36
|
+
/**
|
|
37
|
+
* Lays the radios out in a row or a column.
|
|
38
|
+
* @default 'vertical'
|
|
39
|
+
*/
|
|
40
|
+
orientation?: 'horizontal' | 'vertical';
|
|
41
|
+
/** {@link Radio}s, each with a `value`. */
|
|
42
|
+
children: ReactNode;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A labelled group of {@link Radio}s. Renders a `<fieldset>` and `<legend>`, shares one `name`,
|
|
46
|
+
* and tracks the selected value. Radios inside don't need `name` or `checked`.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* <RadioGroup label="Plan" defaultValue="pro" orientation="horizontal">
|
|
51
|
+
* <Radio value="free">Free</Radio>
|
|
52
|
+
* <Radio value="pro">Pro</Radio>
|
|
53
|
+
* </RadioGroup>
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function RadioGroup({ label, description, error, name, value: valueProp, defaultValue, onValueChange, size, color, orientation, disabled, className, children, ...props }: RadioGroupProps): import("react").JSX.Element;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useConfig } from "../runtime.js";
|
|
2
|
+
import { cx, typeClass } from "../classes.js";
|
|
3
|
+
import { useControllable } from "../hooks.js";
|
|
4
|
+
import { createContext, useContext, useId } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/components/RadioGroup.tsx
|
|
7
|
+
var RadioGroupContext = createContext(null);
|
|
8
|
+
function useRadioGroup() {
|
|
9
|
+
return useContext(RadioGroupContext);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A labelled group of {@link Radio}s. Renders a `<fieldset>` and `<legend>`, shares one `name`,
|
|
13
|
+
* and tracks the selected value. Radios inside don't need `name` or `checked`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <RadioGroup label="Plan" defaultValue="pro" orientation="horizontal">
|
|
18
|
+
* <Radio value="free">Free</Radio>
|
|
19
|
+
* <Radio value="pro">Pro</Radio>
|
|
20
|
+
* </RadioGroup>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
function RadioGroup({ label, description, error, name, value: valueProp, defaultValue = null, onValueChange, size, color, orientation = "vertical", disabled, className, children, ...props }) {
|
|
24
|
+
const config = useConfig();
|
|
25
|
+
const id = useId();
|
|
26
|
+
const [value, setValue] = useControllable(valueProp, defaultValue, (v) => v != null && onValueChange?.(v));
|
|
27
|
+
const descriptionId = description != null ? `${id}-description` : void 0;
|
|
28
|
+
const errorId = error != null && error !== false ? `${id}-error` : void 0;
|
|
29
|
+
return /* @__PURE__ */ jsx(RadioGroupContext.Provider, {
|
|
30
|
+
value: {
|
|
31
|
+
name: name ?? id,
|
|
32
|
+
value,
|
|
33
|
+
select: setValue,
|
|
34
|
+
size,
|
|
35
|
+
color,
|
|
36
|
+
invalid: errorId != null,
|
|
37
|
+
disabled
|
|
38
|
+
},
|
|
39
|
+
children: /* @__PURE__ */ jsxs("fieldset", {
|
|
40
|
+
className: cx("yarcl-field yarcl-radio-group", className),
|
|
41
|
+
"aria-describedby": cx(descriptionId, errorId) || void 0,
|
|
42
|
+
disabled,
|
|
43
|
+
...props,
|
|
44
|
+
children: [
|
|
45
|
+
/* @__PURE__ */ jsx("legend", {
|
|
46
|
+
className: cx("yarcl-field-label", typeClass(config.defaults.labelStyle)),
|
|
47
|
+
children: label
|
|
48
|
+
}),
|
|
49
|
+
/* @__PURE__ */ jsx("div", {
|
|
50
|
+
className: cx("yarcl-radio-group-options", `yarcl-radio-group-${orientation}`),
|
|
51
|
+
children
|
|
52
|
+
}),
|
|
53
|
+
descriptionId && /* @__PURE__ */ jsx("p", {
|
|
54
|
+
className: cx("yarcl-field-description", typeClass(config.defaults.helperStyle)),
|
|
55
|
+
id: descriptionId,
|
|
56
|
+
children: description
|
|
57
|
+
}),
|
|
58
|
+
errorId && /* @__PURE__ */ jsx("p", {
|
|
59
|
+
className: cx("yarcl-field-error", typeClass(config.defaults.helperStyle)),
|
|
60
|
+
id: errorId,
|
|
61
|
+
children: error
|
|
62
|
+
})
|
|
63
|
+
]
|
|
64
|
+
})
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { RadioGroup, useRadioGroup };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
|
+
import type { TokenProps } from '../types';
|
|
3
|
+
/** An option of a {@link Select} or {@link Combobox}. */
|
|
4
|
+
export interface SelectOption<V extends string = string> {
|
|
5
|
+
/** Value reported by `onValueChange` and submitted with forms. */
|
|
6
|
+
value: V;
|
|
7
|
+
/** Text shown to the user. Also used for type-to-select and filtering. */
|
|
8
|
+
label: string;
|
|
9
|
+
/** Prevents choosing this option. */
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Props for {@link Select}. */
|
|
13
|
+
export interface SelectProps<V extends string = string> extends TokenProps<'Select'>, Omit<ComponentProps<'button'>, 'color' | 'value' | 'defaultValue' | 'onChange' | 'children'> {
|
|
14
|
+
/** The options to choose from. */
|
|
15
|
+
options: readonly SelectOption<V>[];
|
|
16
|
+
/** Controlled value. `null` means nothing is selected. */
|
|
17
|
+
value?: V | null;
|
|
18
|
+
/**
|
|
19
|
+
* Initial value when uncontrolled.
|
|
20
|
+
* @default null
|
|
21
|
+
*/
|
|
22
|
+
defaultValue?: V | null;
|
|
23
|
+
/** Called with the chosen option's value. */
|
|
24
|
+
onValueChange?: (value: V | null) => void;
|
|
25
|
+
/** Text shown when nothing is selected. */
|
|
26
|
+
placeholder?: ReactNode;
|
|
27
|
+
/** Form field name. Renders a hidden input with the value. */
|
|
28
|
+
name?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Picks one value from a list, like a native `<select>` but styled from the design tokens.
|
|
32
|
+
* Arrow keys and type-to-select work both open and closed.
|
|
33
|
+
* Shares the size scale with {@link Input} and {@link Button}. Works inside a {@link Field}.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```tsx
|
|
37
|
+
* <Select
|
|
38
|
+
* placeholder="Choose a plan"
|
|
39
|
+
* options={[
|
|
40
|
+
* { value: 'free', label: 'Free' },
|
|
41
|
+
* { value: 'pro', label: 'Pro' },
|
|
42
|
+
* ]}
|
|
43
|
+
* onValueChange={setPlan}
|
|
44
|
+
* />
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function Select<V extends string = string>(props: SelectProps<V>): import("react").JSX.Element;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { useDefaults } from "../runtime.js";
|
|
2
|
+
import { colorClass, cx, radiusClass, sizeClass } from "../classes.js";
|
|
3
|
+
import { useControllable } from "../hooks.js";
|
|
4
|
+
import { useFieldProps } from "../field-context.js";
|
|
5
|
+
import { CheckIcon, ChevronIcon, floatingMiddleware } from "../floating.js";
|
|
6
|
+
import { useRef, useState } from "react";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { FloatingFocusManager, FloatingPortal, autoUpdate, useClick, useDismiss, useFloating, useInteractions, useListNavigation, useMergeRefs, useRole, useTypeahead } from "@floating-ui/react";
|
|
9
|
+
//#region src/components/Select.tsx
|
|
10
|
+
/**
|
|
11
|
+
* Picks one value from a list, like a native `<select>` but styled from the design tokens.
|
|
12
|
+
* Arrow keys and type-to-select work both open and closed.
|
|
13
|
+
* Shares the size scale with {@link Input} and {@link Button}. Works inside a {@link Field}.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <Select
|
|
18
|
+
* placeholder="Choose a plan"
|
|
19
|
+
* options={[
|
|
20
|
+
* { value: 'free', label: 'Free' },
|
|
21
|
+
* { value: 'pro', label: 'Pro' },
|
|
22
|
+
* ]}
|
|
23
|
+
* onValueChange={setPlan}
|
|
24
|
+
* />
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
function Select(props) {
|
|
28
|
+
const own = useDefaults("Select");
|
|
29
|
+
const { options, value: valueProp, defaultValue = null, onValueChange, placeholder, name, size, radius, color, className, disabled, ...rest } = useFieldProps(props);
|
|
30
|
+
const [value, setValue] = useControllable(valueProp, defaultValue, onValueChange);
|
|
31
|
+
const [open, setOpen] = useState(false);
|
|
32
|
+
const [activeIndex, setActiveIndex] = useState(null);
|
|
33
|
+
const listRef = useRef([]);
|
|
34
|
+
const labelsRef = useRef([]);
|
|
35
|
+
const typingRef = useRef(false);
|
|
36
|
+
labelsRef.current = options.map((option) => option.disabled ? null : option.label);
|
|
37
|
+
const selectedIndex = options.findIndex((option) => option.value === value);
|
|
38
|
+
const selected = selectedIndex >= 0 ? options[selectedIndex] : void 0;
|
|
39
|
+
const disabledIndices = options.flatMap((option, i) => option.disabled ? [i] : []);
|
|
40
|
+
function choose(index) {
|
|
41
|
+
const option = options[index];
|
|
42
|
+
if (!option || option.disabled) return;
|
|
43
|
+
setValue(option.value);
|
|
44
|
+
setOpen(false);
|
|
45
|
+
}
|
|
46
|
+
const { refs, floatingStyles, context } = useFloating({
|
|
47
|
+
open,
|
|
48
|
+
onOpenChange: setOpen,
|
|
49
|
+
placement: "bottom-start",
|
|
50
|
+
transform: false,
|
|
51
|
+
whileElementsMounted: autoUpdate,
|
|
52
|
+
middleware: floatingMiddleware({
|
|
53
|
+
gap: 4,
|
|
54
|
+
matchWidth: true
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
|
|
58
|
+
useClick(context, { enabled: !disabled }),
|
|
59
|
+
useDismiss(context),
|
|
60
|
+
useRole(context, { role: "select" }),
|
|
61
|
+
useListNavigation(context, {
|
|
62
|
+
listRef,
|
|
63
|
+
activeIndex,
|
|
64
|
+
selectedIndex: selectedIndex >= 0 ? selectedIndex : null,
|
|
65
|
+
onNavigate: setActiveIndex,
|
|
66
|
+
disabledIndices,
|
|
67
|
+
loop: true
|
|
68
|
+
}),
|
|
69
|
+
useTypeahead(context, {
|
|
70
|
+
listRef: labelsRef,
|
|
71
|
+
activeIndex,
|
|
72
|
+
selectedIndex: selectedIndex >= 0 ? selectedIndex : null,
|
|
73
|
+
onMatch: open ? setActiveIndex : choose,
|
|
74
|
+
onTypingChange: (typing) => {
|
|
75
|
+
typingRef.current = typing;
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
]);
|
|
79
|
+
const buttonRef = useMergeRefs([refs.setReference, rest.ref]);
|
|
80
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
81
|
+
/* @__PURE__ */ jsxs("button", {
|
|
82
|
+
ref: buttonRef,
|
|
83
|
+
type: "button",
|
|
84
|
+
disabled,
|
|
85
|
+
className: cx("yarcl-input yarcl-select", sizeClass(size ?? own.size, "Select"), radiusClass(radius ?? own.radius, size ?? own.size), colorClass(color ?? own.color), className),
|
|
86
|
+
...getReferenceProps(rest),
|
|
87
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
88
|
+
className: cx("yarcl-select-value", !selected && "yarcl-select-placeholder"),
|
|
89
|
+
children: selected ? selected.label : placeholder
|
|
90
|
+
}), /* @__PURE__ */ jsx(ChevronIcon, {})]
|
|
91
|
+
}),
|
|
92
|
+
name && /* @__PURE__ */ jsx("input", {
|
|
93
|
+
type: "hidden",
|
|
94
|
+
name,
|
|
95
|
+
value: value ?? ""
|
|
96
|
+
}),
|
|
97
|
+
open && /* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(FloatingFocusManager, {
|
|
98
|
+
context,
|
|
99
|
+
modal: false,
|
|
100
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
101
|
+
ref: refs.setFloating,
|
|
102
|
+
style: floatingStyles,
|
|
103
|
+
className: cx("yarcl-floating yarcl-panel yarcl-listbox", sizeClass(size ?? own.size, "Select"), colorClass(color ?? own.color)),
|
|
104
|
+
...getFloatingProps(),
|
|
105
|
+
children: options.map((option, i) => {
|
|
106
|
+
const isSelected = i === selectedIndex;
|
|
107
|
+
const isActive = i === activeIndex;
|
|
108
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
109
|
+
ref: (node) => {
|
|
110
|
+
listRef.current[i] = node;
|
|
111
|
+
},
|
|
112
|
+
tabIndex: isActive ? 0 : -1,
|
|
113
|
+
"aria-disabled": option.disabled || void 0,
|
|
114
|
+
"data-active": isActive || void 0,
|
|
115
|
+
className: "yarcl-option",
|
|
116
|
+
...getItemProps({
|
|
117
|
+
active: isActive,
|
|
118
|
+
selected: isSelected,
|
|
119
|
+
onClick: () => choose(i),
|
|
120
|
+
onKeyDown(event) {
|
|
121
|
+
if (event.key === "Enter" || event.key === " " && !typingRef.current) {
|
|
122
|
+
event.preventDefault();
|
|
123
|
+
choose(i);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}),
|
|
127
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
128
|
+
className: "yarcl-option-label",
|
|
129
|
+
children: option.label
|
|
130
|
+
}), isSelected && /* @__PURE__ */ jsx(CheckIcon, {})]
|
|
131
|
+
}, option.value);
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
}) })
|
|
135
|
+
] });
|
|
136
|
+
}
|
|
137
|
+
//#endregion
|
|
138
|
+
export { Select };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
import type { ComponentSize, Radius, TextStyle } from '../types';
|
|
3
|
+
/** Props for {@link Skeleton}. */
|
|
4
|
+
export interface SkeletonProps extends Omit<ComponentProps<'span'>, 'children'> {
|
|
5
|
+
/**
|
|
6
|
+
* `text`: lines matching a text style; `control`: the height of a control of the given `size`;
|
|
7
|
+
* `circle`: a circle, e.g. for an avatar; `rect`: a block sized by `width` and `height`.
|
|
8
|
+
* @default 'text'
|
|
9
|
+
*/
|
|
10
|
+
shape?: 'text' | 'control' | 'circle' | 'rect';
|
|
11
|
+
/** Number of lines for `shape="text"`. The last line is shorter. */
|
|
12
|
+
lines?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Text style whose font size and line height the lines match, for `shape="text"`.
|
|
15
|
+
* @default config.defaults.textStyle
|
|
16
|
+
*/
|
|
17
|
+
textStyle?: TextStyle;
|
|
18
|
+
/**
|
|
19
|
+
* Control size, from the `sizes` config. Sets the height for `shape="control"` and the diameter for `shape="circle"`.
|
|
20
|
+
* @default config.defaults.size
|
|
21
|
+
*/
|
|
22
|
+
size?: ComponentSize<'Skeleton'>;
|
|
23
|
+
/**
|
|
24
|
+
* Corner radius for `control` and `rect`, from the `radii` config.
|
|
25
|
+
* @default config.defaults.radius
|
|
26
|
+
*/
|
|
27
|
+
radius?: Radius | 'size';
|
|
28
|
+
/** Width as a CSS length. */
|
|
29
|
+
width?: string;
|
|
30
|
+
/** Height as a CSS length, for `shape="rect"`. */
|
|
31
|
+
height?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A placeholder shown while content loads. Hidden from assistive technology;
|
|
35
|
+
* mark the loading region with `aria-busy` instead.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* <Stack aria-busy>
|
|
40
|
+
* <Skeleton shape="text" textStyle="title" width="40%" />
|
|
41
|
+
* <Skeleton shape="text" lines={3} />
|
|
42
|
+
* <Skeleton shape="control" width="12rem" />
|
|
43
|
+
* </Stack>
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function Skeleton({ shape, lines, textStyle, size, radius, width, height, className, style, ...props }: SkeletonProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useDefaults } from "../runtime.js";
|
|
2
|
+
import { cx, radiusClass, sizeClass, typeClass } from "../classes.js";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/Skeleton.tsx
|
|
5
|
+
/**
|
|
6
|
+
* A placeholder shown while content loads. Hidden from assistive technology;
|
|
7
|
+
* mark the loading region with `aria-busy` instead.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <Stack aria-busy>
|
|
12
|
+
* <Skeleton shape="text" textStyle="title" width="40%" />
|
|
13
|
+
* <Skeleton shape="text" lines={3} />
|
|
14
|
+
* <Skeleton shape="control" width="12rem" />
|
|
15
|
+
* </Stack>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
function Skeleton({ shape = "text", lines = 1, textStyle, size, radius, width, height, className, style, ...props }) {
|
|
19
|
+
const own = useDefaults("Skeleton");
|
|
20
|
+
const dimensions = {
|
|
21
|
+
width,
|
|
22
|
+
height,
|
|
23
|
+
...style
|
|
24
|
+
};
|
|
25
|
+
if (shape === "text") return /* @__PURE__ */ jsx("span", {
|
|
26
|
+
"aria-hidden": "true",
|
|
27
|
+
className: cx("yarcl-skeleton-text", textStyle && typeClass(textStyle), className),
|
|
28
|
+
style: dimensions,
|
|
29
|
+
...props,
|
|
30
|
+
children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx("span", { className: "yarcl-skeleton yarcl-skeleton-line" }, i))
|
|
31
|
+
});
|
|
32
|
+
return /* @__PURE__ */ jsx("span", {
|
|
33
|
+
"aria-hidden": "true",
|
|
34
|
+
className: cx("yarcl-skeleton", `yarcl-skeleton-${shape}`, shape !== "rect" && sizeClass(size ?? own.size, "Skeleton"), shape !== "circle" && radiusClass(radius ?? own.radius, size ?? own.size), className),
|
|
35
|
+
style: dimensions,
|
|
36
|
+
...props
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { Skeleton };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { type ComponentProps } from 'react';
|
|
2
|
+
import type { TokenProps } from '../types';
|
|
3
|
+
/** A {@link Slider} value: one number, or a `[start, end]` pair for a range. */
|
|
4
|
+
export type SliderValue = number | [number, number];
|
|
5
|
+
/** Props for {@link Slider}. Accepts all native `<div>` attributes except `color`, `defaultValue`, `onChange` and `children`. */
|
|
6
|
+
export interface SliderProps<V extends SliderValue = number> extends TokenProps<'Slider'>, Omit<ComponentProps<'div'>, 'color' | 'defaultValue' | 'onChange' | 'children'> {
|
|
7
|
+
/**
|
|
8
|
+
* Controlled value. Pass a `[start, end]` pair for a range with two thumbs.
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <Slider value={volume} onValueChange={setVolume} aria-label="Volume" />
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
value?: V;
|
|
15
|
+
/**
|
|
16
|
+
* Initial value when uncontrolled. Pass a `[start, end]` pair for a range with two thumbs.
|
|
17
|
+
* @default min
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* <Slider defaultValue={[20, 80]} aria-label="Price" />
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
defaultValue?: V;
|
|
24
|
+
/**
|
|
25
|
+
* Called with the new value while the user drags or presses a key.
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* <Slider onValueChange={(value) => setVolume(value)} aria-label="Volume" />
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
onValueChange?: (value: V) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Lowest value.
|
|
34
|
+
* @default 0
|
|
35
|
+
* @example
|
|
36
|
+
* ```tsx
|
|
37
|
+
* <Slider min={-10} max={10} aria-label="Offset" />
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
min?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Highest value.
|
|
43
|
+
* @default 100
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* <Slider max={10} aria-label="Rating" />
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
max?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Interval between values. Values snap to multiples of it, counted from `min`.
|
|
52
|
+
* @default 1
|
|
53
|
+
* @example
|
|
54
|
+
* ```tsx
|
|
55
|
+
* <Slider step={5} aria-label="Opacity" />
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
step?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Jump for PageUp and PageDown.
|
|
61
|
+
* @default a tenth of the range, rounded to a whole number of steps
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* <Slider step={1} largeStep={25} aria-label="Progress" />
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
largeStep?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Prevents interaction and dims the slider.
|
|
70
|
+
* @default false
|
|
71
|
+
* @example
|
|
72
|
+
* ```tsx
|
|
73
|
+
* <Slider disabled defaultValue={40} aria-label="Volume" />
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
disabled?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Form field name. Renders a hidden input per thumb with its value.
|
|
79
|
+
* @example
|
|
80
|
+
* ```tsx
|
|
81
|
+
* <Slider name="volume" aria-label="Volume" />
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
name?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Formats a value for screen readers (`aria-valuetext`).
|
|
87
|
+
* @example
|
|
88
|
+
* ```tsx
|
|
89
|
+
* <Slider formatValue={(value) => `${value} percent`} aria-label="Volume" />
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
formatValue?: (value: number) => string;
|
|
93
|
+
/**
|
|
94
|
+
* Names of the two thumbs of a range, added to the slider's label.
|
|
95
|
+
* @default ['Minimum', 'Maximum']
|
|
96
|
+
* @example
|
|
97
|
+
* ```tsx
|
|
98
|
+
* <Slider defaultValue={[9, 17]} thumbLabels={['Opens', 'Closes']} aria-label="Hours" />
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
thumbLabels?: readonly [string, string];
|
|
102
|
+
}
|
|
103
|
+
/** Props for `Slider.Range`. */
|
|
104
|
+
export type SliderRangeProps = SliderProps<[number, number]>;
|
|
105
|
+
/**
|
|
106
|
+
* Picks a number, or a range with two thumbs, by dragging along a track.
|
|
107
|
+
* Each thumb has `role="slider"` and supports the arrow keys, Home, End, PageUp and PageDown.
|
|
108
|
+
* Shares the size scale with the other controls. Works inside a {@link Field}; outside one, give it an `aria-label`.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```tsx
|
|
112
|
+
* <Field label="Volume">
|
|
113
|
+
* <Slider defaultValue={40} />
|
|
114
|
+
* </Field>
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
declare function SliderRoot<V extends SliderValue = number>(props: SliderProps<V>): import("react").JSX.Element;
|
|
118
|
+
declare function SliderRange(props: SliderRangeProps): import("react").JSX.Element;
|
|
119
|
+
/**
|
|
120
|
+
* Picks a number, or a range with two thumbs, by dragging along a track.
|
|
121
|
+
* Use `Slider.Range` for an explicitly range-only API.
|
|
122
|
+
*/
|
|
123
|
+
export declare const Slider: typeof SliderRoot & {
|
|
124
|
+
Range: typeof SliderRange;
|
|
125
|
+
};
|
|
126
|
+
export {};
|