@invana/ui 0.0.34 → 0.0.35

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.
package/dist/index.cjs CHANGED
@@ -4565,7 +4565,7 @@ var NavItems = ({
4565
4565
  const isActive = key === currentKey;
4566
4566
  const hasMenu = !item.href && Boolean(item.menuItems?.length);
4567
4567
  const asCaret = hasMenu && item.menuTrigger === "caret";
4568
- const hostsButton = asCaret || Boolean(item.onClose);
4568
+ const hostsButton = asCaret;
4569
4569
  const isInteractive = Boolean(
4570
4570
  item.href || item.onClick || hasMenu || isTabs
4571
4571
  );
@@ -4628,9 +4628,9 @@ var NavItems = ({
4628
4628
  }
4629
4629
  ) });
4630
4630
  const close = item.onClose && /* @__PURE__ */ jsxRuntime.jsx(
4631
- "span",
4631
+ "button",
4632
4632
  {
4633
- role: "button",
4633
+ type: "button",
4634
4634
  tabIndex: -1,
4635
4635
  "aria-label": `Close ${item.name}`,
4636
4636
  onClick: (e) => {
@@ -4645,20 +4645,49 @@ var NavItems = ({
4645
4645
  icon,
4646
4646
  label,
4647
4647
  caret,
4648
- close,
4649
4648
  badge
4650
4649
  ] });
4651
- const control = hostsButton ? /* @__PURE__ */ jsxRuntime.jsx(
4650
+ const control = close ? /* @__PURE__ */ jsxRuntime.jsxs(
4652
4651
  "div",
4653
4652
  {
4654
- ref: setNode,
4655
- ...tabProps,
4656
- ...a11y,
4653
+ ref: itemRef(index),
4657
4654
  style: item.style,
4658
4655
  onClick: () => select(item),
4659
- className: itemClass,
4660
- children: inner
4656
+ className: cn(
4657
+ itemClass,
4658
+ "has-[[role=tab]:focus-visible]:ring-2 has-[[role=tab]:focus-visible]:ring-ring"
4659
+ ),
4660
+ children: [
4661
+ /* @__PURE__ */ jsxRuntime.jsx(
4662
+ "div",
4663
+ {
4664
+ ref: (el) => {
4665
+ nodes.current[key] = el;
4666
+ },
4667
+ ...tabProps,
4668
+ ...a11y,
4669
+ className: "inline-flex items-center gap-[inherit] focus-visible:outline-none",
4670
+ children: inner
4671
+ }
4672
+ ),
4673
+ close
4674
+ ]
4661
4675
  }
4676
+ ) : hostsButton ? (
4677
+ // A caret item hosts a button, so it cannot itself be one — nested
4678
+ // buttons are invalid, and the browser resolves the click to the outer control.
4679
+ /* @__PURE__ */ jsxRuntime.jsx(
4680
+ "div",
4681
+ {
4682
+ ref: setNode,
4683
+ ...tabProps,
4684
+ ...a11y,
4685
+ style: item.style,
4686
+ onClick: () => select(item),
4687
+ className: itemClass,
4688
+ children: inner
4689
+ }
4690
+ )
4662
4691
  ) : item.href ? /* @__PURE__ */ jsxRuntime.jsx(
4663
4692
  "a",
4664
4693
  {
@@ -5469,6 +5498,7 @@ ClarifyActions.displayName = "ClarifyActions";
5469
5498
  var ClarifyCard = React25__namespace.forwardRef(
5470
5499
  ({
5471
5500
  state = "pending",
5501
+ variant = "card",
5472
5502
  kind = "question",
5473
5503
  step,
5474
5504
  waiting,
@@ -5476,7 +5506,13 @@ var ClarifyCard = React25__namespace.forwardRef(
5476
5506
  question,
5477
5507
  options,
5478
5508
  value,
5509
+ answer,
5510
+ questions,
5479
5511
  onSelect,
5512
+ onTypeInstead,
5513
+ typeInsteadLabel,
5514
+ collapsible = false,
5515
+ defaultOpen,
5480
5516
  children,
5481
5517
  footnote,
5482
5518
  actions,
@@ -5485,50 +5521,153 @@ var ClarifyCard = React25__namespace.forwardRef(
5485
5521
  ...props
5486
5522
  }, ref) => {
5487
5523
  const settled = state !== "pending";
5524
+ const inline = variant === "inline";
5488
5525
  const name = React25__namespace.useId();
5526
+ const asks = questions ?? (question != null || options ? [{ question, options, value, answer }] : []);
5527
+ const [open, setOpen] = React25__namespace.useState(defaultOpen ?? !settled);
5528
+ const wasSettled = React25__namespace.useRef(settled);
5529
+ React25__namespace.useEffect(() => {
5530
+ if (settled && !wasSettled.current) setOpen(defaultOpen ?? false);
5531
+ wasSettled.current = settled;
5532
+ }, [settled, defaultOpen]);
5533
+ const shown = !collapsible || open;
5534
+ const summary = settled ? summaryOf(asks) : null;
5535
+ const title = settled && !inline ? state : kind;
5536
+ const sub = inline ? [settled ? state : null, summary ?? step].filter((x) => x != null) : step != null ? [step] : [];
5537
+ const chevron = collapsible ? /* @__PURE__ */ jsxRuntime.jsx(
5538
+ "svg",
5539
+ {
5540
+ "aria-hidden": "true",
5541
+ viewBox: "0 0 24 24",
5542
+ fill: "none",
5543
+ stroke: "currentColor",
5544
+ strokeWidth: 2,
5545
+ strokeLinecap: "round",
5546
+ strokeLinejoin: "round",
5547
+ className: cn("size-3 shrink-0 transition-transform", open && "rotate-180"),
5548
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
5549
+ }
5550
+ ) : null;
5551
+ const headerContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5552
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("shrink-0 font-medium", inline && "first-letter:uppercase"), children: title }),
5553
+ sub.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate text-muted-foreground first-letter:uppercase", children: sub.map((part, i) => /* @__PURE__ */ jsxRuntime.jsxs(React25__namespace.Fragment, { children: [
5554
+ i > 0 ? " \xB7 " : null,
5555
+ part
5556
+ ] }, i)) }) : null,
5557
+ inline ? chevron : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1" }),
5558
+ waiting != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: waiting }) : null,
5559
+ time != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: time }) : null,
5560
+ !inline ? chevron : null
5561
+ ] });
5562
+ const headerClass = inline ? "flex min-w-0 items-center gap-1.5 text-start" : "flex h-control-sm shrink-0 items-center gap-2 border-b border-border bg-chrome px-2 text-sm text-start";
5489
5563
  return /* @__PURE__ */ jsxRuntime.jsxs(
5490
5564
  "div",
5491
5565
  {
5492
5566
  ref,
5493
5567
  "data-state": state,
5568
+ "data-variant": variant,
5494
5569
  className: cn(
5495
- "flex min-w-0 flex-col overflow-hidden border border-border bg-card",
5570
+ "flex min-w-0 flex-col",
5571
+ inline ? "gap-2" : "overflow-hidden border border-border bg-card",
5496
5572
  (state === "superseded" || state === "expired") && "opacity-75",
5497
5573
  className
5498
5574
  ),
5499
5575
  ...props,
5500
5576
  children: [
5501
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-control-sm shrink-0 items-center gap-2 border-b border-border bg-chrome px-2 text-sm", children: [
5502
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 font-medium", children: settled ? state : kind }),
5503
- step != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-muted-foreground", children: step }) : null,
5504
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1" }),
5505
- waiting != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: waiting }) : null,
5506
- time != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: time }) : null
5507
- ] }),
5508
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-2 p-2", children: [
5509
- question != null ? /* @__PURE__ */ jsxRuntime.jsx("p", { children: question }) : null,
5510
- children ?? (options ? /* @__PURE__ */ jsxRuntime.jsx(Questionnaire, { onSubmit: (e) => e.preventDefault(), children: /* @__PURE__ */ jsxRuntime.jsx(QuestionnaireItem, { name, children: /* @__PURE__ */ jsxRuntime.jsx(QuestionnaireChoices, { children: options.map((o) => /* @__PURE__ */ jsxRuntime.jsx(
5511
- QuestionnaireChoice,
5577
+ collapsible ? /* @__PURE__ */ jsxRuntime.jsx(
5578
+ "button",
5579
+ {
5580
+ type: "button",
5581
+ "aria-expanded": open,
5582
+ onClick: () => setOpen((o) => !o),
5583
+ className: cn(
5584
+ headerClass,
5585
+ "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
5586
+ inline && "self-start rounded-control"
5587
+ ),
5588
+ children: headerContent
5589
+ }
5590
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: headerClass, children: headerContent }),
5591
+ shown ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-1 flex-col", inline ? "gap-3" : "gap-2 p-2"), children: [
5592
+ children ?? asks.map((ask, index) => /* @__PURE__ */ jsxRuntime.jsx(
5593
+ Ask,
5512
5594
  {
5513
- value: o.value,
5514
- detail: o.detail,
5515
- disabled: o.disabled,
5516
- readOnly: settled,
5517
- checked: value === void 0 ? void 0 : value === o.value,
5518
- onChange: () => onSelect?.(o.value),
5519
- children: /* @__PURE__ */ jsxRuntime.jsx(QuestionnaireChoiceTitle, { children: o.label })
5595
+ ask,
5596
+ name: `${name}-${index}`,
5597
+ inline,
5598
+ settled,
5599
+ onSelect: onSelect ? (v) => onSelect(v, index) : void 0,
5600
+ onTypeInstead,
5601
+ typeInsteadLabel
5520
5602
  },
5521
- o.value
5522
- )) }) }) }) : null),
5603
+ index
5604
+ )),
5523
5605
  footnote != null ? /* @__PURE__ */ jsxRuntime.jsx(ClarifyFootnote, { children: footnote }) : null,
