@stratakit/structures 0.4.4 → 0.5.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.
@@ -1,201 +1,177 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { Button as ButtonAk } from "@ariakit/react/button";
4
- import {
5
- Menu,
6
- MenuButton,
7
- MenuItem,
8
- MenuItemCheckbox,
9
- MenuProvider,
10
- useMenuContext,
11
- useMenuStore
12
- } from "@ariakit/react/menu";
4
+ import { Menu, MenuButton, MenuItem, MenuItemCheckbox, MenuProvider, useMenuContext, useMenuStore } from "@ariakit/react/menu";
13
5
  import { useStoreState } from "@ariakit/react/store";
14
6
  import { Button, Kbd } from "@stratakit/bricks";
15
- import {
16
- DisclosureArrow,
17
- Dot,
18
- predefinedSymbols
19
- } from "@stratakit/bricks/secret-internals";
7
+ import { DisclosureArrow, Dot, predefinedSymbols } from "@stratakit/bricks/secret-internals";
20
8
  import { Icon } from "@stratakit/foundations";
21
- import {
22
- forwardRef,
23
- usePopoverApi,
24
- useSafeContext
25
- } from "@stratakit/foundations/secret-internals";
9
+ import { forwardRef, usePopoverApi, useSafeContext } from "@stratakit/foundations/secret-internals";
26
10
  import cx from "classnames";
27
11
  import { Checkmark, ChevronRight } from "./~utils.icons.js";
28
12
  import * as ListItem from "./~utils.ListItem.js";
29
13
  function DropdownMenuProvider(props) {
30
- const { children, placement, open, setOpen, defaultOpen } = props;
31
- return /* @__PURE__ */ jsx(
32
- MenuProvider,
33
- {
34
- defaultOpen,
35
- open,
36
- placement,
37
- setOpen,
38
- children
39
- }
40
- );
14
+ const {
15
+ children,
16
+ placement,
17
+ open,
18
+ setOpen,
19
+ defaultOpen
20
+ } = props;
21
+ return /* @__PURE__ */ jsx(MenuProvider, {
22
+ defaultOpen,
23
+ open,
24
+ placement,
25
+ setOpen,
26
+ children
27
+ });
41
28
  }
