@godxjp/ui 21.0.0 → 22.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/app-provider.js +2 -1
- package/dist/components/data-display/badge.d.ts +28 -1
- package/dist/components/data-display/badge.js +2 -0
- package/dist/components/data-display/data-table.d.ts +18 -2
- package/dist/components/data-display/data-table.js +4 -0
- package/dist/components/data-display/index.d.ts +1 -1
- package/dist/components/data-display/popover.d.ts +19 -1
- package/dist/components/data-display/popover.js +9 -1
- package/dist/components/data-display/progress.d.ts +37 -0
- package/dist/components/data-display/progress.js +57 -5
- package/dist/components/data-entry/date-picker.d.ts +10 -3
- package/dist/components/data-entry/date-picker.js +503 -238
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +4 -1
- package/dist/components/data-entry/form.js +10 -1
- package/dist/components/data-entry/index.d.ts +0 -6
- package/dist/components/data-entry/index.js +0 -6
- package/dist/components/data-entry/label.d.ts +14 -1
- package/dist/components/data-entry/label.js +6 -1
- package/dist/components/data-entry/radio.d.ts +27 -6
- package/dist/components/data-entry/radio.js +88 -43
- package/dist/components/data-entry/search-select.js +8 -1
- package/dist/components/data-entry/select.js +2 -0
- package/dist/components/data-entry/switch.d.ts +6 -3
- package/dist/components/data-entry/switch.js +34 -11
- package/dist/components/layout/mobile-shell.d.ts +1 -1
- package/dist/components/layout/mobile-shell.js +2 -0
- package/dist/components/navigation/menubar.d.ts +10 -3
- package/dist/components/navigation/steps.d.ts +1 -1
- package/dist/components/navigation/steps.js +3 -1
- package/dist/components/navigation/tabs-scroll.d.ts +27 -0
- package/dist/components/navigation/tabs-scroll.js +52 -1
- package/dist/components/navigation/tabs.d.ts +2 -2
- package/dist/components/navigation/tabs.js +88 -23
- package/dist/components/ui/index.d.ts +0 -1
- package/dist/components/ui/index.js +0 -1
- package/dist/components/ui/segmented.d.ts +15 -1
- package/dist/components/ui/segmented.js +13 -6
- package/dist/i18n/messages/en.json +3 -2
- package/dist/i18n/messages/ja.json +3 -2
- package/dist/i18n/messages/vi.json +3 -2
- package/dist/lib/datetime/picker-format.d.ts +18 -0
- package/dist/lib/datetime/picker-format.js +35 -1
- package/dist/lib/field-a11y.d.ts +12 -0
- package/dist/lib/field-a11y.js +14 -1
- package/dist/props/components/data-display.prop.d.ts +7 -0
- package/dist/props/components/data-entry.prop.d.ts +180 -99
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/components/layout.prop.d.ts +12 -1
- package/dist/props/components/navigation.prop.d.ts +76 -1
- package/dist/props/registry.d.ts +16 -16
- package/dist/props/registry.js +16 -15
- package/dist/props/vocabulary/data.prop.d.ts +12 -0
- package/dist/props/vocabulary/index.d.ts +2 -2
- package/dist/props/vocabulary/layout.prop.d.ts +11 -0
- package/dist/styles/badge-layout.css +4 -0
- package/dist/styles/card-layout.css +6 -6
- package/dist/styles/control.css +15 -6
- package/dist/styles/data-display-layout.css +76 -13
- package/dist/styles/focus-ring.css +4 -2
- package/dist/styles/navigation-layout.css +25 -0
- package/dist/styles/shell-layout.css +5 -0
- package/dist/styles/table-layout.css +34 -0
- package/dist/tokens/components/data-display.css +9 -0
- package/dist/tokens/components/navigation.css +6 -0
- package/dist/tokens/components/segmented.css +0 -2
- package/dist/tokens/components/shell.css +2 -0
- package/dist/tokens/components/table.css +3 -0
- package/dist/tokens/foundation.css +7 -0
- package/docs/COMPONENTS.md +14 -14
- package/docs/CONSUMER-RULES.md +24 -1
- package/docs/FRAME-COVERAGE-REPORT.md +3 -6
- package/docs/TOKENS.md +65 -0
- package/docs/data-display/badge.tsx +37 -0
- package/docs/data-display/data-table/index.tsx +18 -0
- package/docs/data-display/popover.tsx +41 -1
- package/docs/data-display/progress.tsx +28 -0
- package/docs/data-entry/calendar.tsx +2 -2
- package/docs/data-entry/date-picker.tsx +143 -3
- package/docs/data-entry/form/examples/invoice-form.tsx +2 -2
- package/docs/data-entry/form-field/examples/a11y-contract.tsx +3 -5
- package/docs/data-entry/form.tsx +4 -4
- package/docs/data-entry/number-input.tsx +31 -0
- package/docs/data-entry/segmented.tsx +103 -1
- package/docs/layout/mobile-shell.tsx +5 -0
- package/docs/navigation/tabs.tsx +149 -0
- package/docs/roadmap/antd-parity.md +35 -34
- package/docs/roadmap/parity-audit-data-entry.md +178 -165
- package/docs/roadmap/parity-backlog.md +6 -7
- package/docs/showcase/acme-portal.tsx +7 -0
- package/package.json +11 -23
- package/scripts/ui-audit.mjs +17 -4
- package/dist/components/data-entry/date-range-picker.d.ts +0 -11
- package/dist/components/data-entry/date-range-picker.js +0 -349
- package/dist/components/data-entry/month-picker.d.ts +0 -10
- package/dist/components/data-entry/month-picker.js +0 -241
- package/dist/components/data-entry/month-range-picker.d.ts +0 -10
- package/dist/components/data-entry/month-range-picker.js +0 -301
- package/dist/components/ui/date-range-picker.d.ts +0 -1
- package/dist/components/ui/date-range-picker.js +0 -2
- package/docs/data-entry/date-range-picker.tsx +0 -175
- package/docs/data-entry/month-picker.tsx +0 -101
- package/docs/data-entry/month-range-picker.tsx +0 -115
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { FormFieldProp } from "../../props/components/data-entry.prop.js";
|
|
3
3
|
export type { FormFieldProp, FormFieldProp as FormFieldProps, } from "../../props/components/data-entry.prop.js";
|
|
4
|
-
export declare function FormField({ id, name, field, label, required, helper, error: errorProp, validateStatus, hasFeedback, feedback, labelAddon, layout: layoutProp, labelWidth: labelWidthProp, controlWidth: controlWidthProp, colSpan, className, children, staticText, }: FormFieldProp): React.JSX.Element;
|
|
4
|
+
export declare function FormField({ id, name, field, label, required, helper, helperPlacement, error: errorProp, validateStatus, hasFeedback, feedback, labelAddon, layout: layoutProp, labelWidth: labelWidthProp, controlWidth: controlWidthProp, colSpan, className, children, staticText, }: FormFieldProp): React.JSX.Element;
|
|
@@ -19,6 +19,7 @@ function FormField({
|
|
|
19
19
|
label,
|
|
20
20
|
required,
|
|
21
21
|
helper,
|
|
22
|
+
helperPlacement = "after",
|
|
22
23
|
error: errorProp,
|
|
23
24
|
validateStatus,
|
|
24
25
|
hasFeedback,
|
|
@@ -46,6 +47,7 @@ function FormField({
|
|
|
46
47
|
const resolvedId = id ?? autoId;
|
|
47
48
|
const labelId = `${resolvedId}-label`;
|
|
48
49
|
const helperId = helper ? `${resolvedId}-helper` : void 0;
|
|
50
|
+
const helperNode = helper ? /* @__PURE__ */ jsx("p", { id: helperId, className: "text-muted-foreground text-xs", children: helper }) : null;
|
|
49
51
|
const validationStatus = error ? "error" : validateStatus;
|
|
50
52
|
const feedbackId = hasFeedback && validationStatus ? `${resolvedId}-feedback` : void 0;
|
|
51
53
|
const FeedbackIcon = validationStatus === "validating" ? LoaderCircle : validationStatus === "error" ? CircleAlert : validationStatus === "warning" ? TriangleAlert : CheckCircle;
|
|
@@ -151,6 +153,7 @@ function FormField({
|
|
|
151
153
|
labelAddon
|
|
152
154
|
] }),
|
|
153
155
|
/* @__PURE__ */ jsxs("div", { "data-slot": "form-field-control", className: "ui-form-field-control", children: [
|
|
156
|
+
helperPlacement === "before" ? helperNode : null,
|
|
154
157
|
isStatic ? childWithA11y : /* @__PURE__ */ jsx(FieldNameContext.Provider, { value: fieldNameContext, children: /* @__PURE__ */ jsx(FieldIdentityContext.Provider, { value: fieldIdentityContext, children: /* @__PURE__ */ jsx(
|
|
155
158
|
"fieldset",
|
|
156
159
|
{
|
|
@@ -170,7 +173,7 @@ function FormField({
|
|
|
170
173
|
),
|
|
171
174
|
t(`dataEntry.form.${validationStatus}`)
|
|
172
175
|
] }) : null,
|
|
173
|
-
|
|
176
|
+
helperPlacement === "after" ? helperNode : null,
|
|
174
177
|
error ? /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: "text-destructive text-xs", children: error }) : null
|
|
175
178
|
] })
|
|
176
179
|
]
|
|
@@ -9,6 +9,15 @@ const FormLayoutContext = React.createContext(null);
|
|
|
9
9
|
function useFormLayout() {
|
|
10
10
|
return React.useContext(FormLayoutContext);
|
|
11
11
|
}
|
|
12
|
+
function asChildContent(children, columns) {
|
|
13
|
+
if (columns == null) return children;
|
|
14
|
+
const child = React.Children.only(children);
|
|
15
|
+
return React.cloneElement(
|
|
16
|
+
child,
|
|
17
|
+
void 0,
|
|
18
|
+
/* @__PURE__ */ jsx(ResponsiveGrid, { columns, children: child.props.children })
|
|
19
|
+
);
|
|
20
|
+
}
|
|
12
21
|
const Form = React.forwardRef(function Form2({
|
|
13
22
|
layout = "vertical",
|
|
14
23
|
disabled,
|
|
@@ -41,7 +50,7 @@ const Form = React.forwardRef(function Form2({
|
|
|
41
50
|
"data-layout": layout,
|
|
42
51
|
className: cn("ui-form", density && `ui-density-${density}`, className),
|
|
43
52
|
...props,
|
|
44
|
-
children
|
|
53
|
+
children: asChildContent(children, columns)
|
|
45
54
|
}
|
|
46
55
|
)
|
|
47
56
|
) });
|
|
@@ -32,14 +32,8 @@ export { Slider } from "./slider.js";
|
|
|
32
32
|
export type { SliderProps } from "./slider.js";
|
|
33
33
|
export { Calendar } from "./calendar.js";
|
|
34
34
|
export type { CalendarProps } from "./calendar.js";
|
|
35
|
-
export { MonthPicker } from "./month-picker.js";
|
|
36
|
-
export type { MonthPickerProps } from "./month-picker.js";
|
|
37
|
-
export { MonthRangePicker } from "./month-range-picker.js";
|
|
38
|
-
export type { MonthRangePickerProps } from "./month-range-picker.js";
|
|
39
35
|
export { DatePicker } from "./date-picker.js";
|
|
40
36
|
export type { DatePickerProps } from "./date-picker.js";
|
|
41
|
-
export { DateRangePicker } from "./date-range-picker.js";
|
|
42
|
-
export type { DateRangePickerProps } from "./date-range-picker.js";
|
|
43
37
|
export { TimePicker } from "./time-picker.js";
|
|
44
38
|
export type { TimePickerProps } from "./time-picker.js";
|
|
45
39
|
export { ColorPicker } from "./color-picker.js";
|
|
@@ -29,10 +29,7 @@ import { Toggle } from "./toggle.js";
|
|
|
29
29
|
import { ToggleGroup, ToggleGroupItem } from "./toggle-group.js";
|
|
30
30
|
import { Slider } from "./slider.js";
|
|
31
31
|
import { Calendar } from "./calendar.js";
|
|
32
|
-
import { MonthPicker } from "./month-picker.js";
|
|
33
|
-
import { MonthRangePicker } from "./month-range-picker.js";
|
|
34
32
|
import { DatePicker } from "./date-picker.js";
|
|
35
|
-
import { DateRangePicker } from "./date-range-picker.js";
|
|
36
33
|
import { TimePicker } from "./time-picker.js";
|
|
37
34
|
import { ColorPicker } from "./color-picker.js";
|
|
38
35
|
import {
|
|
@@ -79,7 +76,6 @@ export {
|
|
|
79
76
|
CommandList,
|
|
80
77
|
CommandPalette,
|
|
81
78
|
DatePicker,
|
|
82
|
-
DateRangePicker,
|
|
83
79
|
Field,
|
|
84
80
|
Form,
|
|
85
81
|
FormErrors,
|
|
@@ -91,8 +87,6 @@ export {
|
|
|
91
87
|
InputOTPSeparator,
|
|
92
88
|
InputOTPSlot,
|
|
93
89
|
Label,
|
|
94
|
-
MonthPicker,
|
|
95
|
-
MonthRangePicker,
|
|
96
90
|
NumberInput,
|
|
97
91
|
PasswordInput,
|
|
98
92
|
PasswordStrength,
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
|
-
export declare const Label: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>, "ref"> & VariantProps<(props?: import("class-variance-authority/types").ClassProp | undefined) => string> & {
|
|
3
|
+
export declare const Label: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>, "ref">, "slot"> & VariantProps<(props?: import("class-variance-authority/types").ClassProp | undefined) => string> & {
|
|
4
4
|
asChild?: boolean;
|
|
5
|
+
/**
|
|
6
|
+
* react-aria's slot channel, DEFAULTED OFF.
|
|
7
|
+
*
|
|
8
|
+
* A `Label` rendered inside a react-aria collection (a `RadioGroup`, say) is otherwise
|
|
9
|
+
* claimed by that collection as the GROUP's label: it comes out as a `<span>`, the `htmlFor`
|
|
10
|
+
* this library passed is dropped on the floor, and the control it was meant to name ends up
|
|
11
|
+
* with no accessible name at all — a silent failure, measured on `Radio.Group` the moment
|
|
12
|
+
* that group moved to react-aria. `<Label htmlFor="x">` means one thing in this library and
|
|
13
|
+
* a surrounding primitive does not get to redefine it, so the default is react-aria's own
|
|
14
|
+
* opt-out: "an explicit `null` value indicates that the local props completely override all
|
|
15
|
+
* props received from a parent". Pass a slot name to opt back in.
|
|
16
|
+
*/
|
|
17
|
+
slot?: string | null;
|
|
5
18
|
} & React.RefAttributes<HTMLLabelElement>>;
|
|
@@ -7,8 +7,13 @@ import { Slot } from "../../lib/slot.js";
|
|
|
7
7
|
const labelVariants = cva(
|
|
8
8
|
"font-medium leading-[var(--control-label-line-height)] peer-disabled:cursor-not-allowed peer-disabled:opacity-[var(--control-label-disabled-alpha)]"
|
|
9
9
|
);
|
|
10
|
-
const Label = React.forwardRef(({ className, onMouseDown, asChild = false, ...props }, ref) => {
|
|
10
|
+
const Label = React.forwardRef(({ className, onMouseDown, asChild = false, slot = null, ...props }, ref) => {
|
|
11
11
|
const shared = {
|
|
12
|
+
// `string | null`, cast because react-aria's own `LabelProps` extends `LabelHTMLAttributes`
|
|
13
|
+
// and so re-types `slot` as `string | undefined` — narrower than the `SlotProps` contract the
|
|
14
|
+
// rest of the library publishes, and narrower than `useSlottedContext`, which branches on
|
|
15
|
+
// `slot === null` explicitly. React drops a `null` attribute, so nothing reaches the DOM.
|
|
16
|
+
slot,
|
|
12
17
|
// `...props` đứng TRƯỚC, không phải sau: giữ đúng thứ tự thuộc tính mà
|
|
13
18
|
// @radix-ui/react-label phát ra (`for` → `data-slot` → `class`), nên phép so
|
|
14
19
|
// `outerHTML` trong __tests__/label-checkbox-rac.test.tsx khớp từng ký tự.
|
|
@@ -1,14 +1,35 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
3
2
|
import type { RadioGroupProp } from "../../props/components/data-entry.prop.js";
|
|
4
3
|
export type { RadioGroupProp, RadioGroupProp as RadioGroupProps, } from "../../props/components/data-entry.prop.js";
|
|
5
|
-
declare const RadioGroupRoot: React.ForwardRefExoticComponent<Omit<
|
|
6
|
-
|
|
4
|
+
declare const RadioGroupRoot: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "defaultValue" | "dir" | "onChange"> & {
|
|
5
|
+
value?: string;
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
onValueChange?: (value: string) => void;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
name?: string;
|
|
11
|
+
orientation?: "horizontal" | "vertical";
|
|
12
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
13
|
+
declare const RadioItem: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref">, "value"> & {
|
|
14
|
+
value: string;
|
|
15
|
+
} & React.RefAttributes<HTMLLabelElement>>;
|
|
7
16
|
declare function RadioGroupOptions({ value, defaultValue, onValueChange, options, orientation, optionType, buttonStyle, disabled, name, id, className, children, ...ariaProps }: RadioGroupProp): React.JSX.Element;
|
|
8
17
|
/** Single radio — use inside `Radio.Group` / `RadioGroupRoot`, or via `options` API. */
|
|
9
|
-
export declare const Radio: React.ForwardRefExoticComponent<Omit<
|
|
10
|
-
|
|
18
|
+
export declare const Radio: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref">, "value"> & {
|
|
19
|
+
value: string;
|
|
20
|
+
} & React.RefAttributes<HTMLLabelElement>> & {
|
|
21
|
+
Root: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "defaultValue" | "dir" | "onChange"> & {
|
|
22
|
+
value?: string;
|
|
23
|
+
defaultValue?: string;
|
|
24
|
+
onValueChange?: (value: string) => void;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
required?: boolean;
|
|
27
|
+
name?: string;
|
|
28
|
+
orientation?: "horizontal" | "vertical";
|
|
29
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
11
30
|
Group: typeof RadioGroupOptions;
|
|
12
|
-
Item: React.ForwardRefExoticComponent<Omit<
|
|
31
|
+
Item: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref">, "value"> & {
|
|
32
|
+
value: string;
|
|
33
|
+
} & React.RefAttributes<HTMLLabelElement>>;
|
|
13
34
|
};
|
|
14
35
|
export { RadioGroupRoot, RadioItem, RadioGroupOptions as RadioGroup };
|
|
@@ -1,64 +1,108 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import
|
|
4
|
+
import { Radio as AriaRadio, RadioGroup as AriaRadioGroup } from "react-aria-components";
|
|
5
5
|
import { Circle } from "lucide-react";
|
|
6
6
|
import { cn } from "../../lib/utils.js";
|
|
7
|
-
import { pickFieldA11y, useFieldIdentity } from "../../lib/field-a11y.js";
|
|
7
|
+
import { pickFieldA11y, useFieldIdentity, useMirroredInputAttributes } from "../../lib/field-a11y.js";
|
|
8
8
|
import { Field } from "./field.js";
|
|
9
9
|
import { choiceGroupClassName } from "./choice-option.js";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
function checkedState(isSelected) {
|
|
11
|
+
return isSelected ? "checked" : "unchecked";
|
|
12
|
+
}
|
|
13
|
+
function useFieldKeyedInput(fieldKey) {
|
|
14
|
+
const inputRef = React.useRef(null);
|
|
15
|
+
useMirroredInputAttributes(inputRef, { "data-field": fieldKey });
|
|
16
|
+
return inputRef;
|
|
17
|
+
}
|
|
18
|
+
const RadioGroupRoot = React.forwardRef(
|
|
19
|
+
({ className, value, defaultValue, onValueChange, disabled, required, orientation, ...props }, ref) => {
|
|
20
|
+
const invalid = props["aria-invalid"];
|
|
21
|
+
const { "aria-label": ariaLabel, ...rest } = props;
|
|
22
|
+
return /* @__PURE__ */ jsx(
|
|
23
|
+
AriaRadioGroup,
|
|
24
|
+
{
|
|
25
|
+
ref,
|
|
26
|
+
"data-slot": "radio-group",
|
|
27
|
+
className: cn("ui-choice-group", className),
|
|
28
|
+
value,
|
|
29
|
+
defaultValue,
|
|
30
|
+
onChange: onValueChange,
|
|
31
|
+
isDisabled: disabled,
|
|
32
|
+
isRequired: required,
|
|
33
|
+
isInvalid: invalid !== void 0 && invalid !== false && invalid !== "false",
|
|
34
|
+
orientation,
|
|
35
|
+
"aria-label": props["aria-labelledby"] ? void 0 : ariaLabel,
|
|
36
|
+
...rest
|
|
37
|
+
}
|
|
38
|
+
);
|
|
17
39
|
}
|
|
18
|
-
)
|
|
19
|
-
RadioGroupRoot.displayName =
|
|
20
|
-
const RadioItem = React.forwardRef(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// `.ui-radio:disabled, .ui-radio[data-disabled]` in styles/control.css already declares both
|
|
27
|
-
// and reads --disabled-opacity. The utility was layered after components, so it silently
|
|
28
|
-
// outranked that token — a service theme's --disabled-opacity never reached a radio.
|
|
29
|
-
// Byte-identical: --disabled-opacity defaults to 0.5.
|
|
30
|
-
"ui-radio aria-invalid:border-destructive shrink-0 shadow-xs transition-shadow outline-none",
|
|
31
|
-
className
|
|
32
|
-
),
|
|
33
|
-
...props,
|
|
34
|
-
children: /* @__PURE__ */ jsx(
|
|
35
|
-
RadioGroupPrimitive.Indicator,
|
|
40
|
+
);
|
|
41
|
+
RadioGroupRoot.displayName = "RadioGroup";
|
|
42
|
+
const RadioItem = React.forwardRef(
|
|
43
|
+
({ className, disabled, value, ...props }, ref) => {
|
|
44
|
+
const { "data-field": fieldKey } = props;
|
|
45
|
+
const inputRef = useFieldKeyedInput(fieldKey);
|
|
46
|
+
return /* @__PURE__ */ jsx(
|
|
47
|
+
AriaRadio,
|
|
36
48
|
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
49
|
+
ref,
|
|
50
|
+
inputRef,
|
|
51
|
+
value,
|
|
52
|
+
isDisabled: disabled,
|
|
53
|
+
"data-slot": "radio-group-item",
|
|
54
|
+
className: cn(
|
|
55
|
+
// `.ui-radio:disabled, .ui-radio[data-disabled]` in styles/control.css already declares both
|
|
56
|
+
// and reads --disabled-opacity. The utility was layered after components, so it silently
|
|
57
|
+
// outranked that token — a service theme's --disabled-opacity never reached a radio.
|
|
58
|
+
// Byte-identical: --disabled-opacity defaults to 0.5.
|
|
59
|
+
//
|
|
60
|
+
// `inline-flex items-center justify-center` is load-bearing, for the reason Checkbox
|
|
61
|
+
// records: react-aria's root is a `<label>`, which is `display:inline`, so without it the
|
|
62
|
+
// 16px dot collapses to nothing. `data-[invalid]` replaces `aria-invalid:` because
|
|
63
|
+
// react-aria puts `aria-invalid` on the `<input>` and `data-invalid` on this box.
|
|
64
|
+
"ui-radio data-[invalid]:border-destructive inline-flex shrink-0 items-center justify-center shadow-xs transition-shadow outline-none",
|
|
65
|
+
className
|
|
66
|
+
),
|
|
67
|
+
...props,
|
|
68
|
+
render: (domProps, state) => /* @__PURE__ */ jsx("label", { ...domProps, "data-state": checkedState(state.isSelected) }),
|
|
69
|
+
children: /* @__PURE__ */ jsx("span", { "data-slot": "radio-group-indicator", className: "ui-choice-indicator", children: /* @__PURE__ */ jsx(Circle, { className: "ui-radio-icon", "aria-hidden": "true" }) })
|
|
40
70
|
}
|
|
41
|
-
)
|
|
71
|
+
);
|
|
42
72
|
}
|
|
43
|
-
)
|
|
44
|
-
RadioItem.displayName =
|
|
73
|
+
);
|
|
74
|
+
RadioItem.displayName = "Radio";
|
|
75
|
+
function RadioBarButton({
|
|
76
|
+
id,
|
|
77
|
+
option,
|
|
78
|
+
resolvedField
|
|
79
|
+
}) {
|
|
80
|
+
const inputRef = useFieldKeyedInput(resolvedField);
|
|
81
|
+
return /* @__PURE__ */ jsx(
|
|
82
|
+
AriaRadio,
|
|
83
|
+
{
|
|
84
|
+
id,
|
|
85
|
+
inputRef,
|
|
86
|
+
value: option.value,
|
|
87
|
+
isDisabled: option.disabled,
|
|
88
|
+
"data-slot": "radio-button",
|
|
89
|
+
className: "ui-radio-button ui-focus-ring",
|
|
90
|
+
render: (domProps, state) => /* @__PURE__ */ jsx("label", { ...domProps, "data-state": checkedState(state.isSelected) }),
|
|
91
|
+
children: /* @__PURE__ */ jsx("span", { className: "ui-radio-button-label", children: option.label })
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
}
|
|
45
95
|
function RadioButtonBar({
|
|
46
96
|
options,
|
|
47
|
-
value,
|
|
48
97
|
optionDomId,
|
|
49
98
|
resolvedField
|
|
50
99
|
}) {
|
|
51
100
|
return /* @__PURE__ */ jsx(Fragment, { children: options.map((opt, index) => /* @__PURE__ */ jsx(
|
|
52
|
-
|
|
101
|
+
RadioBarButton,
|
|
53
102
|
{
|
|
54
103
|
id: optionDomId(opt.value, index),
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"data-slot": "radio-button",
|
|
58
|
-
"data-field": resolvedField,
|
|
59
|
-
"data-state": value === opt.value ? "checked" : "unchecked",
|
|
60
|
-
className: "ui-radio-button ui-focus-ring",
|
|
61
|
-
children: /* @__PURE__ */ jsx("span", { className: "ui-radio-button-label", children: opt.label })
|
|
104
|
+
option: opt,
|
|
105
|
+
resolvedField
|
|
62
106
|
},
|
|
63
107
|
opt.value
|
|
64
108
|
)) });
|
|
@@ -94,6 +138,7 @@ function RadioGroupOptions({
|
|
|
94
138
|
disabled,
|
|
95
139
|
name: resolvedName,
|
|
96
140
|
id,
|
|
141
|
+
orientation,
|
|
97
142
|
...groupA11y,
|
|
98
143
|
"data-field": resolvedField,
|
|
99
144
|
"data-orientation": orientation,
|
|
@@ -108,7 +153,6 @@ function RadioGroupOptions({
|
|
|
108
153
|
RadioButtonBar,
|
|
109
154
|
{
|
|
110
155
|
options,
|
|
111
|
-
value,
|
|
112
156
|
optionDomId,
|
|
113
157
|
resolvedField
|
|
114
158
|
}
|
|
@@ -147,6 +191,7 @@ function RadioGroupOptions({
|
|
|
147
191
|
disabled,
|
|
148
192
|
name: resolvedName,
|
|
149
193
|
id,
|
|
194
|
+
orientation,
|
|
150
195
|
...groupA11y,
|
|
151
196
|
"data-field": resolvedField,
|
|
152
197
|
"data-orientation": orientation,
|
|
@@ -36,6 +36,7 @@ function SearchSelect(props) {
|
|
|
36
36
|
size,
|
|
37
37
|
status,
|
|
38
38
|
variant,
|
|
39
|
+
width = "full",
|
|
39
40
|
loading: loadingProp = false,
|
|
40
41
|
open: openProp,
|
|
41
42
|
defaultOpen = false,
|
|
@@ -334,9 +335,15 @@ function SearchSelect(props) {
|
|
|
334
335
|
"data-field": resolvedField,
|
|
335
336
|
"data-value": (multiple ? values.join(",") : value) || void 0,
|
|
336
337
|
"data-mode": multiple ? "multiple" : void 0,
|
|
338
|
+
"data-width": width,
|
|
337
339
|
className: cn(
|
|
338
340
|
controlSurfaceTriggerClass,
|
|
339
|
-
"
|
|
341
|
+
"justify-start",
|
|
342
|
+
// `bounded` deliberately emits NO width utility — its width is owned by the
|
|
343
|
+
// `[data-width="bounded"]` rule in control.css, and a utility here would win the
|
|
344
|
+
// layer order and make that token dead. Same reasoning as SelectTrigger.
|
|
345
|
+
width === "auto" && "w-auto",
|
|
346
|
+
width === "full" && "w-full",
|
|
340
347
|
// Reserve trailing room for the single clear-or-chevron overlay rendered below.
|
|
341
348
|
"ui-control-trigger-affixed"
|
|
342
349
|
),
|
|
@@ -298,6 +298,7 @@ function DataSelect(props) {
|
|
|
298
298
|
size,
|
|
299
299
|
status,
|
|
300
300
|
variant,
|
|
301
|
+
width,
|
|
301
302
|
loading,
|
|
302
303
|
open,
|
|
303
304
|
defaultOpen,
|
|
@@ -372,6 +373,7 @@ function DataSelect(props) {
|
|
|
372
373
|
size,
|
|
373
374
|
variant,
|
|
374
375
|
status,
|
|
376
|
+
width,
|
|
375
377
|
"aria-busy": loading || void 0,
|
|
376
378
|
className: cn(
|
|
377
379
|
(showClear || loading) && "ui-control-trigger-affixed",
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as SwitchPrimitive from "@radix-ui/react-switch";
|
|
3
2
|
export type { SwitchProp, SwitchProp as SwitchProps } from "../../props/components/data-entry.prop.js";
|
|
4
|
-
export declare const Switch: React.ForwardRefExoticComponent<Omit<
|
|
3
|
+
export declare const Switch: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref">, "checked" | "defaultChecked" | "onChange" | "value"> & {
|
|
4
|
+
checked?: boolean;
|
|
5
|
+
defaultChecked?: boolean;
|
|
6
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
7
|
+
required?: boolean;
|
|
5
8
|
size?: "sm" | "md";
|
|
6
9
|
loading?: boolean;
|
|
7
10
|
checkedChildren?: React.ReactNode;
|
|
8
11
|
unCheckedChildren?: React.ReactNode;
|
|
9
|
-
} & React.RefAttributes<
|
|
12
|
+
} & React.RefAttributes<HTMLLabelElement>>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import
|
|
4
|
+
import { Switch as AriaSwitch } from "react-aria-components";
|
|
5
5
|
import { Loader2 } from "lucide-react";
|
|
6
6
|
import { cn } from "../../lib/utils.js";
|
|
7
|
-
import { useFieldIdentity } from "../../lib/field-a11y.js";
|
|
7
|
+
import { useFieldIdentity, useMirroredInputAttributes } from "../../lib/field-a11y.js";
|
|
8
8
|
const Switch = React.forwardRef(
|
|
9
9
|
({
|
|
10
10
|
className,
|
|
@@ -16,6 +16,8 @@ const Switch = React.forwardRef(
|
|
|
16
16
|
loading = false,
|
|
17
17
|
checkedChildren,
|
|
18
18
|
unCheckedChildren,
|
|
19
|
+
disabled,
|
|
20
|
+
required,
|
|
19
21
|
...props
|
|
20
22
|
}, ref) => {
|
|
21
23
|
const identity = useFieldIdentity({
|
|
@@ -34,19 +36,42 @@ const Switch = React.forwardRef(
|
|
|
34
36
|
}
|
|
35
37
|
onCheckedChange?.(next);
|
|
36
38
|
};
|
|
39
|
+
const ownField = props["data-field"];
|
|
40
|
+
const fieldKey = ownField ?? identity["data-field"];
|
|
41
|
+
const invalid = props["aria-invalid"];
|
|
42
|
+
const isInvalid = invalid !== void 0 && invalid !== false && invalid !== "false";
|
|
43
|
+
const inputRef = React.useRef(null);
|
|
44
|
+
useMirroredInputAttributes(inputRef, {
|
|
45
|
+
"aria-invalid": isInvalid ? "true" : void 0,
|
|
46
|
+
"aria-busy": loading ? "true" : void 0,
|
|
47
|
+
"aria-disabled": loading ? "true" : void 0,
|
|
48
|
+
// react-aria's `Switch` Omits `isRequired`, and a switch is never the target of native
|
|
49
|
+
// constraint validation in this library — the form layer owns that. The prop is accepted
|
|
50
|
+
// for shape and announced through `aria-required`.
|
|
51
|
+
"aria-required": required ? "true" : void 0,
|
|
52
|
+
"data-field": fieldKey
|
|
53
|
+
});
|
|
54
|
+
const state = isChecked ? "checked" : "unchecked";
|
|
37
55
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38
56
|
resolvedName ? /* @__PURE__ */ jsx("input", { type: "hidden", name: resolvedName, value: isChecked ? "1" : "0", readOnly: true }) : null,
|
|
39
57
|
/* @__PURE__ */ jsxs(
|
|
40
|
-
|
|
58
|
+
AriaSwitch,
|
|
41
59
|
{
|
|
60
|
+
...props,
|
|
42
61
|
ref,
|
|
62
|
+
inputRef,
|
|
43
63
|
"data-slot": "switch",
|
|
44
64
|
"data-size": size,
|
|
65
|
+
"data-state": state,
|
|
45
66
|
"data-loading": loading ? "true" : void 0,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
67
|
+
isSelected: isChecked,
|
|
68
|
+
isDisabled: disabled,
|
|
69
|
+
onChange: handleCheckedChange,
|
|
70
|
+
onKeyDown: (event) => {
|
|
71
|
+
if (event.key !== "Enter") return;
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
handleCheckedChange(!isChecked);
|
|
74
|
+
},
|
|
50
75
|
className: cn(
|
|
51
76
|
// `.ui-switch:disabled, .ui-switch[data-disabled]` in styles/control.css already
|
|
52
77
|
// declares both and reads --disabled-opacity. The utility was layered after
|
|
@@ -56,11 +81,9 @@ const Switch = React.forwardRef(
|
|
|
56
81
|
"peer ui-switch shadow-xs transition-all outline-none",
|
|
57
82
|
className
|
|
58
83
|
),
|
|
59
|
-
...props,
|
|
60
|
-
"data-field": identity["data-field"] ?? props["data-field"],
|
|
61
84
|
children: [
|
|
62
85
|
checkedChildren != null || unCheckedChildren != null ? /* @__PURE__ */ jsx("span", { "data-slot": "switch-content", className: "ui-switch-content", "aria-hidden": "true", children: isChecked ? checkedChildren : unCheckedChildren }) : null,
|
|
63
|
-
/* @__PURE__ */ jsx(
|
|
86
|
+
/* @__PURE__ */ jsx("span", { "data-slot": "switch-thumb", "data-state": state, className: "ui-switch-thumb", children: loading ? /* @__PURE__ */ jsx(
|
|
64
87
|
Loader2,
|
|
65
88
|
{
|
|
66
89
|
"data-slot": "switch-spinner",
|
|
@@ -74,7 +97,7 @@ const Switch = React.forwardRef(
|
|
|
74
97
|
] });
|
|
75
98
|
}
|
|
76
99
|
);
|
|
77
|
-
Switch.displayName =
|
|
100
|
+
Switch.displayName = "Switch";
|
|
78
101
|
export {
|
|
79
102
|
Switch
|
|
80
103
|
};
|
|
@@ -18,4 +18,4 @@ export type { MobileShellProp, MobileShellProp as MobileShellProps, } from "../.
|
|
|
18
18
|
* IS the app's primary navigation). They are the same strings in all three locales, and a fourth
|
|
19
19
|
* identical copy under `layout.mobileShell.*` would be three files of duplication to keep in sync.
|
|
20
20
|
*/
|
|
21
|
-
export declare function MobileShell({ statusBar, header, children, actions, tabBar, height, className, }: MobileShellProp): import("react").JSX.Element;
|
|
21
|
+
export declare function MobileShell({ statusBar, header, children, actions, tabBar, height, width, className, }: MobileShellProp): import("react").JSX.Element;
|
|
@@ -9,6 +9,7 @@ function MobileShell({
|
|
|
9
9
|
actions,
|
|
10
10
|
tabBar,
|
|
11
11
|
height = "viewport",
|
|
12
|
+
width = "fill",
|
|
12
13
|
className
|
|
13
14
|
}) {
|
|
14
15
|
const { t } = useTranslation();
|
|
@@ -17,6 +18,7 @@ function MobileShell({
|
|
|
17
18
|
{
|
|
18
19
|
"data-slot": "mobile-shell",
|
|
19
20
|
"data-height": height === "viewport" ? void 0 : height,
|
|
21
|
+
"data-width": width === "fill" ? void 0 : width,
|
|
20
22
|
className: cn("ui-mobile-shell", className),
|
|
21
23
|
children: [
|
|
22
24
|
(statusBar !== void 0 || header !== void 0) && /* @__PURE__ */ jsxs("header", { className: "ui-mobile-shell-chrome", "aria-label": t("layout.appShell.headerLabel"), children: [
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as MenubarPrimitive from "@radix-ui/react-menubar";
|
|
3
3
|
export declare const Menubar: React.ForwardRefExoticComponent<MenubarPrimitive.MenubarProps & React.RefAttributes<HTMLDivElement>>;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Annotated rather than inferred, and that is load-bearing.
|
|
6
|
+
*
|
|
7
|
+
* Radix types this one through `createContextScope`, so its INFERRED type reaches into
|
|
8
|
+
* `@radix-ui/react-context` for a `Scope` — and TypeScript then refuses to emit a declaration it
|
|
9
|
+
* cannot name portably (TS2883) unless that package is a DIRECT dependency. It was one, purely to
|
|
10
|
+
* satisfy this line: nothing in the tree ever imported it. Naming the props here severs that,
|
|
11
|
+
* which is what let the dependency go.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MenubarMenu: (props: React.ComponentProps<typeof MenubarPrimitive.Menu>) => React.ReactNode;
|
|
7
14
|
export declare function MenubarTrigger(props: React.ComponentProps<typeof MenubarPrimitive.Trigger>): React.JSX.Element;
|
|
8
15
|
export declare const MenubarContent: React.ForwardRefExoticComponent<Omit<MenubarPrimitive.MenubarContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
9
16
|
export declare const MenubarItem: React.ForwardRefExoticComponent<Omit<MenubarPrimitive.MenubarItemProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { StepsProp } from "../../props/components/navigation.prop.js";
|
|
3
3
|
export type { StepsProp, StepsProp as StepsProps, StepItemProp, StepStatusProp, StepsSeparatorProp, StepsTypeProp, } from "../../props/components/navigation.prop.js";
|
|
4
|
-
export declare function Steps({ items, value: current, defaultValue, status: currentStatus, orientation, type, size, titlePlacement, separator, percent, onValueChange, className, }: StepsProp): React.JSX.Element;
|
|
4
|
+
export declare function Steps({ items, value: current, defaultValue, status: currentStatus, orientation, type, size, titlePlacement, separator, percent, onValueChange, className, ...props }: StepsProp): React.JSX.Element;
|
|
@@ -50,7 +50,8 @@ function Steps({
|
|
|
50
50
|
separator = "chevron",
|
|
51
51
|
percent,
|
|
52
52
|
onValueChange,
|
|
53
|
-
className
|
|
53
|
+
className,
|
|
54
|
+
...props
|
|
54
55
|
}) {
|
|
55
56
|
const { t } = useTranslation();
|
|
56
57
|
const base = defaultValue;
|
|
@@ -69,6 +70,7 @@ function Steps({
|
|
|
69
70
|
"data-type": type,
|
|
70
71
|
className: cn("flex w-full", inline ? "ui-steps-inline" : "ui-steps-list", className),
|
|
71
72
|
"aria-label": t("navigation.steps.ariaLabel"),
|
|
73
|
+
...props,
|
|
72
74
|
children: items.map((item, index) => {
|
|
73
75
|
const absoluteIndex = base + index;
|
|
74
76
|
const stepStatus = resolveStepStatus(absoluteIndex, current, item.status, currentStatus);
|
|
@@ -34,3 +34,30 @@ export declare function syncActiveTabIntoView(list: HTMLElement | null, behavior
|
|
|
34
34
|
* pre-fix behaviour instead of throwing.
|
|
35
35
|
*/
|
|
36
36
|
export declare function useKeepActiveTabVisible(listRef: React.RefObject<HTMLElement | null>): void;
|
|
37
|
+
/**
|
|
38
|
+
* The values of the triggers that are NOT fully inside the strip's scrollport, in document order.
|
|
39
|
+
*
|
|
40
|
+
* Pure apart from the two rect reads — `values` is the `items` array's own order, and the triggers
|
|
41
|
+
* are matched to it by INDEX rather than by DOM id: `TabsTrigger` hands its `value` to React Aria
|
|
42
|
+
* as the collection KEY, and the rendered `id` attribute is RAC-generated, so the element carries
|
|
43
|
+
* no readable handle back to the item it came from.
|
|
44
|
+
*
|
|
45
|
+
* This is the measurement behind `overflow="menu"`. It is separated from the hook below so it can
|
|
46
|
+
* be exercised on plain numbers — jsdom lays nothing out, so the only honest unit assertions about
|
|
47
|
+
* it are the ones that hand it real geometry.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveHiddenTabValues(list: HTMLElement, values: readonly string[]): string[];
|
|
50
|
+
/**
|
|
51
|
+
* Keeps `onChange` fed with the values currently out of the scrollport, recomputing on the two
|
|
52
|
+
* things that can move them: the strip resizing (a viewport change, a font swap, a tab added or
|
|
53
|
+
* removed) and the strip scrolling (the user swiping, or `useKeepActiveTabVisible` re-pinning a
|
|
54
|
+
* trigger).
|
|
55
|
+
*
|
|
56
|
+
* `values` is joined into the effect key rather than passed as a dependency, so a consumer that
|
|
57
|
+
* rebuilds its `items` array on every render does not re-arm the observers on every render.
|
|
58
|
+
*
|
|
59
|
+
* The first measurement ALWAYS reports, even when nothing is hidden. Suppressing it looks harmless
|
|
60
|
+
* and is not: on a remount the local `last` resets while the caller's state does not, so a strip
|
|
61
|
+
* that had overflowed and then stopped would keep a stale menu forever.
|
|
62
|
+
*/
|
|
63
|
+
export declare function useTabsOverflowValues(listRef: React.RefObject<HTMLElement | null>, values: readonly string[] | undefined, onChange: (hidden: string[]) => void): void;
|