@teja-app/ui 0.0.12 → 0.0.14

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