42
- const DropdownMenuContent = forwardRef(
43
- (props, forwardedRef) => {
44
- const context = useMenuContext();
45
- const open = useStoreState(context, "open");
46
- const popoverElement = useStoreState(context, "popoverElement");
47
- const popoverProps = usePopoverApi({ element: popoverElement, open });
48
- return /* @__PURE__ */ jsx(
49
- Menu,
50
- {
51
- portal: true,
52
- unmountOnHide: true,
53
- ...props,
54
- gutter: 4,
55
- style: { ...popoverProps.style, ...props.style },
56
- wrapperProps: { popover: popoverProps.popover },
57
- className: cx("\u{1F95D}DropdownMenu", props.className),
58
- ref: forwardedRef
59
- }
60
- );
61
- }
62
- );
63
- const DropdownMenuButton = forwardRef(
64
- (props, forwardedRef) => {
65
- const { accessibleWhenDisabled = true, children, ...rest } = props;
66
- const open = useStoreState(useMenuContext(), "open");
67
- return /* @__PURE__ */ jsx(
68
- MenuButton,
69
- {
70
- accessibleWhenDisabled: true,
71
- ...rest,
72
- render: props.render ?? /* @__PURE__ */ jsxs(Button, { accessibleWhenDisabled, children: [
73
- children,
74
- /* @__PURE__ */ jsx(DisclosureArrow, {})
75
- ] }),
76
- className: cx("\u{1F95D}DropdownMenuButton", props.className),
77
- "data-has-popover-open": open || void 0,
78
- ref: forwardedRef
79
- }
80
- );
81
- }
82
- );
83
- const DropdownMenuItem = forwardRef(
84
- (props, forwardedRef) => {
85
- const { label, shortcuts, icon, unstable_dot, submenu, ...rest } = props;
86
- const dotId = React.useId();
87
- const defaultSubmenuStore = useMenuStore();
88
- const [submenuStore, setSubmenuStore] = React.useState();
89
- const store = submenuStore ?? defaultSubmenuStore;
90
- const open = useStoreState(store, "open");
91
- return /* @__PURE__ */ jsxs(Fragment, { children: [
92
- /* @__PURE__ */ jsxs(
93
- MenuItem,
94
- {
29
+ const DropdownMenuContent = forwardRef((props, forwardedRef) => {
30
+ const context = useMenuContext();
31
+ const open = useStoreState(context, "open");
32
+ const popoverElement = useStoreState(context, "popoverElement");
33
+ const popoverProps = usePopoverApi({
34
+ element: popoverElement,
35
+ open
36
+ });
37
+ return /* @__PURE__ */ jsx(Menu, {
38
+ portal: true,
39
+ unmountOnHide: true,
40
+ ...props,
41
+ gutter: 4,
42
+ style: {
43
+ ...popoverProps.style,
44
+ ...props.style
45
+ },
46
+ wrapperProps: {
47
+ popover: popoverProps.popover
48
+ },
49
+ className: cx("\u{1F95D}DropdownMenu", props.className),
50
+ ref: forwardedRef
51
+ });
52
+ });
53
+ const DropdownMenuButton = forwardRef((props, forwardedRef) => {
54
+ const {
55
+ accessibleWhenDisabled = true,
56
+ children,
57
+ ...rest
58
+ } = props;
59
+ const open = useStoreState(useMenuContext(), "open");
60
+ return /* @__PURE__ */ jsx(MenuButton, {
61
+ accessibleWhenDisabled: true,
62
+ ...rest,
63
+ render: props.render ?? /* @__PURE__ */ jsxs(Button, {
64
+ accessibleWhenDisabled,
65
+ children: [children, /* @__PURE__ */ jsx(DisclosureArrow, {})]
66
+ }),
67
+ className: cx("\u{1F95D}DropdownMenuButton", props.className),
68
+ "data-has-popover-open": open || void 0,
69
+ ref: forwardedRef
70
+ });
71
+ });
72
+ const DropdownMenuItem = forwardRef((props, forwardedRef) => {
73
+ const {
74
+ label,
75
+ shortcuts,
76
+ icon,
77
+ unstable_dot,
78
+ submenu,
79
+ ...rest
80
+ } = props;
81
+ const dotId = React.useId();
82
+ const defaultSubmenuStore = useMenuStore();
83
+ const [submenuStore, setSubmenuStore] = React.useState();
84
+ const store = submenuStore ?? defaultSubmenuStore;
85
+ const open = useStoreState(store, "open");
86
+ return /* @__PURE__ */ jsxs(Fragment, {
87
+ children: [/* @__PURE__ */ jsxs(MenuItem, {
88
+ accessibleWhenDisabled: true,
89
+ render: /* @__PURE__ */ jsx(ListItem.Root, {
90
+ render: /* @__PURE__ */ jsx(ButtonAk, {
95
91
  accessibleWhenDisabled: true,
96
- render: /* @__PURE__ */ jsx(
97
- ListItem.Root,
98
- {
99
- render: /* @__PURE__ */ jsx(
100
- ButtonAk,
101
- {
102
- accessibleWhenDisabled: true,
103
- "aria-describedby": dotId,
104
- ...rest,
105
- render: submenu ? /* @__PURE__ */ jsx(
106
- MenuButton,
107
- {
108
- render: props.render ?? /* @__PURE__ */ jsx("button", {}),
109
- store
110
- }
111
- ) : props.render,
112
- className: cx("\u{1F95D}DropdownMenuItem", props.className),
113
- "data-has-popover-open": open || void 0,
114
- ref: forwardedRef
115
- }
116
- )
117
- }
118
- ),
119
- children: [
120
- icon ? /* @__PURE__ */ jsx(DropdownMenuIcon, { icon }) : null,
121
- /* @__PURE__ */ jsx(ListItem.Content, { render: /* @__PURE__ */ jsx("span", {}), children: label }),
122
- shortcuts ? /* @__PURE__ */ jsx(DropdownMenuItemShortcuts, { shortcuts }) : null,
123
- unstable_dot ? /* @__PURE__ */ jsx(
124
- ListItem.Decoration,
125
- {
126
- render: /* @__PURE__ */ jsx(Dot, { id: dotId, className: "\u{1F95D}DropdownMenuItemDot", children: unstable_dot })
127
- }
128
- ) : null,
129
- submenu ? /* @__PURE__ */ jsx(
130
- ListItem.Decoration,
131
- {
132
- className: "\u{1F95D}DropdownMenuItemChevron",
133
- render: /* @__PURE__ */ jsx(ChevronRight, {})
134
- }
135
- ) : null
136
- ]
137
- }
138
- ),
139
- /* @__PURE__ */ jsx(
140
- DropdownMenuSubmenuContext.Provider,
141
- {
142
- value: React.useMemo(() => ({ setStore: setSubmenuStore }), []),
143
- children: submenu
144
- }
145
- )
146
- ] });
147
- }
148
- );
92
+ "aria-describedby": dotId,
93
+ ...rest,
94
+ render: submenu ? /* @__PURE__ */ jsx(MenuButton, {
95
+ render: props.render ?? /* @__PURE__ */ jsx("button", {}),
96
+ store
97
+ }) : props.render,
98
+ className: cx("\u{1F95D}DropdownMenuItem", props.className),
99
+ "data-has-popover-open": open || void 0,
100
+ ref: forwardedRef
101
+ })
102
+ }),
103
+ children: [icon ? /* @__PURE__ */ jsx(DropdownMenuIcon, {
104
+ icon
105
+ }) : null, /* @__PURE__ */ jsx(ListItem.Content, {
106
+ render: /* @__PURE__ */ jsx("span", {}),
107
+ children: label
108
+ }), shortcuts ? /* @__PURE__ */ jsx(DropdownMenuItemShortcuts, {
109
+ shortcuts
110
+ }) : null, unstable_dot ? /* @__PURE__ */ jsx(ListItem.Decoration, {
111
+ render: /* @__PURE__ */ jsx(Dot, {
112
+ id: dotId,
113
+ className: "\u{1F95D}DropdownMenuItemDot",
114
+ children: unstable_dot
115
+ })
116
+ }) : null, submenu ? /* @__PURE__ */ jsx(ListItem.Decoration, {
117
+ className: "\u{1F95D}DropdownMenuItemChevron",
118
+ render: /* @__PURE__ */ jsx(ChevronRight, {})
119
+ }) : null]
120
+ }), /* @__PURE__ */ jsx(DropdownMenuSubmenuContext.Provider, {
121
+ value: React.useMemo(() => ({
122
+ setStore: setSubmenuStore
123
+ }), []),
124
+ children: submenu
125
+ })]
126
+ });
127
+ });
149
128
  const DropdownMenuItemShortcuts = forwardRef((props, forwardedRef) => {
150
- const { shortcuts, ...rest } = props;
129
+ const {
130
+ shortcuts,
131
+ ...rest
132
+ } = props;
151
133
  const shortcutKeys = React.useMemo(() => {
152
134
  return shortcuts.split("+").map((key) => ({
153
135
  key: key.trim(),
154
136
  isSymbol: key in predefinedSymbols
155
137
  }));
156
138
  }, [shortcuts]);
157
- return /* @__PURE__ */ jsx(
158
- ListItem.Decoration,
159
- {
160
- render: /* @__PURE__ */ jsx("span", {}),
139
+ return /* @__PURE__ */ jsx(ListItem.Decoration, {
140
+ render: /* @__PURE__ */ jsx("span", {}),
141
+ ...rest,
142
+ className: cx("\u{1F95D}DropdownMenuItemShortcuts", props.className),
143
+ ref: forwardedRef,
144
+ children: shortcutKeys.map(({
145
+ key: key_0,
146
+ isSymbol
147
+ }, index) => {
148
+ if (isSymbol) {
149
+ return /* @__PURE__ */ jsx(Kbd, {
150
+ variant: "ghost",
151
+ symbol: key_0
152
+ }, `${key_0 + index}`);
153
+ }
154
+ return /* @__PURE__ */ jsx(Kbd, {
155
+ variant: "ghost",
156
+ children: key_0
157
+ }, `${key_0 + index}`);
158
+ })
159
+ });
160
+ });
161
+ const DropdownMenuIcon = forwardRef((props, forwardedRef) => {
162
+ const {
163
+ icon,
164
+ ...rest
165
+ } = props;
166
+ return /* @__PURE__ */ jsx(ListItem.Decoration, {
167
+ render: /* @__PURE__ */ jsx(Icon, {
168
+ href: typeof icon === "string" ? icon : void 0,
169
+ render: React.isValidElement(icon) ? icon : void 0,
161
170
  ...rest,
162
- className: cx("\u{1F95D}DropdownMenuItemShortcuts", props.className),
163
- ref: forwardedRef,
164
- children: shortcutKeys.map(({ key, isSymbol }, index) => {
165
- if (isSymbol) {
166
- return /* @__PURE__ */ jsx(
167
- Kbd,
168
- {
169
- variant: "ghost",
170
- symbol: key
171
- },
172
- `${key + index}`
173
- );
174
- }
175
- return /* @__PURE__ */ jsx(Kbd, { variant: "ghost", children: key }, `${key + index}`);
176
- })
177
- }
178
- );
171
+ ref: forwardedRef
172
+ })
173
+ });
179
174
  });
