@ahrowe/ui 0.50.0 → 0.52.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 (86) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +2 -1
  3. package/dist/cjs-types/common/actionIcon/actionIcon.types.d.ts +10 -6
  4. package/dist/cjs-types/common/ahroweProvider/ahroweProvider.d.ts +1 -1
  5. package/dist/cjs-types/common/button/button.types.d.ts +25 -8
  6. package/dist/cjs-types/common/chatMessageList/chatMessageList.types.d.ts +1 -1
  7. package/dist/cjs-types/common/configProvider/configProvider.d.ts +2 -1
  8. package/dist/cjs-types/common/configProvider/configProvider.types.d.ts +8 -0
  9. package/dist/cjs-types/common/copyButton/copyButton.types.d.ts +4 -1
  10. package/dist/cjs-types/common/dropdown/dropdown.types.d.ts +3 -2
  11. package/dist/cjs-types/common/infiniteBlock/useInfiniteScroll.d.ts +1 -1
  12. package/dist/cjs-types/common/listItem/index.d.ts +2 -0
  13. package/dist/cjs-types/common/listItem/listItem.d.ts +4 -0
  14. package/dist/cjs-types/common/listItem/listItem.types.d.ts +33 -0
  15. package/dist/cjs-types/common/menu/menu.types.d.ts +2 -2
  16. package/dist/cjs-types/common/menu/menuItem.d.ts +5 -2
  17. package/dist/cjs-types/common/themeProvider/theme.types.d.ts +4 -0
  18. package/dist/cjs-types/common/utils/navigation.d.ts +12 -0
  19. package/dist/cjs-types/index.d.ts +2 -0
  20. package/dist/esm/common/ahroweProvider/ahroweProvider.mjs +1 -1
  21. package/dist/esm/common/ahroweProvider/ahroweProvider.mjs.map +1 -1
  22. package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
  23. package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
  24. package/dist/esm/common/button/button.mjs +1 -1
  25. package/dist/esm/common/button/button.mjs.map +1 -1
  26. package/dist/esm/common/button/button.module.mjs +1 -1
  27. package/dist/esm/common/button/button.module.mjs.map +1 -1
  28. package/dist/esm/common/button/button.types.mjs.map +1 -1
  29. package/dist/esm/common/chatMessageList/chatMessageList.mjs +1 -1
  30. package/dist/esm/common/chatMessageList/chatMessageList.mjs.map +1 -1
  31. package/dist/esm/common/commandPalette/commandPalette.mjs +1 -1
  32. package/dist/esm/common/commandPalette/commandPalette.mjs.map +1 -1
  33. package/dist/esm/common/configProvider/configProvider.mjs +1 -1
  34. package/dist/esm/common/configProvider/configProvider.mjs.map +1 -1
  35. package/dist/esm/common/dropdown/dropdown.mjs +1 -1
  36. package/dist/esm/common/dropdown/dropdown.mjs.map +1 -1
  37. package/dist/esm/common/dropdown/dropdown.module.mjs +1 -1
  38. package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
  39. package/dist/esm/common/infiniteBlock/useInfiniteScroll.mjs +1 -1
  40. package/dist/esm/common/infiniteBlock/useInfiniteScroll.mjs.map +1 -1
  41. package/dist/esm/common/listItem/listItem.mjs +2 -0
  42. package/dist/esm/common/listItem/listItem.mjs.map +1 -0
  43. package/dist/esm/common/listItem/listItem.module.mjs +2 -0
  44. package/dist/esm/common/listItem/listItem.module.mjs.map +1 -0
  45. package/dist/esm/common/loader/loader.module.mjs.map +1 -1
  46. package/dist/esm/common/menu/menu.mjs +1 -1
  47. package/dist/esm/common/menu/menu.mjs.map +1 -1
  48. package/dist/esm/common/menu/menu.types.mjs.map +1 -1
  49. package/dist/esm/common/menu/menuItem.mjs +1 -1
  50. package/dist/esm/common/menu/menuItem.mjs.map +1 -1
  51. package/dist/esm/common/utils/navigation.mjs +2 -0
  52. package/dist/esm/common/utils/navigation.mjs.map +1 -0
  53. package/dist/esm/index.mjs +1 -1
  54. package/dist/index.cjs +5 -5
  55. package/dist/index.cjs.map +1 -1
  56. package/dist/style.css +1 -1
  57. package/dist/types/common/actionIcon/actionIcon.types.d.ts +10 -6
  58. package/dist/types/common/ahroweProvider/ahroweProvider.d.ts +1 -1
  59. package/dist/types/common/button/button.types.d.ts +25 -8
  60. package/dist/types/common/chatMessageList/chatMessageList.types.d.ts +1 -1
  61. package/dist/types/common/configProvider/configProvider.d.ts +2 -1
  62. package/dist/types/common/configProvider/configProvider.types.d.ts +8 -0
  63. package/dist/types/common/copyButton/copyButton.types.d.ts +4 -1
  64. package/dist/types/common/dropdown/dropdown.types.d.ts +3 -2
  65. package/dist/types/common/infiniteBlock/useInfiniteScroll.d.ts +1 -1
  66. package/dist/types/common/listItem/index.d.ts +2 -0
  67. package/dist/types/common/listItem/listItem.d.ts +4 -0
  68. package/dist/types/common/listItem/listItem.types.d.ts +33 -0
  69. package/dist/types/common/menu/menu.types.d.ts +2 -2
  70. package/dist/types/common/menu/menuItem.d.ts +5 -2
  71. package/dist/types/common/themeProvider/theme.types.d.ts +4 -0
  72. package/dist/types/common/utils/navigation.d.ts +12 -0
  73. package/dist/types/index.d.ts +2 -0
  74. package/docs/ActionIcon.md +7 -3
  75. package/docs/AhroweProvider.md +2 -1
  76. package/docs/Breadcrumb.md +4 -24
  77. package/docs/Button.md +44 -9
  78. package/docs/CLAUDE.md +4 -0
  79. package/docs/ChatMessageList.md +5 -5
  80. package/docs/CommandPalette.md +1 -1
  81. package/docs/ConfigProvider.md +34 -1
  82. package/docs/Dropdown.md +17 -3
  83. package/docs/ListItem.md +97 -0
  84. package/docs/Menu.md +2 -2
  85. package/docs/ScrollbarProvider.md +1 -1
  86. package/package.json +1 -1
