@teja-app/ui 0.0.12 → 0.0.13

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.
@@ -640,7 +640,7 @@ const VARIANT_STYLES = {
640
640
  border: "1px solid transparent"
641
641
  }
642
642
  };
643
- const SIZE_DIMS$1 = {
643
+ const SIZE_DIMS$2 = {
644
644
  sm: { h: 28, pad: "0 10px", fz: 12 },
645
645
  md: { h: 32, pad: "0 12px", fz: 13 },
646
646
  lg: { h: 38, pad: "0 16px", fz: 14 }
@@ -658,7 +658,7 @@ const Button$1 = forwardRef(function Button2({
658
658
  testId,
659
659
  ...rest
660
660
  }, ref) {
661
- const dims = SIZE_DIMS$1[size2];
661
+ const dims = SIZE_DIMS$2[size2];
662
662
  return /* @__PURE__ */ jsxs(
663
663
  "button",
664
664
  {
@@ -722,13 +722,15 @@ function Badge({
722
722
  tone = "neutral",
723
723
  size: size2 = "md",
724
724
  dot,
725
+ colors,
725
726
  children,
726
727
  style,
727
728
  testId,
728
729
  "data-testid": dataTestId,
729
730
  ...rest
730
731
  }) {
731
- const t2 = TONES$1[tone];
732
+ const base = TONES$1[tone] ?? TONES$1.neutral;
733
+ const t2 = colors ? { bg: colors.bg, fg: colors.fg, dot: colors.dot ?? colors.fg } : base;
732
734
  const h2 = size2 === "sm" ? 18 : 22;
733
735
  const fz = size2 === "sm" ? 10.5 : 11.5;
734
736
  const merged = {
@@ -765,16 +767,80 @@ function Badge({
765
767
  children
766
768
  ] });
767
769
  }
768
- function Card({ padding = 20, children, style, testId, ...rest }) {
769
- const merged = {
770
- background: "var(--surface-0)",
771
- borderRadius: "var(--r-lg)",
772
- border: "1px solid var(--border)",
770
+ const Card = forwardRef(function Card2({
771
+ padding = 20,
772
+ children,
773
+ style,
774
+ testId,
775
+ selected = false,
776
+ interactive,
777
+ onClick,
778
+ onKeyDown,
779
+ ...rest
780
+ }, ref) {
781
+ const isInteractive = interactive ?? !!onClick;
782
+ const surfaceStyle = {
783
+ background: selected ? "var(--primary-soft)" : "var(--surface-0)",
784
+ borderRadius: isInteractive ? "var(--r-md)" : "var(--r-lg)",
785
+ border: selected ? "1px solid var(--primary)" : "1px solid var(--border)",
786
+ boxShadow: selected ? "0 0 0 3px var(--primary-ring)" : isInteractive ? "var(--shadow-xs)" : void 0,
773
787
  padding,
788
+ cursor: isInteractive ? "pointer" : void 0,
789
+ transition: isInteractive ? "background .12s, box-shadow .12s" : void 0,
790
+ fontFamily: "inherit",
791
+ fontSize: "inherit",
792
+ textAlign: "inherit",
774
793
  ...style
775
794
  };
776
- return /* @__PURE__ */ jsx("div", { "data-testid": testId, style: merged, ...rest, children });
777
- }
795
+ if (isInteractive) {
796
+ const handleKeyDown = (e2) => {
797
+ if ((e2.key === "Enter" || e2.key === " ") && onClick) {
798
+ e2.preventDefault();
799
+ onClick(
800
+ e2
801
+ );
802
+ }
803
+ if (onKeyDown) {
804
+ onKeyDown(e2);
805
+ }
806
+ };
807
+ return /* @__PURE__ */ jsx(
808
+ "button",
809
+ {
810
+ ref,
811
+ type: "button",
812
+ "data-testid": testId,
813
+ "data-selected": selected ? "true" : void 0,
814
+ "data-interactive": "true",
815
+ onClick,
816
+ onKeyDown: handleKeyDown,
817
+ style: {
818
+ // Reset default button chrome
819
+ appearance: "none",
820
+ WebkitAppearance: "none",
821
+ display: "block",
822
+ width: "100%",
823
+ ...surfaceStyle,
824
+ // Re-apply border after reset (border: 'none' from reset would win)
825
+ border: surfaceStyle.border
826
+ },
827
+ ...rest,
828
+ children
829
+ }
830
+ );
831
+ }
832
+ return /* @__PURE__ */ jsx(
833
+ "div",
834
+ {
835
+ ref,
836
+ "data-testid": testId,
837
+ "data-selected": selected ? "true" : void 0,
838
+ style: surfaceStyle,
839
+ ...rest,
840
+ children
841
+ }
842
+ );
843
+ });
778
844
  function TejaMark({ size: size2 = 22, style, testId }) {
779
845
  return /* @__PURE__ */ jsxs(
780
846
  "svg",
@@ -13293,6 +13359,65 @@ function RoleTile({
13293
13359
  }
13294
13360
  );
13295
13361
  }
13362
+ const SelectableCard = forwardRef(
13363
+ function SelectableCard2({
13364
+ selected,
13365
+ role = "radio",
13366
+ onSelect,
13367
+ disabled = false,
13368
+ testId,
13369
+ children,
13370
+ style,
13371
+ onClick,
13372
+ ...rest
13373
+ }, ref) {
13374
+ const cardStyle = {
13375
+ // Layout
13376
+ display: "block",
13377
+ width: "100%",
13378
+ textAlign: "left",
13379
+ // Spacing — matches RoleTile (padding: 12)
13380
+ padding: 12,
13381
+ // Border — 1.5px primary when selected, border-strong when not
13382
+ border: `1.5px solid ${selected ? "var(--primary)" : "var(--border-strong)"}`,
13383
+ // Background — primary-soft when selected, surface-0 when not
13384
+ background: selected ? "var(--primary-soft)" : "var(--surface-0)",
13385
+ // Shape — matches RoleTile
13386
+ borderRadius: "var(--r-md)",
13387
+ // Shadow — shadow-xs when selected, none when not (matches RoleTile)
13388
+ boxShadow: selected ? "var(--shadow-xs)" : "none",
13389
+ // Typography reset
13390
+ font: "inherit",
13391
+ // Cursor
13392
+ cursor: disabled ? "not-allowed" : "pointer",
13393
+ // Disabled dimming
13394
+ opacity: disabled ? 0.5 : 1,
13395
+ // Merge caller overrides last
13396
+ ...style
13397
+ };
13398
+ function handleClick(e2) {
13399
+ if (!disabled) {
13400
+ onSelect?.();
13401
+ onClick?.(e2);
13402
+ }
13403
+ }
13404
+ return /* @__PURE__ */ jsx(
13405
+ "button",
13406
+ {
13407
+ ref,
13408
+ type: "button",
13409
+ role,
13410
+ "aria-checked": selected,
13411
+ "data-testid": testId,
13412
+ disabled,
13413
+ onClick: handleClick,
13414
+ style: cardStyle,
13415
+ ...rest,
13416
+ children
13417
+ }
13418
+ );
13419
+ }
13420
+ );
13296
13421
  const CELL_COUNT = 6;
13297
13422
  const EMPTY_CELLS = Array.from(
13298
13423
  { length: CELL_COUNT },
@@ -14179,6 +14304,7 @@ function SegmentedControl({
14179
14304
  role: "tab",
14180
14305
  "aria-selected": active,
14181
14306
  "data-state": active ? "active" : "inactive",
14307
+ "data-active": active ? "true" : "false",
14182
14308
  "data-testid": testId ? `${testId}-${it.value}` : void 0,
14183
14309
  onClick: () => onChange?.(it.value),
14184
14310
  style: {
@@ -15408,7 +15534,7 @@ function Drawer$1({
15408
15534
  testId,
15409
15535
  ariaLabel,
15410
15536
  style,
15411
- panelStyle
15537
+ panelStyle: panelStyle2
15412
15538
  }) {
15413
15539
  const panelRef = useRef(null);
15414
15540
  const previouslyFocusedRef = useRef(null);
@@ -15510,7 +15636,7 @@ function Drawer$1({
15510
15636
  display: "flex",
15511
15637
  flexDirection: "column",
15512
15638
  outline: "none",
15513
- ...panelStyle
15639
+ ...panelStyle2
15514
15640
  },
15515
15641
  children: [
15516
15642
  header,
@@ -15645,7 +15771,7 @@ function Modal$1({
15645
15771
  testId,
15646
15772
  ariaLabel,
15647
15773
  style,
15648
- panelStyle
15774
+ panelStyle: panelStyle2
15649
15775
  }) {
15650
15776
  const panelRef = useRef(null);
15651
15777
  const previouslyFocusedRef = useRef(null);
@@ -15755,7 +15881,7 @@ function Modal$1({
15755
15881
  boxShadow: "0 24px 64px rgba(0,0,0,0.22), 0 4px 16px rgba(0,0,0,0.12)",
15756
15882
  overflow: "hidden",
15757
15883
  outline: "none",
15758
- ...panelStyle
15884
+ ...panelStyle2
15759
15885
  },
15760
15886
  children: [
15761
15887
  header ?? (title || description ? /* @__PURE__ */ jsx(
@@ -16694,6 +16820,79 @@ const Chip = forwardRef(function Chip2({ active, count: count2, tone = "primary"
16694
16820
  }
16695
16821
  );
16696
16822
  });
16823
+ const SIZE_DIMS$1 = {
16824
+ sm: { height: 24, padding: "0 10px", fontSize: 11, gap: 4 },
16825
+ md: { height: 28, padding: "0 12px", fontSize: 12, gap: 6 }
16826
+ };
16827
+ const ToggleChip = forwardRef(
16828
+ function ToggleChip2({
16829
+ pressed,
16830
+ onPressedChange,
16831
+ icon,
16832
+ tone = "primary",
16833
+ size: size2 = "md",
16834
+ disabled = false,
16835
+ style,
16836
+ testId,
16837
+ onClick,
16838
+ children,
16839
+ ...rest
16840
+ }, ref) {
16841
+ const dims = SIZE_DIMS$1[size2];
16842
+ const pillStyle = {
16843
+ // Geometry — from PillSelector item template
16844
+ display: "inline-flex",
16845
+ alignItems: "center",
16846
+ justifyContent: "center",
16847
+ gap: dims.gap,
16848
+ height: dims.height,
16849
+ padding: dims.padding,
16850
+ fontSize: dims.fontSize,
16851
+ fontWeight: 500,
16852
+ borderRadius: "var(--r-pill)",
16853
+ // Colours — tokens only, never hardcoded
16854
+ border: "1px solid",
16855
+ borderColor: pressed ? `var(--${tone})` : "var(--border)",
16856
+ background: pressed ? `var(--${tone}-soft)` : "var(--surface-0)",
16857
+ color: pressed ? `var(--${tone})` : "var(--ink-2)",
16858
+ // Interaction
16859
+ cursor: disabled ? "not-allowed" : "pointer",
16860
+ opacity: disabled ? 0.5 : 1,
16861
+ whiteSpace: "nowrap",
16862
+ flexShrink: 0,
16863
+ transition: "background .12s, border-color .12s, color .12s",
16864
+ // Reset button defaults
16865
+ outline: "none",
16866
+ ...style
16867
+ };
16868
+ const handleClick = (e2) => {
16869
+ if (disabled) return;
16870
+ onPressedChange?.(!pressed);
16871
+ onClick?.(e2);
16872
+ };
16873
+ return /* @__PURE__ */ jsxs(
16874
+ "button",
16875
+ {
16876
+ ref,
16877
+ type: "button",
16878
+ disabled,
16879
+ "aria-pressed": pressed,
16880
+ "data-state": pressed ? "on" : "off",
16881
+ "data-active": pressed ? "true" : "false",
16882
+ "data-tone": tone,
16883
+ "data-testid": testId,
16884
+ style: pillStyle,
16885
+ onClick: handleClick,
16886
+ ...rest,
16887
+ children: [
16888
+ icon != null ? icon : null,
16889
+ children != null ? /* @__PURE__ */ jsx("span", { children }) : null
16890
+ ]
16891
+ }
16892
+ );
16893
+ }
16894
+ );
16895
+ ToggleChip.displayName = "ToggleChip";
16697
16896
  const SIZE_DIMS = {
16698
16897
  sm: { height: 24, padding: "0 10px", fontSize: 11, gap: 4, iconSize: 12 },
16699
16898
  md: { height: 28, padding: "0 12px", fontSize: 12, gap: 6, iconSize: 14 },
@@ -18103,6 +18302,747 @@ function ConfirmDialog({
18103
18302
  }
18104
18303
  );
18105
18304
  }
18305
+ function panelStyle(placement, minWidth, zIndex) {
18306
+ const isTop = placement.startsWith("top");
18307
+ const isStart = placement.endsWith("start");
18308
+ return {
18309
+ position: "absolute",
18310
+ // vertical
18311
+ ...isTop ? { bottom: "100%", marginBottom: 4 } : { top: "100%", marginTop: 4 },
18312
+ // horizontal
18313
+ ...isStart ? { left: 0 } : { right: 0 },
18314
+ zIndex,
18315
+ minWidth,
18316
+ background: "var(--surface-0)",
18317
+ border: "1px solid var(--border)",
18318
+ borderRadius: "var(--r-md)",
18319
+ boxShadow: "var(--shadow-pop)",
18320
+ padding: 4,
18321
+ overflow: "hidden"
18322
+ };
18323
+ }
18324
+ function Menu({
18325
+ open,
18326
+ onClose,
18327
+ trigger,
18328
+ children,
18329
+ placement = "bottom-end",
18330
+ minWidth = 220,
18331
+ zIndex = 200,
18332
+ testId,
18333
+ style
18334
+ }) {
18335
+ const panelRef = useRef(null);
18336
+ useEffect(() => {
18337
+ if (!open) return;
18338
+ const onKey = (e2) => {
18339
+ if (e2.key === "Escape") {
18340
+ onClose();
18341
+ return;
18342
+ }
18343
+ if (e2.key === "ArrowDown" || e2.key === "ArrowUp") {
18344
+ e2.preventDefault();
18345
+ const panel = panelRef.current;
18346
+ if (!panel) return;
18347
+ const items = Array.from(
18348
+ panel.querySelectorAll('button[role="menuitem"]:not(:disabled)')
18349
+ );
18350
+ if (items.length === 0) return;
18351
+ const focused = items.indexOf(document.activeElement);
18352
+ const next = e2.key === "ArrowDown" ? (focused + 1) % items.length : (focused - 1 + items.length) % items.length;
18353
+ items[next]?.focus();
18354
+ }
18355
+ };
18356
+ window.addEventListener("keydown", onKey);
18357
+ return () => window.removeEventListener("keydown", onKey);
18358
+ }, [open, onClose]);
18359
+ useEffect(() => {
18360
+ if (!open) return;
18361
+ const panel = panelRef.current;
18362
+ if (!panel) return;
18363
+ const first = panel.querySelector('button[role="menuitem"]:not(:disabled)');
18364
+ if (first && !panel.contains(document.activeElement)) {
18365
+ first.focus();
18366
+ }
18367
+ }, [open]);
18368
+ const ps = panelStyle(placement, minWidth, zIndex);
18369
+ return /* @__PURE__ */ jsxs("div", { style: { position: "relative", display: "inline-flex" }, children: [
18370
+ trigger,
18371
+ open && /* @__PURE__ */ jsxs(Fragment, { children: [
18372
+ /* @__PURE__ */ jsx(
18373
+ "div",
18374
+ {
18375
+ "aria-hidden": "true",
18376
+ onClick: onClose,
18377
+ style: { position: "fixed", inset: 0, zIndex: zIndex - 1 }
18378
+ }
18379
+ ),
18380
+ /* @__PURE__ */ jsx(
18381
+ "div",
18382
+ {
18383
+ ref: panelRef,
18384
+ role: "menu",
18385
+ "aria-label": "menu",
18386
+ "data-testid": testId,
18387
+ onClick: onClose,
18388
+ style: { ...ps, ...style },
18389
+ children
18390
+ }
18391
+ )
18392
+ ] })
18393
+ ] });
18394
+ }
18395
+ const MenuItem = forwardRef(function MenuItem2({ icon, danger = false, children, onClick, disabled, testId, style, ...rest }, ref) {
18396
+ const [hovered, setHovered] = useState(false);
18397
+ const handleClick = useCallback(
18398
+ (e2) => {
18399
+ onClick?.(e2);
18400
+ },
18401
+ [onClick]
18402
+ );
18403
+ const merged = {
18404
+ display: "flex",
18405
+ alignItems: "center",
18406
+ gap: 8,
18407
+ width: "100%",
18408
+ padding: "8px 10px",
18409
+ border: 0,
18410
+ borderRadius: "var(--r-sm)",
18411
+ background: hovered && !disabled ? "var(--surface-1)" : "transparent",
18412
+ cursor: disabled ? "not-allowed" : "pointer",
18413
+ fontFamily: "inherit",
18414
+ fontSize: 12.5,
18415
+ color: disabled ? "var(--ink-4)" : danger ? "var(--danger)" : "var(--ink-1)",
18416
+ textAlign: "left",
18417
+ opacity: disabled ? 0.55 : 1,
18418
+ transition: "background .1s",
18419
+ outline: "none",
18420
+ ...style
18421
+ };
18422
+ return /* @__PURE__ */ jsxs(
18423
+ "button",
18424
+ {
18425
+ ref,
18426
+ role: "menuitem",
18427
+ type: "button",
18428
+ disabled,
18429
+ "data-testid": testId,
18430
+ "data-danger": danger ? "true" : void 0,
18431
+ style: merged,
18432
+ onMouseEnter: () => setHovered(true),
18433
+ onMouseLeave: () => setHovered(false),
18434
+ onClick: handleClick,
18435
+ ...rest,
18436
+ children: [
18437
+ icon ? /* @__PURE__ */ jsx(
18438
+ Icon,
18439
+ {
18440
+ name: icon,
18441
+ size: 12,
18442
+ color: disabled ? "var(--ink-4)" : danger ? "var(--danger)" : "var(--ink-3)"
18443
+ }
18444
+ ) : null,
18445
+ children
18446
+ ]
18447
+ }
18448
+ );
18449
+ });
18450
+ function MenuDivider({ style, ...rest }) {
18451
+ return /* @__PURE__ */ jsx(
18452
+ "hr",
18453
+ {
18454
+ role: "separator",
18455
+ style: {
18456
+ border: 0,
18457
+ borderTop: "1px solid var(--divider)",
18458
+ margin: "4px 2px",
18459
+ ...style
18460
+ },
18461
+ ...rest
18462
+ }
18463
+ );
18464
+ }
18465
+ const GAP = 8;
18466
+ const ARROW_SIZE = 5;
18467
+ function getBubbleStyle(placement) {
18468
+ const base = {
18469
+ position: "absolute",
18470
+ zIndex: "var(--z-tooltip)"
18471
+ };
18472
+ switch (placement) {
18473
+ case "top":
18474
+ return {
18475
+ ...base,
18476
+ bottom: `calc(100% + ${GAP}px)`,
18477
+ left: "50%",
18478
+ transform: "translateX(-50%)"
18479
+ };
18480
+ case "bottom":
18481
+ return {
18482
+ ...base,
18483
+ top: `calc(100% + ${GAP}px)`,
18484
+ left: "50%",
18485
+ transform: "translateX(-50%)"
18486
+ };
18487
+ case "left":
18488
+ return {
18489
+ ...base,
18490
+ right: `calc(100% + ${GAP}px)`,
18491
+ top: "50%",
18492
+ transform: "translateY(-50%)"
18493
+ };
18494
+ case "right":
18495
+ return {
18496
+ ...base,
18497
+ left: `calc(100% + ${GAP}px)`,
18498
+ top: "50%",
18499
+ transform: "translateY(-50%)"
18500
+ };
18501
+ }
18502
+ }
18503
+ function getArrowStyle(placement) {
18504
+ const base = {
18505
+ position: "absolute",
18506
+ width: ARROW_SIZE * 2,
18507
+ height: ARROW_SIZE * 2,
18508
+ background: "var(--ink-1)",
18509
+ transform: "rotate(45deg)"
18510
+ };
18511
+ switch (placement) {
18512
+ case "top":
18513
+ return {
18514
+ ...base,
18515
+ bottom: -4,
18516
+ left: "50%",
18517
+ marginLeft: -ARROW_SIZE
18518
+ };
18519
+ case "bottom":
18520
+ return {
18521
+ ...base,
18522
+ top: -4,
18523
+ left: "50%",
18524
+ marginLeft: -ARROW_SIZE
18525
+ };
18526
+ case "left":
18527
+ return {
18528
+ ...base,
18529
+ right: -4,
18530
+ top: "50%",
18531
+ marginTop: -ARROW_SIZE
18532
+ };
18533
+ case "right":
18534
+ return {
18535
+ ...base,
18536
+ left: -4,
18537
+ top: "50%",
18538
+ marginTop: -ARROW_SIZE
18539
+ };
18540
+ }
18541
+ }
18542
+ const Tooltip = forwardRef(function Tooltip2({
18543
+ label,
18544
+ placement = "top",
18545
+ delay = 400,
18546
+ children,
18547
+ testId,
18548
+ maxWidth = 220,
18549
+ style,
18550
+ ...rest
18551
+ }, ref) {
18552
+ const [visible, setVisible] = useState(false);
18553
+ const timerRef = useRef(null);
18554
+ const tooltipId = useId$1();
18555
+ const show = useCallback(() => {
18556
+ timerRef.current = setTimeout(() => setVisible(true), delay);
18557
+ }, [delay]);
18558
+ const hide = useCallback(() => {
18559
+ if (timerRef.current !== null) {
18560
+ clearTimeout(timerRef.current);
18561
+ timerRef.current = null;
18562
+ }
18563
+ setVisible(false);
18564
+ }, []);
18565
+ useEffect(() => {
18566
+ return () => {
18567
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
18568
+ };
18569
+ }, []);
18570
+ useEffect(() => {
18571
+ if (!visible) return;
18572
+ const onKey = (e2) => {
18573
+ if (e2.key === "Escape") hide();
18574
+ };
18575
+ document.addEventListener("keydown", onKey);
18576
+ return () => document.removeEventListener("keydown", onKey);
18577
+ }, [visible, hide]);
18578
+ const wrapperStyle = {
18579
+ position: "relative",
18580
+ display: "inline-flex",
18581
+ alignItems: "center",
18582
+ justifyContent: "center",
18583
+ ...style
18584
+ };
18585
+ const bubbleStyle = {
18586
+ ...getBubbleStyle(placement),
18587
+ background: "var(--ink-1)",
18588
+ color: "var(--surface-0)",
18589
+ fontSize: 12,
18590
+ fontWeight: 500,
18591
+ lineHeight: 1.4,
18592
+ padding: "6px 8px",
18593
+ borderRadius: "var(--r-sm)",
18594
+ boxShadow: "var(--shadow-pop)",
18595
+ maxWidth,
18596
+ whiteSpace: "nowrap",
18597
+ pointerEvents: "none",
18598
+ // Fade in
18599
+ opacity: visible ? 1 : 0,
18600
+ transition: "opacity 0.12s ease"
18601
+ };
18602
+ return /* @__PURE__ */ jsxs(
18603
+ "div",
18604
+ {
18605
+ ref,
18606
+ "data-testid": testId,
18607
+ "data-placement": placement,
18608
+ style: wrapperStyle,
18609
+ onMouseEnter: show,
18610
+ onMouseLeave: hide,
18611
+ onFocusCapture: show,
18612
+ onBlurCapture: hide,
18613
+ ...rest,
18614
+ children: [
18615
+ /* @__PURE__ */ jsx(
18616
+ "span",
18617
+ {
18618
+ "aria-describedby": visible ? tooltipId : void 0,
18619
+ style: { display: "contents" },
18620
+ children
18621
+ }
18622
+ ),
18623
+ /* @__PURE__ */ jsxs(
18624
+ "div",
18625
+ {
18626
+ id: tooltipId,
18627
+ role: "tooltip",
18628
+ "aria-hidden": !visible,
18629
+ style: bubbleStyle,
18630
+ children: [
18631
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, style: getArrowStyle(placement) }),
18632
+ label
18633
+ ]
18634
+ }
18635
+ )
18636
+ ]
18637
+ }
18638
+ );
18639
+ });
18640
+ const DarkScope = forwardRef(
18641
+ function DarkScope2({ children, style, testId, "data-testid": dataTestId, ...rest }, ref) {
18642
+ const merged = {
18643
+ colorScheme: "dark",
18644
+ ...style
18645
+ };
18646
+ return /* @__PURE__ */ jsx(
18647
+ "div",
18648
+ {
18649
+ ref,
18650
+ "data-theme": "dark",
18651
+ "data-testid": dataTestId ?? testId,
18652
+ style: merged,
18653
+ ...rest,
18654
+ children
18655
+ }
18656
+ );
18657
+ }
18658
+ );
18659
+ const TONE_SPECS = {
18660
+ success: {
18661
+ accent: "var(--success)",
18662
+ iconBg: "var(--success-soft)",
18663
+ iconColor: "var(--success)",
18664
+ defaultIcon: "check-circle"
18665
+ },
18666
+ danger: {
18667
+ accent: "var(--danger)",
18668
+ iconBg: "var(--danger-soft)",
18669
+ iconColor: "var(--danger)",
18670
+ defaultIcon: "alert-circle"
18671
+ },
18672
+ info: {
18673
+ accent: "var(--primary)",
18674
+ iconBg: "var(--primary-soft)",
18675
+ iconColor: "var(--primary)",
18676
+ defaultIcon: "info"
18677
+ },
18678
+ neutral: {
18679
+ accent: "var(--border)",
18680
+ iconBg: "var(--surface-2)",
18681
+ iconColor: "var(--ink-2)",
18682
+ defaultIcon: "bell"
18683
+ }
18684
+ };
18685
+ const ToastContext = createContext(null);
18686
+ let _idCounter = 0;
18687
+ const nextId = () => `toast-${++_idCounter}`;
18688
+ function useToast() {
18689
+ const ctx = useContext(ToastContext);
18690
+ if (!ctx) {
18691
+ throw new Error("useToast must be used within a <ToastHost />");
18692
+ }
18693
+ return ctx;
18694
+ }
18695
+ const Toast = forwardRef(function Toast2({
18696
+ message: message2,
18697
+ tone = "success",
18698
+ icon,
18699
+ action,
18700
+ onDismiss,
18701
+ style,
18702
+ testId,
18703
+ ...rest
18704
+ }, ref) {
18705
+ const t2 = TONE_SPECS[tone];
18706
+ const iconName = icon ?? t2.defaultIcon;
18707
+ const merged = {
18708
+ display: "flex",
18709
+ alignItems: "flex-start",
18710
+ gap: 10,
18711
+ padding: "11px 14px",
18712
+ background: "var(--surface-0)",
18713
+ border: "1px solid var(--border)",
18714
+ borderLeft: `3px solid ${t2.accent}`,
18715
+ borderRadius: "var(--r-md)",
18716
+ boxShadow: "var(--shadow-pop)",
18717
+ maxWidth: 320,
18718
+ width: 320,
18719
+ pointerEvents: "auto",
18720
+ ...style
18721
+ };
18722
+ return /* @__PURE__ */ jsxs("div", { ref, "data-testid": testId, "data-tone": tone, style: merged, ...rest, children: [
18723
+ /* @__PURE__ */ jsx(
18724
+ "span",
18725
+ {
18726
+ "aria-hidden": true,
18727
+ style: {
18728
+ width: 26,
18729
+ height: 26,
18730
+ borderRadius: 999,
18731
+ flexShrink: 0,
18732
+ background: t2.iconBg,
18733
+ display: "inline-flex",
18734
+ alignItems: "center",
18735
+ justifyContent: "center"
18736
+ },
18737
+ children: /* @__PURE__ */ jsx(Icon, { name: iconName, size: 12, color: t2.iconColor })
18738
+ }
18739
+ ),
18740
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0, alignSelf: "center" }, children: [
18741
+ /* @__PURE__ */ jsx(
18742
+ "div",
18743
+ {
18744
+ style: {
18745
+ fontSize: 12.5,
18746
+ fontWeight: 600,
18747
+ color: "var(--ink-1)",
18748
+ lineHeight: 1.4
18749
+ },
18750
+ children: message2
18751
+ }
18752
+ ),
18753
+ action ? /* @__PURE__ */ jsx(
18754
+ "button",
18755
+ {
18756
+ type: "button",
18757
+ onClick: () => {
18758
+ action.onClick();
18759
+ onDismiss?.();
18760
+ },
18761
+ style: {
18762
+ marginTop: 4,
18763
+ fontSize: 11.5,
18764
+ fontWeight: 500,
18765
+ color: "var(--primary)",
18766
+ background: "none",
18767
+ border: 0,
18768
+ padding: 0,
18769
+ cursor: "pointer",
18770
+ lineHeight: 1
18771
+ },
18772
+ children: action.label
18773
+ }
18774
+ ) : null
18775
+ ] }),
18776
+ /* @__PURE__ */ jsx(
18777
+ "button",
18778
+ {
18779
+ type: "button",
18780
+ "aria-label": "Dismiss",
18781
+ onClick: onDismiss,
18782
+ style: {
18783
+ background: "none",
18784
+ border: 0,
18785
+ padding: 2,
18786
+ cursor: "pointer",
18787
+ color: "var(--ink-3)",
18788
+ display: "inline-flex",
18789
+ alignItems: "center",
18790
+ flexShrink: 0,
18791
+ borderRadius: "var(--r-sm)"
18792
+ },
18793
+ children: /* @__PURE__ */ jsx(Icon, { name: "x", size: 12 })
18794
+ }
18795
+ )
18796
+ ] });
18797
+ });
18798
+ function ToastEntry({ item, onRemove }) {
18799
+ const [visible, setVisible] = useState(false);
18800
+ const timerRef = useRef(null);
18801
+ useEffect(() => {
18802
+ const raf = requestAnimationFrame(() => setVisible(true));
18803
+ return () => cancelAnimationFrame(raf);
18804
+ }, []);
18805
+ useEffect(() => {
18806
+ timerRef.current = setTimeout(() => {
18807
+ setVisible(false);
18808
+ setTimeout(() => {
18809
+ onRemove(item.id);
18810
+ item.then?.();
18811
+ }, 220);
18812
+ }, item.ms);
18813
+ return () => {
18814
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
18815
+ };
18816
+ }, [item, onRemove]);
18817
+ const handleDismiss = useCallback(() => {
18818
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
18819
+ setVisible(false);
18820
+ setTimeout(() => {
18821
+ onRemove(item.id);
18822
+ item.then?.();
18823
+ }, 220);
18824
+ }, [item, onRemove]);
18825
+ return /* @__PURE__ */ jsx(
18826
+ "div",
18827
+ {
18828
+ style: {
18829
+ transition: "opacity 0.2s ease, transform 0.2s ease",
18830
+ opacity: visible ? 1 : 0,
18831
+ transform: visible ? "translateX(0)" : "translateX(24px)"
18832
+ },
18833
+ children: /* @__PURE__ */ jsx(
18834
+ Toast,
18835
+ {
18836
+ message: item.message,
18837
+ tone: item.tone,
18838
+ icon: item.icon,
18839
+ action: item.action,
18840
+ onDismiss: handleDismiss,
18841
+ testId: `toast-${item.id}`
18842
+ }
18843
+ )
18844
+ }
18845
+ );
18846
+ }
18847
+ function ToastHost({ children, container }) {
18848
+ const [items, setItems] = useState([]);
18849
+ const showToast = useCallback((message2, opts = {}) => {
18850
+ const tone = opts.tone ?? "success";
18851
+ const t2 = TONE_SPECS[tone];
18852
+ const item = {
18853
+ id: nextId(),
18854
+ message: message2,
18855
+ tone,
18856
+ icon: opts.icon ?? t2.defaultIcon,
18857
+ ms: opts.ms ?? 2500,
18858
+ action: opts.action,
18859
+ then: opts.then
18860
+ };
18861
+ setItems((prev) => [...prev, item]);
18862
+ }, []);
18863
+ const removeItem = useCallback((id) => {
18864
+ setItems((prev) => prev.filter((i2) => i2.id !== id));
18865
+ }, []);
18866
+ const hostStyle = {
18867
+ position: "fixed",
18868
+ top: 80,
18869
+ right: 20,
18870
+ zIndex: 200,
18871
+ display: "flex",
18872
+ flexDirection: "column",
18873
+ gap: 8,
18874
+ pointerEvents: "none"
18875
+ // Ensure toasts stack above most content
18876
+ };
18877
+ const portal = createPortal(
18878
+ /* @__PURE__ */ jsx(
18879
+ "div",
18880
+ {
18881
+ role: "region",
18882
+ "aria-live": "polite",
18883
+ "aria-label": "Notifications",
18884
+ style: hostStyle,
18885
+ children: items.map((item) => /* @__PURE__ */ jsx(ToastEntry, { item, onRemove: removeItem }, item.id))
18886
+ }
18887
+ ),
18888
+ container ?? document.body
18889
+ );
18890
+ return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: { showToast }, children: [
18891
+ children,
18892
+ portal
18893
+ ] });
18894
+ }
18895
+ const AccordionContext = createContext(null);
18896
+ function useAccordionCtx() {
18897
+ const ctx = useContext(AccordionContext);
18898
+ if (!ctx) {
18899
+ throw new Error("AccordionItem must be rendered inside an Accordion.");
18900
+ }
18901
+ return ctx;
18902
+ }
18903
+ function Accordion({
18904
+ multiple = false,
18905
+ defaultValue,
18906
+ value: controlledValue,
18907
+ onChange,
18908
+ children,
18909
+ style,
18910
+ testId
18911
+ }) {
18912
+ const [internalOpen, setInternalOpen] = useState(() => {
18913
+ if (defaultValue === void 0) return /* @__PURE__ */ new Set();
18914
+ return new Set(Array.isArray(defaultValue) ? defaultValue : [defaultValue]);
18915
+ });
18916
+ const isControlled = controlledValue !== void 0;
18917
+ const openSet = useMemo(
18918
+ () => isControlled ? new Set(Array.isArray(controlledValue) ? controlledValue : [controlledValue]) : internalOpen,
18919
+ [isControlled, controlledValue, internalOpen]
18920
+ );
18921
+ const isOpen = useCallback((v2) => openSet.has(v2), [openSet]);
18922
+ const toggle = useCallback(
18923
+ (v2) => {
18924
+ let next;
18925
+ if (openSet.has(v2)) {
18926
+ next = new Set([...openSet].filter((x2) => x2 !== v2));
18927
+ } else if (multiple) {
18928
+ next = /* @__PURE__ */ new Set([...openSet, v2]);
18929
+ } else {
18930
+ next = /* @__PURE__ */ new Set([v2]);
18931
+ }
18932
+ if (!isControlled) {
18933
+ setInternalOpen(next);
18934
+ }
18935
+ if (onChange) {
18936
+ const arr = [...next];
18937
+ onChange(multiple ? arr : arr[0] ?? "");
18938
+ }
18939
+ },
18940
+ [openSet, multiple, isControlled, onChange]
18941
+ );
18942
+ const ctx = { isOpen, toggle };
18943
+ return /* @__PURE__ */ jsx(AccordionContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx(
18944
+ "div",
18945
+ {
18946
+ "data-testid": testId,
18947
+ style: {
18948
+ display: "flex",
18949
+ flexDirection: "column",
18950
+ gap: 0,
18951
+ ...style
18952
+ },
18953
+ children
18954
+ }
18955
+ ) });
18956
+ }
18957
+ const AccordionItem = forwardRef(
18958
+ function AccordionItem2({ value, title, children, testId, style, ...rest }, ref) {
18959
+ const { isOpen, toggle } = useAccordionCtx();
18960
+ const open = isOpen(value);
18961
+ const uid = useId$1();
18962
+ const headerId = `accordion-header-${uid}`;
18963
+ const panelId = `accordion-panel-${uid}`;
18964
+ const [hovered, setHovered] = useState(false);
18965
+ const headerStyle = {
18966
+ display: "flex",
18967
+ alignItems: "center",
18968
+ justifyContent: "space-between",
18969
+ width: "100%",
18970
+ padding: "10px 12px",
18971
+ border: 0,
18972
+ borderRadius: "var(--r-md)",
18973
+ background: hovered ? "var(--surface-1)" : "transparent",
18974
+ cursor: "pointer",
18975
+ fontFamily: "inherit",
18976
+ textAlign: "left",
18977
+ transition: "background .1s",
18978
+ outline: "none"
18979
+ };
18980
+ const titleStyle = {
18981
+ fontSize: 13,
18982
+ fontWeight: 600,
18983
+ color: "var(--ink-1)",
18984
+ flex: 1,
18985
+ minWidth: 0
18986
+ };
18987
+ const chevronStyle = {
18988
+ flexShrink: 0,
18989
+ display: "inline-flex",
18990
+ alignItems: "center",
18991
+ justifyContent: "center",
18992
+ transform: open ? "rotate(180deg)" : "rotate(0deg)",
18993
+ transition: "transform .15s"
18994
+ };
18995
+ const panelStyle2 = {
18996
+ paddingTop: 8
18997
+ };
18998
+ return /* @__PURE__ */ jsxs("div", { style: { ...style }, children: [
18999
+ /* @__PURE__ */ jsxs(
19000
+ "button",
19001
+ {
19002
+ ref,
19003
+ id: headerId,
19004
+ type: "button",
19005
+ "aria-expanded": open,
19006
+ "aria-controls": panelId,
19007
+ "data-testid": testId ? `${testId}-header` : void 0,
19008
+ onClick: () => toggle(value),
19009
+ onMouseEnter: () => setHovered(true),
19010
+ onMouseLeave: () => setHovered(false),
19011
+ style: headerStyle,
19012
+ ...rest,
19013
+ children: [
19014
+ /* @__PURE__ */ jsx("span", { style: titleStyle, children: title }),
19015
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, style: chevronStyle, children: /* @__PURE__ */ jsx(
19016
+ "svg",
19017
+ {
19018
+ width: 11,
19019
+ height: 11,
19020
+ viewBox: "0 0 16 16",
19021
+ fill: "none",
19022
+ stroke: "var(--ink-3)",
19023
+ strokeWidth: 1.5,
19024
+ strokeLinecap: "round",
19025
+ strokeLinejoin: "round",
19026
+ children: /* @__PURE__ */ jsx("path", { d: "M4 6l4 4 4-4" })
19027
+ }
19028
+ ) })
19029
+ ]
19030
+ }
19031
+ ),
19032
+ open && /* @__PURE__ */ jsx(
19033
+ "div",
19034
+ {
19035
+ id: panelId,
19036
+ role: "region",
19037
+ "aria-labelledby": headerId,
19038
+ "data-testid": testId ? `${testId}-panel` : void 0,
19039
+ style: panelStyle2,
19040
+ children
19041
+ }
19042
+ )
19043
+ ] });
19044
+ }
19045
+ );
18106
19046
  export {
18107
19047
  AIBadge,
18108
19048
  AICard,
@@ -18113,6 +19053,8 @@ export {
18113
19053
  AISparkle,
18114
19054
  AIWorking,
18115
19055
  AI_OPTIONS,
19056
+ Accordion,
19057
+ AccordionItem,
18116
19058
  Alert,
18117
19059
  AppShell,
18118
19060
  AskTeja,
@@ -18131,6 +19073,7 @@ export {
18131
19073
  DEFAULT_LANG_OPTIONS,
18132
19074
  DENSITY_OPTIONS,
18133
19075
  DISPLAY_OPTIONS,
19076
+ DarkScope,
18134
19077
  DateInput,
18135
19078
  Divider,
18136
19079
  Drawer,
@@ -18149,6 +19092,9 @@ export {
18149
19092
  KV,
18150
19093
  LabelGroup,
18151
19094
  LangSwitcher,
19095
+ Menu,
19096
+ MenuDivider,
19097
+ MenuItem,
18152
19098
  MiniStat,
18153
19099
  Modal,
18154
19100
  ModalFooter,
@@ -18171,6 +19117,7 @@ export {
18171
19117
  SectionLabel,
18172
19118
  SegmentedControl,
18173
19119
  Select$1 as Select,
19120
+ SelectableCard,
18174
19121
  SettingRow,
18175
19122
  Sidebar,
18176
19123
  SidebarNav,
@@ -18204,7 +19151,11 @@ export {
18204
19151
  ThemeProvider,
18205
19152
  TimeZonePicker,
18206
19153
  TimelineRow,
19154
+ Toast,
19155
+ ToastHost,
19156
+ ToggleChip,
18207
19157
  ToolbarSearch,
19158
+ Tooltip,
18208
19159
  TopBar,
18209
19160
  US_STATES,
18210
19161
  ViewToggle,
@@ -18222,6 +19173,7 @@ export {
18222
19173
  parseDate,
18223
19174
  resolveThemeMode,
18224
19175
  shouldShowNavItem as shouldShowSidebarNavItem,
18225
- useTheme
19176
+ useTheme,
19177
+ useToast
18226
19178
  };
18227
19179
  //# sourceMappingURL=index.js.map