pixelize-design-library 2.4.2-beta.62 → 2.4.2-beta.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/CHANGELOG.md +75 -2
  2. package/COMPONENT-GOTCHAS.md +25 -6
  3. package/DESIGN-GUIDE.md +12 -5
  4. package/dist/Components/Button/Button.styles.js +51 -21
  5. package/dist/Components/Card/CardProps.d.ts +2 -2
  6. package/dist/Components/ConfirmDialog/ConfirmDialog.js +2 -1
  7. package/dist/Components/CustomModulesTable/CustomModulesTable.js +6 -4
  8. package/dist/Components/CustomModulesTable/EditModuleModal.js +2 -1
  9. package/dist/Components/DatePicker/RangeDatePicker.js +2 -1
  10. package/dist/Components/DatePicker/SingleDatePicker.js +2 -1
  11. package/dist/Components/DatePicker/TimeOnlyPicker.js +2 -1
  12. package/dist/Components/DatePicker/dayStates.js +2 -1
  13. package/dist/Components/Drawer/Drawer.js +2 -1
  14. package/dist/Components/Dropdown/DropDown.js +2 -1
  15. package/dist/Components/FileUpload/FileUpload.js +9 -2
  16. package/dist/Components/FilterSidebar/FilterSidebar.js +7 -4
  17. package/dist/Components/KanbanBoard/AccountCard.js +4 -2
  18. package/dist/Components/NavigationBar/NavigationBar.js +3 -2
  19. package/dist/Components/Notification/Notification.js +4 -3
  20. package/dist/Components/NotificationBell/NotificationPanel.js +4 -3
  21. package/dist/Components/OrganizationDetails/CreateOrgModal.js +2 -1
  22. package/dist/Components/OrganizationDetails/OrganizationDetails.js +5 -3
  23. package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +7 -3
  24. package/dist/Components/SearchSelect/SearchSelect.js +42 -21
  25. package/dist/Components/SearchSelect/searchSelectNav.d.ts +13 -0
  26. package/dist/Components/SearchSelect/searchSelectNav.js +40 -0
  27. package/dist/Components/Select/SelectPopup.js +2 -1
  28. package/dist/Components/SelectSearch/SelectSearch.js +2 -1
  29. package/dist/Components/SettingRow/SettingRow.js +2 -1
  30. package/dist/Components/SettingRow/SettingsSection.js +2 -1
  31. package/dist/Components/SideBar/SecondaryBar.js +4 -3
  32. package/dist/Components/SideBar/SideBar.js +16 -13
  33. package/dist/Components/SideBar/SideBarProps.d.ts +1 -1
  34. package/dist/Components/SideBar/components/MenuItemBox.js +7 -4
  35. package/dist/Components/SideBar/components/MenuPopoverContent.js +2 -1
  36. package/dist/Components/SideBar/components/OtherApps.js +2 -1
  37. package/dist/Components/SideBar/components/PinnedSection.js +7 -4
  38. package/dist/Components/SideBar/sidebarMotion.d.ts +2 -0
  39. package/dist/Components/SideBar/sidebarMotion.js +6 -0
  40. package/dist/Components/SignInActivityTable/SignInActivityTable.js +6 -4
  41. package/dist/Components/StageProgress/StageItem.js +5 -2
  42. package/dist/Components/StageProgress/StepperStage.js +2 -2
  43. package/dist/Components/StatCard/StatCard.js +2 -1
  44. package/dist/Components/Table/Table.js +6 -2
  45. package/dist/Components/Table/components/TableActions.js +3 -2
  46. package/dist/Components/Table/filters/CompactSelect.js +2 -1
  47. package/dist/Components/Table/settings/TableSettings.js +7 -2
  48. package/dist/Components/Table/variants/classic.js +3 -2
  49. package/dist/Components/Timeline/Timeline.js +11 -4
  50. package/dist/Components/Toaster/Toaster.js +19 -8
  51. package/dist/Components/Toggle/TableToggle.js +5 -2
  52. package/dist/Components/UserDetails/AddUserModal.js +2 -1
  53. package/dist/Components/UserDetails/ChangeRoleModal.js +2 -1
  54. package/dist/Components/UserDetails/UserDetails.js +3 -1
  55. package/dist/Theme/chakra/Card.styles.d.ts +7 -1
  56. package/dist/Theme/chakra/Card.styles.js +4 -1
  57. package/dist/Theme/chakra/Menu.styles.d.ts +3 -5
  58. package/dist/Theme/chakra/Menu.styles.js +3 -0
  59. package/dist/Theme/chakra/Popover.styles.d.ts +2 -11
  60. package/dist/Theme/chakra/Popover.styles.js +2 -0
  61. package/dist/Theme/chakra/common.web.d.ts +4 -0
  62. package/dist/Theme/chakra/componentStyles.d.ts +11 -3
  63. package/dist/Theme/chakra/componentStyles.js +10 -6
  64. package/dist/Theme/chakra/motion.d.ts +1 -0
  65. package/dist/Theme/chakra/motion.js +2 -1
  66. package/dist/Theme/chakra/overlay.styles.d.ts +5 -0
  67. package/dist/Theme/chakra/overlay.styles.js +4 -1
  68. package/dist/Theme/themeProps.d.ts +4 -0
  69. package/dist/Theme/tokens/brands/index.d.ts +1 -0
  70. package/dist/Theme/tokens/brands/index.js +17 -1
  71. package/dist/Theme/tokens/brands/radiant/palette.light.js +15 -0
  72. package/dist/Theme/tokens/brands/rosewood/palette.light.js +10 -10
  73. package/dist/Theme/tokens/brands/zinc/palette.dark.d.ts +7 -29
  74. package/dist/Theme/tokens/brands/zinc/palette.dark.js +3 -35
  75. package/dist/Theme/tokens/builders/buildDarkPalette.d.ts +6 -1
  76. package/dist/Theme/tokens/builders/buildDarkPalette.js +37 -8
  77. package/dist/Theme/tokens/builders/mutedText.d.ts +1 -1
  78. package/dist/Theme/tokens/builders/mutedText.js +13 -3
  79. package/dist/Theme/tokens/builders/planeStep.d.ts +4 -0
  80. package/dist/Theme/tokens/builders/planeStep.js +20 -0
  81. package/dist/Theme/tokens/builders/planes.d.ts +4 -0
  82. package/dist/Theme/tokens/builders/planes.js +33 -0
  83. package/dist/Theme/tokens/builders/skeletonShimmer.d.ts +9 -0
  84. package/dist/Theme/tokens/builders/skeletonShimmer.js +25 -0
  85. package/dist/Theme/tokens/builders/surfaceRaised.d.ts +3 -1
  86. package/dist/Theme/tokens/builders/surfaceRaised.js +18 -8
  87. package/dist/Theme/tokens/builders/surfaceRungs.js +3 -1
  88. package/dist/Theme/tokens/primitives/index.d.ts +2 -2
  89. package/dist/Theme/tokens/primitives/index.js +4 -1
  90. package/dist/Theme/tokens/primitives/motion.d.ts +1 -0
  91. package/dist/Theme/tokens/primitives/motion.js +2 -1
  92. package/dist/Theme/tokens/primitives/shadows.d.ts +16 -0
  93. package/dist/Theme/tokens/primitives/shadows.js +56 -6
  94. package/dist/Theme/tokens/primitives/typography.js +1 -1
  95. package/dist/esm/Components/Button/Button.styles.js +54 -24
  96. package/dist/esm/Components/ConfirmDialog/ConfirmDialog.js +2 -1
  97. package/dist/esm/Components/CustomModulesTable/CustomModulesTable.js +6 -4
  98. package/dist/esm/Components/CustomModulesTable/EditModuleModal.js +2 -1
  99. package/dist/esm/Components/DatePicker/RangeDatePicker.js +2 -1
  100. package/dist/esm/Components/DatePicker/SingleDatePicker.js +2 -1
  101. package/dist/esm/Components/DatePicker/TimeOnlyPicker.js +2 -1
  102. package/dist/esm/Components/DatePicker/dayStates.js +2 -1
  103. package/dist/esm/Components/Drawer/Drawer.js +2 -1
  104. package/dist/esm/Components/Dropdown/DropDown.js +2 -1
  105. package/dist/esm/Components/FileUpload/FileUpload.js +10 -3
  106. package/dist/esm/Components/FilterSidebar/FilterSidebar.js +7 -4
  107. package/dist/esm/Components/KanbanBoard/AccountCard.js +4 -2
  108. package/dist/esm/Components/NavigationBar/NavigationBar.js +3 -2
  109. package/dist/esm/Components/Notification/Notification.js +4 -3
  110. package/dist/esm/Components/NotificationBell/NotificationPanel.js +4 -3
  111. package/dist/esm/Components/OrganizationDetails/CreateOrgModal.js +2 -1
  112. package/dist/esm/Components/OrganizationDetails/OrganizationDetails.js +5 -3
  113. package/dist/esm/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +7 -3
  114. package/dist/esm/Components/SearchSelect/SearchSelect.js +42 -21
  115. package/dist/esm/Components/SearchSelect/searchSelectNav.js +32 -0
  116. package/dist/esm/Components/Select/SelectPopup.js +2 -1
  117. package/dist/esm/Components/SelectSearch/SelectSearch.js +2 -1
  118. package/dist/esm/Components/SettingRow/SettingRow.js +2 -1
  119. package/dist/esm/Components/SettingRow/SettingsSection.js +2 -1
  120. package/dist/esm/Components/SideBar/SecondaryBar.js +4 -3
  121. package/dist/esm/Components/SideBar/SideBar.js +17 -14
  122. package/dist/esm/Components/SideBar/components/MenuItemBox.js +7 -4
  123. package/dist/esm/Components/SideBar/components/MenuPopoverContent.js +2 -1
  124. package/dist/esm/Components/SideBar/components/OtherApps.js +2 -1
  125. package/dist/esm/Components/SideBar/components/PinnedSection.js +7 -4
  126. package/dist/esm/Components/SideBar/sidebarMotion.js +3 -0
  127. package/dist/esm/Components/SignInActivityTable/SignInActivityTable.js +6 -4
  128. package/dist/esm/Components/StageProgress/StageItem.js +5 -2
  129. package/dist/esm/Components/StageProgress/StepperStage.js +2 -2
  130. package/dist/esm/Components/StatCard/StatCard.js +2 -1
  131. package/dist/esm/Components/Table/Table.js +8 -4
  132. package/dist/esm/Components/Table/components/TableActions.js +3 -2
  133. package/dist/esm/Components/Table/filters/CompactSelect.js +2 -1
  134. package/dist/esm/Components/Table/settings/TableSettings.js +8 -3
  135. package/dist/esm/Components/Table/variants/classic.js +3 -2
  136. package/dist/esm/Components/Timeline/Timeline.js +11 -4
  137. package/dist/esm/Components/Toaster/Toaster.js +20 -9
  138. package/dist/esm/Components/Toggle/TableToggle.js +5 -2
  139. package/dist/esm/Components/UserDetails/AddUserModal.js +2 -1
  140. package/dist/esm/Components/UserDetails/ChangeRoleModal.js +2 -1
  141. package/dist/esm/Components/UserDetails/UserDetails.js +3 -1
  142. package/dist/esm/Theme/chakra/Card.styles.js +4 -1
  143. package/dist/esm/Theme/chakra/Menu.styles.js +3 -0
  144. package/dist/esm/Theme/chakra/Popover.styles.js +2 -0
  145. package/dist/esm/Theme/chakra/componentStyles.js +10 -6
  146. package/dist/esm/Theme/chakra/motion.js +1 -0
  147. package/dist/esm/Theme/chakra/overlay.styles.js +3 -0
  148. package/dist/esm/Theme/tokens/brands/index.js +16 -0
  149. package/dist/esm/Theme/tokens/brands/radiant/palette.light.js +15 -0
  150. package/dist/esm/Theme/tokens/brands/rosewood/palette.light.js +10 -10
  151. package/dist/esm/Theme/tokens/brands/zinc/palette.dark.js +3 -35
  152. package/dist/esm/Theme/tokens/builders/buildDarkPalette.js +38 -9
  153. package/dist/esm/Theme/tokens/builders/mutedText.js +12 -2
  154. package/dist/esm/Theme/tokens/builders/planeStep.js +14 -0
  155. package/dist/esm/Theme/tokens/builders/planes.js +28 -0
  156. package/dist/esm/Theme/tokens/builders/skeletonShimmer.js +21 -0
  157. package/dist/esm/Theme/tokens/builders/surfaceRaised.js +16 -7
  158. package/dist/esm/Theme/tokens/builders/surfaceRungs.js +3 -1
  159. package/dist/esm/Theme/tokens/primitives/index.js +1 -1
  160. package/dist/esm/Theme/tokens/primitives/motion.js +1 -0
  161. package/dist/esm/Theme/tokens/primitives/shadows.js +54 -5
  162. package/dist/esm/Theme/tokens/primitives/typography.js +1 -1
  163. package/dist/esm/index.js +1 -0
  164. package/dist/index.d.ts +1 -0
  165. package/dist/index.js +9 -5
  166. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -18,6 +18,12 @@ next major.
