@dreamtree-org/twreact-ui 2.0.3 → 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
@@ -432,7 +432,7 @@ Calendar-based date selection with keyboard navigation.
432
432
  **Props:**
433
433
  - `value`: Date | string
434
434
  - `onChange`: (date: Date | null) => void
435
- - `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)
436
436
  - `label`: string
437
437
  - `error`: string
438
438
  - `helperText`: ReactNode — hint below the trigger; replaced by `error` while shown
@@ -464,6 +464,7 @@ Collapsible sidebar navigation with nested items.
464
464
  **Props:**
465
465
  - `items`: Array<SidebarItem>
466
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
467
468
  - `onToggle`: () => void
468
469
  - `logo`: ReactNode
469
470
  - `user`: {name: string, email: string, avatar?: string, menuItems?: Array<MenuItem>}
@@ -518,7 +519,9 @@ Top navigation bar with user menu and notifications.
518
519
  - `onNotificationClick`: (notifications: Array<Notification>) => void
519
520
  - `onUserClick`: (user: object) => void
520
521
  - `leftIcon`: ReactNode | false
521
- - `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
522
525
 
523
526
  ```jsx
524
527
  <Navbar
@@ -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
@@ -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
@@ -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":"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) {
@@ -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"),
@@ -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 +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"}
package/dist/index.esm.js CHANGED
@@ -5976,9 +5976,29 @@ function Portal(_ref) {
5976
5976
  // Internal (not exported from the package). Shared focus management for the
5977
5977
  // overlay primitives (Drawer, Dialog, Popover, Tour, Sidebar, AppShell).
5978
5978
  var FOCUSABLE_SELECTOR = ["a[href]", "button:not([disabled])", "textarea:not([disabled])", "input:not([disabled])", "select:not([disabled])", '[tabindex]:not([tabindex="-1"])'].join(",");
5979
+ // A responsive drawer (Sidebar's `md:hidden`, AppShell's `lg:hidden`) can be
5980
+ // "open" while CSS hides it on wide viewports; there is nothing to trap then.
5981
+ // `stopAt` (exclusive) bounds the walk, so getFocusable checks only the
5982
+ // elements between a candidate and its root.
5983
+ var isDisplayNone = function isDisplayNone(el) {
5984
+ var stopAt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
5985
+ for (var node = el; node && node.nodeType === 1 && node !== stopAt; node = node.parentElement) {
5986
+ if (window.getComputedStyle(node).display === "none") return true;
5987
+ }
5988
+ return false;
5989
+ };
5990
+ // `.focus()` silently fails on an element that is not rendered (`display:none`
5991
+ // on it or an ancestor) or is `visibility:hidden` (inherited, so the element's
5992
+ // own computed value covers its ancestors). getClientRects() is not used:
5993
+ // jsdom reports empty rects for every element.
5994
+ var isRendered = function isRendered(el, root) {
5995
+ return window.getComputedStyle(el).visibility !== "hidden" && !isDisplayNone(el, root);
5996
+ };
5997
+ // Tabbable, rendered descendants of `root`, in DOM order. Used for the initial
5998
+ // focus and for the Tab trap's first/last items.
5979
5999
  var getFocusable = function getFocusable(root) {
5980
6000
  return root ? Array.from(root.querySelectorAll(FOCUSABLE_SELECTOR)).filter(function (el) {
5981
- return el.getAttribute("aria-hidden") !== "true";
6001
+ return el.getAttribute("aria-hidden") !== "true" && isRendered(el, root);
5982
6002
  }) : [];
5983
6003
  };
5984
6004
  // Only the most recently opened overlay reacts to Escape / Tab, so a Popover
@@ -5987,14 +6007,6 @@ var layerStack = [];
5987
6007
  var isTopLayer = function isTopLayer(token) {
5988
6008
  return layerStack[layerStack.length - 1] === token;
5989
6009
  };
5990
- // A responsive drawer (Sidebar's `md:hidden`, AppShell's `lg:hidden`) can be
5991
- // "open" while CSS hides it on wide viewports; there is nothing to trap then.
5992
- var isDisplayNone = function isDisplayNone(el) {
5993
- for (var node = el; node && node.nodeType === 1; node = node.parentElement) {
5994
- if (window.getComputedStyle(node).display === "none") return true;
5995
- }
5996
- return false;
5997
- };
5998
6010
  function cycleFocus(e, panel) {
5999
6011
  if (isDisplayNone(panel)) return;
6000
6012
  var focusables = getFocusable(panel);
@@ -6899,7 +6911,7 @@ var SheetCloseButton = function SheetCloseButton(_ref5) {
6899
6911
 
6900
6912
  var _excluded$Y = ["open", "isOpen", "placement", "title", "description", "showCloseButton", "haptics", "onSnapChange"],
6901
6913
  _excluded2$9 = ["className"],
6902
- _excluded3$4 = ["className"],
6914
+ _excluded3$5 = ["className"],
6903
6915
  _excluded4$3 = ["className"];
6904
6916
  function ownKeys$16(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
6905
6917
  function _objectSpread$16(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$16(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$16(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -6987,7 +6999,7 @@ var SheetHeader = /*#__PURE__*/React__default.forwardRef(function (_ref3, ref) {
6987
6999
  });
6988
7000
  var SheetBody = /*#__PURE__*/React__default.forwardRef(function (_ref4, _ref5) {
6989
7001
  var className = _ref4.className,
6990
- props = _objectWithoutProperties$1(_ref4, _excluded3$4);
7002
+ props = _objectWithoutProperties$1(_ref4, _excluded3$5);
6991
7003
  var ctx = useContext(SheetContext);
6992
7004
  var dragProps = ctx ? mergeHandlers(ctx.bodyDragProps, props) : {};
6993
7005
  return jsx("div", _objectSpread$16(_objectSpread$16(_objectSpread$16({
@@ -7497,7 +7509,8 @@ var Select = /*#__PURE__*/React__default.forwardRef(function (_ref, forwardedRef
7497
7509
  return document.removeEventListener("mousedown", handleClickOutside);
7498
7510
  };
7499
7511
  }, []);
7500
- var showClearButton = allowClear && !disabled && selectedOptions.length > 0;
7512
+ var isEmpty = selectedOptions.length === 0;
7513
+ var showClearButton = allowClear && !disabled && !isEmpty;
7501
7514
  var displayValue = function displayValue() {
7502
7515
  var _selectedOptions$;
7503
7516
  if (multiSelect) {
@@ -7755,9 +7768,12 @@ var Select = /*#__PURE__*/React__default.forwardRef(function (_ref, forwardedRef
7755
7768
  "aria-invalid": error ? true : undefined,
7756
7769
  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$3[size] || SIZE_CLASSES$3.md, {
7757
7770
  "border-error-500 focus:ring-error-500": error,
7758
- "text-primary-500": !selectedOptions.length,
7771
+ // Empty: the placeholder reads muted, like Input's
7772
+ // ::placeholder (#159). `className` still merges last.
7773
+ "text-muted": isEmpty,
7759
7774
  "pr-14": showClearButton
7760
7775
  }, className),
7776
+ "data-empty": isEmpty ? "" : undefined,
7761
7777
  onClick: function onClick() {
7762
7778
  if (!disabled) {
7763
7779
  setIsOpen(function (prev) {
@@ -18201,10 +18217,13 @@ var DatePicker = /*#__PURE__*/React__default.forwardRef(function (_ref, forwarde
18201
18217
  "aria-invalid": error ? true : undefined,
18202
18218
  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", {
18203
18219
  "border-error-500 focus:ring-error-500": error,
18204
- "text-primary-500": !selected,
18220
+ // Empty: the placeholder reads muted, like Input's
18221
+ // ::placeholder (#159). `className` still merges last.
18222
+ "text-muted": !selected,
18205
18223
  // leave room for the sibling clear button overlaid on the field
18206
18224
  "pr-16": showClear && selected
18207
18225
  }, className),
18226
+ "data-empty": selected ? undefined : "",
18208
18227
  onClick: function onClick() {
18209
18228
  return setIsOpen(function (open) {
18210
18229
  return !open;
@@ -19172,7 +19191,7 @@ ColorPicker.displayName = "ColorPicker";
19172
19191
 
19173
19192
  var _excluded$P = ["fields", "onSubmit", "defaultValues", "validationSchema", "className", "submitText", "resetText", "submitButtonClass", "resetButtonClass", "showReset", "submitDisabled"],
19174
19193
  _excluded2$7 = ["type", "name", "label", "required", "options", "placeholder", "helperText"],
19175
- _excluded3$3 = ["onChange", "ref", "value"];
19194
+ _excluded3$4 = ["onChange", "ref", "value"];
19176
19195
  function ownKeys$U(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
19177
19196
  function _objectSpread$U(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$U(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$U(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
19178
19197
  /**
@@ -19502,7 +19521,7 @@ var Form = /*#__PURE__*/forwardRef(function Form(_ref2, ref) {
19502
19521
  _onChange3 = _ref9$field.onChange,
19503
19522
  ref = _ref9$field.ref,
19504
19523
  value = _ref9$field.value,
19505
- field = _objectWithoutProperties$1(_ref9$field, _excluded3$3);
19524
+ field = _objectWithoutProperties$1(_ref9$field, _excluded3$4);
19506
19525
  return jsxs("div", {
19507
19526
  className: "w-full",
19508
19527
  children: [label && jsxs("label", {
@@ -20468,7 +20487,8 @@ var DateRangePicker = /*#__PURE__*/forwardRef(function DateRangePicker(_ref, ref
20468
20487
  }));
20469
20488
  };
20470
20489
  // Display placeholder until both start and end are committed (mandatory range).
20471
- var triggerText = committed.start && committed.end ? formatRange(committed.start, committed.end) : placeholder;
20490
+ var isEmpty = !committed.start || !committed.end;
20491
+ var triggerText = isEmpty ? placeholder : formatRange(committed.start, committed.end);
20472
20492
  var draftText = localStart && localEnd ? formatRange(localStart, localEnd) : placeholder;
20473
20493
  var presetList = Array.isArray(presets) && presets.length > 0 ? presets : null;
20474
20494
  var presetChips = presetList ? jsx("div", {
@@ -20548,9 +20568,12 @@ var DateRangePicker = /*#__PURE__*/forwardRef(function DateRangePicker(_ref, ref
20548
20568
  "aria-invalid": error ? true : undefined,
20549
20569
  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", {
20550
20570
  "border-error-500 focus:ring-error-500": error,
20551
- "text-primary-500": !committed.start || !committed.end,
20571
+ // Empty: the placeholder reads muted, like Input's
20572
+ // ::placeholder (#159). `className` still merges last.
20573
+ "text-muted": isEmpty,
20552
20574
  "pr-16": showClearButton
20553
20575
  }, className),
20576
+ "data-empty": isEmpty ? "" : undefined,
20554
20577
  onClick: function onClick() {
20555
20578
  // The trigger always toggles, even mid-pick (DTUI-35): closing
20556
20579
  // drops the uncommitted start, reopening starts from the last
@@ -25467,7 +25490,7 @@ var SearchField = /*#__PURE__*/React__default.forwardRef(function (_ref, ref) {
25467
25490
  });
25468
25491
  SearchField.displayName = "SearchField";
25469
25492
 
25470
- var _excluded$u = ["items", "collapsed", "onToggle", "className", "containerClassName", "stickyOffset", "logo", "footer", "user", "onUserClick", "drawerPosition", "isMobileOpen", "setIsMobileOpen", "showCollapsedTooltips", "tooltipOptions", "linkAs", "expandedIds", "defaultExpandedIds", "onExpandedChange", "swipeable"];
25493
+ var _excluded$u = ["items", "collapsed", "collapsible", "onToggle", "className", "containerClassName", "stickyOffset", "logo", "footer", "user", "onUserClick", "drawerPosition", "isMobileOpen", "setIsMobileOpen", "showCollapsedTooltips", "tooltipOptions", "linkAs", "expandedIds", "defaultExpandedIds", "onExpandedChange", "swipeable"];
25471
25494
  function ownKeys$z(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
25472
25495
  function _objectSpread$z(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$z(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$z(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
25473
25496
  // From `md` up the sidebar is an in-flow sticky column; below it, the same
@@ -25636,6 +25659,8 @@ var hasBadge$1 = function hasBadge(item) {
25636
25659
  * - linkAs: element type used for items with `href` (default "a"; pass Next.js Link etc.)
25637
25660
  * - collapsed: boolean (desktop collapsed)
25638
25661
  * - onToggle: function to toggle collapse
25662
+ * - collapsible: boolean (default true) — false hides the md+ collapse/expand
25663
+ * toggle (the drawer keeps its "Close navigation" button)
25639
25664
  * - expandedIds / defaultExpandedIds / onExpandedChange: open groups (ids)
25640
25665
  * - className, containerClassName, stickyOffset, logo, footer, user, onUserClick
25641
25666
  * - drawerPosition: 'left' | 'right'
@@ -25652,6 +25677,8 @@ var Sidebar = /*#__PURE__*/React__default.forwardRef(function (_ref2, ref) {
25652
25677
  items = _ref2$items === void 0 ? [] : _ref2$items,
25653
25678
  _ref2$collapsed = _ref2.collapsed,
25654
25679
  collapsed = _ref2$collapsed === void 0 ? false : _ref2$collapsed,
25680
+ _ref2$collapsible = _ref2.collapsible,
25681
+ collapsible = _ref2$collapsible === void 0 ? true : _ref2$collapsible,
25655
25682
  onToggle = _ref2.onToggle,
25656
25683
  className = _ref2.className,
25657
25684
  containerClassName = _ref2.containerClassName,
@@ -25983,6 +26010,9 @@ var Sidebar = /*#__PURE__*/React__default.forwardRef(function (_ref2, ref) {
25983
26010
  if (drawerMode && mobileOpen && setIsMobileOpen) setIsMobileOpen(false);else onToggle === null || onToggle === void 0 || onToggle();
25984
26011
  };
25985
26012
  var toggleLabel = drawerMode ? "Close navigation" : effectiveCollapsed ? "Expand sidebar" : "Collapse sidebar";
26013
+ // `collapsible={false}`: no collapse/expand toggle on md+. The drawer keeps
26014
+ // its close button (44px touch target, the drawer's only visible close).
26015
+ var showToggle = drawerMode || collapsible;
25986
26016
  var CloseChevron = isRight ? ChevronRight : ChevronLeft;
25987
26017
  var toggleIcon = drawerMode ? jsx(CloseChevron, {
25988
26018
  className: "h-5 w-5",
@@ -26049,7 +26079,7 @@ var Sidebar = /*#__PURE__*/React__default.forwardRef(function (_ref2, ref) {
26049
26079
  children: [!effectiveCollapsed && logo && jsx("div", {
26050
26080
  className: "flex min-w-0 items-center",
26051
26081
  children: logo
26052
- }), jsx("button", {
26082
+ }), showToggle && jsx("button", {
26053
26083
  type: "button",
26054
26084
  onClick: handleToggleClick,
26055
26085
  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"),
@@ -26274,7 +26304,8 @@ var Avatar = /*#__PURE__*/React__default.forwardRef(function (_ref, ref) {
26274
26304
  Avatar.displayName = 'Avatar';
26275
26305
 
26276
26306
  var _excluded$r = ["emitter", "content", "notifications"],
26277
- _excluded2$5 = ["emitter", "logo", "center", "items", "user", "notifications", "searchable", "onSearch", "leftIcon", "rightMenuContent", "onLeftIconClick", "onLoginClick", "onLogoutClick", "className", "onFetch", "isMobileOpen", "setIsMobileOpen", "sticky", "largeTitle"];
26307
+ _excluded2$5 = ["emitter", "logo", "center", "items", "user", "notifications", "searchable", "onSearch", "leftIcon", "rightMenuContent", "onLeftIconClick", "leftIconLabel", "leftIconProps", "onLoginClick", "onLogoutClick", "className", "onFetch", "isMobileOpen", "setIsMobileOpen", "sticky", "largeTitle"],
26308
+ _excluded3$3 = ["className", "onClick"];
26278
26309
  function ownKeys$w(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
26279
26310
  function _objectSpread$w(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$w(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$w(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
26280
26311
  var NO_NOTIFICATIONS = [];
@@ -26505,6 +26536,9 @@ var Navbar = /*#__PURE__*/React__default.forwardRef(function (_ref3, ref) {
26505
26536
  leftIcon = _ref3$leftIcon === void 0 ? jsx(ChevronLeft, {}) : _ref3$leftIcon,
26506
26537
  RightMenuContentProp = _ref3.rightMenuContent,
26507
26538
  onLeftIconClick = _ref3.onLeftIconClick,
26539
+ _ref3$leftIconLabel = _ref3.leftIconLabel,
26540
+ leftIconLabel = _ref3$leftIconLabel === void 0 ? "Go back" : _ref3$leftIconLabel,
26541
+ leftIconProps = _ref3.leftIconProps,
26508
26542
  _ref3$onLoginClick = _ref3.onLoginClick,
26509
26543
  onLoginClick = _ref3$onLoginClick === void 0 ? function () {
26510
26544
  return console.log("invoked onLoginClick");
@@ -26551,6 +26585,18 @@ var Navbar = /*#__PURE__*/React__default.forwardRef(function (_ref3, ref) {
26551
26585
  window.removeEventListener("resize", handleResize);
26552
26586
  };
26553
26587
  }, [handleResize]);
26588
+ // Left button: `leftIconLabel` names it ("Go back" by default; e.g. "Open
26589
+ // menu" when it opens a Sidebar drawer). `leftIconProps` lands on the
26590
+ // <button> (aria-expanded, aria-controls, data-*, …); its className merges
26591
+ // last and its onClick runs after `onLeftIconClick`.
26592
+ var _ref4 = leftIconProps || {},
26593
+ leftIconClassName = _ref4.className,
26594
+ leftIconOnClick = _ref4.onClick,
26595
+ leftIconRest = _objectWithoutProperties$1(_ref4, _excluded3$3);
26596
+ var handleLeftIconClick = function handleLeftIconClick(e) {
26597
+ onLeftIconClick === null || onLeftIconClick === void 0 || onLeftIconClick(e);
26598
+ leftIconOnClick === null || leftIconOnClick === void 0 || leftIconOnClick(e);
26599
+ };
26554
26600
  // Handle search submit
26555
26601
  var handleSearch = function handleSearch(e) {
26556
26602
  e.preventDefault();
@@ -26620,13 +26666,14 @@ var Navbar = /*#__PURE__*/React__default.forwardRef(function (_ref3, ref) {
26620
26666
  "aria-hidden": true
26621
26667
  }), jsxs("div", {
26622
26668
  className: "flex min-w-0 items-center",
26623
- children: [leftIcon !== false && jsx("button", {
26624
- onClick: onLeftIconClick,
26669
+ children: [leftIcon !== false && jsx("button", _objectSpread$w(_objectSpread$w({
26625
26670
  type: "button",
26626
- className: cn(ICON_BUTTON, "shrink-0 md:hidden"),
26627
- "aria-label": "Go back",
26671
+ "aria-label": leftIconLabel
26672
+ }, leftIconRest), {}, {
26673
+ onClick: handleLeftIconClick,
26674
+ className: cn(ICON_BUTTON, "shrink-0 md:hidden", leftIconClassName),
26628
26675
  children: leftIcon
26629
- }), logo && jsx("div", {
26676
+ })), logo && jsx("div", {
26630
26677
  className: "ml-2 min-w-0 truncate sm:ml-4 md:ml-0",
26631
26678
  children: logo
26632
26679
  })]