@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 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
 
@@ -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,oFAoSE;kBAlTK,OAAO"}
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,yFA0aG;kBAtcI,OAAO"}
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,gFAuzBE;kBA76BK,OAAO"}
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,+EA+kDG;kBAtnDI,OAAO"}
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,+EAiYG;;kBAnoBmF,OAAO"}
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;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,iFA0kBG;kBAlwBI,OAAO"}
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
- "text-primary-500": !selected,
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 triggerText = committed.start && committed.end ? formatRange(committed.start, committed.end) : placeholder;
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
- "text-primary-500": !committed.start || !committed.end,
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 showClearButton = allowClear && !disabled && selectedOptions.length > 0;
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
- "text-primary-500": !selectedOptions.length,
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 && pagination && jsx(PaginationHeader, {
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, pagination && jsx(PaginationFooter, {
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
- className: cn(ICON_BUTTON, "shrink-0 md:hidden"),
363
- "aria-label": "Go back",
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"),
@@ -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
- var fetchData = /*#__PURE__*/function () {
58
- var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(url, method, data, headers) {
59
- var options,
60
- _options$needLoading,
61
- needLoading,
62
- requestInstance,
63
- response,
64
- _error,
65
- _args = arguments,
66
- _t;
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 fetchData(_x, _x2, _x3, _x4) {
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 fetchData(url, method, payload, headers, {
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(_x5, _x6, _x7) {
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);
@@ -1,10 +1,27 @@
1
1
  import { AxiosInstance, AxiosResponse, Method } from "axios";
2
- interface UseApiProps {
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,UAAU,WAAW;IACjB,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;CAC/B;AAED,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,CAiHvE,CAAC"}
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":"AAyDA;;;;GAIG;AACH;;;;;;SAmCC;AA3FD,wCAOY;AAEL,+CAKC"}
1
+ {"version":3,"file":"useFocusTrap.d.ts","sourceRoot":"","sources":["../../src/hooks/useFocusTrap.js"],"names":[],"mappings":"AAoEA;;;;GAIG;AACH;;;;;;SAmCC;AAtGD,wCAOY;AAsBL,+CAKC"}