18
18
 
19
19
  ### Added
20
20
 
21
+ - **`Card variant="elevated"`**: borderless, `background[50]` lifted by `shadows.card`; declares a 0 border width so it
22
+ never inherits an outline parent's rule.
23
+ - **`bandOn`, `recessOn`, `cardRule`**: plane-step helpers that return the input unchanged in light and a visible step
24
+ off the dark plane a fill or rule sits on (`raisedRule` now matches `cardRule`'s weight).
25
+ - **`buildDarkPalette`** takes an optional `{ planes: "lifted" | "flat" }` and `buildSurfaceRaised` an optional list of
26
+ filled marks to keep at 3:1.
21
27
  - **`formatDate` / `formatDateTime` / `formatDateRange`**: Intl-based date text, en-IN by default ("09 Oct 2026"),
22
28
  with `locale`, `timeZone`, `year: "never"`, `time: "12h" | "24h"` and a `fallback` (default "—") for null or
23
29
  invalid input instead of "Invalid Date". A bare `YYYY-MM-DD` is that calendar day in every zone; ranges write a
@@ -316,8 +322,8 @@ next major.
316
322
  - **`Card` `padding` is no longer Chakra's style prop** — it is omitted from the type and now takes
317
323
  the `CardPadding` steps. A consumer passing `padding={4}` gets a compile error; use `p` or `sx`.
318
324
  Staged for the next major (see Breaking); consumer blast radius not measured.
319
- - **`SideBar` default box-shadow transition is 260ms** (was 200ms) so it follows `collapseTransition`
320
- `speed="slow"`. The width transition is unchanged.
325
+ - **`SideBar` `collapseTransition` defaults to `{ speed: "base" }`** (200ms width and shadow, was 260ms).
326
+ Pass `{ speed: "slow" }` for the old pace.
321
327
  - **`StageProgress variant="stepper"` renders an `ol` of `li`** (`StepperStageProps.asListItem`).
322
328
  Visual layout is unchanged; selectors that expected a `div` list no longer match.
323
329
  - **`PdfViewer` `pdfUrl` is optional** — pass exactly one of `pdfUrl` / `getBlob`. In `getBlob` mode
@@ -373,8 +379,75 @@ next major.
373
379
  `aria-readonly`, and `m`/`mt`/`mb`/`ml`/`mr`/`mx`/`my` on the wrapper. `InputSwitch` is now a
374
380
  genuine thin wrapper — no prop it previously accepted is silently dropped.
375
381
 
382
+ ### Changed (visual)
383
+
384
+ - **Elevation follows Pebble, per mode.** `shadows.sm`/`base`/`md`/`lg` are the Pebble card-press/
385
+ card/float/dialog stacks, with new `card`, `float`, `dialog` and `sheet` role keys. Light shadows are
386
+ softer and wider; dark mode gets its own heavier black ramp, so overlays cast a visible shadow on a
387
+ dark canvas. `xs`, `xl`, `2xl`, `inner`, `none`, `darkLg` and the focus `outline` are unchanged.
388
+ - **`Menu` and `Popover` join the owned popup family:** radius `md` → `xl` (`RADIUS_ROLE.float`)
389
+ and shadow `sm` → `md` (float), like every other anchored popup. Their border stays.
390
+ - **`fonts.mono` is a real monospace stack** (`ui-monospace, SFMono-Regular, Menlo, Consolas,
391
+ monospace`). It was Inter, so code and keyboard shortcuts never aligned.
392
+ - **`Button` gray `ghost`/`outline` hover is visible.** Gray has no opacity ramp, so hover/active
393
+ take the list-row `active`/`selectedActive` steps (at least 1.15:1 on a card, all 9 brands x 2 modes)
394
+ instead of `gray.50` (1.04-1.08:1). `solid` and `gradient` hover no longer add a box-shadow; the
395
+ colour step carries hover.
396
+ - **`Toaster` status-icon pulse** animates a pseudo-element's transform and opacity (scale 1 to 1.5,
397
+ faded out by 70%, the same 900 ms one-shot) instead of `box-shadow`, so it no longer repaints every
398
+ frame. The icon chip background is the same tint composited opaque over the toast surface.
399
+ - **`Table` filter sidebar** opens on the 200 ms motion token (was 500 ms), does not animate on
400
+ mount, and is instant under reduced motion.
401
+ - **`FileUpload` image thumbnails are a keyboard-operable "Preview <file name>" button**: a new tab
402
+ stop with the library focus ring; Enter or Space opens the preview. Each image row now has two
403
+ buttons (Preview and remove), so a test that queries an unnamed `getByRole("button")` inside a row
404
+ must name the one it means.
405
+ - **`Menu` item highlight sits inside the menu.** A themed `MenuItem`/`MenuItemOption` is
406
+ `calc(100% - 2 * mx)` wide, so its hover/focus fill keeps the same 6px inset on both sides instead of
407
+ overhanging the menu's right edge by 6px. Menu size and row height are unchanged; a `MenuItem` given
408
+ its own `w`/`width` keeps that width.
409
+ - **`Skeleton` shimmer is one depth on every brand and mode**: 1.35:1 between its two colours (the
410
+ mobile library's `SKELETON_SHIMMER_CONTRAST`), was 1.34-1.58:1 in light and 1.93-1.99:1 in dark. The
411
+ end colour is `gray[300]`'s tint settled against `gray[100]`; dark skeletons pulse much more gently.
412
+ An explicit `startColor`/`endColor` still wins.
413
+
414
+ - **Motion comes from the tokens.** `SideBar`, `Notification`, `Toaster`, the Table settings sheet,
415
+ `ProfilePhotoViewer`, `TableToggle` and `StageProgress` take every duration and curve from the motion tokens
416
+ (colour fades 150ms, movement 200ms, enters on `MOTION_EASE_OUT`, exits on `MOTION_EASE_IN`). Most timings
417
+ move by under 60ms; the Table settings sheet goes from 400ms to 200ms. `Notification` cards no longer lift
418
+ 2px on hover; the shadow still deepens.
419
+ - **`Button` (solid, outline, ghost) and `IconButton` scale to 0.98 while pressed** (`MOTION_PRESS_SCALE`).
420
+ Never when disabled or loading, nor under `prefers-reduced-motion`.
421
+ - **Dark planes carry the brand hue and separate by lift.** The dark canvas takes a faint brand tint and cards
422
+ (`background[50]`) sit one step (1.16:1) above it, with overlays (`surfaceRaised`) one step (1.15:1) above
423
+ the card; every filled mark keeps 3:1 on all three. Light mode is unchanged. A brand opts out with
424
+ `buildDarkPalette(light, { planes: "flat" })`. `meadow` and `rosewood` dark `accentText` move one rung
425
+ lighter so they clear AA on selected list rows.
426
+ - **`zinc`:** muted text in light mode is `#515157` (was `#27272a`, 14.9:1), settled under a new 8:1 muted
427
+ ceiling; zinc's dark card is no longer darker than its canvas.
428
+ - **A brand's primary never reads as danger.** `radiant`'s danger colour (`red` and `semantic.error`) is
429
+ crimson and `rosewood`'s primary rotates toward raspberry; a delta-E >= 10 gate in `brandIdentity.test.ts`
430
+ covers all 9 brands in both modes.
431
+ - **`Button` solid primary paints `resolveFilledSurface`.** Only `zinc` dark moves: the primary fill goes from `#52525b` with
432
+ white ink (2.5:1 on the canvas) to `#e4e4e7` with black ink, matching `resolveFilledSurface`, the fill every other filled surface already paints.
433
+ - **Dark mode: header strips, calendar off-days and in-card rules step visibly off the lifted planes.** Table header
434
+ strips (`CustomModulesTable`, `SignInActivityTable`), `DatePicker` weekly-off cells, and the rules inside cards and
435
+ dialogs (`Table`, `SettingRow`, `SettingsSection`, `StatCard`, `Drawer`, `Modal`, `ConfirmDialog` and the account
436
+ modals) now clear 1.15:1 (bands) and 1.31:1 (rules) off their plane. Light mode is unchanged.
437
+ - **`Card` defaults to `variant="elevated"`** (borderless, `background[50]` lifted by `shadows.card`). Pass
438
+ `variant="outline"` for a Card that frames a table or a list of rows. Measured blast radius: 22 library `<Card>`
439
+ sites with no variant flip (hrms 18, account 1, tickets 3); 305 with an explicit variant are unchanged. The
440
+ `SettingsSection` danger zone keeps its red frame by taking `variant="outline"`.
441
+ - **Light page canvas (`backgroundColor.base`) sits 1.09:1 below the card on all 9 brands**, so a borderless card keeps
442
+ its top edge (zinc and slate `#fafafa` to `#f5f5f5`, lavender `#fbfafd` to `#f5f4f8`). `main` and every other token
443
+ are unchanged.
444
+
376
445
  ### Fixed
377
446
 
447
+ - **`Table` settings sheet** fades in place instead of dropping in when the user prefers reduced motion.
448
+ - **`SearchSelect`**: the Select All and Add New rows are reachable from the keyboard. Arrow keys, Home and End walk
449
+ Select All, then the options, then Add New, and Enter runs them. Both are now `role="option"` rows, so a test that
450
+ counts `getAllByRole("option")` with either row shown sees one or two more.
378
451
  - **Field helper text no longer leaves a dangling `<id>-helptext` in `aria-describedby`** when a field with an
379
452
  explicit `id` sits inside a consumer `FormControl` (`TextInput` and every field rendering
380
453
  `FieldMessage`/`HelperText`).
@@ -215,7 +215,7 @@ and wires `aria-controls` to them. Pick by that, never by the picture. A screen
215
215
 
216
216
  | Need | Component | Why not the others |
217
217
  | --- | --- | --- |
218
- | Generic bordered/padded container, no commerce semantics | `Card` | Layout wrapper with `header`/`footer` slots and a padded body — see gotcha below |
218
+ | Generic padded container (borderless by default; `variant="outline"` for a ruled one), no commerce semantics | `Card` | Layout wrapper with `header`/`footer` slots and a padded body — see gotcha below |
219
219
  | Product tile for a grid, list or rail (photo, price, rating, swatches, quick add) | `ProductCard` | Takes the same `axes` / `variants` as `ProductDetails`; for a whole page use `ProductDetails` |
220
220
  | A KPI figure with delta and sparkline | `StatCard` | Not a product or a container |
221
221
  | Subscription/pricing-tier card (plans, billing cycle, feature list) | `PaymentCard` | Takes a `Plan` object, unrelated to `options`/`productImage` |
@@ -401,7 +401,7 @@ The wrapper is deliberately not a button; make the custom component a button, or
401
401
  | `InputTextArea` / `FileUpload` / `TextInput` | Width 500px → 100% / `maxSizeKB` 5 → 5120 / no default "Placeholder" text | `width="500px"` / — (5 KB was a bug) / — |
402
402
  | `DatePicker` (no `pickerType`) | Inference is case-sensitive: `MM` is month, `mm` minutes. `dd/MM/yyyy` was misread as date+time and showed time selects; it is now date-only | `pickerType="datetime"` |
403
403
  | `EmptyState` | Title is an `h3`; image is decorative (`alt=""`, was the title) | `titleAs`, `imageAlt` |
404
- | Theme `Badge` / `Card` / field labels | Badge: pill, no uppercase, default `sm`. Card: default variant `outline`. Label colour `text[700]`; helper/error row 12px | `size`/`variant` props |
404
+ | Theme `Badge` / `Card` / field labels | Badge: pill, no uppercase, default `sm`. Card: default variant `elevated` (borderless, `shadows.card`). Label colour `text[700]`; helper/error row 12px | `size`/`variant` props |
405
405
  | `Header` | `position: sticky; top: 0`, z-index `sticky` (1100, was 1000); `rightSlot` mounts once, not per layout | — |
406
406
  | `Table` | Radius `xl`; row height 32/40/52 by density; filter button is named "Filter {label}" (tests querying "Search" break); client pagination resets to page 1 when `data.length` changes | — |
407
407
  | `KanbanBoard` | `height`/`maxH` props replace the clipping wrapper; `height="100%"` needs a parent with a definite height | — |
@@ -534,10 +534,19 @@ A popup opened inside another popup takes `zIndex="popoverNested"` (1510), never
534
534
 
535
535
  ### Your own overlay painted `background[50]` sinks into the dark canvas
536
536
 
537
- In dark mode `background[50]` equals the page canvas on 8 of 9 brands. Library dialogs, drawers,
538
- popovers and menus now paint `colors.surfaceRaised` — identical `#ffffff` in light, one elevation
539
- step up in dark. A custom panel, popover or `ModalContent bg=` in an app should read
540
- `surfaceRaised` too, and a divider inside it `raisedRule(colors)`.
537
+ In dark mode `background[50]` is the card plane, one step above the canvas; an overlay painted with it
538
+ merges into the cards under it. Library dialogs, drawers, popovers and menus paint `colors.surfaceRaised`,
539
+ one step above the card in dark and identical `#ffffff` in light. A custom panel, popover or
540
+ `ModalContent bg=` should read `surfaceRaised` too, and a divider inside it `raisedRule(colors)`.
541
+
542
+ ### Named fills nearly vanish on a dark card
543
+
544
+ In dark mode `backgroundColor.light`, `tertiary`, `medium` and `tableHeader` sit only 1.01-1.05:1 off
545
+ `background[50]`, `muted` 1.00-1.06:1 off `surfaceRaised`, and `boxborder[200]` 1.10-1.16:1 off a card and
546
+ 1.00-1.06:1 off `surfaceRaised`. Never paint a named canvas fill or raw `boxborder[200]` on a card or overlay:
547
+ use `bandOn(fill, surface)` for a header strip, hover or selection tint, `recessOn(fill, surface)` for a shaded
548
+ or off cell, `cardRule(colors)` for a rule inside a card and `raisedRule(colors)` for a rule inside an overlay.
549
+ All four return the old value unchanged in light mode.
541
550
 
542
551
  ### `Drawer` / `Modal` / `ProfileCard` drop any child that isn't a named slot — use `portalChildren`
543
552
 
@@ -1873,6 +1882,16 @@ can outgrow the column.
1873
1882
  to `null`, so put a Clear action beside it if one is needed.
1874
1883
  - For free-text chips that are not email addresses use `TagInput`: same look as `MultiSelect`, any text, with
1875
1884
  your own `validate`.
1885
+ - **Button press scale matches a real `:active` only.** A `MenuButton as={Button}` held open by Chakra's
1886
+ `data-active` keeps the darker pressed fill but does not stay at 0.98. A consumer `_active={{ transform }}`
1887
+ loses to the press rule while the pointer is down; use `variant="unstyled"` or an `sx` `&:active` with
1888
+ `!important`.
1889
+
1890
+ ### `Card` is borderless by default (`elevated`)
1891
+
1892
+ A Card that frames a table or a list of rows needs `variant="outline"`. `borderColor` alone shows nothing, because
1893
+ the default border width is 0, and the outline rule is Chakra `gray[200]`, not `boxborder[200]`. Paint the page with
1894
+ `backgroundColor.base`: on `backgroundColor.main` a borderless card can be white on white.
1876
1895
 
1877
1896
  ### `Select` / `SearchSelect` multi rows have no checkbox role
1878
1897
 
package/DESIGN-GUIDE.md CHANGED
@@ -12,15 +12,21 @@ tickets `layoutDensity.ts`), use it — it encodes these same rules. Otherwise t
12
12
 
