@proteos/ui 0.61.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.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { cn, Button, Skeleton } from './chunk-NSE4VW3Z.js';
2
2
  export { Button, Skeleton, buttonStyles, cn, skeletonStyles } from './chunk-NSE4VW3Z.js';
3
- import { icons, Contact, Paperclip, BookText, Banknote, UsersRound, User, Link2, Braces, Brackets, ToggleLeft, CircleDot, Calendar, Hash, Type, File, FileImage, FileText, FileSpreadsheet, FileArchive, Loader2, X, Shapes, Search, Phone, AudioLines, Video, Mic, AtSign, MessagesSquare, Camera, Send, Linkedin, MessageCircle, Mail, Pipette, Pencil, ChevronDown, GripVertical, SendHorizontal, CircleX, Download, ChevronRight as ChevronRight$1, AlertCircle, Undo2, ArrowRight, CircleCheck, CircleAlert, Info } from 'lucide-react';
3
+ import { icons, Contact, Paperclip, BookText, Banknote, UsersRound, User, Link2, Braces, Brackets, ToggleLeft, CircleDot, Calendar, Hash, Type, File, FileImage, FileText, FileSpreadsheet, FileArchive, Loader2, X, ChevronLeft, ChevronRight, Shapes, Search, Phone, AudioLines, Video, Mic, AtSign, MessagesSquare, Camera, Send, Linkedin, MessageCircle, Mail, Pipette, Pencil, ChevronDown, GripVertical, SendHorizontal, CircleX, Download, AlertCircle, Undo2, ArrowRight, Check, CircleCheck, CircleAlert, Info } from 'lucide-react';
4
4
  import { tv } from 'tailwind-variants';
5
- import { Tabs as Tabs$1, TabPanel, Tab, TabList, MenuTrigger as MenuTrigger$1, SubmenuTrigger as SubmenuTrigger$1, DialogTrigger, Popover as Popover$1, Dialog, DropZone, Text, FileTrigger, Heading, Label, Input as Input$1, ListBox, ListBoxItem, TooltipTrigger as TooltipTrigger$1, Tooltip as Tooltip$1, Button as Button$1, Breadcrumbs as Breadcrumbs$1, Breadcrumb, Link, Checkbox as Checkbox$1, CheckboxGroup as CheckboxGroup$1, FieldError, TextField, ComboBox, ComboBoxStateContext, Select as Select$1, SelectValue, ModalOverlay, Modal as Modal$1, DatePicker as DatePicker$1, Group, DateInput, DateSegment, Menu as Menu$1, MenuItem as MenuItem$1, Disclosure, DisclosurePanel, ProgressBar as ProgressBar$1, RadioGroup as RadioGroup$1, Radio as Radio$1, Separator as Separator$1, Switch as Switch$1, TextArea, TimeField as TimeField$1, UNSTABLE_ToastQueue, UNSTABLE_ToastRegion, UNSTABLE_Toast, UNSTABLE_ToastContent, Calendar as Calendar$1, CalendarGrid, CalendarGridHeader, CalendarHeaderCell, CalendarGridBody, CalendarCell, DatePickerStateContext } from 'react-aria-components';
5
+ import { Tabs as Tabs$1, TabPanel, Tab, TabList, MenuTrigger as MenuTrigger$1, SubmenuTrigger as SubmenuTrigger$1, DialogTrigger, Popover as Popover$1, Dialog, DropZone, Text, FileTrigger, Heading, Calendar as Calendar$1, Button as Button$1, CalendarGrid, CalendarGridHeader, CalendarHeaderCell, CalendarGridBody, CalendarCell, CalendarStateContext, Label, Input as Input$1, ListBox, ListBoxItem, TooltipTrigger as TooltipTrigger$1, Tooltip as Tooltip$1, Breadcrumbs as Breadcrumbs$1, Breadcrumb, Link, Checkbox as Checkbox$1, CheckboxGroup as CheckboxGroup$1, FieldError, TextField, ComboBox, ComboBoxStateContext, Select as Select$1, SelectValue, ModalOverlay, Modal as Modal$1, DatePicker as DatePicker$1, Group, DateInput, DateSegment, Menu as Menu$1, MenuItem as MenuItem$1, Disclosure, DisclosurePanel, ProgressBar as ProgressBar$1, RadioGroup as RadioGroup$1, Radio as Radio$1, Separator as Separator$1, Switch as Switch$1, TextArea, TimeField as TimeField$1, ToggleButtonGroup, ToggleButton, UNSTABLE_ToastQueue, UNSTABLE_ToastRegion, UNSTABLE_Toast, UNSTABLE_ToastContent, DatePickerStateContext } from 'react-aria-components';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
- import { lazy, createContext, useState, useRef, useMemo, Children, isValidElement, useLayoutEffect, useEffect, useContext, useSyncExternalStore, useCallback, Suspense, useId, Fragment as Fragment$1 } from 'react';
7
+ import { lazy, createContext, useContext, useState, useRef, useMemo, Children, isValidElement, useLayoutEffect, useEffect, useSyncExternalStore, useCallback, Suspense, useId, Fragment as Fragment$1 } from 'react';
8
8
  import { formatAmount, parseAmount } from '@proteos/sdk';