@@ -0,0 +1,97 @@
1
+ # ListItem
2
+
3
+ **When to use:** One row of a list that stands for a record: a customer, an invoice, a delivery note. It shows a title, a second line and a status, can hold actions of its own, and can open the record from the whole row. For hundreds of rows use [VirtualList](VirtualList.md); for actions hanging off a trigger, [Menu](Menu.md).
4
+
5
+ **Keywords:** row, list row, cell, entry, record, item, drill-down, detail link, settings row
6
+
7
+ **Import:** `import { ListItem } from '@ahrowe/ui'`
8
+ **Types:** `import type { ListItemProps } from '@ahrowe/ui'`
9
+
10
+ ```tsx
11
+ import { ActionIcon, Chip, ListItem, ThemeColor } from '@ahrowe/ui';
12
+ import { faFileInvoice, faPen } from '@fortawesome/free-solid-svg-icons';
13
+
14
+ // Shows a record
15
+ <ListItem title="Created" endContent="12 Oct 2026" />
16
+
17
+ // Opens it: the whole row is the link, with a chevron
18
+ <ListItem
19
+ icon={faFileInvoice}
20
+ title="Invoice 2026-0042"
21
+ subtitle="Müller GmbH, due 1 Nov"
22
+ endContent={<Chip text="Open" color={ThemeColor.Warn} />}
23
+ href="/invoices/42"
24
+ />
25
+
26
+ // Opens it and has an action: the edit button stays its own
27
+ <ListItem
28
+ title="Müller GmbH"
29
+ subtitle="3 projects"
30
+ href="/clients/7"
31
+ endContent={<ActionIcon icon={faPen} aria-label="Edit" onClick={editClient} />}
32
+ />
33
+
34
+ // Opens it from a button instead of a link: no chevron, which promises a page
35
+ <ListItem title="Add a contact" onClick={openContactModal} />
36
+
37
+ // The one that is open, beside its detail view
38
+ <ListItem title="Müller GmbH" href="/clients/7" selected={clientId === 7} />
39
+ ```
40
+
41
+ ## Opening a record
42
+
43
+ With `href` the title is a link, and with `onClick` a button. Either one stretches over the whole
44
+ row, so a click anywhere on it opens the record, and with a link a middle click and a long press
45
+ too. Controls in the row stay their own: a button, a link, an input or anything with a `tabindex`
46
+ sits above the stretched area. Text around them still opens the row, so a click on a status `Chip`
47
+ opens the record.
48
+
49
+ A plain click on a page of the app goes through `ConfigProvider`'s `navigate` when it is set, see
50
+ [ConfigProvider.md](ConfigProvider.md). A screen reader hears the title as the link's name and the
51
+ subtitle, and a text `endContent`, as its description, rather than the whole row run together.
52
+
53
+ Because the link covers the row, its text cannot be selected with the mouse. A row that is only
54
+ read, with neither `href` nor `onClick`, selects as usual.
55
+
56
+ The rows sit in whatever holds them, a `Card` or a `<ul>` of your own. ListItem draws no dividers
57
+ and no list semantics of its own: it is a `<div>`, so in a `<ul>` give each one an `<li>`.
58
+
59
+ **Dividers.** Between groups of rows, a [Divider](Divider.md): it has no margin, so it adds the line
60
+ and nothing else. Between every row, a border from the container instead, because a screen reader
61
+ announces each `Divider` as a separator. The same rule works on `<div>`s and on `<li>`s:
62
+
63
+ ```css
64
+ .clients > * + * {
65
+ border-top: 1px solid var(--border-color);
66
+ }
67
+ ```
68
+
69
+ **Key props:**
70
+
71
+ | Prop | Type | Description |
72
+ |------|------|-------------|
73
+ | `title` | `ReactNode` | The main line, cut off with an ellipsis where it does not fit (required) |
74
+ | `subtitle` | `ReactNode` | A smaller line under it, cut off after two lines |
75
+ | `icon` | `IconDefinition \| ReactElement` | Before the title: a FontAwesome icon or any element, such as an `Avatar` |
76
+ | `endContent` | `ReactNode` | The trailing edge: a status, a date, an amount, and controls of its own |
77
+ | `href` | `string` | Opens the record from the whole row, as a link. `target`, `rel` and `download` apply to it |
78
+ | `onClick` | `MouseEventHandler<HTMLElement>` | Opens the record from the whole row, as a button. With `href` too, runs first, and `preventDefault()` keeps the link from being followed |
79
+ | `selected` | `boolean` | The row whose record is open: tinted in `--list-item-selected-background`, and `aria-current="page"` on its link |
80
+ | `chevron` | `boolean` | The chevron at the end. On by default for a row with an `href`, off for one with only `onClick`, which opens a dialog or runs an action rather than going somewhere |
81
+
82
+ Every native attribute passes through to the root `<div>`. A long title shrinks before
83
+ `endContent` and the chevron do, so they never leave the row. `endContent` itself never shrinks:
84
+ a value longer than a date or an amount belongs in the `subtitle`.
85
+
86
+ **Theming:**
87
+
88
+ | Variable | Default |
89
+ |----------|---------|
90
+ | `--list-item-min-height` | `48px`, the smallest comfortable touch target |
91
+ | `--list-item-selected-background` | a 12% tint of `--primary-color` |
92
+
93
+ Set it once in the theme rather than on each row: `'--list-item-min-height': '64px'`. Hover and
94
+ press tint the row in its own text colour, so they show on any surface; the keyboard focus ring
95
+ goes around the whole row, inside its edge, in `--focus-border-color`.
96
+
97
+ **Slots:** `root` `icon` `labels` `trigger` (the link or button, which draws the hover and focus ring in its `::after`) `title` `subtitle` `endContent` `chevron`
package/docs/Menu.md CHANGED
@@ -54,7 +54,7 @@ useHotkeys(menuHotkeys(items, run));
54
54
  useHotkeys(menuHotkeys(items, run), { enabled: isOpen });
