@blockle/blocks-react 3.1.0 → 3.3.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 (135) hide show
  1. package/dist/components/display/Divider/divider.css.js +3 -3
  2. package/dist/components/display/Tag/Tag.d.ts +28 -0
  3. package/dist/components/display/Tag/Tag.d.ts.map +1 -0
  4. package/dist/components/display/Tag/Tag.js +46 -0
  5. package/dist/components/feedback/Alert/Alert.d.ts +15 -6
  6. package/dist/components/feedback/Alert/Alert.d.ts.map +1 -1
  7. package/dist/components/feedback/Alert/Alert.js +8 -37
  8. package/dist/components/feedback/Toast/ToastContext.d.ts +6 -0
  9. package/dist/components/feedback/Toast/ToastContext.d.ts.map +1 -1
  10. package/dist/components/feedback/Toast/ToastProvider.d.ts +6 -0
  11. package/dist/components/feedback/Toast/ToastProvider.d.ts.map +1 -1
  12. package/dist/components/feedback/Toast/ToastProvider.js +90 -29
  13. package/dist/components/feedback/Toast/useCountdowns.d.ts +14 -0
  14. package/dist/components/feedback/Toast/useCountdowns.d.ts.map +1 -0
  15. package/dist/components/feedback/Toast/useCountdowns.js +74 -0
  16. package/dist/components/form/Button/Button.d.ts +11 -3
  17. package/dist/components/form/Button/Button.d.ts.map +1 -1
  18. package/dist/components/form/Checkbox/Checkbox.d.ts.map +1 -1
  19. package/dist/components/form/Checkbox/Checkbox.js +7 -25
  20. package/dist/components/form/IconButton/IconButton.d.ts +29 -0
  21. package/dist/components/form/IconButton/IconButton.d.ts.map +1 -0
  22. package/dist/components/form/IconButton/IconButton.js +61 -0
  23. package/dist/components/form/Label/Label.d.ts +1 -1
  24. package/dist/components/form/Label/Label.d.ts.map +1 -1
  25. package/dist/components/form/NumericInput/NumericInput.d.ts +11 -1
  26. package/dist/components/form/NumericInput/NumericInput.d.ts.map +1 -1
  27. package/dist/components/form/NumericInput/NumericInput.js +52 -24
  28. package/dist/components/form/Select/Select.d.ts.map +1 -1
  29. package/dist/components/form/Select/Select.js +2 -23
  30. package/dist/components/form/Select/select.css.js +1 -1
  31. package/dist/components/form/Textarea/Textarea.css.d.ts +2 -0
  32. package/dist/components/form/Textarea/Textarea.css.d.ts.map +1 -1
  33. package/dist/components/form/Textarea/Textarea.css.js +17 -1
  34. package/dist/components/form/Textarea/Textarea.d.ts +11 -0
  35. package/dist/components/form/Textarea/Textarea.d.ts.map +1 -1
  36. package/dist/components/form/Textarea/Textarea.js +8 -2
  37. package/dist/components/layout/Inline/Inline.d.ts +11 -3
  38. package/dist/components/layout/Inline/Inline.d.ts.map +1 -1
  39. package/dist/components/layout/Inline/Inline.js +5 -3
  40. package/dist/components/layout/Stack/Stack.d.ts +12 -8
  41. package/dist/components/layout/Stack/Stack.d.ts.map +1 -1
  42. package/dist/components/layout/Stack/Stack.js +8 -4
  43. package/dist/components/navigation/Link/Link.d.ts +1 -1
  44. package/dist/components/navigation/Link/Link.d.ts.map +1 -1
  45. package/dist/components/navigation/Link/Link.js +2 -2
  46. package/dist/components/navigation/Tabs/Tab.d.ts +21 -0
  47. package/dist/components/navigation/Tabs/Tab.d.ts.map +1 -0
  48. package/dist/components/navigation/Tabs/Tab.js +138 -0
  49. package/dist/components/navigation/Tabs/TabIndicator.d.ts +6 -0
  50. package/dist/components/navigation/Tabs/TabIndicator.d.ts.map +1 -0
  51. package/dist/components/navigation/Tabs/TabIndicator.js +19 -0
  52. package/dist/components/navigation/Tabs/TabList.d.ts +10 -0
  53. package/dist/components/navigation/Tabs/TabList.d.ts.map +1 -0
  54. package/dist/components/navigation/Tabs/TabList.js +101 -0
  55. package/dist/components/navigation/Tabs/TabListContext.d.ts +13 -0
  56. package/dist/components/navigation/Tabs/TabListContext.d.ts.map +1 -0
  57. package/dist/components/navigation/Tabs/TabListContext.js +6 -0
  58. package/dist/components/navigation/Tabs/TabNav.d.ts +15 -0
  59. package/dist/components/navigation/Tabs/TabNav.d.ts.map +1 -0
  60. package/dist/components/navigation/Tabs/TabNav.js +44 -0
  61. package/dist/components/navigation/Tabs/TabPanel.d.ts +14 -0
  62. package/dist/components/navigation/Tabs/TabPanel.d.ts.map +1 -0
  63. package/dist/components/navigation/Tabs/TabPanel.js +31 -0
  64. package/dist/components/navigation/Tabs/Tabs.d.ts +13 -0
  65. package/dist/components/navigation/Tabs/Tabs.d.ts.map +1 -0
  66. package/dist/components/navigation/Tabs/Tabs.js +33 -0
  67. package/dist/components/navigation/Tabs/TabsContext.d.ts +13 -0
  68. package/dist/components/navigation/Tabs/TabsContext.d.ts.map +1 -0
  69. package/dist/components/navigation/Tabs/TabsContext.js +27 -0
  70. package/dist/components/navigation/Tabs/tabs.css.d.ts +7 -0
  71. package/dist/components/navigation/Tabs/tabs.css.d.ts.map +1 -0
  72. package/dist/components/navigation/Tabs/tabs.css.js +122 -0
  73. package/dist/components/overlay/Dialog/Dialog.d.ts +1 -1
  74. package/dist/components/overlay/Dialog/Dialog.d.ts.map +1 -1
  75. package/dist/components/overlay/Dialog/Dialog.js +9 -7
  76. package/dist/components/overlay/Drawer/Drawer.d.ts +1 -1
  77. package/dist/components/overlay/Drawer/Drawer.d.ts.map +1 -1
  78. package/dist/components/overlay/Drawer/Drawer.js +9 -7
  79. package/dist/components/overlay/Menu/Menu.d.ts +52 -0
  80. package/dist/components/overlay/Menu/Menu.d.ts.map +1 -0
  81. package/dist/components/overlay/Menu/Menu.js +273 -0
  82. package/dist/components/overlay/Menu/menu-utils.d.ts +33 -0
  83. package/dist/components/overlay/Menu/menu-utils.d.ts.map +1 -0
  84. package/dist/components/overlay/Menu/menu-utils.js +54 -0
  85. package/dist/components/overlay/Popover/Popover.d.ts +9 -0
  86. package/dist/components/overlay/Popover/Popover.d.ts.map +1 -1
  87. package/dist/components/overlay/Popover/Popover.js +70 -31
  88. package/dist/components/overlay/Popover/popover-utils.d.ts +32 -1
  89. package/dist/components/overlay/Popover/popover-utils.d.ts.map +1 -1
  90. package/dist/components/overlay/Popover/popover-utils.js +77 -22
  91. package/dist/components/overlay/modalOverlayStack.d.ts +8 -0
  92. package/dist/components/overlay/modalOverlayStack.d.ts.map +1 -0
  93. package/dist/components/overlay/modalOverlayStack.js +37 -0
  94. package/dist/components/overlay/useModalOverlay.d.ts +6 -14
  95. package/dist/components/overlay/useModalOverlay.d.ts.map +1 -1
  96. package/dist/components/overlay/useModalOverlay.js +8 -31
  97. package/dist/components/typography/Heading/Heading.d.ts +2 -1
  98. package/dist/components/typography/Heading/Heading.d.ts.map +1 -1
  99. package/dist/components/typography/Heading/Heading.js +9 -1
  100. package/dist/components/typography/Text/Text.d.ts +3 -2
  101. package/dist/components/typography/Text/Text.d.ts.map +1 -1
  102. package/dist/components/typography/Text/Text.js +9 -1
  103. package/dist/components/typography/textOverflow.css.d.ts +3 -0
  104. package/dist/components/typography/textOverflow.css.d.ts.map +1 -0
  105. package/dist/components/typography/textOverflow.css.js +32 -0
  106. package/dist/components/typography/textOverflow.d.ts +9 -0
  107. package/dist/components/typography/textOverflow.d.ts.map +1 -0
  108. package/dist/components/typography/textOverflow.js +10 -0
  109. package/dist/hooks/useModalDialog/useModalDialog.d.ts +5 -0
  110. package/dist/hooks/useModalDialog/useModalDialog.d.ts.map +1 -1
  111. package/dist/hooks/useModalDialog/useModalDialog.js +3 -2
  112. package/dist/hooks/usePreventBodyScroll/usePreventBodyScroll.d.ts +5 -0
  113. package/dist/hooks/usePreventBodyScroll/usePreventBodyScroll.d.ts.map +1 -1
  114. package/dist/hooks/usePreventBodyScroll/usePreventBodyScroll.js +31 -16
  115. package/dist/icons/icons.d.ts +8 -0
  116. package/dist/icons/icons.d.ts.map +1 -0
  117. package/dist/icons/icons.js +39 -0
  118. package/dist/index.d.ts +8 -0
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +16 -0
  121. package/dist/testUtils/browser/consumerStyles.css.d.ts +2 -0
  122. package/dist/testUtils/browser/consumerStyles.css.d.ts.map +1 -0
  123. package/dist/testUtils/browser/contrast.d.ts +6 -2
  124. package/dist/testUtils/browser/contrast.d.ts.map +1 -1
  125. package/dist/testUtils/browser/emulateNoAnchorPositioning.d.ts +8 -0
  126. package/dist/testUtils/browser/emulateNoAnchorPositioning.d.ts.map +1 -0
  127. package/dist/testUtils/browser/render.d.ts +6 -2
  128. package/dist/testUtils/browser/render.d.ts.map +1 -1
  129. package/dist/testUtils/browser/screenshot.d.ts +2 -0
  130. package/dist/testUtils/browser/screenshot.d.ts.map +1 -0
  131. package/dist/testUtils/testTheme.css.d.ts.map +1 -1
  132. package/package.json +2 -2
  133. package/dist/components/feedback/Alert/Alert.css.d.ts +0 -2
  134. package/dist/components/feedback/Alert/Alert.css.d.ts.map +0 -1
  135. package/dist/components/feedback/Alert/Alert.css.js +0 -15
