@yarcl/react 0.1.0 → 0.2.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.
Files changed (223) hide show
  1. package/README.md +14 -2
  2. package/{src/apply.ts → dist/apply.d.ts} +4 -23
  3. package/dist/apply.js +37 -0
  4. package/dist/classes.d.ts +13 -0
  5. package/dist/classes.js +22 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +58 -0
  8. package/dist/color.js +49 -32
  9. package/dist/components/Accordion.d.ts +96 -0
  10. package/dist/components/Accordion.js +148 -0
  11. package/dist/components/Alert.d.ts +60 -0
  12. package/dist/components/Alert.js +61 -0
  13. package/dist/components/Avatar.d.ts +100 -0
  14. package/dist/components/Avatar.js +89 -0
  15. package/dist/components/Badge.d.ts +44 -0
  16. package/dist/components/Badge.js +43 -0
  17. package/dist/components/Breadcrumb.d.ts +77 -0
  18. package/dist/components/Breadcrumb.js +126 -0
  19. package/dist/components/Button.d.ts +18 -0
  20. package/dist/components/Button.js +33 -0
  21. package/dist/components/ButtonGroup.d.ts +29 -0
  22. package/dist/components/ButtonGroup.js +37 -0
  23. package/dist/components/Card.d.ts +36 -0
  24. package/dist/components/Card.js +26 -0
  25. package/dist/components/Checkbox.d.ts +28 -0
  26. package/dist/components/Checkbox.js +38 -0
  27. package/dist/components/Combobox.d.ts +75 -0
  28. package/dist/components/Combobox.js +362 -0
  29. package/dist/components/CommandPalette.d.ts +92 -0
  30. package/dist/components/CommandPalette.js +293 -0
  31. package/dist/components/DatePicker.d.ts +157 -0
  32. package/dist/components/DatePicker.js +230 -0
  33. package/dist/components/Dialog.d.ts +25 -0
  34. package/dist/components/Dialog.js +29 -0
  35. package/dist/components/Divider.d.ts +23 -0
  36. package/dist/components/Divider.js +25 -0
  37. package/dist/components/Drawer.d.ts +21 -0
  38. package/dist/components/Drawer.js +25 -0
  39. package/dist/components/EmptyState.d.ts +51 -0
  40. package/dist/components/EmptyState.js +47 -0
  41. package/dist/components/Field.d.ts +27 -0
  42. package/dist/components/Field.js +59 -0
  43. package/dist/components/Heading.d.ts +26 -0
  44. package/dist/components/Heading.js +25 -0
  45. package/dist/components/HoverCard.d.ts +47 -0
  46. package/dist/components/HoverCard.js +53 -0
  47. package/dist/components/IconButton.d.ts +19 -0
  48. package/dist/components/IconButton.js +32 -0
  49. package/dist/components/Inline.d.ts +21 -0
  50. package/dist/components/Inline.js +24 -0
  51. package/dist/components/Input.d.ts +19 -0
  52. package/dist/components/Input.js +25 -0
  53. package/dist/components/Label.d.ts +46 -0
  54. package/dist/components/Label.js +33 -0
  55. package/dist/components/Link.d.ts +27 -0
  56. package/dist/components/Link.js +26 -0
  57. package/dist/components/Menu.d.ts +73 -0
  58. package/dist/components/Menu.js +143 -0
  59. package/dist/components/Modal.d.ts +45 -0
  60. package/dist/components/Modal.js +110 -0
  61. package/dist/components/NumberInput.d.ts +49 -0
  62. package/dist/components/NumberInput.js +130 -0
  63. package/dist/components/Pagination.d.ts +86 -0
  64. package/dist/components/Pagination.js +119 -0
  65. package/dist/components/Popover.d.ts +72 -0
  66. package/dist/components/Popover.js +87 -0
  67. package/dist/components/Progress.d.ts +60 -0
  68. package/dist/components/Progress.js +59 -0
  69. package/dist/components/Radio.d.ts +32 -0
  70. package/dist/components/Radio.js +47 -0
  71. package/dist/components/RadioGroup.d.ts +57 -0
  72. package/dist/components/RadioGroup.js +68 -0
  73. package/dist/components/Select.d.ts +47 -0
  74. package/dist/components/Select.js +138 -0
  75. package/dist/components/Skeleton.d.ts +46 -0
  76. package/dist/components/Skeleton.js +40 -0
  77. package/dist/components/Slider.d.ts +126 -0
  78. package/dist/components/Slider.js +166 -0
  79. package/dist/components/Spinner.d.ts +23 -0
  80. package/dist/components/Spinner.js +23 -0
  81. package/dist/components/Stack.d.ts +35 -0
  82. package/dist/components/Stack.js +24 -0
  83. package/dist/components/Switch.d.ts +27 -0
  84. package/dist/components/Switch.js +33 -0
  85. package/dist/components/Table.d.ts +71 -0
  86. package/dist/components/Table.js +61 -0
  87. package/dist/components/Tabs.d.ts +66 -0
  88. package/dist/components/Tabs.js +109 -0
  89. package/dist/components/Text.d.ts +32 -0
  90. package/dist/components/Text.js +28 -0
  91. package/dist/components/Textarea.d.ts +15 -0
  92. package/dist/components/Textarea.js +24 -0
  93. package/dist/components/Toast.d.ts +90 -0
  94. package/dist/components/Toast.js +156 -0
  95. package/dist/components/ToggleGroup.d.ts +79 -0
  96. package/dist/components/ToggleGroup.js +101 -0
  97. package/dist/components/Tooltip.d.ts +46 -0
  98. package/dist/components/Tooltip.js +62 -0
  99. package/dist/components/VisuallyHidden.d.ts +18 -0
  100. package/dist/components/VisuallyHidden.js +22 -0
  101. package/dist/contrast.d.ts +32 -0
  102. package/dist/css.d.ts +2 -2
  103. package/dist/css.js +193 -157
  104. package/dist/define.d.ts +40 -15
  105. package/dist/define.js +30 -27
  106. package/dist/demo.d.ts +2 -0
  107. package/dist/demo.js +2 -0
  108. package/dist/esbuild.cjs +5 -0
  109. package/dist/esbuild.d.ts +4 -0
  110. package/dist/esbuild.js +6 -0
  111. package/dist/field-context.d.ts +16 -0
  112. package/dist/field-context.js +17 -0
  113. package/dist/floating.d.ts +12 -0
  114. package/dist/floating.js +52 -0
  115. package/dist/hooks.d.ts +1 -0
  116. package/dist/hooks.js +12 -0
  117. package/{src/index.ts → dist/index.d.ts} +11 -33
  118. package/dist/index.js +50 -0
  119. package/dist/init.d.ts +18 -0
  120. package/dist/init.js +224 -0
  121. package/dist/plugin.d.ts +10 -26
  122. package/dist/plugin.js +152 -78
  123. package/dist/reference/DemoYarcl.d.ts +12 -0
  124. package/dist/reference/DemoYarcl.js +312 -0
  125. package/dist/reference/DesignReference.d.ts +24 -0
  126. package/dist/reference/DesignReference.js +403 -0
  127. package/dist/reference/index.js +2 -0
  128. package/dist/rollup.cjs +5 -0
  129. package/dist/rollup.d.ts +4 -0
  130. package/dist/rollup.js +6 -0
  131. package/dist/rspack.cjs +5 -0
  132. package/dist/rspack.d.ts +4 -0
  133. package/dist/rspack.js +6 -0
  134. package/dist/runtime.d.ts +13 -0
  135. package/dist/runtime.js +30 -0
  136. package/dist/setup.d.ts +6 -0
  137. package/dist/setup.js +33 -0
  138. package/{src → dist}/styles.css +224 -106
  139. package/dist/themes/bloom.d.ts +295 -0
  140. package/dist/themes/bloom.js +202 -0
  141. package/dist/themes/brutalist.d.ts +277 -0
  142. package/dist/themes/brutalist.js +199 -0
  143. package/dist/themes/compact.d.ts +274 -0
  144. package/dist/themes/compact.js +200 -0
  145. package/dist/themes/contract.d.ts +23 -0
  146. package/dist/themes/editorial.d.ts +277 -0
  147. package/dist/themes/editorial.js +183 -0
  148. package/dist/themes/index.d.ts +1425 -0
  149. package/dist/themes/index.js +45 -0
  150. package/{src/types.ts → dist/types.d.ts} +40 -37
  151. package/dist/vite.cjs +5 -0
  152. package/dist/vite.d.ts +4 -0
  153. package/dist/vite.js +6 -0
  154. package/dist/webpack.cjs +5 -0
  155. package/dist/webpack.d.ts +4 -0
  156. package/dist/webpack.js +6 -0
  157. package/dist/yarcl.config.d.ts +276 -0
  158. package/dist/yarcl.config.js +273 -0
  159. package/package.json +69 -17
  160. package/src/classes.ts +0 -23
  161. package/src/color.ts +0 -48
  162. package/src/components/Accordion.tsx +0 -274
  163. package/src/components/Alert.tsx +0 -85
  164. package/src/components/Badge.tsx +0 -79
  165. package/src/components/Breadcrumb.tsx +0 -239
  166. package/src/components/Button.tsx +0 -58
  167. package/src/components/ButtonGroup.tsx +0 -61
  168. package/src/components/Card.tsx +0 -50
  169. package/src/components/Checkbox.tsx +0 -49
  170. package/src/components/Combobox.tsx +0 -522
  171. package/src/components/CommandPalette.tsx +0 -452
  172. package/src/components/DatePicker.tsx +0 -432
  173. package/src/components/Dialog.tsx +0 -39
  174. package/src/components/Divider.tsx +0 -34
  175. package/src/components/Drawer.tsx +0 -31
  176. package/src/components/Field.tsx +0 -61
  177. package/src/components/Heading.tsx +0 -40
  178. package/src/components/HoverCard.tsx +0 -108
  179. package/src/components/IconButton.tsx +0 -59
  180. package/src/components/Inline.tsx +0 -42
  181. package/src/components/Input.tsx +0 -28
  182. package/src/components/Label.tsx +0 -58
  183. package/src/components/Link.tsx +0 -41
  184. package/src/components/Menu.tsx +0 -207
  185. package/src/components/Modal.tsx +0 -164
  186. package/src/components/NumberInput.tsx +0 -208
  187. package/src/components/Pagination.tsx +0 -227
  188. package/src/components/Popover.tsx +0 -140
  189. package/src/components/Progress.tsx +0 -122
  190. package/src/components/Radio.tsx +0 -59
  191. package/src/components/RadioGroup.tsx +0 -114
  192. package/src/components/Select.tsx +0 -197
  193. package/src/components/Skeleton.tsx +0 -95
  194. package/src/components/Slider.tsx +0 -315
  195. package/src/components/Spinner.tsx +0 -38
  196. package/src/components/Stack.tsx +0 -57
  197. package/src/components/Switch.tsx +0 -42
  198. package/src/components/Table.tsx +0 -99
  199. package/src/components/Tabs.tsx +0 -159
  200. package/src/components/Text.tsx +0 -67
  201. package/src/components/Textarea.tsx +0 -26
  202. package/src/components/Toast.tsx +0 -190
  203. package/src/components/ToggleGroup.tsx +0 -227
  204. package/src/components/Tooltip.tsx +0 -78
  205. package/src/contrast.ts +0 -82
  206. package/src/css.ts +0 -228
  207. package/src/define.check.ts +0 -259
  208. package/src/define.ts +0 -379
  209. package/src/field-context.ts +0 -31
  210. package/src/floating.tsx +0 -61
  211. package/src/hooks.ts +0 -19
  212. package/src/plugin.ts +0 -94
  213. package/src/reference/DesignReference.tsx +0 -374
  214. package/src/runtime.ts +0 -38
  215. package/src/themes/bloom.ts +0 -72
  216. package/src/themes/brutalist.ts +0 -63
  217. package/src/themes/compact.ts +0 -63
  218. package/src/themes/contract.ts +0 -24
  219. package/src/themes/editorial.ts +0 -55
  220. package/src/themes/index.ts +0 -47
  221. package/src/yarcl.config.ts +0 -104
  222. /package/{src/reference/index.ts → dist/reference/index.d.ts} +0 -0
  223. /package/{src → dist}/reference/reference.css +0 -0