9
9
  import { draggable, dropTargetForElements, monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
10
10
  import { extractClosestEdge, attachClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
@@ -400,6 +400,108 @@ function AttributeTypeIcon({
400
400
  }
401
401
  );
402
402
  }
403
+ var availabilityCalendarStyles = tv({
404
+ slots: {
405
+ root: "flex flex-col",
406
+ header: "flex items-center justify-between mb-3.5",
407
+ heading: "font-sans text-[15px] text-ink tracking-[-0.01em]",
408
+ headingYear: "ml-1 text-ink-3",
409
+ nav: "flex gap-1",
410
+ navButton: [
411
+ "size-7 rounded-md inline-flex items-center justify-center cursor-pointer outline-none",
412
+ "text-ink-3 hovered:text-ink hovered:bg-surface-3 pressed:bg-surface-4",
413
+ "data-[focus-visible]:shadow-[var(--shadow-focus)]",
414
+ "data-[disabled]:opacity-40 data-[disabled]:cursor-default data-[disabled]:hover:bg-transparent"
415
+ ],
416
+ grid: "w-full border-separate border-spacing-1 table-fixed -m-1",
417
+ weekday: "font-mono text-[11px] font-medium uppercase tracking-[0.08em] text-ink-3 pb-2 text-center",
418
+ cell: [
419
+ "relative aspect-square flex items-center justify-center cursor-pointer outline-none",
420
+ "font-sans text-[14px] font-medium rounded-sm border border-transparent",
421
+ "transition-[background-color,color,border-color] duration-150",
422
+ // Available (the default when neither unavailable nor disabled).
423
+ "bg-surface-2 text-ink",
424
+ "data-[hovered]:bg-surface-3 data-[hovered]:border-rule-strong",
425
+ "data-[focus-visible]:shadow-[var(--shadow-focus)]",
426
+ // Selected: the one ink fill on the page.
427
+ "data-[selected]:bg-ink data-[selected]:text-surface data-[selected]:border-ink",
428
+ "data-[selected]:data-[hovered]:bg-ink data-[selected]:data-[hovered]:border-ink",
429
+ // Unavailable / past: quiet text, no fill, no hover.
430
+ "data-[unavailable]:bg-transparent data-[unavailable]:text-ink-4 data-[unavailable]:font-normal data-[unavailable]:cursor-default",
431
+ "data-[unavailable]:data-[hovered]:bg-transparent data-[unavailable]:data-[hovered]:border-transparent",
432
+ "data-[disabled]:bg-transparent data-[disabled]:text-ink-4 data-[disabled]:font-normal data-[disabled]:cursor-default",
433
+ "data-[disabled]:data-[hovered]:bg-transparent data-[disabled]:data-[hovered]:border-transparent",
434
+ // Days of the neighbouring months are blank in a month-aligned grid.
435
+ "data-[outside-month]:invisible"
436
+ ],
437
+ dot: "absolute bottom-1.5 left-1/2 -translate-x-1/2 size-1 rounded-full bg-current",
438
+ cellSkeleton: "absolute inset-0 rounded-sm"
439
+ },
440
+ variants: {
441
+ isLoading: {
442
+ true: { cell: "bg-transparent cursor-default" },
443
+ false: {}
444
+ }
445
+ },
446
+ defaultVariants: { isLoading: false }
447
+ });
448
+ function AvailabilityCalendar({
449
+ value,
450
+ onChange,
451
+ isLoading = false,
452
+ className,
453
+ isDateUnavailable,
454
+ weekdayStyle = "short",
455
+ ...props
456
+ }) {
457
+ const styles4 = availabilityCalendarStyles({ isLoading });
458
+ const unavailable = isLoading ? () => true : isDateUnavailable;
459
+ return /* @__PURE__ */ jsxs(
460
+ Calendar$1,
461
+ {
462
+ ...props,
463
+ value,
464
+ onChange: (next) => onChange(next),
465
+ ...unavailable ? { isDateUnavailable: unavailable } : {},
466
+ visibleDuration: { months: 1 },
467
+ className: cn(styles4.root(), className),
468
+ children: [
469
+ /* @__PURE__ */ jsxs("header", { className: styles4.header(), children: [
470
+ /* @__PURE__ */ jsx(Heading, { className: styles4.heading(), children: /* @__PURE__ */ jsx(MonthHeading, { yearClassName: styles4.headingYear() }) }),
471
+ /* @__PURE__ */ jsxs("div", { className: styles4.nav(), children: [
472
+ /* @__PURE__ */ jsx(Button$1, { slot: "previous", "aria-label": "Previous month", className: styles4.navButton(), children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4", "aria-hidden": "true" }) }),
473
+ /* @__PURE__ */ jsx(Button$1, { slot: "next", "aria-label": "Next month", className: styles4.navButton(), children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4", "aria-hidden": "true" }) })
474
+ ] })
475
+ ] }),
476
+ /* @__PURE__ */ jsx("div", { "aria-busy": isLoading, children: /* @__PURE__ */ jsxs(CalendarGrid, { weekdayStyle, className: styles4.grid(), children: [
477
+ /* @__PURE__ */ jsx(CalendarGridHeader, { children: (day) => /* @__PURE__ */ jsx(CalendarHeaderCell, { className: styles4.weekday(), children: day }) }),
478
+ /* @__PURE__ */ jsx(CalendarGridBody, { children: (date) => /* @__PURE__ */ jsx(CalendarCell, { date, className: styles4.cell(), children: ({ formattedDate, isToday, isOutsideMonth }) => isLoading && !isOutsideMonth ? /* @__PURE__ */ jsx(Skeleton, { className: styles4.cellSkeleton() }) : /* @__PURE__ */ jsxs(Fragment, { children: [
479
+ formattedDate,
480
+ isToday && /* @__PURE__ */ jsx("span", { className: styles4.dot(), "aria-hidden": "true" })
481
+ ] }) }) })
482
+ ] }) })
483
+ ]
484
+ }
485
+ );
486
+ }
487
+ function MonthHeading({ yearClassName }) {
488
+ const state = useContext(CalendarStateContext);
489
+ if (!state) return null;
490
+ const start = state.visibleRange.start;
491
+ const date = start.toDate(state.timeZone);
492
+ const month = new Intl.DateTimeFormat(void 0, {
493
+ month: "long",
494
+ timeZone: state.timeZone
495
+ }).format(date);
496
+ const year = new Intl.DateTimeFormat(void 0, {
497
+ year: "numeric",
498
+ timeZone: state.timeZone
499
+ }).format(date);
500
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
501
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: month }),
502
+ /* @__PURE__ */ jsx("span", { className: yearClassName, children: year })
503
+ ] });
504
+ }
403
505
  var avatarStyles = tv({
404
506
  base: [
405
507
  "inline-grid place-items-center shrink-0 select-none overflow-hidden",
@@ -954,7 +1056,10 @@ function Tooltip({ className, offset = 6, ...props }) {
954
1056
  ...props,
955
1057
  offset,
956
1058
  className: (renderProps) => cn(
957
- "z-50 max-w-xs",
1059
+ // Above the floating chat / softphone windows (1100 / 1200) and their
1060
+ // full-screen workspace, like Select and Toast — a page inside the
1061
+ // window keeps its tooltips.
1062
+ "z-[1300] max-w-xs",
958
1063
  "rounded-md border border-rule bg-surface shadow-[var(--shadow-raised)]",
959
1064
  "px-2.5 py-1.5",
960
1065
  "font-mono text-[11.5px] text-ink-2",
@@ -2518,9 +2623,13 @@ function ConversationBriefPreview({
2518
2623
  contentClassName,
2519
2624
  renderContent,
2520
2625
  onEdit,
2521
- editor
2626
+ editor,
2627
+ aside,
2628
+ isMetaHidden = false,
2629
+ isSubjectHidden = false
2522
2630
  }) {
2523
2631
  const [pickedContactId, setPickedContactId] = useState("");
2632
+ const [isPickingTarget, setIsPickingTarget] = useState(false);
2524
2633
  const contact = contacts.find((entry) => entry.id === pickedContactId) ?? contacts[0] ?? null;
2525
2634
  const numbers = useMemo(() => contactPhoneNumbers(contact), [contact]);
2526
2635
  const [pickedNumber, setPickedNumber] = useState("");
@@ -2533,22 +2642,25 @@ function ConversationBriefPreview({
2533
2642
  onSelectionChangeRef.current?.(contact, phoneNumber);
2534
2643
  }, [contact, phoneNumber]);
2535
2644
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3", className), children: [
2536
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
2645
+ isSubjectHidden ? null : /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
2537
2646
  /* @__PURE__ */ jsx("p", { className: "truncate text-[14px] font-semibold text-ink", children: brief.subject || names || "Prepared conversation" }),
2538
- /* @__PURE__ */ jsx("p", { className: "font-mono text-[10.5px] text-ink-4", children: [
2647
+ isMetaHidden ? null : /* @__PURE__ */ jsx("p", { className: "font-mono text-[10.5px] text-ink-4", children: [
2539
2648
  brief.subject ? names : "",
2540
2649
  brief.channel ? `Channel ${brief.channel}` : "Any channel",
2541
2650
  brief.type_key ? `Type ${brief.type_key}` : "",
2542
2651
  brief.status === "prepared" ? "Prepared" : brief.status === "used" ? "Call held" : "Discarded"
2543
2652
  ].filter(Boolean).join(" \xB7 ") })
2544
2653
  ] }),
2545
- editor ?? /* @__PURE__ */ jsxs("div", { className: "group/brief-content relative", children: [
2654
+ editor ?? // A flex column of its own so a host that gives the box `flex-1`
2655
+ // (the call window) gets a scrolling box that fills the remaining
2656
+ // height; in an unconstrained host (a modal) it just wraps.
2657
+ /* @__PURE__ */ jsxs("div", { className: "group/brief-content relative flex min-h-0 flex-1 flex-col", children: [
2546
2658
  /* @__PURE__ */ jsx(
2547
2659
  "div",
2548
2660
  {
2549
2661
  className: cn(
2550
2662
  "rounded-md border border-rule-2 bg-surface-2/60 px-3 py-2.5",
2551
- "text-[13px] leading-relaxed text-ink-2 overflow-y-auto [scrollbar-width:thin]",
2663
+ "min-h-0 text-[13px] leading-relaxed text-ink-2 overflow-y-auto [scrollbar-width:thin]",
2552
2664
  renderContent ? null : "whitespace-pre-wrap",
2553
2665
  contentClassName
2554
2666
  ),
@@ -2572,28 +2684,121 @@ function ConversationBriefPreview({
2572
2684
  ) : null
2573
2685
  ] }),
2574
2686
  onCall ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-rule-2 pt-3", children: [
2575
- contacts.length > 1 ? /* @__PURE__ */ jsx(
2576
- Select,
2577
- {
2578
- "aria-label": "Who to call",
2579
- selectedKey: contact?.id ?? "",
2580
- onSelectionChange: (key) => {
2581
- setPickedContactId(String(key));
2582
- setPickedNumber("");
2583
- },
2584
- options: contacts.map((entry) => ({ id: entry.id, label: entry.name || entry.id }))
2585
- }
2586
- ) : null,
2587
- numbers.length > 1 ? /* @__PURE__ */ jsx(
2588
- Select,
2687
+ /* @__PURE__ */ jsxs(
2688
+ "div",
2589
2689
  {
2590
- "aria-label": "Number to call",
2591
- selectedKey: phoneNumber,
2592
- onSelectionChange: (key) => setPickedNumber(String(key)),
2593
- options: numbers.map((number) => ({ id: number, label: number }))
2690
+ className: cn(
2691
+ "grid gap-3",
2692
+ aside ? "grid-cols-[minmax(0,1fr)_minmax(0,1fr)]" : "grid-cols-1"
2693
+ ),
2694
+ children: [
2695
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [
2696
+ isPickingTarget && (contacts.length > 1 || numbers.length > 1) ? /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
2697
+ /* @__PURE__ */ jsx("p", { className: "font-mono text-[10px] uppercase tracking-[0.08em] text-ink-4", children: "Calling" }),
2698
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start gap-1.5", children: [
2699
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
2700
+ contacts.length > 1 ? /* @__PURE__ */ jsx(
2701
+ Select,
2702
+ {
2703
+ "aria-label": "Who to call",
2704
+ size: "sm",
2705
+ autoFocus: true,
2706
+ selectedKey: contact?.id ?? "",
2707
+ onSelectionChange: (key) => {
2708
+ setPickedContactId(String(key));
2709
+ setPickedNumber("");
2710
+ const picked = contacts.find((entry) => entry.id === String(key));
2711
+ if (contactPhoneNumbers(picked).length <= 1) setIsPickingTarget(false);
2712
+ },
2713
+ options: contacts.map((entry) => ({
2714
+ id: entry.id,
2715
+ label: entry.name || entry.id
2716
+ }))
2717
+ }
2718
+ ) : null,
2719
+ numbers.length > 1 ? /* @__PURE__ */ jsx(
2720
+ Select,
2721
+ {
2722
+ "aria-label": "Number to dial",
2723
+ size: "sm",
2724
+ ...contacts.length > 1 ? {} : { autoFocus: true },
2725
+ selectedKey: phoneNumber,
2726
+ onSelectionChange: (key) => {
2727
+ if (key !== null) setPickedNumber(String(key));
2728
+ setIsPickingTarget(false);
2729
+ },
2730
+ options: numbers.map((number) => ({ id: number, label: number }))
2731
+ }
2732
+ ) : null
2733
+ ] }),
2734
+ /* @__PURE__ */ jsx(
2735
+ Button,
2736
+ {
2737
+ variant: "ghost",
2738
+ size: "icon-sm",
2739
+ "aria-label": "Keep the current number",
2740
+ onPress: () => setIsPickingTarget(false),
2741
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": true })
2742
+ }
2743
+ )
2744
+ ] })
2745
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "group/dial flex min-w-0 flex-col gap-1", children: [
2746
+ /* @__PURE__ */ jsx("p", { className: "font-mono text-[10px] uppercase tracking-[0.08em] text-ink-4", children: "Calling" }),
2747
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-9 min-w-0 items-center gap-2", children: [
2748
+ (() => {
2749
+ const hasChoice = contacts.length > 1 || numbers.length > 1;
2750
+ 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.";
2751
+ const valueClassName = cn(
2752
+ "min-w-0 truncate text-[12px] tabular-nums",
2753
+ phoneNumber ? "text-ink-2" : "text-warning"
2754
+ );
2755
+ const icon = /* @__PURE__ */ jsx(
2756
+ Phone,
2757
+ {
2758
+ className: cn(
2759
+ "size-3 shrink-0",
2760
+ phoneNumber ? "text-ink-4" : "text-warning"
2761
+ ),
2762
+ "aria-hidden": true
2763
+ }
2764
+ );
2765
+ return hasChoice ? /* @__PURE__ */ jsxs(
2766
+ Button$1,
2767
+ {
2768
+ className: cn(
2769
+ "flex min-w-0 cursor-pointer items-center gap-2 rounded-sm text-left outline-none",
2770
+ "hover:text-ink focus-visible:shadow-[var(--shadow-focus)]"
2771
+ ),
2772
+ onPress: () => setIsPickingTarget(true),
2773
+ children: [
2774
+ icon,
2775
+ /* @__PURE__ */ jsx("span", { className: valueClassName, title: phoneNumber, children: valueText })
2776
+ ]
2777
+ }
2778
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2779
+ icon,
2780
+ /* @__PURE__ */ jsx("span", { className: valueClassName, title: phoneNumber, children: valueText })
2781
+ ] });
2782
+ })(),
2783
+ contacts.length > 1 || numbers.length > 1 ? /* @__PURE__ */ jsx(
2784
+ Button,
2785
+ {
2786
+ variant: "ghost",
2787
+ size: "icon-sm",
2788
+ "aria-label": "Change the number to dial",
2789
+ className: "opacity-0 transition-opacity group-hover/dial:opacity-100 focus-visible:opacity-100",
2790
+ onPress: () => setIsPickingTarget(true),
2791
+ children: /* @__PURE__ */ jsx(Pencil, { "aria-hidden": true })
2792
+ }
2793
+ ) : null
2794
+ ] })
2795
+ ] }),
2796
+ controls
2797
+ ] }),
2798
+ aside ? /* @__PURE__ */ jsx("div", { className: "min-h-0 min-w-0", children: aside }) : null
2799
+ ]
2594
2800
  }
