@minimalstuff/ui 3.0.1 → 3.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.
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { Callable } from 'react-call';
2
2
  import { ComponentPropsWithRef } from 'react';
3
+ import type { HTMLAttributeAnchorTarget } from 'react';
3
4
  import { JSX } from 'react';
4
5
  import { JSXElementConstructor } from 'react';
5
- import { MouseEvent as MouseEvent_2 } from 'react';
6
+ import type { MouseEvent as MouseEvent_2 } from 'react';
6
7
  import { ReactElement } from 'react';
7
8
  import { ReactNode } from 'react';
8
9
  import { ReactPortal } from 'react';
@@ -10,6 +11,34 @@ import { Ref } from 'react';
10
11
  import { StoreApi } from 'zustand';
11
12
  import { UseBoundStore } from 'zustand';
12
13
 
14
+ /**
15
+ * The picture of a person, or the initial of `name` when there is none.
16
+ * Labelled with the full `name` so screen readers announce the person rather
17
+ * than a stray letter; the `<img>` itself stays out of the accessibility
18
+ * tree to avoid announcing it twice.
19
+ *
20
+ * A `src` that fails to load falls back to the initial — remote avatars go
21
+ * missing (deleted accounts, rate limits), and a broken-image glyph in a
22
+ * circle looks like a bug. Pointing `src` at a different URL retries.
23
+ *
24
+ * A missing name is the caller's call to make: this renders whatever `name`
25
+ * starts with, and an empty circle for a blank string, rather than inventing
26
+ * a placeholder identity.
27
+ */
28
+ export declare function Avatar({ name, src, size, color, radius, unstyled, className, }: Readonly<AvatarProps>): JSX.Element;
29
+
30
+ export declare interface AvatarProps {
31
+ name: string;
32
+ src?: string;
33
+ size?: AvatarSize;
34
+ color?: ButtonColor;
35
+ radius?: Radius;
36
+ unstyled?: boolean;
37
+ className?: string;
38
+ }
39
+
40
+ export declare type AvatarSize = ControlSize;
41
+
13
42
  export declare const Badge: ({ children, color, variant, size, radius, className, ...props }: Readonly<BadgeProps>) => JSX.Element;
14
43
 
