@godxjp/ui 18.15.4 → 19.1.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.d.ts +1 -1
- package/dist/app/app-provider.js +3 -0
- package/dist/app/date-format-labels.d.ts +1 -1
- package/dist/app/time-format-labels.d.ts +1 -1
- package/dist/components/data-display/badge.d.ts +1 -1
- package/dist/components/data-display/card.d.ts +4 -13
- package/dist/components/data-display/card.js +2 -15
- package/dist/components/data-display/data-table.d.ts +3 -8
- package/dist/components/data-display/data-table.js +106 -68
- package/dist/components/data-display/descriptions.js +34 -5
- package/dist/components/data-display/empty-state.js +1 -1
- package/dist/components/data-display/permission-matrix.js +7 -7
- package/dist/components/data-display/popover.js +2 -9
- package/dist/components/data-display/qr-code.d.ts +1 -1
- package/dist/components/data-display/scroll-area.d.ts +3 -1
- package/dist/components/data-display/scroll-area.js +150 -16
- package/dist/components/data-display/table.js +12 -3
- package/dist/components/data-entry/branch-scope-picker.js +4 -4
- package/dist/components/data-entry/calendar.js +15 -24
- package/dist/components/data-entry/cascader.js +70 -72
- package/dist/components/data-entry/checkbox-group.js +12 -5
- package/dist/components/data-entry/checkbox.js +30 -13
- package/dist/components/data-entry/command.d.ts +6 -6
- package/dist/components/data-entry/date-picker.js +34 -17
- package/dist/components/data-entry/date-range-picker.js +19 -13
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +22 -5
- package/dist/components/data-entry/index.d.ts +2 -1
- package/dist/components/data-entry/input.js +18 -22
- package/dist/components/data-entry/label.js +4 -2
- package/dist/components/data-entry/month-picker.js +20 -17
- package/dist/components/data-entry/month-range-picker.js +26 -19
- package/dist/components/data-entry/radio.js +25 -6
- package/dist/components/data-entry/search-select.d.ts +1 -1
- package/dist/components/data-entry/search-select.js +37 -31
- package/dist/components/data-entry/select.d.ts +8 -0
- package/dist/components/data-entry/select.js +68 -26
- package/dist/components/data-entry/switch.js +16 -2
- package/dist/components/data-entry/textarea.d.ts +56 -0
- package/dist/components/data-entry/textarea.js +110 -40
- package/dist/components/data-entry/time-picker.js +52 -52
- package/dist/components/data-entry/toggle-group.d.ts +1 -0
- package/dist/components/data-entry/toggle.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +14 -15
- package/dist/components/data-entry/tree-select.js +19 -23
- package/dist/components/data-entry/upload-crop-dialog.js +4 -4
- package/dist/components/data-entry/upload.d.ts +1 -1
- package/dist/components/data-entry/upload.js +46 -46
- package/dist/components/feedback/alert.js +7 -14
- package/dist/components/feedback/dialog.d.ts +23 -32
- package/dist/components/feedback/dialog.js +16 -13
- package/dist/components/feedback/sheet.d.ts +1 -1
- package/dist/components/feedback/sheet.js +14 -14
- package/dist/components/feedback/skeleton.js +13 -10
- package/dist/components/feedback/sonner.d.ts +1 -1
- package/dist/components/feedback/sonner.js +17 -8
- package/dist/components/feedback/tooltip.js +1 -1
- package/dist/components/general/activity.d.ts +44 -0
- package/dist/components/general/activity.js +65 -0
- package/dist/components/general/button.d.ts +2 -2
- package/dist/components/general/button.js +11 -24
- package/dist/components/general/index.d.ts +2 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/layout/app-shell.js +5 -3
- package/dist/components/layout/auth-divider.d.ts +9 -2
- package/dist/components/layout/auth-divider.js +7 -11
- package/dist/components/layout/index.d.ts +1 -0
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +32 -20
- package/dist/components/layout/resizable.d.ts +12 -12
- package/dist/components/layout/separator.d.ts +1 -0
- package/dist/components/layout/service-role-panel.js +47 -42
- package/dist/components/layout/sidebar.js +13 -1
- package/dist/components/layout/split-pane.d.ts +12 -1
- package/dist/components/layout/split-pane.js +13 -4
- package/dist/components/navigation/app-setting-picker.js +5 -14
- package/dist/components/navigation/dropdown-menu.js +10 -16
- package/dist/components/navigation/menubar.d.ts +3 -6
- package/dist/components/navigation/pagination-utils.d.ts +15 -2
- package/dist/components/navigation/pagination-utils.js +27 -21
- package/dist/components/navigation/pagination.d.ts +4 -4
- package/dist/components/navigation/pagination.js +2 -2
- package/dist/components/navigation/steps.js +31 -67
- package/dist/components/navigation/tabs.js +17 -5
- package/dist/components/query/infinite-query-state.js +2 -2
- package/dist/components/ui/accordion.d.ts +1 -1
- package/dist/components/ui/avatar.d.ts +1 -1
- package/dist/components/ui/avatar.js +29 -10
- package/dist/components/ui/input-otp.d.ts +8 -6
- package/dist/components/ui/rating.js +1 -1
- package/dist/components/ui/separator.d.ts +27 -2
- package/dist/components/ui/separator.js +42 -11
- package/dist/components/ui/toggle-group.d.ts +15 -5
- package/dist/components/ui/toggle-group.js +43 -18
- package/dist/components/ui/toggle.d.ts +66 -5
- package/dist/components/ui/toggle.js +64 -9
- package/dist/i18n/messages/en.json +8 -0
- package/dist/i18n/messages/ja.json +8 -0
- package/dist/i18n/messages/vi.json +8 -0
- package/dist/lib/control-styles.d.ts +14 -0
- package/dist/lib/control-styles.js +2 -0
- package/dist/lib/field-a11y.d.ts +52 -0
- package/dist/lib/field-a11y.js +17 -2
- package/dist/props/components/app.prop.d.ts +15 -0
- package/dist/props/components/data-display.prop.d.ts +85 -3
- package/dist/props/components/data-entry.prop.d.ts +35 -2
- package/dist/props/components/general.prop.d.ts +52 -1
- package/dist/props/components/layout.prop.d.ts +137 -2
- package/dist/props/registry.d.ts +116 -5
- package/dist/props/registry.js +165 -4
- package/dist/props/vocabulary/index.d.ts +2 -2
- package/dist/props/vocabulary/interaction.prop.d.ts +15 -0
- package/dist/props/vocabulary/layout.prop.d.ts +8 -0
- package/dist/styles/alert-layout.css +69 -3
- package/dist/styles/badge-layout.css +2 -2
- package/dist/styles/base.css +6 -0
- package/dist/styles/card-layout.css +25 -8
- package/dist/styles/control.css +1150 -29
- package/dist/styles/data-display-layout.css +185 -11
- package/dist/styles/data-entry-layout.css +352 -1
- package/dist/styles/density.css +2 -2
- package/dist/styles/dialog-layout.css +203 -4
- package/dist/styles/focus-ring.css +155 -0
- package/dist/styles/form-layout.css +50 -5
- package/dist/styles/index.css +1 -0
- package/dist/styles/layout.css +412 -23
- package/dist/styles/motion.css +178 -0
- package/dist/styles/navigation-layout.css +398 -22
- package/dist/styles/shell-layout.css +137 -39
- package/dist/styles/table-layout.css +153 -22
- package/dist/styles/toggle.css +59 -0
- package/dist/tokens/base.css +5 -0
- package/dist/tokens/components/activity.css +64 -0
- package/dist/tokens/components/badge.css +7 -0
- package/dist/tokens/components/card.css +14 -10
- package/dist/tokens/components/chart.css +1 -1
- package/dist/tokens/components/control.css +358 -8
- package/dist/tokens/components/data-display.css +75 -0
- package/dist/tokens/components/data-entry.css +25 -0
- package/dist/tokens/components/descriptions.css +22 -0
- package/dist/tokens/components/feedback.css +143 -4
- package/dist/tokens/components/form.css +16 -0
- package/dist/tokens/components/legal-document.css +5 -1
- package/dist/tokens/components/navigation.css +109 -0
- package/dist/tokens/components/scroll-area.css +21 -0
- package/dist/tokens/components/separator.css +52 -0
- package/dist/tokens/components/shell.css +132 -20
- package/dist/tokens/components/table.css +52 -3
- package/dist/tokens/components/toggle.css +82 -0
- package/dist/tokens/components/upload.css +107 -0
- package/dist/tokens/foundation.css +171 -10
- package/dist/tokens/semantic/layout.css +120 -1
- package/package.json +85 -68
- package/scripts/ui-audit.mjs +51 -2
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "../../lib/utils.js";
|
|
5
|
-
import { pickGroupFieldA11y } from "../../lib/field-a11y.js";
|
|
5
|
+
import { pickGroupFieldA11y, useFieldIdentity } from "../../lib/field-a11y.js";
|
|
6
6
|
import { Checkbox } from "./checkbox.js";
|
|
7
7
|
import { Field } from "./field.js";
|
|
8
8
|
import { choiceGroupClassName } from "./choice-option.js";
|
|
@@ -33,6 +33,10 @@ function CheckboxGroup({
|
|
|
33
33
|
const reactId = React.useId();
|
|
34
34
|
const [value, setValue] = useControllableArray(controlledValue, defaultValue);
|
|
35
35
|
const groupA11y = pickGroupFieldA11y(ariaProps);
|
|
36
|
+
const identity = useFieldIdentity({ id, name, "data-field": groupA11y["data-field"] });
|
|
37
|
+
const resolvedName = name ?? identity.name;
|
|
38
|
+
const resolvedField = groupA11y["data-field"] ?? identity["data-field"];
|
|
39
|
+
const optionDomId = (optionValue, index) => id ? `${id}-${optionValue}` : `${reactId}-${optionValue}-${index}`;
|
|
36
40
|
const toggle = (optionValue) => {
|
|
37
41
|
const next = value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue];
|
|
38
42
|
setValue(next);
|
|
@@ -45,17 +49,19 @@ function CheckboxGroup({
|
|
|
45
49
|
role: "group",
|
|
46
50
|
id,
|
|
47
51
|
...groupA11y,
|
|
52
|
+
"data-field": resolvedField,
|
|
48
53
|
"aria-disabled": disabled ? true : void 0,
|
|
49
54
|
"data-orientation": orientation,
|
|
50
55
|
className: choiceGroupClassName(orientation, className),
|
|
51
56
|
children: options.map((opt, index) => {
|
|
52
|
-
const
|
|
57
|
+
const optionId = optionDomId(opt.value, index);
|
|
53
58
|
const checked = value.includes(opt.value);
|
|
54
|
-
return /* @__PURE__ */ jsx(Field, { id:
|
|
59
|
+
return /* @__PURE__ */ jsx(Field, { id: optionId, label: opt.label, description: opt.description, children: /* @__PURE__ */ jsx(
|
|
55
60
|
Checkbox,
|
|
56
61
|
{
|
|
57
|
-
id:
|
|
58
|
-
name,
|
|
62
|
+
id: optionId,
|
|
63
|
+
name: resolvedName,
|
|
64
|
+
"data-field": resolvedField,
|
|
59
65
|
value: opt.value,
|
|
60
66
|
checked,
|
|
61
67
|
disabled: Boolean(disabled) || Boolean(opt.disabled),
|
|
@@ -74,6 +80,7 @@ function CheckboxGroup({
|
|
|
74
80
|
role: "group",
|
|
75
81
|
id,
|
|
76
82
|
...groupA11y,
|
|
83
|
+
"data-field": resolvedField,
|
|
77
84
|
"aria-disabled": disabled ? true : void 0,
|
|
78
85
|
"data-orientation": orientation,
|
|
79
86
|
className: cn(choiceGroupClassName(orientation), className),
|
|
@@ -4,20 +4,37 @@ import * as React from "react";
|
|
|
4
4
|
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
5
5
|
import { Check } from "lucide-react";
|
|
6
6
|
import { cn } from "../../lib/utils.js";
|
|
7
|
+
import { useFieldIdentity } from "../../lib/field-a11y.js";
|
|
7
8
|
import { CheckboxGroup } from "./checkbox-group.js";
|
|
8
|
-
const CheckboxRoot = React.forwardRef(({ className, ...props }, ref) =>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"data-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
const CheckboxRoot = React.forwardRef(({ className, ...props }, ref) => {
|
|
10
|
+
const identity = useFieldIdentity({
|
|
11
|
+
id: props.id,
|
|
12
|
+
name: props.name,
|
|
13
|
+
"data-field": props["data-field"]
|
|
14
|
+
});
|
|
15
|
+
return /* @__PURE__ */ jsx(
|
|
16
|
+
CheckboxPrimitive.Root,
|
|
17
|
+
{
|
|
18
|
+
ref,
|
|
19
|
+
"data-slot": "checkbox",
|
|
20
|
+
className: cn(
|
|
21
|
+
// `disabled:cursor-not-allowed disabled:opacity-50` and the checked fill are DELETED, not
|
|
22
|
+
// moved (#319): `.ui-checkbox:disabled, .ui-checkbox[data-disabled]` and
|
|
23
|
+
// `.ui-checkbox[data-state="checked"]` in styles/control.css already declare both, reading
|
|
24
|
+
// --disabled-opacity and --checkbox-checked-background. Utilities are layered AFTER
|
|
25
|
+
// components in Tailwind v4, so these literals were silently OUTRANKING those knobs — a
|
|
26
|
+
// service overriding --checkbox-checked-background got no fill change at all. Radix sets
|
|
27
|
+
// `data-state`/`data-disabled` on the root, so the CSS rules match. Rendering is unchanged:
|
|
28
|
+
// both knobs default to exactly the values these utilities hard-coded.
|
|
29
|
+
"peer ui-checkbox aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:text-primary-foreground shrink-0 shadow-xs transition-shadow outline-none",
|
|
30
|
+
className
|
|
31
|
+
),
|
|
32
|
+
...props,
|
|
33
|
+
...identity,
|
|
34
|
+
children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { "data-slot": "checkbox-indicator", className: "ui-choice-indicator", children: /* @__PURE__ */ jsx(Check, { className: "ui-checkbox-icon", "aria-hidden": "true" }) })
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
});
|
|
21
38
|
CheckboxRoot.displayName = CheckboxPrimitive.Root.displayName;
|
|
22
39
|
const Checkbox = Object.assign(CheckboxRoot, {
|
|
23
40
|
Group: CheckboxGroup
|
|
@@ -5,7 +5,7 @@ export declare const Command: React.ForwardRefExoticComponent<Omit<{
|
|
|
5
5
|
ref?: React.Ref<HTMLDivElement>;
|
|
6
6
|
} & {
|
|
7
7
|
asChild?: boolean;
|
|
8
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
8
|
+
}, "asChild" | "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
|
|
9
9
|
label?: string;
|
|
10
10
|
shouldFilter?: boolean;
|
|
11
11
|
filter?: (value: string, search: string, keywords?: string[]) => number;
|
|
@@ -20,7 +20,7 @@ export declare const CommandInput: React.ForwardRefExoticComponent<Omit<Omit<Pic
|
|
|
20
20
|
ref?: React.Ref<HTMLInputElement>;
|
|
21
21
|
} & {
|
|
22
22
|
asChild?: boolean;
|
|
23
|
-
}, "
|
|
23
|
+
}, "asChild" | "key" | keyof React.InputHTMLAttributes<HTMLInputElement>>, "onChange" | "type" | "value"> & {
|
|
24
24
|
value?: string;
|
|
25
25
|
onValueChange?: (search: string) => void;
|
|
26
26
|
} & React.RefAttributes<HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -30,7 +30,7 @@ export declare const CommandList: React.ForwardRefExoticComponent<Omit<{
|
|
|
30
30
|
ref?: React.Ref<HTMLDivElement>;
|
|
31
31
|
} & {
|
|
32
32
|
asChild?: boolean;
|
|
33
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
33
|
+
}, "asChild" | "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
|
|
34
34
|
label?: string;
|
|
35
35
|
} & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
36
36
|
export declare const CommandEmpty: React.ForwardRefExoticComponent<Omit<{
|
|
@@ -39,14 +39,14 @@ export declare const CommandEmpty: React.ForwardRefExoticComponent<Omit<{
|
|
|
39
39
|
ref?: React.Ref<HTMLDivElement>;
|
|
40
40
|
} & {
|
|
41
41
|
asChild?: boolean;
|
|
42
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
42
|
+
}, "asChild" | "key" | keyof React.HTMLAttributes<HTMLDivElement>> & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
43
43
|
export declare const CommandGroup: React.ForwardRefExoticComponent<Omit<{
|
|
44
44
|
children?: React.ReactNode;
|
|
45
45
|
} & Omit<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
|
|
46
46
|
ref?: React.Ref<HTMLDivElement>;
|
|
47
47
|
} & {
|
|
48
48
|
asChild?: boolean;
|
|
49
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
49
|
+
}, "asChild" | "key" | keyof React.HTMLAttributes<HTMLDivElement>>, "heading" | "value"> & {
|
|
50
50
|
heading?: React.ReactNode;
|
|
51
51
|
value?: string;
|
|
52
52
|
forceMount?: boolean;
|
|
@@ -57,7 +57,7 @@ export declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
|
|
|
57
57
|
ref?: React.Ref<HTMLDivElement>;
|
|
58
58
|
} & {
|
|
59
59
|
asChild?: boolean;
|
|
60
|
-
}, "key" | keyof React.HTMLAttributes<HTMLDivElement
|
|
60
|
+
}, "asChild" | "key" | keyof React.HTMLAttributes<HTMLDivElement>>, "disabled" | "onSelect" | "value"> & {
|
|
61
61
|
disabled?: boolean;
|
|
62
62
|
onSelect?: (value: string) => void;
|
|
63
63
|
value?: string;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import { CalendarIcon } from "lucide-react";
|
|
4
|
+
import { CalendarIcon, X } from "lucide-react";
|
|
5
5
|
import { usePickerLocales, useTranslation } from "../../i18n/use-translation.js";
|
|
6
6
|
import { parseDateInput, toIsoDate } from "../../lib/datetime/parse.js";
|
|
7
7
|
import { useControlledLatch } from "../../lib/hooks.js";
|
|
8
|
-
import { pickFieldA11y } from "../../lib/field-a11y.js";
|
|
8
|
+
import { pickFieldA11y, useFieldIdentity } from "../../lib/field-a11y.js";
|
|
9
9
|
import { cn } from "../../lib/utils.js";
|
|
10
10
|
import { Input } from "./input.js";
|
|
11
11
|
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../data-display/popover.js";
|
|
@@ -30,6 +30,9 @@ function DatePicker({
|
|
|
30
30
|
const { dayPickerLocale } = usePickerLocales(localeProp);
|
|
31
31
|
const [open, setOpen] = React.useState(false);
|
|
32
32
|
const fieldA11y = pickFieldA11y(ariaProps);
|
|
33
|
+
const identity = useFieldIdentity({ id, name, "data-field": fieldA11y["data-field"] });
|
|
34
|
+
const resolvedName = name ?? identity.name;
|
|
35
|
+
const resolvedField = fieldA11y["data-field"] ?? identity["data-field"];
|
|
33
36
|
const reactId = React.useId();
|
|
34
37
|
const dialogId = `${id ?? reactId}-dialog`;
|
|
35
38
|
const isControlled = useControlledLatch(valueProp !== void 0);
|
|
@@ -48,6 +51,7 @@ function DatePicker({
|
|
|
48
51
|
emit(void 0);
|
|
49
52
|
setText("");
|
|
50
53
|
};
|
|
54
|
+
const showClear = allowClear && text !== "" && !disabled;
|
|
51
55
|
const commit = (raw) => {
|
|
52
56
|
const trimmed = raw.trim();
|
|
53
57
|
if (trimmed === "") {
|
|
@@ -65,7 +69,8 @@ function DatePicker({
|
|
|
65
69
|
Input,
|
|
66
70
|
{
|
|
67
71
|
id,
|
|
68
|
-
name,
|
|
72
|
+
name: resolvedName,
|
|
73
|
+
"data-field": resolvedField,
|
|
69
74
|
value: text,
|
|
70
75
|
disabled,
|
|
71
76
|
placeholder: resolvedPlaceholder,
|
|
@@ -76,19 +81,31 @@ function DatePicker({
|
|
|
76
81
|
"aria-haspopup": "dialog",
|
|
77
82
|
"aria-controls": open ? dialogId : void 0,
|
|
78
83
|
...fieldA11y,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
className: showClear ? "ui-control-inline-affix-pair-affixed" : void 0,
|
|
85
|
+
trailingIcon: /* @__PURE__ */ jsxs("span", { className: "ui-time-picker-affix", children: [
|
|
86
|
+
showClear ? /* @__PURE__ */ jsx(
|
|
87
|
+
"button",
|
|
88
|
+
{
|
|
89
|
+
type: "button",
|
|
90
|
+
tabIndex: -1,
|
|
91
|
+
"aria-label": t("common.clear") ?? "Clear",
|
|
92
|
+
onClick: clear,
|
|
93
|
+
className: "ui-control-inline-affix-action",
|
|
94
|
+
children: /* @__PURE__ */ jsx(X, { className: "ui-control-inline-affix-icon", "aria-hidden": "true" })
|
|
95
|
+
}
|
|
96
|
+
) : null,
|
|
97
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
98
|
+
"button",
|
|
99
|
+
{
|
|
100
|
+
type: "button",
|
|
101
|
+
disabled,
|
|
102
|
+
tabIndex: -1,
|
|
103
|
+
"aria-label": t("dataEntry.datePicker.openCalendar") ?? "Open calendar",
|
|
104
|
+
className: "ui-control-inline-affix-action",
|
|
105
|
+
children: /* @__PURE__ */ jsx(CalendarIcon, { className: "ui-control-inline-affix-icon", "aria-hidden": "true" })
|
|
106
|
+
}
|
|
107
|
+
) })
|
|
108
|
+
] }),
|
|
92
109
|
onClick: () => {
|
|
93
110
|
if (!disabled) setOpen(true);
|
|
94
111
|
},
|
|
@@ -116,7 +133,7 @@ function DatePicker({
|
|
|
116
133
|
id: dialogId,
|
|
117
134
|
role: "dialog",
|
|
118
135
|
"aria-label": t("dataEntry.datePicker.openCalendar") ?? "Calendar",
|
|
119
|
-
className: "
|
|
136
|
+
className: "ui-control-panel-flush",
|
|
120
137
|
align: "start",
|
|
121
138
|
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
122
139
|
children: /* @__PURE__ */ jsx(
|
|
@@ -5,7 +5,7 @@ import { ArrowRight, CalendarIcon, X } from "lucide-react";
|
|
|
5
5
|
import { usePickerLocales, useTranslation } from "../../i18n/use-translation.js";
|
|
6
6
|
import { parseDateInput, toIsoDate } from "../../lib/datetime/index.js";
|
|
7
7
|
import { useControlledLatch } from "../../lib/hooks.js";
|
|
8
|
-
import { pickGroupFieldA11y } from "../../lib/field-a11y.js";
|
|
8
|
+
import { pickGroupFieldA11y, useFieldIdentity } from "../../lib/field-a11y.js";
|
|
9
9
|
import { cn } from "../../lib/utils.js";
|
|
10
10
|
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../data-display/popover.js";
|
|
11
11
|
import { Calendar } from "./calendar.js";
|
|
@@ -33,6 +33,9 @@ function DateRangePicker({
|
|
|
33
33
|
const groupId = id ?? autoId;
|
|
34
34
|
const fromId = `${groupId}-from`;
|
|
35
35
|
const toId = `${groupId}-to`;
|
|
36
|
+
const identity = useFieldIdentity({ id: groupId, name, "data-field": groupA11y["data-field"] });
|
|
37
|
+
const rangeField = groupA11y["data-field"] ?? identity["data-field"];
|
|
38
|
+
const rangeName = name ?? identity.name;
|
|
36
39
|
const isControlled = useControlledLatch(valueProp !== void 0);
|
|
37
40
|
const [internalValue, setInternalValue] = React.useState(defaultValue);
|
|
38
41
|
const value = isControlled ? valueProp : internalValue;
|
|
@@ -70,21 +73,21 @@ function DateRangePicker({
|
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
75
|
};
|
|
73
|
-
const innerInputClass = "
|
|
76
|
+
const innerInputClass = "ui-month-picker-input";
|
|
74
77
|
return /* @__PURE__ */ jsx(Popover, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
75
78
|
"div",
|
|
76
79
|
{
|
|
77
80
|
role: "group",
|
|
78
81
|
id: groupId,
|
|
79
82
|
...groupA11y,
|
|
83
|
+
"data-field": rangeField,
|
|
80
84
|
"aria-disabled": disabled ? true : void 0,
|
|
81
85
|
className: cn(
|
|
82
|
-
// One input-styled shell for the whole range —
|
|
83
|
-
//
|
|
84
|
-
"ui-control
|
|
86
|
+
// One input-styled shell for the whole range — the shared composite-field box, so
|
|
87
|
+
// this and the month range picker cannot drift into two slightly different fields.
|
|
88
|
+
"ui-control ui-control-composite-field",
|
|
85
89
|
"focus-within:border-ring focus-within:ring-ring/50 focus-within:ring-[3px]",
|
|
86
90
|
open && "border-ring ring-ring/50 ring-[3px]",
|
|
87
|
-
disabled && "pointer-events-none cursor-not-allowed opacity-50",
|
|
88
91
|
className
|
|
89
92
|
),
|
|
90
93
|
onClick: () => {
|
|
@@ -95,7 +98,8 @@ function DateRangePicker({
|
|
|
95
98
|
"input",
|
|
96
99
|
{
|
|
97
100
|
id: fromId,
|
|
98
|
-
|
|
101
|
+
"data-field": rangeField ? `${rangeField}_from` : void 0,
|
|
102
|
+
name: rangeName ? `${rangeName}_from` : void 0,
|
|
99
103
|
value: fromText,
|
|
100
104
|
disabled,
|
|
101
105
|
placeholder: resolvedPlaceholder,
|
|
@@ -114,12 +118,13 @@ function DateRangePicker({
|
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
120
|
),
|
|
117
|
-
/* @__PURE__ */ jsx(ArrowRight, { className: "
|
|
121
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "ui-month-picker-separator-icon", "aria-hidden": "true" }),
|
|
118
122
|
/* @__PURE__ */ jsx(
|
|
119
123
|
"input",
|
|
120
124
|
{
|
|
121
125
|
id: toId,
|
|
122
|
-
|
|
126
|
+
"data-field": rangeField ? `${rangeField}_to` : void 0,
|
|
127
|
+
name: rangeName ? `${rangeName}_to` : void 0,
|
|
123
128
|
value: toText,
|
|
124
129
|
disabled,
|
|
125
130
|
placeholder: resolvedPlaceholder,
|
|
@@ -149,9 +154,10 @@ function DateRangePicker({
|
|
|
149
154
|
event.stopPropagation();
|
|
150
155
|
clear();
|
|
151
156
|
},
|
|
152
|
-
children: /* @__PURE__ */ jsx(X, { className: "
|
|
157
|
+
children: /* @__PURE__ */ jsx(X, { className: "ui-month-picker-icon", "aria-hidden": "true" })
|
|
153
158
|
}
|
|
154
|
-
) :
|
|
159
|
+
) : null,
|
|
160
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
155
161
|
"button",
|
|
156
162
|
{
|
|
157
163
|
type: "button",
|
|
@@ -159,13 +165,13 @@ function DateRangePicker({
|
|
|
159
165
|
tabIndex: -1,
|
|
160
166
|
"aria-label": t("dataEntry.dateRangePicker.openCalendar") ?? "Open calendar",
|
|
161
167
|
className: "text-muted-foreground hover:text-foreground shrink-0",
|
|
162
|
-
children: /* @__PURE__ */ jsx(CalendarIcon, { className: "
|
|
168
|
+
children: /* @__PURE__ */ jsx(CalendarIcon, { className: "ui-month-picker-icon", "aria-hidden": "true" })
|
|
163
169
|
}
|
|
164
170
|
) }),
|
|
165
171
|
/* @__PURE__ */ jsx(
|
|
166
172
|
PopoverContent,
|
|
167
173
|
{
|
|
168
|
-
className: "
|
|
174
|
+
className: "ui-control-panel-flush",
|
|
169
175
|
align: "start",
|
|
170
176
|
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
171
177
|
children: /* @__PURE__ */ jsx(
|
|
@@ -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, label, required, helper, error: errorProp, 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, error: errorProp, labelAddon, layout: layoutProp, labelWidth: labelWidthProp, controlWidth: controlWidthProp, colSpan, className, children, staticText, }: FormFieldProp): React.JSX.Element;
|
|
@@ -3,7 +3,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Label } from "../data-entry/label.js";
|
|
5
5
|
import { cn } from "../../lib/utils.js";
|
|
6
|
-
import { FieldNameContext, mergeAriaIds } from "../../lib/field-a11y.js";
|
|
6
|
+
import { FieldIdentityContext, FieldNameContext, mergeAriaIds } from "../../lib/field-a11y.js";
|
|
7
|
+
import { useOptionalAppContext } from "../../app/app-provider.js";
|
|
7
8
|
import { useFormLayout } from "./form.js";
|
|
8
9
|
import { firstBagMessage, useClaimErrorKey, useFormErrorsRegistry } from "./form-errors.js";
|
|
9
10
|
const toCssLength = (v) => typeof v === "number" ? `${v}px` : v;
|
|
@@ -11,6 +12,7 @@ const FOCUSABLE_SELECTOR = 'input:not([type="hidden"]), select, textarea, button
|
|
|
11
12
|
function FormField({
|
|
12
13
|
id,
|
|
13
14
|
name,
|
|
15
|
+
field,
|
|
14
16
|
label,
|
|
15
17
|
required,
|
|
16
18
|
helper,
|
|
@@ -38,6 +40,8 @@ function FormField({
|
|
|
38
40
|
const labelId = `${resolvedId}-label`;
|
|
39
41
|
const helperId = helper ? `${resolvedId}-helper` : void 0;
|
|
40
42
|
const errorId = error ? `${resolvedId}-error` : void 0;
|
|
43
|
+
const fieldKey = field ?? name ?? id;
|
|
44
|
+
const emitFieldNames = useOptionalAppContext()?.emitFieldNames ?? false;
|
|
41
45
|
const isStatic = staticText !== void 0;
|
|
42
46
|
if (!isStatic && typeof process !== "undefined" && process.env?.NODE_ENV !== "production" && !React.isValidElement(children)) {
|
|
43
47
|
console.warn(
|
|
@@ -48,17 +52,30 @@ function FormField({
|
|
|
48
52
|
() => ({ labelId, label: typeof label === "string" ? label : void 0 }),
|
|
49
53
|
[labelId, label]
|
|
50
54
|
);
|
|
55
|
+
const fieldIdentityContext = React.useMemo(
|
|
56
|
+
() => fieldKey === void 0 ? null : { emitName: emitFieldNames },
|
|
57
|
+
[fieldKey, emitFieldNames]
|
|
58
|
+
);
|
|
51
59
|
const childProps = React.isValidElement(children) ? children.props : void 0;
|
|
52
60
|
const mergeIds = mergeAriaIds;
|
|
53
61
|
const childWithA11y = isStatic ? (
|
|
54
62
|
// Byte-for-byte the same value typography as `Descriptions.Item`'s `dd` (gh#294), so a
|
|
55
|
-
// read-only FormField row and a Descriptions value are indistinguishable when mixed.
|
|
56
|
-
|
|
63
|
+
// read-only FormField row and a Descriptions value are indistinguishable when mixed. That
|
|
64
|
+
// used to be two copies of the literal `text-sm` kept in sync by this comment; both call sites
|
|
65
|
+
// now read the SAME token pair (#319), so a service retunes both from one place and they
|
|
66
|
+
// cannot drift. --descriptions-value-line-height is the mandatory companion: `text-sm` also
|
|
67
|
+
// set Tailwind's `--text-sm--line-height`, which the theme never remaps (the gh#260 bug).
|
|
68
|
+
/* @__PURE__ */ jsx("span", { className: "text-[length:var(--descriptions-value-font-size)] leading-[var(--descriptions-value-line-height)] break-all", children: staticText })
|
|
57
69
|
) : React.isValidElement(children) ? React.cloneElement(children, {
|
|
58
70
|
// The label is associated via aria-labelledby (not <label for>): composite
|
|
59
71
|
// controls (Radio.Group, checkbox lists, range pairs) have no labelable root,
|
|
60
72
|
// and a dangling `for` triggers Chrome's "Incorrect use of <label>" issue.
|
|
61
73
|
id: childProps?.id ?? resolvedId,
|
|
74
|
+
// gh#337 — the machine key. Read the child's own value first in BOTH cases: cloneElement
|
|
75
|
+
// overwrites every key present in the config bag, `undefined` included, so a bare
|
|
76
|
+
// `"data-field": fieldKey` would erase a value the control set for itself.
|
|
77
|
+
"data-field": childProps?.["data-field"] ?? fieldKey,
|
|
78
|
+
...emitFieldNames ? { name: childProps?.name ?? fieldKey } : void 0,
|
|
62
79
|
"aria-labelledby": childProps?.["aria-labelledby"] ?? labelId,
|
|
63
80
|
// Redundant `aria-label` fallback (belt-and-suspenders): the accessible name is the
|
|
64
81
|
// SAME string as the visible label, just reachable even if an aria-labelledby lookup
|
|
@@ -83,7 +100,7 @@ function FormField({
|
|
|
83
100
|
style["--form-label-width"] = toCssLength(labelWidth);
|
|
84
101
|
if (controlWidth != null)
|
|
85
102
|
style["--form-control-width"] = toCssLength(controlWidth);
|
|
86
|
-
if (colSpan != null) style
|
|
103
|
+
if (colSpan != null) style["--form-field-col-span"] = String(colSpan);
|
|
87
104
|
return /* @__PURE__ */ jsxs(
|
|
88
105
|
"div",
|
|
89
106
|
{
|
|
@@ -121,7 +138,7 @@ function FormField({
|
|
|
121
138
|
labelAddon
|
|
122
139
|
] }),
|
|
123
140
|
/* @__PURE__ */ jsxs("div", { "data-slot": "form-field-control", className: "ui-form-field-control", children: [
|
|
124
|
-
isStatic ? childWithA11y : /* @__PURE__ */ jsx(FieldNameContext.Provider, { value: fieldNameContext, children: childWithA11y }),
|
|
141
|
+
isStatic ? childWithA11y : /* @__PURE__ */ jsx(FieldNameContext.Provider, { value: fieldNameContext, children: /* @__PURE__ */ jsx(FieldIdentityContext.Provider, { value: fieldIdentityContext, children: childWithA11y }) }),
|
|
125
142
|
helper ? /* @__PURE__ */ jsx("p", { id: helperId, className: "text-muted-foreground text-xs", children: helper }) : null,
|
|
126
143
|
error ? /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: "text-destructive text-xs", children: error }) : null
|
|
127
144
|
] })
|
|
@@ -21,8 +21,9 @@ export { SearchInput } from "./search-input.js";
|
|
|
21
21
|
export { Switch } from "./switch.js";
|
|
22
22
|
export type { SwitchProps } from "./switch.js";
|
|
23
23
|
export { Toggle } from "./toggle.js";
|
|
24
|
-
export type { ToggleProps } from "./toggle.js";
|
|
24
|
+
export type { ToggleProp, ToggleProps } from "./toggle.js";
|
|
25
25
|
export { ToggleGroup, ToggleGroupItem } from "./toggle-group.js";
|
|
26
|
+
export type { ToggleGroupItemProp, ToggleGroupItemProps } from "./toggle-group.js";
|
|
26
27
|
export { Slider } from "./slider.js";
|
|
27
28
|
export type { SliderProps } from "./slider.js";
|
|
28
29
|
export { Calendar } from "./calendar.js";
|
|
@@ -3,15 +3,12 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { X } from "lucide-react";
|
|
5
5
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
|
-
import { useFieldNameFallback } from "../../lib/field-a11y.js";
|
|
6
|
+
import { useFieldIdentity, useFieldNameFallback } from "../../lib/field-a11y.js";
|
|
7
7
|
import { cn } from "../../lib/utils.js";
|
|
8
8
|
const inputBaseClass = [
|
|
9
|
-
"ui-control border-input bg-background w-full
|
|
9
|
+
"ui-control ui-input border-input bg-background w-full rounded-[var(--control-radius)] transition-[color,box-shadow] outline-none",
|
|
10
10
|
"selection:bg-primary selection:text-primary-foreground",
|
|
11
|
-
"file:text-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium",
|
|
12
11
|
"placeholder:text-muted-foreground",
|
|
13
|
-
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
14
|
-
"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
15
12
|
"aria-invalid:border-destructive aria-invalid:ring-destructive/20"
|
|
16
13
|
];
|
|
17
14
|
const Input = React.forwardRef(
|
|
@@ -32,6 +29,11 @@ const Input = React.forwardRef(
|
|
|
32
29
|
"aria-label": props["aria-label"],
|
|
33
30
|
"aria-labelledby": props["aria-labelledby"]
|
|
34
31
|
});
|
|
32
|
+
const identity = useFieldIdentity({
|
|
33
|
+
id: props.id,
|
|
34
|
+
name: props.name,
|
|
35
|
+
"data-field": props["data-field"]
|
|
36
|
+
});
|
|
35
37
|
const innerRef = React.useRef(null);
|
|
36
38
|
const setRefs = React.useCallback(
|
|
37
39
|
(node) => {
|
|
@@ -77,7 +79,8 @@ const Input = React.forwardRef(
|
|
|
77
79
|
onChange,
|
|
78
80
|
className: cn(inputBaseClass, className),
|
|
79
81
|
...props,
|
|
80
|
-
...nameFallback
|
|
82
|
+
...nameFallback,
|
|
83
|
+
...identity
|
|
81
84
|
}
|
|
82
85
|
);
|
|
83
86
|
}
|
|
@@ -89,20 +92,12 @@ const Input = React.forwardRef(
|
|
|
89
92
|
tabIndex: -1,
|
|
90
93
|
"aria-label": t("common.clear") ?? "Clear",
|
|
91
94
|
onClick: clear,
|
|
92
|
-
className: "
|
|
93
|
-
children: /* @__PURE__ */ jsx(X, { className: "
|
|
95
|
+
className: "ui-control-inline-affix-action",
|
|
96
|
+
children: /* @__PURE__ */ jsx(X, { className: "ui-control-inline-affix-icon", "aria-hidden": "true" })
|
|
94
97
|
}
|
|
95
98
|
) : trailingIcon;
|
|
96
|
-
return /* @__PURE__ */ jsxs("span", { "data-slot": "input-affix-wrapper", className: "
|
|
97
|
-
leadingIcon != null ? /* @__PURE__ */ jsx(
|
|
98
|
-
"span",
|
|
99
|
-
{
|
|
100
|
-
"data-slot": "input-leading",
|
|
101
|
-
"aria-hidden": "true",
|
|
102
|
-
className: "text-muted-foreground pointer-events-none absolute inset-y-0 start-2 inline-flex items-center",
|
|
103
|
-
children: leadingIcon
|
|
104
|
-
}
|
|
105
|
-
) : null,
|
|
99
|
+
return /* @__PURE__ */ jsxs("span", { "data-slot": "input-affix-wrapper", className: "ui-input-affix-wrapper", children: [
|
|
100
|
+
leadingIcon != null ? /* @__PURE__ */ jsx("span", { "data-slot": "input-leading", "aria-hidden": "true", className: "ui-input-leading", children: leadingIcon }) : null,
|
|
106
101
|
/* @__PURE__ */ jsx(
|
|
107
102
|
"input",
|
|
108
103
|
{
|
|
@@ -114,15 +109,16 @@ const Input = React.forwardRef(
|
|
|
114
109
|
onChange: handleChange,
|
|
115
110
|
className: cn(
|
|
116
111
|
inputBaseClass,
|
|
117
|
-
leadingIcon != null && "
|
|
118
|
-
(showClear || trailingIcon != null) && "
|
|
112
|
+
leadingIcon != null && "ui-input--leading-affix",
|
|
113
|
+
(showClear || trailingIcon != null) && "ui-input--trailing-affix",
|
|
119
114
|
className
|
|
120
115
|
),
|
|
121
116
|
...props,
|
|
122
|
-
...nameFallback
|
|
117
|
+
...nameFallback,
|
|
118
|
+
...identity
|
|
123
119
|
}
|
|
124
120
|
),
|
|
125
|
-
trailing != null ? /* @__PURE__ */ jsx("span", { className: "
|
|
121
|
+
trailing != null ? /* @__PURE__ */ jsx("span", { className: "ui-input-trailing", children: trailing }) : null
|
|
126
122
|
] });
|
|
127
123
|
}
|
|
128
124
|
);
|
|
@@ -5,7 +5,7 @@ import * as LabelPrimitive from "@radix-ui/react-label";
|
|
|
5
5
|
import { cva } from "class-variance-authority";
|
|
6
6
|
import { cn } from "../../lib/utils.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
10
|
const Label = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
11
11
|
LabelPrimitive.Root,
|
|
@@ -13,7 +13,9 @@ const Label = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
|
13
13
|
ref,
|
|
14
14
|
"data-slot": "label",
|
|
15
15
|
className: cn(
|
|
16
|
-
|
|
16
|
+
// A label inside a disabled group reads at the SYSTEM disabled alpha (--disabled-opacity),
|
|
17
|
+
// the same one .ui-checkbox/.ui-radio/.ui-switch:disabled use — one knob, not a second one.
|
|
18
|
+
"ui-label group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-[var(--disabled-opacity)]",
|
|
17
19
|
labelVariants(),
|
|
18
20
|
className
|
|
19
21
|
),
|