@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.
@@ -658,7 +658,7 @@ const VARIANT_STYLES = {
658
658
  border: "1px solid transparent"
659
659
  }
660
660
  };
661
- const SIZE_DIMS$1 = {
661
+ const SIZE_DIMS$2 = {
662
662
  sm: { h: 28, pad: "0 10px", fz: 12 },
663
663
  md: { h: 32, pad: "0 12px", fz: 13 },
664
664
  lg: { h: 38, pad: "0 16px", fz: 14 }
@@ -676,7 +676,7 @@ const Button$1 = React.forwardRef(function Button2({
676
676
  testId,
677
677
  ...rest
678
678
  }, ref) {
679
- const dims = SIZE_DIMS$1[size2];
679
+ const dims = SIZE_DIMS$2[size2];
680
680
  return /* @__PURE__ */ jsxRuntime.jsxs(
681
681
  "button",
682
682
  {
@@ -740,13 +740,15 @@ function Badge({
740
740
  tone = "neutral",
741
741
  size: size2 = "md",
742
742
  dot,
743
+ colors,
743
744
  children,
744
745
  style,
745
746
  testId,
746
747
  "data-testid": dataTestId,
747
748
  ...rest
748
749
  }) {
749
- const t2 = TONES$1[tone];
750
+ const base = TONES$1[tone] ?? TONES$1.neutral;
751
+ const t2 = colors ? { bg: colors.bg, fg: colors.fg, dot: colors.dot ?? colors.fg } : base;
750
752
  const h2 = size2 === "sm" ? 18 : 22;
751
753
  const fz = size2 === "sm" ? 10.5 : 11.5;
752
754
  const merged = {
@@ -783,16 +785,80 @@ function Badge({
783
785
  children
784
786
  ] });
785
787
  }
786
- function Card({ padding = 20, children, style, testId, ...rest }) {
787
- const merged = {
788
- background: "var(--surface-0)",
789
- borderRadius: "var(--r-lg)",
790
- border: "1px solid var(--border)",
788
+ const Card = React.forwardRef(function Card2({
789
+ padding = 20,
790
+ children,
791
+ style,
792
+ testId,
793
+ selected = false,
794
+ interactive,
795
+ onClick,
796
+ onKeyDown,
797
+ ...rest
798
+ }, ref) {
799
+ const isInteractive = interactive ?? !!onClick;
800
+ const surfaceStyle = {
801
+ background: selected ? "var(--primary-soft)" : "var(--surface-0)",
802
+ borderRadius: isInteractive ? "var(--r-md)" : "var(--r-lg)",
803
+ border: selected ? "1px solid var(--primary)" : "1px solid var(--border)",
804
+ boxShadow: selected ? "0 0 0 3px var(--primary-ring)" : isInteractive ? "var(--shadow-xs)" : void 0,
791
805
  padding,
806
+ cursor: isInteractive ? "pointer" : void 0,
807
+ transition: isInteractive ? "background .12s, box-shadow .12s" : void 0,
808
+ fontFamily: "inherit",
809
+ fontSize: "inherit",
810
+ textAlign: "inherit",
792
811
  ...style
793
812
  };
794
- return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": testId, style: merged, ...rest, children });
795
- }
813
+ if (isInteractive) {
814
+ const handleKeyDown = (e2) => {
815
+ if ((e2.key === "Enter" || e2.key === " ") && onClick) {
816
+ e2.preventDefault();
817
+ onClick(
818
+ e2
819
+ );
820
+ }
821
+ if (onKeyDown) {
822
+ onKeyDown(e2);
823
+ }
824
+ };
825
+ return /* @__PURE__ */ jsxRuntime.jsx(
826
+ "button",
827
+ {
828
+ ref,
829
+ type: "button",
830
+ "data-testid": testId,
831
+ "data-selected": selected ? "true" : void 0,
832
+ "data-interactive": "true",
833
+ onClick,
834
+ onKeyDown: handleKeyDown,
835
+ style: {
836
+ // Reset default button chrome
837
+ appearance: "none",
838
+ WebkitAppearance: "none",
839
+ display: "block",
840
+ width: "100%",
841
+ ...surfaceStyle,
842
+ // Re-apply border after reset (border: 'none' from reset would win)
843
+ border: surfaceStyle.border
844
+ },
845
+ ...rest,
846
+ children
847
+ }
848
+ );
849
+ }
850
+ return /* @__PURE__ */ jsxRuntime.jsx(
851
+ "div",
852
+ {
853
+ ref,
854
+ "data-testid": testId,
855
+ "data-selected": selected ? "true" : void 0,
856
+ style: surfaceStyle,
857
+ ...rest,
858
+ children
859
+ }
860
+ );
861
+ });
796
862
  function TejaMark({ size: size2 = 22, style, testId }) {
797
863
  return /* @__PURE__ */ jsxRuntime.jsxs(
798
864
  "svg",
@@ -13311,6 +13377,65 @@ function RoleTile({
13311
13377
  }
13312
13378
  );
13313
13379
  }
13380
+ const SelectableCard = React.forwardRef(
13381
+ function SelectableCard2({
13382
+ selected,
13383
+ role = "radio",
13384
+ onSelect,
13385
+ disabled = false,
13386
+ testId,
13387
+ children,
13388
+ style,
13389
+ onClick,
13390
+ ...rest
13391
+ }, ref) {
13392
+ const cardStyle = {
13393
+ // Layout
13394
+ display: "block",
13395
+ width: "100%",
13396
+ textAlign: "left",
13397
+ // Spacing — matches RoleTile (padding: 12)
13398
+ padding: 12,
13399
+ // Border — 1.5px primary when selected, border-strong when not
13400
+ border: `1.5px solid ${selected ? "var(--primary)" : "var(--border-strong)"}`,
13401
+ // Background — primary-soft when selected, surface-0 when not
13402
+ background: selected ? "var(--primary-soft)" : "var(--surface-0)",
13403
+ // Shape — matches RoleTile
13404
+ borderRadius: "var(--r-md)",
13405
+ // Shadow — shadow-xs when selected, none when not (matches RoleTile)
13406
+ boxShadow: selected ? "var(--shadow-xs)" : "none",
13407
+ // Typography reset
13408
+ font: "inherit",
13409
+ // Cursor
13410
+ cursor: disabled ? "not-allowed" : "pointer",
13411
+ // Disabled dimming
13412
+ opacity: disabled ? 0.5 : 1,
13413
+ // Merge caller overrides last
13414
+ ...style
13415
+ };
13416
+ function handleClick(e2) {
13417
+ if (!disabled) {
13418
+ onSelect?.();
13419
+ onClick?.(e2);
13420
+ }
13421
+ }
13422
+ return /* @__PURE__ */ jsxRuntime.jsx(
13423
+ "button",
13424
+ {
13425
+ ref,
13426
+ type: "button",
13427
+ role,
13428
+ "aria-checked": selected,
13429
+ "data-testid": testId,
13430
+ disabled,
13431
+ onClick: handleClick,
13432
+ style: cardStyle,
13433
+ ...rest,
13434
+ children
13435
+ }
13436
+ );
13437
+ }
13438
+ );
13314
13439
  const CELL_COUNT = 6;
13315
13440
  const EMPTY_CELLS = Array.from(
13316
13441
  { length: CELL_COUNT },
@@ -14197,6 +14322,7 @@ function SegmentedControl({
14197
14322
  role: "tab",
14198
14323
  "aria-selected": active,
14199
14324
  "data-state": active ? "active" : "inactive",
14325
+ "data-active": active ? "true" : "false",
14200
14326
  "data-testid": testId ? `${testId}-${it.value}` : void 0,
14201
14327
  onClick: () => onChange?.(it.value),
14202
14328
  style: {
@@ -15426,7 +15552,7 @@ function Drawer$1({
15426
15552
  testId,
15427
15553
  ariaLabel,
15428
15554
  style,
15429
- panelStyle
15555
+ panelStyle: panelStyle2
15430
15556
  }) {
15431
15557
  const panelRef = React.useRef(null);
15432
15558
  const previouslyFocusedRef = React.useRef(null);
@@ -15528,7 +15654,7 @@ function Drawer$1({
15528
15654
  display: "flex",
15529
15655
  flexDirection: "column",
15530
15656
  outline: "none",
15531
- ...panelStyle
15657
+ ...panelStyle2
15532
15658
  },
15533
15659
  children: [
15534
15660
  header,
@@ -15663,7 +15789,7 @@ function Modal$1({
15663
15789
  testId,
15664
15790
  ariaLabel,
15665
15791
  style,
15666
- panelStyle
15792
+ panelStyle: panelStyle2
15667
15793
  }) {
15668
15794
  const panelRef = React.useRef(null);
15669
15795
  const previouslyFocusedRef = React.useRef(null);
@@ -15773,7 +15899,7 @@ function Modal$1({
15773
15899
  boxShadow: "0 24px 64px rgba(0,0,0,0.22), 0 4px 16px rgba(0,0,0,0.12)",
15774
15900
  overflow: "hidden",
15775
15901
  outline: "none",
15776
- ...panelStyle
15902
+ ...panelStyle2
15777
15903
  },
15778
15904
  children: [
15779
15905
  header ?? (title || description ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -16712,6 +16838,79 @@ const Chip = React.forwardRef(function Chip2({ active, count: count2, tone = "pr
16712
16838
  }
16713
16839
  );
16714
16840
  });
16841
+ const SIZE_DIMS$1 = {
16842
+ sm: { height: 24, padding: "0 10px", fontSize: 11, gap: 4 },
16843
+ md: { height: 28, padding: "0 12px", fontSize: 12, gap: 6 }
16844
+ };
16845
+ const ToggleChip = React.forwardRef(
16846
+ function ToggleChip2({
16847
+ pressed,
16848
+ onPressedChange,
16849
+ icon,
16850
+ tone = "primary",
16851
+ size: size2 = "md",
16852
+ disabled = false,
16853
+ style,
16854
+ testId,
16855
+ onClick,
16856
+ children,
16857
+ ...rest
16858
+ }, ref) {
16859
+ const dims = SIZE_DIMS$1[size2];
16860
+ const pillStyle = {
16861
+ // Geometry — from PillSelector item template
16862
+ display: "inline-flex",
16863
+ alignItems: "center",
16864
+ justifyContent: "center",
16865
+ gap: dims.gap,
16866
+ height: dims.height,
16867
+ padding: dims.padding,
16868
+ fontSize: dims.fontSize,
16869
+ fontWeight: 500,
16870
+ borderRadius: "var(--r-pill)",
16871
+ // Colours — tokens only, never hardcoded
16872
+ border: "1px solid",
16873
+ borderColor: pressed ? `var(--${tone})` : "var(--border)",
16874
+ background: pressed ? `var(--${tone}-soft)` : "var(--surface-0)",
16875
+ color: pressed ? `var(--${tone})` : "var(--ink-2)",
16876
+ // Interaction
16877
+ cursor: disabled ? "not-allowed" : "pointer",
16878
+ opacity: disabled ? 0.5 : 1,
16879
+ whiteSpace: "nowrap",
16880
+ flexShrink: 0,
16881
+ transition: "background .12s, border-color .12s, color .12s",
16882
+ // Reset button defaults
16883
+ outline: "none",
16884
+ ...style
16885
+ };
16886
+ const handleClick = (e2) => {
16887
+ if (disabled) return;
16888
+ onPressedChange?.(!pressed);
16889
+ onClick?.(e2);
16890
+ };
16891
+ return /* @__PURE__ */ jsxRuntime.jsxs(
16892
+ "button",
16893
+ {
16894
+ ref,
16895
+ type: "button",
16896
+ disabled,
16897
+ "aria-pressed": pressed,
16898
+ "data-state": pressed ? "on" : "off",
16899
+ "data-active": pressed ? "true" : "false",
16900
+ "data-tone": tone,
16901
+ "data-testid": testId,
16902
+ style: pillStyle,
16903
+ onClick: handleClick,
16904
+ ...rest,
16905
+ children: [
16906
+ icon != null ? icon : null,
16907
+ children != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { children }) : null
16908
+ ]
16909
+ }
16910
+ );
16911
+ }
16912
+ );
16913
+ ToggleChip.displayName = "ToggleChip";
16715
16914
  const SIZE_DIMS = {
16716
16915
  sm: { height: 24, padding: "0 10px", fontSize: 11, gap: 4, iconSize: 12 },
16717
16916
  md: { height: 28, padding: "0 12px", fontSize: 12, gap: 6, iconSize: 14 },
@@ -18121,6 +18320,747 @@ function ConfirmDialog({
18121
18320
  }
18122
18321
  );
18123
18322
  }
18323
+ function panelStyle(placement, minWidth, zIndex) {
18324
+ const isTop = placement.startsWith("top");
18325
+ const isStart = placement.endsWith("start");
18326
+ return {
18327
+ position: "absolute",
18328
+ // vertical
18329
+ ...isTop ? { bottom: "100%", marginBottom: 4 } : { top: "100%", marginTop: 4 },
18330
+ // horizontal
18331
+ ...isStart ? { left: 0 } : { right: 0 },
18332
+ zIndex,
18333
+ minWidth,
18334
+ background: "var(--surface-0)",
18335
+ border: "1px solid var(--border)",
18336
+ borderRadius: "var(--r-md)",
18337
+ boxShadow: "var(--shadow-pop)",
18338
+ padding: 4,
18339
+ overflow: "hidden"
18340
+ };
18341
+ }
18342
+ function Menu({
18343
+ open,
18344
+ onClose,
18345
+ trigger,
18346
+ children,
18347
+ placement = "bottom-end",
18348
+ minWidth = 220,
18349
+ zIndex = 200,
18350
+ testId,
18351
+ style
18352
+ }) {
18353
+ const panelRef = React.useRef(null);
18354
+ React.useEffect(() => {
18355
+ if (!open) return;
18356
+ const onKey = (e2) => {
18357
+ if (e2.key === "Escape") {
18358
+ onClose();
18359
+ return;
18360
+ }
18361
+ if (e2.key === "ArrowDown" || e2.key === "ArrowUp") {
18362
+ e2.preventDefault();
18363
+ const panel = panelRef.current;
18364
+ if (!panel) return;
18365
+ const items = Array.from(
18366
+ panel.querySelectorAll('button[role="menuitem"]:not(:disabled)')
18367
+ );
18368
+ if (items.length === 0) return;
18369
+ const focused = items.indexOf(document.activeElement);
18370
+ const next = e2.key === "ArrowDown" ? (focused + 1) % items.length : (focused - 1 + items.length) % items.length;
18371
+ items[next]?.focus();
18372
+ }
18373
+ };
18374
+ window.addEventListener("keydown", onKey);
18375
+ return () => window.removeEventListener("keydown", onKey);
18376
+ }, [open, onClose]);
18377
+ React.useEffect(() => {
18378
+ if (!open) return;
18379
+ const panel = panelRef.current;
18380
+ if (!panel) return;
18381
+ const first = panel.querySelector('button[role="menuitem"]:not(:disabled)');
18382
+ if (first && !panel.contains(document.activeElement)) {
18383
+ first.focus();
18384
+ }
18385
+ }, [open]);
18386
+ const ps = panelStyle(placement, minWidth, zIndex);
18387
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", display: "inline-flex" }, children: [
18388
+ trigger,
18389
+ open && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18390
+ /* @__PURE__ */ jsxRuntime.jsx(
18391
+ "div",
18392
+ {
18393
+ "aria-hidden": "true",
18394
+ onClick: onClose,
18395
+ style: { position: "fixed", inset: 0, zIndex: zIndex - 1 }
18396
+ }
18397
+ ),
18398
+ /* @__PURE__ */ jsxRuntime.jsx(
18399
+ "div",
18400
+ {
18401
+ ref: panelRef,
18402
+ role: "menu",
18403
+ "aria-label": "menu",
18404
+ "data-testid": testId,
18405
+ onClick: onClose,
18406
+ style: { ...ps, ...style },
18407
+ children
18408
+ }
18409
+ )
18410
+ ] })
18411
+ ] });
18412
+ }
18413
+ const MenuItem = React.forwardRef(function MenuItem2({ icon, danger = false, children, onClick, disabled, testId, style, ...rest }, ref) {
18414
+ const [hovered, setHovered] = React.useState(false);
18415
+ const handleClick = React.useCallback(
18416
+ (e2) => {
18417
+ onClick?.(e2);
18418
+ },
18419
+ [onClick]
18420
+ );
18421
+ const merged = {
18422
+ display: "flex",
18423
+ alignItems: "center",
18424
+ gap: 8,
18425
+ width: "100%",
18426
+ padding: "8px 10px",
18427
+ border: 0,
18428
+ borderRadius: "var(--r-sm)",
18429
+ background: hovered && !disabled ? "var(--surface-1)" : "transparent",
18430
+ cursor: disabled ? "not-allowed" : "pointer",
18431
+ fontFamily: "inherit",
18432
+ fontSize: 12.5,
18433
+ color: disabled ? "var(--ink-4)" : danger ? "var(--danger)" : "var(--ink-1)",
18434
+ textAlign: "left",
18435
+ opacity: disabled ? 0.55 : 1,
18436
+ transition: "background .1s",
18437
+ outline: "none",
18438
+ ...style
18439
+ };
18440
+ return /* @__PURE__ */ jsxRuntime.jsxs(
18441
+ "button",
18442
+ {
18443
+ ref,
18444
+ role: "menuitem",
18445
+ type: "button",
18446
+ disabled,
18447
+ "data-testid": testId,
18448
+ "data-danger": danger ? "true" : void 0,
18449
+ style: merged,
18450
+ onMouseEnter: () => setHovered(true),
18451
+ onMouseLeave: () => setHovered(false),
18452
+ onClick: handleClick,
18453
+ ...rest,
18454
+ children: [
18455
+ icon ? /* @__PURE__ */ jsxRuntime.jsx(
18456
+ Icon,
18457
+ {
18458
+ name: icon,
18459
+ size: 12,
18460
+ color: disabled ? "var(--ink-4)" : danger ? "var(--danger)" : "var(--ink-3)"
18461
+ }
18462
+ ) : null,
18463
+ children
18464
+ ]
18465
+ }
18466
+ );
18467
+ });
18468
+ function MenuDivider({ style, ...rest }) {
18469
+ return /* @__PURE__ */ jsxRuntime.jsx(
18470
+ "hr",
18471
+ {
18472
+ role: "separator",
18473
+ style: {
18474
+ border: 0,
18475
+ borderTop: "1px solid var(--divider)",
18476
+ margin: "4px 2px",
18477
+ ...style
18478
+ },
18479
+ ...rest
18480
+ }
18481
+ );
18482
+ }
18483
+ const GAP = 8;
18484
+ const ARROW_SIZE = 5;
18485
+ function getBubbleStyle(placement) {
18486
+ const base = {
18487
+ position: "absolute",
18488
+ zIndex: "var(--z-tooltip)"
18489
+ };
18490
+ switch (placement) {
18491
+ case "top":
18492
+ return {
18493
+ ...base,
18494
+ bottom: `calc(100% + ${GAP}px)`,
18495
+ left: "50%",
18496
+ transform: "translateX(-50%)"
18497
+ };
18498
+ case "bottom":
18499
+ return {
18500
+ ...base,
18501
+ top: `calc(100% + ${GAP}px)`,
18502
+ left: "50%",
18503
+ transform: "translateX(-50%)"
18504
+ };
18505
+ case "left":
18506
+ return {
18507
+ ...base,
18508
+ right: `calc(100% + ${GAP}px)`,
18509
+ top: "50%",
18510
+ transform: "translateY(-50%)"
18511
+ };
18512
+ case "right":
18513
+ return {
18514
+ ...base,
18515
+ left: `calc(100% + ${GAP}px)`,
18516
+ top: "50%",
18517
+ transform: "translateY(-50%)"
18518
+ };
18519
+ }
18520
+ }
18521
+ function getArrowStyle(placement) {
18522
+ const base = {
18523
+ position: "absolute",
18524
+ width: ARROW_SIZE * 2,
18525
+ height: ARROW_SIZE * 2,
18526
+ background: "var(--ink-1)",
18527
+ transform: "rotate(45deg)"
18528
+ };
18529
+ switch (placement) {
18530
+ case "top":
18531
+ return {
18532
+ ...base,
18533
+ bottom: -4,
18534
+ left: "50%",
18535
+ marginLeft: -ARROW_SIZE
18536
+ };
18537
+ case "bottom":
18538
+ return {
18539
+ ...base,
18540
+ top: -4,
18541
+ left: "50%",
18542
+ marginLeft: -ARROW_SIZE
18543
+ };
18544
+ case "left":
18545
+ return {
18546
+ ...base,
18547
+ right: -4,
18548
+ top: "50%",
18549
+ marginTop: -ARROW_SIZE
18550
+ };
18551
+ case "right":
18552
+ return {
18553
+ ...base,
18554
+ left: -4,
18555
+ top: "50%",
18556
+ marginTop: -ARROW_SIZE
18557
+ };
18558
+ }
18559
+ }
18560
+ const Tooltip = React.forwardRef(function Tooltip2({
18561
+ label,
18562
+ placement = "top",
18563
+ delay = 400,
18564
+ children,
18565
+ testId,
18566
+ maxWidth = 220,
18567
+ style,
18568
+ ...rest
18569
+ }, ref) {
18570
+ const [visible, setVisible] = React.useState(false);
18571
+ const timerRef = React.useRef(null);
18572
+ const tooltipId = React.useId();
18573
+ const show = React.useCallback(() => {
18574
+ timerRef.current = setTimeout(() => setVisible(true), delay);
18575
+ }, [delay]);
18576
+ const hide = React.useCallback(() => {
18577
+ if (timerRef.current !== null) {
18578
+ clearTimeout(timerRef.current);
18579
+ timerRef.current = null;
18580
+ }
18581
+ setVisible(false);
18582
+ }, []);
18583
+ React.useEffect(() => {
18584
+ return () => {
18585
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
18586
+ };
18587
+ }, []);
18588
+ React.useEffect(() => {
18589
+ if (!visible) return;
18590
+ const onKey = (e2) => {
18591
+ if (e2.key === "Escape") hide();
18592
+ };
18593
+ document.addEventListener("keydown", onKey);
18594
+ return () => document.removeEventListener("keydown", onKey);
18595
+ }, [visible, hide]);
18596
+ const wrapperStyle = {
18597
+ position: "relative",
18598
+ display: "inline-flex",
18599
+ alignItems: "center",
18600
+ justifyContent: "center",
18601
+ ...style
18602
+ };
18603
+ const bubbleStyle = {
18604
+ ...getBubbleStyle(placement),
18605
+ background: "var(--ink-1)",
18606
+ color: "var(--surface-0)",
18607
+ fontSize: 12,
18608
+ fontWeight: 500,
18609
+ lineHeight: 1.4,
18610
+ padding: "6px 8px",
18611
+ borderRadius: "var(--r-sm)",
18612
+ boxShadow: "var(--shadow-pop)",
18613
+ maxWidth,
18614
+ whiteSpace: "nowrap",
18615
+ pointerEvents: "none",
18616
+ // Fade in
18617
+ opacity: visible ? 1 : 0,
18618
+ transition: "opacity 0.12s ease"
18619
+ };
18620
+ return /* @__PURE__ */ jsxRuntime.jsxs(
18621
+ "div",
18622
+ {
18623
+ ref,
18624
+ "data-testid": testId,
18625
+ "data-placement": placement,
18626
+ style: wrapperStyle,
18627
+ onMouseEnter: show,
18628
+ onMouseLeave: hide,
18629
+ onFocusCapture: show,
18630
+ onBlurCapture: hide,
18631
+ ...rest,
18632
+ children: [
18633
+ /* @__PURE__ */ jsxRuntime.jsx(
18634
+ "span",
18635
+ {
18636
+ "aria-describedby": visible ? tooltipId : void 0,
18637
+ style: { display: "contents" },
18638
+ children
18639
+ }
18640
+ ),
18641
+ /* @__PURE__ */ jsxRuntime.jsxs(
18642
+ "div",
18643
+ {
18644
+ id: tooltipId,
18645
+ role: "tooltip",
18646
+ "aria-hidden": !visible,
18647
+ style: bubbleStyle,
18648
+ children: [
18649
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, style: getArrowStyle(placement) }),
18650
+ label
18651
+ ]
18652
+ }
18653
+ )
18654
+ ]
18655
+ }
18656
+ );
18657
+ });
18658
+ const DarkScope = React.forwardRef(
18659
+ function DarkScope2({ children, style, testId, "data-testid": dataTestId, ...rest }, ref) {
18660
+ const merged = {
18661
+ colorScheme: "dark",
18662
+ ...style
18663
+ };
18664
+ return /* @__PURE__ */ jsxRuntime.jsx(
18665
+ "div",
18666
+ {
18667
+ ref,
18668
+ "data-theme": "dark",
18669
+ "data-testid": dataTestId ?? testId,
18670
+ style: merged,
18671
+ ...rest,
18672
+ children
18673
+ }
18674
+ );
18675
+ }
18676
+ );
18677
+ const TONE_SPECS = {
18678
+ success: {
18679
+ accent: "var(--success)",
18680
+ iconBg: "var(--success-soft)",
18681
+ iconColor: "var(--success)",
18682
+ defaultIcon: "check-circle"
18683
+ },
18684
+ danger: {
18685
+ accent: "var(--danger)",
18686
+ iconBg: "var(--danger-soft)",
18687
+ iconColor: "var(--danger)",
18688
+ defaultIcon: "alert-circle"
18689
+ },
18690
+ info: {
18691
+ accent: "var(--primary)",
18692
+ iconBg: "var(--primary-soft)",
18693
+ iconColor: "var(--primary)",
18694
+ defaultIcon: "info"
18695
+ },
18696
+ neutral: {
18697
+ accent: "var(--border)",
18698
+ iconBg: "var(--surface-2)",
18699
+ iconColor: "var(--ink-2)",
18700
+ defaultIcon: "bell"
18701
+ }
18702
+ };
18703
+ const ToastContext = React.createContext(null);
18704
+ let _idCounter = 0;
18705
+ const nextId = () => `toast-${++_idCounter}`;
18706
+ function useToast() {
18707
+ const ctx = React.useContext(ToastContext);
18708
+ if (!ctx) {
18709
+ throw new Error("useToast must be used within a <ToastHost />");
18710
+ }
18711
+ return ctx;
18712
+ }
18713
+ const Toast = React.forwardRef(function Toast2({
18714
+ message: message2,
18715
+ tone = "success",
18716
+ icon,
18717
+ action,
18718
+ onDismiss,
18719
+ style,
18720
+ testId,
18721
+ ...rest
18722
+ }, ref) {
18723
+ const t2 = TONE_SPECS[tone];
18724
+ const iconName = icon ?? t2.defaultIcon;
18725
+ const merged = {
18726
+ display: "flex",
18727
+ alignItems: "flex-start",
18728
+ gap: 10,
18729
+ padding: "11px 14px",
18730
+ background: "var(--surface-0)",
18731
+ border: "1px solid var(--border)",
18732
+ borderLeft: `3px solid ${t2.accent}`,
18733
+ borderRadius: "var(--r-md)",
18734
+ boxShadow: "var(--shadow-pop)",
18735
+ maxWidth: 320,
18736
+ width: 320,
18737
+ pointerEvents: "auto",
18738
+ ...style
18739
+ };
18740
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, "data-testid": testId, "data-tone": tone, style: merged, ...rest, children: [
18741
+ /* @__PURE__ */ jsxRuntime.jsx(
18742
+ "span",
18743
+ {
18744
+ "aria-hidden": true,
18745
+ style: {
18746
+ width: 26,
18747
+ height: 26,
18748
+ borderRadius: 999,
18749
+ flexShrink: 0,
18750
+ background: t2.iconBg,
18751
+ display: "inline-flex",
18752
+ alignItems: "center",
18753
+ justifyContent: "center"
18754
+ },
18755
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: iconName, size: 12, color: t2.iconColor })
18756
+ }
18757
+ ),
18758
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minWidth: 0, alignSelf: "center" }, children: [
18759
+ /* @__PURE__ */ jsxRuntime.jsx(
18760
+ "div",
18761
+ {
18762
+ style: {
18763
+ fontSize: 12.5,
18764
+ fontWeight: 600,
18765
+ color: "var(--ink-1)",
18766
+ lineHeight: 1.4
18767
+ },
18768
+ children: message2
18769
+ }
18770
+ ),
18771
+ action ? /* @__PURE__ */ jsxRuntime.jsx(
18772
+ "button",
18773
+ {
18774
+ type: "button",
18775
+ onClick: () => {
18776
+ action.onClick();
18777
+ onDismiss?.();
18778
+ },
18779
+ style: {
18780
+ marginTop: 4,
18781
+ fontSize: 11.5,
18782
+ fontWeight: 500,
18783
+ color: "var(--primary)",
18784
+ background: "none",
18785
+ border: 0,
18786
+ padding: 0,
18787
+ cursor: "pointer",
18788
+ lineHeight: 1
18789
+ },
18790
+ children: action.label
18791
+ }
18792
+ ) : null
18793
+ ] }),
18794
+ /* @__PURE__ */ jsxRuntime.jsx(
18795
+ "button",
18796
+ {
18797
+ type: "button",
18798
+ "aria-label": "Dismiss",
18799
+ onClick: onDismiss,
18800
+ style: {
18801
+ background: "none",
18802
+ border: 0,
18803
+ padding: 2,
18804
+ cursor: "pointer",
18805
+ color: "var(--ink-3)",
18806
+ display: "inline-flex",
18807
+ alignItems: "center",
18808
+ flexShrink: 0,
18809
+ borderRadius: "var(--r-sm)"
18810
+ },
18811
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "x", size: 12 })
18812
+ }
18813
+ )
18814
+ ] });
18815
+ });
18816
+ function ToastEntry({ item, onRemove }) {
18817
+ const [visible, setVisible] = React.useState(false);
18818
+ const timerRef = React.useRef(null);
18819
+ React.useEffect(() => {
18820
+ const raf = requestAnimationFrame(() => setVisible(true));
18821
+ return () => cancelAnimationFrame(raf);
18822
+ }, []);
18823
+ React.useEffect(() => {
18824
+ timerRef.current = setTimeout(() => {
18825
+ setVisible(false);
18826
+ setTimeout(() => {
18827
+ onRemove(item.id);
18828
+ item.then?.();
18829
+ }, 220);
18830
+ }, item.ms);
18831
+ return () => {
18832
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
18833
+ };
18834
+ }, [item, onRemove]);
18835
+ const handleDismiss = React.useCallback(() => {
18836
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
18837
+ setVisible(false);
18838
+ setTimeout(() => {
18839
+ onRemove(item.id);
18840
+ item.then?.();
18841
+ }, 220);
18842
+ }, [item, onRemove]);
18843
+ return /* @__PURE__ */ jsxRuntime.jsx(
18844
+ "div",
18845
+ {
18846
+ style: {
18847
+ transition: "opacity 0.2s ease, transform 0.2s ease",
18848
+ opacity: visible ? 1 : 0,
18849
+ transform: visible ? "translateX(0)" : "translateX(24px)"
18850
+ },
18851
+ children: /* @__PURE__ */ jsxRuntime.jsx(
18852
+ Toast,
18853
+ {
18854
+ message: item.message,
18855
+ tone: item.tone,
18856
+ icon: item.icon,
18857
+ action: item.action,
18858
+ onDismiss: handleDismiss,
18859
+ testId: `toast-${item.id}`
18860
+ }
18861
+ )
18862
+ }
18863
+ );
18864
+ }
18865
+ function ToastHost({ children, container }) {
18866
+ const [items, setItems] = React.useState([]);
18867
+ const showToast = React.useCallback((message2, opts = {}) => {
18868
+ const tone = opts.tone ?? "success";
18869
+ const t2 = TONE_SPECS[tone];
18870
+ const item = {
18871
+ id: nextId(),
18872
+ message: message2,
18873
+ tone,
18874
+ icon: opts.icon ?? t2.defaultIcon,
18875
+ ms: opts.ms ?? 2500,
18876
+ action: opts.action,
18877
+ then: opts.then
18878
+ };
18879
+ setItems((prev) => [...prev, item]);
18880
+ }, []);
18881
+ const removeItem = React.useCallback((id) => {
18882
+ setItems((prev) => prev.filter((i2) => i2.id !== id));
18883
+ }, []);
18884
+ const hostStyle = {
18885
+ position: "fixed",
18886
+ top: 80,
18887
+ right: 20,
18888
+ zIndex: 200,
18889
+ display: "flex",
18890
+ flexDirection: "column",
18891
+ gap: 8,
18892
+ pointerEvents: "none"
18893
+ // Ensure toasts stack above most content
18894
+ };
18895
+ const portal = ReactDOM.createPortal(
18896
+ /* @__PURE__ */ jsxRuntime.jsx(
18897
+ "div",
18898
+ {
18899
+ role: "region",
18900
+ "aria-live": "polite",
18901
+ "aria-label": "Notifications",
18902
+ style: hostStyle,
18903
+ children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(ToastEntry, { item, onRemove: removeItem }, item.id))
18904
+ }
18905
+ ),
18906
+ container ?? document.body
18907
+ );
18908
+ return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value: { showToast }, children: [
18909
+ children,
18910
+ portal
18911
+ ] });
18912
+ }
18913
+ const AccordionContext = React.createContext(null);
18914
+ function useAccordionCtx() {
18915
+ const ctx = React.useContext(AccordionContext);
18916
+ if (!ctx) {
18917
+ throw new Error("AccordionItem must be rendered inside an Accordion.");
18918
+ }
18919
+ return ctx;
18920
+ }
18921
+ function Accordion({
18922
+ multiple = false,
18923
+ defaultValue,
18924
+ value: controlledValue,
18925
+ onChange,
18926
+ children,
18927
+ style,
18928
+ testId
18929
+ }) {
18930
+ const [internalOpen, setInternalOpen] = React.useState(() => {
18931
+ if (defaultValue === void 0) return /* @__PURE__ */ new Set();
18932
+ return new Set(Array.isArray(defaultValue) ? defaultValue : [defaultValue]);
18933
+ });
18934
+ const isControlled = controlledValue !== void 0;
18935
+ const openSet = React.useMemo(
18936
+ () => isControlled ? new Set(Array.isArray(controlledValue) ? controlledValue : [controlledValue]) : internalOpen,
18937
+ [isControlled, controlledValue, internalOpen]
18938
+ );
18939
+ const isOpen = React.useCallback((v2) => openSet.has(v2), [openSet]);
18940
+ const toggle = React.useCallback(
18941
+ (v2) => {
18942
+ let next;
18943
+ if (openSet.has(v2)) {
18944
+ next = new Set([...openSet].filter((x2) => x2 !== v2));
18945
+ } else if (multiple) {
18946
+ next = /* @__PURE__ */ new Set([...openSet, v2]);
18947
+ } else {
18948
+ next = /* @__PURE__ */ new Set([v2]);
18949
+ }
18950
+ if (!isControlled) {
18951
+ setInternalOpen(next);
18952
+ }
18953
+ if (onChange) {
18954
+ const arr = [...next];
18955
+ onChange(multiple ? arr : arr[0] ?? "");
18956
+ }
18957
+ },
18958
+ [openSet, multiple, isControlled, onChange]
18959
+ );
18960
+ const ctx = { isOpen, toggle };
18961
+ return /* @__PURE__ */ jsxRuntime.jsx(AccordionContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx(
18962
+ "div",
18963
+ {
18964
+ "data-testid": testId,
18965
+ style: {
18966
+ display: "flex",
18967
+ flexDirection: "column",
18968
+ gap: 0,
18969
+ ...style
18970
+ },
18971
+ children
18972
+ }
18973
+ ) });
18974
+ }
18975
+ const AccordionItem = React.forwardRef(
18976
+ function AccordionItem2({ value, title, children, testId, style, ...rest }, ref) {
18977
+ const { isOpen, toggle } = useAccordionCtx();
18978
+ const open = isOpen(value);
18979
+ const uid = React.useId();
18980
+ const headerId = `accordion-header-${uid}`;
18981
+ const panelId = `accordion-panel-${uid}`;
18982
+ const [hovered, setHovered] = React.useState(false);
18983
+ const headerStyle = {
18984
+ display: "flex",
18985
+ alignItems: "center",
18986
+ justifyContent: "space-between",
18987
+ width: "100%",
18988
+ padding: "10px 12px",
18989
+ border: 0,
18990
+ borderRadius: "var(--r-md)",
18991
+ background: hovered ? "var(--surface-1)" : "transparent",
18992
+ cursor: "pointer",
18993
+ fontFamily: "inherit",
18994
+ textAlign: "left",
18995
+ transition: "background .1s",
18996
+ outline: "none"
18997
+ };
18998
+ const titleStyle = {
18999
+ fontSize: 13,
19000
+ fontWeight: 600,
19001
+ color: "var(--ink-1)",
19002
+ flex: 1,
19003
+ minWidth: 0
19004
+ };
19005
+ const chevronStyle = {
19006
+ flexShrink: 0,
19007
+ display: "inline-flex",
19008
+ alignItems: "center",
19009
+ justifyContent: "center",
19010
+ transform: open ? "rotate(180deg)" : "rotate(0deg)",
19011
+ transition: "transform .15s"
19012
+ };
19013
+ const panelStyle2 = {
19014
+ paddingTop: 8
19015
+ };
19016
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...style }, children: [
19017
+ /* @__PURE__ */ jsxRuntime.jsxs(
19018
+ "button",
19019
+ {
19020
+ ref,
19021
+ id: headerId,
19022
+ type: "button",
19023
+ "aria-expanded": open,
19024
+ "aria-controls": panelId,
19025
+ "data-testid": testId ? `${testId}-header` : void 0,
19026
+ onClick: () => toggle(value),
19027
+ onMouseEnter: () => setHovered(true),
19028
+ onMouseLeave: () => setHovered(false),
19029
+ style: headerStyle,
19030
+ ...rest,
19031
+ children: [
19032
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: titleStyle, children: title }),
19033
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, style: chevronStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
19034
+ "svg",
19035
+ {
19036
+ width: 11,
19037
+ height: 11,
19038
+ viewBox: "0 0 16 16",
19039
+ fill: "none",
19040
+ stroke: "var(--ink-3)",
19041
+ strokeWidth: 1.5,
19042
+ strokeLinecap: "round",
19043
+ strokeLinejoin: "round",
19044
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 6l4 4 4-4" })
19045
+ }
19046
+ ) })
19047
+ ]
19048
+ }
19049
+ ),
19050
+ open && /* @__PURE__ */ jsxRuntime.jsx(
19051
+ "div",
19052
+ {
19053
+ id: panelId,
19054
+ role: "region",
19055
+ "aria-labelledby": headerId,
19056
+ "data-testid": testId ? `${testId}-panel` : void 0,
19057
+ style: panelStyle2,
19058
+ children
19059
+ }
19060
+ )
19061
+ ] });
19062
+ }
19063
+ );
18124
19064
  exports.AIBadge = AIBadge;
