@proteos/ui 0.60.0 → 0.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -401,6 +401,108 @@ function AttributeTypeIcon({
401
401
  }
402
402
  );
403
403
  }
404
+ var availabilityCalendarStyles = tailwindVariants.tv({
405
+ slots: {
406
+ root: "flex flex-col",
407
+ header: "flex items-center justify-between mb-3.5",
408
+ heading: "font-sans text-[15px] text-ink tracking-[-0.01em]",
409
+ headingYear: "ml-1 text-ink-3",
410
+ nav: "flex gap-1",
411
+ navButton: [
412
+ "size-7 rounded-md inline-flex items-center justify-center cursor-pointer outline-none",
413
+ "text-ink-3 hovered:text-ink hovered:bg-surface-3 pressed:bg-surface-4",
414
+ "data-[focus-visible]:shadow-[var(--shadow-focus)]",
415
+ "data-[disabled]:opacity-40 data-[disabled]:cursor-default data-[disabled]:hover:bg-transparent"
416
+ ],
417
+ grid: "w-full border-separate border-spacing-1 table-fixed -m-1",
418
+ weekday: "font-mono text-[11px] font-medium uppercase tracking-[0.08em] text-ink-3 pb-2 text-center",
419
+ cell: [
420
+ "relative aspect-square flex items-center justify-center cursor-pointer outline-none",
421
+ "font-sans text-[14px] font-medium rounded-sm border border-transparent",
422
+ "transition-[background-color,color,border-color] duration-150",
423
+ // Available (the default when neither unavailable nor disabled).
424
+ "bg-surface-2 text-ink",
425
+ "data-[hovered]:bg-surface-3 data-[hovered]:border-rule-strong",
426
+ "data-[focus-visible]:shadow-[var(--shadow-focus)]",
427
+ // Selected: the one ink fill on the page.
428
+ "data-[selected]:bg-ink data-[selected]:text-surface data-[selected]:border-ink",
429
+ "data-[selected]:data-[hovered]:bg-ink data-[selected]:data-[hovered]:border-ink",
430
+ // Unavailable / past: quiet text, no fill, no hover.
431
+ "data-[unavailable]:bg-transparent data-[unavailable]:text-ink-4 data-[unavailable]:font-normal data-[unavailable]:cursor-default",
432
+ "data-[unavailable]:data-[hovered]:bg-transparent data-[unavailable]:data-[hovered]:border-transparent",
433
+ "data-[disabled]:bg-transparent data-[disabled]:text-ink-4 data-[disabled]:font-normal data-[disabled]:cursor-default",
434
+ "data-[disabled]:data-[hovered]:bg-transparent data-[disabled]:data-[hovered]:border-transparent",
435
+ // Days of the neighbouring months are blank in a month-aligned grid.
436
+ "data-[outside-month]:invisible"
437
+ ],
438
+ dot: "absolute bottom-1.5 left-1/2 -translate-x-1/2 size-1 rounded-full bg-current",
439
+ cellSkeleton: "absolute inset-0 rounded-sm"
440
+ },
441
+ variants: {
442
+ isLoading: {
443
+ true: { cell: "bg-transparent cursor-default" },
444
+ false: {}
445
+ }
446
+ },
447
+ defaultVariants: { isLoading: false }
448
+ });
449
+ function AvailabilityCalendar({
450
+ value,
451
+ onChange,
452
+ isLoading = false,
453
+ className,
454
+ isDateUnavailable,
455
+ weekdayStyle = "short",
456
+ ...props
457
+ }) {
458
+ const styles4 = availabilityCalendarStyles({ isLoading });
459
+ const unavailable = isLoading ? () => true : isDateUnavailable;
460
+ return /* @__PURE__ */ jsxRuntime.jsxs(
461
+ reactAriaComponents.Calendar,
462
+ {
463
+ ...props,
464
+ value,
465
+ onChange: (next) => onChange(next),
466
+ ...unavailable ? { isDateUnavailable: unavailable } : {},
467
+ visibleDuration: { months: 1 },
468
+ className: chunkNWGG5WFL_cjs.cn(styles4.root(), className),
469
+ children: [
470
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: styles4.header(), children: [
471
+ /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Heading, { className: styles4.heading(), children: /* @__PURE__ */ jsxRuntime.jsx(MonthHeading, { yearClassName: styles4.headingYear() }) }),
472
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles4.nav(), children: [
473
+ /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Button, { slot: "previous", "aria-label": "Previous month", className: styles4.navButton(), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "size-4", "aria-hidden": "true" }) }),
474
+ /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Button, { slot: "next", "aria-label": "Next month", className: styles4.navButton(), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4", "aria-hidden": "true" }) })
475
+ ] })
476
+ ] }),
477
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-busy": isLoading, children: /* @__PURE__ */ jsxRuntime.jsxs(reactAriaComponents.CalendarGrid, { weekdayStyle, className: styles4.grid(), children: [
478
+ /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.CalendarGridHeader, { children: (day) => /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.CalendarHeaderCell, { className: styles4.weekday(), children: day }) }),
479
+ /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.CalendarGridBody, { children: (date) => /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.CalendarCell, { date, className: styles4.cell(), children: ({ formattedDate, isToday, isOutsideMonth }) => isLoading && !isOutsideMonth ? /* @__PURE__ */ jsxRuntime.jsx(chunkNWGG5WFL_cjs.Skeleton, { className: styles4.cellSkeleton() }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
480
+ formattedDate,
481
+ isToday && /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles4.dot(), "aria-hidden": "true" })
482
+ ] }) }) })
483
+ ] }) })
484
+ ]
485
+ }
486
+ );
487
+ }
488
+ function MonthHeading({ yearClassName }) {
489
+ const state = react.useContext(reactAriaComponents.CalendarStateContext);
490
+ if (!state) return null;
491
+ const start = state.visibleRange.start;
492
+ const date = start.toDate(state.timeZone);
493
+ const month = new Intl.DateTimeFormat(void 0, {
494
+ month: "long",
495
+ timeZone: state.timeZone
496
+ }).format(date);
497
+ const year = new Intl.DateTimeFormat(void 0, {
498
+ year: "numeric",
499
+ timeZone: state.timeZone
500
+ }).format(date);
501
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
502
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: month }),
503
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: yearClassName, children: year })
504
+ ] });
505
+ }
404
506
  var avatarStyles = tailwindVariants.tv({
405
507
  base: [
406
508
  "inline-grid place-items-center shrink-0 select-none overflow-hidden",
@@ -955,7 +1057,10 @@ function Tooltip({ className, offset = 6, ...props }) {
955
1057
  ...props,
956
1058
  offset,
957
1059
  className: (renderProps) => chunkNWGG5WFL_cjs.cn(
958
- "z-50 max-w-xs",
1060
+ // Above the floating chat / softphone windows (1100 / 1200) and their
1061
+ // full-screen workspace, like Select and Toast — a page inside the
1062
+ // window keeps its tooltips.
1063
+ "z-[1300] max-w-xs",
959
1064
  "rounded-md border border-rule bg-surface shadow-[var(--shadow-raised)]",
960
1065
  "px-2.5 py-1.5",
961
1066
  "font-mono text-[11.5px] text-ink-2",
@@ -2519,9 +2624,13 @@ function ConversationBriefPreview({
2519
2624
  contentClassName,
2520
2625
  renderContent,
2521
2626
  onEdit,
2522
- editor
2627
+ editor,
2628
+ aside,
2629
+ isMetaHidden = false,
2630
+ isSubjectHidden = false
2523
2631
  }) {
2524
2632
  const [pickedContactId, setPickedContactId] = react.useState("");
2633
+ const [isPickingTarget, setIsPickingTarget] = react.useState(false);
2525
2634
  const contact = contacts.find((entry) => entry.id === pickedContactId) ?? contacts[0] ?? null;
2526
2635
  const numbers = react.useMemo(() => contactPhoneNumbers(contact), [contact]);
2527
2636
  const [pickedNumber, setPickedNumber] = react.useState("");
@@ -2534,22 +2643,25 @@ function ConversationBriefPreview({
2534
2643
  onSelectionChangeRef.current?.(contact, phoneNumber);
2535
2644
  }, [contact, phoneNumber]);
2536
2645
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkNWGG5WFL_cjs.cn("flex flex-col gap-3", className), children: [
2537
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
2646
+ isSubjectHidden ? null : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
2538
2647
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[14px] font-semibold text-ink", children: brief.subject || names || "Prepared conversation" }),
2539
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-[10.5px] text-ink-4", children: [
2648
+ isMetaHidden ? null : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-[10.5px] text-ink-4", children: [
2540
2649
  brief.subject ? names : "",
2541
2650
  brief.channel ? `Channel ${brief.channel}` : "Any channel",
2542
2651
  brief.type_key ? `Type ${brief.type_key}` : "",
2543
2652
  brief.status === "prepared" ? "Prepared" : brief.status === "used" ? "Call held" : "Discarded"
2544
2653
  ].filter(Boolean).join(" \xB7 ") })
2545
2654
  ] }),
2546
- editor ?? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/brief-content relative", children: [
2655
+ editor ?? // A flex column of its own so a host that gives the box `flex-1`
2656
+ // (the call window) gets a scrolling box that fills the remaining
2657
+ // height; in an unconstrained host (a modal) it just wraps.
2658
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/brief-content relative flex min-h-0 flex-1 flex-col", children: [
2547
2659
  /* @__PURE__ */ jsxRuntime.jsx(
2548
2660
  "div",
2549
2661
  {
2550
2662
  className: chunkNWGG5WFL_cjs.cn(
2551
2663
  "rounded-md border border-rule-2 bg-surface-2/60 px-3 py-2.5",
2552
- "text-[13px] leading-relaxed text-ink-2 overflow-y-auto [scrollbar-width:thin]",
2664
+ "min-h-0 text-[13px] leading-relaxed text-ink-2 overflow-y-auto [scrollbar-width:thin]",
2553
2665
  renderContent ? null : "whitespace-pre-wrap",
2554
2666
  contentClassName
2555
2667
  ),
@@ -2573,28 +2685,121 @@ function ConversationBriefPreview({
2573
2685
  ) : null
2574
2686
  ] }),
2575
2687
  onCall ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 border-t border-rule-2 pt-3", children: [
2576
- contacts.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
2577
- Select,
2578
- {
2579
- "aria-label": "Who to call",
2580
- selectedKey: contact?.id ?? "",
2581
- onSelectionChange: (key) => {
2582
- setPickedContactId(String(key));
2583
- setPickedNumber("");
2584
- },
2585
- options: contacts.map((entry) => ({ id: entry.id, label: entry.name || entry.id }))
2586
- }
2587
- ) : null,
2588
- numbers.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
2589
- Select,
2688
+ /* @__PURE__ */ jsxRuntime.jsxs(
2689
+ "div",
2590
2690
  {
2591
- "aria-label": "Number to call",
2592
- selectedKey: phoneNumber,
2593
- onSelectionChange: (key) => setPickedNumber(String(key)),
2594
- options: numbers.map((number) => ({ id: number, label: number }))
2691
+ className: chunkNWGG5WFL_cjs.cn(
2692
+ "grid gap-3",
2693
+ aside ? "grid-cols-[minmax(0,1fr)_minmax(0,1fr)]" : "grid-cols-1"
2694
+ ),
2695
+ children: [
2696
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [
2697
+ isPickingTarget && (contacts.length > 1 || numbers.length > 1) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
2698
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-[10px] uppercase tracking-[0.08em] text-ink-4", children: "Calling" }),
2699
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-start gap-1.5", children: [
2700
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
2701
+ contacts.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
2702
+ Select,
2703
+ {
2704
+ "aria-label": "Who to call",
2705
+ size: "sm",
2706
+ autoFocus: true,
2707
+ selectedKey: contact?.id ?? "",
2708
+ onSelectionChange: (key) => {
2709
+ setPickedContactId(String(key));
2710
+ setPickedNumber("");
2711
+ const picked = contacts.find((entry) => entry.id === String(key));
2712
+ if (contactPhoneNumbers(picked).length <= 1) setIsPickingTarget(false);
2713
+ },
2714
+ options: contacts.map((entry) => ({
2715
+ id: entry.id,
2716
+ label: entry.name || entry.id
2717
+ }))
2718
+ }
2719
+ ) : null,
2720
+ numbers.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
2721
+ Select,
2722
+ {
2723
+ "aria-label": "Number to dial",
2724
+ size: "sm",
2725
+ ...contacts.length > 1 ? {} : { autoFocus: true },
2726
+ selectedKey: phoneNumber,
2727
+ onSelectionChange: (key) => {
2728
+ if (key !== null) setPickedNumber(String(key));
2729
+ setIsPickingTarget(false);
2730
+ },
2731
+ options: numbers.map((number) => ({ id: number, label: number }))
2732
+ }
2733
+ ) : null
2734
+ ] }),
2735
+ /* @__PURE__ */ jsxRuntime.jsx(
2736
+ chunkNWGG5WFL_cjs.Button,
2737
+ {
2738
+ variant: "ghost",
2739
+ size: "icon-sm",
2740
+ "aria-label": "Keep the current number",
2741
+ onPress: () => setIsPickingTarget(false),
2742
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { "aria-hidden": true })
2743
+ }
2744
+ )
2745
+ ] })
2746
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/dial flex min-w-0 flex-col gap-1", children: [
2747
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-[10px] uppercase tracking-[0.08em] text-ink-4", children: "Calling" }),
2748
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-9 min-w-0 items-center gap-2", children: [
2749
+ (() => {
2750
+ const hasChoice = contacts.length > 1 || numbers.length > 1;
2751
+ const valueText = phoneNumber ? contacts.length > 1 ? `${contact?.name || contact?.id} \xB7 ${phoneNumber}` : phoneNumber : contact ? `${contacts.length > 1 ? `${contact.name || contact.id} \xB7 ` : ""}no phone number on file` : "No contact to call.";
2752
+ const valueClassName = chunkNWGG5WFL_cjs.cn(
2753
+ "min-w-0 truncate text-[12px] tabular-nums",
2754
+ phoneNumber ? "text-ink-2" : "text-warning"
2755
+ );
2756
+ const icon = /* @__PURE__ */ jsxRuntime.jsx(
2757
+ lucideReact.Phone,
2758
+ {
2759
+ className: chunkNWGG5WFL_cjs.cn(
2760
+ "size-3 shrink-0",
2761
+ phoneNumber ? "text-ink-4" : "text-warning"
2762
+ ),
2763
+ "aria-hidden": true
2764
+ }
2765
+ );
2766
+ return hasChoice ? /* @__PURE__ */ jsxRuntime.jsxs(
2767
+ reactAriaComponents.Button,
2768
+ {
2769
+ className: chunkNWGG5WFL_cjs.cn(
2770
+ "flex min-w-0 cursor-pointer items-center gap-2 rounded-sm text-left outline-none",
2771
+ "hover:text-ink focus-visible:shadow-[var(--shadow-focus)]"
2772
+ ),
2773
+ onPress: () => setIsPickingTarget(true),
2774
+ children: [
2775
+ icon,
2776
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: valueClassName, title: phoneNumber, children: valueText })
2777
+ ]
2778
+ }
2779
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2780
+ icon,
2781
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: valueClassName, title: phoneNumber, children: valueText })
2782
+ ] });
2783
+ })(),
2784
+ contacts.length > 1 || numbers.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
2785
+ chunkNWGG5WFL_cjs.Button,
2786
+ {
2787
+ variant: "ghost",
2788
+ size: "icon-sm",
2789
+ "aria-label": "Change the number to dial",
2790
+ className: "opacity-0 transition-opacity group-hover/dial:opacity-100 focus-visible:opacity-100",
2791
+ onPress: () => setIsPickingTarget(true),
2792
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { "aria-hidden": true })
2793
+ }
2794
+ ) : null
2795
+ ] })
2796
+ ] }),
2797
+ controls
2798
+ ] }),
2799
+ aside ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 min-w-0", children: aside }) : null
2800
+ ]
2595
2801
  }