13
13
  Calm, dense, professional SaaS admin — Linear/Stripe-dashboard, not a landing page.
14
14
 
15
- - **Hierarchy comes from type and whitespace, not boxes.** One border per surface. Never nest a
16
- bordered card inside a bordered card; inside a card, separate with spacing or a `Divider`.
15
+ - **Hierarchy comes from type and whitespace, not boxes.** One surface per level. Never nest a
16
+ card inside a card; inside a card, separate with spacing or a `Divider`.
17
17
  - **One primary action per view.** One `variant="solid"` button in the page header; everything
18
18
  else `outline` or `ghost`. The only exception is a composer's Send button.
19
19
  - **Left-aligned, scannable.** Titles and forms left-aligned; numbers right-aligned in tables.
20
20
  - **Color means something.** Neutral by default; brand color for the primary action and selection;
21
21
  semantic color only for status. No decorative gradients, no colored section backgrounds.
22
- - **Borders, not shadows, for resting surfaces.** Shadows only on floating things (menus, popovers,
23
- modals) and on hover of a card that is itself clickable.
22
+ - **Content cards float, data surfaces are ruled.** `Card` is borderless by default
23
+ (`variant="elevated"`: `background[50]` lifted by the soft `shadows.card`). Tables, filter bars,
24
+ list panes and fields keep their 1px `boxborder[200]` rule; a `Card` that frames a table or a
25
+ list of rows takes `variant="outline"`. Heavier shadows only on floating things (menus,
26
+ popovers, modals) and on hover of a card that is itself clickable.
27
+ - **Paint the page with `backgroundColor.base`.** In light mode it sits one step (1.09:1) below
28
+ the card, which is what gives a borderless card its top edge; `backgroundColor.main` is a
29
+ component surface and can be as white as the card.
24
30
 