2595
- ) : /* @__PURE__ */ 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.") }),
2596
- controls,
2801
+ ),
2597
2802
  callDisabledReason ? /* @__PURE__ */ jsx("p", { className: "text-[12px] text-warning", children: callDisabledReason }) : null,
2598
2803
  isCallButtonHidden ? null : /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs(
2599
2804
  Button,
@@ -3902,6 +4107,11 @@ function DataTable({
3902
4107
  {
3903
4108
  ref: listRef,
3904
4109
  role: "presentation",
4110
+ "aria-busy": query.isPlaceholderData ? true : void 0,
4111
+ className: cn(
4112
+ "transition-opacity duration-150 motion-reduce:transition-none",
4113
+ query.isPlaceholderData && "opacity-50"
4114
+ ),
3905
4115
  style: { height: totalSize, position: "relative", width: "100%" },
3906
4116
  children: virtualItems.map((vRow) => {
3907
4117
  const item = listItems[vRow.index];
@@ -4088,7 +4298,7 @@ function CalendarGlyph() {
4088
4298
  /* @__PURE__ */ jsx("path", { d: "M5.5 2V5M10.5 2V5", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" })
4089
4299
  ] });
4090
4300
  }
4091
- function ChevronLeft() {
4301
+ function ChevronLeft2() {
4092
4302
  return /* @__PURE__ */ jsx("svg", { "aria-hidden": true, viewBox: "0 0 12 12", className: "size-3", fill: "none", children: /* @__PURE__ */ jsx(
4093
4303
  "path",
4094
4304
  {
@@ -4100,7 +4310,7 @@ function ChevronLeft() {
4100
4310
  }
4101
4311
  ) });
4102
4312
  }
4103
- function ChevronRight() {
4313
+ function ChevronRight2() {
4104
4314
  return /* @__PURE__ */ jsx("svg", { "aria-hidden": true, viewBox: "0 0 12 12", className: "size-3", fill: "none", children: /* @__PURE__ */ jsx(
4105
4315
  "path",
4106
4316
  {
@@ -4125,7 +4335,7 @@ function CalendarSurface() {
4125
4335
  "text-ink-3 hover:text-ink hover:bg-surface-2 cursor-pointer outline-none",
4126
4336
  "focus-visible:shadow-[var(--shadow-focus)]"
4127
4337
  ),
4128
- children: /* @__PURE__ */ jsx(ChevronLeft, {})
4338
+ children: /* @__PURE__ */ jsx(ChevronLeft2, {})
4129
4339
  }
4130
4340
  ),
4131
4341
  /* @__PURE__ */ jsx(Heading, { className: "font-sans font-medium text-[14px] text-ink tracking-[-0.01em]" }),
@@ -4139,7 +4349,7 @@ function CalendarSurface() {
4139
4349
  "text-ink-3 hover:text-ink hover:bg-surface-2 cursor-pointer outline-none",
4140
4350
  "focus-visible:shadow-[var(--shadow-focus)]"
4141
4351
  ),
4142
- children: /* @__PURE__ */ jsx(ChevronRight, {})
4352
+ children: /* @__PURE__ */ jsx(ChevronRight2, {})
4143
4353
  }
4144
4354
  )
4145
4355
  ] }),
@@ -5952,7 +6162,7 @@ function MenuItem({ icon, hasSubmenu, children, className, ...props }) {
5952
6162
  children: [
5953
6163
  icon ? /* @__PURE__ */ jsx("span", { className: "flex shrink-0 items-center", children: icon }) : null,
5954
6164
  /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children }),
5955
- hasSubmenu ? /* @__PURE__ */ jsx(ChevronRight$1, { className: "ml-2 size-3 shrink-0 text-ink-4" }) : null
6165
+ hasSubmenu ? /* @__PURE__ */ jsx(ChevronRight, { className: "ml-2 size-3 shrink-0 text-ink-4" }) : null
5956
6166
  ]
5957
6167
  }
5958
6168
  );
@@ -8537,6 +8747,81 @@ function Separator({
8537
8747
  }
8538
8748
  );
8539
8749
  }
8750
+ var stepperStyles = tv({
8751
+ slots: {
8752
+ root: "flex min-w-0 flex-wrap items-center gap-y-2 m-0 list-none p-0",
8753
+ item: "flex items-center",
8754
+ trigger: [
8755
+ "inline-flex items-center gap-[7px] rounded-sm border-0 bg-transparent p-0",
8756
+ "cursor-pointer select-none outline-none",
8757
+ "transition-colors duration-150",
8758
+ "data-[focus-visible]:shadow-[var(--shadow-focus)]",
8759
+ "data-[disabled]:cursor-default"
8760
+ ],
8761
+ marker: [
8762
+ "grid size-[18px] shrink-0 place-items-center rounded-pill border-[1.5px]",
8763
+ "font-mono text-[10px] font-medium leading-none",
8764
+ "transition-[background-color,border-color,color] duration-150",
8765
+ "[&_svg]:size-[11px]"
8766
+ ],
8767
+ label: "whitespace-nowrap text-[13px]",
8768
+ connector: "mx-2.5 h-px w-6 shrink-0 bg-rule"
8769
+ },
8770
+ variants: {
8771
+ orientation: {
8772
+ horizontal: {},
8773
+ vertical: {
8774
+ root: "flex-col flex-nowrap items-stretch gap-y-0",
8775
+ item: "flex-col items-start",
8776
+ // Centered under the 18px marker (9px in, minus half the line).
8777
+ connector: "mx-0 my-1 ml-[8.5px] h-4 w-px"
8778
+ }
8779
+ },
8780
+ state: {
8781
+ completed: {
8782
+ marker: "border-accent bg-accent text-surface",
8783
+ label: "text-ink-2 group-data-[hovered]:text-ink"
8784
+ },
8785
+ current: {
8786
+ marker: "border-accent bg-accent text-surface",
8787
+ label: "font-medium text-accent"
8788
+ },
8789
+ upcoming: {
8790
+ marker: "border-rule-strong bg-transparent text-ink-3",
8791
+ label: "text-ink-3 group-data-[hovered]:text-ink"
8792
+ }
8793
+ },
8794
+ isSelected: {
8795
+ true: { label: "underline decoration-accent/40 underline-offset-4" },
8796
+ false: {}
8797
+ }
8798
+ },
8799
+ defaultVariants: { orientation: "horizontal", state: "upcoming", isSelected: false }
8800
+ });
8801
+ function Stepper({ orientation, className, ...props }) {
8802
+ const { root } = stepperStyles({ orientation });
8803
+ return /* @__PURE__ */ jsx("ol", { ...props, className: cn(root(), className) });
8804
+ }
8805
+ function StepperStep({
8806
+ state,
8807
+ orientation,
8808
+ index,
8809
+ icon,
8810
+ isSelected = false,
8811
+ isLast = false,
8812
+ children,
8813
+ className,
8814
+ ...props
8815
+ }) {
8816
+ const styles4 = stepperStyles({ orientation, state, isSelected });
8817
+ return /* @__PURE__ */ jsxs("li", { "aria-current": state === "current" ? "step" : void 0, className: styles4.item(), children: [
8818
+ /* @__PURE__ */ jsxs(Button$1, { ...props, className: cn("group", styles4.trigger(), className), children: [
8819
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: styles4.marker(), children: state === "completed" ? /* @__PURE__ */ jsx(Check, { strokeWidth: 2.5 }) : icon ?? index + 1 }),
8820
+ /* @__PURE__ */ jsx("span", { className: styles4.label(), children })
8821
+ ] }),
8822
+ !isLast && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: styles4.connector() })
8823
+ ] });
8824
+ }
8540
8825
  function SuccessAnimation({ className }) {
8541
8826
  return /* @__PURE__ */ jsx(
8542
8827
  "div",
@@ -8820,6 +9105,100 @@ function TimeField({
8820
9105
  }
8821
9106
  );
8822
9107
  }
9108
+ var timeSlotListStyles = tv({
9109
+ slots: {
9110
+ group: "flex flex-col gap-2",
9111
+ row: "flex gap-2 min-w-0",
9112
+ item: [
9113
+ "flex-1 min-h-9 px-3 inline-flex items-center justify-center cursor-pointer outline-none",
9114
+ "font-sans text-[13.5px] font-medium text-ink rounded-md",
9115
+ "bg-surface border border-rule-strong",
9116
+ "transition-[background-color,color,border-color,box-shadow] duration-150",
9117
+ "hovered:bg-surface-2 hovered:border-ink-3",
9118
+ "pressed:bg-surface-3",
9119
+ "selected:border-ink selected:bg-surface selected:shadow-[inset_0_0_0_1px_var(--color-ink)]",
9120
+ "selected:hovered:bg-surface",
9121
+ "data-[focus-visible]:shadow-[var(--shadow-focus)]",
9122
+ "selected:data-[focus-visible]:shadow-[var(--shadow-focus),inset_0_0_0_1px_var(--color-ink)]",
9123
+ // Taken while you looked: dashed and quiet.
9124
+ "data-[disabled]:border-dashed data-[disabled]:border-rule data-[disabled]:text-ink-4",
9125
+ "data-[disabled]:cursor-default data-[disabled]:bg-transparent"
9126
+ ],
9127
+ confirm: "flex-1 min-h-9",
9128
+ empty: [
9129
+ "rounded-md border border-rule-2 bg-surface-2 px-4 py-5 text-center",
9130
+ "font-sans text-[13px] text-ink-3"
9131
+ ]
9132
+ },
9133
+ variants: {
9134
+ columns: {
9135
+ 1: { group: "grid grid-cols-1" },
9136
+ 2: { group: "grid grid-cols-2" }
9137
+ }
9138
+ },
9139
+ defaultVariants: { columns: 1 }
9140
+ });
9141
+ function TimeSlotList({
9142
+ items,
9143
+ selectedId,
9144
+ onSelect,
9145
+ confirmLabel,
9146
+ onConfirm,
9147
+ emptyMessage = "Nothing available.",
9148
+ columns,
9149
+ autoFocus = false,
9150
+ isDisabled = false,
9151
+ className,
9152
+ orientation = "vertical",
9153
+ ...props
9154
+ }) {
9155
+ const styles4 = timeSlotListStyles({ columns });
9156
+ if (items.length === 0) {
9157
+ return /* @__PURE__ */ jsx("div", { role: "status", className: cn(styles4.empty(), className), children: emptyMessage });
9158
+ }
9159
+ const focusTarget = selectedId ?? items.find((item) => !item.isDisabled)?.id ?? null;
9160
+ return /* @__PURE__ */ jsx(
9161
+ ToggleButtonGroup,
9162
+ {
9163
+ ...props,
9164
+ orientation,
9165
+ selectionMode: "single",
9166
+ disallowEmptySelection: true,
9167
+ isDisabled,
9168
+ selectedKeys: selectedId === null ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([selectedId]),
9169
+ onSelectionChange: (keys) => {
9170
+ const [next] = Array.from(keys);
9171
+ if (next !== void 0) onSelect(next);
9172
+ },
9173
+ className: cn(styles4.group(), className),
9174
+ children: items.map((item) => {
9175
+ const isSelected = item.id === selectedId;
9176
+ return /* @__PURE__ */ jsxs("div", { className: styles4.row(), children: [
9177
+ /* @__PURE__ */ jsx(
9178
+ ToggleButton,
9179
+ {
9180
+ id: item.id,
9181
+ ...item.isDisabled ? { isDisabled: true } : {},
9182
+ ...autoFocus && item.id === focusTarget ? { autoFocus: true } : {},
9183
+ className: styles4.item(),
9184
+ children: item.label
9185
+ }
9186
+ ),
9187
+ isSelected && confirmLabel && /* @__PURE__ */ jsx(
9188
+ Button,
9189
+ {
9190
+ variant: "cta",
9191
+ className: styles4.confirm(),
9192
+ isDisabled,
9193
+ onPress: () => onConfirm?.(item.id),
9194
+ children: confirmLabel
9195
+ }
9196
+ )
9197
+ ] }, String(item.id));
9198
+ })
9199
+ }
9200
+ );
9201
+ }
8823
9202
  function createToastQueue(options = {}) {
8824
9203
  return new UNSTABLE_ToastQueue({ maxVisibleToasts: options.maxVisibleToasts ?? 3 });
8825
9204
  }
@@ -8889,6 +9268,6 @@ function ToastRegion({ queue, className }) {
8889
9268
  );
8890
9269
  }