2596
- ) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-[12px] text-ink-3", children: phoneNumber || (contact ? "This contact has no phone number on file." : "No contact to call.") }),
2597
- controls,
2802
+ ),
2598
2803
  callDisabledReason ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[12px] text-warning", children: callDisabledReason }) : null,
2599
2804
  isCallButtonHidden ? null : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
2600
2805
  chunkNWGG5WFL_cjs.Button,
@@ -3903,6 +4108,11 @@ function DataTable({
3903
4108
  {
3904
4109
  ref: listRef,
3905
4110
  role: "presentation",
4111
+ "aria-busy": query.isPlaceholderData ? true : void 0,
4112
+ className: chunkNWGG5WFL_cjs.cn(
4113
+ "transition-opacity duration-150 motion-reduce:transition-none",
4114
+ query.isPlaceholderData && "opacity-50"
4115
+ ),
3906
4116
  style: { height: totalSize, position: "relative", width: "100%" },
3907
4117
  children: virtualItems.map((vRow) => {
3908
4118
  const item = listItems[vRow.index];
@@ -4089,7 +4299,7 @@ function CalendarGlyph() {
4089
4299
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5.5 2V5M10.5 2V5", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" })
4090
4300
  ] });
4091
4301
  }
4092
- function ChevronLeft() {
4302
+ function ChevronLeft2() {
4093
4303
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": true, viewBox: "0 0 12 12", className: "size-3", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
4094
4304
  "path",
4095
4305
  {
@@ -4101,7 +4311,7 @@ function ChevronLeft() {
4101
4311
  }
4102
4312
  ) });
