@ahrowe/ui 0.1.18 → 0.1.20

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.
@@ -0,0 +1,62 @@
1
+ # TabHeader
2
+
3
+ **When to use:** A horizontal row of tabs to switch between sibling views or sections — settings panels, dashboards, detail pages. Each tab carries an icon plus an optional title and subtitle.
4
+
5
+ **Import:** `import { TabHeader } from '@ahrowe/ui'`
6
+
7
+ **Mobile behaviour:** On narrow screens (≤ 640px) only the active tab keeps its title and subtitle; every other tab collapses to just its icon.
8
+
9
+ ```tsx
10
+ import { useState } from 'react';
11
+ import { TabHeader } from '@ahrowe/ui';
12
+ import type { TabHeaderTab } from '@ahrowe/ui';
13
+ import { faUser, faBell, faGear } from '@fortawesome/free-solid-svg-icons';
14
+
15
+ const TABS: TabHeaderTab[] = [
16
+ { id: 'profile', icon: faUser, title: 'Profile', subtitle: 'Your details' },
17
+ { id: 'notifications', icon: faBell, title: 'Notifications', subtitle: 'Email & push' },
18
+ { id: 'settings', icon: faGear, title: 'Settings' }, // title only
19
+ ];
20
+
21
+ function Example() {
22
+ const [tab, setTab] = useState('profile');
23
+ return <TabHeader tabs={TABS} currentTab={tab} onChange={setTab} />;
24
+ }
25
+
26
+ // Icon-only tabs
27
+ <TabHeader
28
+ tabs={[{ id: 'a', icon: faUser }, { id: 'b', icon: faGear }]}
29
+ currentTab={tab}
30
+ onChange={setTab}
31
+ />
32
+
33
+ // Disabled tab — dimmed and not selectable
34
+ <TabHeader
35
+ tabs={[
36
+ { id: 'a', icon: faUser, title: 'Profile' },
37
+ { id: 'b', icon: faGear, title: 'Billing', disabled: true },
38
+ ]}
39
+ currentTab={tab}
40
+ onChange={setTab}
41
+ />
42
+ ```
43
+
44
+ **TabHeaderProps:**
45
+
46
+ | Prop | Type | Description |
47
+ |------|------|-------------|
48
+ | `tabs` | `TabHeaderTab[]` | The tabs to render, in order |
49
+ | `currentTab` | `string` | `id` of the selected tab |
50
+ | `onChange` | `(id: string) => void` | Called with the tab `id` when a different, enabled tab is clicked |
51
+
52
+ **TabHeaderTab:**
53
+
54
+ | Field | Type | Description |
55
+ |-------|------|-------------|
56
+ | `id` | `string` | Unique identifier, matched against `currentTab` |
57
+ | `icon` | `IconDefinition` | FontAwesome icon (always visible, incl. mobile) |
58
+ | `title` | `string` | Optional title next to the icon |
59
+ | `subtitle` | `string` | Optional subtitle beneath the title |
60
+ | `disabled` | `boolean` | Dim the tab and prevent selection |
61
+
62
+ **Slots:** `root` `tab` `icon` `labels` `title` `subtitle`
@@ -3,7 +3,7 @@
3
3
  **When to use:** Efficiently render large lists or tables — thousands of rows rendered with a virtualised scroll window so only visible rows are in the DOM. Supports column definitions, row selection, multi-select, column visibility toggling, and infinite scroll.
4
4
 
5
5
  **Import:** `import { VirtualList } from '@ahrowe/ui'`
6
- **Types:** `import type { VirtualListProps, VirtualListColumn } from '@ahrowe/ui'`
6
+ **Types:** `import type { VirtualListProps, VirtualListColumn, VirtualListHandle } from '@ahrowe/ui'`
7
7
 
8
8
  ```tsx
9
9
  import { VirtualList } from '@ahrowe/ui';
@@ -105,4 +105,28 @@ const columns: VirtualListColumn<User>[] = [
105
105
  | `loadMoreThreshold` | `number` | Distance from bottom that triggers `onLoadMore` (default `100`) |
106
106
  | `isLoading` | `boolean` | Replaces list body with a full-height spinner |
107
107
 
108
+ **Imperative handle (`ref`):**
109
+
110
+ Pass a `ref` typed as `VirtualListHandle` to control the list imperatively:
111
+
112
+ ```tsx
113
+ import { useRef } from 'react';
114
+ import { VirtualList } from '@ahrowe/ui';
115
+ import type { VirtualListHandle } from '@ahrowe/ui';
116
+
117
+ const listRef = useRef<VirtualListHandle>(null);
118
+
119
+ <VirtualList ref={listRef} items={items} columns={columns} height={600} />;
120
+
121
+ listRef.current?.scrollToKey(user.id, { align: 'center' });
122
+ ```
123
+
124
+ | Method | Signature | Description |
125
+ |--------|-----------|-------------|
126
+ | `scrollToIndex` | `(index, options?) => void` | Scroll so the row at `index` is visible. `options`: `{ align?: 'start' \| 'center' \| 'end'; behavior?: ScrollBehavior }` |
127
+ | `scrollToKey` | `(key, options?) => void` | Scroll to the row whose `getItemKey` matches `key` (no-op if not found) |
128
+ | `scrollToTop` | `(options?) => void` | Scroll back to the top |
129
+ | `getScrollElement` | `() => HTMLDivElement \| null` | The underlying scroll container, for advanced use |
130
+ | `recalculateColumns` | `() => void` | Re-measure `fit` columns on the next layout. Only needed after an out-of-band content change that doesn't flow through a new `items` array or `columns` set — those re-measure automatically, as does content first appearing in a cell |
131
+
108
132
  **Slots:** `root` `header` `headerCell` `headerToggle` `togglePopover` `toggleItem` `body` `row` `cell` `selectCell` `loadingIndicator`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ahrowe/ui",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },