@viax.io/uxm 4.45.0 → 4.47.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/CHANGELOG.md +14 -0
- package/dist/studio/lib/registry/inputs/radio-group.cjs +33 -1
- package/dist/studio/lib/registry/inputs/radio-group.cjs.map +1 -1
- package/dist/studio/lib/registry/inputs/radio-group.d.ts.map +1 -1
- package/dist/studio/lib/registry/inputs/radio-group.js +33 -1
- package/dist/studio/lib/registry/inputs/radio-group.js.map +1 -1
- package/dist/ui/index.cjs +2 -0
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +2 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/menu/index.cjs +3 -1
- package/dist/ui/menu/index.cjs.map +1 -1
- package/dist/ui/menu/index.d.ts +1 -0
- package/dist/ui/menu/index.d.ts.map +1 -1
- package/dist/ui/menu/index.js +1 -0
- package/dist/ui/menu/index.js.map +1 -1
- package/dist/ui/menu/menu-button.cjs +89 -0
- package/dist/ui/menu/menu-button.cjs.map +1 -0
- package/dist/ui/menu/menu-button.css +30 -0
- package/dist/ui/menu/menu-button.d.ts +48 -0
- package/dist/ui/menu/menu-button.d.ts.map +1 -0
- package/dist/ui/menu/menu-button.js +70 -0
- package/dist/ui/menu/menu-button.js.map +1 -0
- package/dist/ui/radio-group/radio-group-preview.cjs +86 -35
- package/dist/ui/radio-group/radio-group-preview.cjs.map +1 -1
- package/dist/ui/radio-group/radio-group-preview.d.ts.map +1 -1
- package/dist/ui/radio-group/radio-group-preview.js +87 -36
- package/dist/ui/radio-group/radio-group-preview.js.map +1 -1
- package/dist/ui/radio-group/radio-group.cjs +46 -18
- package/dist/ui/radio-group/radio-group.cjs.map +1 -1
- package/dist/ui/radio-group/radio-group.css +82 -0
- package/dist/ui/radio-group/radio-group.d.ts +24 -1
- package/dist/ui/radio-group/radio-group.d.ts.map +1 -1
- package/dist/ui/radio-group/radio-group.js +46 -18
- package/dist/ui/radio-group/radio-group.js.map +1 -1
- package/dist/ui/styles.css +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/menu/menu-button.tsx"],"sourcesContent":["import { cn } from '@/helpers';\nimport {\n ButtonGhost,\n ButtonPrimary,\n ButtonSecondary,\n ButtonTertiary,\n} from '@/ui/button';\nimport { Icon } from '@/ui/icon';\nimport type { PopoverPlacement } from '@/ui/popover';\n\nimport { Menu } from './menu';\n\nimport type { MenuEntry } from './menu';\nimport type { ComponentPropsWithRef, ReactNode } from 'react';\n\n/** Which shipped button renders the trigger. */\nexport type MenuButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'ghost';\n\nconst TRIGGER: Record<\n MenuButtonVariant,\n (props: ComponentPropsWithRef<'button'>) => ReactNode\n> = {\n primary: ButtonPrimary,\n secondary: ButtonSecondary,\n tertiary: ButtonTertiary,\n ghost: ButtonGhost,\n};\n\nexport interface MenuButtonProps {\n /** Menu entries — the same `MenuEntry[]` `Menu` takes. */\n items: MenuEntry[];\n /** Button label. */\n children: ReactNode;\n /** Which shipped button renders the trigger. Default `secondary`. */\n variant?: MenuButtonVariant;\n /** Optional leading icon, before the label. */\n icon?: ReactNode;\n /**\n * Trailing dropdown affordance. Default a `chevron-down` that rotates while\n * the menu is open; pass `false` to omit it (for a trigger whose label\n * already reads as a menu, or where space is tight).\n */\n chevron?: boolean;\n /** Forwarded to `Menu`. Default `bottom-end`, as `Menu`'s own default. */\n placement?: PopoverPlacement;\n /** Disables the trigger. The menu cannot be opened. */\n disabled?: boolean;\n /** Accessible name for the menu panel. Forwarded to `Menu`. */\n 'aria-label'?: string;\n /** Class on the trigger button. */\n className?: string;\n}\n\n/**\n * The labelled dropdown button — a `Menu` whose trigger is one of the shipped\n * `Button*` atoms, with the chevron, the ARIA and the trigger ref already\n * wired.\n *\n * `Menu` is deliberately trigger-agnostic: `renderTrigger` is required so a ⋮\n * `IconButton`, an avatar or a field can all open one. That is the right\n * primitive, but it means the single most common shape — a button that says\n * what it does and drops a menu — is re-derived at every call site, along with\n * a hand-added chevron and the `triggerProps` plumbing. This is that shape,\n * shipped once.\n *\n * It is a composition, not a new visual primitive: the button is a real\n * `Button*`, the menu is a real `Menu`. Anything this does not expose —\n * controlled `open`, `matchAnchorWidth`, a bespoke trigger — is a sign to drop\n * to `Menu` + `renderTrigger`, which is unchanged and always available.\n */\nexport function MenuButton({\n items,\n children,\n variant = 'secondary',\n icon,\n chevron = true,\n placement,\n disabled,\n 'aria-label': ariaLabel,\n className,\n}: MenuButtonProps) {\n const Trigger = TRIGGER[variant];\n\n return (\n <Menu\n items={items}\n placement={placement}\n aria-label={ariaLabel}\n renderTrigger={({ open, triggerProps }) => (\n // `triggerProps` spreads straight onto the button — its `ref` included.\n // Before 4.45.0 the button family did not declare `ref`, which is why\n // consumers wrapped the trigger in a `<span ref>`; that wrapper is what\n // this composite exists to stop re-deriving.\n <Trigger\n {...triggerProps}\n disabled={disabled}\n className={cn('uxm-menu-button', className)}\n >\n {icon}\n {children}\n {chevron && (\n <Icon\n glyph=\"chevron-down\"\n size={14}\n className={cn(\n 'uxm-menu-button__chevron',\n open && 'uxm-menu-button__chevron--open',\n )}\n />\n )}\n </Trigger>\n )}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA6FQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA7FR,qBAAmB;AACnB,oBAKO;AACP,kBAAqB;AAGrB,kBAAqB;AAQrB,MAAM,UAGF;AAAA,EACF,SAAS;AAAA,EACT,WAAW;AAAA,EACX,UAAU;AAAA,EACV,OAAO;AACT;AA4CO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AACF,GAAoB;AAClB,QAAM,UAAU,QAAQ,OAAO;AAE/B,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,cAAY;AAAA,MACZ,eAAe,CAAC,EAAE,MAAM,aAAa,MAKnC;AAAA,QAAC;AAAA;AAAA,UACE,GAAG;AAAA,UACJ;AAAA,UACA,eAAW,mBAAG,mBAAmB,SAAS;AAAA,UAEzC;AAAA;AAAA,YACA;AAAA,YACA,WACC;AAAA,cAAC;AAAA;AAAA,gBACC,OAAM;AAAA,gBACN,MAAM;AAAA,gBACN,eAAW;AAAA,kBACT;AAAA,kBACA,QAAQ;AAAA,gBACV;AAAA;AAAA,YACF;AAAA;AAAA;AAAA,MAEJ;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* ── menu-button ── */
|
|
2
|
+
/* `MenuButton` is a composition: the trigger IS a shipped `Button*`, so the
|
|
3
|
+
whole row — `display: inline-flex`, the alignment, and
|
|
4
|
+
`gap: var(--uxm-button-{variant}-gap, 8px)` — already comes from that atom.
|
|
5
|
+
Nothing here re-declares any of it.
|
|
6
|
+
|
|
7
|
+
That is not tidiness, it is the difference between the button's gap knob
|
|
8
|
+
working and not: `styles.css` imports `button.css` at line 16 and this file
|
|
9
|
+
at 65, so a `gap` declared here would win the cascade at equal specificity
|
|
10
|
+
and quietly pin a MenuButton to its own value while every other button in
|
|
11
|
+
the app followed `--uxm-button-{variant}-gap`.
|
|
12
|
+
|
|
13
|
+
So this block owns exactly one thing the button cannot know about: the
|
|
14
|
+
chevron's open state. */
|
|
15
|
+
.uxm-menu-button__chevron {
|
|
16
|
+
flex-shrink: 0;
|
|
17
|
+
/* Turns to point at the open panel. Purely decorative — `aria-expanded` on
|
|
18
|
+
the trigger is what actually announces the state. */
|
|
19
|
+
transition: transform 0.15s ease;
|
|
20
|
+
}
|
|
21
|
+
.uxm-menu-button__chevron--open {
|
|
22
|
+
transform: rotate(180deg);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* The rotation is decoration; the chevron must still point the right way. */
|
|
26
|
+
@media (prefers-reduced-motion: reduce) {
|
|
27
|
+
.uxm-menu-button__chevron {
|
|
28
|
+
transition: none;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { PopoverPlacement } from '../popover/index.js';
|
|
2
|
+
import type { MenuEntry } from './menu.js';
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
/** Which shipped button renders the trigger. */
|
|
5
|
+
export type MenuButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'ghost';
|
|
6
|
+
export interface MenuButtonProps {
|
|
7
|
+
/** Menu entries — the same `MenuEntry[]` `Menu` takes. */
|
|
8
|
+
items: MenuEntry[];
|
|
9
|
+
/** Button label. */
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
/** Which shipped button renders the trigger. Default `secondary`. */
|
|
12
|
+
variant?: MenuButtonVariant;
|
|
13
|
+
/** Optional leading icon, before the label. */
|
|
14
|
+
icon?: ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* Trailing dropdown affordance. Default a `chevron-down` that rotates while
|
|
17
|
+
* the menu is open; pass `false` to omit it (for a trigger whose label
|
|
18
|
+
* already reads as a menu, or where space is tight).
|
|
19
|
+
*/
|
|
20
|
+
chevron?: boolean;
|
|
21
|
+
/** Forwarded to `Menu`. Default `bottom-end`, as `Menu`'s own default. */
|
|
22
|
+
placement?: PopoverPlacement;
|
|
23
|
+
/** Disables the trigger. The menu cannot be opened. */
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
/** Accessible name for the menu panel. Forwarded to `Menu`. */
|
|
26
|
+
'aria-label'?: string;
|
|
27
|
+
/** Class on the trigger button. */
|
|
28
|
+
className?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The labelled dropdown button — a `Menu` whose trigger is one of the shipped
|
|
32
|
+
* `Button*` atoms, with the chevron, the ARIA and the trigger ref already
|
|
33
|
+
* wired.
|
|
34
|
+
*
|
|
35
|
+
* `Menu` is deliberately trigger-agnostic: `renderTrigger` is required so a ⋮
|
|
36
|
+
* `IconButton`, an avatar or a field can all open one. That is the right
|
|
37
|
+
* primitive, but it means the single most common shape — a button that says
|
|
38
|
+
* what it does and drops a menu — is re-derived at every call site, along with
|
|
39
|
+
* a hand-added chevron and the `triggerProps` plumbing. This is that shape,
|
|
40
|
+
* shipped once.
|
|
41
|
+
*
|
|
42
|
+
* It is a composition, not a new visual primitive: the button is a real
|
|
43
|
+
* `Button*`, the menu is a real `Menu`. Anything this does not expose —
|
|
44
|
+
* controlled `open`, `matchAnchorWidth`, a bespoke trigger — is a sign to drop
|
|
45
|
+
* to `Menu` + `renderTrigger`, which is unchanged and always available.
|
|
46
|
+
*/
|
|
47
|
+
export declare function MenuButton({ items, children, variant, icon, chevron, placement, disabled, 'aria-label': ariaLabel, className, }: MenuButtonProps): import("react").JSX.Element;
|
|
48
|
+
//# sourceMappingURL=menu-button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu-button.d.ts","sourceRoot":"","sources":["../../../src/ui/menu/menu-button.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAyB,SAAS,EAAE,MAAM,OAAO,CAAC;AAE9D,gDAAgD;AAChD,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC;AAY/E,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,oBAAoB;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,qEAAqE;IACrE,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,+CAA+C;IAC/C,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,uDAAuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,OAAqB,EACrB,IAAI,EACJ,OAAc,EACd,SAAS,EACT,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,SAAS,GACV,EAAE,eAAe,+BAkCjB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../helpers/index.js";
|
|
3
|
+
import {
|
|
4
|
+
ButtonGhost,
|
|
5
|
+
ButtonPrimary,
|
|
6
|
+
ButtonSecondary,
|
|
7
|
+
ButtonTertiary
|
|
8
|
+
} from "../button/index.js";
|
|
9
|
+
import { Icon } from "../icon/index.js";
|
|
10
|
+
import { Menu } from "./menu.js";
|
|
11
|
+
const TRIGGER = {
|
|
12
|
+
primary: ButtonPrimary,
|
|
13
|
+
secondary: ButtonSecondary,
|
|
14
|
+
tertiary: ButtonTertiary,
|
|
15
|
+
ghost: ButtonGhost
|
|
16
|
+
};
|
|
17
|
+
function MenuButton({
|
|
18
|
+
items,
|
|
19
|
+
children,
|
|
20
|
+
variant = "secondary",
|
|
21
|
+
icon,
|
|
22
|
+
chevron = true,
|
|
23
|
+
placement,
|
|
24
|
+
disabled,
|
|
25
|
+
"aria-label": ariaLabel,
|
|
26
|
+
className
|
|
27
|
+
}) {
|
|
28
|
+
const Trigger = TRIGGER[variant];
|
|
29
|
+
return /* @__PURE__ */ jsx(
|
|
30
|
+
Menu,
|
|
31
|
+
{
|
|
32
|
+
items,
|
|
33
|
+
placement,
|
|
34
|
+
"aria-label": ariaLabel,
|
|
35
|
+
renderTrigger: ({ open, triggerProps }) => (
|
|
36
|
+
// `triggerProps` spreads straight onto the button — its `ref` included.
|
|
37
|
+
// Before 4.45.0 the button family did not declare `ref`, which is why
|
|
38
|
+
// consumers wrapped the trigger in a `<span ref>`; that wrapper is what
|
|
39
|
+
// this composite exists to stop re-deriving.
|
|
40
|
+
/* @__PURE__ */ jsxs(
|
|
41
|
+
Trigger,
|
|
42
|
+
{
|
|
43
|
+
...triggerProps,
|
|
44
|
+
disabled,
|
|
45
|
+
className: cn("uxm-menu-button", className),
|
|
46
|
+
children: [
|
|
47
|
+
icon,
|
|
48
|
+
children,
|
|
49
|
+
chevron && /* @__PURE__ */ jsx(
|
|
50
|
+
Icon,
|
|
51
|
+
{
|
|
52
|
+
glyph: "chevron-down",
|
|
53
|
+
size: 14,
|
|
54
|
+
className: cn(
|
|
55
|
+
"uxm-menu-button__chevron",
|
|
56
|
+
open && "uxm-menu-button__chevron--open"
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
MenuButton
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=menu-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/menu/menu-button.tsx"],"sourcesContent":["import { cn } from '@/helpers';\nimport {\n ButtonGhost,\n ButtonPrimary,\n ButtonSecondary,\n ButtonTertiary,\n} from '@/ui/button';\nimport { Icon } from '@/ui/icon';\nimport type { PopoverPlacement } from '@/ui/popover';\n\nimport { Menu } from './menu';\n\nimport type { MenuEntry } from './menu';\nimport type { ComponentPropsWithRef, ReactNode } from 'react';\n\n/** Which shipped button renders the trigger. */\nexport type MenuButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'ghost';\n\nconst TRIGGER: Record<\n MenuButtonVariant,\n (props: ComponentPropsWithRef<'button'>) => ReactNode\n> = {\n primary: ButtonPrimary,\n secondary: ButtonSecondary,\n tertiary: ButtonTertiary,\n ghost: ButtonGhost,\n};\n\nexport interface MenuButtonProps {\n /** Menu entries — the same `MenuEntry[]` `Menu` takes. */\n items: MenuEntry[];\n /** Button label. */\n children: ReactNode;\n /** Which shipped button renders the trigger. Default `secondary`. */\n variant?: MenuButtonVariant;\n /** Optional leading icon, before the label. */\n icon?: ReactNode;\n /**\n * Trailing dropdown affordance. Default a `chevron-down` that rotates while\n * the menu is open; pass `false` to omit it (for a trigger whose label\n * already reads as a menu, or where space is tight).\n */\n chevron?: boolean;\n /** Forwarded to `Menu`. Default `bottom-end`, as `Menu`'s own default. */\n placement?: PopoverPlacement;\n /** Disables the trigger. The menu cannot be opened. */\n disabled?: boolean;\n /** Accessible name for the menu panel. Forwarded to `Menu`. */\n 'aria-label'?: string;\n /** Class on the trigger button. */\n className?: string;\n}\n\n/**\n * The labelled dropdown button — a `Menu` whose trigger is one of the shipped\n * `Button*` atoms, with the chevron, the ARIA and the trigger ref already\n * wired.\n *\n * `Menu` is deliberately trigger-agnostic: `renderTrigger` is required so a ⋮\n * `IconButton`, an avatar or a field can all open one. That is the right\n * primitive, but it means the single most common shape — a button that says\n * what it does and drops a menu — is re-derived at every call site, along with\n * a hand-added chevron and the `triggerProps` plumbing. This is that shape,\n * shipped once.\n *\n * It is a composition, not a new visual primitive: the button is a real\n * `Button*`, the menu is a real `Menu`. Anything this does not expose —\n * controlled `open`, `matchAnchorWidth`, a bespoke trigger — is a sign to drop\n * to `Menu` + `renderTrigger`, which is unchanged and always available.\n */\nexport function MenuButton({\n items,\n children,\n variant = 'secondary',\n icon,\n chevron = true,\n placement,\n disabled,\n 'aria-label': ariaLabel,\n className,\n}: MenuButtonProps) {\n const Trigger = TRIGGER[variant];\n\n return (\n <Menu\n items={items}\n placement={placement}\n aria-label={ariaLabel}\n renderTrigger={({ open, triggerProps }) => (\n // `triggerProps` spreads straight onto the button — its `ref` included.\n // Before 4.45.0 the button family did not declare `ref`, which is why\n // consumers wrapped the trigger in a `<span ref>`; that wrapper is what\n // this composite exists to stop re-deriving.\n <Trigger\n {...triggerProps}\n disabled={disabled}\n className={cn('uxm-menu-button', className)}\n >\n {icon}\n {children}\n {chevron && (\n <Icon\n glyph=\"chevron-down\"\n size={14}\n className={cn(\n 'uxm-menu-button__chevron',\n open && 'uxm-menu-button__chevron--open',\n )}\n />\n )}\n </Trigger>\n )}\n />\n );\n}\n"],"mappings":"AA6FQ,SAQI,KARJ;AA7FR,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY;AAGrB,SAAS,YAAY;AAQrB,MAAM,UAGF;AAAA,EACF,SAAS;AAAA,EACT,WAAW;AAAA,EACX,UAAU;AAAA,EACV,OAAO;AACT;AA4CO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AACF,GAAoB;AAClB,QAAM,UAAU,QAAQ,OAAO;AAE/B,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,cAAY;AAAA,MACZ,eAAe,CAAC,EAAE,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,QAKnC;AAAA,UAAC;AAAA;AAAA,YACE,GAAG;AAAA,YACJ;AAAA,YACA,WAAW,GAAG,mBAAmB,SAAS;AAAA,YAEzC;AAAA;AAAA,cACA;AAAA,cACA,WACC;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAM;AAAA,kBACN,MAAM;AAAA,kBACN,WAAW;AAAA,oBACT;AAAA,oBACA,QAAQ;AAAA,kBACV;AAAA;AAAA,cACF;AAAA;AAAA;AAAA,QAEJ;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
|
|
@@ -27,16 +27,80 @@ function ShowcaseRow({
|
|
|
27
27
|
selected,
|
|
28
28
|
state,
|
|
29
29
|
styles,
|
|
30
|
-
label
|
|
30
|
+
label,
|
|
31
|
+
variant,
|
|
32
|
+
indicator
|
|
31
33
|
}) {
|
|
32
34
|
const isHover = state === "hover";
|
|
33
35
|
const isFocus = state === "focus";
|
|
34
36
|
const isDisabled = state === "disabled";
|
|
37
|
+
const isCard = variant === "card";
|
|
35
38
|
const bg = isHover ? styles.hoverUnselectedBg : styles.unselectedBg;
|
|
36
39
|
const border = isHover ? selected ? styles.hoverSelectedBorder : styles.hoverUnselectedBorder : selected ? styles.selectedBorder : styles.unselectedBorder;
|
|
37
40
|
const dot = isHover ? styles.hoverDotColor : styles.dotColor;
|
|
38
41
|
const ring = styles.focusRing;
|
|
39
42
|
const size = styles.size ?? 20;
|
|
43
|
+
const circle = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
44
|
+
"span",
|
|
45
|
+
{
|
|
46
|
+
"aria-hidden": "true",
|
|
47
|
+
style: {
|
|
48
|
+
width: size,
|
|
49
|
+
height: size,
|
|
50
|
+
flexShrink: 0,
|
|
51
|
+
borderRadius: "50%",
|
|
52
|
+
border: `2px solid ${border}`,
|
|
53
|
+
backgroundColor: bg,
|
|
54
|
+
display: "inline-flex",
|
|
55
|
+
alignItems: "center",
|
|
56
|
+
justifyContent: "center",
|
|
57
|
+
transition: "border-color 0.15s, background-color 0.15s",
|
|
58
|
+
...isFocus && !isCard ? { outline: `2px solid ${ring}`, outlineOffset: 2 } : {},
|
|
59
|
+
...isCard ? { position: "absolute", top: styles.cardPadding, right: styles.cardPadding } : {}
|
|
60
|
+
},
|
|
61
|
+
children: selected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
62
|
+
"span",
|
|
63
|
+
{
|
|
64
|
+
style: {
|
|
65
|
+
width: size * 0.5,
|
|
66
|
+
height: size * 0.5,
|
|
67
|
+
borderRadius: "50%",
|
|
68
|
+
backgroundColor: dot
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
if (isCard) {
|
|
75
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
76
|
+
"div",
|
|
77
|
+
{
|
|
78
|
+
style: {
|
|
79
|
+
position: "relative",
|
|
80
|
+
display: "flex",
|
|
81
|
+
flexDirection: "column",
|
|
82
|
+
gap: styles.cardGap,
|
|
83
|
+
minWidth: 150,
|
|
84
|
+
boxSizing: "border-box",
|
|
85
|
+
padding: styles.cardPadding,
|
|
86
|
+
borderRadius: styles.cardRadius,
|
|
87
|
+
border: `${styles.cardBorderWidth}px solid ${border}`,
|
|
88
|
+
backgroundColor: styles.cardBg,
|
|
89
|
+
fontSize: 14,
|
|
90
|
+
color: "var(--color-text)",
|
|
91
|
+
opacity: isDisabled ? styles.disabledOpacity ?? 0.4 : 1,
|
|
92
|
+
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
93
|
+
transition: "border-color 0.15s, background-color 0.15s",
|
|
94
|
+
...isFocus ? { outline: `2px solid ${ring}`, outlineOffset: 2 } : {}
|
|
95
|
+
},
|
|
96
|
+
children: [
|
|
97
|
+
indicator === "corner" && circle,
|
|
98
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: label }),
|
|
99
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--color-text-muted)", fontSize: 12 }, children: "What this option does" })
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
}
|
|
40
104
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
41
105
|
"div",
|
|
42
106
|
{
|
|
@@ -50,36 +114,7 @@ function ShowcaseRow({
|
|
|
50
114
|
cursor: isDisabled ? "not-allowed" : "pointer"
|
|
51
115
|
},
|
|
52
116
|
children: [
|
|
53
|
-
|
|
54
|
-
"span",
|
|
55
|
-
{
|
|
56
|
-
"aria-hidden": "true",
|
|
57
|
-
style: {
|
|
58
|
-
width: size,
|
|
59
|
-
height: size,
|
|
60
|
-
flexShrink: 0,
|
|
61
|
-
borderRadius: "50%",
|
|
62
|
-
border: `2px solid ${border}`,
|
|
63
|
-
backgroundColor: bg,
|
|
64
|
-
display: "inline-flex",
|
|
65
|
-
alignItems: "center",
|
|
66
|
-
justifyContent: "center",
|
|
67
|
-
transition: "border-color 0.15s, background-color 0.15s",
|
|
68
|
-
...isFocus ? { outline: `2px solid ${ring}`, outlineOffset: 2 } : {}
|
|
69
|
-
},
|
|
70
|
-
children: selected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
71
|
-
"span",
|
|
72
|
-
{
|
|
73
|
-
style: {
|
|
74
|
-
width: size * 0.5,
|
|
75
|
-
height: size * 0.5,
|
|
76
|
-
borderRadius: "50%",
|
|
77
|
-
backgroundColor: dot
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
),
|
|
117
|
+
circle,
|
|
83
118
|
label
|
|
84
119
|
]
|
|
85
120
|
}
|
|
@@ -89,6 +124,8 @@ const INTERACTIVE_OPTIONS = ["Small", "Medium", "Large"];
|
|
|
89
124
|
function RadioGroupPreview({ styles, variants }) {
|
|
90
125
|
const state = variants.state ?? "default";
|
|
91
126
|
const direction = variants.direction ?? "vertical";
|
|
127
|
+
const variant = variants.variant ?? "default";
|
|
128
|
+
const indicator = variants.indicator ?? "hidden";
|
|
92
129
|
const cssVars = {
|
|
93
130
|
"--uxm-radio-group-size": styles.size != null ? `${styles.size}px` : void 0,
|
|
94
131
|
"--uxm-radio-group-gap": styles.gap != null ? `${styles.gap}px` : void 0,
|
|
@@ -103,7 +140,12 @@ function RadioGroupPreview({ styles, variants }) {
|
|
|
103
140
|
"--uxm-radio-group-focus-ring": styles.focusRing,
|
|
104
141
|
"--uxm-radio-group-disabled-opacity": styles.disabledOpacity != null ? String(styles.disabledOpacity) : void 0,
|
|
105
142
|
"--uxm-radio-group-error-color": styles.errorColor,
|
|
106
|
-
"--uxm-radio-group-error-message-size": styles.errorMessageSize != null ? `${styles.errorMessageSize}px` : void 0
|
|
143
|
+
"--uxm-radio-group-error-message-size": styles.errorMessageSize != null ? `${styles.errorMessageSize}px` : void 0,
|
|
144
|
+
"--uxm-radio-card-padding": `${styles.cardPadding}px`,
|
|
145
|
+
"--uxm-radio-card-radius": `${styles.cardRadius}px`,
|
|
146
|
+
"--uxm-radio-card-gap": `${styles.cardGap}px`,
|
|
147
|
+
"--uxm-radio-card-border-width": `${styles.cardBorderWidth}px`,
|
|
148
|
+
"--uxm-radio-card-bg": styles.cardBg
|
|
107
149
|
};
|
|
108
150
|
const sectionLabel = {
|
|
109
151
|
fontSize: 11,
|
|
@@ -121,8 +163,8 @@ function RadioGroupPreview({ styles, variants }) {
|
|
|
121
163
|
" state"
|
|
122
164
|
] }),
|
|
123
165
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
|
|
124
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ShowcaseRow, { selected: false, state, styles, label: "Unselected" }),
|
|
125
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ShowcaseRow, { selected: true, state, styles, label: "Selected" })
|
|
166
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ShowcaseRow, { selected: false, state, styles, label: "Unselected", variant, indicator }),
|
|
167
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ShowcaseRow, { selected: true, state, styles, label: "Selected", variant, indicator })
|
|
126
168
|
] })
|
|
127
169
|
] }),
|
|
128
170
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { borderTop: "1px solid var(--color-border)", paddingTop: 16 }, children: [
|
|
@@ -132,6 +174,8 @@ function RadioGroupPreview({ styles, variants }) {
|
|
|
132
174
|
{
|
|
133
175
|
name: `uxm-radio-preview-${interactiveKey}`,
|
|
134
176
|
direction,
|
|
177
|
+
variant,
|
|
178
|
+
indicator,
|
|
135
179
|
error: state === "error" ? "Pick an option to continue" : void 0,
|
|
136
180
|
children: INTERACTIVE_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
137
181
|
import_ui.RadioOption,
|
|
@@ -139,7 +183,14 @@ function RadioGroupPreview({ styles, variants }) {
|
|
|
139
183
|
name: `uxm-radio-preview-${interactiveKey}`,
|
|
140
184
|
value: opt,
|
|
141
185
|
disabled: interactiveDisabled,
|
|
142
|
-
children:
|
|
186
|
+
children: variant === "card" ? (
|
|
187
|
+
// Card mode is for rich content — a one-word label in a tile
|
|
188
|
+
// would demo a box, not the shape the variant exists for.
|
|
189
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
190
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: opt }),
|
|
191
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "var(--color-text-muted)", fontSize: 12 }, children: "What this option does" })
|
|
192
|
+
] })
|
|
193
|
+
) : opt
|
|
143
194
|
},
|
|
144
195
|
opt
|
|
145
196
|
))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/radio-group/radio-group-preview.tsx"],"sourcesContent":["import { type CSSProperties } from 'react';\n\nimport type { PreviewProps } from '@/previews/types';\nimport { RadioGroup, RadioOption } from '@/ui';\n\ntype Styles = PreviewProps['styles'];\n\nfunction ShowcaseRow({\n selected,\n state,\n styles,\n label,\n}: {\n selected: boolean;\n state: string;\n styles: Styles;\n label: string;\n}) {\n // Static showcase — paints the selected forced state regardless of\n // pointer interaction. Inline JSX (not the real <RadioOption>) so each\n // forced state can override the circle + dot directly; the interactive\n // instance below is where production CSS rules exercise.\n const isHover = state === 'hover';\n const isFocus = state === 'focus';\n const isDisabled = state === 'disabled';\n\n const bg = isHover\n ? styles.hoverUnselectedBg\n : styles.unselectedBg;\n const border = isHover\n ? (selected ? styles.hoverSelectedBorder : styles.hoverUnselectedBorder)\n : (selected ? styles.selectedBorder : styles.unselectedBorder);\n const dot = isHover ? styles.hoverDotColor : styles.dotColor;\n const ring = styles.focusRing;\n const size = (styles.size as number) ?? 20;\n\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n fontSize: 14,\n color: 'var(--color-text)',\n opacity: isDisabled ? ((styles.disabledOpacity as number) ?? 0.4) : 1,\n cursor: isDisabled ? 'not-allowed' : 'pointer',\n }}\n >\n <span\n aria-hidden=\"true\"\n style={{\n width: size,\n height: size,\n flexShrink: 0,\n borderRadius: '50%',\n border: `2px solid ${border as string}`,\n backgroundColor: bg as string,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'border-color 0.15s, background-color 0.15s',\n ...(isFocus\n ? { outline: `2px solid ${ring as string}`, outlineOffset: 2 }\n : {}),\n }}\n >\n {selected && (\n <span\n style={{\n width: size * 0.5,\n height: size * 0.5,\n borderRadius: '50%',\n backgroundColor: dot as string,\n }}\n />\n )}\n </span>\n {label}\n </div>\n );\n}\n\nconst INTERACTIVE_OPTIONS = ['Small', 'Medium', 'Large'];\n\nexport function RadioGroupPreview({ styles, variants }: PreviewProps) {\n const state = (variants.state as string) ?? 'default';\n const direction = (variants.direction as 'vertical' | 'horizontal' | undefined) ?? 'vertical';\n\n // Project every registry knob as a `--uxm-radio-group-*` custom property\n // on the wrapper. The interactive <RadioGroup> below renders the real\n // component whose styles.css rules read these vars — live editor edits\n // paint immediately, and production `:hover` / `:focus-visible` rules\n // exercise exactly as they would in prod.\n const cssVars: Record<string, string | undefined> = {\n '--uxm-radio-group-size': styles.size != null ? `${styles.size}px` : undefined,\n '--uxm-radio-group-gap': styles.gap != null ? `${styles.gap}px` : undefined,\n '--uxm-radio-group-unselected-bg': styles.unselectedBg as string | undefined,\n '--uxm-radio-group-unselected-border': styles.unselectedBorder as string | undefined,\n '--uxm-radio-group-selected-border': styles.selectedBorder as string | undefined,\n '--uxm-radio-group-dot-color': styles.dotColor as string | undefined,\n '--uxm-radio-group-hover-unselected-bg': styles.hoverUnselectedBg as string | undefined,\n '--uxm-radio-group-hover-unselected-border': styles.hoverUnselectedBorder as string | undefined,\n '--uxm-radio-group-hover-selected-border': styles.hoverSelectedBorder as string | undefined,\n '--uxm-radio-group-hover-dot-color': styles.hoverDotColor as string | undefined,\n '--uxm-radio-group-focus-ring': styles.focusRing as string | undefined,\n '--uxm-radio-group-disabled-opacity':\n styles.disabledOpacity != null ? String(styles.disabledOpacity) : undefined,\n '--uxm-radio-group-error-color': styles.errorColor as string | undefined,\n '--uxm-radio-group-error-message-size':\n styles.errorMessageSize != null ? `${styles.errorMessageSize}px` : undefined,\n };\n\n const sectionLabel = {\n fontSize: 11,\n color: 'var(--color-text-muted)',\n marginBottom: 12,\n letterSpacing: 0.5,\n textTransform: 'uppercase' as const,\n };\n\n // Pair the state and direction into the interactive `key` so that\n // toggling either variant resets the radio group cleanly (matches the\n // freshly-{re,dis}abled UX and clears any stale selection when the user\n // flips layout).\n const interactiveKey = `${state}-${direction}`;\n const interactiveDisabled = state === 'disabled';\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 32, ...cssVars } as CSSProperties}>\n <div>\n <div style={sectionLabel}>{state} state</div>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>\n <ShowcaseRow selected={false} state={state} styles={styles} label=\"Unselected\" />\n <ShowcaseRow selected={true} state={state} styles={styles} label=\"Selected\" />\n </div>\n </div>\n\n {/* Interactive instance — uncontrolled so the browser owns the\n checked state. React (and the canvas's event-capture re-renders)\n can't fight the DOM here, so click/keyboard navigation toggle\n reliably between options. Three options share a unique `name`\n so the browser's radio-group semantics work natively. */}\n <div style={{ borderTop: '1px solid var(--color-border)', paddingTop: 16 }}>\n <div style={sectionLabel}>Interactive</div>\n <RadioGroup\n key={interactiveKey}\n name={`uxm-radio-preview-${interactiveKey}`}\n direction={direction}\n error={state === 'error' ? 'Pick an option to continue' : undefined}\n >\n {INTERACTIVE_OPTIONS.map((opt) => (\n <RadioOption\n key={opt}\n name={`uxm-radio-preview-${interactiveKey}`}\n value={opt}\n disabled={interactiveDisabled}\n >\n {opt}\n </RadioOption>\n ))}\n </RadioGroup>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/radio-group/radio-group-preview.tsx"],"sourcesContent":["import { type CSSProperties } from 'react';\n\nimport type { PreviewProps } from '@/previews/types';\nimport { RadioGroup, RadioOption } from '@/ui';\n\ntype Styles = PreviewProps['styles'];\n\nfunction ShowcaseRow({\n selected,\n state,\n styles,\n label,\n variant,\n indicator,\n}: {\n selected: boolean;\n state: string;\n styles: Styles;\n label: string;\n variant: 'default' | 'card';\n indicator: 'hidden' | 'corner';\n}) {\n // Static showcase — paints the selected forced state regardless of\n // pointer interaction. Inline JSX (not the real <RadioOption>) so each\n // forced state can override the circle + dot directly; the interactive\n // instance below is where production CSS rules exercise.\n //\n // It has to follow `variant`: this is the ONLY thing that paints the forced\n // hover / focus / disabled states — the interactive group below shows the\n // resting state and real input. Left as a row while the variant is `card`,\n // the States picker would show a hovered CIRCLE for a control that is a\n // tile, and the hover / focus knobs (which the card frame genuinely reads)\n // would be tuned against feedback that is not what ships.\n const isHover = state === 'hover';\n const isFocus = state === 'focus';\n const isDisabled = state === 'disabled';\n const isCard = variant === 'card';\n\n const bg = isHover\n ? styles.hoverUnselectedBg\n : styles.unselectedBg;\n const border = isHover\n ? (selected ? styles.hoverSelectedBorder : styles.hoverUnselectedBorder)\n : (selected ? styles.selectedBorder : styles.unselectedBorder);\n const dot = isHover ? styles.hoverDotColor : styles.dotColor;\n const ring = styles.focusRing;\n const size = (styles.size as number) ?? 20;\n\n const circle = (\n <span\n aria-hidden=\"true\"\n style={{\n width: size,\n height: size,\n flexShrink: 0,\n borderRadius: '50%',\n border: `2px solid ${border as string}`,\n backgroundColor: bg as string,\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'border-color 0.15s, background-color 0.15s',\n ...(isFocus && !isCard\n ? { outline: `2px solid ${ring as string}`, outlineOffset: 2 }\n : {}),\n ...(isCard\n ? { position: 'absolute' as const, top: styles.cardPadding as number, right: styles.cardPadding as number }\n : {}),\n }}\n >\n {selected && (\n <span\n style={{\n width: size * 0.5,\n height: size * 0.5,\n borderRadius: '50%',\n backgroundColor: dot as string,\n }}\n />\n )}\n </span>\n );\n\n if (isCard) {\n // Mirrors `.uxm-radio--card`: the tile carries the frame and the focus\n // ring, and the circle is either gone or pinned to the corner.\n return (\n <div\n style={{\n position: 'relative',\n display: 'flex',\n flexDirection: 'column',\n gap: styles.cardGap as number,\n minWidth: 150,\n boxSizing: 'border-box',\n padding: styles.cardPadding as number,\n borderRadius: styles.cardRadius as number,\n border: `${styles.cardBorderWidth}px solid ${border as string}`,\n backgroundColor: styles.cardBg as string,\n fontSize: 14,\n color: 'var(--color-text)',\n opacity: isDisabled ? ((styles.disabledOpacity as number) ?? 0.4) : 1,\n cursor: isDisabled ? 'not-allowed' : 'pointer',\n transition: 'border-color 0.15s, background-color 0.15s',\n ...(isFocus ? { outline: `2px solid ${ring as string}`, outlineOffset: 2 } : {}),\n }}\n >\n {indicator === 'corner' && circle}\n <strong>{label}</strong>\n <span style={{ color: 'var(--color-text-muted)', fontSize: 12 }}>\n What this option does\n </span>\n </div>\n );\n }\n\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n fontSize: 14,\n color: 'var(--color-text)',\n opacity: isDisabled ? ((styles.disabledOpacity as number) ?? 0.4) : 1,\n cursor: isDisabled ? 'not-allowed' : 'pointer',\n }}\n >\n {circle}\n {label}\n </div>\n );\n}\n\nconst INTERACTIVE_OPTIONS = ['Small', 'Medium', 'Large'];\n\nexport function RadioGroupPreview({ styles, variants }: PreviewProps) {\n const state = (variants.state as string) ?? 'default';\n const direction = (variants.direction as 'vertical' | 'horizontal' | undefined) ?? 'vertical';\n const variant = (variants.variant as 'default' | 'card' | undefined) ?? 'default';\n const indicator = (variants.indicator as 'hidden' | 'corner' | undefined) ?? 'hidden';\n\n // Project every registry knob as a `--uxm-radio-group-*` custom property\n // on the wrapper. The interactive <RadioGroup> below renders the real\n // component whose styles.css rules read these vars — live editor edits\n // paint immediately, and production `:hover` / `:focus-visible` rules\n // exercise exactly as they would in prod.\n const cssVars: Record<string, string | undefined> = {\n '--uxm-radio-group-size': styles.size != null ? `${styles.size}px` : undefined,\n '--uxm-radio-group-gap': styles.gap != null ? `${styles.gap}px` : undefined,\n '--uxm-radio-group-unselected-bg': styles.unselectedBg as string | undefined,\n '--uxm-radio-group-unselected-border': styles.unselectedBorder as string | undefined,\n '--uxm-radio-group-selected-border': styles.selectedBorder as string | undefined,\n '--uxm-radio-group-dot-color': styles.dotColor as string | undefined,\n '--uxm-radio-group-hover-unselected-bg': styles.hoverUnselectedBg as string | undefined,\n '--uxm-radio-group-hover-unselected-border': styles.hoverUnselectedBorder as string | undefined,\n '--uxm-radio-group-hover-selected-border': styles.hoverSelectedBorder as string | undefined,\n '--uxm-radio-group-hover-dot-color': styles.hoverDotColor as string | undefined,\n '--uxm-radio-group-focus-ring': styles.focusRing as string | undefined,\n '--uxm-radio-group-disabled-opacity':\n styles.disabledOpacity != null ? String(styles.disabledOpacity) : undefined,\n '--uxm-radio-group-error-color': styles.errorColor as string | undefined,\n '--uxm-radio-group-error-message-size':\n styles.errorMessageSize != null ? `${styles.errorMessageSize}px` : undefined,\n '--uxm-radio-card-padding': `${styles.cardPadding}px`,\n '--uxm-radio-card-radius': `${styles.cardRadius}px`,\n '--uxm-radio-card-gap': `${styles.cardGap}px`,\n '--uxm-radio-card-border-width': `${styles.cardBorderWidth}px`,\n '--uxm-radio-card-bg': styles.cardBg as string,\n };\n\n const sectionLabel = {\n fontSize: 11,\n color: 'var(--color-text-muted)',\n marginBottom: 12,\n letterSpacing: 0.5,\n textTransform: 'uppercase' as const,\n };\n\n // Pair the state and direction into the interactive `key` so that\n // toggling either variant resets the radio group cleanly (matches the\n // freshly-{re,dis}abled UX and clears any stale selection when the user\n // flips layout).\n const interactiveKey = `${state}-${direction}`;\n const interactiveDisabled = state === 'disabled';\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 32, ...cssVars } as CSSProperties}>\n <div>\n <div style={sectionLabel}>{state} state</div>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>\n <ShowcaseRow selected={false} state={state} styles={styles} label=\"Unselected\" variant={variant} indicator={indicator} />\n <ShowcaseRow selected={true} state={state} styles={styles} label=\"Selected\" variant={variant} indicator={indicator} />\n </div>\n </div>\n\n {/* Interactive instance — uncontrolled so the browser owns the\n checked state. React (and the canvas's event-capture re-renders)\n can't fight the DOM here, so click/keyboard navigation toggle\n reliably between options. Three options share a unique `name`\n so the browser's radio-group semantics work natively. */}\n <div style={{ borderTop: '1px solid var(--color-border)', paddingTop: 16 }}>\n <div style={sectionLabel}>Interactive</div>\n <RadioGroup\n key={interactiveKey}\n name={`uxm-radio-preview-${interactiveKey}`}\n direction={direction}\n variant={variant}\n indicator={indicator}\n error={state === 'error' ? 'Pick an option to continue' : undefined}\n >\n {INTERACTIVE_OPTIONS.map((opt) => (\n <RadioOption\n key={opt}\n name={`uxm-radio-preview-${interactiveKey}`}\n value={opt}\n disabled={interactiveDisabled}\n >\n {variant === 'card' ? (\n // Card mode is for rich content — a one-word label in a tile\n // would demo a box, not the shape the variant exists for.\n <>\n <strong>{opt}</strong>\n <span style={{ color: 'var(--color-text-muted)', fontSize: 12 }}>\n What this option does\n </span>\n </>\n ) : (\n opt\n )}\n </RadioOption>\n ))}\n </RadioGroup>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radio-group-preview.d.ts","sourceRoot":"","sources":["../../../src/ui/radio-group/radio-group-preview.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"radio-group-preview.d.ts","sourceRoot":"","sources":["../../../src/ui/radio-group/radio-group-preview.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAsIrD,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,YAAY,+BAoGnE"}
|
|
@@ -1,19 +1,83 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { RadioGroup, RadioOption } from "../index.js";
|
|
3
3
|
function ShowcaseRow({
|
|
4
4
|
selected,
|
|
5
5
|
state,
|
|
6
6
|
styles,
|
|
7
|
-
label
|
|
7
|
+
label,
|
|
8
|
+
variant,
|
|
9
|
+
indicator
|
|
8
10
|
}) {
|
|
9
11
|
const isHover = state === "hover";
|
|
10
12
|
const isFocus = state === "focus";
|
|
11
13
|
const isDisabled = state === "disabled";
|
|
14
|
+
const isCard = variant === "card";
|
|
12
15
|
const bg = isHover ? styles.hoverUnselectedBg : styles.unselectedBg;
|
|
13
16
|
const border = isHover ? selected ? styles.hoverSelectedBorder : styles.hoverUnselectedBorder : selected ? styles.selectedBorder : styles.unselectedBorder;
|
|
14
17
|
const dot = isHover ? styles.hoverDotColor : styles.dotColor;
|
|
15
18
|
const ring = styles.focusRing;
|
|
16
19
|
const size = styles.size ?? 20;
|
|
20
|
+
const circle = /* @__PURE__ */ jsx(
|
|
21
|
+
"span",
|
|
22
|
+
{
|
|
23
|
+
"aria-hidden": "true",
|
|
24
|
+
style: {
|
|
25
|
+
width: size,
|
|
26
|
+
height: size,
|
|
27
|
+
flexShrink: 0,
|
|
28
|
+
borderRadius: "50%",
|
|
29
|
+
border: `2px solid ${border}`,
|
|
30
|
+
backgroundColor: bg,
|
|
31
|
+
display: "inline-flex",
|
|
32
|
+
alignItems: "center",
|
|
33
|
+
justifyContent: "center",
|
|
34
|
+
transition: "border-color 0.15s, background-color 0.15s",
|
|
35
|
+
...isFocus && !isCard ? { outline: `2px solid ${ring}`, outlineOffset: 2 } : {},
|
|
36
|
+
...isCard ? { position: "absolute", top: styles.cardPadding, right: styles.cardPadding } : {}
|
|
37
|
+
},
|
|
38
|
+
children: selected && /* @__PURE__ */ jsx(
|
|
39
|
+
"span",
|
|
40
|
+
{
|
|
41
|
+
style: {
|
|
42
|
+
width: size * 0.5,
|
|
43
|
+
height: size * 0.5,
|
|
44
|
+
borderRadius: "50%",
|
|
45
|
+
backgroundColor: dot
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
if (isCard) {
|
|
52
|
+
return /* @__PURE__ */ jsxs(
|
|
53
|
+
"div",
|
|
54
|
+
{
|
|
55
|
+
style: {
|
|
56
|
+
position: "relative",
|
|
57
|
+
display: "flex",
|
|
58
|
+
flexDirection: "column",
|
|
59
|
+
gap: styles.cardGap,
|
|
60
|
+
minWidth: 150,
|
|
61
|
+
boxSizing: "border-box",
|
|
62
|
+
padding: styles.cardPadding,
|
|
63
|
+
borderRadius: styles.cardRadius,
|
|
64
|
+
border: `${styles.cardBorderWidth}px solid ${border}`,
|
|
65
|
+
backgroundColor: styles.cardBg,
|
|
66
|
+
fontSize: 14,
|
|
67
|
+
color: "var(--color-text)",
|
|
68
|
+
opacity: isDisabled ? styles.disabledOpacity ?? 0.4 : 1,
|
|
69
|
+
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
70
|
+
transition: "border-color 0.15s, background-color 0.15s",
|
|
71
|
+
...isFocus ? { outline: `2px solid ${ring}`, outlineOffset: 2 } : {}
|
|
72
|
+
},
|
|
73
|
+
children: [
|
|
74
|
+
indicator === "corner" && circle,
|
|
75
|
+
/* @__PURE__ */ jsx("strong", { children: label }),
|
|
76
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--color-text-muted)", fontSize: 12 }, children: "What this option does" })
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
17
81
|
return /* @__PURE__ */ jsxs(
|
|
18
82
|
"div",
|
|
19
83
|
{
|
|
@@ -27,36 +91,7 @@ function ShowcaseRow({
|
|
|
27
91
|
cursor: isDisabled ? "not-allowed" : "pointer"
|
|
28
92
|
},
|
|
29
93
|
children: [
|
|
30
|
-
|
|
31
|
-
"span",
|
|
32
|
-
{
|
|
33
|
-
"aria-hidden": "true",
|
|
34
|
-
style: {
|
|
35
|
-
width: size,
|
|
36
|
-
height: size,
|
|
37
|
-
flexShrink: 0,
|
|
38
|
-
borderRadius: "50%",
|
|
39
|
-
border: `2px solid ${border}`,
|
|
40
|
-
backgroundColor: bg,
|
|
41
|
-
display: "inline-flex",
|
|
42
|
-
alignItems: "center",
|
|
43
|
-
justifyContent: "center",
|
|
44
|
-
transition: "border-color 0.15s, background-color 0.15s",
|
|
45
|
-
...isFocus ? { outline: `2px solid ${ring}`, outlineOffset: 2 } : {}
|
|
46
|
-
},
|
|
47
|
-
children: selected && /* @__PURE__ */ jsx(
|
|
48
|
-
"span",
|
|
49
|
-
{
|
|
50
|
-
style: {
|
|
51
|
-
width: size * 0.5,
|
|
52
|
-
height: size * 0.5,
|
|
53
|
-
borderRadius: "50%",
|
|
54
|
-
backgroundColor: dot
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
),
|
|
94
|
+
circle,
|
|
60
95
|
label
|
|
61
96
|
]
|
|
62
97
|
}
|
|
@@ -66,6 +101,8 @@ const INTERACTIVE_OPTIONS = ["Small", "Medium", "Large"];
|
|
|
66
101
|
function RadioGroupPreview({ styles, variants }) {
|
|
67
102
|
const state = variants.state ?? "default";
|
|
68
103
|
const direction = variants.direction ?? "vertical";
|
|
104
|
+
const variant = variants.variant ?? "default";
|
|
105
|
+
const indicator = variants.indicator ?? "hidden";
|
|
69
106
|
const cssVars = {
|
|
70
107
|
"--uxm-radio-group-size": styles.size != null ? `${styles.size}px` : void 0,
|
|
71
108
|
"--uxm-radio-group-gap": styles.gap != null ? `${styles.gap}px` : void 0,
|
|
@@ -80,7 +117,12 @@ function RadioGroupPreview({ styles, variants }) {
|
|
|
80
117
|
"--uxm-radio-group-focus-ring": styles.focusRing,
|
|
81
118
|
"--uxm-radio-group-disabled-opacity": styles.disabledOpacity != null ? String(styles.disabledOpacity) : void 0,
|
|
82
119
|
"--uxm-radio-group-error-color": styles.errorColor,
|
|
83
|
-
"--uxm-radio-group-error-message-size": styles.errorMessageSize != null ? `${styles.errorMessageSize}px` : void 0
|
|
120
|
+
"--uxm-radio-group-error-message-size": styles.errorMessageSize != null ? `${styles.errorMessageSize}px` : void 0,
|
|
121
|
+
"--uxm-radio-card-padding": `${styles.cardPadding}px`,
|
|
122
|
+
"--uxm-radio-card-radius": `${styles.cardRadius}px`,
|
|
123
|
+
"--uxm-radio-card-gap": `${styles.cardGap}px`,
|
|
124
|
+
"--uxm-radio-card-border-width": `${styles.cardBorderWidth}px`,
|
|
125
|
+
"--uxm-radio-card-bg": styles.cardBg
|
|
84
126
|
};
|
|
85
127
|
const sectionLabel = {
|
|
86
128
|
fontSize: 11,
|
|
@@ -98,8 +140,8 @@ function RadioGroupPreview({ styles, variants }) {
|
|
|
98
140
|
" state"
|
|
99
141
|
] }),
|
|
100
142
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
|
|
101
|
-
/* @__PURE__ */ jsx(ShowcaseRow, { selected: false, state, styles, label: "Unselected" }),
|
|
102
|
-
/* @__PURE__ */ jsx(ShowcaseRow, { selected: true, state, styles, label: "Selected" })
|
|
143
|
+
/* @__PURE__ */ jsx(ShowcaseRow, { selected: false, state, styles, label: "Unselected", variant, indicator }),
|
|
144
|
+
/* @__PURE__ */ jsx(ShowcaseRow, { selected: true, state, styles, label: "Selected", variant, indicator })
|
|
103
145
|
] })
|
|
104
146
|
] }),
|
|
105
147
|
/* @__PURE__ */ jsxs("div", { style: { borderTop: "1px solid var(--color-border)", paddingTop: 16 }, children: [
|
|
@@ -109,6 +151,8 @@ function RadioGroupPreview({ styles, variants }) {
|
|
|
109
151
|
{
|
|
110
152
|
name: `uxm-radio-preview-${interactiveKey}`,
|
|
111
153
|
direction,
|
|
154
|
+
variant,
|
|
155
|
+
indicator,
|
|
112
156
|
error: state === "error" ? "Pick an option to continue" : void 0,
|
|
113
157
|
children: INTERACTIVE_OPTIONS.map((opt) => /* @__PURE__ */ jsx(
|
|
114
158
|
RadioOption,
|
|
@@ -116,7 +160,14 @@ function RadioGroupPreview({ styles, variants }) {
|
|
|
116
160
|
name: `uxm-radio-preview-${interactiveKey}`,
|
|
117
161
|
value: opt,
|
|
118
162
|
disabled: interactiveDisabled,
|
|
119
|
-
children:
|
|
163
|
+
children: variant === "card" ? (
|
|
164
|
+
// Card mode is for rich content — a one-word label in a tile
|
|
165
|
+
// would demo a box, not the shape the variant exists for.
|
|
166
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
167
|
+
/* @__PURE__ */ jsx("strong", { children: opt }),
|
|
168
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--color-text-muted)", fontSize: 12 }, children: "What this option does" })
|
|
169
|
+
] })
|
|
170
|
+
) : opt
|
|
120
171
|
},
|
|
121
172
|
opt
|
|
122
173
|
))
|