4103
4313
  }
4104
- function ChevronRight() {
4314
+ function ChevronRight2() {
4105
4315
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { "aria-hidden": true, viewBox: "0 0 12 12", className: "size-3", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
4106
4316
  "path",
4107
4317
  {
@@ -4126,7 +4336,7 @@ function CalendarSurface() {
4126
4336
  "text-ink-3 hover:text-ink hover:bg-surface-2 cursor-pointer outline-none",
4127
4337
  "focus-visible:shadow-[var(--shadow-focus)]"
4128
4338
  ),
4129
- children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft, {})
4339
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft2, {})
4130
4340
  }
4131
4341
  ),
4132
4342
  /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Heading, { className: "font-sans font-medium text-[14px] text-ink tracking-[-0.01em]" }),
@@ -4140,7 +4350,7 @@ function CalendarSurface() {
4140
4350
  "text-ink-3 hover:text-ink hover:bg-surface-2 cursor-pointer outline-none",
4141
4351
  "focus-visible:shadow-[var(--shadow-focus)]"
4142
4352
  ),
4143
- children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight, {})
4353
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight2, {})
4144
4354
  }
4145
4355
  )
4146
4356
  ] }),
@@ -8538,6 +8748,81 @@ function Separator({
8538
8748
  }
8539
8749
  );