18125
19065
  exports.AICard = AICard;
18126
19066
  exports.AIChip = AIChip;
@@ -18130,6 +19070,8 @@ exports.AISectionHeader = AISectionHeader;
18130
19070
  exports.AISparkle = AISparkle;
18131
19071
  exports.AIWorking = AIWorking;
18132
19072
  exports.AI_OPTIONS = AI_OPTIONS;
19073
+ exports.Accordion = Accordion;
19074
+ exports.AccordionItem = AccordionItem;
18133
19075
  exports.Alert = Alert;
18134
19076
  exports.AppShell = AppShell;
18135
19077
  exports.AskTeja = AskTeja;
@@ -18148,6 +19090,7 @@ exports.CountryPicker = CountryPicker;
18148
19090
  exports.DEFAULT_LANG_OPTIONS = DEFAULT_LANG_OPTIONS;
18149
19091
  exports.DENSITY_OPTIONS = DENSITY_OPTIONS;
18150
19092
  exports.DISPLAY_OPTIONS = DISPLAY_OPTIONS;
19093
+ exports.DarkScope = DarkScope;
18151
19094
  exports.DateInput = DateInput;
18152
19095
  exports.Divider = Divider;
18153
19096
  exports.Drawer = Drawer;
@@ -18166,6 +19109,9 @@ exports.IconButton = IconButton;
18166
19109
  exports.KV = KV;