15
44
  export declare interface BadgeProps extends ComponentPropsWithRef<'span'> {
@@ -35,6 +64,7 @@ declare type ButtonColor =
35
64
  | 'danger'
36
65
  | 'success'
37
66
  | 'warning';
67
+ export { ButtonColor as AvatarColor }
38
68
  export { ButtonColor as BadgeColor }
39
69
  export { ButtonColor }
40
70
 
@@ -59,6 +89,39 @@ declare type ButtonStyle = {
59
89
 
60
90
  export declare type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'subtle';
61
91
 
92
+ /**
93
+ * A section container: surface, border, radius, padding. Pass `title` (plus
94
+ * optionally `description` and `actions`, which sit opposite the title) to
95
+ * get the standard header, or omit all three and lay the section out inside
96
+ * `children` yourself.
97
+ *
98
+ * A titled card is also a labelled `region`, so screen reader users can jump
99
+ * between sections by name — worth it on a settings page stacking seven of
100
+ * them. Untitled cards stay plain `div`s rather than adding nameless
101
+ * landmarks. Set `headingLevel` when the card sits under an existing heading:
102
+ * the default `h2` is right at the top level of a page and wrong nested.
103
+ *
104
+ * `unstyled` strips the surface, border, radius and padding; the header
105
+ * markup stays, since that is structure rather than skin.
106
+ */
107
+ export declare function Card({ children, title, description, actions, headingLevel, padding, radius, unstyled, className, }: Readonly<CardProps>): JSX.Element;
108
+
109
+ export declare type CardHeadingLevel = 2 | 3 | 4;
110
+
111
+ export declare type CardPadding = 'none' | 'sm' | 'md' | 'lg';
112
+
113
+ export declare interface CardProps {
114
+ children: ReactNode;
115
+ title?: ReactNode;
116
+ description?: ReactNode;
117
+ actions?: ReactNode;
118
+ headingLevel?: CardHeadingLevel;
119
+ padding?: CardPadding;
120
+ radius?: Radius;
121
+ unstyled?: boolean;
122
+ className?: string;
123
+ }
124
+
62
125
  export declare function CharacterCount({ current, min, max, showMin, showMax, unstyled, className, }: Readonly<CharacterCountProps>): JSX.Element;
63
126
 
64
127
  export declare interface CharacterCountProps {
@@ -83,7 +146,7 @@ export declare interface CheckboxProps extends Omit<ComponentPropsWithRef<'input
83
146
  wrapperClassName?: string;
84
147
  }
85
148
 
86
- export declare function ClientOnly({ children, fallback }: Readonly<ClientOnlyProps>): string | number | bigint | boolean | Iterable< ReactNode> | Promise<string | number | bigint | boolean | ReactPortal | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable< ReactNode> | null | undefined> | JSX.Element | null;
149
+ export declare function ClientOnly({ children, fallback }: Readonly<ClientOnlyProps>): string | number | bigint | boolean | JSX.Element | Iterable< ReactNode> | Promise<string | number | bigint | boolean | ReactPortal | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable< ReactNode> | null | undefined> | null;
87
150
 
88
151
  export declare interface ClientOnlyProps extends React.PropsWithChildren {
89
152
  fallback?: React.ReactNode;
@@ -134,10 +197,10 @@ export declare interface ConfirmModalProps {
134
197
  export declare type ConfirmModalResponse = boolean;
135
198
 
136
199
  /**
137
- * Wraps `children` (the right-click target area) and opens `items`, a list
138
- * of `MenuItem` elements as direct children (see `MenuItem`'s own doc
139
- * comment), at the cursor position. Right-click again elsewhere on the
140
- * wrapped area to reposition it.
200
+ * Wraps `children` (the right-click target area) and opens `items` — made
201
+ * of `MenuItem`s, optionally wrapped in `MenuGroup`s and split by
202
+ * `MenuSeparator`s — at the cursor position. Right-click again elsewhere on
203
+ * the wrapped area to reposition it.
141
204
  *
142
205
  * For a menu anchored to a specific button (e.g. a kebab icon) instead of a
143
206
  * right-click, use `Menu`.
@@ -232,39 +295,112 @@ export declare type KbdSize = ControlSize;
232
295
 
233
296
  /**
234
297
  * A dropdown anchored to `trigger` (e.g. a kebab `IconButton`): click to
235
- * open, click again/click outside/Escape to close. `children` must be
236
- * `MenuItem` elements as direct children (see `MenuItem`'s own doc comment)
237
- * for keyboard nav and close-on-select to work.
298
+ * open, click again/click outside/Escape to close. `children` is made of
299
+ * `MenuItem`s, optionally wrapped in `MenuGroup`s and split by
300
+ * `MenuSeparator`s.
238
301
  *
239
302
  * For "right-click anywhere on this area" instead of a specific trigger
240
303
  * button, use `ContextMenu`.
304
+ *
305
+ * Opening a `Modal` from a `MenuItem`'s `onClick` is safe: the menu returns
306
+ * focus to `trigger` synchronously during the click, then the modal mounts a
307
+ * render later and takes focus from there. That ordering is what makes the
308
+ * modal record `trigger` as its restore target, so focus lands back on the
309
+ * trigger when the modal closes. The menu panel outlives the click by one
310
+ * exit animation, but the modal sits above it and owns Escape (a document
311
+ * listener), so the fading panel is inert. See `menu_with_modal.test.tsx`.
241
312
  */
242
313
  export declare function Menu({ trigger, children, side, align, radius, className, ref, }: Readonly<MenuProps>): JSX.Element;
243
314
 
244
315
  export declare type MenuAlign = 'start' | 'center' | 'end';
245
316
 
246
317
  /**
247
- * A row inside a `Menu` or `ContextMenu`. Must be a direct child of one of
248
- * those (or of a `<>` fragment passed as their `children`/`items`): arrow
249
- * key navigation and close-on-select both rely on `role="menuitem"` being a
250
- * direct descendant. Wrapping items in another element (e.g. a `<div>` for
251
- * a labeled section) will render fine but breaks both.
318
+ * A named group of `MenuItem`s inside a `Menu` or `ContextMenu`. Where
319
+ * `MenuSeparator` cuts, this one names — and unlike a bare title sitting
320
+ * next to the items, `role="group"` plus `aria-labelledby` actually tells
321
+ * assistive tech which items the name covers.
252
322
  *
253
- * Works standalone outside a `Menu`/`ContextMenu` too (e.g. in isolation in
254
- * Storybook): `onClick` still fires, it just won't auto-close anything.
323
+ * Wrapping items is safe: the enclosing menu collects `[role="menuitem"]`
324
+ * across all its descendants, so keyboard navigation still walks into the
325
+ * group, and close-on-select travels through React context rather than the
326
+ * DOM tree.
327
+ *
328
+ * `className` styles the label — the only part of the group that carries any
329
+ * skin. `wrapperClassName` styles the `role="group"` element around both the
330
+ * label and the items.
255
331
  */
256
- export declare function MenuItem({ icon, onClick, danger, disabled, children, className, ref, }: Readonly<MenuItemProps>): JSX.Element;
332
+ export declare function MenuGroup({ label, children, unstyled, className, wrapperClassName, }: Readonly<MenuGroupProps>): JSX.Element;
257
333
 
258
- export declare interface MenuItemProps {
259
- icon?: string;
260
- onClick: (event: MouseEvent_2<HTMLButtonElement>) => void;
261
- danger?: boolean;
262
- disabled?: boolean;
334
+ export declare interface MenuGroupProps {
335
+ label: ReactNode;
263
336
  children: ReactNode;
337
+ unstyled?: boolean;
264
338
  className?: string;
265
- ref?: Ref<HTMLButtonElement>;
339
+ wrapperClassName?: string;
266
340
  }
267
341
 
342
+ /**
343
+ * A row inside a `Menu` or `ContextMenu`, at any depth: the menu collects
344
+ * `[role="menuitem"]`/`[role="menuitemradio"]` across all its descendants
345
+ * for keyboard navigation, and close-on-select travels through React
346
+ * context rather than the DOM tree. `MenuGroup` relies on that to wrap the
347
+ * items it names.
348
+ *
349
+ * Renders either a `<button>` (pass `onClick`) or a native `<a>` (pass
350
+ * `href`, plus optional `target`/`rel`); the two are mutually exclusive.
351
+ * A disabled link drops its `href` and is marked `aria-disabled`, which
352
+ * keeps it out of the menu's keyboard navigation just like a disabled
353
+ * button.
354
+ *
355
+ * Works standalone outside a `Menu`/`ContextMenu` too (e.g. in isolation in
356
+ * Storybook): `onClick` still fires, it just won't auto-close anything.
357
+ */
358
+ export declare function MenuItem(menuItemProps: Readonly<MenuItemProps>): JSX.Element;
359
+
360
+ declare type MenuItemBaseProps = {
361
+ icon?: string;
362
+ /**
363
+ * Content pinned to the end of the row, dimmed by default — a `Kbd`, the
364
+ * current value of a setting. Keep it inert: the whole row is already the
365
+ * control, so anything focusable or separately clickable in here breaks
366
+ * both the menu's keyboard navigation and its `menuitem` semantics.
367
+ *
368
+ * It sits inside the row, so it is part of what the row announces:
369
+ * "Theme, Dark" for a value, "Shortcuts, Command K" for a shortcut. That
370
+ * is usually what you want; pass already-hidden content if it is not.
371
+ */
372
+ trailing?: ReactNode;
373
+ danger?: boolean;
374
+ disabled?: boolean;
375
+ children: ReactNode;
376
+ className?: string;
377
+ };
378
+
379
+ export declare type MenuItemButtonProps = MenuItemBaseProps & {
380
+ onClick: (event: MouseEvent_2<HTMLButtonElement>) => void;
381
+ /**
382
+ * Turns the item into one option of a choice: it reports as
383
+ * `menuitemradio`, carries `aria-checked`, and shows a check mark when
384
+ * true. Leave it out for plain actions — an unset `selected` is not the
385
+ * same as `false`, which reads as "an option, currently not the one".
386
+ */
387
+ selected?: boolean;
388
+ href?: never;
389
+ target?: never;
390
+ rel?: never;
391
+ ref?: Ref<HTMLButtonElement>;
392
+ };
393
+
394
+ export declare type MenuItemLinkProps = MenuItemBaseProps & {
395
+ href: string;
396
+ target?: HTMLAttributeAnchorTarget;
397
+ rel?: string;
398
+ onClick?: never;
399
+ ref?: Ref<HTMLAnchorElement>;
400
+ };
401
+
402
+ export declare type MenuItemProps = MenuItemButtonProps | MenuItemLinkProps;
403
+
268
404
  export declare interface MenuProps {
269
405
  trigger: ReactElement;
270
406
  children: ReactNode;
@@ -276,6 +412,18 @@ export declare interface MenuProps {
276
412
  ref?: Ref<HTMLSpanElement>;
277
413
  }
278
414
 
415
+ /**
416
+ * A divider between groups of `MenuItem`s inside a `Menu` or `ContextMenu`.
417
+ * Carries `role="separator"` (never `menuitem`), so the surrounding menu's
418
+ * arrow key navigation skips it: only focusable items take part.
419
+ */
420
+ export declare const MenuSeparator: ({ unstyled, className, }: Readonly<MenuSeparatorProps>) => JSX.Element;
421
+
422
+ export declare interface MenuSeparatorProps {
423
+ unstyled?: boolean;
424
+ className?: string;
425
+ }
426
+
279
427
  export declare type MenuSide = 'top' | 'bottom' | 'left' | 'right';
280
428
 
281
429
  export declare const Modal: Callable<ModalProps, void, {}>;