8540
8750
  }
8751
+ var stepperStyles = tailwindVariants.tv({
8752
+ slots: {
8753
+ root: "flex min-w-0 flex-wrap items-center gap-y-2 m-0 list-none p-0",
8754
+ item: "flex items-center",
8755
+ trigger: [
8756
+ "inline-flex items-center gap-[7px] rounded-sm border-0 bg-transparent p-0",
8757
+ "cursor-pointer select-none outline-none",
8758
+ "transition-colors duration-150",
8759
+ "data-[focus-visible]:shadow-[var(--shadow-focus)]",
8760
+ "data-[disabled]:cursor-default"
8761
+ ],
8762
+ marker: [
8763
+ "grid size-[18px] shrink-0 place-items-center rounded-pill border-[1.5px]",
8764
+ "font-mono text-[10px] font-medium leading-none",
8765
+ "transition-[background-color,border-color,color] duration-150",
8766
+ "[&_svg]:size-[11px]"
8767
+ ],
8768
+ label: "whitespace-nowrap text-[13px]",
8769
+ connector: "mx-2.5 h-px w-6 shrink-0 bg-rule"
8770
+ },
8771
+ variants: {
8772
+ orientation: {
8773
+ horizontal: {},
8774
+ vertical: {
8775
+ root: "flex-col flex-nowrap items-stretch gap-y-0",
8776
+ item: "flex-col items-start",
8777
+ // Centered under the 18px marker (9px in, minus half the line).
8778
+ connector: "mx-0 my-1 ml-[8.5px] h-4 w-px"
8779
+ }
8780
+ },
8781
+ state: {
8782
+ completed: {
8783
+ marker: "border-accent bg-accent text-surface",
8784
+ label: "text-ink-2 group-data-[hovered]:text-ink"
8785
+ },
8786
+ current: {
8787
+ marker: "border-accent bg-accent text-surface",
8788
+ label: "font-medium text-accent"
8789
+ },
8790
+ upcoming: {
8791
+ marker: "border-rule-strong bg-transparent text-ink-3",
8792
+ label: "text-ink-3 group-data-[hovered]:text-ink"
8793
+ }
8794
+ },
8795
+ isSelected: {
8796
+ true: { label: "underline decoration-accent/40 underline-offset-4" },
8797
+ false: {}
8798
+ }
8799
+ },
8800
+ defaultVariants: { orientation: "horizontal", state: "upcoming", isSelected: false }
8801
+ });
8802
+ function Stepper({ orientation, className, ...props }) {
8803
+ const { root } = stepperStyles({ orientation });
8804
+ return /* @__PURE__ */ jsxRuntime.jsx("ol", { ...props, className: chunkNWGG5WFL_cjs.cn(root(), className) });
8805
+ }
8806
+ function StepperStep({
8807
+ state,
8808
+ orientation,
8809
+ index,
8810
+ icon,
8811
+ isSelected = false,
8812
+ isLast = false,
8813
+ children,
8814
+ className,
8815
+ ...props
8816
+ }) {
8817
+ const styles4 = stepperStyles({ orientation, state, isSelected });
8818
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { "aria-current": state === "current" ? "step" : void 0, className: styles4.item(), children: [
8819
+ /* @__PURE__ */ jsxRuntime.jsxs(reactAriaComponents.Button, { ...props, className: chunkNWGG5WFL_cjs.cn("group", styles4.trigger(), className), children: [
8820
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: styles4.marker(), children: state === "completed" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { strokeWidth: 2.5 }) : icon ?? index + 1 }),
8821
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles4.label(), children })
8822
+ ] }),
8823
+ !isLast && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: styles4.connector() })
8824
+ ] });
8825
+ }
8541
8826
  function SuccessAnimation({ className }) {
8542
8827
  return /* @__PURE__ */ jsxRuntime.jsx(
8543
8828
  "div",
@@ -8821,6 +9106,100 @@ function TimeField({
8821
9106
  }
8822
9107
  );
8823
9108
  }
9109
+ var timeSlotListStyles = tailwindVariants.tv({
9110
+ slots: {
9111
+ group: "flex flex-col gap-2",
9112
+ row: "flex gap-2 min-w-0",
9113
+ item: [
9114
+ "flex-1 min-h-9 px-3 inline-flex items-center justify-center cursor-pointer outline-none",
9115
+ "font-sans text-[13.5px] font-medium text-ink rounded-md",
9116
+ "bg-surface border border-rule-strong",
9117
+ "transition-[background-color,color,border-color,box-shadow] duration-150",
9118
+ "hovered:bg-surface-2 hovered:border-ink-3",
9119
+ "pressed:bg-surface-3",
9120
+ "selected:border-ink selected:bg-surface selected:shadow-[inset_0_0_0_1px_var(--color-ink)]",
9121
+ "selected:hovered:bg-surface",
9122
+ "data-[focus-visible]:shadow-[var(--shadow-focus)]",
9123
+ "selected:data-[focus-visible]:shadow-[var(--shadow-focus),inset_0_0_0_1px_var(--color-ink)]",
9124
+ // Taken while you looked: dashed and quiet.
9125
+ "data-[disabled]:border-dashed data-[disabled]:border-rule data-[disabled]:text-ink-4",
9126
+ "data-[disabled]:cursor-default data-[disabled]:bg-transparent"
9127
+ ],
9128
+ confirm: "flex-1 min-h-9",
9129
+ empty: [
9130
+ "rounded-md border border-rule-2 bg-surface-2 px-4 py-5 text-center",
9131
+ "font-sans text-[13px] text-ink-3"
9132
+ ]
9133
+ },
9134
+ variants: {
9135
+ columns: {
9136
+ 1: { group: "grid grid-cols-1" },
9137
+ 2: { group: "grid grid-cols-2" }
9138
+ }
9139
+ },
9140
+ defaultVariants: { columns: 1 }
9141
+ });
9142
+ function TimeSlotList({
9143
+ items,
9144
+ selectedId,
9145
+ onSelect,
9146
+ confirmLabel,
9147
+ onConfirm,
9148
+ emptyMessage = "Nothing available.",
9149
+ columns,
9150
+ autoFocus = false,
9151
+ isDisabled = false,
9152
+ className,
9153
+ orientation = "vertical",
9154
+ ...props
9155
+ }) {
9156
+ const styles4 = timeSlotListStyles({ columns });
9157
+ if (items.length === 0) {
9158
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", className: chunkNWGG5WFL_cjs.cn(styles4.empty(), className), children: emptyMessage });
9159
+ }
9160
+ const focusTarget = selectedId ?? items.find((item) => !item.isDisabled)?.id ?? null;
9161
+ return /* @__PURE__ */ jsxRuntime.jsx(
9162
+ reactAriaComponents.ToggleButtonGroup,
9163
+ {
9164
+ ...props,
9165
+ orientation,
9166
+ selectionMode: "single",
9167
+ disallowEmptySelection: true,
9168
+ isDisabled,
9169
+ selectedKeys: selectedId === null ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([selectedId]),
9170
+ onSelectionChange: (keys) => {
9171
+ const [next] = Array.from(keys);
9172
+ if (next !== void 0) onSelect(next);
9173
+ },
9174
+ className: chunkNWGG5WFL_cjs.cn(styles4.group(), className),
9175
+ children: items.map((item) => {
9176
+ const isSelected = item.id === selectedId;
9177
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles4.row(), children: [
9178
+ /* @__PURE__ */ jsxRuntime.jsx(
9179
+ reactAriaComponents.ToggleButton,
9180
+ {
9181
+ id: item.id,
9182
+ ...item.isDisabled ? { isDisabled: true } : {},
9183
+ ...autoFocus && item.id === focusTarget ? { autoFocus: true } : {},
9184
+ className: styles4.item(),
9185
+ children: item.label
9186
+ }
9187
+ ),
9188
+ isSelected && confirmLabel && /* @__PURE__ */ jsxRuntime.jsx(
9189
+ chunkNWGG5WFL_cjs.Button,
9190
+ {
9191
+ variant: "cta",
9192
+ className: styles4.confirm(),
9193
+ isDisabled,
9194
+ onPress: () => onConfirm?.(item.id),
9195
+ children: confirmLabel
9196
+ }
9197
+ )
9198
+ ] }, String(item.id));
9199
+ })
9200
+ }
9201
+ );
9202
+ }
8824
9203
  function createToastQueue(options = {}) {
8825
9204
  return new reactAriaComponents.UNSTABLE_ToastQueue({ maxVisibleToasts: options.maxVisibleToasts ?? 3 });
8826
9205
  }
