@dreamtree-org/twreact-ui 2.0.2 → 2.0.4
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/README.md +9 -3
- package/ai-skills/dreamtree-ui.md +15 -3
- package/dist/ai-schema.json +25 -1
- package/dist/components/core/DatePicker.d.ts.map +1 -1
- package/dist/components/core/DateRangePicker.d.ts.map +1 -1
- package/dist/components/core/Select.d.ts.map +1 -1
- package/dist/components/core/Table/Table.d.ts.map +1 -1
- package/dist/components/navigation/Navbar.d.ts.map +1 -1
- package/dist/components/navigation/Sidebar.d.ts +2 -0
- package/dist/components/navigation/Sidebar.d.ts.map +1 -1
- package/dist/esm/components/core/DatePicker.js +4 -1
- package/dist/esm/components/core/DateRangePicker.js +6 -2
- package/dist/esm/components/core/Select.js +6 -2
- package/dist/esm/components/core/Table/Table.js +11 -3
- package/dist/esm/components/navigation/Navbar.js +23 -6
- package/dist/esm/components/navigation/Sidebar.js +9 -2
- package/dist/esm/hooks/useApi.js +37 -16
- package/dist/esm/hooks/useFocusTrap.js +21 -9
- package/dist/hooks/useApi.d.ts +18 -1
- package/dist/hooks/useApi.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/index.esm.js +121 -45
- package/dist/index.js +121 -45
- package/dist/types/index.d.ts +8 -1
- package/dist/types/index.d.ts.map +1 -1
- package/mcp/catalog.snapshot.json +51 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -285,7 +285,7 @@ Advanced select component with search, multi-select, and grouping support.
|
|
|
285
285
|
- `options`: Array<{value: any, label: string, disabled?: boolean, group?: string}> (with `grouped`: also `[{ label, options }]` groups)
|
|
286
286
|
- `value`: any | Array<any>
|
|
287
287
|
- `onChange`: (value: any) => void
|
|
288
|
-
- `placeholder`: string (default: 'Select an option...')
|
|
288
|
+
- `placeholder`: string (default: 'Select an option...') — shown muted (`text-muted`) with `data-empty` on the trigger while nothing is selected
|
|
289
289
|
- `label`: string — associated with the trigger (accessible name = label + value)
|
|
290
290
|
- `error`: string
|
|
291
291
|
- `helperText`: ReactNode — hint below the control; replaced by `error` while shown
|
|
@@ -385,6 +385,7 @@ actions, and expandable row details.
|
|
|
385
385
|
- `onSave`: ({ updatedRows, newRows, allData, tableData }) => void | Promise<allData | { data: allData } | void>
|
|
386
386
|
- `onEdit`: ({ rowKey, colKey, newValue, row, action, isNew }) => void
|
|
387
387
|
- `showSerial`: boolean (default: true)
|
|
388
|
+
- `paginationPosition`: 'top' | 'bottom' | 'both' (default: 'both') — which pager renders with `pagination`: the toolbar's compact pager, the footer, or both. `'bottom'` keeps the toolbar (search, reload, page size) without the second pager
|
|
388
389
|
- `showToolbar`: boolean (default: true) — `false` hides the toolbar (reload, page size, result count, pager header) and the column picker; interactive save controls still render
|
|
389
390
|
- `showColumnPicker`: boolean (default: true) — hide just the column-picker button and its column
|
|
390
391
|
- `wrapCells`: boolean (default: false) — let every cell wrap; a column's own `wrap` wins
|
|
@@ -431,7 +432,7 @@ Calendar-based date selection with keyboard navigation.
|
|
|
431
432
|
**Props:**
|
|
432
433
|
- `value`: Date | string
|
|
433
434
|
- `onChange`: (date: Date | null) => void
|
|
434
|
-
- `placeholder`: string (default: 'Select date...')
|
|
435
|
+
- `placeholder`: string (default: 'Select date...') — shown muted (`text-muted`) with `data-empty` on the trigger while empty (same for DateRangePicker)
|
|
435
436
|
- `label`: string
|
|
436
437
|
- `error`: string
|
|
437
438
|
- `helperText`: ReactNode — hint below the trigger; replaced by `error` while shown
|
|
@@ -463,6 +464,7 @@ Collapsible sidebar navigation with nested items.
|
|
|
463
464
|
**Props:**
|
|
464
465
|
- `items`: Array<SidebarItem>
|
|
465
466
|
- `collapsed`: boolean (default: false)
|
|
467
|
+
- `collapsible`: boolean (default: true) — `false` removes the md+ collapse/expand toggle; the phone drawer keeps its 44px "Close navigation" button
|
|
466
468
|
- `onToggle`: () => void
|
|
467
469
|
- `logo`: ReactNode
|
|
468
470
|
- `user`: {name: string, email: string, avatar?: string, menuItems?: Array<MenuItem>}
|
|
@@ -517,7 +519,9 @@ Top navigation bar with user menu and notifications.
|
|
|
517
519
|
- `onNotificationClick`: (notifications: Array<Notification>) => void
|
|
518
520
|
- `onUserClick`: (user: object) => void
|
|
519
521
|
- `leftIcon`: ReactNode | false
|
|
520
|
-
- `onLeftIconClick`: () => void
|
|
522
|
+
- `onLeftIconClick`: (event) => void
|
|
523
|
+
- `leftIconLabel`: string (default: "Go back") — the left button's accessible name, e.g. "Open navigation" when it opens a Sidebar drawer
|
|
524
|
+
- `leftIconProps`: ButtonHTMLAttributes — spread onto the left button (e.g. `aria-expanded`, `aria-controls`); `className` merges last
|
|
521
525
|
|
|
522
526
|
```jsx
|
|
523
527
|
<Navbar
|
|
@@ -885,6 +889,8 @@ fetchApi('getUser', 7);
|
|
|
885
889
|
fetchApiWith('updateUser', [7, { name: 'Ada' }]);
|
|
886
890
|
```
|
|
887
891
|
|
|
892
|
+
- `onUnauthorized(error, { apiKey, url, method })` runs once per failing request that `isUnauthorized(error)` matches (default: HTTP 401), before the promise rejects; the promise still rejects. Use it to clear the session and redirect to sign-in — see the "redirect only once" recipe in the doc.
|
|
893
|
+
|
|
888
894
|
See [doc/useApi.md](doc/useApi.md).
|
|
889
895
|
|
|
890
896
|
#### useHaptics
|
|
@@ -142,7 +142,7 @@ The library exports four kinds of things from `@dreamtree-org/twreact-ui`:
|
|
|
142
142
|
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
143
143
|
| `useTheme` | Read/write the current theme (`light | dark`); pairs with `<ThemeProvider>`. Throws if used outside the provider. |
|
|
144
144
|
| `ThemeProvider` | Provider that persists theme to `localStorage` (`dreamtree-theme`) and toggles `data-theme` and the `.dark` class on `<html>`. |
|
|
145
|
-
| `useApi` | Thin axios wrapper. Returns `{data, error, loading, lastRequest, fetchData, fetchApi, fetchApiWith}`. Accepts `BASE_URL`, `DEFAULT_HEADERS`, `apiMap
|
|
145
|
+
| `useApi` | Thin axios wrapper. Returns `{data, error, loading, lastRequest, fetchData, fetchApi, fetchApiWith}`. Accepts `BASE_URL`, `DEFAULT_HEADERS`, `apiMap`, `onUnauthorized(error, { apiKey, url, method })`, `isUnauthorized(error)` (default: 401). |
|
|
146
146
|
| `useHaptics` | Opt-in `navigator.vibrate` wrapper. Returns `{trigger(pattern), supported, reducedMotion}`; patterns `selection` / `success` / `warning` / `error`. No-op on iOS Safari, the server and under reduced motion. |
|
|
147
147
|
| `useMixins` | Bridge between component state, Redux store, and an in-memory cache. Power-user hook — prefer local React state for new code. |
|
|
148
148
|
|
|
@@ -204,7 +204,7 @@ When suggesting a component or new variant value, use this exact vocabulary.
|
|
|
204
204
|
**Blocks** are page-level patterns extracted from the products, so screens stop re-inventing them:
|
|
205
205
|
|
|
206
206
|
- `AppShell` — sidebar + top bar + mobile drawer (a left `Sheet`); pass `nav` items and `linkAs={Link}` in Next.js. `bottomNav={<FootNav … />}` adds a phone tab bar (below `md`, spacer included). Fills `min-h-dvh` and pads safe areas.
|
|
207
|
-
- `Sidebar` — every item renders as an `<a>`; give items an `href` (and `linkAs={Link}` in Next.js) so Ctrl/Cmd-click opens a new tab. Parents with `href` navigate + expand; the chevron toggles. Mark the current page `active: true` and its group opens on load (control groups with `expandedIds`/`defaultExpandedIds`/`onExpandedChange`). Top-level `group: 'Name'` adds section headings; `badge` (+ `badgeLabel: '3 unread'`) shows counts; `footer` pins links above the user block; `stickyOffset={64}` when a top bar sits above it. The mobile drawer (`isMobileOpen`/`setIsMobileOpen`) is inert when shut, closes on Escape, and opens/closes with an edge swipe (`swipeable`, default on). The content renders once (column on `md`+, drawer below), so don't render a second Sidebar for phones.
|
|
207
|
+
- `Sidebar` — every item renders as an `<a>`; give items an `href` (and `linkAs={Link}` in Next.js) so Ctrl/Cmd-click opens a new tab. Parents with `href` navigate + expand; the chevron toggles. Mark the current page `active: true` and its group opens on load (control groups with `expandedIds`/`defaultExpandedIds`/`onExpandedChange`). Top-level `group: 'Name'` adds section headings; `badge` (+ `badgeLabel: '3 unread'`) shows counts; `footer` pins links above the user block; `stickyOffset={64}` when a top bar sits above it. The mobile drawer (`isMobileOpen`/`setIsMobileOpen`) is inert when shut, closes on Escape, and opens/closes with an edge swipe (`swipeable`, default on). `collapsible={false}` drops the desktop collapse toggle (the drawer keeps "Close navigation"). Hide drawer items with real CSS if you must — the focus trap skips `display:none` / `visibility:hidden` elements. The content renders once (column on `md`+, drawer below), so don't render a second Sidebar for phones.
|
|
208
208
|
- `PageHeader` — the page's only `h1`, subtitle, one primary action, optional `back` link. `actionsPlacement="bottom"` pins the actions in a `BottomActionBar` on phones (inline on desktop).
|
|
209
209
|
- `BottomActionBar` — sticky bottom bar for a form's / checkout's primary action (`pb-safe`, `z-sticky`, rides above the on-screen keyboard via `visualViewport`). Children are the actions; `fullWidth` / `stackOnMobile` for phone layouts, `align`, `position="fixed" | "sticky"`. Put `<BottomActionBar.Spacer />` at the end of the page. Never hand-roll a `fixed bottom-0` action bar.
|
|
210
210
|
- `StatCard` — KPI tile (`label`, `value`, `icon`, `tone`, `change`).
|
|
@@ -312,7 +312,13 @@ with a `group` key (`{ value, label, group: 'Code' }`) — no need to pre-group.
|
|
|
312
312
|
`user.name` initials when `user.avatar` is missing; it fits a 390px phone.
|
|
313
313
|
`sticky` makes it a translucent sticky bar with the top safe area; `largeTitle="Inbox"`
|
|
314
314
|
adds an iOS large title that collapses on scroll. With `searchable`, phones get a
|
|
315
|
-
Search button that opens a `SearchField` sheet wired to `onSearch`.
|
|
315
|
+
Search button that opens a `SearchField` sheet wired to `onSearch`. When the left
|
|
316
|
+
button opens your Sidebar drawer (`leftIcon={<Menu />}`), name it with
|
|
317
|
+
`leftIconLabel="Open navigation"` (default "Go back") and pass
|
|
318
|
+
`leftIconProps={{ 'aria-expanded': open, 'aria-controls': 'app-sidebar' }}`.
|
|
319
|
+
|
|
320
|
+
**Select / DatePicker / DateRangePicker** show their placeholder muted (`text-muted`)
|
|
321
|
+
and set `data-empty` on the trigger while empty — don't add a muted `className` yourself.
|
|
316
322
|
|
|
317
323
|
**Tooltip** around a component (e.g. `<Button>`) in a row/grid: use
|
|
318
324
|
`customTrigger={<Button>…</Button>}` so there is one tab stop, not two. A lone
|
|
@@ -385,6 +391,12 @@ fetchApiWith('updateUser', [7, { name: 'A' }]); // apiMap.updateUser(7, {...})
|
|
|
385
391
|
`fetchApi(key, data)` always passes the map entry exactly one argument; use
|
|
386
392
|
`fetchApiWith(key, [a, b])` for multi-argument entries.
|
|
387
393
|
|
|
394
|
+
For session expiry pass `onUnauthorized: (error, { apiKey, url, method }) => …`.
|
|
395
|
+
It runs once per request that fails with a 401 (override with `isUnauthorized`),
|
|
396
|
+
before the promise rejects; the promise still rejects. Several requests can fail
|
|
397
|
+
together, so guard the redirect with a module-level `redirecting` flag and skip
|
|
398
|
+
`apiKey === 'login'`. Don't hand-roll an axios interceptor for this.
|
|
399
|
+
|
|
388
400
|
Treat `useApi` as a thin axios wrapper, not a caching/dedup layer. For
|
|
389
401
|
cache, the consumer brings their own (React Query, SWR, etc.).
|
|
390
402
|
|
package/dist/ai-schema.json
CHANGED
|
@@ -1785,7 +1785,16 @@
|
|
|
1785
1785
|
"default": "false"
|
|
1786
1786
|
},
|
|
1787
1787
|
"onLeftIconClick": {
|
|
1788
|
-
"type": "() => void",
|
|
1788
|
+
"type": "(event: React.MouseEvent<HTMLButtonElement>) => void",
|
|
1789
|
+
"required": false
|
|
1790
|
+
},
|
|
1791
|
+
"leftIconLabel": {
|
|
1792
|
+
"type": "string",
|
|
1793
|
+
"required": false,
|
|
1794
|
+
"default": "\"Go back\""
|
|
1795
|
+
},
|
|
1796
|
+
"leftIconProps": {
|
|
1797
|
+
"type": "ButtonHTMLAttributes<HTMLButtonElement> & Record<`data-${string}`, string | undefined>",
|
|
1789
1798
|
"required": false
|
|
1790
1799
|
},
|
|
1791
1800
|
"onLoginClick": {
|
|
@@ -2811,6 +2820,11 @@
|
|
|
2811
2820
|
"required": false,
|
|
2812
2821
|
"default": "false"
|
|
2813
2822
|
},
|
|
2823
|
+
"collapsible": {
|
|
2824
|
+
"type": "boolean",
|
|
2825
|
+
"required": false,
|
|
2826
|
+
"default": "true"
|
|
2827
|
+
},
|
|
2814
2828
|
"onToggle": {
|
|
2815
2829
|
"type": "() => void",
|
|
2816
2830
|
"required": false
|
|
@@ -3455,6 +3469,16 @@
|
|
|
3455
3469
|
"required": false,
|
|
3456
3470
|
"default": "false"
|
|
3457
3471
|
},
|
|
3472
|
+
"paginationPosition": {
|
|
3473
|
+
"type": "enum",
|
|
3474
|
+
"required": false,
|
|
3475
|
+
"values": [
|
|
3476
|
+
"top",
|
|
3477
|
+
"bottom",
|
|
3478
|
+
"both"
|
|
3479
|
+
],
|
|
3480
|
+
"default": "'bottom'"
|
|
3481
|
+
},
|
|
3458
3482
|
"pageSize": {
|
|
3459
3483
|
"type": "number",
|
|
3460
3484
|
"required": false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/core/DatePicker.jsx"],"names":[],"mappings":";AAsBA,
|
|
1
|
+
{"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/core/DatePicker.jsx"],"names":[],"mappings":";AAsBA,oFAuSE;kBArTK,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/core/DateRangePicker.jsx"],"names":[],"mappings":";AAoCA,
|
|
1
|
+
{"version":3,"file":"DateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/core/DateRangePicker.jsx"],"names":[],"mappings":";AAoCA,yFA6aG;kBAzcI,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/components/core/Select.jsx"],"names":[],"mappings":";AA8HA,
|
|
1
|
+
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/components/core/Select.jsx"],"names":[],"mappings":";AA8HA,gFA0zBE;kBAh7BK,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Table.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/Table.jsx"],"names":[],"mappings":";AAgDA,+
|
|
1
|
+
{"version":3,"file":"Table.d.ts","sourceRoot":"","sources":["../../../../src/components/core/Table/Table.jsx"],"names":[],"mappings":";AAgDA,+EA0lDG;kBAjoDI,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Navbar.d.ts","sourceRoot":"","sources":["../../../src/components/navigation/Navbar.jsx"],"names":[],"mappings":"AAmQA,+
|
|
1
|
+
{"version":3,"file":"Navbar.d.ts","sourceRoot":"","sources":["../../../src/components/navigation/Navbar.jsx"],"names":[],"mappings":"AAmQA,+EAkZG;;kBAppBmF,OAAO"}
|
|
@@ -12,6 +12,8 @@ export default Sidebar;
|
|
|
12
12
|
* - linkAs: element type used for items with `href` (default "a"; pass Next.js Link etc.)
|
|
13
13
|
* - collapsed: boolean (desktop collapsed)
|
|
14
14
|
* - onToggle: function to toggle collapse
|
|
15
|
+
* - collapsible: boolean (default true) — false hides the md+ collapse/expand
|
|
16
|
+
* toggle (the drawer keeps its "Close navigation" button)
|
|
15
17
|
* - expandedIds / defaultExpandedIds / onExpandedChange: open groups (ids)
|
|
16
18
|
* - className, containerClassName, stickyOffset, logo, footer, user, onUserClick
|
|
17
19
|
* - drawerPosition: 'left' | 'right'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/navigation/Sidebar.jsx"],"names":[],"mappings":"AAqBA,oCAAqC,oBAAoB,CAAC;;AAoJ1D
|
|
1
|
+
{"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/navigation/Sidebar.jsx"],"names":[],"mappings":"AAqBA,oCAAqC,oBAAoB,CAAC;;AAoJ1D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,iFAglBG;kBA1wBI,OAAO"}
|
|
@@ -210,10 +210,13 @@ var DatePicker = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
|
|
|
210
210
|
"aria-invalid": error ? true : undefined,
|
|
211
211
|
className: cn("flex w-full items-center justify-between rounded-md border border-gray-300 bg-white px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent disabled:cursor-not-allowed disabled:opacity-50", {
|
|
212
212
|
"border-error-500 focus:ring-error-500": error,
|
|
213
|
-
|
|
213
|
+
// Empty: the placeholder reads muted, like Input's
|
|
214
|
+
// ::placeholder (#159). `className` still merges last.
|
|
215
|
+
"text-muted": !selected,
|
|
214
216
|
// leave room for the sibling clear button overlaid on the field
|
|
215
217
|
"pr-16": showClear && selected
|
|
216
218
|
}, className),
|
|
219
|
+
"data-empty": selected ? undefined : "",
|
|
217
220
|
onClick: function onClick() {
|
|
218
221
|
return setIsOpen(function (open) {
|
|
219
222
|
return !open;
|
|
@@ -279,7 +279,8 @@ var DateRangePicker = /*#__PURE__*/forwardRef(function DateRangePicker(_ref, ref
|
|
|
279
279
|
}));
|
|
280
280
|
};
|
|
281
281
|
// Display placeholder until both start and end are committed (mandatory range).
|
|
282
|
-
var
|
|
282
|
+
var isEmpty = !committed.start || !committed.end;
|
|
283
|
+
var triggerText = isEmpty ? placeholder : formatRange(committed.start, committed.end);
|
|
283
284
|
var draftText = localStart && localEnd ? formatRange(localStart, localEnd) : placeholder;
|
|
284
285
|
var presetList = Array.isArray(presets) && presets.length > 0 ? presets : null;
|
|
285
286
|
var presetChips = presetList ? jsx("div", {
|
|
@@ -359,9 +360,12 @@ var DateRangePicker = /*#__PURE__*/forwardRef(function DateRangePicker(_ref, ref
|
|
|
359
360
|
"aria-invalid": error ? true : undefined,
|
|
360
361
|
className: cn("flex w-full items-center justify-between rounded-md border border-gray-300 bg-white px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent disabled:cursor-not-allowed disabled:opacity-50", {
|
|
361
362
|
"border-error-500 focus:ring-error-500": error,
|
|
362
|
-
|
|
363
|
+
// Empty: the placeholder reads muted, like Input's
|
|
364
|
+
// ::placeholder (#159). `className` still merges last.
|
|
365
|
+
"text-muted": isEmpty,
|
|
363
366
|
"pr-16": showClearButton
|
|
364
367
|
}, className),
|
|
368
|
+
"data-empty": isEmpty ? "" : undefined,
|
|
365
369
|
onClick: function onClick() {
|
|
366
370
|
// The trigger always toggles, even mid-pick (DTUI-35): closing
|
|
367
371
|
// drops the uncommitted start, reopening starts from the last
|
|
@@ -495,7 +495,8 @@ var Select = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
|
|
|
495
495
|
return document.removeEventListener("mousedown", handleClickOutside);
|
|
496
496
|
};
|
|
497
497
|
}, []);
|
|
498
|
-
var
|
|
498
|
+
var isEmpty = selectedOptions.length === 0;
|
|
499
|
+
var showClearButton = allowClear && !disabled && !isEmpty;
|
|
499
500
|
var displayValue = function displayValue() {
|
|
500
501
|
var _selectedOptions$;
|
|
501
502
|
if (multiSelect) {
|
|
@@ -753,9 +754,12 @@ var Select = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
|
|
|
753
754
|
"aria-invalid": error ? true : undefined,
|
|
754
755
|
className: cn("flex w-full items-center justify-between rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent disabled:cursor-not-allowed disabled:opacity-50", SIZE_CLASSES[size] || SIZE_CLASSES.md, {
|
|
755
756
|
"border-error-500 focus:ring-error-500": error,
|
|
756
|
-
|
|
757
|
+
// Empty: the placeholder reads muted, like Input's
|
|
758
|
+
// ::placeholder (#159). `className` still merges last.
|
|
759
|
+
"text-muted": isEmpty,
|
|
757
760
|
"pr-14": showClearButton
|
|
758
761
|
}, className),
|
|
762
|
+
"data-empty": isEmpty ? "" : undefined,
|
|
759
763
|
onClick: function onClick() {
|
|
760
764
|
if (!disabled) {
|
|
761
765
|
setIsOpen(function (prev) {
|
|
@@ -18,7 +18,7 @@ import TableRow from './TableRow.js';
|
|
|
18
18
|
import MobileCard from './MobileCard.js';
|
|
19
19
|
import FieldInput from './FieldInput.js';
|
|
20
20
|
|
|
21
|
-
var _excluded = ["data", "columns", "sortable", "filterable", "selectable", "pagination", "pageSize", "onSort", "onFilter", "onFetch", "onFilterChange", "onSelectionChange", "onRowClick", "hasDetails", "DetailsComponent", "className", "withAction", "onAction", "actions", "replaceDefaultActions", "showSerial", "cellClass", "rowClass", "globalSearch", "limitOptions", "showLimitSelector", "onLimitChange", "showReloadButton", "renderReloadButton", "onReload", "stripedRows", "theme", "responsiveBreakpoint", "showToolbar", "showColumnPicker", "wrapCells", "mobileMaxFields", "serverSide", "totalRecords", "pageNumber", "onPageChange", "TheadComponent", "TfootComponent", "interactive", "onSave", "onEdit", "onRowAdd", "onRowDelete", "editKeyBinding", "newRowPosition", "addRowRef", "onInitAddRow", "renderAddRowButton", "renderExternalAddRow", "actionMenuPresentation", "defaultMobileView", "mobileFiltersPresentation", "swipeActions", "stickyHeader"],
|
|
21
|
+
var _excluded = ["data", "columns", "sortable", "filterable", "selectable", "pagination", "paginationPosition", "pageSize", "onSort", "onFilter", "onFetch", "onFilterChange", "onSelectionChange", "onRowClick", "hasDetails", "DetailsComponent", "className", "withAction", "onAction", "actions", "replaceDefaultActions", "showSerial", "cellClass", "rowClass", "globalSearch", "limitOptions", "showLimitSelector", "onLimitChange", "showReloadButton", "renderReloadButton", "onReload", "stripedRows", "theme", "responsiveBreakpoint", "showToolbar", "showColumnPicker", "wrapCells", "mobileMaxFields", "serverSide", "totalRecords", "pageNumber", "onPageChange", "TheadComponent", "TfootComponent", "interactive", "onSave", "onEdit", "onRowAdd", "onRowDelete", "editKeyBinding", "newRowPosition", "addRowRef", "onInitAddRow", "renderAddRowButton", "renderExternalAddRow", "actionMenuPresentation", "defaultMobileView", "mobileFiltersPresentation", "swipeActions", "stickyHeader"],
|
|
22
22
|
_excluded2 = ["_key", "_isNew"];
|
|
23
23
|
var DEFAULT_DATA = [];
|
|
24
24
|
var DEFAULT_COLUMNS = [];
|
|
@@ -43,6 +43,8 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
|
|
|
43
43
|
selectable = _ref$selectable === void 0 ? false : _ref$selectable,
|
|
44
44
|
_ref$pagination = _ref.pagination,
|
|
45
45
|
pagination = _ref$pagination === void 0 ? false : _ref$pagination,
|
|
46
|
+
_ref$paginationPositi = _ref.paginationPosition,
|
|
47
|
+
paginationPosition = _ref$paginationPositi === void 0 ? "both" : _ref$paginationPositi,
|
|
46
48
|
_ref$pageSize = _ref.pageSize,
|
|
47
49
|
pageSize = _ref$pageSize === void 0 ? 25 : _ref$pageSize,
|
|
48
50
|
onSort = _ref.onSort,
|
|
@@ -1179,6 +1181,12 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
|
|
|
1179
1181
|
openSwipe: openSwipe,
|
|
1180
1182
|
setOpenSwipe: setOpenSwipe
|
|
1181
1183
|
};
|
|
1184
|
+
// Which pager(s) render when `pagination` is on: the toolbar's compact
|
|
1185
|
+
// PaginationHeader ("top"), the PaginationFooter ("bottom"), or both
|
|
1186
|
+
// (default). Unknown values fall back to "both" (#135).
|
|
1187
|
+
var pagerPosition = paginationPosition === "top" || paginationPosition === "bottom" ? paginationPosition : "both";
|
|
1188
|
+
var showHeaderPager = pagination && pagerPosition !== "bottom";
|
|
1189
|
+
var showFooterPager = pagination && pagerPosition !== "top";
|
|
1182
1190
|
var showToolbarBar = showToolbar || interactive && (isDirty || !!renderAddRowButton || !!renderExternalAddRow);
|
|
1183
1191
|
var renderAddRowClickableRow = useCallback(function () {
|
|
1184
1192
|
return jsx("tr", {
|
|
@@ -1295,7 +1303,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
|
|
|
1295
1303
|
}), showToolbar && jsxs("div", {
|
|
1296
1304
|
className: "text-sm whitespace-nowrap",
|
|
1297
1305
|
children: [resultRange.start, " - ", resultRange.end, " of ", resultRange.total, " ", "results"]
|
|
1298
|
-
}), showToolbar &&
|
|
1306
|
+
}), showToolbar && showHeaderPager && jsx(PaginationHeader, {
|
|
1299
1307
|
currentPage: pageIndex,
|
|
1300
1308
|
totalPages: totalPages,
|
|
1301
1309
|
onPageChange: handlePageChange,
|
|
@@ -1576,7 +1584,7 @@ var Table = /*#__PURE__*/forwardRef(function Table(_ref, ref) {
|
|
|
1576
1584
|
}), TfootComponent && typeof TfootComponent === "function" ? jsx(TfootComponent, {
|
|
1577
1585
|
columns: columnsState,
|
|
1578
1586
|
data: filteredData
|
|
1579
|
-
}) : TfootComponent,
|
|
1587
|
+
}) : TfootComponent, showFooterPager && jsx(PaginationFooter, {
|
|
1580
1588
|
currentPage: pageIndex,
|
|
1581
1589
|
totalPages: totalPages,
|
|
1582
1590
|
onPageChange: handlePageChange,
|
|
@@ -12,7 +12,8 @@ import { TOUCH_TARGET } from '../../utils/touchTarget.js';
|
|
|
12
12
|
import PropTypes from '../../_vendor/prop-types/index.js';
|
|
13
13
|
|
|
14
14
|
var _excluded = ["emitter", "content", "notifications"],
|
|
15
|
-
_excluded2 = ["emitter", "logo", "center", "items", "user", "notifications", "searchable", "onSearch", "leftIcon", "rightMenuContent", "onLeftIconClick", "onLoginClick", "onLogoutClick", "className", "onFetch", "isMobileOpen", "setIsMobileOpen", "sticky", "largeTitle"]
|
|
15
|
+
_excluded2 = ["emitter", "logo", "center", "items", "user", "notifications", "searchable", "onSearch", "leftIcon", "rightMenuContent", "onLeftIconClick", "leftIconLabel", "leftIconProps", "onLoginClick", "onLogoutClick", "className", "onFetch", "isMobileOpen", "setIsMobileOpen", "sticky", "largeTitle"],
|
|
16
|
+
_excluded3 = ["className", "onClick"];
|
|
16
17
|
var NO_NOTIFICATIONS = [];
|
|
17
18
|
// Icon-only bar buttons: 36px on desktop, the 44px touch target on coarse pointers.
|
|
18
19
|
var ICON_BUTTON = cn("inline-flex items-center justify-center rounded-md p-2 text-primary-400 hover:text-primary-500 hover:bg-gray-100 dark:hover:bg-gray-800", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500", TOUCH_TARGET);
|
|
@@ -241,6 +242,9 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
241
242
|
leftIcon = _ref3$leftIcon === void 0 ? jsx(ChevronLeft, {}) : _ref3$leftIcon,
|
|
242
243
|
RightMenuContentProp = _ref3.rightMenuContent,
|
|
243
244
|
onLeftIconClick = _ref3.onLeftIconClick,
|
|
245
|
+
_ref3$leftIconLabel = _ref3.leftIconLabel,
|
|
246
|
+
leftIconLabel = _ref3$leftIconLabel === void 0 ? "Go back" : _ref3$leftIconLabel,
|
|
247
|
+
leftIconProps = _ref3.leftIconProps,
|
|
244
248
|
_ref3$onLoginClick = _ref3.onLoginClick,
|
|
245
249
|
onLoginClick = _ref3$onLoginClick === void 0 ? function () {
|
|
246
250
|
return console.log("invoked onLoginClick");
|
|
@@ -287,6 +291,18 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
287
291
|
window.removeEventListener("resize", handleResize);
|
|
288
292
|
};
|
|
289
293
|
}, [handleResize]);
|
|
294
|
+
// Left button: `leftIconLabel` names it ("Go back" by default; e.g. "Open
|
|
295
|
+
// menu" when it opens a Sidebar drawer). `leftIconProps` lands on the
|
|
296
|
+
// <button> (aria-expanded, aria-controls, data-*, …); its className merges
|
|
297
|
+
// last and its onClick runs after `onLeftIconClick`.
|
|
298
|
+
var _ref4 = leftIconProps || {},
|
|
299
|
+
leftIconClassName = _ref4.className,
|
|
300
|
+
leftIconOnClick = _ref4.onClick,
|
|
301
|
+
leftIconRest = _objectWithoutProperties(_ref4, _excluded3);
|
|
302
|
+
var handleLeftIconClick = function handleLeftIconClick(e) {
|
|
303
|
+
onLeftIconClick === null || onLeftIconClick === void 0 || onLeftIconClick(e);
|
|
304
|
+
leftIconOnClick === null || leftIconOnClick === void 0 || leftIconOnClick(e);
|
|
305
|
+
};
|
|
290
306
|
// Handle search submit
|
|
291
307
|
var handleSearch = function handleSearch(e) {
|
|
292
308
|
e.preventDefault();
|
|
@@ -356,13 +372,14 @@ var Navbar = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
|
|
|
356
372
|
"aria-hidden": true
|
|
357
373
|
}), jsxs("div", {
|
|
358
374
|
className: "flex min-w-0 items-center",
|
|
359
|
-
children: [leftIcon !== false && jsx("button", {
|
|
360
|
-
onClick: onLeftIconClick,
|
|
375
|
+
children: [leftIcon !== false && jsx("button", _objectSpread2(_objectSpread2({
|
|
361
376
|
type: "button",
|
|
362
|
-
|
|
363
|
-
|
|
377
|
+
"aria-label": leftIconLabel
|
|
378
|
+
}, leftIconRest), {}, {
|
|
379
|
+
onClick: handleLeftIconClick,
|
|
380
|
+
className: cn(ICON_BUTTON, "shrink-0 md:hidden", leftIconClassName),
|
|
364
381
|
children: leftIcon
|
|
365
|
-
}), logo && jsx("div", {
|
|
382
|
+
})), logo && jsx("div", {
|
|
366
383
|
className: "ml-2 min-w-0 truncate sm:ml-4 md:ml-0",
|
|
367
384
|
children: logo
|
|
368
385
|
})]
|
|
@@ -11,7 +11,7 @@ import { useScrollLock } from '../../hooks/useScrollLock.js';
|
|
|
11
11
|
import { useMediaQuery } from '../../hooks/useMediaQuery.js';
|
|
12
12
|
import { useSheetDrag, FLICK_VELOCITY } from '../../hooks/useSheetDrag.js';
|
|
13
13
|
|
|
14
|
-
var _excluded = ["items", "collapsed", "onToggle", "className", "containerClassName", "stickyOffset", "logo", "footer", "user", "onUserClick", "drawerPosition", "isMobileOpen", "setIsMobileOpen", "showCollapsedTooltips", "tooltipOptions", "linkAs", "expandedIds", "defaultExpandedIds", "onExpandedChange", "swipeable"];
|
|
14
|
+
var _excluded = ["items", "collapsed", "collapsible", "onToggle", "className", "containerClassName", "stickyOffset", "logo", "footer", "user", "onUserClick", "drawerPosition", "isMobileOpen", "setIsMobileOpen", "showCollapsedTooltips", "tooltipOptions", "linkAs", "expandedIds", "defaultExpandedIds", "onExpandedChange", "swipeable"];
|
|
15
15
|
// From `md` up the sidebar is an in-flow sticky column; below it, the same
|
|
16
16
|
// tree becomes an off-canvas drawer (modal dialog while open).
|
|
17
17
|
var SIDEBAR_DESKTOP_QUERY = "(min-width: 768px)";
|
|
@@ -178,6 +178,8 @@ var hasBadge = function hasBadge(item) {
|
|
|
178
178
|
* - linkAs: element type used for items with `href` (default "a"; pass Next.js Link etc.)
|
|
179
179
|
* - collapsed: boolean (desktop collapsed)
|
|
180
180
|
* - onToggle: function to toggle collapse
|
|
181
|
+
* - collapsible: boolean (default true) — false hides the md+ collapse/expand
|
|
182
|
+
* toggle (the drawer keeps its "Close navigation" button)
|
|
181
183
|
* - expandedIds / defaultExpandedIds / onExpandedChange: open groups (ids)
|
|
182
184
|
* - className, containerClassName, stickyOffset, logo, footer, user, onUserClick
|
|
183
185
|
* - drawerPosition: 'left' | 'right'
|
|
@@ -194,6 +196,8 @@ var Sidebar = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
|
|
|
194
196
|
items = _ref2$items === void 0 ? [] : _ref2$items,
|
|
195
197
|
_ref2$collapsed = _ref2.collapsed,
|
|
196
198
|
collapsed = _ref2$collapsed === void 0 ? false : _ref2$collapsed,
|
|
199
|
+
_ref2$collapsible = _ref2.collapsible,
|
|
200
|
+
collapsible = _ref2$collapsible === void 0 ? true : _ref2$collapsible,
|
|
197
201
|
onToggle = _ref2.onToggle,
|
|
198
202
|
className = _ref2.className,
|
|
199
203
|
containerClassName = _ref2.containerClassName,
|
|
@@ -525,6 +529,9 @@ var Sidebar = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
|
|
|
525
529
|
if (drawerMode && mobileOpen && setIsMobileOpen) setIsMobileOpen(false);else onToggle === null || onToggle === void 0 || onToggle();
|
|
526
530
|
};
|
|
527
531
|
var toggleLabel = drawerMode ? "Close navigation" : effectiveCollapsed ? "Expand sidebar" : "Collapse sidebar";
|
|
532
|
+
// `collapsible={false}`: no collapse/expand toggle on md+. The drawer keeps
|
|
533
|
+
// its close button (44px touch target, the drawer's only visible close).
|
|
534
|
+
var showToggle = drawerMode || collapsible;
|
|
528
535
|
var CloseChevron = isRight ? ChevronRight : ChevronLeft;
|
|
529
536
|
var toggleIcon = drawerMode ? jsx(CloseChevron, {
|
|
530
537
|
className: "h-5 w-5",
|
|
@@ -591,7 +598,7 @@ var Sidebar = /*#__PURE__*/React.forwardRef(function (_ref2, ref) {
|
|
|
591
598
|
children: [!effectiveCollapsed && logo && jsx("div", {
|
|
592
599
|
className: "flex min-w-0 items-center",
|
|
593
600
|
children: logo
|
|
594
|
-
}), jsx("button", {
|
|
601
|
+
}), showToggle && jsx("button", {
|
|
595
602
|
type: "button",
|
|
596
603
|
onClick: handleToggleClick,
|
|
597
604
|
className: cn("inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-md", "hover:bg-gray-100 dark:hover:bg-gray-800", "focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"),
|
package/dist/esm/hooks/useApi.js
CHANGED
|
@@ -3,6 +3,10 @@ import { slicedToArray as _slicedToArray, asyncToGenerator as _asyncToGenerator,
|
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
import axios from 'axios';
|
|
5
5
|
|
|
6
|
+
var defaultIsUnauthorized = function defaultIsUnauthorized(error) {
|
|
7
|
+
var _error$response;
|
|
8
|
+
return (error === null || error === void 0 || (_error$response = error.response) === null || _error$response === void 0 ? void 0 : _error$response.status) === 401;
|
|
9
|
+
};
|
|
6
10
|
var useApi = function useApi() {
|
|
7
11
|
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
8
12
|
var _props$BASE_URL = props.BASE_URL,
|
|
@@ -37,7 +41,10 @@ var useApi = function useApi() {
|
|
|
37
41
|
headers: headers
|
|
38
42
|
});
|
|
39
43
|
}
|
|
40
|
-
} : _props$sendRequest
|
|
44
|
+
} : _props$sendRequest,
|
|
45
|
+
onUnauthorized = props.onUnauthorized,
|
|
46
|
+
_props$isUnauthorized = props.isUnauthorized,
|
|
47
|
+
isUnauthorized = _props$isUnauthorized === void 0 ? defaultIsUnauthorized : _props$isUnauthorized;
|
|
41
48
|
var _useState = useState(null),
|
|
42
49
|
_useState2 = _slicedToArray(_useState, 2),
|
|
43
50
|
data = _useState2[0],
|
|
@@ -54,20 +61,25 @@ var useApi = function useApi() {
|
|
|
54
61
|
_useState8 = _slicedToArray(_useState7, 2),
|
|
55
62
|
lastRequest = _useState8[0],
|
|
56
63
|
setLastRequest = _useState8[1];
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
// Runs `onUnauthorized` for a failed request. Never throws: a failing
|
|
65
|
+
// predicate or handler must not replace the request's own error.
|
|
66
|
+
var notifyUnauthorized = function notifyUnauthorized(error, request) {
|
|
67
|
+
if (!onUnauthorized) return;
|
|
68
|
+
try {
|
|
69
|
+
if (isUnauthorized(error)) onUnauthorized(error, request);
|
|
70
|
+
} catch (handlerError) {
|
|
71
|
+
// eslint-disable-next-line no-console
|
|
72
|
+
console.error('useApi: onUnauthorized / isUnauthorized threw', handlerError);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
// Single send path for fetchData and callApi, so `onUnauthorized` fires
|
|
76
|
+
// exactly once per failing request and sees the `apiKey` when there is one.
|
|
77
|
+
var request = /*#__PURE__*/function () {
|
|
78
|
+
var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(url, method, data, headers, options, apiKey) {
|
|
79
|
+
var _options$needLoading, needLoading, requestInstance, response, _error, _t;
|
|
67
80
|
return _regenerator().w(function (_context) {
|
|
68
81
|
while (1) switch (_context.p = _context.n) {
|
|
69
82
|
case 0:
|
|
70
|
-
options = _args.length > 4 && _args[4] !== undefined ? _args[4] : {};
|
|
71
83
|
_options$needLoading = options.needLoading, needLoading = _options$needLoading === void 0 ? true : _options$needLoading;
|
|
72
84
|
requestInstance = createRequestInstance(BASE_URL, DEFAULT_HEADERS);
|
|
73
85
|
if (needLoading) setLoading(true);
|
|
@@ -83,6 +95,11 @@ var useApi = function useApi() {
|
|
|
83
95
|
_t = _context.v;
|
|
84
96
|
_error = _t;
|
|
85
97
|
setError(_error);
|
|
98
|
+
notifyUnauthorized(_error, {
|
|
99
|
+
apiKey: apiKey,
|
|
100
|
+
url: url,
|
|
101
|
+
method: String(method).toUpperCase()
|
|
102
|
+
});
|
|
86
103
|
throw _error;
|
|
87
104
|
case 4:
|
|
88
105
|
_context.p = 4;
|
|
@@ -93,10 +110,14 @@ var useApi = function useApi() {
|
|
|
93
110
|
}
|
|
94
111
|
}, _callee, null, [[1, 3, 4, 5]]);
|
|
95
112
|
}));
|
|
96
|
-
return function
|
|
113
|
+
return function request(_x, _x2, _x3, _x4, _x5, _x6) {
|
|
97
114
|
return _ref.apply(this, arguments);
|
|
98
115
|
};
|
|
99
116
|
}();
|
|
117
|
+
var fetchData = function fetchData(url, method, data, headers) {
|
|
118
|
+
var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
|
|
119
|
+
return request(url, method, data, headers, options);
|
|
120
|
+
};
|
|
100
121
|
var callApi = /*#__PURE__*/function () {
|
|
101
122
|
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(apiKey, args, needLoading) {
|
|
102
123
|
var apiResolve, _apiResolve, url, method, headers, payload;
|
|
@@ -113,9 +134,9 @@ var useApi = function useApi() {
|
|
|
113
134
|
_apiResolve = apiResolve.apply(void 0, _toConsumableArray(args)), url = _apiResolve.url, method = _apiResolve.method, headers = _apiResolve.headers, payload = _apiResolve.data;
|
|
114
135
|
_context2.p = 2;
|
|
115
136
|
_context2.n = 3;
|
|
116
|
-
return
|
|
137
|
+
return request(url, method, payload, headers, {
|
|
117
138
|
needLoading: needLoading
|
|
118
|
-
});
|
|
139
|
+
}, apiKey);
|
|
119
140
|
case 3:
|
|
120
141
|
return _context2.a(2, _context2.v);
|
|
121
142
|
case 4:
|
|
@@ -127,7 +148,7 @@ var useApi = function useApi() {
|
|
|
127
148
|
}
|
|
128
149
|
}, _callee2, null, [[2,, 4, 5]]);
|
|
129
150
|
}));
|
|
130
|
-
return function callApi(
|
|
151
|
+
return function callApi(_x7, _x8, _x9) {
|
|
131
152
|
return _ref2.apply(this, arguments);
|
|
132
153
|
};
|
|
133
154
|
}();
|
|
@@ -5,9 +5,29 @@ import { useLatestRef } from './useLatestRef.js';
|
|
|
5
5
|
// Internal (not exported from the package). Shared focus management for the
|
|
6
6
|
// overlay primitives (Drawer, Dialog, Popover, Tour, Sidebar, AppShell).
|
|
7
7
|
var FOCUSABLE_SELECTOR = ["a[href]", "button:not([disabled])", "textarea:not([disabled])", "input:not([disabled])", "select:not([disabled])", '[tabindex]:not([tabindex="-1"])'].join(",");
|
|
8
|
+
// A responsive drawer (Sidebar's `md:hidden`, AppShell's `lg:hidden`) can be
|
|
9
|
+
// "open" while CSS hides it on wide viewports; there is nothing to trap then.
|
|
10
|
+
// `stopAt` (exclusive) bounds the walk, so getFocusable checks only the
|
|
11
|
+
// elements between a candidate and its root.
|
|
12
|
+
var isDisplayNone = function isDisplayNone(el) {
|
|
13
|
+
var stopAt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
14
|
+
for (var node = el; node && node.nodeType === 1 && node !== stopAt; node = node.parentElement) {
|
|
15
|
+
if (window.getComputedStyle(node).display === "none") return true;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
};
|
|
19
|
+
// `.focus()` silently fails on an element that is not rendered (`display:none`
|
|
20
|
+
// on it or an ancestor) or is `visibility:hidden` (inherited, so the element's
|
|
21
|
+
// own computed value covers its ancestors). getClientRects() is not used:
|
|
22
|
+
// jsdom reports empty rects for every element.
|
|
23
|
+
var isRendered = function isRendered(el, root) {
|
|
24
|
+
return window.getComputedStyle(el).visibility !== "hidden" && !isDisplayNone(el, root);
|
|
25
|
+
};
|
|
26
|
+
// Tabbable, rendered descendants of `root`, in DOM order. Used for the initial
|
|
27
|
+
// focus and for the Tab trap's first/last items.
|
|
8
28
|
var getFocusable = function getFocusable(root) {
|
|
9
29
|
return root ? Array.from(root.querySelectorAll(FOCUSABLE_SELECTOR)).filter(function (el) {
|
|
10
|
-
return el.getAttribute("aria-hidden") !== "true";
|
|
30
|
+
return el.getAttribute("aria-hidden") !== "true" && isRendered(el, root);
|
|
11
31
|
}) : [];
|
|
12
32
|
};
|
|
13
33
|
// Only the most recently opened overlay reacts to Escape / Tab, so a Popover
|
|
@@ -16,14 +36,6 @@ var layerStack = [];
|
|
|
16
36
|
var isTopLayer = function isTopLayer(token) {
|
|
17
37
|
return layerStack[layerStack.length - 1] === token;
|
|
18
38
|
};
|
|
19
|
-
// A responsive drawer (Sidebar's `md:hidden`, AppShell's `lg:hidden`) can be
|
|
20
|
-
// "open" while CSS hides it on wide viewports; there is nothing to trap then.
|
|
21
|
-
var isDisplayNone = function isDisplayNone(el) {
|
|
22
|
-
for (var node = el; node && node.nodeType === 1; node = node.parentElement) {
|
|
23
|
-
if (window.getComputedStyle(node).display === "none") return true;
|
|
24
|
-
}
|
|
25
|
-
return false;
|
|
26
|
-
};
|
|
27
39
|
function cycleFocus(e, panel) {
|
|
28
40
|
if (isDisplayNone(panel)) return;
|
|
29
41
|
var focusables = getFocusable(panel);
|
package/dist/hooks/useApi.d.ts
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
import { AxiosInstance, AxiosResponse, Method } from "axios";
|
|
2
|
-
|
|
2
|
+
/** The request that failed, passed to `onUnauthorized`. */
|
|
3
|
+
export interface UseApiUnauthorizedRequest {
|
|
4
|
+
/** `apiMap` key for `fetchApi` / `fetchApiWith`; `undefined` for `fetchData`. */
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
url: string;
|
|
7
|
+
/** Upper-cased HTTP method, e.g. `"GET"`. */
|
|
8
|
+
method: string;
|
|
9
|
+
}
|
|
10
|
+
export interface UseApiProps {
|
|
3
11
|
BASE_URL?: string | null;
|
|
4
12
|
DEFAULT_HEADERS?: Record<string, string>;
|
|
5
13
|
apiMap?: Record<string, (...args: any[]) => ApiConfig>;
|
|
6
14
|
createRequestInstance?: (baseURL?: string | null, defaultHeaders?: Record<string, string>) => AxiosInstance;
|
|
7
15
|
sendRequest?: (requestInstance: AxiosInstance, method: string, url: string, data?: any, headers?: Record<string, string>) => Promise<AxiosResponse>;
|
|
16
|
+
/**
|
|
17
|
+
* Called once per failing request that `isUnauthorized` matches (default:
|
|
18
|
+
* HTTP 401), before the returned promise rejects. The promise still
|
|
19
|
+
* rejects with the original error. Errors thrown here are caught and
|
|
20
|
+
* logged so they never replace the request's error.
|
|
21
|
+
*/
|
|
22
|
+
onUnauthorized?: (error: any, request: UseApiUnauthorizedRequest) => void;
|
|
23
|
+
/** Decides which errors count as unauthorized. Default: `error?.response?.status === 401`. */
|
|
24
|
+
isUnauthorized?: (error: any) => boolean;
|
|
8
25
|
}
|
|
9
26
|
interface ApiConfig {
|
|
10
27
|
url: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useApi.d.ts","sourceRoot":"","sources":["../../src/hooks/useApi.ts"],"names":[],"mappings":"AACA,OAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEpE,
|
|
1
|
+
{"version":3,"file":"useApi.d.ts","sourceRoot":"","sources":["../../src/hooks/useApi.ts"],"names":[],"mappings":"AACA,OAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEpE,2DAA2D;AAC3D,MAAM,WAAW,yBAAyB;IACtC,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,SAAS,CAAC,CAAC;IACvD,qBAAqB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,aAAa,CAAC;IAC5G,WAAW,CAAC,EAAE,CACV,eAAe,EAAE,aAAa,EAC9B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,GAAG,EACV,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/B,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,yBAAyB,KAAK,IAAI,CAAC;IAC1E,8FAA8F;IAC9F,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC;CAC5C;AAID,UAAU,SAAS;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,GAAG,CAAC;CACd;AAED,UAAU,YAAY;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,UAAU,YAAY,CAAC,CAAC,GAAG,GAAG;IAC1B,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,CACP,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,GAAG,EACV,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,OAAO,CAAC,EAAE,YAAY,KACrB,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5E,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CACtF;AAED,eAAO,MAAM,MAAM,GAAI,CAAC,GAAG,GAAG,EAAE,QAAO,WAAgB,KAAG,YAAY,CAAC,CAAC,CA2IvE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFocusTrap.d.ts","sourceRoot":"","sources":["../../src/hooks/useFocusTrap.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useFocusTrap.d.ts","sourceRoot":"","sources":["../../src/hooks/useFocusTrap.js"],"names":[],"mappings":"AAoEA;;;;GAIG;AACH;;;;;;SAmCC;AAtGD,wCAOY;AAsBL,+CAKC"}
|