8891
9270
 
8892
- export { ATTRIBUTE_TYPES, ATTRIBUTE_TYPE_ICONS, AttachmentChip, AttributePicker, AttributeType, AttributeTypeIcon, Avatar, AvatarGroup, Badge, BadgeAction, BadgeGroup, BadgeMultiSelect, BooleanCell, Breadcrumbs, COLUMN_DRAG_KIND, CONVERSATION_BRIEF_OUTCOME_LABEL, Card, CardBody, CardContent, CardEyebrow, CardFeatureTitle, CardFooter, CardHeader, CardTitle, ChannelIcon, Checkbox, CheckboxGroup, ChipValue, ColorInput, Combobox, Command, CommandHint, ConversationBriefCard, ConversationBriefPreview, ConversationBriefReview, CurrencyInput, DRAFT_OUTCOME_LABEL, DataTable, DataTableEmpty, DataTableError, DataTableSkeleton, DateCell, DatePicker, DateTimeCell, DateTimePicker, DraftMessageCard, DraftMessageComposer, DraftMessageReview, EmptyState, ErrorAnimation, FIELD_LABEL_SEPARATOR, FieldCaret, FileField, FileViewer, FileViewerFallbackCard, FilterRow, FilterValueInput, IconPicker, ImageAttachment, ImageLightbox, Input, Kbd, LinkCell, MAX_COMPOSER_ATTACHMENT_BYTES, Menu, MenuItem, MenuPopover, MenuTrigger, MessageComposer, Modal, ModalBody, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle, MultiSelect, NavGroup, NavItem, NavSection, OPERATORS, OperatorPicker, Orb, PROTECTED_COMBOS, Popover, PopoverContent, PopoverPanelBody, PopoverPanelFooter, PopoverPanelHeader, PressableCard, ProgressBar, ProgressRing, Radio, RadioGroup, RecipientSelect, RecordFilterBuilderPanel, RecordFilterButton, RecordFilterChips, RecordFilterEditor, RecordUpdate, RecordUpdateErrors, RecordUpdateFooter, RecordUpdateRow, RecordUpdateRows, RecordUpdateSummary, RenderChipItemProvider, RenderValueInputProvider, SELECTION_COLUMN_ID, SegmentedControl, Select, Separator, SubmenuTrigger, SuccessAnimation, Switch, Table, TableBody, TableCell, TableHeader, TableHeaderCell, TableHeaderSpacer, TableRow, TableScroller, Tabs, TagInput, TextShimmer, Textarea, TimeField, ToastRegion, Tooltip, TooltipTrigger, TruncateCell, __resetDraftMessageActions, __resetDraftMessageOutcomes, addLeaf as addFilterLeaf, addPendingLeaf, addSubgroup, arityOf, attachmentChipStyles, avatarGroupStyles, avatarStyles, badgeGroupOverflowStyles, badgeGroupStyles, badgeStyles, cardStyles2 as cardStyles, channelIcon, contactPhoneNumbers, conversationBriefCardStyles, conversationBriefOutcomeFor, countLeaves, createConversationBriefClient, createDraftMessageClient, createToastQueue, defaultValueFor, draftMessageCardStyles, draftMessageComposerStyles, draftOutcomeFor, emptyStateStyles, fieldControlStyles, fieldErrorStyles, fieldHintStyles, fieldLabelStyles, fileViewerFallbackCardStyles, fileViewerStyles, fitBadgeCount, formatFileSize, formatValue, getPlatform, iconForContentType, imageAttachmentStyles, imageLightboxStyles, isColumnDragData, isDialableConversationBrief, isDraftReviewOutcome, isEditableTarget, isPreviewableImageName, joinFieldLabel, makeActionsColumn, messageComposerStyles, namesOf, navItemStyles, normalizeHexColor, operatorById, operatorsForType, parseCombo, progressBarStyles, progressRingStyles, publishDraftMessageOutcome, rebaseRowOnFieldChange, rebaseRowOnOperatorChange, recordUpdateRowStyles, recordUpdateStyles, registerDraftMessageActions, removeLeaf, removeSubgroup, replaceLeaf, resolveLucideIcon, resolveLucideIconName, segmentedControlStyles, setJoiner, subscribeDraftMessageOutcome, summaryFor, tableCellStyles, tableHeaderCellStyles, tabsStyles, terminalKindFor, textShimmerStyles, toastStyles, updateLeaf, updateSubgroup, useActiveCommands, useAttributeTypeIcon, useCommand, useDiscoveryActive, useDraftMessageActions, useDraftMessageOutcome, useEscapeKey, useInfiniteScrollSentinel, useRenderChipItem, useRenderValueInput, useShowDetails, viewerKindForContentType, wrapLeafInGroup };
9271
+ export { ATTRIBUTE_TYPES, ATTRIBUTE_TYPE_ICONS, AttachmentChip, AttributePicker, AttributeType, AttributeTypeIcon, AvailabilityCalendar, Avatar, AvatarGroup, Badge, BadgeAction, BadgeGroup, BadgeMultiSelect, BooleanCell, Breadcrumbs, COLUMN_DRAG_KIND, CONVERSATION_BRIEF_OUTCOME_LABEL, Card, CardBody, CardContent, CardEyebrow, CardFeatureTitle, CardFooter, CardHeader, CardTitle, ChannelIcon, Checkbox, CheckboxGroup, ChipValue, ColorInput, Combobox, Command, CommandHint, ConversationBriefCard, ConversationBriefPreview, ConversationBriefReview, CurrencyInput, DRAFT_OUTCOME_LABEL, DataTable, DataTableEmpty, DataTableError, DataTableSkeleton, DateCell, DatePicker, DateTimeCell, DateTimePicker, DraftMessageCard, DraftMessageComposer, DraftMessageReview, EmptyState, ErrorAnimation, FIELD_LABEL_SEPARATOR, FieldCaret, FileField, FileViewer, FileViewerFallbackCard, FilterRow, FilterValueInput, IconPicker, ImageAttachment, ImageLightbox, Input, Kbd, LinkCell, MAX_COMPOSER_ATTACHMENT_BYTES, Menu, MenuItem, MenuPopover, MenuTrigger, MessageComposer, Modal, ModalBody, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle, MultiSelect, NavGroup, NavItem, NavSection, OPERATORS, OperatorPicker, Orb, PROTECTED_COMBOS, Popover, PopoverContent, PopoverPanelBody, PopoverPanelFooter, PopoverPanelHeader, PressableCard, ProgressBar, ProgressRing, Radio, RadioGroup, RecipientSelect, RecordFilterBuilderPanel, RecordFilterButton, RecordFilterChips, RecordFilterEditor, RecordUpdate, RecordUpdateErrors, RecordUpdateFooter, RecordUpdateRow, RecordUpdateRows, RecordUpdateSummary, RenderChipItemProvider, RenderValueInputProvider, SELECTION_COLUMN_ID, SegmentedControl, Select, Separator, Stepper, StepperStep, SubmenuTrigger, SuccessAnimation, Switch, Table, TableBody, TableCell, TableHeader, TableHeaderCell, TableHeaderSpacer, TableRow, TableScroller, Tabs, TagInput, TextShimmer, Textarea, TimeField, TimeSlotList, ToastRegion, Tooltip, TooltipTrigger, TruncateCell, __resetDraftMessageActions, __resetDraftMessageOutcomes, addLeaf as addFilterLeaf, addPendingLeaf, addSubgroup, arityOf, attachmentChipStyles, availabilityCalendarStyles, avatarGroupStyles, avatarStyles, badgeGroupOverflowStyles, badgeGroupStyles, badgeStyles, cardStyles2 as cardStyles, channelIcon, contactPhoneNumbers, conversationBriefCardStyles, conversationBriefOutcomeFor, countLeaves, createConversationBriefClient, createDraftMessageClient, createToastQueue, defaultValueFor, draftMessageCardStyles, draftMessageComposerStyles, draftOutcomeFor, emptyStateStyles, fieldControlStyles, fieldErrorStyles, fieldHintStyles, fieldLabelStyles, fileViewerFallbackCardStyles, fileViewerStyles, fitBadgeCount, formatFileSize, formatValue, getPlatform, iconForContentType, imageAttachmentStyles, imageLightboxStyles, isColumnDragData, isDialableConversationBrief, isDraftReviewOutcome, isEditableTarget, isPreviewableImageName, joinFieldLabel, makeActionsColumn, messageComposerStyles, namesOf, navItemStyles, normalizeHexColor, operatorById, operatorsForType, parseCombo, progressBarStyles, progressRingStyles, publishDraftMessageOutcome, rebaseRowOnFieldChange, rebaseRowOnOperatorChange, recordUpdateRowStyles, recordUpdateStyles, registerDraftMessageActions, removeLeaf, removeSubgroup, replaceLeaf, resolveLucideIcon, resolveLucideIconName, segmentedControlStyles, setJoiner, stepperStyles, subscribeDraftMessageOutcome, summaryFor, tableCellStyles, tableHeaderCellStyles, tabsStyles, terminalKindFor, textShimmerStyles, timeSlotListStyles, toastStyles, updateLeaf, updateSubgroup, useActiveCommands, useAttributeTypeIcon, useCommand, useDiscoveryActive, useDraftMessageActions, useDraftMessageOutcome, useEscapeKey, useInfiniteScrollSentinel, useRenderChipItem, useRenderValueInput, useShowDetails, viewerKindForContentType, wrapLeafInGroup };
8893
9272
  //# sourceMappingURL=index.js.map
8894
9273
  //# sourceMappingURL=index.js.map