@@ -8916,6 +9295,7 @@ exports.AttachmentChip = AttachmentChip;
8916
9295
  exports.AttributePicker = AttributePicker;
8917
9296
  exports.AttributeType = AttributeType;
8918
9297
  exports.AttributeTypeIcon = AttributeTypeIcon;
9298
+ exports.AvailabilityCalendar = AvailabilityCalendar;
8919
9299
  exports.Avatar = Avatar;
8920
9300
  exports.AvatarGroup = AvatarGroup;
8921
9301
  exports.Badge = Badge;
@@ -9021,6 +9401,8 @@ exports.SELECTION_COLUMN_ID = SELECTION_COLUMN_ID;
9021
9401
  exports.SegmentedControl = SegmentedControl;
9022
9402
  exports.Select = Select;
9023
9403
  exports.Separator = Separator;
9404
+ exports.Stepper = Stepper;
9405
+ exports.StepperStep = StepperStep;
9024
9406
  exports.SubmenuTrigger = SubmenuTrigger;
9025
9407
  exports.SuccessAnimation = SuccessAnimation;
9026
9408
  exports.Switch = Switch;
@@ -9037,6 +9419,7 @@ exports.TagInput = TagInput;
9037
9419
  exports.TextShimmer = TextShimmer;
9038
9420
  exports.Textarea = Textarea;