25
31
  ## 2. Spacing (Chakra units, 1 = 4px)
26
32
 
@@ -228,7 +234,8 @@ hides its primary; when only one section is empty on a populated page, that sect
228
234
  - Reaching for `SelectV2`, `SearchSelect`, `SelectSearch` in new work — all `@deprecated`.
229
235
  One picker now: `Select` (`native={false}` for the themed, searchable, multi popup).
230
236
  `Dropdown` is the exception — it is an action menu, not a picker, and is not replaced.
231
- - A bordered card inside a bordered card; a shadow on a resting card.
237
+ - A card inside a card; a border on a content `Card` (it is borderless by default), or any resting
238
+ shadow heavier than `shadows.card`.
232
239
  - Painting a whole table cell with a status color — use a `Tag` in the cell.
233
240
  - Centered page titles, hero-sized headings, `size="lg"` buttons, or `size` props restating the default.
234
241
  - More than one solid button in a view; a destructive action without `AlertDialog`.
@@ -5,18 +5,35 @@ const accentText_1 = require("../../Theme/tokens/builders/accentText");
5
5
  const filledSurface_1 = require("../../Theme/tokens/builders/filledSurface");
6
6
  const gradientInk_1 = require("../../Theme/tokens/builders/gradientInk");
7
7
  const focusRing_styles_1 = require("../../Theme/chakra/focusRing.styles");
8
+ const rowStates_1 = require("../../Theme/tokens/builders/rowStates");
8
9
  const motion_1 = require("../../Theme/chakra/motion");
9
10
  const primitives_1 = require("../../Theme/tokens/primitives");
11
+ const BUTTON_TRANSITION = [
12
+ (0, primitives_1.transitionFor)(["background-color", "border-color", "color", "box-shadow", "filter"]),
13
+ (0, primitives_1.transitionFor)(["transform"], "fast", "out"),
14
+ ].join(", ");
15
+ const PRESS = {
16
+ [motion_1.MOTION_OK_QUERY]: {
17
+ "&:active:not(:disabled):not([data-loading]):not([aria-disabled=true])": {
18
+ transform: `scale(${primitives_1.MOTION_PRESS_SCALE})`,
19
+ },
20
+ },
21
+ };
10
22
  const controlSize = (size) => {
11
23
  const { height, fontSize, paddingX } = primitives_1.BUTTON_SIZES[size];
12
24
  return { h: height, minW: height, fontSize, px: paddingX };
13
25
  };
14
26
  // NOTE: [500] alone measures ~4.2 on a dark canvas — resolved per-mode so outline/ghost/link text stays readable.
15
27
  const onCanvasText = (theme, colorScheme) => (0, accentText_1.accentTextOnCanvas)(theme.colors[colorScheme], theme.colors.backgroundColor.main);
16
- // NOTE: [50] alone measured ~1.04 (invisible) in both modes — opacity ramp fixes it where available.
28
+ // NOTE: [50] alone measured ~1.04 (invisible) in both modes — gray borrows the row-state steps.
17
29
  const onCanvasHoverBg = (theme, colorScheme, step) => {
18
30
  const scale = theme.colors[colorScheme];
19
- return "opacity" in scale ? scale.opacity[step] : scale[50];
31
+ if ("opacity" in scale)
32
+ return scale.opacity[step];
33
+ if (colorScheme !== "gray")
34
+ return scale[50];
35
+ const rows = (0, rowStates_1.listRowBackgrounds)(theme.colors);
36
+ return step === 16 ? rows.active : rows.selectedActive;
20
37
  };
21
38
  const swatch = (theme, colorScheme) => theme.colors[colorScheme];
22
39
  const buttonSolidRung = (theme, colorScheme) => (0, filledSurface_1.solidFillRung)(swatch(theme, colorScheme), theme.colors.white);
@@ -27,6 +44,21 @@ const darkerFill = (theme, colorScheme, step) => {
27
44
  };
28
45
  /** Label for the solid variant's filled bg — derived from THAT fill, since hover/active swap it. */
29
46
  const labelFor = (theme, fill) => (0, filledSurface_1.labelOnFill)(fill, theme.colors.white, theme.colors.black);
47
+ const solidSurface = (theme, colorScheme) => {
48
+ if (colorScheme === "primary")
49
+ return (0, filledSurface_1.resolveFilledSurface)(theme.colors.primary, theme.colors);
50
+ const fill = theme.colors[colorScheme][buttonSolidRung(theme, colorScheme)];
51
+ const hoverFill = darkerFill(theme, colorScheme, 0);
52
+ const activeFill = darkerFill(theme, colorScheme, 1);
53
+ return {
54
+ fill,
55
+ color: labelFor(theme, fill),
56
+ hoverFill,
57
+ hoverColor: labelFor(theme, hoverFill),
58
+ activeFill,
59
+ activeColor: labelFor(theme, activeFill),
60
+ };
61
+ };
30
62
  // NOTE: replaces Chakra's stock ring, which failed WCAG 1.4.11 on every brand — gated by focusRing.test.ts.
31
63
  const focusRing = (theme) => (0, focusRing_styles_1.focusVisibleStyles)(theme.colors);