@@ -9,7 +9,7 @@ export type DialogProps = {
9
9
  className?: string;
10
10
  size?: DialogTheme['variants']['size'];
11
11
  'aria-label'?: string;
12
- } & HTMLElementProps<HTMLDialogElement>;
12
+ } & Omit<HTMLElementProps<HTMLDialogElement>, 'size'>;
13
13
  export declare const Dialog: React.FC<DialogProps>;
14
14
  export {};
15
15
  //# sourceMappingURL=Dialog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Dialog/Dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,eAAe,EAGpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAInE,KAAK,WAAW,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACrD,kFAAkF;IAClF,QAAQ,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;AAExC,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAkDxC,CAAC"}
1
+ {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Dialog/Dialog.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,eAAe,EAGpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAInE,KAAK,WAAW,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACrD,kFAAkF;IAClF,QAAQ,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;AAEtD,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAgDxC,CAAC"}
@@ -4,7 +4,7 @@ import { classnames, composeRefs } from "@blockle/blocks-core";
4
4
  import { useRef } from "react";
5
5
  import { useComponentStyles } from "../../../hooks/useComponentStyles/useComponentStyles.js";
6
6
  import { useModalDialog } from "../../../hooks/useModalDialog/useModalDialog.js";
7
- import { useModalOverlay, DialogContext } from "../useModalOverlay.js";
7
+ import { useModalOverlay } from "../useModalOverlay.js";
8
8
  import { dialog } from "./dialog.css.js";
9
9
  const Dialog = ({
10
10
  children,
@@ -23,23 +23,25 @@ const Dialog = ({
23
23
  dialog: true,
24
24
  variants: { size }
25
25
  });
26
- const { contextValue, closeRequestProps } = useModalOverlay(dialogRef, {
26
+ const closeRequestProps = useModalOverlay(dialogRef, {
27
27
  open,
28
28
  onRequestClose,
29
29
  onKeyDown,
30
30
  onKeyDownCapture,
31
31
  onCancel
32
32
  });
33
- const { visible, onAnimationEnd } = useModalDialog(dialogRef, open);
33
+ const { visible, onAnimationEnd, openAttribute } = useModalDialog(
34
+ dialogRef,
35
+ open
36
+ );
34
37
  if (!visible) {
35
38
  return null;
36
39
  }
37
- const dataOpen = typeof window === "undefined" && open ? true : void 0;
38
- return /* @__PURE__ */ jsx(DialogContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
40
+ return /* @__PURE__ */ jsx(
39
41
  "dialog",
40
42
  {
41
43
  ref: composeRefs(ref, dialogRef),
42
- open: dataOpen,
44
+ open: openAttribute,
43
45
  className: classnames(dialog, dialogClassName, className),
44
46
  onAnimationEnd,
45
47
  onTransitionEnd: onAnimationEnd,
@@ -47,7 +49,7 @@ const Dialog = ({
47
49
  ...closeRequestProps,
48
50
  children
49
51
  }
50
- ) });
52
+ );
51
53
  };
52
54
  export {
53
55
  Dialog
@@ -10,7 +10,7 @@ export type DrawerProps = {
10
10
  className?: string;
11
11
  placement?: keyof typeof styles.placement;
12
12
  size?: DrawerTheme['variants']['size'];
13
- } & HTMLElementProps<HTMLDialogElement>;
13
+ } & Omit<HTMLElementProps<HTMLDialogElement>, 'size'>;
14
14
  export declare const Drawer: React.FC<DrawerProps>;
15
15
  export {};
16
16
  //# sourceMappingURL=Drawer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Drawer.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Drawer/Drawer.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,eAAe,EAGpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAC;AAE1C,KAAK,WAAW,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACrD,kFAAkF;IAClF,QAAQ,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,OAAO,MAAM,CAAC,SAAS,CAAC;IAC1C,IAAI,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;CACxC,GAAG,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;AAExC,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAyDxC,CAAC"}
1
+ {"version":3,"file":"Drawer.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Drawer/Drawer.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,eAAe,EAGpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAC;AAE1C,KAAK,WAAW,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACrD,kFAAkF;IAClF,QAAQ,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,OAAO,MAAM,CAAC,SAAS,CAAC;IAC1C,IAAI,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;CACxC,GAAG,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;AAEtD,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAuDxC,CAAC"}
@@ -4,7 +4,7 @@ import { classnames, composeRefs } from "@blockle/blocks-core";
4
4
  import { useRef } from "react";
5
5
  import { useComponentStyles } from "../../../hooks/useComponentStyles/useComponentStyles.js";
6
6
  import { useModalDialog } from "../../../hooks/useModalDialog/useModalDialog.js";
7
- import { useModalOverlay, DialogContext } from "../useModalOverlay.js";
7
+ import { useModalOverlay } from "../useModalOverlay.js";
8
8
  import { drawer, placement } from "./drawer.css.js";
9
9
  const Drawer = ({
10
10
  open,
@@ -24,23 +24,25 @@ const Drawer = ({
24
24
  root: true,
25
25
  variants: { placement: placement$1, size }
26
26
  });
27
- const dataOpen = typeof window === "undefined" && open ? true : void 0;
28
- const { contextValue, closeRequestProps } = useModalOverlay(dialogRef, {
27
+ const closeRequestProps = useModalOverlay(dialogRef, {
29
28
  open,
30
29
  onRequestClose,
31
30
  onKeyDown,
32
31
  onKeyDownCapture,
33
32
  onCancel
34
33
  });
35
- const { visible, onAnimationEnd } = useModalDialog(dialogRef, open);
34
+ const { visible, onAnimationEnd, openAttribute } = useModalDialog(
35
+ dialogRef,
36
+ open
37
+ );
36
38
  if (!visible) {
37
39
  return null;
38
40
  }
39
- return /* @__PURE__ */ jsx(DialogContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
41
+ return /* @__PURE__ */ jsx(
40
42
  "dialog",
41
43
  {
42
44
  ref: composeRefs(ref, dialogRef),
43
- open: dataOpen,
45
+ open: openAttribute,
44
46
  className: classnames(
45
47
  drawer,
46
48
  placement[placement$1],
@@ -53,7 +55,7 @@ const Drawer = ({
53
55
  ...closeRequestProps,
54
56
  children
55
57
  }
56
- ) });
58
+ );
57
59
  };
58
60
  export {
59
61
  Drawer
@@ -0,0 +1,52 @@
1
+ import { HTMLElementProps } from '@blockle/blocks-core';
2
+ import { PopoverProps } from '../Popover/Popover.js';
3
+ type ReactElement = React.ReactElement<any, string | React.JSXElementConstructor<any>>;
4
+ export type MenuActionItem = {
5
+ type?: undefined;
6
+ label: React.ReactNode;
7
+ /**
8
+ * Text for typeahead, when `label` is not a plain string
9
+ */
10
+ textValue?: string;
11
+ onSelect: () => void;
12
+ disabled?: boolean;
13
+ startSlot?: React.ReactNode;
14
+ endSlot?: React.ReactNode;
15
+ };
16
+ export type MenuSeparatorItem = {
17
+ type: 'separator';
18
+ };
19
+ export type MenuRadioItem = {
20
+ value: string;
21
+ label: React.ReactNode;
22
+ /**
23
+ * Text for typeahead, when `label` is not a plain string
24
+ */
25
+ textValue?: string;
26
+ disabled?: boolean;
27
+ endSlot?: React.ReactNode;
28
+ };
29
+ export type MenuRadioGroupItem = {
30
+ type: 'radio-group';
31
+ value: string;
32
+ onChange: (value: string) => void;
33
+ items: MenuRadioItem[];
34
+ };
35
+ export type MenuItem = MenuActionItem | MenuSeparatorItem | MenuRadioGroupItem;
36
+ export type MenuProps = {
37
+ /**
38
+ * The trigger, usually a `Button` or `IconButton`
39
+ */
40
+ children: ReactElement;
41
+ items: MenuItem[];
42
+ open?: boolean;
43
+ onOpenChange?: (open: boolean) => void;
44
+ /**
45
+ * Side of the trigger to open on, and which of its edges to line up with
46
+ * @default 'bottom-start'
47
+ */
48
+ placement?: PopoverProps['placement'];
49
+ } & Omit<HTMLElementProps<HTMLDivElement>, 'ref' | 'children'>;
50
+ export declare const Menu: React.FC<MenuProps>;
51
+ export {};
52
+ //# sourceMappingURL=Menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Menu.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Menu/Menu.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAc9B,OAAO,EAAW,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAenE,KAAK,YAAY,GAAG,KAAK,CAAC,YAAY,CAEpC,GAAG,EAEH,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAC1C,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAE/E,MAAM,MAAM,SAAS,GAAG;IACtB;;OAEG;IACH,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC;;;OAGG;IACH,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACvC,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC,CAAC;AAU/D,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,SAAS,CAyLpC,CAAC"}
@@ -0,0 +1,273 @@
1
+ "use client";
2
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
3
+ import { composeRefs, classnames } from "@blockle/blocks-core";
4
+ import { Children, useId, useRef, useState, useEffect, isValidElement, cloneElement, Fragment as Fragment$1 } from "react";
5
+ import { useComponentStyles } from "../../../hooks/useComponentStyles/useComponentStyles.js";
6
+ import { CheckIcon } from "../../../icons/icons.js";
7
+ import { Popover } from "../Popover/Popover.js";
8
+ import { isMenuNavigationKey, isTypeaheadKey, getEnabledItems, getNextIndex, getTypeaheadMatch, getItemText, getTextValue } from "./menu-utils.js";
9
+ const TYPEAHEAD_RESET_MS = 500;
10
+ function focusItem(list, which) {
11
+ const items = getEnabledItems(list);
12
+ items.at(which === "first" ? 0 : -1)?.focus();
13
+ }
14
+ const Menu = ({
15
+ children,
16
+ items,
17
+ open: openProp,
18
+ onOpenChange,
19
+ placement = "bottom-start",
20
+ className,
21
+ ...restProps
22
+ }) => {
23
+ if (Children.count(children) !== 1) {
24
+ throw new Error("Menu component can only have one child");
25
+ }
26
+ const listId = useId();
27
+ const generatedTriggerId = useId();
28
+ const triggerRef = useRef(null);
29
+ const listRef = useRef(null);
30
+ const searchRef = useRef("");
31
+ const searchTimeoutRef = useRef(void 0);
32
+ const initialFocus = useRef("first");
33
+ const [internalOpen, setInternalOpen] = useState(false);
34
+ const isControlled = openProp !== void 0;
35
+ const open = (isControlled ? openProp : internalOpen) && items.length > 0;
36
+ const listClassName = useComponentStyles("menu", { list: true }, false);
37
+ const setOpen = (next) => {
38
+ if (!isControlled) {
39
+ setInternalOpen(next);
40
+ }
41
+ onOpenChange?.(next);
42
+ };
43
+ const openAndFocus = (which) => {
44
+ if (items.length === 0) {
45
+ return;
46
+ }
47
+ initialFocus.current = which;
48
+ setOpen(true);
49
+ };
50
+ const closeMenu = () => {
51
+ setOpen(false);
52
+ };
53
+ const closeAndFocusTrigger = () => {
54
+ setOpen(false);
55
+ triggerRef.current?.focus();
56
+ };
57
+ const onRequestClose = (reason) => {
58
+ if (reason === "escape") {
59
+ closeAndFocusTrigger();
60
+ } else {
61
+ closeMenu();
62
+ }
63
+ };
64
+ useEffect(() => {
65
+ return () => window.clearTimeout(searchTimeoutRef.current);
66
+ }, []);
67
+ const child = Children.toArray(children)[0];
68
+ if (!isValidElement(child)) {
69
+ return null;
70
+ }
71
+ const trigger = child;
72
+ const triggerId = trigger.props.id ?? generatedTriggerId;
73
+ const onTriggerClick = (event) => {
74
+ trigger.props.onClick?.(event);
75
+ if (event.defaultPrevented) {
76
+ return;
77
+ }
78
+ if (!open) {
79
+ openAndFocus("first");
80
+ }
81
+ };
82
+ const onTriggerKeyDown = (event) => {
83
+ trigger.props.onKeyDown?.(event);
84
+ if (event.defaultPrevented || open) {
85
+ return;
86
+ }
87
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
88
+ event.preventDefault();
89
+ openAndFocus(event.key === "ArrowDown" ? "first" : "last");
90
+ }
91
+ };
92
+ const onListKeyDown = (event) => {
93
+ if (event.key === "Tab") {
94
+ closeAndFocusTrigger();
95
+ return;
96
+ }
97
+ const navigationKey = isMenuNavigationKey(event.key) ? event.key : null;
98
+ if (!navigationKey && !isTypeaheadKey(event)) {
99
+ return;
100
+ }
101
+ const enabled = getEnabledItems(listRef.current);
102
+ const current = enabled.indexOf(document.activeElement);
103
+ if (navigationKey) {
104
+ if (enabled.length === 0) {
105
+ return;
106
+ }
107
+ event.preventDefault();
108
+ enabled[getNextIndex(navigationKey, current, enabled.length)]?.focus();
109
+ return;
110
+ }
111
+ if (event.key === " " && searchRef.current === "") {
112
+ return;
113
+ }
114
+ event.preventDefault();
115
+ window.clearTimeout(searchTimeoutRef.current);
116
+ searchRef.current += event.key;
117
+ searchTimeoutRef.current = window.setTimeout(() => {
118
+ searchRef.current = "";
119
+ }, TYPEAHEAD_RESET_MS);
120
+ enabled[getTypeaheadMatch(enabled.map(getItemText), current, searchRef.current)]?.focus();
121
+ };
122
+ const onPick = (select) => {
123
+ select();
124
+ closeAndFocusTrigger();
125
+ };
126
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
127
+ cloneElement(trigger, {
128
+ ref: composeRefs(triggerRef, trigger.props.ref),
129
+ id: triggerId,
130
+ "aria-haspopup": "menu",
131
+ "aria-expanded": open,
132
+ "aria-controls": open ? listId : void 0,
133
+ onClick: onTriggerClick,
134
+ onKeyDown: onTriggerKeyDown
135
+ }),
136
+ /* @__PURE__ */ jsx(
137
+ Popover,
138
+ {
139
+ ...restProps,
140
+ ref: listRef,
141
+ id: listId,
142
+ role: "menu",
143
+ "aria-labelledby": triggerId,
144
+ anchorElement: triggerRef,
145
+ open,
146
+ onRequestClose,
147
+ placement,
148
+ limitHeight: true,
149
+ className: classnames(listClassName, className),
150
+ onKeyDown: onListKeyDown,
151
+ children: /* @__PURE__ */ jsx(
152
+ MenuItems,
153
+ {
154
+ items,
155
+ listRef,
156
+ initialFocus: initialFocus.current,
157
+ onPick
158
+ }
159
+ )
160
+ }
161
+ )
162
+ ] });
163
+ };
164
+ const MenuItems = ({
165
+ items,
166
+ listRef,
167
+ initialFocus,
168
+ onPick
169
+ }) => {
170
+ const separatorClassName = useComponentStyles(
171
+ "menu",
172
+ { separator: true },
173
+ false
174
+ );
175
+ useEffect(() => {
176
+ focusItem(listRef.current, initialFocus);
177
+ }, []);
178
+ return items.map((item, index) => {
179
+ if (item.type === "separator") {
180
+ return /* @__PURE__ */ jsx(
181
+ "hr",
182
+ {
183
+ className: separatorClassName
184
+ },
185
+ index
186
+ );
187
+ }
188
+ if (item.type === "radio-group") {
189
+ return (
190
+ // biome-ignore lint/suspicious/noArrayIndexKey: items have no id
191
+ /* @__PURE__ */ jsx(Fragment$1, { children: item.items.map((radio) => /* @__PURE__ */ jsx(
192
+ MenuRadio,
193
+ {
194
+ item: radio,
195
+ checked: radio.value === item.value,
196
+ onActivate: () => onPick(() => item.onChange(radio.value))
197
+ },
198
+ radio.value
199
+ )) }, index)
200
+ );
201
+ }
202
+ return /* @__PURE__ */ jsxs(
203
+ MenuItemButton,
204
+ {
205
+ role: "menuitem",
206
+ item,
207
+ onActivate: () => onPick(item.onSelect),
208
+ children: [
209
+ item.startSlot,
210
+ item.label,
211
+ item.endSlot
212
+ ]
213
+ },
214
+ index
215
+ );
216
+ });
217
+ };
218
+ const MenuItemButton = ({
219
+ role,
220
+ item,
221
+ onActivate,
222
+ children,
223
+ ...ariaProps
224
+ }) => {
225
+ const className = useComponentStyles("menu", { item: true }, false);
226
+ return /* @__PURE__ */ jsx(
227
+ "button",
228
+ {
229
+ type: "button",
230
+ role,
231
+ tabIndex: -1,
232
+ "aria-disabled": item.disabled || void 0,
233
+ "data-text-value": getTextValue(item),
234
+ ...ariaProps,
235
+ className,
236
+ onClick: () => {
237
+ if (!item.disabled) {
238
+ onActivate();
239
+ }
240
+ },
241
+ onPointerMove: (event) => {
242
+ if (!item.disabled) {
243
+ event.currentTarget.focus();
244
+ }
245
+ },
246
+ children
247
+ }
248
+ );
249
+ };
250
+ const MenuRadio = ({ item, checked, onActivate }) => {
251
+ const indicatorClassName = useComponentStyles(
252
+ "menu",
253
+ { itemIndicator: true },
254
+ false
255
+ );
256
+ return /* @__PURE__ */ jsxs(
257
+ MenuItemButton,
258
+ {
259
+ role: "menuitemradio",
260
+ "aria-checked": checked,
261
+ item,
262
+ onActivate,
263
+ children: [
264
+ /* @__PURE__ */ jsx("span", { className: indicatorClassName, "data-radio-indicator": "", children: checked && /* @__PURE__ */ jsx(CheckIcon, {}) }),
265
+ item.label,
266
+ item.endSlot
267
+ ]
268
+ }
269
+ );
270
+ };
271
+ export {
272
+ Menu
273
+ };
@@ -0,0 +1,33 @@
1
+ export declare function getEnabledItems(list: HTMLElement | null): HTMLElement[];
2
+ type MenuNavigationKey = 'ArrowDown' | 'ArrowUp' | 'Home' | 'End';
3
+ export declare function isMenuNavigationKey(key: string): key is MenuNavigationKey;
4
+ /**
5
+ * Returns the index to focus after `key`, wrapping at both ends. `current` is
6
+ * -1 when none of the items has focus.
7
+ */
8
+ export declare function getNextIndex(key: MenuNavigationKey, current: number, count: number): number;
9
+ /**
10
+ * The text an item takes part in typeahead with: its `textValue`, else its
11
+ * `label` when that is a string.
12
+ */
13
+ export declare function getTextValue(item: {
14
+ label: React.ReactNode;
15
+ textValue?: string;
16
+ }): string | undefined;
17
+ export declare function getItemText(item: HTMLElement): string | undefined;
18
+ export declare function isTypeaheadKey(event: {
19
+ key: string;
20
+ ctrlKey: boolean;
21
+ metaKey: boolean;
22
+ altKey: boolean;
23
+ }): boolean;
24
+ /**
25
+ * Returns the index of the item to focus for `search`, or -1 for no match.
26
+ * `texts` holds each item's text, `undefined` for items without any. Typing
27
+ * the same character repeatedly cycles through the items starting with it,
28
+ * beginning after `current`. A longer search matches from `current` itself, so
29
+ * refining a search doesn't skip past the item already in focus.
30
+ */
31
+ export declare function getTypeaheadMatch(texts: (string | undefined)[], current: number, search: string): number;
32
+ export {};
33
+ //# sourceMappingURL=menu-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu-utils.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Menu/menu-utils.ts"],"names":[],"mappings":"AAKA,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,WAAW,EAAE,CAMvE;AAED,KAAK,iBAAiB,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC;AAElE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,IAAI,iBAAiB,CAIzE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,iBAAiB,EACtB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,MAAM,CAWR;AAOD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,GAAG,SAAS,CAIrB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAEjE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAIV;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,EAC7B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,MAAM,CAgBR"}
@@ -0,0 +1,54 @@
1
+ const ENABLED_ITEM_SELECTOR = '[role^="menuitem"]:not([aria-disabled="true"])';
2
+ function getEnabledItems(list) {
3
+ if (!list) {
4
+ return [];
5
+ }
6
+ return Array.from(list.querySelectorAll(ENABLED_ITEM_SELECTOR));
7
+ }
8
+ function isMenuNavigationKey(key) {
9
+ return key === "ArrowDown" || key === "ArrowUp" || key === "Home" || key === "End";
10
+ }
11
+ function getNextIndex(key, current, count) {
12
+ switch (key) {
13
+ case "Home":
14
+ return 0;
15
+ case "End":
16
+ return count - 1;
17
+ case "ArrowDown":
18
+ return (current + 1) % count;
19
+ case "ArrowUp":
20
+ return current <= 0 ? count - 1 : current - 1;
21
+ }
22
+ }
23
+ const TEXT_VALUE_ATTRIBUTE = "data-text-value";
24
+ function getTextValue(item) {
25
+ return item.textValue ?? (typeof item.label === "string" ? item.label : void 0);
26
+ }
27
+ function getItemText(item) {
28
+ return item.getAttribute(TEXT_VALUE_ATTRIBUTE) ?? void 0;
29
+ }
30
+ function isTypeaheadKey(event) {
31
+ return event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
32
+ }
33
+ function getTypeaheadMatch(texts, current, search) {
34
+ const query = search.toLowerCase();
35
+ const repeated = query.length > 1 && [...query].every((c) => c === query[0]);
36
+ const prefix = repeated ? query.slice(0, 1) : query;
37
+ const start = repeated || query.length === 1 ? current + 1 : current;
38
+ for (let offset = 0; offset < texts.length; offset++) {
39
+ const index = ((start + offset) % texts.length + texts.length) % texts.length;
40
+ if (texts[index]?.toLowerCase().startsWith(prefix)) {
41
+ return index;
42
+ }
43
+ }
44
+ return -1;
45
+ }
46
+ export {
47
+ getEnabledItems,
48
+ getItemText,
49
+ getNextIndex,
50
+ getTextValue,
51
+ getTypeaheadMatch,
52
+ isMenuNavigationKey,
53
+ isTypeaheadKey
54
+ };
@@ -17,7 +17,16 @@ export type PopoverProps = {
17
17
  * @deprecated Use `placement`, which wins when both are passed
18
18
  */
19
19
  position?: 'top' | 'bottom' | 'left' | 'right';
20
+ /**
21
+ * @deprecated Has no effect, an open popover always keeps its layout up to
22
+ * date
23
+ */
20
24
  sticky?: boolean;
25
+ /**
26
+ * Caps the popover's height to the room on the side it opens on, so a tall
27
+ * popover stops at the viewport's edge. Give it `overflow: auto` to scroll.
28
+ */
29
+ limitHeight?: boolean;
21
30
  } & HTMLElementProps<HTMLDivElement>;
22
31
  export declare const Popover: React.FC<PopoverProps>;
23
32
  //# sourceMappingURL=Popover.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Popover/Popover.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE/E,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAIjC,MAAM,MAAM,YAAY,GAAG;IACzB,aAAa,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACnD,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACrD,IAAI,EAAE,OAAO,CAAC;IACd;;;;;OAKG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C,MAAM,CAAC,EAAE,OAAO,CAAC;CAElB,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;AAErC,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAkJ1C,CAAC"}
1
+ {"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../../../../src/components/overlay/Popover/Popover.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAIjC,MAAM,MAAM,YAAY,GAAG;IACzB,aAAa,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACnD,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACrD,IAAI,EAAE,OAAO,CAAC;IACd;;;;;OAKG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CAEvB,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;AAErC,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAsN1C,CAAC"}