@moderneinc/neo-styled-components 5.0.0-next.e88b47 → 5.0.0

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 (42) hide show
  1. package/dist/Alert/Alert.d.ts +15 -1
  2. package/dist/Badge/Badge.d.ts +16 -2
  3. package/dist/Breadcrumbs/Breadcrumbs.d.ts +0 -10
  4. package/dist/CanceledIcon/CanceledIcon.d.ts +11 -0
  5. package/dist/Checkbox/Checkbox.d.ts +5 -4
  6. package/dist/DatePickerListItem/DatePickerListItem.d.ts +2 -22
  7. package/dist/DatePickerMenu/DatePickerMenu.d.ts +2 -22
  8. package/dist/Dot/Dot.d.ts +11 -4
  9. package/dist/FilledStatusIcons/FilledStatusIcons.d.ts +41 -0
  10. package/dist/GeneralAvatar/GeneralAvatar.d.ts +1 -7
  11. package/dist/InputField/InputField.d.ts +12 -1
  12. package/dist/ListItemButton/ListItemButton.d.ts +12 -1
  13. package/dist/MenuItem/MenuItem.d.ts +31 -9
  14. package/dist/NavigationAvatar/NavigationAvatar.d.ts +1 -1
  15. package/dist/NavigationItem/NavigationItem.d.ts +21 -2
  16. package/dist/NeoAvatarCell/NeoAvatarCell.d.ts +1 -3
  17. package/dist/PageContent/PageContent.d.ts +12 -1
  18. package/dist/RadioButtonWithText/RadioButtonWithText.d.ts +2 -22
  19. package/dist/RipplingDot/RipplingDot.d.ts +12 -0
  20. package/dist/SelectField/SelectField.d.ts +64 -0
  21. package/dist/SideNav/NeoSideNavContext.d.ts +5 -0
  22. package/dist/SideNav/SideNav.d.ts +18 -25
  23. package/dist/TabPanel/TabPanel.d.ts +47 -0
  24. package/dist/Table/Table.d.ts +64 -0
  25. package/dist/Tabs/Tabs.d.ts +1 -1
  26. package/dist/Tag/Tag.d.ts +1 -2
  27. package/dist/ToggleButton/ToggleButton.d.ts +13 -18
  28. package/dist/ToggleButtonGroup/ToggleButtonGroup.d.ts +26 -0
  29. package/dist/ToggleButtonWithText/ToggleButtonWithText.d.ts +2 -22
  30. package/dist/Tooltip/Tooltip.d.ts +8 -5
  31. package/dist/TopNav/TopNav.d.ts +2 -22
  32. package/dist/TourModal/TourModal.d.ts +2 -22
  33. package/dist/TypologyControl/TypologyControl.d.ts +1 -1
  34. package/dist/VibratingDot/VibratingDot.d.ts +12 -0
  35. package/dist/index.d.ts +533 -106
  36. package/dist/index.esm.js +1042 -453
  37. package/dist/index.esm.js.map +1 -1
  38. package/dist/index.js +1060 -449
  39. package/dist/index.js.map +1 -1
  40. package/dist/utils/colorHelpers.d.ts +6 -0
  41. package/package.json +5 -5
  42. package/dist/utils/avatarColors.d.ts +0 -7
package/dist/index.esm.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { semanticColors, spacing, typography, borderRadius, colors, shadows } from '@moderneinc/neo-design';
2
+ import { semanticColors, spacing, typography, borderRadius, shadows, colors, semanticTypography } from '@moderneinc/neo-design';
3
3
  import Box from '@mui/material/Box';
4
4
  import { styled, alpha } from '@mui/material/styles';
5
5
  import Chip, { chipClasses } from '@mui/material/Chip';
6
6
  import MuiAvatar from '@mui/material/Avatar';
7
- import SvgIcon, { svgIconClasses } from '@mui/material/SvgIcon';
7
+ import SvgIcon from '@mui/material/SvgIcon';
8
8
  import Alert, { alertClasses } from '@mui/material/Alert';
9
9
  import ButtonBase, { buttonBaseClasses } from '@mui/material/ButtonBase';
10
- import React, { useContext, createContext, forwardRef, createElement, useState, useRef, useCallback, useMemo, useEffect } from 'react';
10
+ import React, { useContext, createContext, forwardRef, createElement, useState, useRef, useCallback, useMemo, useEffect, Children, isValidElement, cloneElement } from 'react';
11
11
  import IconButton, { iconButtonClasses } from '@mui/material/IconButton';
12
12
  import Breadcrumbs, { breadcrumbsClasses } from '@mui/material/Breadcrumbs';
13
13
  import Link from '@mui/material/Link';
@@ -36,7 +36,6 @@ import { pickersCalendarHeaderClasses } from '@mui/x-date-pickers/PickersCalenda
36
36
  import { PickersShortcuts } from '@mui/x-date-pickers/PickersShortcuts';
37
37
  import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
38
38
  import { dateRangePickerDayClasses } from '@mui/x-date-pickers-pro/DateRangePickerDay';
39
- import Badge, { badgeClasses } from '@mui/material/Badge';
40
39
  import LinearProgress, { linearProgressClasses } from '@mui/material/LinearProgress';
41
40
  import Paper, { paperClasses } from '@mui/material/Paper';
42
41
  import Stack from '@mui/material/Stack';
@@ -52,9 +51,16 @@ import Dialog, { dialogClasses } from '@mui/material/Dialog';
52
51
  import DialogActions, { dialogActionsClasses } from '@mui/material/DialogActions';
53
52
  import DialogContent, { dialogContentClasses } from '@mui/material/DialogContent';
54
53
  import Fab from '@mui/material/Fab';
55
- import Fade from '@mui/material/Fade';
54
+ import Fade$1 from '@mui/material/Fade';
56
55
  import Radio, { radioClasses } from '@mui/material/Radio';
56
+ import { keyframes, Box as Box$1 } from '@mui/material';
57
57
  import Skeleton from '@mui/material/Skeleton';
58
+ import MuiTable from '@mui/material/Table';
59
+ import TableBody from '@mui/material/TableBody';
60
+ import TableCell, { tableCellClasses } from '@mui/material/TableCell';
61
+ import TableContainer from '@mui/material/TableContainer';
62
+ import TableHead from '@mui/material/TableHead';
63
+ import TableRow from '@mui/material/TableRow';
58
64
  import MuiTab, { tabClasses } from '@mui/material/Tab';
59
65
  import MuiTabs, { tabsClasses } from '@mui/material/Tabs';
60
66
  import Switch, { switchClasses } from '@mui/material/Switch';
@@ -62,8 +68,37 @@ import { useTreeItemModel } from '@mui/x-tree-view/hooks';
62
68
  import { TreeItem, treeItemClasses } from '@mui/x-tree-view/TreeItem';
63
69
  import { RichTreeViewPro } from '@mui/x-tree-view-pro/RichTreeViewPro';
64
70
 