32
64
  exports.Button = {
@@ -35,7 +67,7 @@ exports.Button = {
35
67
  baseStyle: ({ theme }) => ({
36
68
  borderRadius: "lg",
37
69
  fontWeight: 500,
38
- transition: (0, primitives_1.transitionFor)(["background-color", "border-color", "color", "box-shadow", "filter"]),
70
+ transition: BUTTON_TRANSITION,
39
71
  ...(0, motion_1.reducedMotionSx)(),
40
72
  _disabled: {
41
73
  opacity: 0.6,
@@ -45,35 +77,32 @@ exports.Button = {
45
77
  }),
46
78
  variants: {
47
79
  solid: ({ theme, colorScheme = "primary" }) => {
48
- const fill = theme.colors[colorScheme][buttonSolidRung(theme, colorScheme)];
49
- const hoverFill = darkerFill(theme, colorScheme, 0);
50
- const activeFill = darkerFill(theme, colorScheme, 1);
51
- const hoverLabel = labelFor(theme, hoverFill);
80
+ const s = solidSurface(theme, colorScheme);
52
81
  return {
53
- bg: fill,
54
- color: labelFor(theme, fill),
82
+ bg: s.fill,
83
+ color: s.color,
55
84
  _hover: {
56
- bg: hoverFill,
57
- color: hoverLabel,
58
- boxShadow: "sm",
85
+ bg: s.hoverFill,
86
+ color: s.hoverColor,
59
87
  _disabled: {
60
- bg: hoverFill, // keep hover color on loading
61
- color: hoverLabel,
88
+ bg: s.hoverFill, // keep hover color on loading
89
+ color: s.hoverColor,
62
90
  },
63
91
  },
64
92
  _active: {
65
- bg: activeFill,
66
- color: labelFor(theme, activeFill),
93
+ bg: s.activeFill,
94
+ color: s.activeColor,
67
95
  boxShadow: "none",
68
96
  },
69
97
  _loading: {
70
- bg: hoverFill, // keep hover color while loading
71
- color: hoverLabel,
98
+ bg: s.hoverFill, // keep hover color while loading
99
+ color: s.hoverColor,
72
100
  _hover: {
73
- bg: hoverFill,
74
- color: hoverLabel,
101
+ bg: s.hoverFill,
102
+ color: s.hoverColor,
75
103
  },
76
104
  },
105
+ ...PRESS,
77
106
  ...focusRing(theme),
78
107
  };
79
108
  },
@@ -94,6 +123,7 @@ exports.Button = {
94
123
  _loading: {
95
124
  color: ink,
96
125
  },
126
+ ...PRESS,
97
127
  ...focusRing(theme),
98
128
  };
99
129
  },
@@ -107,6 +137,7 @@ exports.Button = {
107
137
  _active: {
108
138
  bg: onCanvasHoverBg(theme, colorScheme, 24),
109
139
  },
140
+ ...PRESS,
110
141
  ...focusRing(theme),
111
142
  }),
112
143
  link: ({ theme, colorScheme = "primary" }) => ({
@@ -143,7 +174,6 @@ exports.Button = {
143
174
  _hover: {
144
175
  bgImage: bg,
145
176
  filter: "brightness(0.92)",
146
- boxShadow: "md",
147
177
  _disabled: { bgImage: bg, filter: "none" },
148
178
  },
149
179
  _active: {
@@ -8,14 +8,14 @@ type DeadDividerProps = {
8
8
  };
9
9
  /** Padding steps: "none" flush, "2xs" 0.375rem, "xs" 0.75rem all round, "sm" / "md" / "lg" match `size`. */
10
10
  export type CardPadding = "none" | "2xs" | "xs" | "sm" | "md" | "lg";
11
- /** Themed outline surface with optional header/footer slots; children and direction/align/justify apply to the body. */
11
+ /** Themed card surface (outline rule or borderless elevated) with optional header/footer slots; direction/align/justify apply to the body. */
12
12
  export type CardProps = Omit<ChakraCardProps, "children" | "variant" | "size" | "color" | "colorScheme" | "direction" | "align" | "justify" | "padding"> & DeadDividerProps & {
13
13
  /** Rendered in CardHeader (semibold header ink) only when truthy. */
14
14
  header?: React.ReactNode;
15
15
  /** Rendered in CardFooter only when truthy. */
16
16
  footer?: React.ReactNode;
17
17
  children: React.ReactNode;
18
- /** Defaults to "outline", the only token-themed one; others fall back to Chakra's stock look. */
18
+ /** "elevated" (default): borderless, lifted by `shadows.card`. "outline": 1px rule, no shadow, for tables and row lists. */
19
19
  variant?: "elevated" | "outline" | "filled" | "unstyled";
20
20
  /** Padding scale for header/body/footer; defaults to "md". */
21
21
  size?: "sm" | "md" | "lg";
@@ -8,6 +8,7 @@ const react_1 = require("react");
8
8
  const react_2 = require("@chakra-ui/react");
9
9
  const lucide_react_1 = require("lucide-react");
10
10
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
11
+ const surfaceRaised_1 = require("../../Theme/tokens/builders/surfaceRaised");
11
12
  const Button_1 = __importDefault(require("../Button/Button"));
12
13
  const TextInput_1 = __importDefault(require("../Input/TextInput"));
13
14
  const ConfirmDialog = ({ isOpen, onClose, onConfirm, title, children, icon, iconBg, iconColor, tone = "destructive", cancelLabel = "Cancel", confirmLabel = "Confirm", confirmIcon, isConfirmLoading = false, disableCancelWhilePending = true, confirmationText, confirmationLabel, bodyLayout = "flush", bodySpacing = 4, actionsPt = 0, focusCancelOnOpen = true, isCentered = true, closeOnEsc, closeOnOverlayClick, }) => {
@@ -18,6 +19,6 @@ const ConfirmDialog = ({ isOpen, onClose, onConfirm, title, children, icon, icon
18
19
  const isConfirmDisabled = isConfirmLoading || (requiresTypedConfirmation && typedText !== confirmationText);
19
20
  const actions = ((0, jsx_runtime_1.jsxs)(react_2.HStack, { justifyContent: "flex-end", spacing: 3, pt: actionsPt, children: [(0, jsx_runtime_1.jsx)(Button_1.default, { ref: cancelRef, label: cancelLabel, onClick: onClose, variant: "outline", colorScheme: "gray", size: "sm", isDisabled: disableCancelWhilePending && isConfirmLoading }), (0, jsx_runtime_1.jsx)(Button_1.default, { label: confirmLabel, onClick: onConfirm, colorScheme: tone === "destructive" ? "red" : "primary", size: "sm", isLoading: isConfirmLoading, isDisabled: isConfirmDisabled, leftIcon: confirmIcon })] }));
20
21
  const body = requiresTypedConfirmation ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [children, (0, jsx_runtime_1.jsx)(TextInput_1.default, { label: confirmationLabel, value: typedText, onChange: (event) => setTypedText(event.target.value) })] })) : (children);
21
- return ((0, jsx_runtime_1.jsxs)(react_2.Modal, { isOpen: isOpen, onClose: onClose, isCentered: isCentered, closeOnEsc: closeOnEsc, closeOnOverlayClick: closeOnOverlayClick, initialFocusRef: focusCancelOnOpen ? cancelRef : undefined, children: [(0, jsx_runtime_1.jsx)(react_2.ModalOverlay, { backdropFilter: "blur(4px)" }), (0, jsx_runtime_1.jsxs)(react_2.ModalContent, { bg: colors.surfaceRaised, borderRadius: "xl", overflow: "hidden", children: [(0, jsx_runtime_1.jsxs)(react_2.ModalHeader, { borderBottom: "1px solid", borderColor: colors.boxborder[200], display: "flex", alignItems: "center", gap: 3, children: [(0, jsx_runtime_1.jsx)(react_2.Flex, { align: "center", justify: "center", boxSize: "36px", borderRadius: "full", bg: iconBg, color: iconColor, children: icon !== null && icon !== void 0 ? icon : (0, jsx_runtime_1.jsx)(lucide_react_1.AlertTriangle, { size: 18 }) }), (0, jsx_runtime_1.jsx)(react_2.Text, { fontSize: "1.05rem", fontWeight: 600, children: title })] }), (0, jsx_runtime_1.jsx)(react_2.ModalCloseButton, {}), (0, jsx_runtime_1.jsx)(react_2.ModalBody, { py: 6, children: bodyLayout === "stack" ? ((0, jsx_runtime_1.jsxs)(react_2.VStack, { spacing: bodySpacing, align: "stretch", children: [body, actions] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [body, actions] })) })] })] }));
22
+ return ((0, jsx_runtime_1.jsxs)(react_2.Modal, { isOpen: isOpen, onClose: onClose, isCentered: isCentered, closeOnEsc: closeOnEsc, closeOnOverlayClick: closeOnOverlayClick, initialFocusRef: focusCancelOnOpen ? cancelRef : undefined, children: [(0, jsx_runtime_1.jsx)(react_2.ModalOverlay, { backdropFilter: "blur(4px)" }), (0, jsx_runtime_1.jsxs)(react_2.ModalContent, { bg: colors.surfaceRaised, borderRadius: "xl", overflow: "hidden", children: [(0, jsx_runtime_1.jsxs)(react_2.ModalHeader, { borderBottom: "1px solid", borderColor: (0, surfaceRaised_1.raisedRule)(colors), display: "flex", alignItems: "center", gap: 3, children: [(0, jsx_runtime_1.jsx)(react_2.Flex, { align: "center", justify: "center", boxSize: "36px", borderRadius: "full", bg: iconBg, color: iconColor, children: icon !== null && icon !== void 0 ? icon : (0, jsx_runtime_1.jsx)(lucide_react_1.AlertTriangle, { size: 18 }) }), (0, jsx_runtime_1.jsx)(react_2.Text, { fontSize: "1.05rem", fontWeight: 600, children: title })] }), (0, jsx_runtime_1.jsx)(react_2.ModalCloseButton, {}), (0, jsx_runtime_1.jsx)(react_2.ModalBody, { py: 6, children: bodyLayout === "stack" ? ((0, jsx_runtime_1.jsxs)(react_2.VStack, { spacing: bodySpacing, align: "stretch", children: [body, actions] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [body, actions] })) })] })] }));
22
23
  };
23
24
  exports.default = ConfirmDialog;
@@ -8,6 +8,7 @@ const react_1 = require("react");
8
8
  const react_2 = require("@chakra-ui/react");
9
9
  const lucide_react_1 = require("lucide-react");
10
10
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
11
+ const planeStep_1 = require("../../Theme/tokens/builders/planeStep");
11
12
  const Button_1 = __importDefault(require("../Button/Button"));
12
13
  const EmptyState_1 = __importDefault(require("../EmptyState/EmptyState"));
13
14
  const EditModuleModal_1 = __importDefault(require("./EditModuleModal"));
@@ -34,20 +35,21 @@ const CustomModulesTable = ({ modules, isLoading = false, isUpdating = false, is
34
35
  const labels = (0, react_1.useMemo)(() => ({ ...DEFAULT_LABELS, ...labelOverrides }), [labelOverrides]);
35
36
  const [editTarget, setEditTarget] = (0, react_1.useState)(null);
36
37
  const [deleteTarget, setDeleteTarget] = (0, react_1.useState)(null);
37
- const border = colors.boxborder[200];
38
+ const edge = colors.boxborder[200];
38
39
  const surface = colors.background[50];
40
+ const rule = (0, planeStep_1.cardRule)(colors);
39
41
  const muted = colors.textMuted;
40
42
  const heading = colors.text[800];
41
- const headBg = colors.backgroundColor.tableHeader;
43
+ const headBg = (0, planeStep_1.bandOn)(colors.backgroundColor.tableHeader, surface);
42
44
  const thStyle = {
43
45
  fontSize: "0.7rem",
44
46
  textTransform: "uppercase",
45
47
  letterSpacing: "0.04em",
46
48
  color: muted,
47
- borderColor: border,
49
+ borderColor: rule,
48
50
  py: 3,
49
51
  };
50
- return ((0, jsx_runtime_1.jsxs)(react_2.Box, { backgroundColor: surface, borderRadius: "xl", border: "1px solid", borderColor: border, boxShadow: "sm", overflow: "hidden", children: [(0, jsx_runtime_1.jsx)(react_2.Flex, { px: 4, py: 3, borderBottom: "1px solid", borderColor: border, alignItems: "center", children: (0, jsx_runtime_1.jsx)(react_2.Heading, { size: "sm", fontWeight: 600, color: heading, children: labels.title }) }), (0, jsx_runtime_1.jsx)(react_2.Box, { overflowX: "auto", children: isLoading ? ((0, jsx_runtime_1.jsx)(react_2.VStack, { spacing: 3, p: 4, align: "stretch", children: Array.from({ length: 4 }).map((_, idx) => ((0, jsx_runtime_1.jsx)(react_2.Skeleton, { height: "18px", borderRadius: "md", startColor: colors.gray[100], endColor: colors.gray[400] }, idx))) })) : modules.length === 0 ? ((0, jsx_runtime_1.jsx)(EmptyState_1.default, { icon: lucide_react_1.Boxes, title: labels.noModules, size: "sm", minH: "180px" })) : ((0, jsx_runtime_1.jsxs)(react_2.Table, { variant: "simple", size: "sm", children: [(0, jsx_runtime_1.jsx)(react_2.Thead, { bg: headBg, children: (0, jsx_runtime_1.jsxs)(react_2.Tr, { children: [(0, jsx_runtime_1.jsx)(react_2.Th, { ...thStyle, children: labels.moduleName }), (0, jsx_runtime_1.jsx)(react_2.Th, { ...thStyle, children: labels.moduleOwner }), (0, jsx_runtime_1.jsx)(react_2.Th, { ...thStyle, textAlign: "right", children: labels.action })] }) }), (0, jsx_runtime_1.jsx)(react_2.Tbody, { children: modules.map((item) => ((0, jsx_runtime_1.jsxs)(react_2.Tr, { _hover: { bg: headBg }, transition: "background 0.15s ease", children: [(0, jsx_runtime_1.jsx)(react_2.Td, { borderColor: border, fontSize: "sm", fontWeight: 500, color: heading, maxW: "220px", children: (0, jsx_runtime_1.jsx)(react_2.Tooltip, { label: item.moduleName, hasArrow: true, openDelay: 400, children: (0, jsx_runtime_1.jsx)(react_2.Text, { noOfLines: 1, children: item.moduleName }) }) }), (0, jsx_runtime_1.jsx)(react_2.Td, { borderColor: border, fontSize: "sm", color: muted, children: item.ownerLabel || "—" }), (0, jsx_runtime_1.jsx)(react_2.Td, { borderColor: border, children: (0, jsx_runtime_1.jsxs)(react_2.HStack, { spacing: 2, justifyContent: "flex-end", children: [(0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "outline", colorScheme: "primary", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 13 }), label: labels.edit, onClick: () => setEditTarget(item) }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "outline", colorScheme: "red", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 13 }), label: labels.delete, onClick: () => setDeleteTarget(item) })] }) })] }, item.module_id))) })] })) }), (0, jsx_runtime_1.jsx)(EditModuleModal_1.default, { isOpen: editTarget !== null, onClose: () => setEditTarget(null), initialName: (_a = editTarget === null || editTarget === void 0 ? void 0 : editTarget.moduleName) !== null && _a !== void 0 ? _a : "", isLoading: isUpdating, onSubmit: async (name) => {
52
+ return ((0, jsx_runtime_1.jsxs)(react_2.Box, { backgroundColor: surface, borderRadius: "xl", border: "1px solid", borderColor: edge, boxShadow: "sm", overflow: "hidden", children: [(0, jsx_runtime_1.jsx)(react_2.Flex, { px: 4, py: 3, borderBottom: "1px solid", borderColor: rule, alignItems: "center", children: (0, jsx_runtime_1.jsx)(react_2.Heading, { size: "sm", fontWeight: 600, color: heading, children: labels.title }) }), (0, jsx_runtime_1.jsx)(react_2.Box, { overflowX: "auto", children: isLoading ? ((0, jsx_runtime_1.jsx)(react_2.VStack, { spacing: 3, p: 4, align: "stretch", children: Array.from({ length: 4 }).map((_, idx) => ((0, jsx_runtime_1.jsx)(react_2.Skeleton, { height: "18px", borderRadius: "md", startColor: colors.gray[100], endColor: colors.gray[400] }, idx))) })) : modules.length === 0 ? ((0, jsx_runtime_1.jsx)(EmptyState_1.default, { icon: lucide_react_1.Boxes, title: labels.noModules, size: "sm", minH: "180px" })) : ((0, jsx_runtime_1.jsxs)(react_2.Table, { variant: "simple", size: "sm", children: [(0, jsx_runtime_1.jsx)(react_2.Thead, { bg: headBg, children: (0, jsx_runtime_1.jsxs)(react_2.Tr, { children: [(0, jsx_runtime_1.jsx)(react_2.Th, { ...thStyle, children: labels.moduleName }), (0, jsx_runtime_1.jsx)(react_2.Th, { ...thStyle, children: labels.moduleOwner }), (0, jsx_runtime_1.jsx)(react_2.Th, { ...thStyle, textAlign: "right", children: labels.action })] }) }), (0, jsx_runtime_1.jsx)(react_2.Tbody, { children: modules.map((item) => ((0, jsx_runtime_1.jsxs)(react_2.Tr, { _hover: { bg: headBg }, transition: "background 0.15s ease", children: [(0, jsx_runtime_1.jsx)(react_2.Td, { borderColor: rule, fontSize: "sm", fontWeight: 500, color: heading, maxW: "220px", children: (0, jsx_runtime_1.jsx)(react_2.Tooltip, { label: item.moduleName, hasArrow: true, openDelay: 400, children: (0, jsx_runtime_1.jsx)(react_2.Text, { noOfLines: 1, children: item.moduleName }) }) }), (0, jsx_runtime_1.jsx)(react_2.Td, { borderColor: rule, fontSize: "sm", color: muted, children: item.ownerLabel || "—" }), (0, jsx_runtime_1.jsx)(react_2.Td, { borderColor: rule, children: (0, jsx_runtime_1.jsxs)(react_2.HStack, { spacing: 2, justifyContent: "flex-end", children: [(0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "outline", colorScheme: "primary", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.Pencil, { size: 13 }), label: labels.edit, onClick: () => setEditTarget(item) }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "outline", colorScheme: "red", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 13 }), label: labels.delete, onClick: () => setDeleteTarget(item) })] }) })] }, item.module_id))) })] })) }), (0, jsx_runtime_1.jsx)(EditModuleModal_1.default, { isOpen: editTarget !== null, onClose: () => setEditTarget(null), initialName: (_a = editTarget === null || editTarget === void 0 ? void 0 : editTarget.moduleName) !== null && _a !== void 0 ? _a : "", isLoading: isUpdating, onSubmit: async (name) => {
51
53
  if (editTarget) {
52
54
  await (onUpdateModule === null || onUpdateModule === void 0 ? void 0 : onUpdateModule({
53
55
  moduleId: editTarget.module_id,
@@ -7,6 +7,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const react_1 = require("react");
8
8
  const react_2 = require("@chakra-ui/react");
9
9
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
10
+ const surfaceRaised_1 = require("../../Theme/tokens/builders/surfaceRaised");
10
11
  const Button_1 = __importDefault(require("../Button/Button"));
11
12
  const EditModuleModal = ({ isOpen, onClose, initialName, isLoading, onSubmit, labels, }) => {
12
13
  const { colors } = (0, useCustomTheme_1.useCustomTheme)();
@@ -15,7 +16,7 @@ const EditModuleModal = ({ isOpen, onClose, initialName, isLoading, onSubmit, la
15
16
  if (isOpen)
16
17
  setName(initialName);
17
18
  }, [isOpen, initialName]);
18
- return ((0, jsx_runtime_1.jsxs)(react_2.Modal, { isOpen: isOpen, onClose: onClose, isCentered: true, children: [(0, jsx_runtime_1.jsx)(react_2.ModalOverlay, { backdropFilter: "blur(4px)" }), (0, jsx_runtime_1.jsxs)(react_2.ModalContent, { borderRadius: "xl", overflow: "hidden", bg: colors.surfaceRaised, children: [(0, jsx_runtime_1.jsx)(react_2.ModalHeader, { borderBottom: "1px solid", borderColor: colors.boxborder[200], fontSize: "1.05rem", fontWeight: 600, children: labels.editModuleTitle }), (0, jsx_runtime_1.jsx)(react_2.ModalCloseButton, {}), (0, jsx_runtime_1.jsxs)(react_2.ModalBody, { py: 6, children: [(0, jsx_runtime_1.jsx)(react_2.Input, { value: name, onChange: (e) => setName(e.target.value), placeholder: labels.moduleNamePlaceholder, "aria-label": labels.moduleNamePlaceholder,
19
+ return ((0, jsx_runtime_1.jsxs)(react_2.Modal, { isOpen: isOpen, onClose: onClose, isCentered: true, children: [(0, jsx_runtime_1.jsx)(react_2.ModalOverlay, { backdropFilter: "blur(4px)" }), (0, jsx_runtime_1.jsxs)(react_2.ModalContent, { borderRadius: "xl", overflow: "hidden", bg: colors.surfaceRaised, children: [(0, jsx_runtime_1.jsx)(react_2.ModalHeader, { borderBottom: "1px solid", borderColor: (0, surfaceRaised_1.raisedRule)(colors), fontSize: "1.05rem", fontWeight: 600, children: labels.editModuleTitle }), (0, jsx_runtime_1.jsx)(react_2.ModalCloseButton, {}), (0, jsx_runtime_1.jsxs)(react_2.ModalBody, { py: 6, children: [(0, jsx_runtime_1.jsx)(react_2.Input, { value: name, onChange: (e) => setName(e.target.value), placeholder: labels.moduleNamePlaceholder, "aria-label": labels.moduleNamePlaceholder,
19
20
  // NOTE: [200] is the decorative divider rung — a real control's outline needs 1.4.11's 3:1, from [800].
20
21
  borderColor: colors.boxborder[500], mb: 5 }), (0, jsx_runtime_1.jsxs)(react_2.HStack, { justifyContent: "flex-end", spacing: 3, children: [(0, jsx_runtime_1.jsx)(Button_1.default, { label: labels.cancel, onClick: onClose, variant: "outline", colorScheme: "gray", size: "sm" }), (0, jsx_runtime_1.jsx)(Button_1.default, { label: labels.update, onClick: () => onSubmit(name.trim()), colorScheme: "primary", size: "sm", isLoading: isLoading, isDisabled: !name.trim() })] })] })] })] }));
21
22
  };
@@ -49,6 +49,7 @@ const useFieldIds_1 = require("../Common/useFieldIds");
49
49
  const pickerField_1 = require("./pickerField");
50
50
  const CalendarPanel_1 = __importDefault(require("./CalendarPanel"));
51
51
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
52
+ const surfaceRaised_1 = require("../../Theme/tokens/builders/surfaceRaised");
52
53
  const controlSizes_1 = require("../../Theme/tokens/primitives/controlSizes");
53
54
  const textInputIconSize_1 = require("../Input/textInputIconSize");
54
55
  const TimePicker_1 = __importDefault(require("./TimePicker"));
@@ -264,7 +265,7 @@ exports.RangeDatePicker = (0, react_1.forwardRef)(function RangeDatePicker(props
264
265
  return;
265
266
  }
266
267
  setTempRangeEnd(setTimeFrom(endTimeBaseDate, t));
267
- }, dateFormat: timePickerFormat, isDisabled: disabled || !tempRangeEnd, size: sizeKey }))] })] })), (0, jsx_runtime_1.jsxs)(react_2.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], children: [(0, jsx_runtime_1.jsx)(Button_1.default, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: handleClear, children: "Clear" }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: "sm", variant: "gradient", onClick: requestClose, children: "Apply" })] })] }) }) })] }), (0, jsx_runtime_1.jsx)(FieldMessage_1.default, { error: error, errorMessage: errorMessage, helperText: helperText, helperId: ids.helperId, errorId: ids.errorId })] }));
268
+ }, dateFormat: timePickerFormat, isDisabled: disabled || !tempRangeEnd, size: sizeKey }))] })] })), (0, jsx_runtime_1.jsxs)(react_2.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: (0, surfaceRaised_1.raisedRule)(theme.colors), children: [(0, jsx_runtime_1.jsx)(Button_1.default, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: handleClear, children: "Clear" }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: "sm", variant: "gradient", onClick: requestClose, children: "Apply" })] })] }) }) })] }), (0, jsx_runtime_1.jsx)(FieldMessage_1.default, { error: error, errorMessage: errorMessage, helperText: helperText, helperId: ids.helperId, errorId: ids.errorId })] }));
268
269
  });
