@tanishqkancharla/maui 0.0.53 → 0.0.55

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.
Files changed (82) hide show
  1. package/dist/components/Avatar.d.ts +8 -0
  2. package/dist/components/Avatar.js +10 -5
  3. package/dist/components/Badge.d.ts +4 -0
  4. package/dist/components/Badge.js +6 -4
  5. package/dist/components/Button.d.ts +11 -6
  6. package/dist/components/Button.js +13 -8
  7. package/dist/components/Checkbox.d.ts +7 -0
  8. package/dist/components/Checkbox.js +29 -34
  9. package/dist/components/Code.d.ts +10 -0
  10. package/dist/components/Code.js +9 -2
  11. package/dist/components/CodeBlock.d.ts +5 -0
  12. package/dist/components/CodeBlock.js +7 -2
  13. package/dist/components/CollectionPopover.d.ts +4 -0
  14. package/dist/components/CollectionPopover.js +4 -2
  15. package/dist/components/Dialog.d.ts +11 -0
  16. package/dist/components/Dialog.js +24 -13
  17. package/dist/components/Drawer.d.ts +9 -0
  18. package/dist/components/Drawer.js +75 -66
  19. package/dist/components/Input.d.ts +25 -0
  20. package/dist/components/Input.js +37 -11
  21. package/dist/components/ListBox.d.ts +5 -2
  22. package/dist/components/ListBox.js +6 -4
  23. package/dist/components/LoadingScreen.js +2 -5
  24. package/dist/components/Menu.d.ts +5 -0
  25. package/dist/components/Menu.js +7 -5
  26. package/dist/components/Radio.d.ts +10 -2
  27. package/dist/components/Radio.js +39 -43
  28. package/dist/components/Select.d.ts +10 -0
  29. package/dist/components/Select.js +23 -13
  30. package/dist/components/Slider.d.ts +11 -2
  31. package/dist/components/Slider.js +47 -60
  32. package/dist/components/Switch.d.ts +7 -0
  33. package/dist/components/Switch.js +27 -32
  34. package/dist/components/TabBar.d.ts +13 -0
  35. package/dist/components/TabBar.js +24 -10
  36. package/dist/components/Table.d.ts +20 -0
  37. package/dist/components/Table.js +60 -44
  38. package/dist/components/Tooltip.d.ts +4 -0
  39. package/dist/components/Tooltip.js +7 -5
  40. package/dist/maui.d.ts +19 -19
  41. package/dist/maui.js +19 -19
  42. package/package.json +2 -2
  43. package/skills/maui/SKILL.md +2 -0
  44. package/skills/maui/references/components/avatar.md +6 -0
  45. package/skills/maui/references/components/badge.md +5 -0
  46. package/skills/maui/references/components/buttons.md +14 -0
  47. package/skills/maui/references/components/code.md +12 -0
  48. package/skills/maui/references/components/drawer.md +10 -0
  49. package/skills/maui/references/components/form-controls.md +50 -0
  50. package/skills/maui/references/components/list-box.md +6 -0
  51. package/skills/maui/references/components/loading-screen.md +2 -2
  52. package/skills/maui/references/components/menu.md +6 -0
  53. package/skills/maui/references/components/select.md +14 -0
  54. package/skills/maui/references/components/tab-bar.md +12 -0
  55. package/skills/maui/references/components/table.md +17 -0
  56. package/skills/maui/references/components/tooltip.md +5 -0
  57. package/skills/maui/references/design_conventions.md +18 -0
  58. package/src/components/Avatar.tsx +22 -14
  59. package/src/components/Badge.tsx +13 -10
  60. package/src/components/Button.tsx +24 -9
  61. package/src/components/Checkbox.tsx +44 -52
  62. package/src/components/Code.tsx +13 -4
  63. package/src/components/CodeBlock.tsx +8 -2
  64. package/src/components/CollectionPopover.tsx +5 -2
  65. package/src/components/Dialog.tsx +40 -30
  66. package/src/components/Drawer.tsx +82 -72
  67. package/src/components/Input.tsx +54 -18
  68. package/src/components/ListBox.tsx +7 -4
  69. package/src/components/LoadingScreen.tsx +2 -6
  70. package/src/components/Menu.tsx +8 -5
  71. package/src/components/Radio.tsx +62 -69
  72. package/src/components/Select.tsx +24 -13
  73. package/src/components/Slider.tsx +87 -103
  74. package/src/components/Switch.tsx +36 -49
  75. package/src/components/TabBar.tsx +27 -13
  76. package/src/components/Table.tsx +74 -56
  77. package/src/components/Tooltip.tsx +16 -13
  78. package/src/maui.ts +22 -9
  79. package/src/pages/BordersTokenPage.tsx +2 -2
  80. package/src/pages/LoadingScreenPage.tsx +2 -2
  81. package/src/tokens/borders.ts +2 -2
  82. package/src/tokens/focusRing.ts +3 -3