18167
19110
  exports.LabelGroup = LabelGroup;
18168
19111
  exports.LangSwitcher = LangSwitcher;
19112
+ exports.Menu = Menu;
19113
+ exports.MenuDivider = MenuDivider;
19114
+ exports.MenuItem = MenuItem;
18169
19115
  exports.MiniStat = MiniStat;
18170
19116
  exports.Modal = Modal;
18171
19117
  exports.ModalFooter = ModalFooter;
@@ -18188,6 +19134,7 @@ exports.SURFACE_OPTIONS = SURFACE_OPTIONS;
18188
19134
  exports.SectionLabel = SectionLabel;
18189
19135
  exports.SegmentedControl = SegmentedControl;
18190
19136
  exports.Select = Select$1;
19137
+ exports.SelectableCard = SelectableCard;
18191
19138
  exports.SettingRow = SettingRow;
18192
19139
  exports.Sidebar = Sidebar;
18193
19140
  exports.SidebarNav = SidebarNav;
@@ -18221,7 +19168,11 @@ exports.Textarea = Textarea;
18221
19168
  exports.ThemeProvider = ThemeProvider;
18222
19169
  exports.TimeZonePicker = TimeZonePicker;
18223
19170
  exports.TimelineRow = TimelineRow;
19171
+ exports.Toast = Toast;
19172
+ exports.ToastHost = ToastHost;
19173
+ exports.ToggleChip = ToggleChip;
18224
19174
  exports.ToolbarSearch = ToolbarSearch;
19175
+ exports.Tooltip = Tooltip;
18225
19176
  exports.TopBar = TopBar;
18226
19177
  exports.US_STATES = US_STATES;
18227
19178
  exports.ViewToggle = ViewToggle;
@@ -18240,4 +19191,5 @@ exports.parseDate = parseDate;
18240
19191
  exports.resolveThemeMode = resolveThemeMode;
18241
19192
  exports.shouldShowSidebarNavItem = shouldShowNavItem;
18242
19193
  exports.useTheme = useTheme;
19194
+ exports.useToast = useToast;
18243
19195
  //# sourceMappingURL=index.cjs.map