9039
9421
  exports.TimeField = TimeField;
9422
+ exports.TimeSlotList = TimeSlotList;
9040
9423
  exports.ToastRegion = ToastRegion;
9041
9424
  exports.Tooltip = Tooltip;
9042
9425
  exports.TooltipTrigger = TooltipTrigger;
@@ -9048,6 +9431,7 @@ exports.addPendingLeaf = addPendingLeaf;
9048
9431
  exports.addSubgroup = addSubgroup;
9049
9432
  exports.arityOf = arityOf;
9050
9433
  exports.attachmentChipStyles = attachmentChipStyles;
9434
+ exports.availabilityCalendarStyles = availabilityCalendarStyles;
9051
9435
  exports.avatarGroupStyles = avatarGroupStyles;
9052
9436
  exports.avatarStyles = avatarStyles;
9053
9437
  exports.badgeGroupOverflowStyles = badgeGroupOverflowStyles;
@@ -9109,6 +9493,7 @@ exports.resolveLucideIcon = resolveLucideIcon;
9109
9493
  exports.resolveLucideIconName = resolveLucideIconName;
9110
9494
  exports.segmentedControlStyles = segmentedControlStyles;
9111
9495
  exports.setJoiner = setJoiner;
9496
+ exports.stepperStyles = stepperStyles;
9112
9497
  exports.subscribeDraftMessageOutcome = subscribeDraftMessageOutcome;
9113
9498
  exports.summaryFor = summaryFor;
9114
9499
  exports.tableCellStyles = tableCellStyles;
@@ -9116,6 +9501,7 @@ exports.tableHeaderCellStyles = tableHeaderCellStyles;
9116
9501
  exports.tabsStyles = tabsStyles;
9117
9502
  exports.terminalKindFor = terminalKindFor;
9118
9503
  exports.textShimmerStyles = textShimmerStyles;
9504
+ exports.timeSlotListStyles = timeSlotListStyles;
9119
9505
  exports.toastStyles = toastStyles;
9120
9506
  exports.updateLeaf = updateLeaf;
9121
9507
  exports.updateSubgroup = updateSubgroup;