5524
5606
  actions ? /* @__PURE__ */ jsxRuntime.jsx(ClarifyActions, { align: actionsAlign, children: actions }) : null
5525
- ] })
5607
+ ] }) : null
5526
5608
  ]
5527
5609
  }
5528
5610
  );
5529
5611
  }
5530
5612
  );
5531
5613
  ClarifyCard.displayName = "ClarifyCard";
5614
+ function summaryOf(asks) {
5615
+ if (asks.length > 1) return `${asks.length} questions`;
5616
+ const ask = asks[0];
5617
+ if (!ask) return null;
5618
+ return ask.options?.find((o) => o.value === ask.value)?.label ?? ask.answer ?? null;
5619
+ }
5620
+ var TYPED = "\0typed";
5621
+ function Ask({
5622
+ ask,
5623
+ name,
5624
+ inline,
5625
+ settled,
5626
+ onSelect,
5627
+ onTypeInstead,
5628
+ typeInsteadLabel
5629
+ }) {
5630
+ const options = ask.options ?? [];
5631
+ const picked = options.some((o) => o.value === ask.value);
5632
+ const typed = settled && !picked && ask.answer != null;
5633
+ const row = (checked) => cn(inline && "border-transparent", settled && !checked && "opacity-60");
5634
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
5635
+ ask.question != null ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn(inline && "font-medium"), children: ask.question }) : null,
5636
+ options.length > 0 || typed || !settled && onTypeInstead ? /* @__PURE__ */ jsxRuntime.jsx(Questionnaire, { onSubmit: (e) => e.preventDefault(), children: /* @__PURE__ */ jsxRuntime.jsx(QuestionnaireItem, { name, children: /* @__PURE__ */ jsxRuntime.jsxs(QuestionnaireChoices, { children: [
5637
+ options.map((o) => {
5638
+ const checked = ask.value === o.value;
5639
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5640
+ QuestionnaireChoice,
5641
+ {
5642
+ value: o.value,
5643
+ detail: o.detail,
5644
+ disabled: o.disabled,
5645
+ readOnly: settled,
5646
+ checked: ask.value === void 0 ? void 0 : checked,
5647
+ onChange: () => onSelect?.(o.value),
5648
+ className: row(checked),
5649
+ children: [
5650
+ /* @__PURE__ */ jsxRuntime.jsx(QuestionnaireChoiceTitle, { children: o.label }),
5651
+ o.description != null ? /* @__PURE__ */ jsxRuntime.jsx(QuestionnaireChoiceDescription, { children: o.description }) : null
5652
+ ]
5653
+ },
5654
+ o.value
5655
+ );
5656
+ }),
5657
+ typed ? /* @__PURE__ */ jsxRuntime.jsx(QuestionnaireChoice, { value: TYPED, readOnly: true, checked: true, className: row(true), children: /* @__PURE__ */ jsxRuntime.jsx(QuestionnaireChoiceTitle, { children: ask.answer }) }) : null,
5658
+ !settled && onTypeInstead ? /* @__PURE__ */ jsxRuntime.jsx(
5659
+ QuestionnaireChoice,
5660
+ {
5661
+ value: TYPED,
5662
+ checked: false,
5663
+ onChange: onTypeInstead,
5664
+ className: row(false),
5665
+ children: /* @__PURE__ */ jsxRuntime.jsx(QuestionnaireChoiceTitle, { children: typeInsteadLabel ?? (options.length > 0 ? "Something else \u2014 let me type" : "Type your answer") })
5666
+ }
5667
+ ) : null
5668
+ ] }) }) }) : null
5669
+ ] });
5670
+ }
5532
5671
  var ContextBar = React25__namespace.forwardRef(
5533
5672
  ({ counters, hint, className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
5534
5673
  "div",
@@ -9285,7 +9424,9 @@ function useTour(options) {
9285
9424
  const lastIndex = Math.max(total - 1, 0);
9286
9425
  const clamped = Math.min(Math.max(current, 0), lastIndex);
9287
9426
  const at = React25__namespace.useRef(clamped);
9288
- at.current = clamped;
9427
+ React25__namespace.useLayoutEffect(() => {
9428
+ at.current = clamped;
9429
+ }, [clamped]);
9289
9430
  const move = React25__namespace.useCallback(
9290
9431
  (to) => {
9291
9432
  if (to === at.current) return;