@@ -0,0 +1,46 @@
1
+ import type { ComponentProps } from 'react';
2
+ import type { Color, ComponentSize, Radius, TextStyle, Variant } from '../types';
3
+ /** Props for {@link Label}. */
4
+ export interface LabelProps extends Omit<ComponentProps<'label'>, 'color'> {
5
+ /**
6
+ * Text style, from the `typography.styles` config.
7
+ * @default config.defaults.labelStyle
8
+ */
9
+ textStyle?: TextStyle;
10
+ /**
11
+ * Semantic color, from the `colors` config. Colors the label text; neutral when omitted.
12
+ */
13
+ color?: Color;
14
+ /**
15
+ * Style recipe, from the `variants` config, for a filled label. Plain when omitted.
16
+ */
17
+ variant?: Variant;
18
+ /**
19
+ * Font size scale, from the `sizes` config. Uses the text style's size when omitted.
20
+ */
21
+ size?: ComponentSize<'Label'>;
22
+ /**
23
+ * Corner radius, from the `radii` config.
24
+ * @default config.defaults.radius
25
+ */
26
+ radius?: Radius | 'size';
27
+ /**
28
+ * Shows a required marker in `defaults.errorColor`. The marker is hidden from screen readers,
29
+ * so also set `required` (or `aria-required`) on the control.
30
+ */
31
+ required?: boolean;
32
+ /** Uses the muted color, to match a disabled control. */
33
+ disabled?: boolean;
34
+ }
35
+ /**
36
+ * A form label in the consumer's `defaults.labelStyle`, or a filled label with a variant. Connect
37
+ * it with `htmlFor`, or give it an `id` and point the control's `aria-labelledby` at it.
38
+ *
39
+ * @example
40
+ * ```tsx
41
+ * <Label htmlFor="email" required>Email</Label>
42
+ * <Input id="email" type="email" />
43
+ * <Label variant="soft" color="success">Active</Label>
44
+ * ```
45
+ */
46
+ export declare function Label({ textStyle, color, variant, size, radius, required, disabled, className, children, ...props }: LabelProps): import("react").JSX.Element;
@@ -0,0 +1,33 @@
1
+ import { useConfig, useDefaults } from "../runtime.js";
2
+ import { colorClass, cx, radiusClass, sizeClass, softVariantClass, typeClass } from "../classes.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/components/Label.tsx
5
+ /**
6
+ * A form label in the consumer's `defaults.labelStyle`, or a filled label with a variant. Connect
7
+ * it with `htmlFor`, or give it an `id` and point the control's `aria-labelledby` at it.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * <Label htmlFor="email" required>Email</Label>
12
+ * <Input id="email" type="email" />
13
+ * <Label variant="soft" color="success">Active</Label>
14
+ * ```
15
+ */
16
+ function Label({ textStyle, color, variant, size, radius, required, disabled, className, children, ...props }) {
17
+ const config = useConfig();
18
+ const own = useDefaults("Label");
19
+ const resolvedSize = size ?? own.size;
20
+ const resolvedColor = color ?? own.color;
21
+ const resolvedVariant = variant ?? own.variant;
22
+ return /* @__PURE__ */ jsxs("label", {
23
+ className: cx("yarcl-label", typeClass(textStyle ?? own.textStyle ?? config.defaults.labelStyle), resolvedColor && cx("yarcl-label-colored", colorClass(resolvedColor)), resolvedVariant && cx("yarcl-label-variant", softVariantClass(resolvedVariant)), resolvedSize && cx("yarcl-label-sized", sizeClass(resolvedSize, "Label")), radiusClass(radius ?? own.radius, resolvedSize), disabled && "yarcl-label-disabled", className),
24
+ ...props,
25
+ children: [children, required && /* @__PURE__ */ jsx("span", {
26
+ className: "yarcl-label-required",
27
+ "aria-hidden": "true",
28
+ children: " *"
29
+ })]
30
+ });
31
+ }
32
+ //#endregion
33
+ export { Label };
@@ -0,0 +1,27 @@
1
+ import type { ComponentProps } from 'react';
2
+ import type { Color } from '../types';
3
+ /** Props for {@link Link}. Accepts all native `<a>` attributes except `color`. */
4
+ export interface LinkProps extends Omit<ComponentProps<'a'>, 'color'> {
5
+ /**
6
+ * Link color, from the `colors` config.
7
+ * @default config.defaults.color
8
+ */
9
+ color?: Color;
10
+ /**
11
+ * When to underline. Keep `'always'` for links inside running text, so they don't rely on color alone.
12
+ * @default 'always'
13
+ */
14
+ underline?: 'always' | 'hover' | 'none';
15
+ /** Opens in a new tab with `rel="noopener noreferrer"`. */
16
+ external?: boolean;
17
+ }
18
+ /**
19
+ * A text link that inherits the surrounding text style.
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * <Link href="/docs">Read the docs</Link>
24
+ * <Link href="https://example.com" external>Example</Link>
25
+ * ```
26
+ */
27
+ export declare function Link({ color, underline, external, className, ...props }: LinkProps): import("react").JSX.Element;
@@ -0,0 +1,26 @@
1
+ import { useDefaults } from "../runtime.js";
2
+ import { colorClass, cx } from "../classes.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/components/Link.tsx
5
+ /**
6
+ * A text link that inherits the surrounding text style.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * <Link href="/docs">Read the docs</Link>
11
+ * <Link href="https://example.com" external>Example</Link>
12
+ * ```
13
+ */
14
+ function Link({ color, underline = "always", external, className, ...props }) {
15
+ const own = useDefaults("Link");
16
+ return /* @__PURE__ */ jsx("a", {
17
+ className: cx("yarcl-link", `yarcl-link-underline-${underline}`, colorClass(color ?? own.color), className),
18
+ ...external && {
19
+ target: "_blank",
20
+ rel: "noopener noreferrer"
21
+ },
22
+ ...props
23
+ });
24
+ }
25
+ //#endregion
26
+ export { Link };
@@ -0,0 +1,73 @@
1
+ import { type Placement } from '@floating-ui/react';
2
+ import { type ComponentProps, type ReactElement, type ReactNode } from 'react';
3
+ import type { Color, ComponentSize } from '../types';
4
+ /** Props for {@link Menu}. */
5
+ export interface MenuProps {
6
+ /** `Menu.Trigger` and `Menu.Content`. */
7
+ children?: ReactNode;
8
+ /** Controlled open state. */
9
+ open?: boolean;
10
+ /**
11
+ * Initial open state when uncontrolled.
12
+ * @default false
13
+ */
14
+ defaultOpen?: boolean;
15
+ /** Called when the menu opens or closes. */
16
+ onOpenChange?: (open: boolean) => void;
17
+ /**
18
+ * Preferred side. Flips when there isn't room.
19
+ * @default 'bottom-start'
20
+ */
21
+ placement?: Placement;
22
+ /**
23
+ * Item size, from the `sizes` config.
24
+ * @default config.defaults.size
25
+ */
26
+ size?: ComponentSize<'Menu'>;
27
+ }
28
+ declare function MenuRoot(props: MenuProps): import("react").JSX.Element;
29
+ /** Props for `Menu.Trigger`. */
30
+ export interface MenuTriggerProps {
31
+ /** A single element, usually a {@link Button}. */
32
+ children: ReactElement;
33
+ }
34
+ declare function MenuTrigger({ children }: MenuTriggerProps): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
35
+ /** Props for `Menu.Content`. */
36
+ export interface MenuContentProps extends ComponentProps<'div'> {
37
+ }
38
+ declare function MenuContent({ className, style, children, ...props }: MenuContentProps): import("react").JSX.Element | null;
39
+ /** Props for `Menu.Item`. */
40
+ export interface MenuItemProps extends Omit<ComponentProps<'button'>, 'color' | 'onSelect'> {
41
+ /** Called when the item is chosen by click, Enter or Space. The menu closes afterwards. */
42
+ onSelect?: () => void;
43
+ /** Semantic color for the item, e.g. a destructive action. From the `colors` config. */
44
+ color?: Color;
45
+ /** Text used for type-to-select. Defaults to `children` when it is a string. */
46
+ textValue?: string;
47
+ }
48
+ declare function MenuItem({ onSelect, color, textValue, disabled, className, children, ...props }: MenuItemProps): import("react").JSX.Element;
49
+ /** A line between groups of `Menu.Item`s. */
50
+ declare function MenuSeparator(): import("react").JSX.Element;
51
+ /**
52
+ * A list of actions opened from a trigger. Arrow keys move between items,
53
+ * typing jumps to a matching item, Esc closes.
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * <Menu>
58
+ * <Menu.Trigger><Button variant="outline">Actions</Button></Menu.Trigger>
59
+ * <Menu.Content>
60
+ * <Menu.Item onSelect={rename}>Rename</Menu.Item>
61
+ * <Menu.Separator />
62
+ * <Menu.Item color="danger" onSelect={remove}>Delete</Menu.Item>
63
+ * </Menu.Content>
64
+ * </Menu>
65
+ * ```
66
+ */
67
+ export declare const Menu: typeof MenuRoot & {
68
+ Trigger: typeof MenuTrigger;
69
+ Content: typeof MenuContent;
70
+ Item: typeof MenuItem;
71
+ Separator: typeof MenuSeparator;
72
+ };
73
+ export {};
@@ -0,0 +1,143 @@
1
+ import { useDefaults } from "../runtime.js";
2
+ import { colorClass, cx, sizeClass } from "../classes.js";
3
+ import { useControllable } from "../hooks.js";
4
+ import { floatingMiddleware, useTrigger } from "../floating.js";
5
+ import { createContext, useContext, useRef, useState } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ import { FloatingFocusManager, FloatingList, FloatingPortal, autoUpdate, useClick, useDismiss, useFloating, useInteractions, useListItem, useListNavigation, useRole, useTypeahead } from "@floating-ui/react";
8
+ //#region src/components/Menu.tsx
9
+ var MenuContext = createContext(null);
10
+ function useMenuContext(component) {
11
+ const context = useContext(MenuContext);
12
+ if (!context) throw new Error(`yarcl: <${component}> must be inside <Menu>`);
13
+ return context;
14
+ }
15
+ function useMenuState({ open: openProp, defaultOpen = false, onOpenChange, placement = "bottom-start", size }) {
16
+ const [open, setOpen] = useControllable(openProp, defaultOpen, onOpenChange);
17
+ const [activeIndex, setActiveIndex] = useState(null);
18
+ const elementsRef = useRef([]);
19
+ const labelsRef = useRef([]);
20
+ const floating = useFloating({
21
+ open,
22
+ onOpenChange: setOpen,
23
+ placement,
24
+ transform: false,
25
+ whileElementsMounted: autoUpdate,
26
+ middleware: floatingMiddleware()
27
+ });
28
+ const interactions = useInteractions([
29
+ useClick(floating.context),
30
+ useDismiss(floating.context),
31
+ useRole(floating.context, { role: "menu" }),
32
+ useListNavigation(floating.context, {
33
+ listRef: elementsRef,
34
+ activeIndex,
35
+ onNavigate: setActiveIndex,
36
+ loop: true
37
+ }),
38
+ useTypeahead(floating.context, {
39
+ listRef: labelsRef,
40
+ activeIndex,
41
+ onMatch: open ? setActiveIndex : void 0
42
+ })
43
+ ]);
44
+ return {
45
+ open,
46
+ setOpen,
47
+ activeIndex,
48
+ setActiveIndex,
49
+ elementsRef,
50
+ labelsRef,
51
+ size,
52
+ ...floating,
53
+ ...interactions
54
+ };
55
+ }
56
+ function MenuRoot(props) {
57
+ const state = useMenuState(props);
58
+ return /* @__PURE__ */ jsx(MenuContext.Provider, {
59
+ value: state,
60
+ children: props.children
61
+ });
62
+ }
63
+ function MenuTrigger({ children }) {
64
+ const { refs, getReferenceProps } = useMenuContext("Menu.Trigger");
65
+ return useTrigger(children, refs.setReference, getReferenceProps);
66
+ }
67
+ function MenuContent({ className, style, children, ...props }) {
68
+ const own = useDefaults("Menu");
69
+ const { open, size, refs, floatingStyles, context, getFloatingProps, elementsRef, labelsRef } = useMenuContext("Menu.Content");
70
+ if (!open) return null;
71
+ return /* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(FloatingFocusManager, {
72
+ context,
73
+ modal: false,
74
+ initialFocus: 0,
75
+ children: /* @__PURE__ */ jsx("div", {
76
+ ref: refs.setFloating,
77
+ style: {
78
+ ...floatingStyles,
79
+ ...style
80
+ },
81
+ className: cx("yarcl-floating yarcl-panel yarcl-listbox", sizeClass(size ?? own.size, "Menu"), colorClass(), className),
82
+ ...getFloatingProps(props),
83
+ children: /* @__PURE__ */ jsx(FloatingList, {
84
+ elementsRef,
85
+ labelsRef,
86
+ children
87
+ })
88
+ })
89
+ }) });
90
+ }
91
+ function MenuItem({ onSelect, color, textValue, disabled, className, children, ...props }) {
92
+ const { activeIndex, setOpen, getItemProps } = useMenuContext("Menu.Item");
93
+ const { ref, index } = useListItem({ label: disabled ? null : textValue ?? (typeof children === "string" ? children : null) });
94
+ const active = activeIndex === index;
95
+ return /* @__PURE__ */ jsx("button", {
96
+ ref,
97
+ type: "button",
98
+ role: "menuitem",
99
+ tabIndex: active ? 0 : -1,
100
+ disabled,
101
+ "data-active": active || void 0,
102
+ className: cx("yarcl-option", color && cx("yarcl-option-colored", colorClass(color)), className),
103
+ ...getItemProps({
104
+ ...props,
105
+ onClick() {
106
+ onSelect?.();
107
+ setOpen(false);
108
+ }
109
+ }),
110
+ children
111
+ });
112
+ }
113
+ /** A line between groups of `Menu.Item`s. */
114
+ function MenuSeparator() {
115
+ return /* @__PURE__ */ jsx("div", {
116
+ role: "separator",
117
+ className: "yarcl-listbox-separator"
118
+ });
119
+ }
120
+ /**
121
+ * A list of actions opened from a trigger. Arrow keys move between items,
122
+ * typing jumps to a matching item, Esc closes.
123
+ *
124
+ * @example
125
+ * ```tsx
126
+ * <Menu>
127
+ * <Menu.Trigger><Button variant="outline">Actions</Button></Menu.Trigger>
128
+ * <Menu.Content>
129
+ * <Menu.Item onSelect={rename}>Rename</Menu.Item>
130
+ * <Menu.Separator />
131
+ * <Menu.Item color="danger" onSelect={remove}>Delete</Menu.Item>
132
+ * </Menu.Content>
133
+ * </Menu>
134
+ * ```
135
+ */
136
+ var Menu = Object.assign(MenuRoot, {
137
+ Trigger: MenuTrigger,
138
+ Content: MenuContent,
139
+ Item: MenuItem,
140
+ Separator: MenuSeparator
141
+ });
142
+ //#endregion
143
+ export { Menu };
@@ -0,0 +1,45 @@
1
+ import { type MouseEvent, type ReactElement, type ReactNode, type SyntheticEvent } from 'react';
2
+ import type { ModalSize, Radius } from '../types';
3
+ /** Props shared by {@link Dialog} and {@link Drawer}. */
4
+ export interface ModalProps {
5
+ /** Heading of the dialog. Also its accessible name. */
6
+ title: ReactNode;
7
+ /** Supporting text below the title. Also its accessible description. */
8
+ description?: ReactNode;
9
+ /** Body content. Scrolls when it doesn't fit. */
10
+ children?: ReactNode;
11
+ /** Actions shown at the bottom, e.g. Cancel and Confirm buttons. */
12
+ footer?: ReactNode;
13
+ /** An element that opens the dialog when clicked, e.g. a {@link Button}. Optional when controlled. */
14
+ trigger?: ReactElement<{
15
+ onClick?: (event: MouseEvent) => void;
16
+ }>;
17
+ /** Controlled open state. */
18
+ open?: boolean;
19
+ /**
20
+ * Initial open state when uncontrolled.
21
+ * @default false
22
+ */
23
+ defaultOpen?: boolean;
24
+ /** Called when the dialog opens or closes, including by Esc, the close button or a backdrop click. */
25
+ onOpenChange?: (open: boolean) => void;
26
+ /**
27
+ * Closes when the backdrop is clicked.
28
+ * @default true
29
+ */
30
+ closeOnBackdrop?: boolean;
31
+ /**
32
+ * Width, from the `modalSizes` config. Height follows the content, up to the viewport.
33
+ * @default config.defaults.modalSize (Drawer: its component default, `sm` in the library defaults)
34
+ */
35
+ size?: ModalSize;
36
+ }
37
+ export declare function useModalDialog(open: boolean, setOpen: (open: boolean) => void, closeOnBackdrop?: boolean): {
38
+ ref: import("react").RefObject<HTMLDialogElement | null>;
39
+ onClose(event: SyntheticEvent<HTMLDialogElement>): void;
40
+ onClick(event: MouseEvent<HTMLDialogElement>): void;
41
+ };
42
+ export declare function Modal({ title, description, children, footer, trigger, open: openProp, defaultOpen, onOpenChange, closeOnBackdrop, size, className, radius, }: ModalProps & {
43
+ className: string;
44
+ radius?: Radius;
45
+ }): import("react").JSX.Element;
@@ -0,0 +1,110 @@
1
+ import { useConfig } from "../runtime.js";
2
+ import { cx, radiusClass, typeClass } from "../classes.js";
3
+ import { useControllable } from "../hooks.js";
4
+ import { cloneElement, useEffect, useId, useRef } from "react";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/Modal.tsx
7
+ var openModals = [];
8
+ function syncBackdrops() {
9
+ openModals.forEach((dialog, i) => dialog.toggleAttribute("data-yarcl-covered", i < openModals.length - 1));
10
+ }
11
+ function removeOpenModal(dialog) {
12
+ const index = openModals.indexOf(dialog);
13
+ if (index === -1) return;
14
+ openModals.splice(index, 1);
15
+ dialog.removeAttribute("data-yarcl-covered");
16
+ syncBackdrops();
17
+ }
18
+ function CloseIcon() {
19
+ return /* @__PURE__ */ jsx("svg", {
20
+ viewBox: "0 0 24 24",
21
+ fill: "none",
22
+ stroke: "currentColor",
23
+ strokeWidth: "2",
24
+ strokeLinecap: "round",
25
+ "aria-hidden": "true",
26
+ children: /* @__PURE__ */ jsx("path", { d: "M6 6l12 12M18 6 6 18" })
27
+ });
28
+ }
29
+ function useModalDialog(open, setOpen, closeOnBackdrop = true) {
30
+ const ref = useRef(null);
31
+ useEffect(() => {
32
+ const dialog = ref.current;
33
+ if (!dialog) return;
34
+ if (open && !dialog.open) {
35
+ dialog.showModal();
36
+ openModals.push(dialog);
37
+ syncBackdrops();
38
+ } else if (!open) {
39
+ if (dialog.open) dialog.close();
40
+ removeOpenModal(dialog);
41
+ }
42
+ }, [open]);
43
+ useEffect(() => {
44
+ const dialog = ref.current;
45
+ return () => {
46
+ if (dialog) removeOpenModal(dialog);
47
+ };
48
+ }, []);
49
+ return {
50
+ ref,
51
+ onClose(event) {
52
+ if (event.target === event.currentTarget && open) setOpen(false);
53
+ },
54
+ onClick(event) {
55
+ if (closeOnBackdrop && event.target === event.currentTarget) setOpen(false);
56
+ }
57
+ };
58
+ }
59
+ function Modal({ title, description, children, footer, trigger, open: openProp, defaultOpen = false, onOpenChange, closeOnBackdrop = true, size, className, radius }) {
60
+ const config = useConfig();
61
+ const [open, setOpen] = useControllable(openProp, defaultOpen, onOpenChange);
62
+ const dialogProps = useModalDialog(open, setOpen, closeOnBackdrop);
63
+ const titleId = useId();
64
+ const descriptionId = useId();
65
+ return /* @__PURE__ */ jsxs(Fragment, { children: [trigger && cloneElement(trigger, { onClick(event) {
66
+ trigger.props.onClick?.(event);
67
+ setOpen(true);
68
+ } }), /* @__PURE__ */ jsx("dialog", {
69
+ ...dialogProps,
70
+ className: cx("yarcl-modal", `yarcl-modal-size-${size ?? config.defaults.modalSize}`, radiusClass(radius), className),
71
+ "aria-labelledby": titleId,
72
+ "aria-describedby": description != null ? descriptionId : void 0,
73
+ children: open && /* @__PURE__ */ jsxs("div", {
74
+ className: "yarcl-modal-content",
75
+ children: [
76
+ /* @__PURE__ */ jsxs("div", {
77
+ className: "yarcl-modal-header",
78
+ children: [/* @__PURE__ */ jsxs("div", {
79
+ className: "yarcl-modal-heading",
80
+ children: [/* @__PURE__ */ jsx("h2", {
81
+ id: titleId,
82
+ className: cx("yarcl-modal-title", typeClass(config.typography.headings.h2)),
83
+ children: title
84
+ }), description != null && /* @__PURE__ */ jsx("p", {
85
+ id: descriptionId,
86
+ className: "yarcl-modal-description",
87
+ children: description
88
+ })]
89
+ }), /* @__PURE__ */ jsx("button", {
90
+ type: "button",
91
+ className: "yarcl-modal-close",
92
+ "aria-label": "Close",
93
+ onClick: () => setOpen(false),
94
+ children: /* @__PURE__ */ jsx(CloseIcon, {})
95
+ })]
96
+ }),
97
+ children != null && /* @__PURE__ */ jsx("div", {
98
+ className: "yarcl-modal-body",
99
+ children
100
+ }),
101
+ footer != null && /* @__PURE__ */ jsx("div", {
102
+ className: "yarcl-modal-footer",
103
+ children: footer
104
+ })
105
+ ]
106
+ })
107
+ })] });
108
+ }
109
+ //#endregion
110
+ export { Modal, useModalDialog };
@@ -0,0 +1,49 @@
1
+ import { type ComponentProps } from 'react';
2
+ import type { TokenProps } from '../types';
3
+ /**
4
+ * Props for {@link NumberInput}. Native `<input>` attributes go to the inner input;
5
+ * `className` and `style` go to the outer box.
6
+ */
7
+ export interface NumberInputProps extends TokenProps<'NumberInput'>, Omit<ComponentProps<'input'>, 'color' | 'size' | 'type' | 'value' | 'defaultValue' | 'onChange' | 'min' | 'max' | 'step'> {
8
+ /** Controlled value. `null` means the input is empty. */
9
+ value?: number | null;
10
+ /**
11
+ * Initial value when uncontrolled.
12
+ * @default null
13
+ */
14
+ defaultValue?: number | null;
15
+ /** Called with the new value after a step, or when typed text is committed on blur or Enter. */
16
+ onValueChange?: (value: number | null) => void;
17
+ /** Lowest allowed value. Typed values are clamped to it, and `Home` jumps to it. */
18
+ min?: number;
19
+ /** Highest allowed value. Typed values are clamped to it, and `End` jumps to it. */
20
+ max?: number;
21
+ /**
22
+ * Amount added or removed by the stepper buttons and the arrow keys. `PageUp` and `PageDown` step ten times as far.
23
+ * @default 1
24
+ */
25
+ step?: number;
26
+ /**
27
+ * Accessible label of the increment button.
28
+ * @default 'Increase'
29
+ */
30
+ incrementLabel?: string;
31
+ /**
32
+ * Accessible label of the decrement button.
33
+ * @default 'Decrease'
34
+ */
35
+ decrementLabel?: string;
36
+ }
37
+ /**
38
+ * A numeric input with increment and decrement buttons, exposed as a `spinbutton`.
39
+ * Arrow keys step by `step`, `PageUp` and `PageDown` by ten steps, `Home` and `End` jump to `min` and `max`.
40
+ * Shares the base size scale with {@link Input}; component size overrides can adjust either one. Works inside a {@link Field}.
41
+ *
42
+ * @example
43
+ * ```tsx
44
+ * <Field label="Guests">
45
+ * <NumberInput min={1} max={10} defaultValue={2} onValueChange={setGuests} />
46
+ * </Field>
47
+ * ```
48
+ */
49
+ export declare function NumberInput(props: NumberInputProps): import("react").JSX.Element;