@@ -4,5 +4,13 @@ type AvatarProps = {
4
4
  size?: TextSize;
5
5
  className?: string;
6
6
  };
7
+ /** `root` on the outer `<span>` (circle; colors seeded from `name`, dimensions from `size`, no state); `initials` on the inner `<span>` holding the letters. */
8
+ export declare const avatarStyles: {
9
+ readonly root: (args_0: {
10
+ name: string;
11
+ size?: TextSize;
12
+ }) => import("purse-styles").StyleElement;
13
+ readonly initials: import("purse-styles").StyleElement;
14
+ };
7
15
  export declare function Avatar({ name, size, className }: AvatarProps): import("react").JSX.Element;
8
16
  export {};
@@ -5,11 +5,6 @@ import { colors } from "../tokens/colors";
5
5
  import { radius } from "../tokens/radius";
6
6
  import { text } from "../tokens/text";
7
7
  import { memoize } from "../utils/memoize";
8
- export function Avatar({ name, size = "sm", className }) {
9
- const avatarClassName = useStyles(avatarClass(name, size));
10
- const initialsClassName = useStyles(initialsClass);
11
- return (_jsx("span", { className: joinClassNames(avatarClassName, className), "aria-hidden": "true", children: _jsx("span", { className: initialsClassName, children: initials(name) }) }));
12
- }
13
8
  const avatarPalette = [
14
9
  { background: colors.accent[4], color: colors.accent[11] },
15
10
  {
@@ -90,6 +85,16 @@ const initialsClass = style({
90
85
  display: "block",
91
86
  textBox: "trim-both cap alphabetic",
92
87
  });
88
+ /** `root` on the outer `<span>` (circle; colors seeded from `name`, dimensions from `size`, no state); `initials` on the inner `<span>` holding the letters. */
89
+ export const avatarStyles = {
90
+ root: memoize(({ name, size = "sm" }) => avatarClass(name, size)),
91
+ initials: initialsClass,
92
+ };
93
+ export function Avatar({ name, size = "sm", className }) {
94
+ const avatarClassName = useStyles(avatarStyles.root({ name, size }));
95
+ const initialsClassName = useStyles(avatarStyles.initials);
96
+ return (_jsx("span", { className: joinClassNames(avatarClassName, className), "aria-hidden": "true", children: _jsx("span", { className: initialsClassName, children: initials(name) }) }));
97
+ }
93
98
  function joinClassNames(...classNames) {
94
99
  return classNames.filter(Boolean).join(" ");
95
100
  }
@@ -1,4 +1,8 @@
1
1
  import type React from "react";
2
2
  type BadgeProps = React.HTMLAttributes<HTMLSpanElement>;
3
+ /** `root` is the pill; put it on any inline element (no state). */
4
+ export declare const badgeStyles: {
5
+ readonly root: import("purse-styles").StyleElement;
6
+ };
3
7
  export declare function Badge({ className, children, ...props }: BadgeProps): React.JSX.Element;
4
8
  export {};
@@ -2,10 +2,6 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { style, useStyles } from "purse-styles";
3
3
  import { colors } from "../tokens/colors";
4
4
  import { radius } from "../tokens/radius";
5
- export function Badge({ className, children, ...props }) {
6
- const badgeClassName = useStyles(badgeClass);
7
- return (_jsx("span", { ...props, className: joinClassNames(badgeClassName, className), children: children }));
8
- }
9
5
  const badgeClass = style(radius.pill, {
10
6
  display: "inline-flex",
11
7
  alignItems: "center",
@@ -22,6 +18,12 @@ const badgeClass = style(radius.pill, {
22
18
  lineHeight: "16px",
23
19
  whiteSpace: "nowrap",
24
20
  });
21
+ /** `root` is the pill; put it on any inline element (no state). */
22
+ export const badgeStyles = { root: badgeClass };
23
+ export function Badge({ className, children, ...props }) {
24
+ const badgeClassName = useStyles(badgeStyles.root);
25
+ return (_jsx("span", { ...props, className: joinClassNames(badgeClassName, className), children: children }));
26
+ }
25
27
  function joinClassNames(...classNames) {
26
28
  return classNames.filter(Boolean).join(" ");
27
29
  }
@@ -3,12 +3,12 @@ import { type ButtonProps as RACButtonProps } from "react-aria-components";
3
3
  import { type ColorName } from "../tokens/colors";
4
4
  export type ButtonVariant = "default" | "quiet" | "primary";
5
5
  export type ButtonSize = "default" | "sm";
6
- /** Internal style primitives for controls that compose Button visuals. */
7
- export declare const buttonStyles: {
8
- readonly base: import("purse-styles").StyleElement;
9
- readonly quiet: import("purse-styles").StyleElement;
10
- readonly text: import("purse-styles").StyleElement;
11
- };
6
+ /**
7
+ * @internal Shared shell under every Button variant (no fill, no hover).
8
+ * Only for Maui controls that layer their own fill on top (TabBar's selected
9
+ * tab); use `buttonStyles.root` everywhere else.
10
+ */
11
+ export declare const buttonBaseStyle: import("purse-styles").StyleElement;
12
12
  /** Opaque hex or `rgb()`. Palette names stay ColorName (`"blue"` is Radix, not CSS `blue`). */
13
13
  export type ButtonCssColor = `#${string}` | `rgb(${string}`;
14
14
  export type ButtonVariantColor = ColorName | ButtonCssColor;
@@ -29,6 +29,11 @@ export declare function useButton(props: Pick<ButtonProps, "onClick" | "onFocus"
29
29
  ButtonData,
30
30
  Pick<ButtonAttributes, "ref"> & Pick<RACButtonProps, "onClick" | "onFocus">
31
31
  ];
32
+ /** `root` goes on the RAC `Button` (native `:hover` / `:focus-visible` / `:disabled`; icons are direct `> svg` children); `label` goes on a `<span>` wrapping each text run. */
33
+ export declare const buttonStyles: {
34
+ readonly root: (args_0?: Pick<ButtonProps, "size" | "variant" | "variantColor"> | undefined) => import("purse-styles").StyleElement;
35
+ readonly label: import("purse-styles").StyleElement;
36
+ };
32
37
  export declare const Button: React.ForwardRefExoticComponent<Omit<RACButtonProps, "children" | "className"> & {
33
38
  children: React.ReactNode;
34
39
  className?: string;
@@ -107,12 +107,12 @@ const quietClass = memoize((color, hoverColor, wash) => style(buttonBaseClass, f
107
107
  "&:disabled": disabledQuiet,
108
108
  }));
109
109
  const quietButtonClass = quietClass(colors.gray[11], colors.gray[12], colors.grayAlpha[9]);
110
- /** Internal style primitives for controls that compose Button visuals. */
111
- export const buttonStyles = {
112
- base: buttonBaseClass,
113
- quiet: quietButtonClass,
114
- text: buttonTextClass,
115
- };
110
+ /**
111
+ * @internal Shared shell under every Button variant (no fill, no hover).
112
+ * Only for Maui controls that layer their own fill on top (TabBar's selected
113
+ * tab); use `buttonStyles.root` everywhere else.
114
+ */
115
+ export const buttonBaseStyle = buttonBaseClass;
116
116
  const darkTextOnSolid = new Set([
117
117
  "amber",
118
118
  "lime",
@@ -197,11 +197,16 @@ export function useButton(props, forwardedRef) {
197
197
  { ref, onClick, onFocus },
198
198
  ];
199
199
  }
200
+ /** `root` goes on the RAC `Button` (native `:hover` / `:focus-visible` / `:disabled`; icons are direct `> svg` children); `label` goes on a `<span>` wrapping each text run. */
201
+ export const buttonStyles = {
202
+ root: memoize(({ variant = "default", size = "default", variantColor, } = {}) => style(buttonVariantClass(variant, variantColor), size === "sm" && smallButtonClass)),
203
+ label: buttonTextClass,
204
+ };
200
205
  export const Button = React.forwardRef(function Button(props, forwardedRef) {
201
206
  const { children, className: classNameProp, onClick, onFocus, type = "button", size = "default", variant = "default", variantColor, isDisabled, ...buttonProps } = props;
202
207
  const [, attributes] = useButton({ onClick, onFocus }, forwardedRef);
203
- const className = useStyles(buttonVariantClass(variant, variantColor), size === "sm" && smallButtonClass);
204
- const textClassName = useStyles(buttonTextClass);
208
+ const className = useStyles(buttonStyles.root({ variant, size, variantColor }));
209
+ const textClassName = useStyles(buttonStyles.label);
205
210
  const mergedClassName = [className, classNameProp].filter(Boolean).join(" ");
206
211
  return (_jsx(RACButton, { ...buttonProps, ref: attributes.ref, type: type, isDisabled: isDisabled, className: mergedClassName, onClick: attributes.onClick, onFocus: attributes.onFocus, children: renderButtonChildren(children, textClassName) }));
207
212
  });
@@ -3,5 +3,12 @@ type CheckboxProps = {
3
3
  checked: boolean;
4
4
  setChecked: (checked: boolean) => void;
5
5
  };
6
+ /** Checkbox parts: `root` RAC `Checkbox` (`[data-hovered]`, `[data-selected]`, `[data-focus-visible]`; restyles `box` and `check` by their own classes), `box` the box span, `check` the checkmark svg, `label` the label text span. */
7
+ export declare const checkboxStyles: {
8
+ readonly root: import("purse-styles").StyleElement;
9
+ readonly box: import("purse-styles").StyleElement;
10
+ readonly check: import("purse-styles").StyleElement;
11
+ readonly label: import("purse-styles").StyleElement;
12
+ };
6
13
  export declare function Checkbox(props: CheckboxProps): import("react").JSX.Element;
7
14
  export {};
@@ -1,7 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRef } from "react";
3
- import { useCheckbox } from "react-aria";
4
- import { useToggleState } from "react-stately";
2
+ import { Checkbox as RACCheckbox } from "react-aria-components";
5
3
  import { defineVars, style, useStyles } from "purse-styles";
6
4
  import { LARGE_SCALE } from "../theme/dataScale";
7
5
  import { backgroundColor, surfaceMixPercent, surfaceWash, } from "../tokens/background";
@@ -12,39 +10,19 @@ import { motion } from "../tokens/motion";
12
10
  import { radius } from "../tokens/radius";
13
11
  import { shadow, shadowVars } from "../tokens/shadow";
14
12
  import { controlSize } from "../tokens/sizing";
15
- import { visuallyHidden } from "../tokens/visuallyHidden";
16
13
  import { labelText } from "./Typography";
17
14
  const checkboxSize = defineVars({
18
15
  box: { default: "14px", [LARGE_SCALE]: "20px" },
19
16
  checkmark: { default: "10px", [LARGE_SCALE]: "14px" },
20
17
  });
21
- const checkboxClass = style(flex({ alignItems: "center", gap: 3 }), focusRing("& .checkbox-input:focus-visible + .checkbox-toggle", shadowVars.control), {
22
- position: "relative",
23
- width: "fit-content",
24
- minHeight: controlSize.minTarget,
25
- minWidth: controlSize.minTarget,
26
- "&:hover .checkbox-toggle": {
27
- backgroundColor: backgroundColor.elementHover,
28
- },
29
- "& .checkbox-input:checked + .checkbox-toggle": {
30
- backgroundColor: colors.accent[9],
31
- },
32
- "&:hover .checkbox-input:checked + .checkbox-toggle": {
33
- backgroundColor: surfaceWash(colors.gray[12], surfaceMixPercent.hover, colors.accent[9]),
34
- },
35
- "& .checkbox-input:checked + .checkbox-toggle .checkbox-icon": {
36
- opacity: 1,
37
- transform: "scale(1)",
38
- },
39
- });
40
- const checkboxToggleClass = style(flex({ alignItems: "center", justifyContent: "center" }), radius["2xs"], shadow.control, {
18
+ const box = style(flex({ alignItems: "center", justifyContent: "center" }), radius["2xs"], shadow.control, {
41
19
  pointerEvents: "none",
42
20
  flexShrink: 0,
43
21
  width: checkboxSize.box,
44
22
  height: checkboxSize.box,
45
23
  backgroundColor: backgroundColor.element,
46
24
  });
47
- const checkboxIconClass = style(motion.standard("opacity", "transform"), {
25
+ const check = style(motion.standard("opacity", "transform"), {
48
26
  width: checkboxSize.checkmark,
49
27
  height: checkboxSize.checkmark,
50
28
  paddingTop: "0.5px",
@@ -53,15 +31,32 @@ const checkboxIconClass = style(motion.standard("opacity", "transform"), {
53
31
  opacity: 0,
54
32
  transform: "scale(0)",
55
33
  });
34
+ const root = style(flex({ alignItems: "center", gap: 3 }), focusRing(`&[data-focus-visible] ${box}`, shadowVars.control), {
35
+ position: "relative",
36
+ width: "fit-content",
37
+ minHeight: controlSize.minTarget,
38
+ minWidth: controlSize.minTarget,
39
+ [`&[data-hovered] ${box}`]: {
40
+ backgroundColor: backgroundColor.elementHover,
41
+ },
42
+ [`&[data-selected] ${box}`]: {
43
+ backgroundColor: colors.accent[9],
44
+ },
45
+ [`&[data-selected][data-hovered] ${box}`]: {
46
+ backgroundColor: surfaceWash(colors.gray[12], surfaceMixPercent.hover, colors.accent[9]),
47
+ },
48
+ [`&[data-selected] ${check}`]: {
49
+ opacity: 1,
50
+ transform: "scale(1)",
51
+ },
52
+ });
53
+ /** Checkbox parts: `root` RAC `Checkbox` (`[data-hovered]`, `[data-selected]`, `[data-focus-visible]`; restyles `box` and `check` by their own classes), `box` the box span, `check` the checkmark svg, `label` the label text span. */
54
+ export const checkboxStyles = { root, box, check, label: labelText };
56
55
  export function Checkbox(props) {
57
56
  const { label, checked, setChecked } = props;
58
- const state = useToggleState({ isSelected: checked, onChange: setChecked });
59
- const ref = useRef(null);
60
- const { inputProps } = useCheckbox({ "aria-label": props.label }, state, ref);
61
- const className = useStyles(checkboxClass);
62
- const inputClassName = useStyles(visuallyHidden);
63
- const toggleClassName = useStyles(checkboxToggleClass);
64
- const iconClassName = useStyles(checkboxIconClass);
65
- const labelClassName = useStyles(labelText);
66
- return (_jsxs("label", { className: className, children: [_jsx("input", { ...inputProps, className: `${inputClassName} checkbox-input`, ref: ref }), _jsx("span", { className: `${toggleClassName} checkbox-toggle`, children: _jsx("svg", { focusable: "false", "aria-hidden": "true", className: `${iconClassName} checkbox-icon`, viewBox: "0 0 11 11", children: _jsx("path", { d: "M3.788 9A.999.999 0 0 1 3 8.615l-2.288-3a1 1 0 1 1 1.576-1.23l1.5 1.991 3.924-4.991a1 1 0 1 1 1.576 1.23l-4.712 6A.999.999 0 0 1 3.788 9z" }) }) }), label && _jsx("span", { className: labelClassName, children: label })] }));
57
+ const className = useStyles(checkboxStyles.root);
58
+ const boxClassName = useStyles(checkboxStyles.box);
59
+ const checkClassName = useStyles(checkboxStyles.check);
60
+ const labelClassName = useStyles(checkboxStyles.label);
61
+ return (_jsxs(RACCheckbox, { className: className, isSelected: checked, onChange: setChecked, children: [_jsx("span", { className: boxClassName, children: _jsx("svg", { focusable: "false", "aria-hidden": "true", className: checkClassName, viewBox: "0 0 11 11", children: _jsx("path", { d: "M3.788 9A.999.999 0 0 1 3 8.615l-2.288-3a1 1 0 1 1 1.576-1.23l1.5 1.991 3.924-4.991a1 1 0 1 1 1.576 1.23l-4.712 6A.999.999 0 0 1 3.788 9z" }) }) }), label && _jsx("span", { className: labelClassName, children: label })] }));
67
62
  }
@@ -4,6 +4,16 @@ export type KbdVariant = "default" | "quiet";
4
4
  export type KbdProps = CodeProps & {
5
5
  variant?: KbdVariant;
6
6
  };
7
+ /** `root` on a `<code>` element (inline, no state). */
8
+ export declare const codeStyles: {
9
+ readonly root: import("purse-styles").StyleElement;
10
+ };
7
11
  export declare function Code({ className, children, ...props }: CodeProps): React.JSX.Element;
12
+ /** `root({ variant })` on a `<kbd>` element (inline keycap, no state). */
13
+ export declare const kbdStyles: {
14
+ readonly root: (args_0?: {
15
+ variant?: KbdVariant;
16
+ } | undefined) => import("purse-styles").StyleElement;
17
+ };
8
18
  export declare function Kbd({ className, children, variant, ...props }: KbdProps): React.JSX.Element;
9
19
  export {};
@@ -4,6 +4,7 @@ import { colors } from "../tokens/colors";
4
4
  import { radius } from "../tokens/radius";
5
5
  import { spacing } from "../tokens/spacing";
6
6
  import { monospace, text } from "../tokens/text";
7
+ import { memoize } from "../utils/memoize";
7
8
  const codeClass = style(monospace, radius.sm, spacing.padding({ x: 2, y: 1 }), {
8
9
  backgroundColor: colors.gray[3],
9
10
  color: colors.gray[12],
@@ -26,12 +27,18 @@ const kbdClass = style(text({ size: "xs", fontWeight: 400, color: "lowContrast"
26
27
  const quietKbdClass = style(kbdClass, {
27
28
  backgroundColor: "transparent",
28
29
  });
30
+ /** `root` on a `<code>` element (inline, no state). */
31
+ export const codeStyles = { root: codeClass };
29
32
  export function Code({ className, children, ...props }) {
30
- const codeClassName = useStyles(codeClass);
33
+ const codeClassName = useStyles(codeStyles.root);
31
34
  return (_jsx("code", { ...props, className: joinClassNames(codeClassName, className), children: children }));
32
35
  }
36
+ /** `root({ variant })` on a `<kbd>` element (inline keycap, no state). */
37
+ export const kbdStyles = {
38
+ root: memoize(({ variant = "default" } = {}) => variant === "quiet" ? quietKbdClass : kbdClass),
39
+ };
33
40
  export function Kbd({ className, children, variant = "default", ...props }) {
34
- const kbdClassName = useStyles(variant === "quiet" ? quietKbdClass : kbdClass);
41
+ const kbdClassName = useStyles(kbdStyles.root({ variant }));
35
42
  return (_jsx("kbd", { ...props, className: joinClassNames(kbdClassName, className), children: children }));
36
43
  }
37
44
  function joinClassNames(...classNames) {
@@ -1,3 +1,8 @@
1
+ /** `root` on the `<pre>` (or on a wrapper around Shiki's HTML; restyles its `.shiki` descendants, no state); `code` on the `<code>` inside a plain, unhighlighted `<pre>`. */
2
+ export declare const codeBlockStyles: {
3
+ readonly root: import("purse-styles").StyleElement;
4
+ readonly code: import("purse-styles").StyleElement;
5
+ };
1
6
  export declare function CodeBlock(props: {
2
7
  children: string;
3
8
  lang: string;
@@ -33,9 +33,14 @@ const codeBlockClass = style(text({ size: "xs", fontWeight: 400, color: "highCon
33
33
  const codeClass = style({
34
34
  font: "inherit",
35
35
  });
36
+ /** `root` on the `<pre>` (or on a wrapper around Shiki's HTML; restyles its `.shiki` descendants, no state); `code` on the `<code>` inside a plain, unhighlighted `<pre>`. */
37
+ export const codeBlockStyles = {
38
+ root: codeBlockClass,
39
+ code: codeClass,
40
+ };
36
41
  export function CodeBlock(props) {
37
- const className = useStyles(codeBlockClass);
38
- const codeClassName = useStyles(codeClass);
42
+ const className = useStyles(codeBlockStyles.root);
43
+ const codeClassName = useStyles(codeBlockStyles.code);
39
44
  const [html, setHtml] = useState(null);
40
45
  const { resolvedTheme } = useTheme();
41
46
  useEffect(() => {
@@ -1,4 +1,8 @@
1
1
  import { type PopoverProps } from "react-aria-components";
2
+ /** `root` goes on RAC `Popover`; sizes from RAC's `--trigger-width` variable. */
3
+ export declare const collectionPopoverStyles: {
4
+ readonly root: import("purse-styles").StyleElement;
5
+ };
2
6
  export interface CollectionPopoverProps extends Omit<PopoverProps, "className"> {
3
7
  }
4
8
  export declare function CollectionPopover({ placement, offset, ...props }: CollectionPopoverProps): import("react").JSX.Element;
@@ -5,13 +5,15 @@ import { backgroundColor } from "../tokens/background";
5
5
  import { radius } from "../tokens/radius";
6
6
  import { shadow } from "../tokens/shadow";
7
7
  import { spacing } from "../tokens/spacing";
8
- const collectionPopoverStyle = style(radius.sm, shadow.strong, spacing.padding({ y: 1 }), {
8
+ const root = style(radius.sm, shadow.strong, spacing.padding({ y: 1 }), {
9
9
  minWidth: "var(--trigger-width)",
10
10
  maxHeight: "280px",
11
11
  overflow: "hidden",
12
12
  background: backgroundColor.element,
13
13
  });
14
+ /** `root` goes on RAC `Popover`; sizes from RAC's `--trigger-width` variable. */
15
+ export const collectionPopoverStyles = { root };
14
16
  export function CollectionPopover({ placement = "bottom start", offset = 6, ...props }) {
15
- const className = useStyles(collectionPopoverStyle);
17
+ const className = useStyles(collectionPopoverStyles.root);
16
18
  return (_jsx(Popover, { ...props, className: className, placement: placement, offset: offset }));
17
19
  }
@@ -15,6 +15,17 @@ export type DialogProps = {
15
15
  "aria-labelledby"?: string;
16
16
  className?: string;
17
17
  };
18
+ /** Dialog parts: `overlay` RAC `ModalOverlay`, `modal({ size })` RAC `Modal`, `dialog` RAC `Dialog`, `title` RAC `Heading slot="title"`, `body` and `actions` plain divs inside the dialog; no state attributes (enter/exit motion is JS, not CSS). */
19
+ export declare const dialogStyles: {
20
+ readonly overlay: import("purse-styles").StyleElement;
21
+ readonly modal: (args_0?: {
22
+ size?: DialogSize;
23
+ } | undefined) => import("purse-styles").StyleElement;
24
+ readonly dialog: import("purse-styles").StyleElement;
25
+ readonly title: import("purse-styles").StyleElement;
26
+ readonly body: import("purse-styles").StyleElement;
27
+ readonly actions: import("purse-styles").StyleElement;
28
+ };
18
29
  export declare function Dialog({ children, isOpen: isOpenProp, defaultOpen, onOpenChange, isDismissable, isKeyboardDismissDisabled, size, role, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, className, }: DialogProps): import("react").JSX.Element;
19
30
  export type DialogTitleProps = Omit<ComponentPropsWithoutRef<typeof Heading>, "slot">;
20
31
  export declare function DialogTitle({ className, ...props }: DialogTitleProps): import("react").JSX.Element;
@@ -10,6 +10,7 @@ import { radius } from "../tokens/radius";
10
10
  import { spacing } from "../tokens/spacing";
11
11
  import { text } from "../tokens/text";
12
12
  import { cls } from "../utils/cls";
13
+ import { memoize } from "../utils/memoize";
13
14
  const MotionModalOverlay = motion.create(ModalOverlay);
14
15
  const MotionModal = motion.create(Modal);
15
16
  const dialogEnterTransition = {
@@ -29,7 +30,7 @@ const reducedMotionTransition = {
29
30
  duration: overlayMotion.reduced.durationMs / 1000,
30
31
  ease: "easeInOut",
31
32
  };
32
- const overlayClass = style({
33
+ const overlay = style({
33
34
  position: "fixed",
34
35
  inset: 0,
35
36
  zIndex: 1200,
@@ -42,7 +43,7 @@ const overlayClass = style({
42
43
  overflow: "auto",
43
44
  overscrollBehavior: "contain",
44
45
  });
45
- const surfaceClass = style(background.element, border([], "outline"), radius.lg, {
46
+ const modalBase = style(background.element, border([], "outline"), radius.lg, {
46
47
  width: "min(440px, calc(100vw - 32px))",
47
48
  maxWidth: "100%",
48
49
  maxHeight: "calc(100dvh - 32px)",
@@ -55,12 +56,12 @@ const surfaceClass = style(background.element, border([], "outline"), radius.lg,
55
56
  transformOrigin: "center",
56
57
  willChange: "opacity, transform",
57
58
  });
58
- const surfaceSizeClasses = {
59
+ const modalSizes = {
59
60
  sm: style({ width: "min(440px, calc(100vw - 32px))" }),
60
61
  md: style({ width: "min(640px, calc(100vw - 32px))" }),
61
62
  lg: style({ width: "min(960px, calc(100vw - 32px))" }),
62
63
  };
63
- const dialogClass = style({
64
+ const dialog = style({
64
65
  minWidth: 0,
65
66
  minHeight: 0,
66
67
  display: "flex",
@@ -68,29 +69,39 @@ const dialogClass = style({
68
69
  gap: spacing.value(8),
69
70
  outline: "none",
70
71
  });
71
- const titleClass = style(text({ size: "lg", fontWeight: 600 }), {
72
+ const title = style(text({ size: "lg", fontWeight: 600 }), {
72
73
  margin: 0,
73
74
  });
74
- const bodyClass = style({
75
+ const body = style({
75
76
  minWidth: 0,
76
77
  minHeight: 0,
77
78
  overflowY: "auto",
78
79
  });
79
- const actionsClass = style({
80
+ const actions = style({
80
81
  display: "flex",
81
82
  alignItems: "center",
82
83
  justifyContent: "flex-end",
83
84
  flexWrap: "wrap",
84
85
  gap: spacing.value(4),
85
86
  });
87
+ const modal = memoize(({ size = "sm" } = {}) => style(modalBase, modalSizes[size]));
88
+ /** Dialog parts: `overlay` RAC `ModalOverlay`, `modal({ size })` RAC `Modal`, `dialog` RAC `Dialog`, `title` RAC `Heading slot="title"`, `body` and `actions` plain divs inside the dialog; no state attributes (enter/exit motion is JS, not CSS). */
89
+ export const dialogStyles = {
90
+ overlay,
91
+ modal,
92
+ dialog,
93
+ title,
94
+ body,
95
+ actions,
96
+ };
86
97
  export function Dialog({ children, isOpen: isOpenProp, defaultOpen = false, onOpenChange, isDismissable = true, isKeyboardDismissDisabled, size = "sm", role = "dialog", "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, className, }) {
87
98
  const isControlled = isOpenProp !== undefined;
88
99
  const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
89
100
  const isOpen = isControlled ? isOpenProp : uncontrolledOpen;
90
101
  const reduceMotion = Boolean(useReducedMotion());
91
- const overlayClassName = useStyles(overlayClass);
92
- const surfaceClassName = useStyles(surfaceClass, surfaceSizeClasses[size]);
93
- const dialogClassName = useStyles(dialogClass);
102
+ const overlayClassName = useStyles(dialogStyles.overlay);
103
+ const surfaceClassName = useStyles(dialogStyles.modal({ size }));
104
+ const dialogClassName = useStyles(dialogStyles.dialog);
94
105
  const setOpen = useCallback((next) => {
95
106
  if (!isControlled) {
96
107
  setUncontrolledOpen(next);
@@ -107,14 +118,14 @@ export function Dialog({ children, isOpen: isOpenProp, defaultOpen = false, onOp
107
118
  return (_jsx(AnimatePresence, { children: isOpen && (_jsx(MotionModalOverlay, { isOpen: true, onOpenChange: setOpen, isDismissable: isDismissable, isKeyboardDismissDisabled: isKeyboardDismissDisabled, className: overlayClassName, initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: reduceMotion ? reducedMotionTransition : backdropTransition, children: _jsx(MotionModal, { className: cls(surfaceClassName, className), initial: { opacity: 0, scale }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale, transition: exitTransition }, transition: enterTransition, children: _jsx(AriaDialog, { role: role, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, className: dialogClassName, children: children }) }) })) }));
108
119
  }
109
120
  export function DialogTitle({ className, ...props }) {
110
- const titleClassName = useStyles(titleClass);
121
+ const titleClassName = useStyles(dialogStyles.title);
111
122
  return (_jsx(Heading, { ...props, slot: "title", className: cls(titleClassName, className) }));
112
123
  }
113
124
  export function DialogBody({ className, ...props }) {
114
- const bodyClassName = useStyles(bodyClass);
125
+ const bodyClassName = useStyles(dialogStyles.body);
115
126
  return _jsx("div", { ...props, className: cls(bodyClassName, className) });
116
127
  }
117
128
  export function DialogActions({ className, ...props }) {
118
- const actionsClassName = useStyles(actionsClass);
129
+ const actionsClassName = useStyles(dialogStyles.actions);
119
130
  return _jsx("div", { ...props, className: cls(actionsClassName, className) });
120
131
  }
@@ -13,4 +13,13 @@ export type DrawerProps = {
13
13
  "aria-labelledby"?: string;
14
14
  className?: string;
15
15
  };
16
+ /** Drawer parts: `overlay` RAC `ModalOverlay` (scrim color is animated inline; add `reducedMotionScrim` with it under reduced motion), `modal` RAC `Modal` (keys off `[data-side='start'|'end']`, which RAC does not set: pass `data-side` yourself), `panel` the sliding element inside the modal (restyles a `nav` that is a direct child of `[role='dialog']`), `dialog` RAC `Dialog`, `title` visually hidden RAC `Heading slot="title"`. */
17
+ export declare const drawerStyles: {
18
+ readonly overlay: import("purse-styles").StyleElement;
19
+ readonly reducedMotionScrim: import("purse-styles").StyleElement;
20
+ readonly modal: import("purse-styles").StyleElement;
21
+ readonly panel: import("purse-styles").StyleElement;
22
+ readonly dialog: import("purse-styles").StyleElement;
23
+ readonly title: import("purse-styles").StyleElement;
24
+ };
16
25
  export declare function Drawer({ children, isOpen: isOpenProp, defaultOpen, onOpenChange, side, isDismissable, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, className, }: DrawerProps): import("react").JSX.Element | null;