55
55
  ```
56
56
 
57
- It runs each entry the way clicking it does, its own `onClick` then `onAction` then its `href`, and leaves out a `disabled` entry and any entry with no `shortcut`. Bind them yourself instead if the actions already live in a keymap of your own; the menu does not mind either way.
57
+ It runs each entry the way clicking it does, its own `onClick` then `onAction` then its `href`, and leaves out a `disabled` entry and any entry with no `shortcut`. It runs outside React, so it cannot reach `ConfigProvider`'s `navigate`: an `href` run from a shortcut loads the page. Bind them yourself instead if the actions already live in a keymap of your own; the menu does not mind either way.
58
58
 
59
59
  An action runs its own `onClick` first, then `onAction` on the menu, then the menu closes. Use whichever of the two fits: a handler per entry when they are unrelated, `onAction` when they funnel into one place.
60
60
 
@@ -120,7 +120,7 @@ Separators and headings are never focused. The trigger is given `aria-haspopup`,
120
120
  | `shortcut` | `string` | A combo in `useHotkeys` spelling, e.g. `'mod+k'`. Shown on the trailing edge, written for the platform. Binding it is yours, see `menuHotkeys` |
121
121
  | `disabled` | `boolean` | Not clickable, and skipped by the arrow keys |
122
122
  | `danger` | `boolean` | Renders in the destructive colour |
123
- | `href` | `string` | Makes the entry a real `<a>`, so Ctrl/⌘-click and a middle click open it in a new tab. A click runs `onClick` and `onAction` first, a middle click neither. The browser loads the page, so with a client-side router navigate in `onClick` instead. A `disabled` entry stays a button |
123
+ | `href` | `string` | Makes the entry a real `<a>`, so Ctrl/⌘-click and a middle click open it in a new tab. A click runs `onClick` and `onAction` first, a middle click neither, then follows the link through `ConfigProvider`'s `navigate` when it is set, see [ConfigProvider.md](ConfigProvider.md). A `disabled` entry stays a button |
124
124
  | `onClick` | `() => void` | Runs before `onAction` |
125
125
 
126
126
  **Slots:** `root` `trigger` `menu` `item` `itemIcon` `itemLabel` `itemShortcut` `separator` `heading`
@@ -10,7 +10,7 @@
10
10
  import { ScrollbarProvider } from '@ahrowe/ui';
11
11
 
12
12
  <ScrollbarProvider className="my-list">
13
- {items.map(item => <ListItem key={item.id} item={item} />)}
13
+ {items.map(item => <Row key={item.id} item={item} />)}
14
14
  </ScrollbarProvider>
15
15
  ```
16
16
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ahrowe/ui",
3
- "version": "0.50.0",
3
+ "version": "0.52.0",
4
4
  "description": "A React UI component library with theming, CSS Modules, and TypeScript support",
5
5
  "keywords": [
6
6
  "agent",