269
270
  exports.RangeDatePicker.displayName = "RangeDatePicker";
270
271
  exports.default = exports.RangeDatePicker;
@@ -44,6 +44,7 @@ const date_fns_1 = require("date-fns");
44
44
  const lucide_react_1 = require("lucide-react");
45
45
  const Button_1 = __importDefault(require("../Button/Button"));
46
46
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
47
+ const surfaceRaised_1 = require("../../Theme/tokens/builders/surfaceRaised");
47
48
  const controlSizes_1 = require("../../Theme/tokens/primitives/controlSizes");
48
49
  const textInputIconSize_1 = require("../Input/textInputIconSize");
49
50
  const DatePickerProps_1 = require("./DatePickerProps");
@@ -1026,7 +1027,7 @@ function SingleDatePickerInner(props, ref) {
1026
1027
  setTempDate(updatedDate);
1027
1028
  setInputValue((0, date_fns_1.format)(updatedDate, resolvedDateFormat));
1028
1029
  setIsTyping(false);
1029
- }, isDisabled: disabled })) })), (0, jsx_runtime_1.jsxs)(react_2.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], children: [(0, jsx_runtime_1.jsx)(Button_1.default, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: () => {
1030
+ }, isDisabled: disabled })) })), (0, jsx_runtime_1.jsxs)(react_2.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", mt: 3, pt: 3, borderTop: "1px solid", borderColor: (0, surfaceRaised_1.raisedRule)(theme.colors), children: [(0, jsx_runtime_1.jsx)(Button_1.default, { size: "sm", variant: "ghost", colorScheme: "gray", onClick: () => {
1030
1031
  setTempDate(null);
1031
1032
  requestClose(null);
1032
1033
  }, children: "Clear" }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: "sm", variant: "gradient", onClick: () => requestClose(), children: "Apply" })] })] }) }) })] }), (0, jsx_runtime_1.jsx)(FieldMessage_1.default, { error: error, errorMessage: errorMessage, helperText: helperText, helperId: ids.helperId, errorId: ids.errorId })] }));