180
- const DropdownMenuIcon = forwardRef(
181
- (props, forwardedRef) => {
182
- const { icon, ...rest } = props;
183
- return /* @__PURE__ */ jsx(
184
- ListItem.Decoration,
185
- {
186
- render: /* @__PURE__ */ jsx(
187
- Icon,
188
- {
189
- href: typeof icon === "string" ? icon : void 0,
190
- render: React.isValidElement(icon) ? icon : void 0,
191
- ...rest,
192
- ref: forwardedRef
193
- }
194
- )
195
- }
196
- );
197
- }
198
- );
199
175
  const DropdownMenuCheckboxItem = forwardRef((props, forwardedRef) => {
200
176
  const {
201
177
  label,
@@ -208,70 +184,61 @@ const DropdownMenuCheckboxItem = forwardRef((props, forwardedRef) => {
208
184
  // For defaultChecked to work
209
185
  ...rest
210
186
  } = props;
211
- return /* @__PURE__ */ jsxs(
212
- MenuItemCheckbox,
213
- {
214
- accessibleWhenDisabled: true,
215
- defaultChecked,
216
- checked,
217
- name,
218
- value,
219
- onChange,
220
- render: /* @__PURE__ */ jsx(
221
- ListItem.Root,
222
- {
223
- render: /* @__PURE__ */ jsx(
224
- ButtonAk,
225
- {
226
- accessibleWhenDisabled: true,
227
- ...rest,
228
- className: cx("\u{1F95D}DropdownMenuItem", props.className),
229
- ref: forwardedRef
230
- }
231
- )
232
- }
233
- ),
234
- children: [
235
- icon ? /* @__PURE__ */ jsx(DropdownMenuIcon, { icon }) : null,
236
- /* @__PURE__ */ jsx(ListItem.Content, { render: /* @__PURE__ */ jsx("span", {}), children: label }),
237
- /* @__PURE__ */ jsx(
238
- ListItem.Decoration,
239
- {
240
- render: /* @__PURE__ */ jsx(Checkmark, { className: "\u{1F95D}DropdownMenuCheckmark" })
241
- }
242
- )
243
- ]
244
- }
245
- );
187
+ return /* @__PURE__ */ jsxs(MenuItemCheckbox, {
188
+ accessibleWhenDisabled: true,
189
+ defaultChecked,
190
+ checked,
191
+ name,
192
+ value,
193
+ onChange,
194
+ render: /* @__PURE__ */ jsx(ListItem.Root, {
195
+ render: /* @__PURE__ */ jsx(ButtonAk, {
196
+ accessibleWhenDisabled: true,
197
+ ...rest,
198
+ className: cx("\u{1F95D}DropdownMenuItem", props.className),
199
+ ref: forwardedRef
200
+ })
201
+ }),
202
+ children: [icon ? /* @__PURE__ */ jsx(DropdownMenuIcon, {
203
+ icon
204
+ }) : null, /* @__PURE__ */ jsx(ListItem.Content, {
205
+ render: /* @__PURE__ */ jsx("span", {}),
206
+ children: label
207
+ }), /* @__PURE__ */ jsx(ListItem.Decoration, {
208
+ render: /* @__PURE__ */ jsx(Checkmark, {
209
+ className: "\u{1F95D}DropdownMenuCheckmark"
210
+ })
211
+ })]
212
+ });
246
213
  });
247
214
  const DropdownMenuSubmenuContext = React.createContext(void 0);
248
- const DropdownMenuSubmenu = forwardRef(
249
- (props, forwardedRef) => {
250
- const { setStore } = useSafeContext(DropdownMenuSubmenuContext);
251
- const store = useMenuStore();
252
- React.useEffect(() => {
253
- setStore(store);
254
- return () => setStore(void 0);
255
- }, [store, setStore]);
256
- const parent = useMenuContext();
257
- const popoverElement = useStoreState(parent, "popoverElement");
258
- return /* @__PURE__ */ jsx(MenuProvider, { store, children: /* @__PURE__ */ jsx(
259
- Menu,
260
- {
261
- store,
262
- portal: true,
263
- portalElement: popoverElement,
264
- preserveTabOrder: false,
265
- unmountOnHide: true,
266
- ...props,
267
- gutter: 2,
268
- shift: -4,
269
- className: cx("\u{1F95D}DropdownMenu", props.className),
270
- ref: forwardedRef
271
- }
272
- ) });
273
- }
274
- );
215
+ const DropdownMenuSubmenu = forwardRef((props, forwardedRef) => {
216
+ const {
217
+ setStore
218
+ } = useSafeContext(DropdownMenuSubmenuContext);
219
+ const store = useMenuStore();
220
+ React.useEffect(() => {
221
+ setStore(store);
222
+ return () => setStore(void 0);
223
+ }, [store, setStore]);
224
+ const parent = useMenuContext();
225
+ const popoverElement = useStoreState(parent, "popoverElement");
226
+ return /* @__PURE__ */ jsx(MenuProvider, {
227
+ store,
228
+ children: /* @__PURE__ */ jsx(Menu, {
229
+ store,
230
+ portal: true,
231
+ portalElement: popoverElement,
232
+ preserveTabOrder: false,
233
+ unmountOnHide: true,
234
+ ...props,
235
+ gutter: 2,
236
+ shift: -4,
237
+ className: cx("\u{1F95D}DropdownMenu", props.className),
238
+ ref: forwardedRef
239
+ })
240
+ });
241
+ });
275
242
  export {
276
243
  DropdownMenuButton as Button,
277
244
  DropdownMenuCheckboxItem as CheckboxItem,
@@ -1,17 +1,19 @@
1
1
  import * as React from "react";
2
2
  import type { BaseProps } from "@stratakit/foundations/secret-internals";
3
- interface ErrorRegionRootProps extends Omit<BaseProps, "children"> {
3
+ interface ErrorRegionRootBaseProps extends Omit<BaseProps, "children"> {
4
4
  /**
5
5
  * Label for the error header, usually indicating the number of errors displayed.
6
- * By default this is used as a name of the region navigational landmark, however an explicit `aria-label` or `aria-labelledby` is strongly suggested.
7
6
  *
8
- * Use `undefined` if you don't want to display errors rather than conditionally rendering the component.
7
+ * Changes to the `label` prop will be communicated
8
+ * using a [live region](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Guides/Live_regions).
9
9
  */
10
10
  label?: React.ReactNode;
11
11
  /**
12
12
  * A list of error items where each item describes an individual error. Must be a list of `ErrorRegion.Item` components.
13
+ *
14
+ * Set to `undefined` or empty array if you don't want to display errors rather than conditionally rendering the component.
13
15
  */
14
- items?: React.ReactNode;
16
+ items?: React.ReactNode[];
15
17
  /**
16
18
  * The controlled open state of the region.
17
19
  */
@@ -23,25 +25,41 @@ interface ErrorRegionRootProps extends Omit<BaseProps, "children"> {
23
25
  */
24
26
  setOpen?: (open: boolean) => void;
25
27
  }
28
+ type ErrorRegionRootExtraProps = {
29
+ /**
30
+ * Name of the region navigational landmark.
31
+ *
32
+ * This label should remain stable throughout the lifetime of the region.
33
+ */
34
+ "aria-label": string | undefined;
35
+ } | {
36
+ /**
37
+ * Identifies the element that labels the region navigational landmark.
38
+ *
39
+ * This label should remain stable throughout the lifetime of the region.
40
+ */
41
+ "aria-labelledby": string | undefined;
42
+ };
43
+ type ErrorRegionRootProps = ErrorRegionRootBaseProps & ErrorRegionRootExtraProps;
26
44
  /**
27
45
  * A collapsible region that displays a list of error messages, which might originate from another
28
46
  * component, such as `Tree`.
29
47
  *
30
48
  * This component is rendered as a [region landmark](https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/region.html)
31
- * and should be labelled either using `label` or `aria-label`/`aria-labelledby`. Changes to the `label` prop will be
32
- * announced communicated using a [live region](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Guides/Live_regions).
49
+ * and should be labelled using `aria-label` or `aria-labelledby`.
50
+ *
51
+ * This component should not be rendered conditionally, instead use the `items` prop to control the visibility.
33
52
  *
34
53
  * Example:
35
54
  * ```tsx
36
55
  * <ErrorRegion.Root
56
+ * aria-label="Issues"
37
57
  * label="3 issues found"
38
- * items={
39
- * <>
40
- * <ErrorRegion.Item message="…" />
41
- * <ErrorRegion.Item message="…" />
42
- * <ErrorRegion.Item message="…" />
43
- * </>
44
- * }
58
+ * items={[
59
+ * <ErrorRegion.Item key={…} message="…" />
60
+ * <ErrorRegion.Item key={…} message="…" />
61
+ * <ErrorRegion.Item key={…} message="…" />
62
+ * ]}
45
63
  * />
46
64
  */
47
65
  declare const ErrorRegionRoot: React.ForwardRefExoticComponent<ErrorRegionRootProps & React.RefAttributes<HTMLDivElement | HTMLElement>>;