@plexui/ui 0.5.0 → 0.7.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 +6 -3
- package/dist/es/components/Checkbox/Checkbox.js +2 -2
- package/dist/es/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/es/components/Checkbox/Checkbox.module.css +58 -44
- package/dist/es/components/CodeBlock/CodeBlock.module.css +24 -11
- package/dist/es/components/Field/Field.js +3 -2
- package/dist/es/components/Field/Field.js.map +1 -1
- package/dist/es/components/Field/Field.module.css +60 -20
- package/dist/es/components/FieldError/FieldError.module.css +0 -1
- package/dist/es/components/RadioGroup/RadioGroup.js +2 -2
- package/dist/es/components/RadioGroup/RadioGroup.js.map +1 -1
- package/dist/es/components/RadioGroup/RadioGroup.module.css +8 -0
- package/dist/es/components/Sidebar/Sidebar.module.css +0 -1
- package/dist/es/components/Switch/Switch.js +3 -2
- package/dist/es/components/Switch/Switch.js.map +1 -1
- package/dist/es/components/Switch/Switch.module.css +28 -2
- package/dist/es/styles/variables-components.css +7 -8
- package/dist/types/components/Checkbox/Checkbox.d.ts +13 -1
- package/dist/types/components/Field/Field.d.ts +8 -1
- package/dist/types/components/RadioGroup/RadioGroup.d.ts +8 -2
- package/dist/types/components/Switch/Switch.d.ts +4 -2
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
# @plexui/ui
|
|
2
2
|
|
|
3
|
-
A modern React component library
|
|
3
|
+
A modern React component library with 35 production-ready components, 14 hooks, a three-layer design token system, and a unified 9-step size scale — all powered by Radix primitives and Tailwind CSS 4.
|
|
4
4
|
|
|
5
|
-
[Documentation](https://plexui.com) • [GitHub](https://github.com/plex-ui/docs)
|
|
5
|
+
[Documentation](https://plexui.com) • [GitHub](https://github.com/plex-ui/docs) • [Figma Kit](https://plexui.com/#pricing)
|
|
6
|
+
|
|
7
|
+
> **Figma Design System PRO** — 22,000+ variants, all on Figma Variables. [Get the kit →](https://plexui.com/#pricing)
|
|
6
8
|
|
|
7
9
|
---
|
|
8
10
|
|
|
9
11
|
## Highlights
|
|
10
12
|
|
|
11
|
-
- **
|
|
13
|
+
- **Production-grade** — components designed and tested for real products at scale.
|
|
12
14
|
- **9-step size scale** — all key controls (Button, Input, Select, SegmentedControl, etc.) share a unified `ControlSize` scale from `3xs` (22 px) to `3xl` (48 px). Most competitors offer only 3–4.
|
|
13
15
|
- **Three-layer design tokens** — primitive → semantic → component CSS custom properties with `light-dark()` theming, alpha transparency scale, and 4-level elevation system.
|
|
14
16
|
- **Radix + Tailwind 4** — accessible primitives under the hood, utility-first styling on top.
|
|
17
|
+
- **Built for AI code editors** — consistent naming, clear token system, and comprehensive props give Claude, Cursor, Codex & other AI tools the building blocks to generate professional UI.
|
|
15
18
|
|
|
16
19
|
---
|
|
17
20
|
|
|
@@ -4,10 +4,10 @@ import clsx from "clsx";
|
|
|
4
4
|
import { Checkbox as RadixCheckbox } from "radix-ui";
|
|
5
5
|
import { useId } from "react";
|
|
6
6
|
import s from "./Checkbox.module.css";
|
|
7
|
-
export const Checkbox = ({ className, label, id: propsId, disabled, orientation = "left", ...restProps }) => {
|
|
7
|
+
export const Checkbox = ({ className, label, id: propsId, disabled, orientation = "left", pill = false, variant = "solid", ...restProps }) => {
|
|
8
8
|
const reactId = useId();
|
|
9
9
|
const id = propsId ?? reactId;
|
|
10
|
-
return (_jsxs("div", { "data-disabled": disabled ? "" : undefined, "data-has-label": label ? "" : undefined, "data-orientation": orientation, className: clsx(className, s.Container), children: [_jsx(RadixCheckbox.Root, { className: s.Checkbox, id: id, disabled: disabled, ...restProps, children: _jsx(RadixCheckbox.Indicator, { className: s.CheckMark }) }), label && (_jsx("label", { htmlFor: id, className: s.Label, onMouseDown: (event) => {
|
|
10
|
+
return (_jsxs("div", { "data-disabled": disabled ? "" : undefined, "data-has-label": label ? "" : undefined, "data-orientation": orientation, className: clsx(className, s.Container), children: [_jsx(RadixCheckbox.Root, { className: s.Checkbox, id: id, disabled: disabled, "data-pill": pill ? "" : undefined, "data-variant": variant, ...restProps, children: _jsx(RadixCheckbox.Indicator, { className: s.CheckMark }) }), label && (_jsx("label", { htmlFor: id, className: s.Label, onMouseDown: (event) => {
|
|
11
11
|
if (!event.defaultPrevented && event.detail > 1)
|
|
12
12
|
event.preventDefault();
|
|
13
13
|
}, children: label }))] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../../../src/components/Checkbox/Checkbox.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,UAAU,CAAA;AACpD,OAAO,EAA0C,KAAK,EAAE,MAAM,OAAO,CAAA;AACrE,OAAO,CAAC,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../../../src/components/Checkbox/Checkbox.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,UAAU,CAAA;AACpD,OAAO,EAA0C,KAAK,EAAE,MAAM,OAAO,CAAA;AACrE,OAAO,CAAC,MAAM,uBAAuB,CAAA;AA+CrC,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,EACvB,SAAS,EACT,KAAK,EACL,EAAE,EAAE,OAAO,EACX,QAAQ,EACR,WAAW,GAAG,MAAM,EACpB,IAAI,GAAG,KAAK,EACZ,OAAO,GAAG,OAAO,EACjB,GAAG,SAAS,EACE,EAAE,EAAE;IAClB,MAAM,OAAO,GAAG,KAAK,EAAE,CAAA;IACvB,MAAM,EAAE,GAAG,OAAO,IAAI,OAAO,CAAA;IAE7B,OAAO,CACL,gCACiB,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,oBACxB,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,sBACpB,WAAW,EAC7B,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,aAEvC,KAAC,aAAa,CAAC,IAAI,IACjB,SAAS,EAAE,CAAC,CAAC,QAAQ,EACrB,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,QAAQ,eACP,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,kBAClB,OAAO,KACjB,SAAS,YAEb,KAAC,aAAa,CAAC,SAAS,IAAC,SAAS,EAAE,CAAC,CAAC,SAAS,GAAI,GAChC,EACpB,KAAK,IAAI,CACR,gBACE,OAAO,EAAE,EAAE,EACX,SAAS,EAAE,CAAC,CAAC,KAAK,EAClB,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE;oBACrB,IAAI,CAAC,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;wBAAE,KAAK,CAAC,cAAc,EAAE,CAAA;gBACzE,CAAC,YAEA,KAAK,GACA,CACT,IACG,CACP,CAAA;AACH,CAAC,CAAA","sourcesContent":["\"use client\"\n\nimport clsx from \"clsx\"\nimport { Checkbox as RadixCheckbox } from \"radix-ui\"\nimport { type FocusEventHandler, type ReactNode, useId } from \"react\"\nimport s from \"./Checkbox.module.css\"\n\nexport type CheckboxProps = {\n /** The `id` of the checkbox. */\n id?: string\n /** The state of the checkbox when it is initially rendered. Use when you do not need to control its state. */\n defaultChecked?: boolean | \"indeterminate\"\n /** The controlled state of the checkbox. Must be used in conjunction with `onCheckedChange`. */\n checked?: boolean | \"indeterminate\"\n /** Optional accessible label rendered to the right of the checkbox. */\n label?: ReactNode\n /** Event handler called when the state of the checkbox changes. */\n onCheckedChange?: (nextState: boolean) => void\n /** Event handler called when the checkbox looses focus. */\n onBlur?: FocusEventHandler<HTMLButtonElement>\n /** Event handler called when the checkbox gains focus. */\n onFocus?: FocusEventHandler<HTMLButtonElement>\n /** When `true`, prevents the user from interacting with the checkbox. */\n disabled?: boolean\n /** When `true`, indicates that the user must check the checkbox before the owning form can be submitted. */\n required?: boolean\n /** The name of the checkbox. Submitted with its owning form as part of a name/value pair. */\n name?: string\n /** The value given as data when submitted with a `name`. */\n value?: string\n /** CSS classes applied to wrapper node */\n className?: string\n /**\n * The orientation of the checkbox relative to the label.\n *\n * @default \"left\"\n */\n orientation?: \"left\" | \"right\"\n /**\n * Determines if the checkbox should be a fully rounded pill shape.\n * @default false\n */\n pill?: boolean\n /**\n * Visual style variant for the checkbox indicator.\n * - `\"solid\"` — filled background when checked (default)\n * - `\"ghost\"` — no border or background, checkmark only\n * @default \"solid\"\n */\n variant?: \"solid\" | \"ghost\"\n}\n\nexport const Checkbox = ({\n className,\n label,\n id: propsId,\n disabled,\n orientation = \"left\",\n pill = false,\n variant = \"solid\",\n ...restProps\n}: CheckboxProps) => {\n const reactId = useId()\n const id = propsId ?? reactId\n\n return (\n <div\n data-disabled={disabled ? \"\" : undefined}\n data-has-label={label ? \"\" : undefined}\n data-orientation={orientation}\n className={clsx(className, s.Container)}\n >\n <RadixCheckbox.Root\n className={s.Checkbox}\n id={id}\n disabled={disabled}\n data-pill={pill ? \"\" : undefined}\n data-variant={variant}\n {...restProps}\n >\n <RadixCheckbox.Indicator className={s.CheckMark} />\n </RadixCheckbox.Root>\n {label && (\n <label\n htmlFor={id}\n className={s.Label}\n onMouseDown={(event) => {\n if (!event.defaultPrevented && event.detail > 1) event.preventDefault()\n }}\n >\n {label}\n </label>\n )}\n </div>\n )\n}\n"]}
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
flex-direction: row-reverse;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
.Container[data-disabled] {
|
|
15
|
+
opacity: 0.5;
|
|
16
|
+
cursor: not-allowed;
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
/* Radix pushes the inputs off screen in a weird way that
|
|
15
20
|
messes with error overlays */
|
|
16
21
|
.Container > input {
|
|
@@ -25,30 +30,20 @@
|
|
|
25
30
|
align-items: center;
|
|
26
31
|
justify-content: center;
|
|
27
32
|
flex-shrink: 0;
|
|
28
|
-
width:
|
|
29
|
-
max-width:
|
|
30
|
-
height:
|
|
33
|
+
width: var(--menu-checkbox-indicator-size);
|
|
34
|
+
max-width: var(--menu-checkbox-indicator-size);
|
|
35
|
+
height: var(--menu-checkbox-indicator-size);
|
|
31
36
|
padding: 0;
|
|
37
|
+
border: 1px solid var(--alpha-16);
|
|
32
38
|
border-radius: var(--radius-xs);
|
|
33
39
|
background-color: transparent;
|
|
34
40
|
cursor: pointer;
|
|
35
41
|
transition:
|
|
36
42
|
border-color 150ms ease,
|
|
37
43
|
background-color 150ms ease;
|
|
38
|
-
}.Checkbox, :where([data-theme="light"]) .Checkbox {
|
|
39
|
-
border: 1px solid var(--gray-200);
|
|
40
|
-
}:where([data-theme="dark"]) .Checkbox {
|
|
41
|
-
border: 1px solid var(--gray-500);
|
|
42
44
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
/* Adjust downward for label line-height - not using center to account for long labels than can wrap. */
|
|
46
|
-
top: 1px;
|
|
47
|
-
}
|
|
48
|
-
@media (hover: hover) and (pointer: fine) {.Checkbox:where(:not([data-disabled], [data-state="checked"])):hover, :where([data-theme="light"]) .Checkbox:where(:not([data-disabled], [data-state="checked"])):hover {
|
|
49
|
-
border-color: var(--gray-300);
|
|
50
|
-
}:where([data-theme="dark"]) .Checkbox:where(:not([data-disabled], [data-state="checked"])):hover {
|
|
51
|
-
border-color: var(--gray-600);
|
|
45
|
+
@media (hover: hover) and (pointer: fine) {.Checkbox:where(:not([data-disabled], [data-state="checked"])):hover {
|
|
46
|
+
border-color: var(--alpha-20);
|
|
52
47
|
}
|
|
53
48
|
}
|
|
54
49
|
|
|
@@ -67,29 +62,52 @@ border-color: var(--gray-600);
|
|
|
67
62
|
outline-offset: 2px;
|
|
68
63
|
}
|
|
69
64
|
|
|
65
|
+
/* =============================================
|
|
66
|
+
Invalid
|
|
67
|
+
============================================= */
|
|
68
|
+
.Checkbox[aria-invalid="true"] {
|
|
69
|
+
border-color: var(--input-border-color-invalid);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.Checkbox[aria-invalid="true"][data-state="indeterminate"],
|
|
73
|
+
.Checkbox[aria-invalid="true"][data-state="checked"] {
|
|
74
|
+
border-color: var(--input-border-color-invalid);
|
|
75
|
+
background-color: var(--input-border-color-invalid);
|
|
76
|
+
}
|
|
77
|
+
|
|
70
78
|
.Checkbox[data-disabled] {
|
|
71
79
|
cursor: not-allowed;
|
|
72
80
|
}
|
|
73
81
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
/* =============================================
|
|
83
|
+
Pill
|
|
84
|
+
============================================= */
|
|
85
|
+
.Checkbox[data-pill] {
|
|
86
|
+
border-radius: var(--radius-full);
|
|
87
|
+
}
|
|
78
88
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
/* =============================================
|
|
90
|
+
Ghost variant
|
|
91
|
+
============================================= */
|
|
92
|
+
.Checkbox[data-variant="ghost"] {
|
|
93
|
+
border-color: transparent;
|
|
94
|
+
background-color: transparent;
|
|
83
95
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
}
|
|
97
|
+
@media (hover: hover) and (pointer: fine) {.Checkbox[data-variant="ghost"]:where(:not([data-disabled], [data-state="checked"])):hover {
|
|
98
|
+
border-color: transparent;
|
|
99
|
+
}.Checkbox[data-variant="ghost"]:where(:not([data-disabled], [data-state="checked"])):hover, :where([data-theme="light"]) .Checkbox[data-variant="ghost"]:where(:not([data-disabled], [data-state="checked"])):hover {
|
|
100
|
+
background-color: var(--gray-50);
|
|
101
|
+
}:where([data-theme="dark"]) .Checkbox[data-variant="ghost"]:where(:not([data-disabled], [data-state="checked"])):hover {
|
|
102
|
+
background-color: var(--gray-800);
|
|
103
|
+
}
|
|
87
104
|
}
|
|
88
105
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
106
|
+
.Checkbox[data-variant="ghost"][data-state="indeterminate"],
|
|
107
|
+
.Checkbox[data-variant="ghost"][data-state="checked"] {
|
|
108
|
+
border-color: transparent;
|
|
109
|
+
background-color: transparent;
|
|
110
|
+
}.CheckMark {
|
|
93
111
|
position: absolute;
|
|
94
112
|
top: 0;
|
|
95
113
|
left: 0;
|
|
@@ -131,11 +149,12 @@ background-color: var(--gray-200);
|
|
|
131
149
|
transform: scale(0)
|
|
132
150
|
}
|
|
133
151
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
152
|
+
|
|
153
|
+
/* Ghost variant — checkmark uses text color instead of white */
|
|
154
|
+
[data-variant="ghost"] .CheckMark::before,
|
|
155
|
+
[data-variant="ghost"] .CheckMark::after {
|
|
156
|
+
background: var(--gray-900);
|
|
157
|
+
}
|
|
139
158
|
|
|
140
159
|
.CheckMark::before {
|
|
141
160
|
top: 0;
|
|
@@ -160,23 +179,18 @@ background-color: var(--gray-200);
|
|
|
160
179
|
transform-origin: 0 100%;
|
|
161
180
|
transition: transform 100ms ease 160ms;
|
|
162
181
|
}.Label {
|
|
163
|
-
display:
|
|
164
|
-
align-items: center;
|
|
182
|
+
display: block;
|
|
165
183
|
min-height: 20px;
|
|
166
184
|
cursor: pointer;
|
|
167
185
|
font-size: 14px;
|
|
168
186
|
line-height: 20px;
|
|
169
187
|
}
|
|
170
188
|
|
|
171
|
-
[data-disabled] .Label {
|
|
172
|
-
cursor: not-allowed;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
189
|
[data-orientation="left"] .Label {
|
|
176
|
-
padding-left:
|
|
190
|
+
padding-left: calc(var(--spacing) * 2);
|
|
177
191
|
}
|
|
178
192
|
|
|
179
193
|
[data-orientation="right"] .Label {
|
|
180
|
-
padding-right:
|
|
194
|
+
padding-right: calc(var(--spacing) * 3);
|
|
181
195
|
}
|
|
182
196
|
}
|
|
@@ -5,18 +5,31 @@
|
|
|
5
5
|
background-color: var(--codeblock-background-color);
|
|
6
6
|
}.CopyButtonContainer {
|
|
7
7
|
position: absolute;
|
|
8
|
-
top:
|
|
9
|
-
right:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
top: 8px;
|
|
9
|
+
right: 8px;
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
display: grid;
|
|
12
|
+
place-items: center;
|
|
13
|
+
width: 32px;
|
|
14
|
+
height: 32px;
|
|
15
|
+
border-radius: 8px;
|
|
16
|
+
background-color: var(--color-surface-elevated-secondary);
|
|
17
|
+
color: var(--color-text-secondary);
|
|
13
18
|
}/* Force the CopyButton to inherit the container's color on all states.
|
|
14
19
|
Ghost hover background (::before) is preserved — it's the correct behavior. */.CopyButtonContainer button {
|
|
15
20
|
color: inherit !important;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
padding: 0 !important;
|
|
22
|
+
-webkit-tap-highlight-color: transparent;
|
|
23
|
+
}.CopyButtonContainer button::before {
|
|
24
|
+
opacity: 0 !important;
|
|
25
|
+
transform: none !important;
|
|
26
|
+
background-color: transparent !important;
|
|
27
|
+
box-shadow: none !important;
|
|
28
|
+
}.CopyButtonContainer button:focus,
|
|
29
|
+
.CopyButtonContainer button:focus-visible {
|
|
30
|
+
outline: none !important;
|
|
31
|
+
}.CopyButtonContainer button:focus-visible::after {
|
|
32
|
+
outline: none !important;
|
|
20
33
|
}.SyntaxHighlighter {
|
|
21
34
|
--syntax1: var(--codeblock-syntax-1);
|
|
22
35
|
--syntax2: var(--codeblock-syntax-2);
|
|
@@ -35,7 +48,7 @@
|
|
|
35
48
|
/* 14px to a 16px baseline */
|
|
36
49
|
font-weight: var(--font-weight-normal);
|
|
37
50
|
line-height: 1.714em;
|
|
38
|
-
/* 24px at 14px
|
|
51
|
+
/* 24px at 14px */
|
|
39
52
|
|
|
40
53
|
/* stylelint-disable selector-class-pattern */
|
|
41
54
|
|
|
@@ -115,4 +128,4 @@
|
|
|
115
128
|
align-items: center;
|
|
116
129
|
justify-content: center;
|
|
117
130
|
}
|
|
118
|
-
}
|
|
131
|
+
}
|
|
@@ -4,7 +4,7 @@ import clsx from "clsx";
|
|
|
4
4
|
import { cloneElement, isValidElement, useId } from "react";
|
|
5
5
|
import { FieldError } from "../FieldError";
|
|
6
6
|
import s from "./Field.module.css";
|
|
7
|
-
export function Field({ label, description, errorMessage, size = "md", required = false, orientation = "vertical", id: idProp, className, children, }) {
|
|
7
|
+
export function Field({ label, description, errorMessage, size = "md", required = false, orientation = "vertical", opticallyAlign, id: idProp, className, children, }) {
|
|
8
8
|
const generatedId = useId();
|
|
9
9
|
const fieldId = idProp || `field-${generatedId}`;
|
|
10
10
|
const descriptionId = description ? `${fieldId}-description` : undefined;
|
|
@@ -17,6 +17,7 @@ export function Field({ label, description, errorMessage, size = "md", required
|
|
|
17
17
|
id: fieldId,
|
|
18
18
|
"aria-describedby": ariaDescribedBy,
|
|
19
19
|
"aria-invalid": invalid || undefined,
|
|
20
|
+
...(opticallyAlign && { opticallyAlign }),
|
|
20
21
|
};
|
|
21
22
|
// Resolve the children
|
|
22
23
|
let resolvedChildren;
|
|
@@ -29,6 +30,6 @@ export function Field({ label, description, errorMessage, size = "md", required
|
|
|
29
30
|
else {
|
|
30
31
|
resolvedChildren = children;
|
|
31
32
|
}
|
|
32
|
-
return (_jsxs("div", { className: clsx(s.Field, className), "data-size": size, "data-orientation": orientation, children: [_jsxs("label", { className: s.Label, htmlFor: fieldId, children: [label, required && (_jsx("span", { className: s.RequiredIndicator, "aria-hidden": "true", children: "*" }))] }), description && (_jsx("div", { className: s.Description, id: descriptionId, children: description })), _jsx("div", { className: s.Control, children: resolvedChildren }), errorMessage && (_jsx(FieldError, { id: errorId, children: errorMessage }))] }));
|
|
33
|
+
return (_jsxs("div", { className: clsx(s.Field, className), "data-size": size, "data-orientation": orientation, "data-optically-align": opticallyAlign, children: [_jsxs("div", { className: s.LabelGroup, children: [_jsxs("label", { className: s.Label, htmlFor: fieldId, children: [label, required && (_jsx("span", { className: s.RequiredIndicator, "aria-hidden": "true", children: "*" }))] }), description && (_jsx("div", { className: s.Description, id: descriptionId, children: description }))] }), _jsxs("div", { className: s.Content, children: [_jsx("div", { className: s.Control, children: resolvedChildren }), errorMessage && (_jsx(FieldError, { id: errorId, children: errorMessage }))] })] }));
|
|
33
34
|
}
|
|
34
35
|
//# sourceMappingURL=Field.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Field.js","sourceRoot":"","sources":["../../../../src/components/Field/Field.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAG3D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE1C,OAAO,CAAC,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"Field.js","sourceRoot":"","sources":["../../../../src/components/Field/Field.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAG3D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE1C,OAAO,CAAC,MAAM,oBAAoB,CAAA;AAmElC,MAAM,UAAU,KAAK,CAAC,EACpB,KAAK,EACL,WAAW,EACX,YAAY,EACZ,IAAI,GAAG,IAAI,EACX,QAAQ,GAAG,KAAK,EAChB,WAAW,GAAG,UAAU,EACxB,cAAc,EACd,EAAE,EAAE,MAAM,EACV,SAAS,EACT,QAAQ,GACG;IACX,MAAM,WAAW,GAAG,KAAK,EAAE,CAAA;IAC3B,MAAM,OAAO,GAAG,MAAM,IAAI,SAAS,WAAW,EAAE,CAAA;IAChD,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,cAAc,CAAC,CAAC,CAAC,SAAS,CAAA;IACxE,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IAE7D,sDAAsD;IACtD,MAAM,eAAe,GACnB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS,CAAA;IAEjE,MAAM,OAAO,GAAG,CAAC,CAAC,YAAY,CAAA;IAE9B,yCAAyC;IACzC,MAAM,eAAe,GAAoB;QACvC,EAAE,EAAE,OAAO;QACX,kBAAkB,EAAE,eAAe;QACnC,cAAc,EAAE,OAAO,IAAI,SAAS;QACpC,GAAG,CAAC,cAAc,IAAI,EAAE,cAAc,EAAE,CAAC;KAC1C,CAAA;IAED,uBAAuB;IACvB,IAAI,gBAAiC,CAAA;IACrC,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACnC,gBAAgB,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAA;IAC9C,CAAC;SAAM,IAAI,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,gBAAgB,GAAG,YAAY,CAC7B,QAAuD,EACvD,eAAe,CAChB,CAAA;IACH,CAAC;SAAM,CAAC;QACN,gBAAgB,GAAG,QAAQ,CAAA;IAC7B,CAAC;IAED,OAAO,CACL,eACE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,eACxB,IAAI,sBACG,WAAW,0BACP,cAAc,aAEpC,eAAK,SAAS,EAAE,CAAC,CAAC,UAAU,aAC1B,iBAAO,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,aACxC,KAAK,EACL,QAAQ,IAAI,CACX,eAAM,SAAS,EAAE,CAAC,CAAC,iBAAiB,iBAAc,MAAM,kBAEjD,CACR,IACK,EACP,WAAW,IAAI,CACd,cAAK,SAAS,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,EAAE,aAAa,YAC7C,WAAW,GACR,CACP,IACG,EACN,eAAK,SAAS,EAAE,CAAC,CAAC,OAAO,aACvB,cAAK,SAAS,EAAE,CAAC,CAAC,OAAO,YAAG,gBAAgB,GAAO,EAClD,YAAY,IAAI,CACf,KAAC,UAAU,IAAC,EAAE,EAAE,OAAO,YAAG,YAAY,GAAc,CACrD,IACG,IACF,CACP,CAAA;AACH,CAAC","sourcesContent":["\"use client\"\n\nimport clsx from \"clsx\"\nimport { cloneElement, isValidElement, useId } from \"react\"\n\nimport type { ControlSize } from \"../../types\"\nimport { FieldError } from \"../FieldError\"\n\nimport s from \"./Field.module.css\"\n\nexport type FieldChildProps = {\n id: string\n \"aria-describedby\"?: string\n \"aria-invalid\"?: boolean\n opticallyAlign?: \"start\" | \"end\"\n}\n\nexport type FieldProps = {\n /**\n * Label text for the field\n */\n label: React.ReactNode\n /**\n * Helper/description text displayed below the label.\n * Automatically linked via aria-describedby.\n */\n description?: React.ReactNode\n /**\n * Error message displayed below the control.\n * When provided, the child control receives aria-invalid=\"true\".\n * Uses the existing FieldError component internally.\n */\n errorMessage?: React.ReactNode\n /**\n * Controls the font size of the label to visually match the child control's size.\n * Matches the ControlSize scale used by Input, Select, etc.\n * @default \"md\"\n */\n size?: ControlSize\n /**\n * Display a required indicator (asterisk) after the label.\n * This is purely visual — it does not add the `required` HTML attribute.\n * @default false\n */\n required?: boolean\n /**\n * Layout direction of label and control.\n * - \"vertical\": label stacked above control (default)\n * - \"horizontal\": label beside control\n * @default \"vertical\"\n */\n orientation?: \"vertical\" | \"horizontal\"\n /**\n * Allows overriding the auto-generated `id`. When provided, this becomes\n * the id set on the child control and the `htmlFor` on the label.\n */\n id?: string\n /**\n * Applies a negative margin on the child control using its gutter to\n * optically align the control's text with surrounding content.\n * Passed through to the child control via cloneElement / render prop.\n */\n opticallyAlign?: \"start\" | \"end\"\n /**\n * CSS class applied to the root wrapper\n */\n className?: string\n /**\n * The form control(s) to render.\n * - If a single ReactElement, Field clones it with { id, aria-describedby, aria-invalid }.\n * - If a function (render prop), it is called with { id, \"aria-describedby\", \"aria-invalid\" }.\n */\n children: React.ReactElement | ((fieldProps: FieldChildProps) => React.ReactNode)\n}\n\nexport function Field({\n label,\n description,\n errorMessage,\n size = \"md\",\n required = false,\n orientation = \"vertical\",\n opticallyAlign,\n id: idProp,\n className,\n children,\n}: FieldProps) {\n const generatedId = useId()\n const fieldId = idProp || `field-${generatedId}`\n const descriptionId = description ? `${fieldId}-description` : undefined\n const errorId = errorMessage ? `${fieldId}-error` : undefined\n\n // Build aria-describedby from description + error IDs\n const ariaDescribedBy =\n [descriptionId, errorId].filter(Boolean).join(\" \") || undefined\n\n const invalid = !!errorMessage\n\n // Props to inject into the child control\n const fieldChildProps: FieldChildProps = {\n id: fieldId,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-invalid\": invalid || undefined,\n ...(opticallyAlign && { opticallyAlign }),\n }\n\n // Resolve the children\n let resolvedChildren: React.ReactNode\n if (typeof children === \"function\") {\n resolvedChildren = children(fieldChildProps)\n } else if (isValidElement(children)) {\n resolvedChildren = cloneElement(\n children as React.ReactElement<Record<string, unknown>>,\n fieldChildProps,\n )\n } else {\n resolvedChildren = children\n }\n\n return (\n <div\n className={clsx(s.Field, className)}\n data-size={size}\n data-orientation={orientation}\n data-optically-align={opticallyAlign}\n >\n <div className={s.LabelGroup}>\n <label className={s.Label} htmlFor={fieldId}>\n {label}\n {required && (\n <span className={s.RequiredIndicator} aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n {description && (\n <div className={s.Description} id={descriptionId}>\n {description}\n </div>\n )}\n </div>\n <div className={s.Content}>\n <div className={s.Control}>{resolvedChildren}</div>\n {errorMessage && (\n <FieldError id={errorId}>{errorMessage}</FieldError>\n )}\n </div>\n </div>\n )\n}\n"]}
|
|
@@ -8,61 +8,105 @@
|
|
|
8
8
|
--field-error-margin-bottom: 0;
|
|
9
9
|
--field-error-padding-inline: 0;
|
|
10
10
|
}/* =============================================
|
|
11
|
-
|
|
11
|
+
LabelGroup (label + description)
|
|
12
|
+
============================================= */.LabelGroup {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
gap: var(--field-label-description-gap, 0px);
|
|
16
|
+
}/* =============================================
|
|
17
|
+
Content (control + error)
|
|
18
|
+
============================================= */.Content {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
gap: var(--field-gap);
|
|
22
|
+
}/* =============================================
|
|
23
|
+
Horizontal orientation
|
|
12
24
|
============================================= */.Field:where([data-orientation="horizontal"]) {
|
|
13
25
|
flex-direction: row;
|
|
14
26
|
align-items: flex-start;
|
|
15
|
-
}.Field:where([data-orientation="horizontal"]) .
|
|
27
|
+
}.Field:where([data-orientation="horizontal"]) .LabelGroup {
|
|
16
28
|
flex-shrink: 0;
|
|
29
|
+
width: var(--field-horizontal-label-width);
|
|
17
30
|
padding-top: var(--field-label-horizontal-offset);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
min-width: 0;
|
|
31
|
+
}.Field:where([data-orientation="horizontal"]) .Content {
|
|
32
|
+
flex-shrink: 0;
|
|
33
|
+
width: var(--field-horizontal-control-width);
|
|
22
34
|
}/* =============================================
|
|
23
|
-
Sizes
|
|
35
|
+
Sizes — shared properties (grouped)
|
|
24
36
|
============================================= */.Field:where([data-size="3xs"]),
|
|
25
37
|
.Field:where([data-size="2xs"]) {
|
|
26
|
-
--field-gap: calc(var(--spacing) * 1
|
|
38
|
+
--field-gap: calc(var(--spacing) * 1);
|
|
39
|
+
--field-label-description-gap: 0px;
|
|
27
40
|
--field-label-font-size: var(--font-text-xs-size);
|
|
28
41
|
--field-label-line-height: var(--font-text-xs-line-height);
|
|
29
42
|
--field-description-font-size: var(--font-text-xs-size);
|
|
30
43
|
--field-description-line-height: var(--font-text-xs-line-height);
|
|
31
|
-
|
|
44
|
+
|
|
45
|
+
/* Scale error elements down for compact sizes */
|
|
46
|
+
--field-error-icon-size: 0.875rem; /* 14px */
|
|
47
|
+
--field-error-gap: calc(var(--spacing) * 1.5); /* 6px */
|
|
32
48
|
}.Field:where([data-size="xs"]),
|
|
33
49
|
.Field:where([data-size="sm"]) {
|
|
34
50
|
--field-gap: calc(var(--spacing) * 1.5);
|
|
51
|
+
--field-label-description-gap: 0px;
|
|
35
52
|
--field-label-font-size: var(--font-text-xs-size);
|
|
36
53
|
--field-label-line-height: var(--font-text-xs-line-height);
|
|
37
54
|
--field-description-font-size: var(--font-text-xs-size);
|
|
38
55
|
--field-description-line-height: var(--font-text-xs-line-height);
|
|
39
|
-
|
|
56
|
+
|
|
57
|
+
/* Scale error elements down for compact sizes */
|
|
58
|
+
--field-error-icon-size: 0.875rem; /* 14px */
|
|
59
|
+
--field-error-gap: calc(var(--spacing) * 1.5); /* 6px */
|
|
40
60
|
}.Field:where([data-size="md"]) {
|
|
41
61
|
--field-gap: calc(var(--spacing) * 2);
|
|
62
|
+
--field-label-description-gap: 2px;
|
|
42
63
|
--field-label-font-size: var(--font-text-sm-size);
|
|
43
64
|
--field-label-line-height: var(--font-text-sm-line-height);
|
|
44
65
|
--field-description-font-size: var(--font-text-xs-size);
|
|
45
66
|
--field-description-line-height: var(--font-text-xs-line-height);
|
|
46
|
-
--field-description-margin-top: calc(-1 * calc(var(--spacing) * 1));
|
|
47
|
-
--field-label-horizontal-offset: 0.5rem;
|
|
48
67
|
}.Field:where([data-size="lg"]),
|
|
49
68
|
.Field:where([data-size="xl"]) {
|
|
50
69
|
--field-gap: calc(var(--spacing) * 2);
|
|
70
|
+
--field-label-description-gap: 2px;
|
|
51
71
|
--field-label-font-size: var(--font-text-sm-size);
|
|
52
72
|
--field-label-line-height: var(--font-text-sm-line-height);
|
|
53
73
|
--field-description-font-size: var(--font-text-xs-size);
|
|
54
74
|
--field-description-line-height: var(--font-text-xs-line-height);
|
|
55
|
-
--field-description-margin-top: calc(-1 * calc(var(--spacing) * 1));
|
|
56
|
-
--field-label-horizontal-offset: 0.625rem;
|
|
57
75
|
}.Field:where([data-size="2xl"]),
|
|
58
76
|
.Field:where([data-size="3xl"]) {
|
|
59
77
|
--field-gap: calc(var(--spacing) * 2.5);
|
|
78
|
+
--field-label-description-gap: 2px;
|
|
60
79
|
--field-label-font-size: var(--font-text-md-size);
|
|
61
80
|
--field-label-line-height: var(--font-text-md-line-height);
|
|
62
81
|
--field-description-font-size: var(--font-text-sm-size);
|
|
63
82
|
--field-description-line-height: var(--font-text-sm-line-height);
|
|
64
|
-
|
|
65
|
-
|
|
83
|
+
|
|
84
|
+
/* Scale error elements up for spacious sizes */
|
|
85
|
+
--field-error-font-size: var(--font-text-sm-size); /* 14px */
|
|
86
|
+
--field-error-line-height: var(--font-text-sm-line-height); /* 20px */
|
|
87
|
+
--field-error-icon-size: 1.125rem; /* 18px */
|
|
88
|
+
}/* =============================================
|
|
89
|
+
Sizes — horizontal label offset (per-size)
|
|
90
|
+
Centers label text vertically with the input:
|
|
91
|
+
offset = (control-height − label-line-height) / 2
|
|
92
|
+
============================================= */.Field:where([data-size="3xs"]) {
|
|
93
|
+
--field-label-horizontal-offset: calc((var(--control-size-3xs) - var(--font-text-xs-line-height)) / 2); /* 2px */
|
|
94
|
+
}.Field:where([data-size="2xs"]) {
|
|
95
|
+
--field-label-horizontal-offset: calc((var(--control-size-2xs) - var(--font-text-xs-line-height)) / 2); /* 3px */
|
|
96
|
+
}.Field:where([data-size="xs"]) {
|
|
97
|
+
--field-label-horizontal-offset: calc((var(--control-size-xs) - var(--font-text-xs-line-height)) / 2); /* 4px */
|
|
98
|
+
}.Field:where([data-size="sm"]) {
|
|
99
|
+
--field-label-horizontal-offset: calc((var(--control-size-sm) - var(--font-text-xs-line-height)) / 2); /* 5px */
|
|
100
|
+
}.Field:where([data-size="md"]) {
|
|
101
|
+
--field-label-horizontal-offset: calc((var(--control-size-md) - var(--font-text-sm-line-height)) / 2); /* 6px */
|
|
102
|
+
}.Field:where([data-size="lg"]) {
|
|
103
|
+
--field-label-horizontal-offset: calc((var(--control-size-lg) - var(--font-text-sm-line-height)) / 2); /* 8px */
|
|
104
|
+
}.Field:where([data-size="xl"]) {
|
|
105
|
+
--field-label-horizontal-offset: calc((var(--control-size-xl) - var(--font-text-sm-line-height)) / 2); /* 10px */
|
|
106
|
+
}.Field:where([data-size="2xl"]) {
|
|
107
|
+
--field-label-horizontal-offset: calc((var(--control-size-2xl) - var(--font-text-md-line-height)) / 2); /* 10px */
|
|
108
|
+
}.Field:where([data-size="3xl"]) {
|
|
109
|
+
--field-label-horizontal-offset: calc((var(--control-size-3xl) - var(--font-text-md-line-height)) / 2); /* 12px */
|
|
66
110
|
}/* =============================================
|
|
67
111
|
Label
|
|
68
112
|
============================================= */.Label {
|
|
@@ -74,9 +118,6 @@
|
|
|
74
118
|
line-height: var(--field-label-line-height);
|
|
75
119
|
font-weight: var(--font-weight-semibold);
|
|
76
120
|
cursor: default;
|
|
77
|
-
-webkit-user-select: none;
|
|
78
|
-
-moz-user-select: none;
|
|
79
|
-
user-select: none;
|
|
80
121
|
}/* =============================================
|
|
81
122
|
Required Indicator
|
|
82
123
|
============================================= */.RequiredIndicator {
|
|
@@ -88,7 +129,6 @@
|
|
|
88
129
|
color: var(--color-text-secondary);
|
|
89
130
|
font-size: var(--field-description-font-size);
|
|
90
131
|
line-height: var(--field-description-line-height);
|
|
91
|
-
margin-top: var(--field-description-margin-top, calc(-1 * calc(var(--spacing) * 0.5)));
|
|
92
132
|
}/* =============================================
|
|
93
133
|
Control
|
|
94
134
|
============================================= */.Control {
|
|
@@ -19,7 +19,7 @@ export const RadioGroup = ({ onChange, children, className, direction = "row", d
|
|
|
19
19
|
}), [disabled, direction]);
|
|
20
20
|
return (_jsx(RadioGroupContext, { value: store, children: _jsx(RadixRadioGroup.Root, { className: clsx(s.RadioGroup, className), "data-direction": direction, onValueChange: onChange, disabled: disabled, ...restProps, children: children }) }));
|
|
21
21
|
};
|
|
22
|
-
const Item = ({ value, disabled: itemDisabled = false, required, children, className, block = false, ...restProps }) => {
|
|
22
|
+
const Item = ({ value, disabled: itemDisabled = false, required, children, className, block = false, orientation = "left", ...restProps }) => {
|
|
23
23
|
const { disabled: groupDisabled } = useRadioGroupContext();
|
|
24
24
|
const disabled = groupDisabled || itemDisabled;
|
|
25
25
|
const id = useId();
|
|
@@ -28,7 +28,7 @@ const Item = ({ value, disabled: itemDisabled = false, required, children, class
|
|
|
28
28
|
// Providing an extra wrapper enables `label` to be inline-flex, avoiding clickable whitespace
|
|
29
29
|
// when radio options are of varied lengths.
|
|
30
30
|
// NOTE: Important that this is `flex` to prevent the `inline-flex` label from extra, unintentional whitespace.
|
|
31
|
-
_jsx("div", { className: "flex", ...restProps, children: _jsxs("label", { htmlFor: itemId, className: clsx(s.RadioLabel, className), "data-disabled": disabled ? "" : undefined, "data-block": block ? "" : undefined, onMouseDown: (event) => {
|
|
31
|
+
_jsx("div", { className: clsx("flex", block && "w-full"), ...restProps, children: _jsxs("label", { htmlFor: itemId, className: clsx(s.RadioLabel, className), "data-disabled": disabled ? "" : undefined, "data-block": block ? "" : undefined, "data-orientation": orientation, onMouseDown: (event) => {
|
|
32
32
|
if (!event.defaultPrevented && event.detail > 1)
|
|
33
33
|
event.preventDefault();
|
|
34
34
|
}, children: [_jsx("div", { className: s.RadioIndicatorWrapper, children: _jsx(RadixRadioGroup.Item, { id: itemId, value: value, disabled: disabled, required: required, className: s.RadioItem, children: _jsx(RadixRadioGroup.Indicator, { className: s.RadioIndicator }) }) }), children] }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioGroup.js","sourceRoot":"","sources":["../../../../src/components/RadioGroup/RadioGroup.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,UAAU,CAAA;AACxD,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,CAAC,MAAM,yBAAyB,CAAA;AASvC,MAAM,iBAAiB,GAAG,aAAa,CAAgC,IAAI,CAAC,CAAA;AAE5E,MAAM,oBAAoB,GAAG,GAAG,EAAE;IAChC,MAAM,OAAO,GAAG,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAEtC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAA;IAC5E,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAqBD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAmB,EAC3C,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAS,GAAG,KAAK,EACjB,QAAQ,GAAG,KAAK,EAChB,GAAG,SAAS,EACO,EAAE,EAAE;IACvB,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ;QACR,SAAS;KACV,CAAC,EACF,CAAC,QAAQ,EAAE,SAAS,CAAC,CACtB,CAAA;IAED,OAAO,CACL,KAAC,iBAAiB,IAAC,KAAK,EAAE,KAAK,YAC7B,KAAC,eAAe,CAAC,IAAI,IACnB,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,oBACxB,SAAS,EACzB,aAAa,EAAE,QAAQ,EACvB,QAAQ,EAAE,QAAQ,KACd,SAAS,YAEZ,QAAQ,GACY,GACL,CACrB,CAAA;AACH,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"RadioGroup.js","sourceRoot":"","sources":["../../../../src/components/RadioGroup/RadioGroup.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,UAAU,CAAA;AACxD,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,CAAC,MAAM,yBAAyB,CAAA;AASvC,MAAM,iBAAiB,GAAG,aAAa,CAAgC,IAAI,CAAC,CAAA;AAE5E,MAAM,oBAAoB,GAAG,GAAG,EAAE;IAChC,MAAM,OAAO,GAAG,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAEtC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAA;IAC5E,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAqBD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAmB,EAC3C,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAS,GAAG,KAAK,EACjB,QAAQ,GAAG,KAAK,EAChB,GAAG,SAAS,EACO,EAAE,EAAE;IACvB,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ;QACR,SAAS;KACV,CAAC,EACF,CAAC,QAAQ,EAAE,SAAS,CAAC,CACtB,CAAA;IAED,OAAO,CACL,KAAC,iBAAiB,IAAC,KAAK,EAAE,KAAK,YAC7B,KAAC,eAAe,CAAC,IAAI,IACnB,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,oBACxB,SAAS,EACzB,aAAa,EAAE,QAAQ,EACvB,QAAQ,EAAE,QAAQ,KACd,SAAS,YAEZ,QAAQ,GACY,GACL,CACrB,CAAA;AACH,CAAC,CAAA;AAkBD,MAAM,IAAI,GAAG,CAAmB,EAC9B,KAAK,EACL,QAAQ,EAAE,YAAY,GAAG,KAAK,EAC9B,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,KAAK,GAAG,KAAK,EACb,WAAW,GAAG,MAAM,EACpB,GAAG,SAAS,EACW,EAAE,EAAE;IAC3B,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,oBAAoB,EAAE,CAAA;IAC1D,MAAM,QAAQ,GAAG,aAAa,IAAI,YAAY,CAAA;IAE9C,MAAM,EAAE,GAAG,KAAK,EAAE,CAAA;IAClB,MAAM,MAAM,GAAG,GAAG,KAAK,IAAI,EAAE,EAAE,CAAA;IAE/B,OAAO;IACL,8FAA8F;IAC9F,4CAA4C;IAC5C,+GAA+G;IAC/G,cAAK,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,QAAQ,CAAC,KAAM,SAAS,YAC5D,iBACE,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,mBACzB,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,gBAC5B,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,sBAChB,WAAW,EAC7B,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE;gBACrB,IAAI,CAAC,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;oBAAE,KAAK,CAAC,cAAc,EAAE,CAAA;YACzE,CAAC,aAED,cAAK,SAAS,EAAE,CAAC,CAAC,qBAAqB,YACrC,KAAC,eAAe,CAAC,IAAI,IACnB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,CAAC,CAAC,SAAS,YAEtB,KAAC,eAAe,CAAC,SAAS,IAAC,SAAS,EAAE,CAAC,CAAC,cAAc,GAAI,GACrC,GACnB,EACL,QAAQ,IACH,GACJ,CACP,CAAA;AACH,CAAC,CAAA;AAED,UAAU,CAAC,IAAI,GAAG,IAAI,CAAA","sourcesContent":["\"use client\"\n\nimport clsx from \"clsx\"\nimport { RadioGroup as RadixRadioGroup } from \"radix-ui\"\nimport React, { createContext, use, useId, useMemo } from \"react\"\nimport s from \"./RadioGroup.module.css\"\n\ntype Direction = \"col\" | \"row\"\n\ntype RadioGroupContextValue = {\n disabled: boolean\n direction: Direction\n}\n\nconst RadioGroupContext = createContext<RadioGroupContextValue | null>(null)\n\nconst useRadioGroupContext = () => {\n const context = use(RadioGroupContext)\n\n if (!context) {\n throw new Error(\"RadioGroup components must be wrapped in <RadioGroup />\")\n }\n\n return context\n}\n\nexport type RadioGroupProps<T extends string> = {\n \"defaultValue\"?: T\n \"value\"?: T\n \"name\"?: string\n \"onChange\"?: (value: T) => void\n /** Accessible label for the radio options */\n \"aria-label\"?: string\n /** Determines the layout direction of the radio items\n * @default row\n */\n \"direction\"?: Direction\n /** Controls whether the entire radio group is disabled */\n \"disabled\"?: boolean\n /** Class applied to the radio group container */\n \"className\"?: string\n \"children\": React.ReactNode\n \"required\"?: boolean\n}\n\nexport const RadioGroup = <T extends string>({\n onChange,\n children,\n className,\n direction = \"row\",\n disabled = false,\n ...restProps\n}: RadioGroupProps<T>) => {\n const store = useMemo<RadioGroupContextValue>(\n () => ({\n disabled,\n direction,\n }),\n [disabled, direction],\n )\n\n return (\n <RadioGroupContext value={store}>\n <RadixRadioGroup.Root\n className={clsx(s.RadioGroup, className)}\n data-direction={direction}\n onValueChange={onChange}\n disabled={disabled}\n {...restProps}\n >\n {children}\n </RadixRadioGroup.Root>\n </RadioGroupContext>\n )\n}\n\nexport type RadioGroupItemProps<T extends string> = {\n value: T\n /** Determines if a given radio item is disabled */\n disabled?: boolean\n required?: boolean\n block?: boolean\n className?: string\n /**\n * The orientation of the radio indicator relative to the label.\n *\n * @default \"left\"\n */\n orientation?: \"left\" | \"right\"\n children: React.ReactNode\n}\n\nconst Item = <T extends string>({\n value,\n disabled: itemDisabled = false,\n required,\n children,\n className,\n block = false,\n orientation = \"left\",\n ...restProps\n}: RadioGroupItemProps<T>) => {\n const { disabled: groupDisabled } = useRadioGroupContext()\n const disabled = groupDisabled || itemDisabled\n\n const id = useId()\n const itemId = `${value}-${id}`\n\n return (\n // Providing an extra wrapper enables `label` to be inline-flex, avoiding clickable whitespace\n // when radio options are of varied lengths.\n // NOTE: Important that this is `flex` to prevent the `inline-flex` label from extra, unintentional whitespace.\n <div className={clsx(\"flex\", block && \"w-full\")} {...restProps}>\n <label\n htmlFor={itemId}\n className={clsx(s.RadioLabel, className)}\n data-disabled={disabled ? \"\" : undefined}\n data-block={block ? \"\" : undefined}\n data-orientation={orientation}\n onMouseDown={(event) => {\n if (!event.defaultPrevented && event.detail > 1) event.preventDefault()\n }}\n >\n <div className={s.RadioIndicatorWrapper}>\n <RadixRadioGroup.Item\n id={itemId}\n value={value}\n disabled={disabled}\n required={required}\n className={s.RadioItem}\n >\n <RadixRadioGroup.Indicator className={s.RadioIndicator} />\n </RadixRadioGroup.Item>\n </div>\n {children}\n </label>\n </div>\n )\n}\n\nRadioGroup.Item = Item\n"]}
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
font-size: var(--radio-group-item-font-size);
|
|
16
16
|
line-height: var(--radio-group-item-line-height);
|
|
17
17
|
}
|
|
18
|
+
.RadioLabel[data-orientation="right"]:where([data-block]) {
|
|
19
|
+
justify-content: space-between;
|
|
20
|
+
}
|
|
18
21
|
|
|
19
22
|
.RadioLabel[data-disabled] {
|
|
20
23
|
cursor: not-allowed;
|
|
@@ -22,6 +25,7 @@
|
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
.RadioLabel[data-block] {
|
|
28
|
+
display: flex;
|
|
25
29
|
width: 100%;
|
|
26
30
|
}/* Creates centered alignment with `line-height` of the label */.RadioIndicatorWrapper {
|
|
27
31
|
position: relative;
|
|
@@ -40,6 +44,10 @@
|
|
|
40
44
|
left: 0;
|
|
41
45
|
height: 1px !important;
|
|
42
46
|
transform: none !important;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.RadioLabel[data-orientation="right"] .RadioIndicatorWrapper {
|
|
50
|
+
order: 1;
|
|
43
51
|
}.RadioItem {
|
|
44
52
|
position: relative;
|
|
45
53
|
display: flex;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
@layer components {/* =============================================
|
|
2
2
|
Sidebar Component Styles
|
|
3
|
-
Based on OpenAI Platform styling
|
|
4
3
|
============================================= *//* Layout container (wraps sidebar + content) */.SidebarLayout {
|
|
5
4
|
display: flex;
|
|
6
5
|
width: 100%;
|
|
@@ -4,9 +4,10 @@ import clsx from "clsx";
|
|
|
4
4
|
import { Switch as RadixSwitch } from "radix-ui";
|
|
5
5
|
import { useId } from "react";
|
|
6
6
|
import s from "./Switch.module.css";
|
|
7
|
-
export const Switch = ({ className, label, id: propsId, disabled, labelPosition = "end", ...restProps }) => {
|
|
7
|
+
export const Switch = ({ className, label, description, id: propsId, disabled, labelPosition = "end", ...restProps }) => {
|
|
8
8
|
const reactId = useId();
|
|
9
9
|
const id = propsId ?? reactId;
|
|
10
|
-
|
|
10
|
+
const descriptionId = description ? `${id}-description` : undefined;
|
|
11
|
+
return (_jsxs("div", { className: clsx(s.Container, className), "data-disabled": disabled ? "" : undefined, "data-has-label": label ? "" : undefined, "data-label-position": labelPosition, children: [_jsx(RadixSwitch.Root, { id: id, className: s.Track, disabled: disabled, "aria-describedby": descriptionId, ...restProps, children: _jsx(RadixSwitch.Thumb, { className: s.Thumb }) }), label && (description ? (_jsxs("div", { className: s.LabelGroup, children: [_jsx("label", { htmlFor: id, className: s.Label, children: label }), _jsx("span", { id: descriptionId, className: s.Description, children: description })] })) : (_jsx("label", { htmlFor: id, className: s.Label, children: label })))] }));
|
|
11
12
|
};
|
|
12
13
|
//# sourceMappingURL=Switch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.js","sourceRoot":"","sources":["../../../../src/components/Switch/Switch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,EAA0C,KAAK,EAAE,MAAM,OAAO,CAAA;AACrE,OAAO,CAAC,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"Switch.js","sourceRoot":"","sources":["../../../../src/components/Switch/Switch.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,EAA0C,KAAK,EAAE,MAAM,OAAO,CAAA;AACrE,OAAO,CAAC,MAAM,qBAAqB,CAAA;AAoCnC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EACrB,SAAS,EACT,KAAK,EACL,WAAW,EACX,EAAE,EAAE,OAAO,EACX,QAAQ,EACR,aAAa,GAAG,KAAK,EACrB,GAAG,SAAS,EACA,EAAE,EAAE;IAChB,MAAM,OAAO,GAAG,KAAK,EAAE,CAAA;IACvB,MAAM,EAAE,GAAG,OAAO,IAAI,OAAO,CAAA;IAC7B,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,SAAS,CAAA;IAEnE,OAAO,CACL,eACE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,mBACxB,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,oBACxB,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,yBACjB,aAAa,aAElC,KAAC,WAAW,CAAC,IAAI,IACf,EAAE,EAAE,EAAE,EACN,SAAS,EAAE,CAAC,CAAC,KAAK,EAClB,QAAQ,EAAE,QAAQ,sBACA,aAAa,KAC3B,SAAS,YAEb,KAAC,WAAW,CAAC,KAAK,IAAC,SAAS,EAAE,CAAC,CAAC,KAAK,GAAI,GACxB,EAElB,KAAK,IAAI,CACR,WAAW,CAAC,CAAC,CAAC,CACZ,eAAK,SAAS,EAAE,CAAC,CAAC,UAAU,aAC1B,gBAAO,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,KAAK,YACnC,KAAK,GACA,EACR,eAAM,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC,WAAW,YAC9C,WAAW,GACP,IACH,CACP,CAAC,CAAC,CAAC,CACF,gBAAO,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,KAAK,YACnC,KAAK,GACA,CACT,CACF,IACG,CACP,CAAA;AACH,CAAC,CAAA","sourcesContent":["\"use client\"\n\nimport clsx from \"clsx\"\nimport { Switch as RadixSwitch } from \"radix-ui\"\nimport { type FocusEventHandler, type ReactNode, useId } from \"react\"\nimport s from \"./Switch.module.css\"\n\nexport type SwitchProps = {\n /** The `id` of the switch. */\n id?: string\n /** The state of the switch when it is initially rendered. Use when you do not need to control its state. */\n defaultChecked?: boolean\n /** The controlled state of the switch. Must be used in conjunction with `onCheckedChange`. */\n checked?: boolean\n /** Optional accessible label rendered next to the switch. */\n label?: ReactNode\n /** Optional description rendered below the label. Linked via `aria-describedby`. */\n description?: ReactNode\n /** Event handler called when the state of the switch changes. */\n onCheckedChange?: (nextState: boolean) => void\n /** Event handler called when the checkbox looses focus. */\n onBlur?: FocusEventHandler<HTMLButtonElement>\n /** Event handler called when the checkbox gains focus. */\n onFocus?: FocusEventHandler<HTMLButtonElement>\n /** When `true`, prevents the user from interacting with the switch. */\n disabled?: boolean\n /** When `true`, indicates that the user must check the switch before the owning form can be submitted. */\n required?: boolean\n /** The name of the switch. Submitted with its owning form as part of a name/value pair. */\n name?: string\n /** The value given as data when submitted with a `name`. */\n value?: string\n /** CSS classes applied to wrapper node */\n className?: string\n /**\n * The position of the label relative to the switch.\n * @default end\n */\n labelPosition?: \"start\" | \"end\"\n}\n\nexport const Switch = ({\n className,\n label,\n description,\n id: propsId,\n disabled,\n labelPosition = \"end\",\n ...restProps\n}: SwitchProps) => {\n const reactId = useId()\n const id = propsId ?? reactId\n const descriptionId = description ? `${id}-description` : undefined\n\n return (\n <div\n className={clsx(s.Container, className)}\n data-disabled={disabled ? \"\" : undefined}\n data-has-label={label ? \"\" : undefined}\n data-label-position={labelPosition}\n >\n <RadixSwitch.Root\n id={id}\n className={s.Track}\n disabled={disabled}\n aria-describedby={descriptionId}\n {...restProps}\n >\n <RadixSwitch.Thumb className={s.Thumb} />\n </RadixSwitch.Root>\n\n {label && (\n description ? (\n <div className={s.LabelGroup}>\n <label htmlFor={id} className={s.Label}>\n {label}\n </label>\n <span id={descriptionId} className={s.Description}>\n {description}\n </span>\n </div>\n ) : (\n <label htmlFor={id} className={s.Label}>\n {label}\n </label>\n )\n )}\n </div>\n )\n}\n"]}
|
|
@@ -75,20 +75,46 @@
|
|
|
75
75
|
.Thumb[data-disabled] {
|
|
76
76
|
background: var(--switch-thumb-color-disabled);
|
|
77
77
|
box-shadow: none;
|
|
78
|
+
}.LabelGroup {
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
gap: 4px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Use padding so that the spacing is intrinsic to the group, remaining clickable. */
|
|
85
|
+
[data-label-position="end"] .LabelGroup {
|
|
86
|
+
padding-left: var(--switch-label-gap);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
[data-label-position="start"] .LabelGroup {
|
|
90
|
+
padding-right: var(--switch-label-gap);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
[data-disabled] .LabelGroup {
|
|
94
|
+
cursor: not-allowed;
|
|
78
95
|
}.Label {
|
|
79
96
|
cursor: pointer;
|
|
80
97
|
}
|
|
81
98
|
|
|
82
99
|
/* Use padding so that the spacing is intrinsic to the label, remaining clickable. */
|
|
83
|
-
[data-label-position="end"] .Label {
|
|
100
|
+
[data-label-position="end"] > .Label {
|
|
84
101
|
padding-left: var(--switch-label-gap);
|
|
85
102
|
}
|
|
86
103
|
|
|
87
|
-
[data-label-position="start"] .Label {
|
|
104
|
+
[data-label-position="start"] > .Label {
|
|
88
105
|
padding-right: var(--switch-label-gap);
|
|
89
106
|
}
|
|
90
107
|
|
|
91
108
|
[data-disabled] .Label {
|
|
92
109
|
cursor: not-allowed;
|
|
110
|
+
}.Description {
|
|
111
|
+
color: var(--color-text-secondary);
|
|
112
|
+
font-size: var(--font-text-xs-size);
|
|
113
|
+
line-height: var(--font-text-xs-line-height);
|
|
114
|
+
cursor: pointer;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
[data-disabled] .Description {
|
|
118
|
+
cursor: not-allowed;
|
|
93
119
|
}
|
|
94
120
|
}
|
|
@@ -99,12 +99,14 @@
|
|
|
99
99
|
--input-outline-border-color-focus: var(--alpha-50);
|
|
100
100
|
--input-soft-background-color: var(--color-background-primary-soft-alpha);
|
|
101
101
|
--input-soft-border-color-focus: var(--alpha-20);
|
|
102
|
+
--input-border-color-invalid: var(--color-border-danger-outline);
|
|
102
103
|
|
|
103
104
|
/* =============================================
|
|
104
105
|
FieldError
|
|
105
106
|
============================================= */
|
|
107
|
+
--field-error-color: var(--color-text-danger-outline);
|
|
106
108
|
--field-error-font-size: 0.75rem;
|
|
107
|
-
--field-error-line-height:
|
|
109
|
+
--field-error-line-height: var(--font-text-xs-line-height);
|
|
108
110
|
--field-error-icon-size: 1rem;
|
|
109
111
|
--field-error-gap: calc(var(--spacing) * 2);
|
|
110
112
|
--field-error-margin-top: 0.5rem;
|
|
@@ -114,7 +116,8 @@
|
|
|
114
116
|
/* =============================================
|
|
115
117
|
Field
|
|
116
118
|
============================================= */
|
|
117
|
-
--field-
|
|
119
|
+
--field-horizontal-label-width: 120px;
|
|
120
|
+
--field-horizontal-control-width: 240px;
|
|
118
121
|
|
|
119
122
|
/* =============================================
|
|
120
123
|
FloatingLabelInput
|
|
@@ -123,9 +126,9 @@
|
|
|
123
126
|
--floating-input-gutter: 1.25rem;
|
|
124
127
|
--floating-input-border-radius: var(--radius-full);
|
|
125
128
|
--floating-input-background: var(--color-surface);
|
|
126
|
-
--floating-input-border-color-invalid: var(--
|
|
129
|
+
--floating-input-border-color-invalid: var(--color-border-danger-outline);
|
|
127
130
|
--floating-input-label-color: var(--color-text-tertiary);
|
|
128
|
-
--floating-input-label-color-invalid: var(--
|
|
131
|
+
--floating-input-label-color-invalid: var(--color-text-danger-outline);
|
|
129
132
|
--floating-input-transition-duration: 80ms;
|
|
130
133
|
--floating-input-label-scale: 0.88;
|
|
131
134
|
|
|
@@ -385,8 +388,6 @@
|
|
|
385
388
|
:where(:root), :where([data-theme="light"]) {
|
|
386
389
|
--avatar-image-border-color: var(--alpha-04);
|
|
387
390
|
--input-outline-border-color-hover: var(--alpha-25);
|
|
388
|
-
--input-border-color-invalid: var(--red-500);
|
|
389
|
-
--field-error-color: #d00e17;
|
|
390
391
|
--floating-input-border-color: rgb(0 0 0 / 15%);
|
|
391
392
|
--floating-input-border-color-hover: rgb(0 0 0 / 20%);
|
|
392
393
|
--floating-input-border-color-focus: #3e68ff;
|
|
@@ -424,8 +425,6 @@
|
|
|
424
425
|
:where([data-theme="dark"]) {
|
|
425
426
|
--avatar-image-border-color: var(--alpha-15);
|
|
426
427
|
--input-outline-border-color-hover: var(--alpha-30);
|
|
427
|
-
--input-border-color-invalid: var(--red-600);
|
|
428
|
-
--field-error-color: #ff6b6b;
|
|
429
428
|
--floating-input-border-color: rgb(255 255 255 / 16%);
|
|
430
429
|
--floating-input-border-color-hover: rgb(255 255 255 / 24%);
|
|
431
430
|
--floating-input-border-color-focus: #6f8dff;
|
|
@@ -30,5 +30,17 @@ export type CheckboxProps = {
|
|
|
30
30
|
* @default "left"
|
|
31
31
|
*/
|
|
32
32
|
orientation?: "left" | "right";
|
|
33
|
+
/**
|
|
34
|
+
* Determines if the checkbox should be a fully rounded pill shape.
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
pill?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Visual style variant for the checkbox indicator.
|
|
40
|
+
* - `"solid"` — filled background when checked (default)
|
|
41
|
+
* - `"ghost"` — no border or background, checkmark only
|
|
42
|
+
* @default "solid"
|
|
43
|
+
*/
|
|
44
|
+
variant?: "solid" | "ghost";
|
|
33
45
|
};
|
|
34
|
-
export declare const Checkbox: ({ className, label, id: propsId, disabled, orientation, ...restProps }: CheckboxProps) => import("react/jsx-runtime").JSX.Element;
|
|
46
|
+
export declare const Checkbox: ({ className, label, id: propsId, disabled, orientation, pill, variant, ...restProps }: CheckboxProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -3,6 +3,7 @@ export type FieldChildProps = {
|
|
|
3
3
|
id: string;
|
|
4
4
|
"aria-describedby"?: string;
|
|
5
5
|
"aria-invalid"?: boolean;
|
|
6
|
+
opticallyAlign?: "start" | "end";
|
|
6
7
|
};
|
|
7
8
|
export type FieldProps = {
|
|
8
9
|
/**
|
|
@@ -44,6 +45,12 @@ export type FieldProps = {
|
|
|
44
45
|
* the id set on the child control and the `htmlFor` on the label.
|
|
45
46
|
*/
|
|
46
47
|
id?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Applies a negative margin on the child control using its gutter to
|
|
50
|
+
* optically align the control's text with surrounding content.
|
|
51
|
+
* Passed through to the child control via cloneElement / render prop.
|
|
52
|
+
*/
|
|
53
|
+
opticallyAlign?: "start" | "end";
|
|
47
54
|
/**
|
|
48
55
|
* CSS class applied to the root wrapper
|
|
49
56
|
*/
|
|
@@ -55,4 +62,4 @@ export type FieldProps = {
|
|
|
55
62
|
*/
|
|
56
63
|
children: React.ReactElement | ((fieldProps: FieldChildProps) => React.ReactNode);
|
|
57
64
|
};
|
|
58
|
-
export declare function Field({ label, description, errorMessage, size, required, orientation, id: idProp, className, children, }: FieldProps): import("react/jsx-runtime").JSX.Element;
|
|
65
|
+
export declare function Field({ label, description, errorMessage, size, required, orientation, opticallyAlign, id: idProp, className, children, }: FieldProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -6,7 +6,7 @@ export type RadioGroupProps<T extends string> = {
|
|
|
6
6
|
"name"?: string;
|
|
7
7
|
"onChange"?: (value: T) => void;
|
|
8
8
|
/** Accessible label for the radio options */
|
|
9
|
-
"aria-label"
|
|
9
|
+
"aria-label"?: string;
|
|
10
10
|
/** Determines the layout direction of the radio items
|
|
11
11
|
* @default row
|
|
12
12
|
*/
|
|
@@ -20,7 +20,7 @@ export type RadioGroupProps<T extends string> = {
|
|
|
20
20
|
};
|
|
21
21
|
export declare const RadioGroup: {
|
|
22
22
|
<T extends string>({ onChange, children, className, direction, disabled, ...restProps }: RadioGroupProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
23
|
-
Item: <T extends string>({ value, disabled: itemDisabled, required, children, className, block, ...restProps }: RadioGroupItemProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
Item: <T extends string>({ value, disabled: itemDisabled, required, children, className, block, orientation, ...restProps }: RadioGroupItemProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
24
24
|
};
|
|
25
25
|
export type RadioGroupItemProps<T extends string> = {
|
|
26
26
|
value: T;
|
|
@@ -29,6 +29,12 @@ export type RadioGroupItemProps<T extends string> = {
|
|
|
29
29
|
required?: boolean;
|
|
30
30
|
block?: boolean;
|
|
31
31
|
className?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The orientation of the radio indicator relative to the label.
|
|
34
|
+
*
|
|
35
|
+
* @default "left"
|
|
36
|
+
*/
|
|
37
|
+
orientation?: "left" | "right";
|
|
32
38
|
children: React.ReactNode;
|
|
33
39
|
};
|
|
34
40
|
export {};
|
|
@@ -6,8 +6,10 @@ export type SwitchProps = {
|
|
|
6
6
|
defaultChecked?: boolean;
|
|
7
7
|
/** The controlled state of the switch. Must be used in conjunction with `onCheckedChange`. */
|
|
8
8
|
checked?: boolean;
|
|
9
|
-
/** Optional accessible label rendered to the
|
|
9
|
+
/** Optional accessible label rendered next to the switch. */
|
|
10
10
|
label?: ReactNode;
|
|
11
|
+
/** Optional description rendered below the label. Linked via `aria-describedby`. */
|
|
12
|
+
description?: ReactNode;
|
|
11
13
|
/** Event handler called when the state of the switch changes. */
|
|
12
14
|
onCheckedChange?: (nextState: boolean) => void;
|
|
13
15
|
/** Event handler called when the checkbox looses focus. */
|
|
@@ -30,4 +32,4 @@ export type SwitchProps = {
|
|
|
30
32
|
*/
|
|
31
33
|
labelPosition?: "start" | "end";
|
|
32
34
|
};
|
|
33
|
-
export declare const Switch: ({ className, label, id: propsId, disabled, labelPosition, ...restProps }: SwitchProps) => import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
export declare const Switch: ({ className, label, description, id: propsId, disabled, labelPosition, ...restProps }: SwitchProps) => import("react/jsx-runtime").JSX.Element;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plexui/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Modern design system for building high-quality applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"tailwind",
|
|
23
23
|
"plexui",
|
|
24
24
|
"radix",
|
|
25
|
-
"
|
|
25
|
+
"ui-kit"
|
|
26
26
|
],
|
|
27
27
|
"engines": {
|
|
28
28
|
"node": ">=18"
|
|
@@ -33,6 +33,9 @@
|
|
|
33
33
|
],
|
|
34
34
|
"exports": {
|
|
35
35
|
"./css": "./dist/es/styles/index.css",
|
|
36
|
+
"./styles/variables-primitive.css": "./dist/es/styles/variables-primitive.css",
|
|
37
|
+
"./styles/variables-semantic.css": "./dist/es/styles/variables-semantic.css",
|
|
38
|
+
"./styles/variables-components.css": "./dist/es/styles/variables-components.css",
|
|
36
39
|
"./components/*": {
|
|
37
40
|
"types": "./dist/types/components/*/index.d.ts",
|
|
38
41
|
"default": "./dist/es/components/*/index.js"
|