65
- const StyledChip$3 = styled(Chip)(({ theme }) => ({
66
- height: 24,
71
+ const STATUS_COLOR_CLASSES = [
72
+ [chipClasses.colorDefault, semanticColors.status.neutral],
73
+ [chipClasses.colorError, semanticColors.status.error],
74
+ [chipClasses.colorWarning, semanticColors.status.warning],
75
+ [chipClasses.colorSuccess, semanticColors.status.success],
76
+ [chipClasses.colorInfo, semanticColors.status.info],
77
+ ];
78
+ const outlinedColorOverrides = {
79
+ backgroundColor: 'transparent',
80
+ color: semanticColors.typography.bodySecondary,
81
+ border: `1px solid ${semanticColors.border.secondary}`,
82
+ [`& .${chipClasses.icon}, & .${chipClasses.deleteIcon}`]: {
83
+ color: semanticColors.typography.bodySecondary,
84
+ },
85
+ };
86
+ const filledColorRules = Object.fromEntries(STATUS_COLOR_CLASSES.map(([className, palette]) => [
87
+ `&.${className}`,
88
+ {
89
+ backgroundColor: palette.light,
90
+ color: palette.dark,
91
+ border: `1px solid ${palette.transparent}`,
92
+ [`& .${chipClasses.icon}, & .${chipClasses.deleteIcon}`]: {
93
+ color: palette.dark,
94
+ },
95
+ },
96
+ ]));
97
+ const outlinedColorRules = Object.fromEntries(STATUS_COLOR_CLASSES.map(([className]) => [`&.${className}`, outlinedColorOverrides]));
98
+ const StyledChip$3 = styled(Chip, {
99
+ shouldForwardProp: prop => prop !== 'badgeSize' && prop !== 'badgeVariant',
100
+ })(({ theme, badgeSize, badgeVariant }) => ({
101
+ height: badgeSize === 'small' ? 20 : 24,
67
102
  paddingTop: spacing.spacing_1_4,
68
103
  paddingBottom: spacing.spacing_1_4,
69
104
  paddingLeft: spacing.spacing_1,
@@ -91,51 +126,7 @@ const StyledChip$3 = styled(Chip)(({ theme }) => ({
91
126
  width: 12,
92
127
  height: 12,
93
128
  },
94
- // Default (Neutral) state
95
- [`&.${chipClasses.colorDefault}`]: {
96
- backgroundColor: semanticColors.status.neutral.light,
97
- color: semanticColors.status.neutral.dark,
98
- border: `1px solid ${semanticColors.status.neutral.default}80`,
99
- [`& .${chipClasses.icon}, & .${chipClasses.deleteIcon}`]: {
100
- color: semanticColors.status.neutral.dark,
101
- },
102
- },
103
- // Error state
104
- [`&.${chipClasses.colorError}`]: {
105
- backgroundColor: semanticColors.status.error.light,
106
- color: semanticColors.status.error.dark,
107
- border: `1px solid ${semanticColors.status.error.default}80`,
108
- [`& .${chipClasses.icon}, & .${chipClasses.deleteIcon}`]: {
109
- color: semanticColors.status.error.dark,
110
- },
111
- },
112
- // Warning state
113
- [`&.${chipClasses.colorWarning}`]: {
114
- backgroundColor: semanticColors.status.warning.light,
115
- color: semanticColors.status.warning.dark,
116
- border: `1px solid ${semanticColors.status.warning.default}80`,
117
- [`& .${chipClasses.icon}, & .${chipClasses.deleteIcon}`]: {
118
- color: semanticColors.status.warning.dark,
119
- },
120
- },
121
- // Success state
122
- [`&.${chipClasses.colorSuccess}`]: {
123
- backgroundColor: semanticColors.status.success.light,
124
- color: semanticColors.status.success.dark,
125
- border: `1px solid ${semanticColors.status.success.default}80`,
126
- [`& .${chipClasses.icon}, & .${chipClasses.deleteIcon}`]: {
127
- color: semanticColors.status.success.dark,
128
- },
129
- },
130
- // Info state
131
- [`&.${chipClasses.colorInfo}`]: {
132
- backgroundColor: semanticColors.status.info.light,
133
- color: semanticColors.status.info.dark,
134
- border: `1px solid ${semanticColors.status.info.default}80`,
135
- [`& .${chipClasses.icon}, & .${chipClasses.deleteIcon}`]: {
136
- color: semanticColors.status.info.dark,
137
- },
138
- },
129
+ ...(badgeVariant === 'outlined' ? outlinedColorRules : filledColorRules),
139
130
  }));
140
131
  /**
141
132
  * NeoBadge - Status badge component based on MUI Chip
@@ -148,23 +139,26 @@ const StyledChip$3 = styled(Chip)(({ theme }) => ({
148
139
  * - TrailingIcon → deleteIcon prop (pass React element)
149
140
  * - Label → label prop
150
141
  */
151
- const NeoBadge = (props) => {
152
- return jsx(StyledChip$3, { ...props });
142
+ const NeoBadge = ({ size = 'medium', variant = 'filled', ...props }) => {
143
+ return jsx(StyledChip$3, { ...props, badgeSize: size, badgeVariant: variant });
153
144
  };
154
145
  NeoBadge.displayName = 'NeoBadge';
155
146
 
147
+ const djb2Hash = (str) => {
148
+ let hash = 5381;
149
+ for (let i = 0; i < str.length; i++) {
150
+ hash = (hash * 33) ^ str.charCodeAt(i);
151
+ }
152
+ return hash >>> 0;
153
+ };
156
154
  /**
157
- * Shared color palette for avatar components (GeneralAvatar, NavigationAvatar).
158
- * Maps color index (1-7) to background color token pairs.
155
+ * Deterministically derives an HSL background color from a string seed.
156
+ * Produces pastel colors matching the aesthetic of the status.avatar.initials
157
+ * semantic tokens (fixed 80% saturation, 90% lightness; only hue varies).
159
158
  */
160
- const avatarColorPalette = {
161
- 1: { bg: colors.digitalBlue[100] },
162
- 2: { bg: colors.digitalGreen[100] },
163
- 3: { bg: colors.gold[100] },
164
- 4: { bg: colors.red[100] },
165
- 5: { bg: colors.violet[100] },
166
- 6: { bg: colors.tealGreen[100] },
167
- 7: { bg: colors.orange[100] },
159
+ const avatarColorFromSeed = (seed) => {
160
+ const hue = seed ? djb2Hash(seed) % 360 : 235;
161
+ return `hsl(${hue}, 80%, 90%)`;
168
162
  };
169
163
 
170
164
  /**
@@ -179,14 +173,13 @@ const focusRingStyles = {
179
173
  };
180
174
 
181
175
  const sizeConfig$1 = {
182
- small: { width: spacing.spacing_4, height: spacing.spacing_4, fontSize: typography.fontSize.xs },
176
+ small: { width: spacing.spacing_4, height: spacing.spacing_4, fontSize: typography.fontSize.sm },
183
177
  medium: { width: spacing.spacing_5, height: spacing.spacing_5, fontSize: typography.fontSize.sm },
184
178
  };
185
179
  const StyledAvatar = styled(MuiAvatar, {
186
- shouldForwardProp: prop => prop !== 'avatarSize' && prop !== 'colorIndex',
187
- })(({ theme, avatarSize, colorIndex }) => {
180
+ shouldForwardProp: prop => prop !== 'avatarSize' && prop !== 'backgroundColor',
181
+ })(({ theme, avatarSize, backgroundColor }) => {
188
182
  const size = sizeConfig$1[avatarSize];
189
- const palette = avatarColorPalette[colorIndex];
190
183
  return {
191
184
  boxSizing: 'border-box',
192
185
  width: size.width,
@@ -196,7 +189,7 @@ const StyledAvatar = styled(MuiAvatar, {
196
189
  fontWeight: typography.fontWeight.regular,
197
190
  lineHeight: 1,
198
191
  color: semanticColors.typography.body,
199
- backgroundColor: palette ? palette.bg : undefined,
192
+ backgroundColor,
200
193
  border: `1px solid ${semanticColors.border.primary}`,
201
194
  '&:focus-visible': {
202
195
  ...focusRingStyles,
@@ -209,8 +202,9 @@ const StyledAvatar = styled(MuiAvatar, {
209
202
  *
210
203
  * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC?node-id=9600-185
211
204
  */
212
- const NeoGeneralAvatar = ({ size = 'medium', colorIndex = 0, children, ...props }) => {
213
- return (jsx(StyledAvatar, { avatarSize: size, colorIndex: colorIndex, ...props, children: children }));
205
+ const NeoGeneralAvatar = ({ size = 'medium', alt, children, ...props }) => {
206
+ const backgroundColor = avatarColorFromSeed(alt);
207
+ return (jsx(StyledAvatar, { avatarSize: size, backgroundColor: backgroundColor, alt: alt, ...props, children: children }));
214
208
  };
215
209
  NeoGeneralAvatar.displayName = 'NeoGeneralAvatar';
216
210
 
@@ -460,7 +454,7 @@ const NeoActivityIndicatorCell = ({ event = 'commit-job', secondaryEvent, scene
460
454
  NeoActivityIndicatorCell.displayName = 'NeoActivityIndicatorCell';
461
455
 
462
456
  /**
463
- * @license lucide-react v1.7.0 - ISC
457
+ * @license lucide-react v1.16.0 - ISC
464
458
  *
465
459
  * This source code is licensed under the ISC license.
466
460
  * See the LICENSE file in the root directory of this source tree.
@@ -471,7 +465,7 @@ const mergeClasses = (...classes) => classes.filter((className, index, array) =>
471
465
  }).join(" ").trim();
472
466
 
473
467
  /**
474
- * @license lucide-react v1.7.0 - ISC
468
+ * @license lucide-react v1.16.0 - ISC
475
469
  *
476
470
  * This source code is licensed under the ISC license.
477
471
  * See the LICENSE file in the root directory of this source tree.
@@ -480,7 +474,7 @@ const mergeClasses = (...classes) => classes.filter((className, index, array) =>
480
474
  const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
481
475
 
482
476
  /**
483
- * @license lucide-react v1.7.0 - ISC
477
+ * @license lucide-react v1.16.0 - ISC
484
478
  *
485
479
  * This source code is licensed under the ISC license.
486
480
  * See the LICENSE file in the root directory of this source tree.
@@ -492,7 +486,7 @@ const toCamelCase = (string) => string.replace(
492
486
  );
493
487
 
494
488
  /**
495
- * @license lucide-react v1.7.0 - ISC
489
+ * @license lucide-react v1.16.0 - ISC
496
490
  *
497
491
  * This source code is licensed under the ISC license.
498
492
  * See the LICENSE file in the root directory of this source tree.
@@ -505,7 +499,7 @@ const toPascalCase = (string) => {
505
499
  };
506
500
 
507
501
  /**
508
- * @license lucide-react v1.7.0 - ISC
502
+ * @license lucide-react v1.16.0 - ISC
509
503
  *
510
504
  * This source code is licensed under the ISC license.
511
505
  * See the LICENSE file in the root directory of this source tree.
@@ -524,7 +518,7 @@ var defaultAttributes = {
524
518
  };
525
519
 
526
520
  /**
527
- * @license lucide-react v1.7.0 - ISC
521
+ * @license lucide-react v1.16.0 - ISC
528
522
  *
529
523
  * This source code is licensed under the ISC license.
530
524
  * See the LICENSE file in the root directory of this source tree.
@@ -574,7 +568,7 @@ const Icon = forwardRef(
574
568
  );
575
569
 
576
570
  /**
577
- * @license lucide-react v1.7.0 - ISC
571
+ * @license lucide-react v1.16.0 - ISC
578
572
  *
579
573
  * This source code is licensed under the ISC license.
580
574
  * See the LICENSE file in the root directory of this source tree.
@@ -599,42 +593,42 @@ const createLucideIcon = (iconName, iconNode) => {
599
593
  };
600
594
 
601
595
  /**
602
- * @license lucide-react v1.7.0 - ISC
596
+ * @license lucide-react v1.16.0 - ISC
603
597
  *
604
598
  * This source code is licensed under the ISC license.
605
599
  * See the LICENSE file in the root directory of this source tree.
606
600
  */
607
601
 
608
602
 
609
- const __iconNode$k = [
603
+ const __iconNode$p = [
610
604
  ["path", { d: "M12 5v14", key: "s699le" }],
611
605
  ["path", { d: "m19 12-7 7-7-7", key: "1idqje" }]
612
606
  ];
613
- const ArrowDown = createLucideIcon("arrow-down", __iconNode$k);
607
+ const ArrowDown = createLucideIcon("arrow-down", __iconNode$p);
614
608
 
615
609
  /**
616
- * @license lucide-react v1.7.0 - ISC
610
+ * @license lucide-react v1.16.0 - ISC
617
611
  *
618
612
  * This source code is licensed under the ISC license.
619
613
  * See the LICENSE file in the root directory of this source tree.
620
614
  */
621
615
 
622
616
 
623
- const __iconNode$j = [
617
+ const __iconNode$o = [
624
618
  ["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
625
619
  ["path", { d: "M12 19V5", key: "x0mq9r" }]
626
620
  ];
627
- const ArrowUp = createLucideIcon("arrow-up", __iconNode$j);
621
+ const ArrowUp = createLucideIcon("arrow-up", __iconNode$o);
628
622
 
629
623
  /**
630
- * @license lucide-react v1.7.0 - ISC
624
+ * @license lucide-react v1.16.0 - ISC
631
625
  *
632
626
  * This source code is licensed under the ISC license.
633
627
  * See the LICENSE file in the root directory of this source tree.
634
628
  */
635
629
 
636
630
 
637
- const __iconNode$i = [
631
+ const __iconNode$n = [
638
632
  [
639
633
  "path",
640
634
  {
@@ -645,17 +639,17 @@ const __iconNode$i = [
645
639
  ["line", { x1: "12", x2: "12", y1: "16", y2: "12", key: "1y1yb1" }],
646
640
  ["line", { x1: "12", x2: "12.01", y1: "8", y2: "8", key: "110wyk" }]
647
641
  ];
648
- const BadgeInfo = createLucideIcon("badge-info", __iconNode$i);
642
+ const BadgeInfo = createLucideIcon("badge-info", __iconNode$n);
649
643
 
650
644
  /**
651
- * @license lucide-react v1.7.0 - ISC
645
+ * @license lucide-react v1.16.0 - ISC
652
646
  *
653
647
  * This source code is licensed under the ISC license.
654
648
  * See the LICENSE file in the root directory of this source tree.
655
649
  */
656
650
 
657
651
 
658
- const __iconNode$h = [
652
+ const __iconNode$m = [
659
653
  ["path", { d: "M8 2v4", key: "1cmpym" }],
660
654
  ["path", { d: "M16 2v4", key: "4m81vk" }],
661
655
  ["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
@@ -667,181 +661,252 @@ const __iconNode$h = [
667
661
  ["path", { d: "M12 18h.01", key: "mhygvu" }],
668
662
  ["path", { d: "M16 18h.01", key: "kzsmim" }]
669
663
  ];
670
- const CalendarDays = createLucideIcon("calendar-days", __iconNode$h);
664
+ const CalendarDays = createLucideIcon("calendar-days", __iconNode$m);
671
665
 
672
666
  /**
673
- * @license lucide-react v1.7.0 - ISC
667
+ * @license lucide-react v1.16.0 - ISC
674
668
  *
675
669
  * This source code is licensed under the ISC license.
676
670
  * See the LICENSE file in the root directory of this source tree.
677
671
  */
678
672
 
679
673
 
680
- const __iconNode$g = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
681
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$g);
674
+ const __iconNode$l = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
675
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$l);
682
676
 
683
677
  /**
684
- * @license lucide-react v1.7.0 - ISC
678
+ * @license lucide-react v1.16.0 - ISC
685
679
  *
686
680
  * This source code is licensed under the ISC license.
687
681
  * See the LICENSE file in the root directory of this source tree.
688
682
  */
689
683
 
690
684
 
691
- const __iconNode$f = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
692
- const ChevronLeft = createLucideIcon("chevron-left", __iconNode$f);
685
+ const __iconNode$k = [["path", { d: "m15 18-6-6 6-6", key: "1wnfg3" }]];
686
+ const ChevronLeft = createLucideIcon("chevron-left", __iconNode$k);
693
687
 
694
688
  /**
695
- * @license lucide-react v1.7.0 - ISC
689
+ * @license lucide-react v1.16.0 - ISC
696
690
  *
697
691
  * This source code is licensed under the ISC license.
698
692
  * See the LICENSE file in the root directory of this source tree.
699
693
  */
700
694
 
701
695
 
702
- const __iconNode$e = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
703
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$e);
696
+ const __iconNode$j = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
697
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$j);
704
698
 
705
699
  /**
706
- * @license lucide-react v1.7.0 - ISC
700
+ * @license lucide-react v1.16.0 - ISC
707
701
  *
708
702
  * This source code is licensed under the ISC license.
709
703
  * See the LICENSE file in the root directory of this source tree.
710
704
  */
711
705
 
712
706
 
713
- const __iconNode$d = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
714
- const ChevronUp = createLucideIcon("chevron-up", __iconNode$d);
707
+ const __iconNode$i = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
708
+ const ChevronUp = createLucideIcon("chevron-up", __iconNode$i);
715
709
 
716
710
  /**
717
- * @license lucide-react v1.7.0 - ISC
711
+ * @license lucide-react v1.16.0 - ISC
718
712
  *
719
713
  * This source code is licensed under the ISC license.
720
714
  * See the LICENSE file in the root directory of this source tree.
721
715
  */
722
716
 
723
717
 
724
- const __iconNode$c = [
718
+ const __iconNode$h = [
725
719
  ["path", { d: "m7 15 5 5 5-5", key: "1hf1tw" }],
726
720
  ["path", { d: "m7 9 5-5 5 5", key: "sgt6xg" }]
727
721
  ];
728
- const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$c);
722
+ const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$h);
729
723
 
730
724
  /**
731
- * @license lucide-react v1.7.0 - ISC
725
+ * @license lucide-react v1.16.0 - ISC
732
726
  *
733
727
  * This source code is licensed under the ISC license.
734
728
  * See the LICENSE file in the root directory of this source tree.
735
729
  */
736
730
 
737
731
 
738
- const __iconNode$b = [
732
+ const __iconNode$g = [
739
733
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
740
734
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
741
735
  ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
742
736
  ];
743
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$b);
737
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$g);
744
738
 
745
739
  /**
746
- * @license lucide-react v1.7.0 - ISC
740
+ * @license lucide-react v1.16.0 - ISC
747
741
  *
748
742
  * This source code is licensed under the ISC license.
749
743
  * See the LICENSE file in the root directory of this source tree.
750
744
  */
751
745
 
752
746
 
753
- const __iconNode$a = [
747
+ const __iconNode$f = [
754
748
  ["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
755
749
  ["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
756
750
  ];
757
- const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$a);
751
+ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$f);
758
752
 
759
753
  /**
760
- * @license lucide-react v1.7.0 - ISC
754
+ * @license lucide-react v1.16.0 - ISC
761
755
  *
762
756
  * This source code is licensed under the ISC license.
763
757
  * See the LICENSE file in the root directory of this source tree.
764
758
  */
765
759
 
766
760
 
767
- const __iconNode$9 = [
761
+ const __iconNode$e = [
768
762
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
769
763
  ["path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3", key: "1u773s" }],
770
764
  ["path", { d: "M12 17h.01", key: "p32p05" }]
771
765
  ];
772
- const CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode$9);
766
+ const CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode$e);
773
767
 
774
768
  /**
775
- * @license lucide-react v1.7.0 - ISC
769
+ * @license lucide-react v1.16.0 - ISC
776
770
  *
777
771
  * This source code is licensed under the ISC license.
778
772
  * See the LICENSE file in the root directory of this source tree.
779
773
  */
780
774
 
781
775
 
782
- const __iconNode$8 = [
776
+ const __iconNode$d = [
783
777
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
784
778
  ["path", { d: "M9 3v18", key: "fh3hqa" }],
785
779
  ["path", { d: "M15 3v18", key: "14nvp0" }]
786
780
  ];
787
- const Columns3 = createLucideIcon("columns-3", __iconNode$8);
781
+ const Columns3 = createLucideIcon("columns-3", __iconNode$d);
788
782
 
789
783
  /**
790
- * @license lucide-react v1.7.0 - ISC
784
+ * @license lucide-react v1.16.0 - ISC
791
785
  *
792
786
  * This source code is licensed under the ISC license.
793
787
  * See the LICENSE file in the root directory of this source tree.
794
788
  */
795
789
 
796
790
 
797
- const __iconNode$7 = [
791
+ const __iconNode$c = [
798
792
  ["path", { d: "M2 5h20", key: "1fs1ex" }],
799
793
  ["path", { d: "M6 12h12", key: "8npq4p" }],
800
794
  ["path", { d: "M9 19h6", key: "456am0" }]
801
795
  ];
802
- const ListFilter = createLucideIcon("list-filter", __iconNode$7);
796
+ const ListFilter = createLucideIcon("list-filter", __iconNode$c);
803
797
 
804
798
  /**
805
- * @license lucide-react v1.7.0 - ISC
799
+ * @license lucide-react v1.16.0 - ISC
806
800
  *
807
801
  * This source code is licensed under the ISC license.
808
802
  * See the LICENSE file in the root directory of this source tree.
809
803
  */
810
804
 
811
805
 
812
- const __iconNode$6 = [["path", { d: "M5 12h14", key: "1ays0h" }]];
813
- const Minus = createLucideIcon("minus", __iconNode$6);
806
+ const __iconNode$b = [["path", { d: "M5 12h14", key: "1ays0h" }]];
807
+ const Minus = createLucideIcon("minus", __iconNode$b);
814
808
 
815
809
  /**
816
- * @license lucide-react v1.7.0 - ISC
810
+ * @license lucide-react v1.16.0 - ISC
817
811
  *
818
812
  * This source code is licensed under the ISC license.
819
813
  * See the LICENSE file in the root directory of this source tree.
820
814
  */
821
815
 
822
816
 
823
- const __iconNode$5 = [
817
+ const __iconNode$a = [
818
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
819
+ ["path", { d: "M9 3v18", key: "fh3hqa" }],
820
+ ["path", { d: "m16 15-3-3 3-3", key: "14y99z" }]
821
+ ];
822
+ const PanelLeftClose = createLucideIcon("panel-left-close", __iconNode$a);
823
+
824
+ /**
825
+ * @license lucide-react v1.16.0 - ISC
826
+ *
827
+ * This source code is licensed under the ISC license.
828
+ * See the LICENSE file in the root directory of this source tree.
829
+ */
830
+
831
+
832
+ const __iconNode$9 = [
833
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
834
+ ["path", { d: "M9 3v18", key: "fh3hqa" }],
835
+ ["path", { d: "m14 9 3 3-3 3", key: "8010ee" }]
836
+ ];
837
+ const PanelLeftOpen = createLucideIcon("panel-left-open", __iconNode$9);
838
+
839
+ /**
840
+ * @license lucide-react v1.16.0 - ISC
841
+ *
842
+ * This source code is licensed under the ISC license.
843
+ * See the LICENSE file in the root directory of this source tree.
844
+ */
845
+
846
+
847
+ const __iconNode$8 = [
824
848
  ["path", { d: "M5 12h14", key: "1ays0h" }],
825
849
  ["path", { d: "M12 5v14", key: "s699le" }]
826
850
  ];
827
- const Plus = createLucideIcon("plus", __iconNode$5);
851
+ const Plus = createLucideIcon("plus", __iconNode$8);
828
852
 
829
853
  /**
830
- * @license lucide-react v1.7.0 - ISC
854
+ * @license lucide-react v1.16.0 - ISC
831
855
  *
832
856
  * This source code is licensed under the ISC license.
833
857
  * See the LICENSE file in the root directory of this source tree.
834
858
  */
835
859
 
836
860
 
837
- const __iconNode$4 = [
861
+ const __iconNode$7 = [
838
862
  ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
839
863
  ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
840
864
  ];
841
- const Search = createLucideIcon("search", __iconNode$4);
865
+ const Search = createLucideIcon("search", __iconNode$7);
866
+
867
+ /**
868
+ * @license lucide-react v1.16.0 - ISC
869
+ *
870
+ * This source code is licensed under the ISC license.
871
+ * See the LICENSE file in the root directory of this source tree.
872
+ */
873
+
874
+
875
+ const __iconNode$6 = [
876
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
877
+ ["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
878
+ ];
879
+ const SquareCheck = createLucideIcon("square-check", __iconNode$6);
880
+
881
+ /**
882
+ * @license lucide-react v1.16.0 - ISC
883
+ *
884
+ * This source code is licensed under the ISC license.
885
+ * See the LICENSE file in the root directory of this source tree.
886
+ */
887
+
888
+
889
+ const __iconNode$5 = [
890
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
891
+ ["path", { d: "M8 12h8", key: "1wcyev" }]
892
+ ];
893
+ const SquareMinus = createLucideIcon("square-minus", __iconNode$5);
842
894
 
843
895
  /**
844
- * @license lucide-react v1.7.0 - ISC
896
+ * @license lucide-react v1.16.0 - ISC
897
+ *
898
+ * This source code is licensed under the ISC license.
899
+ * See the LICENSE file in the root directory of this source tree.
900
+ */
901
+
902
+
903
+ const __iconNode$4 = [
904
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }]
905
+ ];
906
+ const Square = createLucideIcon("square", __iconNode$4);
907
+
908
+ /**
909
+ * @license lucide-react v1.16.0 - ISC
845
910
  *
846
911
  * This source code is licensed under the ISC license.
847
912
  * See the LICENSE file in the root directory of this source tree.
@@ -858,7 +923,7 @@ const __iconNode$3 = [
858
923
  const Trash2 = createLucideIcon("trash-2", __iconNode$3);
859
924
 
860
925
  /**
861
- * @license lucide-react v1.7.0 - ISC
926
+ * @license lucide-react v1.16.0 - ISC
862
927
  *
863
928
  * This source code is licensed under the ISC license.
864
929
  * See the LICENSE file in the root directory of this source tree.
@@ -879,7 +944,7 @@ const __iconNode$2 = [
879
944
  const TriangleAlert = createLucideIcon("triangle-alert", __iconNode$2);
880
945
 
881
946
  /**
882
- * @license lucide-react v1.7.0 - ISC
947
+ * @license lucide-react v1.16.0 - ISC
883
948
  *
884
949
  * This source code is licensed under the ISC license.
885
950
  * See the LICENSE file in the root directory of this source tree.
@@ -898,7 +963,7 @@ const __iconNode$1 = [
898
963
  const WifiOff = createLucideIcon("wifi-off", __iconNode$1);
899
964
 
900
965
  /**
901
- * @license lucide-react v1.7.0 - ISC
966
+ * @license lucide-react v1.16.0 - ISC
902
967
  *
903
968
  * This source code is licensed under the ISC license.
904
969
  * See the LICENSE file in the root directory of this source tree.
@@ -921,22 +986,29 @@ const intentColors$2 = {
921
986
  };
922
987
  // biome-ignore lint/suspicious/noExplicitAny: Type cast required to override MUI Alert variant type without global augmentation
923
988
  const StyledAlert$2 = styled(Alert, {
924
- shouldForwardProp: prop => prop !== 'intent' && prop !== 'alertType',
925
- })(({ theme, intent = 'success', alertType = 'outlined' }) => {
989
+ shouldForwardProp: prop => prop !== 'intent' && prop !== 'alertType' && prop !== 'alertSize' && prop !== 'hasChildren',
990
+ })(({ theme, intent = 'success', alertType = 'outlined', alertSize = 'default', hasChildren = false, }) => {
926
991
  const palette = intentColors$2[intent];
927
992
  const isFilled = alertType === 'filled';
993
+ const isCompact = alertSize === 'compact';
928
994
  const iconColor = isFilled ? semanticColors.typography.tooltip : palette.default;
929
- const messageColor = isFilled ? semanticColors.typography.tooltip : semanticColors.typography.body;
995
+ const messageColor = isFilled
996
+ ? semanticColors.typography.tooltip
997
+ : semanticColors.typography.body;
930
998
  return {
931
- height: spacing.spacing_8,
999
+ ...(isCompact
1000
+ ? { minHeight: spacing.spacing_5 }
1001
+ : hasChildren
1002
+ ? { minHeight: spacing.spacing_8, height: 'auto' }
1003
+ : { height: spacing.spacing_8 }),
932
1004
  width: '100%',
933
1005
  borderRadius: borderRadius.xS,
934
- alignItems: 'center',
1006
+ alignItems: hasChildren ? 'flex-start' : 'center',
935
1007
  fontFamily: typography.fontFamily.body,
936
1008
  fontSize: theme.typography.pxToRem(typography.fontSize.default),
937
1009
  fontWeight: typography.fontWeight.semiBold,
938
1010
  lineHeight: 1.5,
939
- padding: theme.spacing(0, 2),
1011
+ padding: hasChildren ? theme.spacing(1.5, 2) : theme.spacing(0, 2),
940
1012
  backgroundColor: isFilled ? palette.dark : palette.light,
941
1013
  border: isFilled ? 'none' : `1px solid ${palette.transparent}`,
942
1014
  color: isFilled ? semanticColors.typography.tooltip : semanticColors.typography.body,
@@ -953,7 +1025,7 @@ const StyledAlert$2 = styled(Alert, {
953
1025
  flex: 1,
954
1026
  display: 'flex',
955
1027
  flexDirection: 'column',
956
- justifyContent: 'center',
1028
+ justifyContent: hasChildren ? 'flex-start' : 'center',
957
1029
  '& span:last-child': {
958
1030
  fontSize: theme.typography.pxToRem(typography.fontSize.sm),
959
1031
  fontWeight: typography.fontWeight.medium,
@@ -991,9 +1063,9 @@ const iconMap = {
991
1063
  * - Show supporting text → description prop presence
992
1064
  * - Show Button → action prop presence
993
1065
  */
994
- const NeoAlert = ({ intent = 'success', type = 'outlined', title, description, icon, action, ...props }) => {
1066
+ const NeoAlert = ({ intent = 'success', type = 'outlined', size = 'default', title, description, icon, action, children, ...props }) => {
995
1067
  const defaultIcon = iconMap[intent];
996
- return (jsxs(StyledAlert$2, { ...props, intent: intent, alertType: type, icon: icon ?? defaultIcon, action: action, children: [jsx("span", { children: title }), description && jsx("span", { children: description })] }));
1068
+ return (jsxs(StyledAlert$2, { ...props, intent: intent, alertType: type, alertSize: size, hasChildren: Boolean(children), icon: icon ?? defaultIcon, action: action, children: [jsx("span", { children: title }), description && jsx("span", { children: description }), children] }));
997
1069
  };
998
1070
  NeoAlert.displayName = 'NeoAlert';
999
1071
 
@@ -1020,38 +1092,43 @@ const StyledAlert$1 = styled(Alert, {
1020
1092
  };
1021
1093
  return {
1022
1094
  width: '100%',
1023
- minHeight: 52,
1024
- paddingTop: spacing.spacing_3_4,
1025
- paddingBottom: spacing.spacing_3_4,
1026
- paddingLeft: spacing.spacing_3,
1027
- paddingRight: spacing.spacing_3,
1028
- gap: spacing.spacing_2,
1095
+ // Include padding in the width so the full-width banner never overflows its
1096
+ // container (don't rely on a global border-box reset being present).
1097
+ boxSizing: 'border-box',
1098
+ // Square corners by default: banners are full-width and typically sit flush
1099
+ // against the top of the viewport, so rounded corners would break the seam.
1100
+ borderRadius: 0,
1101
+ minHeight: 32,
1102
+ paddingTop: spacing.spacing_1_2,
1103
+ paddingBottom: spacing.spacing_1_2,
1104
+ paddingLeft: spacing.spacing_2,
1105
+ paddingRight: spacing.spacing_2,
1106
+ gap: spacing.spacing_1,
1029
1107
  alignItems: 'center',
1030
1108
  justifyContent: messagePosition === 'center' ? 'center' : 'flex-start',
1031
1109
  ...(messagePosition === 'center' && { position: 'relative' }),
1032
- boxShadow: `${shadows.neutral.small.x}px ${shadows.neutral.small.y}px ${shadows.neutral.small.blur}px ${shadows.neutral.small.spread}px ${shadows.neutral.small.shadow}`,
1033
- fontSize: typography.fontSize.default,
1110
+ fontSize: typography.fontSize.sm,
1034
1111
  fontWeight: typography.fontWeight.medium,
1035
1112
  lineHeight: 1.5,
1036
1113
  ...typeStyles,
1037
1114
  [`& .${alertClasses.icon}`]: {
1038
1115
  padding: 0,
1039
1116
  opacity: 1,
1040
- fontSize: typography.fontSize.h2,
1117
+ fontSize: typography.fontSize.default,
1041
1118
  color: 'inherit',
1042
1119
  },
1043
1120
  [`& .${alertClasses.message}`]: {
1044
1121
  padding: 0,
1045
1122
  display: 'flex',
1046
1123
  alignItems: 'center',
1047
- gap: spacing.spacing_2,
1124
+ gap: spacing.spacing_1,
1048
1125
  ...(messagePosition === 'left' && { flex: 1 }),
1049
1126
  },
1050
1127
  [`& .${alertClasses.action}`]: {
1051
1128
  padding: 0,
1052
1129
  ...(messagePosition === 'center' && {
1053
1130
  position: 'absolute',
1054
- right: spacing.spacing_3,
1131
+ right: spacing.spacing_2,
1055
1132
  }),
1056
1133
  },
1057
1134
  };
@@ -1069,6 +1146,8 @@ const LinkText = styled('span')(({ bannerType = 'outlined' }) => ({
1069
1146
  },
1070
1147
  }));
1071
1148
  const StyledIconButton = styled(IconButton)(({ closeIconColor }) => ({
1149
+ minWidth: 24,
1150
+ minHeight: 24,
1072
1151
  padding: 0,
1073
1152
  color: closeIconColor,
1074
1153
  '&:hover': {
@@ -1085,7 +1164,7 @@ const NeoBanner = ({ intent = 'info', type = 'outlined', message, messagePositio
1085
1164
  return null;
1086
1165
  }
1087
1166
  const closeIconColor = type === 'filled' ? semanticColors.surfaces.white : intentColors$1[intent].default;
1088
- return (jsx(StyledAlert$1, { ...props, intent: intent, bannerType: type, messagePosition: messagePosition, icon: messagePosition === 'left' ? icon || false : false, action: showClose ? (jsx(StyledIconButton, { size: "small", onClick: handleClose, closeIconColor: closeIconColor, children: jsx(X, { size: 24 }) })) : undefined, children: messagePosition === 'center' ? (jsxs(Fragment, { children: [icon, jsx("span", { children: message }), linkText && (jsx(LinkText, { bannerType: type, onClick: onLinkClick, children: linkText }))] })) : (jsxs(Fragment, { children: [jsx("span", { children: message }), linkText && (jsx(LinkText, { bannerType: type, onClick: onLinkClick, children: linkText }))] })) }));
1167
+ return (jsx(StyledAlert$1, { ...props, intent: intent, bannerType: type, messagePosition: messagePosition, icon: messagePosition === 'left' ? icon || false : false, action: showClose ? (jsx(StyledIconButton, { size: "small", onClick: handleClose, closeIconColor: closeIconColor, children: jsx(X, { size: 16 }) })) : undefined, children: messagePosition === 'center' ? (jsxs(Fragment, { children: [icon, jsx("span", { children: message }), linkText && (jsx(LinkText, { bannerType: type, onClick: onLinkClick, children: linkText }))] })) : (jsxs(Fragment, { children: [jsx("span", { children: message }), linkText && (jsx(LinkText, { bannerType: type, onClick: onLinkClick, children: linkText }))] })) }));
1089
1168
  };
1090
1169
  NeoBanner.displayName = 'NeoBanner';
1091
1170
 
@@ -1105,12 +1184,12 @@ const StyledBreadcrumbLink = styled(Link, {
1105
1184
  fontWeight: typography.fontWeight.medium,
1106
1185
  lineHeight: 1,
1107
1186
  textDecoration: 'none',
1108
- color: current ? semanticColors.buttons.primary.default : semanticColors.typography.bodySecondary,
1187
+ color: current ? semanticColors.typography.bodySecondary : semanticColors.typography.link.primary,
1109
1188
  cursor: current ? 'default' : 'pointer',
1110
1189
  borderRadius: borderRadius.xS,
1111
1190
  transition: 'color 0.2s ease-in-out',
1112
1191
  '&:hover': {
1113
- color: current ? semanticColors.buttons.tertiary.hover : semanticColors.icons.hover,
1192
+ color: current ? semanticColors.icons.hover : semanticColors.buttons.tertiary.hover,
1114
1193
  },
1115
1194
  '&:focus-visible': {
1116
1195
  outline: `2px solid ${semanticColors.border.focus}`,
@@ -1493,6 +1572,15 @@ const NeoButtonTabGroup = ({ size = 'medium', exclusive = true, ...props }) => {
1493
1572
  };
1494
1573
  NeoButtonTabGroup.displayName = 'NeoButtonTabGroup';
1495
1574
 
1575
+ /**
1576
+ * NeoCanceledIcon - Outlined circle struck through by a horizontal line.
1577
+ *
1578
+ * Marks a CANCELED state. Color comes entirely from `currentColor` (stroke plus
1579
+ * a 10% fill tint); set it via the `color`/`sx` prop or a parent.
1580
+ */
1581
+ const NeoCanceledIcon = (props) => (jsx(SvgIcon, { viewBox: "0 0 24 24", fill: "none", ...props, children: jsxs("g", { stroke: "currentColor", strokeWidth: "1.35", children: [jsx("path", { fill: "currentColor", fillOpacity: "0.1", d: "M2.55 11.95c0 2.405.918 4.812 2.753 6.647a9.4 9.4 0 0 0 6.647 2.753c2.489 0 4.877-.99 6.646-2.753a9.3 9.3 0 0 0 2.039-3.044 9.4 9.4 0 0 0 .715-3.602m-18.8-.001a9.37 9.37 0 0 1 2.753-6.647A9.4 9.4 0 0 1 11.95 2.55c2.489 0 4.877.99 6.646 2.753a9.3 9.3 0 0 1 2.039 3.045 9.4 9.4 0 0 1 .715 3.603" }), jsx("path", { fill: "none", d: "M3 11.825h18" })] }) }));
1582
+ NeoCanceledIcon.displayName = 'NeoCanceledIcon';
1583
+
1496
1584
  // ─── Shared ──────────────────────────────────────────────────────────────────
1497
1585
  const activeShadow = `${shadows.card.x}px ${shadows.card.y}px ${shadows.card.blur}px ${shadows.card.spread}px ${shadows.card.shadow}`;
1498
1586
  // ─── Small card styled components ────────────────────────────────────────────
@@ -1684,20 +1772,6 @@ const NeoCard = (props) => {
1684
1772
  };
1685
1773
  NeoCard.displayName = 'NeoCard';
1686
1774
 
1687
- // Border radius per size (from Figma)
1688
- const borderRadiusConfig = {
1689
- xs: 2,
1690
- small: 3,
1691
- medium: 4,
1692
- };
1693
- // Unchecked: Rounded square outline (20x20 viewBox)
1694
- const UncheckedIcon$1 = ({ size = 'medium' }) => (jsx(SvgIcon, { viewBox: "0 0 20 20", children: jsx("rect", { x: "1", y: "1", width: "18", height: "18", rx: borderRadiusConfig[size], fill: "none", stroke: "currentColor", strokeWidth: "1.5" }) }));
1695
- // Checked: Filled rounded square with white checkmark
1696
- // Path scaled from Untitled UI 24x24 (M20 6L9 17L4 12) to 20x20
1697
- const CheckedIcon$1 = ({ size = 'medium' }) => (jsxs(SvgIcon, { viewBox: "0 0 20 20", children: [jsx("rect", { width: "20", height: "20", rx: borderRadiusConfig[size], fill: "currentColor" }), jsx("path", { d: "M15 6L8.5 13L5 9.5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", fill: "none" })] }));
1698
- // Indeterminate: Filled rounded square with white minus
1699
- // Path scaled from Untitled UI 24x24 (M5 12H19) to 20x20
1700
- const IndeterminateIcon = ({ size = 'medium' }) => (jsxs(SvgIcon, { viewBox: "0 0 20 20", children: [jsx("rect", { width: "20", height: "20", rx: borderRadiusConfig[size], fill: "currentColor" }), jsx("path", { d: "M5 10H15", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", fill: "none" })] }));
1701
1775
  const CheckboxContainer = styled('label')(({ disabled }) => ({
1702
1776
  display: 'inline-flex',
1703
1777
  alignItems: 'flex-start',
@@ -1730,7 +1804,7 @@ const HelperText$2 = styled('span')(({ theme, size = 'medium' }) => ({
1730
1804
  lineHeight: size === 'xs' ? 1.5 : size === 'small' ? 1.4 : 1.5,
1731
1805
  color: semanticColors.typography.bodySecondary,
1732
1806
  }));
1733
- // Figma-exact border radius for xs checkbox — no matching design token
1807
+ // xs focus-ring radius — no matching design token (box corner comes from the icon)
1734
1808
  const FIGMA_XS_BORDER_RADIUS = 1;
1735
1809
  const StyledCheckbox = styled(Checkbox, {
1736
1810
  shouldForwardProp: prop => prop !== 'size',
@@ -1743,11 +1817,11 @@ const StyledCheckbox = styled(Checkbox, {
1743
1817
  },
1744
1818
  small: {
1745
1819
  size: 16,
1746
- borderRadius: borderRadius.xXS, // From Figma: 2px for small
1820
+ borderRadius: borderRadius.xXS, // focus-ring radius (small)
1747
1821
  },
1748
1822
  medium: {
1749
1823
  size: 20,
1750
- borderRadius: borderRadius.xS, // From Figma: 4px for medium
1824
+ borderRadius: borderRadius.xS, // focus-ring radius (medium)
1751
1825
  },
1752
1826
  };
1753
1827
  const config = sizeConfig[size];
@@ -1759,37 +1833,30 @@ const StyledCheckbox = styled(Checkbox, {
1759
1833
  color: semanticColors.border.primary,
1760
1834
  borderRadius: config.borderRadius,
1761
1835
  flexShrink: 0,
1762
- // Root element
1763
- [`&.${checkboxClasses.root}`]: {
1764
- '&:hover': {
1765
- backgroundColor: 'transparent',
1766
- },
1836
+ // Suppress MUI's grey hover background
1837
+ '&:hover': {
1838
+ backgroundColor: 'transparent',
1767
1839
  },
1768
- // Checkbox icon (unchecked)
1769
- [`& .${checkboxClasses.root}`]: {
1770
- width: config.size,
1771
- height: config.size,
1840
+ // Hover on the unchecked box — subtle blue outline affordance (enabled only)
1841
+ [`&:hover:not(.${checkboxClasses.checked}):not(.${checkboxClasses.indeterminate}):not(.${checkboxClasses.disabled})`]: {
1842
+ color: colors.digitalBlue[300],
1772
1843
  },
1773
- // Checked state
1844
+ // Checked / Indeterminate — primary blue outline + mark
1774
1845
  [`&.${checkboxClasses.checked}`]: {
1775
- color: semanticColors.buttons.primary.default,
1846
+ color: colors.digitalBlue[600],
1776
1847
  },
1777
- // Indeterminate state
1778
1848
  [`&.${checkboxClasses.indeterminate}`]: {
1779
- color: semanticColors.buttons.primary.default,
1849
+ color: colors.digitalBlue[600],
1780
1850
  },
1781
- // Disabled state
1851
+ // Disabled — enabled colors dimmed to 40%. Checked/indeterminate keep
1852
+ // digitalBlue[600] via the rules above; re-assert the unchecked outline
1853
+ // token so it beats MUI's default `.Mui-disabled` color.
1782
1854
  [`&.${checkboxClasses.disabled}`]: {
1783
- color: semanticColors.border.primary,
1855
+ opacity: 0.4,
1784
1856
  cursor: 'not-allowed',
1785
- // When checked and disabled
1786
- [`&.${checkboxClasses.checked}`]: {
1787
- color: semanticColors.border.primary,
1788
- },
1789
- // When indeterminate and disabled
1790
- [`&.${checkboxClasses.indeterminate}`]: {
1791
- color: semanticColors.border.primary,
1792
- },
1857
+ },
1858
+ [`&.${checkboxClasses.disabled}:not(.${checkboxClasses.checked}):not(.${checkboxClasses.indeterminate})`]: {
1859
+ color: semanticColors.border.primary,
1793
1860
  },
1794
1861
  // Focus visible for keyboard navigation
1795
1862
  '&.Mui-focusVisible': {
@@ -1797,11 +1864,10 @@ const StyledCheckbox = styled(Checkbox, {
1797
1864
  outlineOffset: 2,
1798
1865
  borderRadius: config.borderRadius,
1799
1866
  },
1800
- // Custom SVG icons
1867
+ // Size the Lucide icon (color comes from `color` → currentColor → stroke)
1801
1868
  '& svg': {
1802
1869
  width: config.size,
1803
1870
  height: config.size,
1804
- fill: 'currentColor',
1805
1871
  },
1806
1872
  };
1807
1873
  });
@@ -1852,10 +1918,10 @@ const StyledCheckbox = styled(Checkbox, {
1852
1918
  const NeoCheckbox = ({ size = 'medium', label, helperText, disabled, icon, checkedIcon, indeterminateIcon, className, ...props }) => {
1853
1919
  // Add custom class to identify NeoCheckbox instances
1854
1920
  const combinedClassName = className ? `neo-checkbox ${className}` : 'neo-checkbox';
1855
- // Create size-specific icons
1856
- const defaultIcon = icon || jsx(UncheckedIcon$1, { size: size });
1857
- const defaultCheckedIcon = checkedIcon || jsx(CheckedIcon$1, { size: size });
1858
- const defaultIndeterminateIcon = indeterminateIcon || jsx(IndeterminateIcon, { size: size });
1921
+ // Default icons (sized via CSS on the SVG); overridable per instance
1922
+ const defaultIcon = icon || jsx(Square, {});
1923
+ const defaultCheckedIcon = checkedIcon || jsx(SquareCheck, {});
1924
+ const defaultIndeterminateIcon = indeterminateIcon || jsx(SquareMinus, {});
1859
1925
  // If no label, return just the checkbox
1860
1926
  if (!label && !helperText) {
1861
1927
  return (jsx(StyledCheckbox, { size: size, disabled: disabled, icon: defaultIcon, checkedIcon: defaultCheckedIcon, indeterminateIcon: defaultIndeterminateIcon, className: combinedClassName, ...props }));
@@ -2167,7 +2233,8 @@ const StyledMenuItem = styled(MenuItem)(({ theme }) => ({
2167
2233
  gap: theme.spacing(2),
2168
2234
  borderRadius: 0,
2169
2235
  color: semanticColors.icons.default,
2170
- fontSize: theme.typography.pxToRem(typography.fontSize.sm),
2236
+ textDecoration: 'none',
2237
+ fontSize: theme.typography.pxToRem(typography.fontSize.default),
2171
2238
  fontWeight: typography.fontWeight.regular,
2172
2239
  lineHeight: `${typography.lineHeight.s}px`,
2173
2240
  transition: theme.transitions.create(['background-color'], {
@@ -2233,7 +2300,7 @@ const Shortcut = styled('span')(({ theme }) => ({
2233
2300
  /**
2234
2301
  * NeoMenuItem - Menu item component based on MUI MenuItem
2235
2302
  *
2236
- * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC/Neo---Moderne-Design-system---2025?node-id=4159-8584
2303
+ * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC/Neo---Moderne-Design-system---2025-26?node-id=4159-8714
2237
2304
  *
2238
2305
  * @example
2239
2306
  * ```tsx
@@ -2248,11 +2315,22 @@ const Shortcut = styled('span')(({ theme }) => ({
2248
2315
  *
2249
2316
  * // Disabled state
2250
2317
  * <NeoMenuItem disabled>Disabled item</NeoMenuItem>
2318
+ *
2319
+ * // As an anchor — middle-click/right-click open in a new tab
2320
+ * <NeoMenuItem href="/api-explorer">API explorer</NeoMenuItem>
2321
+ *
2322
+ * // External link
2323
+ * <NeoMenuItem href="https://docs.example.com" target="_blank" rel="noopener noreferrer">
2324
+ * Documentation
2325
+ * </NeoMenuItem>
2326
+ *
2327
+ * // Client-side routing (Next.js)
2328
+ * <NeoMenuItem component={NextLink} href="/api-explorer">API explorer</NeoMenuItem>
2251
2329
  * ```
2252
2330
  */
2253
- const NeoMenuItem = ({ icon, shortcut, secondaryText, children, ...props }) => {
2254
- return (jsx(StyledMenuItem, { ...props, children: jsxs(MenuItemContent, { children: [icon && jsx(IconWrapper$1, { children: icon }), jsxs(LabelContainer$3, { children: [jsx(Label$3, { children: children }), secondaryText && jsx(SecondaryLabel, { children: secondaryText })] }), shortcut && jsx(Shortcut, { children: shortcut })] }) }));
2255
- };
2331
+ function NeoMenuItem({ icon, shortcut, secondaryText, children, ...rest }) {
2332
+ return (jsx(StyledMenuItem, { ...rest, children: jsxs(MenuItemContent, { children: [icon && jsx(IconWrapper$1, { children: icon }), jsxs(LabelContainer$3, { children: [jsx(Label$3, { children: children }), secondaryText && jsx(SecondaryLabel, { children: secondaryText })] }), shortcut && jsx(Shortcut, { children: shortcut })] }) }));
2333
+ }
2256
2334
  NeoMenuItem.displayName = 'NeoMenuItem';
2257
2335
 
2258
2336
  /**
@@ -2536,8 +2614,10 @@ const getDataGridHeaderStyles = () => {
2536
2614
  [`& .${gridClasses.columnHeader}`]: {
2537
2615
  backgroundColor: semanticColors.surfaces.dataGrid.header,
2538
2616
  borderBottom: `1px solid ${semanticColors.border.primary}`,
2539
- paddingLeft: `${spacing.spacing_3}px`,
2540
- paddingRight: `${spacing.spacing_3}px`,
2617
+ paddingTop: `${spacing.spacing_1_1_2}px`,
2618
+ paddingBottom: `${spacing.spacing_1_1_2}px`,
2619
+ paddingLeft: `${spacing.spacing_2}px`,
2620
+ paddingRight: `${spacing.spacing_2}px`,
2541
2621
  boxSizing: 'border-box',
2542
2622
  },
2543
2623
  // Style the filler element to match header
@@ -2575,12 +2655,19 @@ const getDataGridHeaderStyles = () => {
2575
2655
  },
2576
2656
  },
2577
2657
  },
2658
+ // MUI clips this container when header vertical padding leaves < 16px of content
2659
+ // area (e.g. compact: 38px − 24px padding = 14px). overflow:visible lets the
2660
+ // sort icon render at full 16px without being cropped.
2661
+ [`& .${gridClasses.columnHeaderTitleContainer}`]: {
2662
+ overflow: 'visible',
2663
+ lineHeight: 1,
2664
+ },
2578
2665
  // Style MUI's sort icon to match Neo design (16x16)
2579
2666
  [`& .${gridClasses.iconButtonContainer}`]: {
2580
2667
  width: 16,
2581
2668
  height: 16,
2582
2669
  marginLeft: `${spacing.spacing_1_2}px`,
2583
- [`& .${checkboxClasses.root}`]: {
2670
+ '& button': {
2584
2671
  padding: 0,
2585
2672
  width: 16,
2586
2673
  height: 16,
@@ -2694,11 +2781,13 @@ function NeoDataGrid({ autoHeight = false, toolbar, slots, sx, density = 'standa
2694
2781
  ...getDataGridHeaderStyles(),
2695
2782
  ...getDataGridRowStyles(),
2696
2783
  border: `1px solid ${semanticColors.border.secondary}`,
2697
- // Style row selection checkboxes to match header (16px, proper spacing)
2784
+ // Style row selection checkboxes to match header (16px, proper spacing).
2785
+ // Target `& svg` (not `.MuiSvgIcon-root`) so the rule also matches the
2786
+ // lucide `<svg>` icons NeoCheckbox renders, mirroring the header rule.
2698
2787
  [`& .${gridClasses.cellCheckbox}`]: {
2699
2788
  [`& .${checkboxClasses.root}`]: {
2700
2789
  padding: `${spacing.spacing_1}px`,
2701
- [`& .${svgIconClasses.root}`]: {
2790
+ '& svg': {
2702
2791
  width: 16,
2703
2792
  height: 16,
2704
2793
  },
@@ -2747,7 +2836,7 @@ function NeoDataGridColumnsButton() {
2747
2836
  }
2748
2837
  NeoDataGridColumnsButton.displayName = 'NeoDataGridColumnsButton';
2749
2838
 
2750
- const sizeStyles = {
2839
+ const sizeStyles$1 = {
2751
2840
  small: {
2752
2841
  height: 16,
2753
2842
  minWidth: 16,
@@ -2820,9 +2909,11 @@ const StyledChip$2 = styled(Chip)(({ theme, size, variant, color }) => ({
2820
2909
  fontSize: theme.typography.pxToRem(typography.fontSize.xs),
2821
2910
  lineHeight: 1,
2822
2911
  fontWeight: typography.fontWeight.medium,
2823
- ...(size && sizeStyles[size]),
2912
+ overflow: 'visible',
2913
+ ...(size && sizeStyles$1[size]),
2824
2914
  [`& .${chipClasses.label}`]: {
2825
2915
  padding: 0,
2916
+ overflow: 'visible',
2826
2917
  },
2827
2918
  ...(variant === 'outlined' &&
2828
2919
  color &&
@@ -3727,6 +3818,20 @@ const NeoDatePicker = ({ type = 'single', open, label, value, rangeValue, onChan
3727
3818
  };
3728
3819
  NeoDatePicker.displayName = 'NeoDatePicker';
3729
3820
 
3821
+ /**
3822
+ * NeoDatePickerListItem
3823
+ *
3824
+ * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC?node-id=4176-8521
3825
+ */
3826
+ const NeoDatePickerListItem = styled('div')({});
3827
+
3828
+ /**
3829
+ * NeoDatePickerMenu
3830
+ *
3831
+ * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC?node-id=4176-8593
3832
+ */
3833
+ const NeoDatePickerMenu = styled('div')({});
3834
+
3730
3835
  const StyledDivider = styled(Divider)(({ theme }) => ({
3731
3836
  borderColor: semanticColors.border.secondary,
3732
3837
  marginTop: theme.spacing(1),
@@ -3767,26 +3872,34 @@ const sizeMap = {
3767
3872
  medium: 10,
3768
3873
  large: 12,
3769
3874
  };
3770
- const StyledBadge = styled(Badge)(({ ownerState }) => {
3875
+ const StyledDot = styled('span', {
3876
+ shouldForwardProp: prop => prop !== 'ownerState',
3877
+ })(({ ownerState }) => {
3771
3878
  const size = sizeMap[ownerState.size];
3772
- const color = semanticColors.status[ownerState.color].default;
3879
+ const palette = semanticColors.status[ownerState.color];
3773
3880
  return {
3774
- [`& .${badgeClasses.badge}`]: {
3775
- width: size,
3776
- height: size,
3777
- minWidth: size,
3778
- borderRadius: ownerState.variant === 'solid' ? '50%' : 0,
3779
- padding: 0,
3780
- backgroundColor: ownerState.variant === 'solid' ? color : 'transparent',
3781
- // Remove default badge positioning - make it standalone
3782
- position: 'static',
3783
- transform: 'none',
3784
- overflow: 'visible',
3881
+ display: 'inline-flex',
3882
+ alignItems: 'center',
3883
+ justifyContent: 'center',
3884
+ width: size,
3885
+ height: size,
3886
+ minWidth: size,
3887
+ borderRadius: '50%',
3888
+ flexShrink: 0,
3889
+ boxSizing: 'border-box',
3890
+ backgroundColor: palette.default,
3891
+ color: semanticColors.typography.tooltip,
3892
+ ...(ownerState.variant === 'outline' && {
3893
+ border: `3px solid ${palette.light}`,
3894
+ }),
3895
+ '& > svg': {
3896
+ width: '70%',
3897
+ height: '70%',
3785
3898
  },
3786
3899
  };
3787
3900
  });
3788
3901
  /**
3789
- * NeoDot - Status indicator dot component based on MUI Badge
3902
+ * NeoDot - Status indicator dot.
3790
3903
  *
3791
3904
  * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC/Neo---Moderne-Design-system---2025?node-id=4163-3577
3792
3905
  *
@@ -3795,26 +3908,8 @@ const StyledBadge = styled(Badge)(({ ownerState }) => {
3795
3908
  * - outline (False|True) → variant prop (solid|outline)
3796
3909
  * - Color is configurable via color prop (success|error|warning|info|neutral)
3797
3910
  */
3798
- const NeoDot = ({ size = 'medium', variant = 'solid', color = 'neutral', ...props }) => {
3799
- const dotSize = sizeMap[size];
3800
- const mediumColor = semanticColors.status[color].default;
3801
- const lightColor = semanticColors.status[color].light;
3802
- // For outline variant, use SVG for precise control
3803
- const renderDot = () => {
3804
- if (variant === 'outline') {
3805
- // SVG approach: outer circle with light fill, inner circle with medium fill
3806
- // Stroke width of ~3px creates the ring effect
3807
- const strokeWidth = 3;
3808
- const radius = dotSize / 2;
3809
- const innerRadius = radius - strokeWidth;
3810
- return (jsxs("svg", { width: dotSize, height: dotSize, viewBox: `0 0 ${dotSize} ${dotSize}`, style: {
3811
- display: 'block',
3812
- borderRadius: '50%',
3813
- }, role: "img", "aria-label": `${color} status indicator`, children: [jsx("title", { children: `${color} status indicator` }), jsx("circle", { cx: radius, cy: radius, r: radius, fill: lightColor }), jsx("circle", { cx: radius, cy: radius, r: innerRadius, fill: mediumColor })] }));
3814
- }
3815
- return jsx("span", { style: { display: 'inline-block', width: 0, height: 0 } });
3816
- };
3817
- return (jsx(StyledBadge, { ...props, ownerState: { size, variant, color }, variant: "dot", children: renderDot() }));
3911
+ const NeoDot = ({ size = 'medium', variant = 'solid', color = 'neutral', children, ...props }) => {
3912
+ return (jsx(StyledDot, { ...props, ownerState: { size, variant, color }, role: "img", "aria-label": props['aria-label'] ?? `${color} status indicator`, children: children }));
3818
3913
  };
3819
3914
  NeoDot.displayName = 'NeoDot';
3820
3915
 
@@ -3896,6 +3991,55 @@ const NeoDownloadToast = ({ title, fileName, progress, showClose = true, showPau
3896
3991
  };
3897
3992
  NeoDownloadToast.displayName = 'NeoDownloadToast';
3898
3993
 
3994
+ const buildFilledIcon = ({ displayName, fillColor, body, knockout }) => {
3995
+ const Component = (props) => (jsxs(SvgIcon, { viewBox: "0 0 16 16", ...props, children: [jsx("g", { fill: fillColor, children: body }), jsx("g", { stroke: "#FFFFFF", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", fill: "none", children: knockout })] }));
3996
+ Component.displayName = displayName;
3997
+ return Component;
3998
+ };
3999
+ const CIRCLE_BODY = (jsx("path", { d: "M8.00001 14.6666C11.6819 14.6666 14.6667 11.6818 14.6667 7.99992C14.6667 4.31802 11.6819 1.33325 8.00001 1.33325C4.31811 1.33325 1.33334 4.31802 1.33334 7.99992C1.33334 11.6818 4.31811 14.6666 8.00001 14.6666Z" }));
4000
+ const NeoFilledSuccess = buildFilledIcon({
4001
+ displayName: 'NeoFilledSuccess',
4002
+ fillColor: '#3B8948',
4003
+ body: CIRCLE_BODY,
4004
+ knockout: jsx("path", { d: "M6 8.00008L7.33333 9.33341L10 6.66675" }),
4005
+ });
4006
+ const NeoFilledQueued = buildFilledIcon({
4007
+ displayName: 'NeoFilledQueued',
4008
+ fillColor: '#992FB9',
4009
+ body: CIRCLE_BODY,
4010
+ knockout: jsx("path", { d: "M8 4V8L10.6667 9.33333" }),
4011
+ });
4012
+ const NeoFilledInfo = buildFilledIcon({
4013
+ displayName: 'NeoFilledInfo',
4014
+ fillColor: '#2F42FF',
4015
+ body: CIRCLE_BODY,
4016
+ knockout: (jsxs(Fragment, { children: [jsx("path", { d: "M8 10.6667V8" }), jsx("path", { d: "M8 5.33325H8.00667" })] })),
4017
+ });
4018
+ const NeoFilledWarning = buildFilledIcon({
4019
+ displayName: 'NeoFilledWarning',
4020
+ fillColor: '#BD9319',
4021
+ body: (jsx("path", { d: "M14.4867 12L9.15335 2.66665C9.03706 2.46146 8.86842 2.29078 8.66463 2.17203C8.46084 2.05329 8.22921 1.99072 7.99335 1.99072C7.75749 1.99072 7.52585 2.05329 7.32206 2.17203C7.11828 2.29078 6.94964 2.46146 6.83335 2.66665L1.50001 12C1.38247 12.2036 1.32083 12.4346 1.32135 12.6697C1.32187 12.9047 1.38453 13.1355 1.50298 13.3385C1.62142 13.5416 1.79145 13.7097 1.99581 13.8259C2.20018 13.942 2.43162 14.0021 2.66668 14H13.3333C13.5673 13.9997 13.797 13.938 13.9995 13.8208C14.202 13.7037 14.3702 13.5354 14.487 13.3327C14.6039 13.1301 14.6654 12.9002 14.6653 12.6663C14.6653 12.4324 14.6036 12.2026 14.4867 12Z" })),
4022
+ knockout: (jsxs(Fragment, { children: [jsx("path", { d: "M8 6V8.66667" }), jsx("path", { d: "M8 11.3333H8.00667" })] })),
4023
+ });
4024
+ const NeoFilledError = buildFilledIcon({
4025
+ displayName: 'NeoFilledError',
4026
+ fillColor: '#CB3446',
4027
+ body: (jsx("path", { d: "M10.208 1.33325C10.5616 1.33333 10.9007 1.47385 11.1507 1.72392L14.276 4.84925C14.5261 5.09924 14.6666 5.43832 14.6667 5.79192V10.2079C14.6666 10.5615 14.5261 10.9006 14.276 11.1506L11.1507 14.2759C10.9007 14.526 10.5616 14.6665 10.208 14.6666H5.79201C5.43842 14.6665 5.09933 14.526 4.84934 14.2759L1.72401 11.1506C1.47394 10.9006 1.33342 10.5615 1.33334 10.2079V5.79192C1.33342 5.43832 1.47394 5.09924 1.72401 4.84925L4.84934 1.72392C5.09933 1.47385 5.43842 1.33333 5.79201 1.33325H10.208Z" })),
4028
+ knockout: (jsxs(Fragment, { children: [jsx("path", { d: "M8 5.33325V7.99992" }), jsx("path", { d: "M8 10.6667H8.00667" })] })),
4029
+ });
4030
+ const NeoFilledNeutral = buildFilledIcon({
4031
+ displayName: 'NeoFilledNeutral',
4032
+ fillColor: '#6B7280',
4033
+ body: CIRCLE_BODY,
4034
+ knockout: jsx("path", { d: "M5.33334 8H10.6667" }),
4035
+ });
4036
+ const NeoFilledCanceled = buildFilledIcon({
4037
+ displayName: 'NeoFilledCanceled',
4038
+ fillColor: '#7B7263',
4039
+ body: CIRCLE_BODY,
4040
+ knockout: (jsxs(Fragment, { children: [jsx("path", { d: "M10 6L6 10" }), jsx("path", { d: "M6 6L10 10" })] })),
4041
+ });
4042
+
3899
4043
  const filterChipOnlyProps = ['selected', 'expanded', 'selectedLabel', 'count', 'onClear'];
3900
4044
  const StyledChip$1 = styled(Chip, {
3901
4045
  shouldForwardProp: prop => !filterChipOnlyProps.includes(prop),
@@ -4028,6 +4172,7 @@ const StyledFooter = styled(Box, {
4028
4172
  shouldForwardProp: prop => prop !== 'showShadow',
4029
4173
  })(({ theme, showShadow = false }) => ({
4030
4174
  backgroundColor: semanticColors.surfaces.white,
4175
+ borderTop: `1px solid ${semanticColors.border.primary}`,
4031
4176
  display: 'flex',
4032
4177
  alignItems: 'center',
4033
4178
  justifyContent: 'center',
@@ -4353,13 +4498,7 @@ function NeoInfiniteScrollGrid({ onLoadMore, hasNextPage = true, loadMoreAtScrol
4353
4498
  showShadow: isScrolling,
4354
4499
  ...userSlotProps?.footer,
4355
4500
  },
4356
- }, sx: {
4357
- // Add border at bottom of rows section (above footer)
4358
- [`& .${gridClasses.virtualScrollerContent}`]: {
4359
- borderBottom: `1px solid ${semanticColors.border.primary}`,
4360
- },
4361
- ...userSx,
4362
- }, pagination: false, ...props,
4501
+ }, sx: userSx, pagination: false, ...props,
4363
4502
  // Only show loading overlay when loading AND no rows exist yet
4364
4503
  // This keeps existing rows visible while loading more data (footer shows loading spinner)
4365
4504
  loading: props.loading && !hasRows }));
@@ -4785,87 +4924,127 @@ const NeoListItem = ({ size = 'medium', primaryText, secondaryText, badge, icon,
4785
4924
  };
4786
4925
  NeoListItem.displayName = 'NeoListItem';
4787
4926
 
4788
- /**
4789
- * Styled ListItemButton with Neo design tokens
4790
- * Uses MUI's ListItemButton as base for proper accessibility and interaction
4791
- */
4792
- const StyledListItemButton = styled(ListItemButton)(({ theme }) => ({
4793
- display: 'flex',
4794
- alignItems: 'center',
4795
- gap: spacing.spacing_2,
4796
- borderRadius: borderRadius.m,
4797
- paddingTop: spacing.spacing_1,
4798
- paddingBottom: spacing.spacing_1,
4799
- paddingLeft: spacing.spacing_3_4,
4800
- paddingRight: spacing.spacing_3_4,
4801
- border: `1px solid ${semanticColors.border.primary}`,
4802
- backgroundColor: theme.palette.common.white,
4803
- transition: theme.transitions.create(['border', 'background-color']),
4804
- // Active (selected) state
4805
- [`&.${listItemButtonClasses.selected}`]: {
4806
- border: `2px solid ${semanticColors.buttons.primary.default}`,
4807
- backgroundColor: theme.palette.common.white,
4808
- '&:hover': {
4809
- backgroundColor: theme.palette.common.white,
4810
- },
4811
- // Icon color in selected state
4812
- [`& .${listItemIconClasses.root}`]: {
4813
- color: semanticColors.icons.default,
4814
- },
4815
- // Text colors in selected state
4816
- [`& .${listItemTextClasses.primary}`]: {
4817
- color: colors.grey[800],
4818
- },
4819
- [`& .${listItemTextClasses.secondary}`]: {
4820
- color: semanticColors.typography.bodySecondary,
4821
- },
4822
- },
4823
- // Deselected (default) state
4824
- [`&:not(.${listItemButtonClasses.selected}):not(.${listItemButtonClasses.disabled})`]: {
4825
- '&:hover': {
4826
- backgroundColor: colors.grey[50],
4927
+ const StyledListItemButton = styled(ListItemButton, {
4928
+ shouldForwardProp: prop => prop !== 'listVariant',
4929
+ })(({ theme, listVariant = 'card' }) => listVariant === 'nav' ? navVariantStyles(theme) : cardVariantStyles(theme));
4930
+ // Nav variant — sidebar list item: no border, compact, subtle highlights.
4931
+ // Renders children inline; no ListItemIcon/ListItemText wrappers required.
4932
+ function navVariantStyles(theme) {
4933
+ return {
4934
+ display: 'flex',
4935
+ alignItems: 'center',
4936
+ gap: spacing.spacing_2,
4937
+ borderRadius: borderRadius.s,
4938
+ paddingTop: spacing.spacing_1,
4939
+ paddingBottom: spacing.spacing_1,
4940
+ paddingLeft: spacing.spacing_2,
4941
+ paddingRight: spacing.spacing_2,
4942
+ border: 'none',
4943
+ color: semanticColors.typography.bodySecondary,
4944
+ backgroundColor: 'transparent',
4945
+ transition: theme.transitions.create(['background-color', 'color']),
4946
+ [`&.${listItemButtonClasses.selected}`]: {
4947
+ backgroundColor: semanticColors.surfaces.activeHighlight,
4948
+ color: semanticColors.typography.body,
4949
+ '&:hover': {
4950
+ backgroundColor: semanticColors.surfaces.activeHighlight,
4951
+ },
4827
4952
  },
4828
- [`& .${listItemIconClasses.root}`]: {
4829
- color: semanticColors.icons.disabled,
4953
+ [`&:not(.${listItemButtonClasses.selected}):not(.${listItemButtonClasses.disabled})`]: {
4954
+ '&:hover': {
4955
+ backgroundColor: semanticColors.surfaces.listHover,
4956
+ color: semanticColors.typography.body,
4957
+ },
4830
4958
  },
4831
- [`& .${listItemTextClasses.primary}`]: {
4832
- color: semanticColors.buttons.tertiary.disabled,
4959
+ [`&.${listItemButtonClasses.focusVisible}`]: {
4960
+ outline: `2px solid ${semanticColors.border.focus}`,
4961
+ outlineOffset: -2,
4833
4962
  },
4834
- [`& .${listItemTextClasses.secondary}`]: {
4963
+ [`&.${listItemButtonClasses.disabled}`]: {
4835
4964
  color: semanticColors.typography.button.disabled,
4965
+ opacity: 1,
4836
4966
  },
4837
- },
4838
- // Focus state
4839
- [`&.${listItemButtonClasses.focusVisible}`]: {
4840
- outline: `2px solid ${semanticColors.buttons.primary.default}`,
4841
- outlineOffset: 2,
4842
- border: `2px solid ${semanticColors.buttons.primary.default}`,
4967
+ };
4968
+ }
4969
+ function cardVariantStyles(theme) {
4970
+ return {
4971
+ display: 'flex',
4972
+ alignItems: 'center',
4973
+ gap: spacing.spacing_2,
4974
+ borderRadius: borderRadius.m,
4975
+ paddingTop: spacing.spacing_1,
4976
+ paddingBottom: spacing.spacing_1,
4977
+ paddingLeft: spacing.spacing_3_4,
4978
+ paddingRight: spacing.spacing_3_4,
4979
+ border: `1px solid ${semanticColors.border.primary}`,
4843
4980
  backgroundColor: theme.palette.common.white,
4844
- [`& .${listItemIconClasses.root}`]: {
4845
- color: semanticColors.icons.default,
4846
- },
4847
- [`& .${listItemTextClasses.primary}`]: {
4848
- color: colors.grey[800],
4849
- },
4850
- [`& .${listItemTextClasses.secondary}`]: {
4851
- color: semanticColors.typography.bodySecondary,
4981
+ transition: theme.transitions.create(['border', 'background-color']),
4982
+ // Active (selected) state
4983
+ [`&.${listItemButtonClasses.selected}`]: {
4984
+ border: `2px solid ${semanticColors.buttons.primary.default}`,
4985
+ backgroundColor: theme.palette.common.white,
4986
+ '&:hover': {
4987
+ backgroundColor: theme.palette.common.white,
4988
+ },
4989
+ // Icon color in selected state
4990
+ [`& .${listItemIconClasses.root}`]: {
4991
+ color: semanticColors.icons.default,
4992
+ },
4993
+ // Text colors in selected state
4994
+ [`& .${listItemTextClasses.primary}`]: {
4995
+ color: colors.grey[800],
4996
+ },
4997
+ [`& .${listItemTextClasses.secondary}`]: {
4998
+ color: semanticColors.typography.bodySecondary,
4999
+ },
4852
5000
  },
4853
- },
4854
- // Disabled state
4855
- [`&.${listItemButtonClasses.disabled}`]: {
4856
- backgroundColor: colors.grey[50],
4857
- opacity: 1, // Override MUI default opacity
4858
- [`& .${listItemIconClasses.root}`]: {
4859
- color: semanticColors.icons.disabled,
5001
+ // Deselected (default) state
5002
+ [`&:not(.${listItemButtonClasses.selected}):not(.${listItemButtonClasses.disabled})`]: {
5003
+ '&:hover': {
5004
+ backgroundColor: colors.grey[50],
5005
+ },
5006
+ [`& .${listItemIconClasses.root}`]: {
5007
+ color: semanticColors.icons.disabled,
5008
+ },
5009
+ [`& .${listItemTextClasses.primary}`]: {
5010
+ color: semanticColors.buttons.tertiary.disabled,
5011
+ },
5012
+ [`& .${listItemTextClasses.secondary}`]: {
5013
+ color: semanticColors.typography.button.disabled,
5014
+ },
4860
5015
  },
4861
- [`& .${listItemTextClasses.primary}`]: {
4862
- color: colors.grey[300],
5016
+ // Focus state
5017
+ [`&.${listItemButtonClasses.focusVisible}`]: {
5018
+ outline: `2px solid ${semanticColors.buttons.primary.default}`,
5019
+ outlineOffset: 2,
5020
+ border: `2px solid ${semanticColors.buttons.primary.default}`,
5021
+ backgroundColor: theme.palette.common.white,
5022
+ [`& .${listItemIconClasses.root}`]: {
5023
+ color: semanticColors.icons.default,
5024
+ },
5025
+ [`& .${listItemTextClasses.primary}`]: {
5026
+ color: colors.grey[800],
5027
+ },
5028
+ [`& .${listItemTextClasses.secondary}`]: {
5029
+ color: semanticColors.typography.bodySecondary,
5030
+ },
4863
5031
  },
4864
- [`& .${listItemTextClasses.secondary}`]: {
4865
- color: colors.grey[300],
5032
+ // Disabled state
5033
+ [`&.${listItemButtonClasses.disabled}`]: {
5034
+ backgroundColor: colors.grey[50],
5035
+ opacity: 1, // Override MUI default opacity
5036
+ [`& .${listItemIconClasses.root}`]: {
5037
+ color: semanticColors.icons.disabled,
5038
+ },
5039
+ [`& .${listItemTextClasses.primary}`]: {
5040
+ color: colors.grey[300],
5041
+ },
5042
+ [`& .${listItemTextClasses.secondary}`]: {
5043
+ color: colors.grey[300],
5044
+ },
4866
5045
  },
4867
- },
4868
- }));
5046
+ };
5047
+ }
4869
5048
  /**
4870
5049
  * NeoListItemButton - Selectable list item with icon and text
4871
5050
  *
@@ -4909,8 +5088,8 @@ const StyledListItemButton = styled(ListItemButton)(({ theme }) => ({
4909
5088
  * - colors.grey[300] (#d1d5db) - Disabled text
4910
5089
  * - colors.grey[50] (#f9fafb) - Disabled background
4911
5090
  */
4912
- const NeoListItemButton = ({ children, selected = false, disabled = false, ...props }) => {
4913
- return (jsx(StyledListItemButton, { selected: selected, disabled: disabled, ...props, children: children }));
5091
+ const NeoListItemButton = ({ children, selected = false, disabled = false, variant = 'card', ...props }) => {
5092
+ return (jsx(StyledListItemButton, { selected: selected, disabled: disabled, listVariant: variant, ...props, children: children }));
4914
5093
  };
4915
5094
  NeoListItemButton.displayName = 'NeoListItemButton';
4916
5095
 
@@ -4920,7 +5099,6 @@ const StyledMenu = styled(Menu)(({ theme }) => ({
4920
5099
  borderRadius: borderRadius.s,
4921
5100
  border: `1px solid ${semanticColors.border.primary}`,
4922
5101
  boxShadow: `${shadows.dropdown.x}px ${shadows.dropdown.y}px ${shadows.dropdown.blur}px ${shadows.dropdown.spread}px ${shadows.dropdown.shadow}`,
4923
- minWidth: 200,
4924
5102
  marginTop: theme.spacing(1),
4925
5103
  paddingTop: theme.spacing(1),
4926
5104
  paddingBottom: theme.spacing(1),
@@ -5147,9 +5325,8 @@ NeoModalFooter.displayName = 'NeoModalFooter';
5147
5325
  const NavigationAvatarContainer = styled('div')({
5148
5326
  display: 'flex',
5149
5327
  boxSizing: 'border-box',
5150
- width: spacing.spacing_5,
5151
- height: spacing.spacing_5,
5152
5328
  padding: spacing.spacing_1_2,
5329
+ aspectRatio: '1 / 1',
5153
5330
  justifyContent: 'center',
5154
5331
  alignItems: 'center',
5155
5332
  borderRadius: '50%',
@@ -5167,11 +5344,98 @@ const NavigationAvatarContainer = styled('div')({
5167
5344
  *
5168
5345
  * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC?node-id=11325-102
5169
5346
  */
5170
- const NeoNavigationAvatar = ({ colorIndex = 0, children, ...props }) => {
5171
- return (jsx(NavigationAvatarContainer, { children: jsx(NeoGeneralAvatar, { size: "small", colorIndex: colorIndex, ...props, children: children }) }));
5347
+ const NeoNavigationAvatar = ({ children, ...props }) => {
5348
+ return (jsx(NavigationAvatarContainer, { children: jsx(NeoGeneralAvatar, { size: "small", ...props, children: children }) }));
5172
5349
  };
5173
5350
  NeoNavigationAvatar.displayName = 'NeoNavigationAvatar';
5174
5351
 
5352
+ const NeoSideNavContext = createContext({
5353
+ collapsed: false,
5354
+ });
5355
+ const useNeoSideNav = () => useContext(NeoSideNavContext);
5356
+
5357
+ /**
5358
+ * Variant color configuration
5359
+ */
5360
+ const variantConfig = {
5361
+ light: {
5362
+ backgroundColor: semanticColors.surfaces.tooltip, // #4b5563 - medium gray
5363
+ color: semanticColors.typography.tooltip, // #ffffff - white
5364
+ },
5365
+ dark: {
5366
+ backgroundColor: colors.grey[50], // #f9fafb - very light gray
5367
+ color: colors.grey[800], // #1f2937 - dark gray
5368
+ },
5369
+ brand: {
5370
+ backgroundColor: colors.digitalBlue[800], // #131e7a - dark blue
5371
+ color: semanticColors.typography.tooltip, // #ffffff - white
5372
+ },
5373
+ };
5374
+ /**
5375
+ * Styled MUI Tooltip with Neo design system tokens
5376
+ */
5377
+ const StyledTooltip$1 = styled(Tooltip, {
5378
+ shouldForwardProp: prop => prop !== 'variant' && prop !== 'description',
5379
+ })(({ variant = 'light', description }) => {
5380
+ const hasDescription = Boolean(description);
5381
+ const variantStyles = variantConfig[variant];
5382
+ return {
5383
+ // Style the tooltip content
5384
+ [`& .${tooltipClasses.tooltip}`]: {
5385
+ backgroundColor: variantStyles.backgroundColor,
5386
+ color: variantStyles.color,
5387
+ fontSize: typography.fontSize.xs,
5388
+ fontWeight: typography.fontWeight.medium,
5389
+ lineHeight: hasDescription ? 1.5 : 1,
5390
+ borderRadius: hasDescription ? borderRadius.s : borderRadius.xS,
5391
+ padding: hasDescription ? spacing.spacing_1_1_2 : `0 ${spacing.spacing_1}px`,
5392
+ ...(hasDescription && {
5393
+ maxWidth: 296,
5394
+ }),
5395
+ ...(!hasDescription && {
5396
+ height: spacing.spacing_3_1_4,
5397
+ display: 'flex',
5398
+ alignItems: 'center',
5399
+ justifyContent: 'center',
5400
+ }),
5401
+ boxShadow: `${shadows.neutral.medium.x}px ${shadows.neutral.medium.y}px ${shadows.neutral.medium.blur}px ${shadows.neutral.medium.spread}px ${shadows.neutral.medium.shadow}`,
5402
+ },
5403
+ // Style the arrow
5404
+ [`& .${tooltipClasses.arrow}`]: {
5405
+ color: variantStyles.backgroundColor,
5406
+ },
5407
+ };
5408
+ });
5409
+ /**
5410
+ * NeoTooltip - Tooltip component following Neo design system
5411
+ *
5412
+ * Provides contextual information when users hover over or focus on an element.
5413
+ * Supports three visual variants (light, dark, brand) and optional supporting text.
5414
+ *
5415
+ * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC/Neo---Moderne-Design-system---2025?node-id=4091-26557&t=Bo58EpFmg6ILJtmv-11
5416
+ *
5417
+ * Figma Props Mapping:
5418
+ * - Theme (Light mode|Dark mode|Brand color) → variant ('light'|'dark'|'brand')
5419
+ * - Placement → arrow (boolean) + placement (top/bottom/left/right/etc)
5420
+ * - Supporting text (True|False) → description (string|undefined)
5421
+ * - text → title (string, literal content)
5422
+ *
5423
+ * Design Tokens Used:
5424
+ * - Light: surfaces.tooltip (#4b5563), typography.tooltip (#ffffff)
5425
+ * - Dark: grey[50] (#f9fafb), grey[800] (#1f2937)
5426
+ * - Brand: digitalBlue[800] (#131e7a), typography.tooltip (#ffffff)
5427
+ * - Shadow: neutralMedium (0px 8px 15px 0px rgba(31,41,55,0.1))
5428
+ * - Typography: fontSize.xs (12), fontSize.caption (13), fontWeight.medium (500), fontWeight.semiBold (600)
5429
+ */
5430
+ const NeoTooltip = ({ variant = 'light', title, description, children, arrow = false, placement, ...props }) => {
5431
+ // Build the title content
5432
+ // If description is provided, create a structured layout with title + description
5433
+ // Otherwise, just show the title text
5434
+ const titleContent = description ? (jsxs(Stack, { gap: 0.5, children: [jsx(Typography, { fontSize: typography.fontSize.caption, fontWeight: typography.fontWeight.semiBold, children: title }), jsx(Typography, { fontSize: typography.fontSize.xs, fontWeight: typography.fontWeight.medium, sx: { opacity: 0.75 }, children: description })] })) : (title);
5435
+ return (jsx(StyledTooltip$1, { variant: variant, description: description, title: titleContent, arrow: arrow, placement: placement, ...props, children: children }));
5436
+ };
5437
+ NeoTooltip.displayName = 'NeoTooltip';
5438
+
5175
5439
  const customProps = ['selected'];
5176
5440
  const StyledRoot = styled(ButtonBase, {
5177
5441
  shouldForwardProp: prop => !customProps.includes(prop),
@@ -5190,41 +5454,34 @@ const StyledRoot = styled(ButtonBase, {
5190
5454
  textDecoration: 'none',
5191
5455
  '&:hover .neo-nav-icon-padding': {
5192
5456
  backgroundColor: semanticColors.buttons.secondary.hoverBackground,
5193
- borderColor: colors.digitalBlue[100],
5457
+ borderColor: semanticColors.buttons.secondary.pressedBackground,
5194
5458
  },
5195
5459
  '&:hover .neo-nav-label': {
5196
5460
  color: semanticColors.buttons.primary.hover,
5197
5461
  },
5462
+ [`& .${chipClasses.root}`]: {
5463
+ flexShrink: 0,
5464
+ },
5198
5465
  '&:focus-visible': {
5199
- ...focusRingStyles,
5466
+ outline: 'none',
5200
5467
  },
5201
5468
  '&:focus-visible .neo-nav-icon-padding': {
5202
- backgroundColor: semanticColors.buttons.secondary.hoverBackground,
5203
- borderColor: colors.digitalBlue[100],
5204
- },
5205
- '&:focus-visible .neo-nav-label': {
5206
- color: semanticColors.buttons.primary.hover,
5469
+ ...focusRingStyles,
5207
5470
  },
5208
5471
  ...(selected && {
5209
5472
  '& .neo-nav-icon-padding': {
5210
- backgroundColor: colors.digitalBlue[100],
5473
+ backgroundColor: semanticColors.buttons.secondary.pressedBackground,
5211
5474
  },
5212
5475
  '& .neo-nav-label': {
5213
5476
  color: semanticColors.buttons.primary.pressed,
5214
5477
  fontWeight: typography.fontWeight.semiBold,
5215
5478
  },
5216
5479
  '&:hover .neo-nav-icon-padding': {
5217
- backgroundColor: colors.digitalBlue[100],
5480
+ backgroundColor: semanticColors.buttons.secondary.pressedBackground,
5218
5481
  },
5219
5482
  '&:hover .neo-nav-label': {
5220
5483
  color: semanticColors.buttons.primary.pressed,
5221
5484
  },
5222
- '&:focus-visible .neo-nav-icon-padding': {
5223
- backgroundColor: colors.digitalBlue[100],
5224
- },
5225
- '&:focus-visible .neo-nav-label': {
5226
- color: semanticColors.buttons.primary.pressed,
5227
- },
5228
5485
  }),
5229
5486
  }));
5230
5487
  const IconPadding = styled('span')({
@@ -5245,28 +5502,21 @@ const Label$2 = styled('span')(({ theme }) => ({
5245
5502
  width: '100%',
5246
5503
  transition: 'color 150ms',
5247
5504
  }));
5248
- const TagPill = styled('span')(({ theme }) => ({
5249
- display: 'inline-flex',
5250
- alignItems: 'center',
5251
- justifyContent: 'center',
5252
- height: 18,
5253
- paddingLeft: spacing.spacing_3_4, // 6px
5254
- paddingRight: spacing.spacing_3_4, // 6px
5255
- borderRadius: borderRadius.full,
5256
- backgroundColor: colors.digitalBlue[300], // #8D99FF
5257
- color: semanticColors.typography.tooltip, // white
5258
- fontFamily: typography.fontFamily.body,
5259
- fontWeight: typography.fontWeight.medium,
5260
- fontSize: theme.typography.pxToRem(typography.fontSize.xs), // 12px
5261
- lineHeight: 1,
5262
- }));
5263
5505
  /**
5264
5506
  * NeoNavigationItem - Vertical navigation item with icon, label, and optional tag
5265
5507
  *
5266
5508
  * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC/Neo---Moderne-Design-system---2025?node-id=8455-6120
5267
5509
  */
5268
- function NeoNavigationItem({ icon, label, selected = false, tag, children, ...props }) {
5269
- return (jsxs(StyledRoot, { selected: selected, disableRipple: true, ...props, children: [jsx(IconPadding, { className: "neo-nav-icon-padding", children: icon }), label && jsx(Label$2, { className: "neo-nav-label", children: label }), tag && jsx(TagPill, { children: tag }), children] }));
5510
+ function NeoNavigationItem({ icon, label, selected = false, tag, tooltip, slotProps, children, ...props }) {
5511
+ const { collapsed } = useNeoSideNav();
5512
+ // When collapsed the label is hidden, so fall back to it for the tooltip and
5513
+ // accessible name — otherwise an icon-only button has no name (WCAG 4.1.2).
5514
+ const collapsedTooltip = tooltip ?? label;
5515
+ const item = (jsxs(StyledRoot, { selected: selected, "aria-label": collapsed && typeof label === 'string' ? label : undefined, disableRipple: true, ...props, children: [jsx(IconPadding, { className: "neo-nav-icon-padding", children: icon }), !collapsed && label && jsx(Label$2, { className: "neo-nav-label", children: label }), !collapsed && tag && (jsx(NeoTag, { size: "medium", variant: "filled", intent: "beta", label: tag, ...slotProps?.badge })), children] }));
5516
+ if (collapsed && collapsedTooltip) {
5517
+ return (jsx(NeoTooltip, { title: collapsedTooltip, placement: "right", arrow: true, children: item }));
5518
+ }
5519
+ return item;
5270
5520
  }
5271
5521
  NeoNavigationItem.displayName = 'NeoNavigationItem';
5272
5522
 
@@ -5312,11 +5562,11 @@ const LabelText = styled('span', {
5312
5562
  * NeoAvatarCell — DataGrid cell displaying a user avatar with optional label.
5313
5563
  * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC?node-id=13425-1725
5314
5564
  */
5315
- const NeoAvatarCell = ({ name, src, colorIndex = 0, label, disabled = false, empty = false, }) => {
5565
+ const NeoAvatarCell = ({ name, src, label, disabled = false, empty = false, }) => {
5316
5566
  if (empty) {
5317
5567
  return jsx(StyledCell$1, { disabled: disabled });
5318
5568
  }
5319
- return (jsxs(StyledCell$1, { disabled: disabled, children: [jsx(NeoGeneralAvatar, { size: "small", src: src, alt: name, colorIndex: colorIndex, children: !src && name ? name.charAt(0).toUpperCase() : undefined }), label && jsx(LabelText, { disabled: disabled, children: label })] }));
5569
+ return (jsxs(StyledCell$1, { disabled: disabled, children: [jsx(NeoGeneralAvatar, { size: "small", src: src, alt: name, children: !src && name ? name.charAt(0).toUpperCase() : undefined }), label && jsx(LabelText, { disabled: disabled, children: label })] }));
5320
5570
  };
5321
5571
  NeoAvatarCell.displayName = 'NeoAvatarCell';
5322
5572
 
@@ -5530,7 +5780,7 @@ const TooltipErrorPre = styled('pre')({
5530
5780
  maxHeight: 200,
5531
5781
  overflowY: 'auto',
5532
5782
  });
5533
- const StyledTooltip$1 = styled(Tooltip)({
5783
+ const StyledTooltip = styled(Tooltip)({
5534
5784
  [`& .${tooltipClasses.tooltip}`]: {
5535
5785
  backgroundColor: semanticColors.surfaces.tooltip,
5536
5786
  maxWidth: 400,
@@ -5554,7 +5804,7 @@ const NeoStatusCell = ({ icon, label, details, disabled = false, variant = 'succ
5554
5804
  }
5555
5805
  const chip = (jsxs(StyledChip, { disabled: disabled, variant: variant, children: [icon, label] }));
5556
5806
  if (details) {
5557
- return (jsx(StyledTooltip$1, { title: jsx(TooltipErrorPre, { children: details }), arrow: true, placement: "bottom-start", children: jsx(Box, { component: "span", sx: { display: 'inline-flex' }, children: chip }) }));
5807
+ return (jsx(StyledTooltip, { title: jsx(TooltipErrorPre, { children: details }), arrow: true, placement: "bottom-start", children: jsx(Box, { component: "span", sx: { display: 'inline-flex' }, children: chip }) }));
5558
5808
  }
5559
5809
  return chip;
5560
5810
  };
@@ -5574,10 +5824,9 @@ const StickyHeader = styled(Box)(({ theme }) => ({
5574
5824
  * Page title typography
5575
5825
  */
5576
5826
  const PageTitle = styled(Typography)(() => ({
5577
- fontSize: typography.fontSize.h3,
5578
- fontWeight: typography.fontWeight.medium,
5827
+ ...semanticTypography.titles.pageHeader,
5579
5828
  lineHeight: 1.4,
5580
- color: colors.grey['900'], // #111827 - matches Figma typography/page-header
5829
+ color: colors.grey['900'],
5581
5830
  }));
5582
5831
  /**
5583
5832
  * Subtitle typography
@@ -5641,7 +5890,12 @@ const Subtitle = styled(Typography)(() => ({
5641
5890
  * </NeoPageContent>
5642
5891
  * ```
5643
5892
  */
5644
- function NeoPageContent({ pageTitle, subtitle, breadcrumbs, action, sticky = false, contentMaxWidth = false, centerContent = true, disableGutters = false, isLoading = false, showBackToTop = true, children, sx, ...boxProps }) {
5893
+ function NeoPageContent({ pageTitle, subtitle, breadcrumbs, action, sticky = false, contentMaxWidth: contentMaxWidthProp = false, centerContent = true, disableGutters: disableGuttersProp = false, isLoading = false, showBackToTop = true, layout = 'default', children, sx, ...boxProps }) {
5894
+ // fullBleed forces no max-width, no gutters, and zero bottom padding
5895
+ // so children can fill the viewport edge-to-edge.
5896
+ const isFullBleed = layout === 'fullBleed';
5897
+ const contentMaxWidth = isFullBleed ? false : contentMaxWidthProp;
5898
+ const disableGutters = isFullBleed || disableGuttersProp;
5645
5899
  const [showBackToTopButton, setShowBackToTopButton] = useState(false);
5646
5900
  const headerRef = useRef(null);
5647
5901
  const containerRef = useRef(null);
@@ -5671,7 +5925,7 @@ function NeoPageContent({ pageTitle, subtitle, breadcrumbs, action, sticky = fal
5671
5925
  // Also try to scroll window in case component is in a different context
5672
5926
  window.scrollTo({ top: 0, behavior: 'smooth' });
5673
5927
  };
5674
- const headerContent = (jsxs(Stack, { ref: headerRef, sx: { flexShrink: 0, gap: '0.5rem' }, children: [breadcrumbs && breadcrumbs.items.length > 0 && (jsx(NeoBreadcrumbs, { children: breadcrumbs.items.map((item, index) => (jsx(NeoBreadcrumbLink, { href: item.href, component: item.href && breadcrumbs.linkComponent ? breadcrumbs.linkComponent : undefined, current: index === breadcrumbs.items.length - 1, children: item.label }, item.href ?? index))) })), jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "flex-start", sx: { gap: '1rem' }, children: [jsxs(Stack, { sx: { gap: '0.5rem', flexGrow: 1 }, children: [jsx(PageTitle, { children: pageTitle }), subtitle &&
5928
+ const headerContent = (jsxs(Stack, { ref: headerRef, sx: { flexShrink: 0, gap: '0.5rem' }, children: [breadcrumbs && breadcrumbs.items.length > 0 && (jsx(NeoBreadcrumbs, { children: breadcrumbs.items.map((item, index) => (jsx(NeoBreadcrumbLink, { href: item.href, component: item.href && breadcrumbs.linkComponent ? breadcrumbs.linkComponent : undefined, current: index === breadcrumbs.items.length - 1, children: item.label }, item.href ?? index))) })), jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "flex-start", sx: { gap: '1rem' }, children: [jsxs(Stack, { sx: { gap: '0.5rem', flexGrow: 1 }, children: [typeof pageTitle === 'string' ? (jsx(PageTitle, { component: "h1", children: pageTitle })) : (pageTitle), subtitle &&
5675
5929
  (typeof subtitle === 'string' ? (jsx(Subtitle, { variant: "caption", children: subtitle })) : (subtitle))] }), action] })] }));
5676
5930
  const content = isLoading ? (jsx(Box, { sx: {
5677
5931
  display: 'flex',
@@ -5693,7 +5947,7 @@ function NeoPageContent({ pageTitle, subtitle, breadcrumbs, action, sticky = fal
5693
5947
  flexDirection: 'column',
5694
5948
  px: disableGutters ? 0 : `${spacing.spacing_2_1_2}px`,
5695
5949
  pt: sticky ? 0 : `${spacing.spacing_2}px`,
5696
- pb: `${spacing.spacing_2_1_2}px`,
5950
+ pb: isFullBleed ? 0 : `${spacing.spacing_2_1_2}px`,
5697
5951
  height: '100%',
5698
5952
  overflow: 'auto',
5699
5953
  }, children: [sticky ? (jsx(StickyHeader, { ref: headerRef, sx: {
@@ -5718,7 +5972,7 @@ function NeoPageContent({ pageTitle, subtitle, breadcrumbs, action, sticky = fal
5718
5972
  width: '100%',
5719
5973
  ...(centerContent ? { mx: 'auto' } : { alignSelf: 'flex-start' }),
5720
5974
  }),
5721
- }, children: content })] }) }), showBackToTop && (jsx(Fade, { in: showBackToTopButton, children: jsx(Box, { sx: {
5975
+ }, children: content })] }) }), showBackToTop && (jsx(Fade$1, { in: showBackToTopButton, children: jsx(Box, { sx: {
5722
5976
  position: 'fixed',
5723
5977
  bottom: spacing.spacing_2,
5724
5978
  right: spacing.spacing_4,
@@ -6023,6 +6277,55 @@ const NeoRadio = ({ size = 'medium', label, helperText, disabled, ...props }) =>
6023
6277
  };
6024
6278
  NeoRadio.displayName = 'NeoRadio';
6025
6279
 
6280
+ /**
6281
+ * NeoRadioButtonWithText
6282
+ *
6283
+ * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC?node-id=11565-7682
6284
+ */
6285
+ const NeoRadioButtonWithText = styled('div')({});
6286
+
6287
+ // Box-breathing rhythm: appear (inhale) → hold → expand+fade (exhale) → rest.
6288
+ // Max scale is capped so the ring fits within a parent row's line-height.
6289
+ const ripple = keyframes `
6290
+ 0% { opacity: 0; transform: scale(0.7); }
6291
+ 20% { opacity: 0.9; transform: scale(0.7); }
6292
+ 35% { opacity: 0.9; transform: scale(0.7); }
6293
+ 80% { opacity: 0; transform: scale(1.7); }
6294
+ 100% { opacity: 0; transform: scale(0.7); }
6295
+ `;
6296
+ /**
6297
+ * NeoRipplingDot - Animated status dot with an expanding ripple ring.
6298
+ *
6299
+ * Indicates an in-progress, indeterminate state (RUNNING / SYNCING / PROCESSING).
6300
+ * Color is inherited from `currentColor`; set it via the `color`/`sx` prop or a
6301
+ * parent. Sized to the lowercase-letter height regardless of parent fontSize.
6302
+ */
6303
+ const NeoRipplingDot = props => (jsx(Box$1, { "aria-hidden": "true", ...props, style: {
6304
+ width: spacing.spacing_1,
6305
+ height: spacing.spacing_1,
6306
+ ...props.style,
6307
+ }, sx: {
6308
+ position: 'relative',
6309
+ display: 'inline-block',
6310
+ borderRadius: '50%',
6311
+ backgroundColor: 'currentColor',
6312
+ verticalAlign: 'middle',
6313
+ flexShrink: 0,
6314
+ '&::before': {
6315
+ content: '""',
6316
+ position: 'absolute',
6317
+ inset: '-25%',
6318
+ borderRadius: '50%',
6319
+ border: '1px solid currentColor',
6320
+ animation: `${ripple} 5.6s ease-in-out infinite`,
6321
+ '@media (prefers-reduced-motion: reduce)': {
6322
+ display: 'none',
6323
+ },
6324
+ },
6325
+ ...props.sx,
6326
+ } }));
6327
+ NeoRipplingDot.displayName = 'NeoRipplingDot';
6328
+
6026
6329
  const StyledSearchChip = styled(InputBase)(({ theme }) => ({
6027
6330
  borderRadius: borderRadius.full,
6028
6331
  border: `1px solid ${semanticColors.buttons.secondary.defaultBorder}`,
@@ -6088,6 +6391,126 @@ const NeoSearchChip = ({ onClear, value, ...props }) => {
6088
6391
  };
6089
6392
  NeoSearchChip.displayName = 'NeoSearchChip';
6090
6393
 
6394
+ /**
6395
+ * NeoSelectField — composite of NeoInputField's form chrome (label,
6396
+ * helper text, error state) wrapped around NeoSelect. Mirrors the
6397
+ * MUI `<TextField select>` ergonomics with Neo design tokens, so
6398
+ * consumers don't have to compose the two manually.
6399
+ *
6400
+ * @example
6401
+ * <NeoSelectField
6402
+ * label="Response format"
6403
+ * value={format}
6404
+ * onChange={e => setFormat(e.target.value)}
6405
+ * options={[
6406
+ * { value: 'json', label: 'JSON' },
6407
+ * { value: 'plain', label: 'Plain text' },
6408
+ * ]}
6409
+ * />
6410
+ */
6411
+ const NeoSelectField = ({ size = 'medium', destructive = false, label, required = false, infoIcon, helperText, errorMessage, options, children, disabled, id, ...selectProps }) => {
6412
+ const inputId = id || `neo-select-${Math.random().toString(36).substring(7)}`;
6413
+ const helperTextId = helperText || errorMessage ? `${inputId}-helper-text` : undefined;
6414
+ return (jsxs(StyledFormControl, { size: size, error: destructive, disabled: disabled, children: [label && (jsxs(StyledInputLabel, { htmlFor: inputId, size: size, infoIcon: !!infoIcon, disabled: disabled, error: destructive, shrink: true, children: [label, required && jsx("span", { "aria-hidden": "true", children: "*" }), infoIcon && jsx(InfoIconWrapper, { children: infoIcon })] })), jsx(NeoSelect, { id: inputId, disabled: disabled, error: destructive, "aria-describedby": helperTextId, ...selectProps, children: children ??
6415
+ options?.map(opt => (jsx(NeoMenuItem, { value: opt.value, disabled: opt.disabled, children: opt.label }, String(opt.value)))) }), (helperText || errorMessage) && (jsx(StyledFormHelperText, { id: helperTextId, error: destructive, disabled: disabled, sx: { marginTop: `${spacing.spacing_3_4}px` }, children: destructive ? errorMessage : helperText }))] }));
6416
+ };
6417
+ NeoSelectField.displayName = 'NeoSelectField';
6418
+
6419
+ const EXPANDED_WIDTH = 98;
6420
+ const COLLAPSED_WIDTH = 56;
6421
+ // The fade overlay must end on the same color as the rail to blend cleanly.
6422
+ const RAIL_BACKGROUND = colors.grey[100];
6423
+ /**
6424
+ * NeoSideNav
6425
+ *
6426
+ * Collapsible vertical navigation rail with fixed `header`/`footer` slots and a
6427
+ * scrolling content area. Controlled via `collapsed` + `onCollapsedChange`;
6428
+ * broadcasts collapsed state to descendant `NeoNavigationItem`s through context.
6429
+ *
6430
+ * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC?node-id=4065-3425
6431
+ */
6432
+ const Root = styled('nav', {
6433
+ shouldForwardProp: prop => prop !== 'collapsed',
6434
+ })(({ collapsed, theme }) => ({
6435
+ display: 'flex',
6436
+ flexDirection: 'column',
6437
+ height: '100%',
6438
+ width: collapsed ? COLLAPSED_WIDTH : EXPANDED_WIDTH,
6439
+ minWidth: collapsed ? COLLAPSED_WIDTH : EXPANDED_WIDTH,
6440
+ backgroundColor: RAIL_BACKGROUND,
6441
+ transition: theme.transitions.create(['width', 'min-width'], {
6442
+ duration: theme.transitions.duration.shorter,
6443
+ }),
6444
+ overflow: 'hidden',
6445
+ }));
6446
+ const Header = styled('div')({
6447
+ flexShrink: 0,
6448
+ display: 'flex',
6449
+ flexDirection: 'column',
6450
+ alignItems: 'center',
6451
+ });
6452
+ const Scroll = styled('div')({
6453
+ flex: 1,
6454
+ minHeight: 0,
6455
+ overflowY: 'auto',
6456
+ overflowX: 'hidden',
6457
+ display: 'flex',
6458
+ flexDirection: 'column',
6459
+ alignItems: 'center',
6460
+ gap: spacing.spacing_1_2,
6461
+ paddingInline: spacing.spacing_1,
6462
+ '&::-webkit-scrollbar': { width: spacing.spacing_1_2 },
6463
+ '&::-webkit-scrollbar-thumb': {
6464
+ backgroundColor: semanticColors.border.primary,
6465
+ borderRadius: borderRadius.xXS,
6466
+ },
6467
+ });
6468
+ const FooterRegion = styled('div')({
6469
+ position: 'relative',
6470
+ flexShrink: 0,
6471
+ display: 'flex',
6472
+ flexDirection: 'column',
6473
+ alignItems: 'center',
6474
+ gap: spacing.spacing_1_2,
6475
+ paddingInline: spacing.spacing_1,
6476
+ paddingBottom: spacing.spacing_1,
6477
+ });
6478
+ // Gradient fade so scrolling items dissolve into the footer instead of butting against it.
6479
+ const Fade = styled('div')({
6480
+ position: 'absolute',
6481
+ top: -spacing.spacing_3,
6482
+ left: 0,
6483
+ right: 0,
6484
+ height: spacing.spacing_3,
6485
+ pointerEvents: 'none',
6486
+ background: `linear-gradient(to bottom, transparent, ${RAIL_BACKGROUND})`,
6487
+ });
6488
+ const Toggle = styled(ButtonBase)(({ theme }) => ({
6489
+ display: 'flex',
6490
+ alignItems: 'center',
6491
+ justifyContent: 'center',
6492
+ flexDirection: 'column',
6493
+ gap: spacing.spacing_1_2,
6494
+ width: '100%',
6495
+ paddingBlock: spacing.spacing_1,
6496
+ borderRadius: borderRadius.s,
6497
+ border: `1px solid ${semanticColors.border.secondary}`,
6498
+ color: semanticColors.typography.bodySecondary,
6499
+ fontFamily: typography.fontFamily.body,
6500
+ fontSize: theme.typography.pxToRem(11),
6501
+ lineHeight: 1,
6502
+ '&:hover': {
6503
+ color: semanticColors.typography.body,
6504
+ borderColor: semanticColors.border.primary,
6505
+ },
6506
+ }));
6507
+ function NeoSideNav({ collapsed, onCollapsedChange, header, footer, children, collapseLabel = 'Less', ...rest }) {
6508
+ const ToggleIcon = collapsed ? PanelLeftOpen : PanelLeftClose;
6509
+ const contextValue = useMemo(() => ({ collapsed }), [collapsed]);
6510
+ return (jsx(NeoSideNavContext.Provider, { value: contextValue, children: jsxs(Root, { collapsed: collapsed, ...rest, children: [header && jsx(Header, { children: header }), jsx(Scroll, { children: children }), jsxs(FooterRegion, { children: [jsx(Fade, {}), footer, jsxs(Toggle, { "data-testid": "neo-side-nav-toggle", "aria-label": collapsed ? 'Expand navigation' : 'Collapse navigation', disableRipple: true, onClick: () => onCollapsedChange(!collapsed), children: [jsx(ToggleIcon, { size: 18 }), !collapsed && jsx("span", { children: collapseLabel })] })] })] }) }));
6511
+ }
6512
+ NeoSideNav.displayName = 'NeoSideNav';
6513
+
6091
6514
  const StyledSkeleton = styled(Skeleton, {
6092
6515
  shouldForwardProp: prop => prop !== 'colorTheme' && prop !== 'position',
6093
6516
  })(({ theme, colorTheme = 'light', position = 'start' }) => ({
@@ -6135,6 +6558,111 @@ const NeoSkeleton = ({ colorTheme = 'light', position = 'start', ...props }) =>
6135
6558
  };
6136
6559
  NeoSkeleton.displayName = 'NeoSkeleton';
6137
6560
 
6561
+ const sizePadding = {
6562
+ small: `${spacing.spacing_3_4}px ${spacing.spacing_1_1_2}px`,
6563
+ medium: `${spacing.spacing_1_1_2}px ${spacing.spacing_2}px`,
6564
+ };
6565
+ const sizeFontSize = {
6566
+ small: typography.fontSize.xs,
6567
+ medium: typography.fontSize.sm,
6568
+ };
6569
+ const StyledTable = styled(MuiTable, {
6570
+ shouldForwardProp: prop => prop !== 'tableSize',
6571
+ })(({ theme, tableSize = 'small' }) => ({
6572
+ borderCollapse: 'separate',
6573
+ borderSpacing: 0,
6574
+ [`& .${tableCellClasses.head}`]: {
6575
+ backgroundColor: colors.grey[50],
6576
+ color: semanticColors.typography.body,
6577
+ fontFamily: typography.fontFamily.body,
6578
+ fontSize: theme.typography.pxToRem(sizeFontSize[tableSize]),
6579
+ fontWeight: typography.fontWeight.semiBold,
6580
+ lineHeight: 1.4,
6581
+ padding: sizePadding[tableSize],
6582
+ borderBottom: `1px solid ${semanticColors.border.secondary}`,
6583
+ },
6584
+ [`& .${tableCellClasses.body}`]: {
6585
+ color: semanticColors.typography.body,
6586
+ fontFamily: typography.fontFamily.body,
6587
+ fontSize: theme.typography.pxToRem(sizeFontSize[tableSize]),
6588
+ fontWeight: typography.fontWeight.regular,
6589
+ lineHeight: 1.4,
6590
+ padding: sizePadding[tableSize],
6591
+ borderBottom: `1px solid ${semanticColors.border.secondary}`,
6592
+ },
6593
+ // Drop the trailing row's bottom border so the container border (if
6594
+ // any) is the visual edge.
6595
+ [`& tbody tr:last-of-type .${tableCellClasses.body}`]: {
6596
+ borderBottom: 'none',
6597
+ },
6598
+ }));
6599
+ const StyledContainer = styled('div', {
6600
+ shouldForwardProp: prop => prop !== 'tableVariant',
6601
+ })(({ tableVariant = 'bordered' }) => tableVariant === 'bordered'
6602
+ ? {
6603
+ border: `1px solid ${semanticColors.border.secondary}`,
6604
+ borderRadius: borderRadius.card,
6605
+ overflow: 'hidden',
6606
+ backgroundColor: semanticColors.surfaces.white,
6607
+ }
6608
+ : { backgroundColor: 'transparent' });
6609
+ /**
6610
+ * NeoTable — lightweight read-only table for static data (schema rows,
6611
+ * key/value summaries, response metadata). For interactive grids with
6612
+ * sorting / filtering / pagination, use NeoDataGrid instead.
6613
+ *
6614
+ * @example
6615
+ * <NeoTable
6616
+ * columns={[
6617
+ * { key: 'name', header: 'Property' },
6618
+ * { key: 'type', header: 'Type', align: 'center', width: '120px' },
6619
+ * { key: 'description', header: 'Description' },
6620
+ * ]}
6621
+ * rows={[
6622
+ * { name: 'id', type: 'string', description: 'Resource identifier' },
6623
+ * { name: 'count', type: 'number', description: 'Item count' },
6624
+ * ]}
6625
+ * size="small"
6626
+ * />
6627
+ */
6628
+ const NeoTable = ({ columns, rows, size = 'small', variant = 'bordered', ariaLabel, ...tableProps }) => (jsx(StyledContainer, { tableVariant: variant, children: jsx(TableContainer, { children: jsxs(StyledTable, { tableSize: size, "aria-label": ariaLabel, ...tableProps, children: [jsx(TableHead, { children: jsx(TableRow, { children: columns.map(col => (jsx(TableCell, { align: col.align ?? 'left', style: col.width ? { width: col.width } : undefined, children: col.header }, col.key))) }) }), jsx(TableBody, { children: rows.map((row, i) => (jsx(TableRow, { children: columns.map(col => (jsx(TableCell, { align: col.align ?? 'left', children: row[col.key] ?? '' }, col.key))) }, i))) })] }) }) }));
6629
+ NeoTable.displayName = 'NeoTable';
6630
+
6631
+ const StyledTabPanel = styled(Box, {
6632
+ shouldForwardProp: prop => prop !== 'tabPanelVariant',
6633
+ })(({ tabPanelVariant = 'default' }) => ({
6634
+ backgroundColor: semanticColors.surfaces.white,
6635
+ // default: 16px top padding for content-driven pages.
6636
+ // flush: zero padding so content sits directly against the tab bar's
6637
+ // bottom border (sidebars, panels, builders, canvases).
6638
+ padding: 0,
6639
+ ...(tabPanelVariant === 'flush' ? {} : { paddingTop: spacing.spacing_2 }),
6640
+ }));
6641
+ /**
6642
+ * NeoTabPanel — completes the NeoTabs + NeoTab + NeoTabPanel set.
6643
+ *
6644
+ * Lightweight ARIA-compliant tab panel that renders children when its
6645
+ * `value` matches `currentValue`. No MUI Lab / TabContext dependency.
6646
+ *
6647
+ * @example
6648
+ * const [tab, setTab] = useState('overview')
6649
+ * return (
6650
+ * <>
6651
+ * <NeoTabs value={tab} onChange={(_, v) => setTab(v)}>
6652
+ * <NeoTab value="overview" label="Overview" />
6653
+ * <NeoTab value="details" label="Details" />
6654
+ * </NeoTabs>
6655
+ * <NeoTabPanel value="overview" currentValue={tab}>...</NeoTabPanel>
6656
+ * <NeoTabPanel value="details" currentValue={tab} variant="flush">...</NeoTabPanel>
6657
+ * </>
6658
+ * )
6659
+ */
6660
+ const NeoTabPanel = ({ value, currentValue, variant = 'default', children, ...boxProps }) => {
6661
+ const selected = value === currentValue;
6662
+ return (jsx(StyledTabPanel, { role: "tabpanel", hidden: !selected, tabPanelVariant: variant, id: `tabpanel-${value}`, "aria-labelledby": `tab-${value}`, ...boxProps, children: selected ? children : null }));
6663
+ };
6664
+ NeoTabPanel.displayName = 'NeoTabPanel';
6665
+
6138
6666
  /**
6139
6667
  * NeoTabs - Tabs container component based on MUI Tabs
6140
6668
  *
@@ -6514,6 +7042,102 @@ const NeoToggle = ({ size = 'medium', label, helperText, disabled, ...props }) =
6514
7042
  };
6515
7043
  NeoToggle.displayName = 'NeoToggle';
6516
7044
 
7045
+ const sizeStyles = {
7046
+ small: {
7047
+ height: 24,
7048
+ fontSize: typography.fontSize.xs,
7049
+ },
7050
+ medium: {
7051
+ height: 32,
7052
+ fontSize: typography.fontSize.sm,
7053
+ },
7054
+ };
7055
+ const StyledToggleButton$1 = styled(MuiToggleButton, {
7056
+ shouldForwardProp: prop => prop !== 'toggleSize',
7057
+ })(({ theme, toggleSize = 'medium' }) => ({
7058
+ height: sizeStyles[toggleSize].height,
7059
+ padding: `0 ${spacing.spacing_1_1_2}px`,
7060
+ fontFamily: typography.fontFamily.body,
7061
+ fontSize: theme.typography.pxToRem(sizeStyles[toggleSize].fontSize),
7062
+ fontWeight: typography.fontWeight.regular,
7063
+ lineHeight: 1,
7064
+ color: semanticColors.typography.bodySecondary,
7065
+ backgroundColor: 'transparent',
7066
+ border: 'none',
7067
+ textTransform: 'none',
7068
+ transition: theme.transitions.create(['background-color', 'color'], {
7069
+ duration: theme.transitions.duration.short,
7070
+ }),
7071
+ '&:hover': {
7072
+ backgroundColor: colors.grey[100],
7073
+ color: semanticColors.typography.body,
7074
+ },
7075
+ '&.Mui-selected, &.Mui-selected:hover': {
7076
+ backgroundColor: colors.grey[100],
7077
+ color: semanticColors.typography.body,
7078
+ fontWeight: typography.fontWeight.semiBold,
7079
+ },
7080
+ '&.Mui-focusVisible': {
7081
+ outline: `2px solid ${semanticColors.border.focus}`,
7082
+ outlineOffset: -2,
7083
+ },
7084
+ '&.Mui-disabled': {
7085
+ color: semanticColors.typography.button.disabled,
7086
+ cursor: 'default',
7087
+ pointerEvents: 'none',
7088
+ },
7089
+ }));
7090
+ /**
7091
+ * NeoToggleButton — a single button in a segmented control. Use inside
7092
+ * NeoToggleButtonGroup; the group manages selection state and forwards
7093
+ * size to its children. Suitable for inline toolbar mode switches
7094
+ * ("Table" / "Raw"). For page-level tabs, prefer NeoButtonTab.
7095
+ */
7096
+ const NeoToggleButton = ({ children, size = 'medium', ...props }) => (jsx(StyledToggleButton$1, { toggleSize: size, ...props, children: children }));
7097
+ NeoToggleButton.displayName = 'NeoToggleButton';
7098
+
7099
+ const StyledToggleButtonGroup$1 = styled(MuiToggleButtonGroup)({
7100
+ borderRadius: borderRadius.button,
7101
+ border: `1px solid ${semanticColors.border.secondary}`,
7102
+ overflow: 'hidden',
7103
+ display: 'inline-flex',
7104
+ // Children fill the pill — first/last get the rounded corners, middles
7105
+ // are square. MUI applies positional classes via ToggleButtonGroup
7106
+ // context; we rely on borderRadius inheritance from the container.
7107
+ [`& .${toggleButtonClasses.root}`]: {
7108
+ borderRadius: 0,
7109
+ },
7110
+ });
7111
+ /**
7112
+ * NeoToggleButtonGroup — pill-shaped segmented control wrapping
7113
+ * MUI ToggleButtonGroup with Neo tokens. Use for inline toolbar mode
7114
+ * switches (e.g. "Table" / "Raw" in a panel header). For page-level
7115
+ * tab navigation, prefer NeoButtonTabGroup.
7116
+ *
7117
+ * @example
7118
+ * <NeoToggleButtonGroup value={mode} exclusive onChange={(_, v) => v && setMode(v)} size="small">
7119
+ * <NeoToggleButton value="table">Table</NeoToggleButton>
7120
+ * <NeoToggleButton value="raw">Raw</NeoToggleButton>
7121
+ * </NeoToggleButtonGroup>
7122
+ */
7123
+ const NeoToggleButtonGroup = ({ size = 'medium', children, ...props }) => {
7124
+ // Forward size to each NeoToggleButton child so consumers don't have to
7125
+ // set it on every button. MUI's group already does this via context for
7126
+ // its own size prop, but our `size` shape doesn't pass through unchanged.
7127
+ const sized = Children.map(children, child => isValidElement(child) && child.type === NeoToggleButton
7128
+ ? cloneElement(child, { size })
7129
+ : child);
7130
+ return jsx(StyledToggleButtonGroup$1, { ...props, children: sized });
7131
+ };
7132
+ NeoToggleButtonGroup.displayName = 'NeoToggleButtonGroup';
7133
+
7134
+ /**
7135
+ * NeoToggleButtonWithText
7136
+ *
7137
+ * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC?node-id=11565-10485
7138
+ */
7139
+ const NeoToggleButtonWithText = styled('div')({});
7140
+
6517
7141
  const StyledToolbar = styled(Toolbar)(({ theme }) => ({
6518
7142
  backgroundColor: semanticColors.surfaces.white,
6519
7143
  minHeight: 'auto',
@@ -6574,86 +7198,18 @@ const NeoToolbar = ({ children, ...props }) => {
6574
7198
  NeoToolbar.displayName = 'NeoToolbar';
6575
7199
 
6576
7200
  /**
6577
- * Variant color configuration
6578
- */
6579
- const variantConfig = {
6580
- light: {
6581
- backgroundColor: semanticColors.surfaces.tooltip, // #4b5563 - medium gray
6582
- color: semanticColors.typography.tooltip, // #ffffff - white
6583
- },
6584
- dark: {
6585
- backgroundColor: colors.grey[50], // #f9fafb - very light gray
6586
- color: colors.grey[800], // #1f2937 - dark gray
6587
- },
6588
- brand: {
6589
- backgroundColor: colors.digitalBlue[800], // #131e7a - dark blue
6590
- color: semanticColors.typography.tooltip, // #ffffff - white
6591
- },
6592
- };
6593
- /**
6594
- * Styled MUI Tooltip with Neo design system tokens
7201
+ * NeoTopNav
7202
+ *
7203
+ * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC?node-id=4618-185228
6595
7204
  */
6596
- const StyledTooltip = styled(Tooltip, {
6597
- shouldForwardProp: prop => prop !== 'variant' && prop !== 'description',
6598
- })(({ variant = 'light', description }) => {
6599
- const hasDescription = Boolean(description);
6600
- const variantStyles = variantConfig[variant];
6601
- return {
6602
- // Style the tooltip content
6603
- [`& .${tooltipClasses.tooltip}`]: {
6604
- backgroundColor: variantStyles.backgroundColor,
6605
- color: variantStyles.color,
6606
- fontSize: typography.fontSize.xs,
6607
- fontWeight: typography.fontWeight.medium,
6608
- lineHeight: hasDescription ? 1.5 : 1,
6609
- borderRadius: hasDescription ? borderRadius.s : borderRadius.xS,
6610
- padding: hasDescription ? spacing.spacing_1_1_2 : `0 ${spacing.spacing_1}px`,
6611
- ...(hasDescription && {
6612
- maxWidth: 296,
6613
- }),
6614
- ...(!hasDescription && {
6615
- height: spacing.spacing_3_1_4,
6616
- display: 'flex',
6617
- alignItems: 'center',
6618
- justifyContent: 'center',
6619
- }),
6620
- boxShadow: `${shadows.neutral.medium.x}px ${shadows.neutral.medium.y}px ${shadows.neutral.medium.blur}px ${shadows.neutral.medium.spread}px ${shadows.neutral.medium.shadow}`,
6621
- },
6622
- // Style the arrow
6623
- [`& .${tooltipClasses.arrow}`]: {
6624
- color: variantStyles.backgroundColor,
6625
- },
6626
- };
6627
- });
7205
+ const NeoTopNav = styled('div')({});
7206
+
6628
7207
  /**
6629
- * NeoTooltip - Tooltip component following Neo design system
7208
+ * NeoTourModal
6630
7209
  *
6631
- * Provides contextual information when users hover over or focus on an element.
6632
- * Supports three visual variants (light, dark, brand) and optional supporting text.
6633
- *
6634
- * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC/Neo---Moderne-Design-system---2025?node-id=4091-26557&t=Bo58EpFmg6ILJtmv-11
6635
- *
6636
- * Figma Props Mapping:
6637
- * - Theme (Light mode|Dark mode|Brand color) → variant ('light'|'dark'|'brand')
6638
- * - Placement → arrow (boolean) + placement (top/bottom/left/right/etc)
6639
- * - Supporting text (True|False) → description (string|undefined)
6640
- * - text → title (string, literal content)
6641
- *
6642
- * Design Tokens Used:
6643
- * - Light: surfaces.tooltip (#4b5563), typography.tooltip (#ffffff)
6644
- * - Dark: grey[50] (#f9fafb), grey[800] (#1f2937)
6645
- * - Brand: digitalBlue[800] (#131e7a), typography.tooltip (#ffffff)
6646
- * - Shadow: neutralMedium (0px 8px 15px 0px rgba(31,41,55,0.1))
6647
- * - Typography: fontSize.xs (12), fontWeight.medium (500), fontWeight.semiBold (600)
7210
+ * @figma https://www.figma.com/design/fQTkGSFbYyE7LiHuQJsENC?node-id=12408-1800
6648
7211
  */
6649
- const NeoTooltip = ({ variant = 'light', title, description, children, arrow = false, placement, ...props }) => {
6650
- // Build the title content
6651
- // If description is provided, create a structured layout with title + description
6652
- // Otherwise, just show the title text
6653
- const titleContent = description ? (jsxs(Stack, { gap: 0.25, children: [jsx(Typography, { fontWeight: typography.fontWeight.semiBold, children: title }), jsx(Typography, { fontWeight: typography.fontWeight.medium, children: description })] })) : (title);
6654
- return (jsx(StyledTooltip, { variant: variant, description: description, title: titleContent, arrow: arrow, placement: placement, ...props, children: children }));
6655
- };
6656
- NeoTooltip.displayName = 'NeoTooltip';
7212
+ const NeoTourModal = styled('div')({});
6657
7213
 
6658
7214
  /**
6659
7215
  * Custom label component that reads extra slot data from the item model.
@@ -6851,6 +7407,39 @@ const NeoTypologyControl = ({ children, ...props }) => {
6851
7407
  };
6852
7408
  NeoTypologyControl.displayName = 'NeoTypologyControl';
6853
7409
 
7410
+ // Box-breathing rhythm: inhale (grow) → hold → exhale (shadow expand+fade) → rest.
7411
+ const vibrate = keyframes `
7412
+ 0% { transform: scale(0.9); box-shadow: 0 0 0 0 transparent; }
7413
+ 25% { transform: scale(1); box-shadow: 0 0 0 0 currentColor; }
7414
+ 50% { transform: scale(1); box-shadow: 0 0 0 0 currentColor; }
7415
+ 75% { transform: scale(0.9); box-shadow: 0 0 0 ${spacing.spacing_3_4}px transparent; }
7416
+ 100% { transform: scale(0.9); box-shadow: 0 0 0 0 transparent; }
7417
+ `;
7418
+ /**
7419
+ * NeoVibratingDot - Animated status dot with a breathing pulse halo.
7420
+ *
7421
+ * Indicates a waiting/pending state (QUEUED / CREATED). Color is inherited from
7422
+ * `currentColor`; set it via the `color`/`sx` prop or a parent. Sized to the
7423
+ * lowercase-letter height regardless of parent fontSize.
7424
+ */
7425
+ const NeoVibratingDot = props => (jsx(Box$1, { "aria-hidden": "true", ...props, style: {
7426
+ width: spacing.spacing_1,
7427
+ height: spacing.spacing_1,
7428
+ ...props.style,
7429
+ }, sx: {
7430
+ display: 'inline-block',
7431
+ borderRadius: '50%',
7432
+ backgroundColor: 'currentColor',
7433
+ verticalAlign: 'middle',
7434
+ flexShrink: 0,
7435
+ animation: `${vibrate} 5.6s ease-in-out infinite`,
7436
+ '@media (prefers-reduced-motion: reduce)': {
7437
+ animation: 'none',
7438
+ },
7439
+ ...props.sx,
7440
+ } }));
7441
+ NeoVibratingDot.displayName = 'NeoVibratingDot';
7442
+
6854
7443
  /**
6855
7444
  * @moderneinc/neo-styled-components
6856
7445
  *
@@ -6859,5 +7448,5 @@ NeoTypologyControl.displayName = 'NeoTypologyControl';
6859
7448
 
6860
7449
  const version = '0.0.0-development';
6861
7450
 
6862
- export { ActivityScene, CIRCLE_RADIUS, NeoActionsCell, NeoActivityHeader, NeoActivityIndicatorCell, NeoAlert, NeoAvatarCell, NeoBadge, NeoBanner, NeoBreadcrumbLink, NeoBreadcrumbs, NeoButton, NeoButtonTab, NeoButtonTabGroup, NeoCard, NeoCheckbox, NeoCheckboxWithText, NeoCodeSnippet, NeoDataGrid, NeoDataGridCellContent, NeoDataGridColumnsButton, NeoDataGridColumnsPanel, NeoDataGridFilterPanel, NeoDataGridFilterPanelAddIcon, NeoDataGridFilterPanelDeleteIcon, NeoDataGridFilterPanelRemoveAllIcon, NeoDataGridFiltersButton, NeoDataGridHeaderLabel, NeoSelect as NeoDataGridSelect, NeoDatePicker, NeoDivider, NeoDot, NeoDownloadToast, NeoSelect as NeoDropdown, NeoMenu as NeoDropdownMenu, NeoMenuItem as NeoDropdownMenuItem, NeoMenuItem as NeoDropdownOption, NeoFilterChip, NeoFooter, NeoGeneralAvatar, NeoIconButton, NeoIconCell, NeoIconWrapper, NeoInfiniteScrollGrid, NeoInputField, NeoListItem, NeoListItemButton, NeoLoadingSpinner, NeoLogoCell, NeoMenu, NeoMenuItem, NeoModal, NeoModalContent, NeoModalFooter, NeoModalHeader, NeoMultiBadgesCell, NeoNavigationAvatar, NeoNavigationItem, NeoPageContent, NeoPaginatedGrid, NeoProgressCell, NeoProgressbar, NeoQuickFilter, NeoRadio, NeoSearchChip, NeoSelect, NeoMenuItem as NeoSelectOption, NeoSkeleton, NeoStatusBadgeCell, NeoStatusCell, NeoTab, NeoTabs, NeoTag, NeoToast, NeoToastButton, NeoToggle, NeoToolbar, NeoTooltip, NeoTreeItem, NeoTreeView, StyledToggleButton as NeoTypologyButton, NeoTypologyControl, NeoUserAvatarCell, SortedAscendingIcon, SortedDescendingIcon, UnsortedIcon, focusRingStyles, getDataGridHeaderStyles, getDataGridRowStyles, neoRowHeights, version };
7451
+ export { ActivityScene, CIRCLE_RADIUS, NeoActionsCell, NeoActivityHeader, NeoActivityIndicatorCell, NeoAlert, NeoAvatarCell, NeoBadge, NeoBanner, NeoBreadcrumbLink, NeoBreadcrumbs, NeoButton, NeoButtonTab, NeoButtonTabGroup, NeoCanceledIcon, NeoCard, NeoCheckbox, NeoCheckboxWithText, NeoCodeSnippet, NeoDataGrid, NeoDataGridCellContent, NeoDataGridColumnsButton, NeoDataGridColumnsPanel, NeoDataGridFilterPanel, NeoDataGridFilterPanelAddIcon, NeoDataGridFilterPanelDeleteIcon, NeoDataGridFilterPanelRemoveAllIcon, NeoDataGridFiltersButton, NeoDataGridHeaderLabel, NeoSelect as NeoDataGridSelect, NeoDatePicker, NeoDatePickerListItem, NeoDatePickerMenu, NeoDivider, NeoDot, NeoDownloadToast, NeoSelect as NeoDropdown, NeoMenu as NeoDropdownMenu, NeoMenuItem as NeoDropdownMenuItem, NeoMenuItem as NeoDropdownOption, NeoFilledCanceled, NeoFilledError, NeoFilledInfo, NeoFilledNeutral, NeoFilledQueued, NeoFilledSuccess, NeoFilledWarning, NeoFilterChip, NeoFooter, NeoGeneralAvatar, NeoIconButton, NeoIconCell, NeoIconWrapper, NeoInfiniteScrollGrid, NeoInputField, NeoListItem, NeoListItemButton, NeoLoadingSpinner, NeoLogoCell, NeoMenu, NeoMenuItem, NeoModal, NeoModalContent, NeoModalFooter, NeoModalHeader, NeoMultiBadgesCell, NeoNavigationAvatar, NeoNavigationItem, NeoPageContent, NeoPaginatedGrid, NeoProgressCell, NeoProgressbar, NeoQuickFilter, NeoRadio, NeoRadioButtonWithText, NeoRipplingDot, NeoSearchChip, NeoSelect, NeoSelectField, NeoMenuItem as NeoSelectOption, NeoSideNav, NeoSkeleton, NeoStatusBadgeCell, NeoStatusCell, NeoTab, NeoTabPanel, NeoTable, NeoTabs, NeoTag, NeoToast, NeoToastButton, NeoToggle, NeoToggleButton, NeoToggleButtonGroup, NeoToggleButtonWithText, NeoToolbar, NeoTooltip, NeoTopNav, NeoTourModal, NeoTreeItem, NeoTreeView, StyledToggleButton as NeoTypologyButton, NeoTypologyControl, NeoUserAvatarCell, NeoVibratingDot, SortedAscendingIcon, SortedDescendingIcon, UnsortedIcon, focusRingStyles, getDataGridHeaderStyles, getDataGridRowStyles, neoRowHeights, version };
6863
7452
  //# sourceMappingURL=index.esm.js.map