@@ -52,6 +52,7 @@ const TimePickerInput_1 = require("./TimePickerInput");
52
52
  const PickerPortal_1 = __importStar(require("./PickerPortal"));
53
53
  const useExclusiveOverlay_1 = require("../../Hooks/useExclusiveOverlay");
54
54
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
55
+ const surfaceRaised_1 = require("../../Theme/tokens/builders/surfaceRaised");
55
56
  const controlSizes_1 = require("../../Theme/tokens/primitives/controlSizes");
56
57
  const formatToPlaceholder = (formatStr) => formatStr.replace(/h{1,2}/gi, "HH").replace(/m{1,2}/gi, "mm").replace(/a{1,2}/gi, "AM");
57
58
  function TimeOnlyPickerInner(props, ref) {
@@ -138,7 +139,7 @@ function TimeOnlyPickerInner(props, ref) {
138
139
  openPicker();
139
140
  }, error: error, size: sizeKey }) }) }) }), (0, jsx_runtime_1.jsx)(PickerPortal_1.default, { isMounted: pickerPortal.isMounted, children: (0, jsx_runtime_1.jsx)(react_2.PopoverContent, { width: "auto", p: 4, ref: popoverRef, boxShadow: "lg", borderRadius: "xl", bg: theme.colors.surfaceRaised, children: (0, jsx_runtime_1.jsxs)(react_2.PopoverBody, { children: [(0, jsx_runtime_1.jsx)(TimePicker_1.default, { date: resolvedTempDate, dateFormat: dateFormat, onChange: (updatedDate) => {
140
141
  handleTimePickerChange(updatedDate);
141
- } }), (0, jsx_runtime_1.jsxs)(react_2.Box, { display: "flex", justifyContent: "space-between", mt: 4, pt: 4, borderTop: "1px solid", borderColor: theme.colors.boxborder[200], children: [(0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "ghost", onClick: handleClear, children: "Clear" }), (0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", colorScheme: "primary", onClick: handleOk, children: "OK" })] })] }) }) })] }), (0, jsx_runtime_1.jsx)(FieldMessage_1.default, { error: error, errorMessage: errorMessage, helperText: helperText, helperId: ids.helperId, errorId: ids.errorId })] }));
142
+ } }), (0, jsx_runtime_1.jsxs)(react_2.Box, { display: "flex", justifyContent: "space-between", mt: 4, pt: 4, borderTop: "1px solid", borderColor: (0, surfaceRaised_1.raisedRule)(theme.colors), children: [(0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", variant: "ghost", onClick: handleClear, children: "Clear" }), (0, jsx_runtime_1.jsx)(react_2.Button, { size: "sm", colorScheme: "primary", onClick: handleOk, children: "OK" })] })] }) }) })] }), (0, jsx_runtime_1.jsx)(FieldMessage_1.default, { error: error, errorMessage: errorMessage, helperText: helperText, helperId: ids.helperId, errorId: ids.errorId })] }));
142
143
  }
143
144
  exports.TimeOnlyPicker = (0, react_1.forwardRef)(TimeOnlyPickerInner);
144
145
  exports.TimeOnlyPicker.displayName = "TimeOnlyPicker";
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dayAccessibleName = exports.describeDayStates = exports.dayStateClassName = exports.DAY_CLASS = exports.resolveDayStateVisual = exports.isDayStateKey = exports.DAY_STATE_KEYS = void 0;
4
+ const planeStep_1 = require("../../Theme/tokens/builders/planeStep");
4
5
  // Ascending precedence — when a day carries several keys, a later one's visual overrides an earlier one's.
5
6
  exports.DAY_STATE_KEYS = [
6
7
  "weekly-off",
@@ -12,7 +13,7 @@ exports.DAY_STATE_KEYS = [
12
13
  // NOTE: token roles per THEME-CONTRACT.md, not raw rungs — e.g. holiday uses semanticText, never semantic[500].
13
14
  const VISUALS = {
14
15
  "weekly-off": (colors) => ({
15
- cellBg: colors.backgroundColor.muted,
16
+ cellBg: (0, planeStep_1.recessOn)(colors.backgroundColor.muted, colors.surfaceRaised),
16
17
  color: colors.textMuted,
17
18
  }),
18
19
  holiday: (colors) => ({
@@ -8,6 +8,7 @@ exports.default = Drawer;
8
8
  const jsx_runtime_1 = require("react/jsx-runtime");
9
9
  const react_1 = __importDefault(require("react"));
10
10
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
11
+ const surfaceRaised_1 = require("../../Theme/tokens/builders/surfaceRaised");
11
12
  const warnDroppedSlotChildren_1 = require("../Modal/warnDroppedSlotChildren");
12
13
  const react_2 = require("@chakra-ui/react");
13
14
  const DrawerHeader = ({ children }) => {
@@ -45,5 +46,5 @@ function Drawer({ isOpen, onClose, placement = "right", size = "xl", id, variant
45
46
  const bodySlot = findSlot(children, exports.DrawerBody);
46
47
  const footerSlot = findSlot(children, exports.DrawerFooter);
47
48
  (0, warnDroppedSlotChildren_1.warnDroppedSlotChildren)("Drawer", children, [exports.DrawerHeader, exports.DrawerBody, exports.DrawerFooter]);
48
- return ((0, jsx_runtime_1.jsxs)(react_2.Drawer, { isOpen: isOpen, placement: placement, onClose: onClose, size: size, variant: (_a = variant !== null && variant !== void 0 ? variant : vaiant) !== null && _a !== void 0 ? _a : "solid", id: id, initialFocusRef: initialFocusRef, finalFocusRef: finalFocusRef, closeOnOverlayClick: closeOnOverlayClick, closeOnEsc: closeOnEsc, children: [(0, jsx_runtime_1.jsx)(react_2.DrawerOverlay, {}), (0, jsx_runtime_1.jsxs)(react_2.DrawerContent, { ...contentProps, children: [!hideCloseButton && (0, jsx_runtime_1.jsx)(react_2.DrawerCloseButton, {}), headerSlot && ((0, jsx_runtime_1.jsx)(react_2.DrawerHeader, { borderBottomWidth: "1px", borderColor: colors.boxborder[200], ...headerSlot.props, children: headerSlot })), (0, jsx_runtime_1.jsx)(react_2.DrawerBody, { ...((_b = bodySlot === null || bodySlot === void 0 ? void 0 : bodySlot.props) !== null && _b !== void 0 ? _b : {}), children: bodySlot }), footerSlot && ((0, jsx_runtime_1.jsx)(react_2.DrawerFooter, { borderTopWidth: "1px", borderColor: colors.boxborder[200], ...footerSlot.props, children: footerSlot })), portalChildren] })] }));
49
+ return ((0, jsx_runtime_1.jsxs)(react_2.Drawer, { isOpen: isOpen, placement: placement, onClose: onClose, size: size, variant: (_a = variant !== null && variant !== void 0 ? variant : vaiant) !== null && _a !== void 0 ? _a : "solid", id: id, initialFocusRef: initialFocusRef, finalFocusRef: finalFocusRef, closeOnOverlayClick: closeOnOverlayClick, closeOnEsc: closeOnEsc, children: [(0, jsx_runtime_1.jsx)(react_2.DrawerOverlay, {}), (0, jsx_runtime_1.jsxs)(react_2.DrawerContent, { ...contentProps, children: [!hideCloseButton && (0, jsx_runtime_1.jsx)(react_2.DrawerCloseButton, {}), headerSlot && ((0, jsx_runtime_1.jsx)(react_2.DrawerHeader, { borderBottomWidth: "1px", borderColor: (0, surfaceRaised_1.raisedRule)(colors), ...headerSlot.props, children: headerSlot })), (0, jsx_runtime_1.jsx)(react_2.DrawerBody, { ...((_b = bodySlot === null || bodySlot === void 0 ? void 0 : bodySlot.props) !== null && _b !== void 0 ? _b : {}), children: bodySlot }), footerSlot && ((0, jsx_runtime_1.jsx)(react_2.DrawerFooter, { borderTopWidth: "1px", borderColor: (0, surfaceRaised_1.raisedRule)(colors), ...footerSlot.props, children: footerSlot })), portalChildren] })] }));
49
50
  }
@@ -5,6 +5,7 @@ const react_1 = require("react");
5
5
  const react_2 = require("@chakra-ui/react");
6
6
  const framer_motion_1 = require("framer-motion");
7
7
  const useCustomTheme_1 = require("../../Theme/useCustomTheme");
8
+ const surfaceRaised_1 = require("../../Theme/tokens/builders/surfaceRaised");
8
9
  const scrollbar_1 = require("../../Theme/tokens/builders/scrollbar");
9
10
  const rowStates_1 = require("../../Theme/tokens/builders/rowStates");
10
11
  const useExclusiveOverlay_1 = require("../../Hooks/useExclusiveOverlay");
@@ -259,7 +260,7 @@ const Dropdown = (0, react_1.forwardRef)(({ dropDownButtonStyle, ButtonText, opt
259
260
  color: theme.colors.accentText,
260
261
  boxShadow: `inset 0 0 0 2px ${theme.colors.focusRing.ring}`,
261
262
  }, borderBottom: divider
262
- ? `${borderWidths_1.BORDER_WIDTHS.hairline} solid ${theme.colors.boxborder[200]}`
263
+ ? `${borderWidths_1.BORDER_WIDTHS.hairline} solid ${(0, surfaceRaised_1.raisedRule)(theme.colors)}`
263
264
  : undefined, sx: { "&:last-child": { borderBottom: "none" }, ...(0, motion_2.reducedMotionSx)() }, style: ItemStyle, fontWeight: 500, children: [option.image && ((0, jsx_runtime_1.jsx)(react_2.Box, { as: option.image, boxSize: s.img, flexShrink: 0, color: theme.colors.textMuted, style: ImageStyle })), (0, jsx_runtime_1.jsx)(react_2.Box, { as: "span", fontSize: rowSpec.fontSize, isTruncated: true, style: LabelStyle, children: option.label })] }, option.id))) }));
264
265
  };
265
266
  return ((0, jsx_runtime_1.jsxs)(react_2.Box, { ref: dropdownRef, position: "relative", display: "inline-block", children: [dropDownToggleOption(), isOpen && ((0, jsx_runtime_1.jsx)(react_2.Portal, { children: (0, jsx_runtime_1.jsx)(MotionBox, { ref: setMenuRef, position: "fixed", zIndex: "popover", initial: prefersReducedMotion ? false : { opacity: 0, y: -6 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -6 }, style: {
@@ -54,12 +54,19 @@ const focusRing_styles_1 = require("../../Theme/chakra/focusRing.styles");
54
54
  const borderWidths_1 = require("../../Theme/tokens/primitives/borderWidths");
55
55
  const FileThumbnail = ({ file, radius, onPreview, }) => {
56
56
  const url = (0, useObjectUrl_1.useObjectUrl)(file);
57
- return ((0, jsx_runtime_1.jsxs)(react_2.Box, { boxSize: "2.5rem", cursor: "pointer", position: "relative", _hover: {
57
+ const { colors } = (0, useCustomTheme_1.useCustomTheme)();
58
+ const preview = () => url && onPreview(url);
59
+ return ((0, jsx_runtime_1.jsxs)(react_2.Box, { role: "button", tabIndex: 0, "aria-label": `Preview ${file.name}`, boxSize: "2.5rem", cursor: "pointer", position: "relative", _focusVisible: (0, focusRing_styles_1.focusVisibleRing)(colors), _hover: {
58
60
  ".hover-icon": {
59
61
  opacity: 1,
60
62
  bg: "blackAlpha.500",
61
63
  },
62
- }, onClick: () => url && onPreview(url), children: [(0, jsx_runtime_1.jsx)("img", { src: url, alt: file.name, style: {
64
+ }, onClick: preview, onKeyDown: (event) => {
65
+ if (event.key !== "Enter" && event.key !== " ")
66
+ return;
67
+ event.preventDefault();
68
+ preview();
69
+ }, children: [(0, jsx_runtime_1.jsx)("img", { src: url, alt: file.name, style: {
63
70
  width: "100%",
64
71
  height: "100%",
65
72
  objectFit: "cover",