@proteos/ui 0.57.1 → 0.58.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.
Files changed (53) hide show
  1. package/dist/index.cjs +552 -192
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +333 -22
  4. package/dist/index.d.ts +333 -22
  5. package/dist/index.js +540 -194
  6. package/dist/index.js.map +1 -1
  7. package/package.json +4 -4
  8. package/src/components/badge-multi-select/badge-multi-select.tsx +1 -1
  9. package/src/components/checkbox/checkbox-group.tsx +4 -1
  10. package/src/components/color-input/color-input.tsx +1 -1
  11. package/src/components/combobox/combobox.tsx +1 -1
  12. package/src/components/command/command-hint.tsx +1 -4
  13. package/src/components/command/command.stories.tsx +2 -2
  14. package/src/components/command/command.test.tsx +65 -3
  15. package/src/components/command/command.tsx +52 -7
  16. package/src/components/command/index.ts +16 -8
  17. package/src/components/currency-input/currency-input.tsx +1 -1
  18. package/src/components/date-picker/date-picker.tsx +1 -1
  19. package/src/components/date-time-picker/date-time-picker.tsx +1 -1
  20. package/src/components/field/field.tsx +6 -0
  21. package/src/components/icon-picker/icon-picker.tsx +1 -1
  22. package/src/components/input/input.tsx +1 -1
  23. package/src/components/multi-select/multi-select.tsx +1 -1
  24. package/src/components/progress-bar/progress-bar.stories.tsx +3 -1
  25. package/src/components/progress-bar/progress-bar.tsx +2 -0
  26. package/src/components/progress-ring/index.ts +2 -0
  27. package/src/components/progress-ring/progress-ring.stories.tsx +82 -0
  28. package/src/components/progress-ring/progress-ring.test.tsx +47 -0
  29. package/src/components/progress-ring/progress-ring.tsx +112 -0
  30. package/src/components/radio-group/radio-group.tsx +4 -1
  31. package/src/components/record-update/index.ts +17 -0
  32. package/src/components/record-update/record-update.stories.tsx +141 -0
  33. package/src/components/record-update/record-update.test.tsx +114 -0
  34. package/src/components/record-update/record-update.tsx +259 -0
  35. package/src/components/select/select.tsx +1 -1
  36. package/src/components/switch/switch.stories.tsx +22 -0
  37. package/src/components/switch/switch.test.tsx +6 -0
  38. package/src/components/switch/switch.tsx +40 -3
  39. package/src/components/tag-input/tag-input.tsx +1 -1
  40. package/src/components/text-shimmer/index.ts +2 -0
  41. package/src/components/text-shimmer/text-shimmer.stories.tsx +35 -0
  42. package/src/components/text-shimmer/text-shimmer.test.tsx +16 -0
  43. package/src/components/text-shimmer/text-shimmer.tsx +43 -0
  44. package/src/components/textarea/textarea.tsx +1 -1
  45. package/src/components/time-field/time-field.tsx +1 -1
  46. package/src/index.ts +3 -0
  47. package/src/lib/commands/index.ts +6 -2
  48. package/src/lib/commands/registry.test.ts +54 -1
  49. package/src/lib/commands/registry.ts +89 -4
  50. package/src/lib/commands/use-active-commands.test.tsx +56 -0
  51. package/src/lib/commands/use-active-commands.ts +16 -0
  52. package/src/lib/commands/use-command.ts +16 -5
  53. package/src/styles.css +14 -0
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
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, 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, 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';
4
4
  import { tv } from 'tailwind-variants';
5
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';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -646,7 +646,7 @@ function IconPicker({
646
646
  open(false);
647
647
  triggerRef.current?.focus();
648
648
  };
649
- return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-1.5", className), children: [
649
+ return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-1.5 content-start", className), children: [
650
650
  label ? /* @__PURE__ */ jsx(Label, { className: fieldLabelStyles, children: label }) : null,
651
651
  compact ? /* @__PURE__ */ jsx(
652
652
  "button",
@@ -1229,7 +1229,7 @@ function BadgeMultiSelect({
1229
1229
  setIsOpen(false);
1230
1230
  }
1231
1231
  };
1232
- return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-1.5", className), children: [
1232
+ return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-1.5 content-start", className), children: [
1233
1233
  label ? /* @__PURE__ */ jsx(Label, { className: fieldLabelStyles, children: label }) : null,
1234
1234
  /* @__PURE__ */ jsxs(
1235
1235
  "div",
@@ -1635,7 +1635,10 @@ function CheckboxGroup({
1635
1635
  CheckboxGroup$1,
1636
1636
  {
1637
1637
  ...props,
1638
- className: (renderProps) => cn("grid gap-2", typeof className === "function" ? className(renderProps) : className),
1638
+ className: (renderProps) => cn(
1639
+ "grid gap-2 content-start",
1640
+ typeof className === "function" ? className(renderProps) : className
1641
+ ),
1639
1642
  children: [
1640
1643
  label ? /* @__PURE__ */ jsx(Label, { className: fieldLabelStyles, children: label }) : null,
1641
1644
  /* @__PURE__ */ jsx("div", { className: "grid gap-3", children }),
@@ -1714,7 +1717,7 @@ function ColorInput({
1714
1717
  isInvalid: invalid,
1715
1718
  onBlur: settle,
1716
1719
  ...ariaLabel ? { "aria-label": ariaLabel } : {},
1717
- className: cn("grid grid-cols-1 gap-1.5", className),
1720
+ className: cn("grid grid-cols-1 gap-1.5 content-start", className),
1718
1721
  children: [
1719
1722
  label ? /* @__PURE__ */ jsx(Label, { className: fieldLabelStyles, children: label }) : null,
1720
1723
  /* @__PURE__ */ jsxs(
@@ -1810,7 +1813,7 @@ function Combobox({
1810
1813
  ...props,
1811
1814
  allowsEmptyCollection,
1812
1815
  className: (renderProps) => cn(
1813
- "grid grid-cols-1 gap-1.5",
1816
+ "grid grid-cols-1 gap-1.5 content-start",
1814
1817
  typeof className === "function" ? className(renderProps) : className
1815
1818
  ),
1816
1819
  children: [
@@ -1939,6 +1942,112 @@ function ComboboxItem(props) {
1939
1942
  );
1940
1943
  }
1941
1944
 
1945
+ // src/lib/commands/platform.ts
1946
+ var cached;
1947
+ function getPlatform() {
1948
+ if (cached !== void 0) return cached;
1949
+ cached = detect();
1950
+ return cached;
1951
+ }
1952
+ function detect() {
1953
+ if (typeof navigator === "undefined") return "other";
1954
+ const ua = navigator.userAgentData;
1955
+ if (ua?.platform) {
1956
+ return /mac/i.test(ua.platform) ? "mac" : "other";
1957
+ }
1958
+ const legacy = navigator.platform ?? "";
1959
+ return /mac/i.test(legacy) ? "mac" : "other";
1960
+ }
1961
+
1962
+ // src/lib/commands/discovery-store.ts
1963
+ var cmdHeld = false;
1964
+ var shiftHeld = false;
1965
+ var initialized = false;
1966
+ var listeners = /* @__PURE__ */ new Set();
1967
+ function getSnapshot() {
1968
+ return cmdHeld && shiftHeld;
1969
+ }
1970
+ function getServerSnapshot() {
1971
+ return false;
1972
+ }
1973
+ function emit() {
1974
+ for (const l of listeners) l();
1975
+ }
1976
+ function sync(cmdNow, shiftNow) {
1977
+ if (cmdNow !== cmdHeld || shiftNow !== shiftHeld) {
1978
+ cmdHeld = cmdNow;
1979
+ shiftHeld = shiftNow;
1980
+ emit();
1981
+ }
1982
+ }
1983
+ function onKeyDown(e) {
1984
+ const platform = getPlatform();
1985
+ const cmdFlag = platform === "mac" ? e.metaKey : e.ctrlKey;
1986
+ if (e.key === "Meta" || e.key === "Control") {
1987
+ sync(true, e.shiftKey);
1988
+ return;
1989
+ }
1990
+ if (e.key === "Shift") {
1991
+ sync(cmdFlag, true);
1992
+ return;
1993
+ }
1994
+ sync(cmdFlag, e.shiftKey);
1995
+ }
1996
+ function onKeyUp(e) {
1997
+ const platform = getPlatform();
1998
+ const cmdFlag = platform === "mac" ? e.metaKey : e.ctrlKey;
1999
+ if (e.key === "Meta" || e.key === "Control") {
2000
+ sync(false, e.shiftKey);
2001
+ return;
2002
+ }
2003
+ if (e.key === "Shift") {
2004
+ sync(cmdFlag, false);
2005
+ return;
2006
+ }
2007
+ sync(cmdFlag, e.shiftKey);
2008
+ }
2009
+ function onBlur() {
2010
+ sync(false, false);
2011
+ }
2012
+ function ensureInitialized() {
2013
+ if (initialized) return;
2014
+ if (typeof window === "undefined") return;
2015
+ window.addEventListener("keydown", onKeyDown, { capture: true });
2016
+ window.addEventListener("keyup", onKeyUp, { capture: true });
2017
+ window.addEventListener("blur", onBlur);
2018
+ initialized = true;
2019
+ }
2020
+ function subscribe(listener) {
2021
+ ensureInitialized();
2022
+ listeners.add(listener);
2023
+ return () => {
2024
+ listeners.delete(listener);
2025
+ };
2026
+ }
2027
+ function useDiscoveryActive() {
2028
+ return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2029
+ }
2030
+
2031
+ // src/lib/commands/match-event.ts
2032
+ function isEditableTarget(target) {
2033
+ if (!(target instanceof HTMLElement)) return false;
2034
+ const tag = target.tagName;
2035
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
2036
+ if (target.isContentEditable) return true;
2037
+ const attr = target.getAttribute("contenteditable");
2038
+ if (attr === "" || attr === "true" || attr === "plaintext-only") return true;
2039
+ return false;
2040
+ }
2041
+ function matches(event, combo) {
2042
+ const platform = getPlatform();
2043
+ const modPressed = platform === "mac" ? event.metaKey : event.ctrlKey;
2044
+ if (!modPressed) return false;
2045
+ if (combo.isLetter) {
2046
+ return event.code === `Key${combo.key.toUpperCase()}`;
2047
+ }
2048
+ return event.key.toLowerCase() === combo.key.toLowerCase();
2049
+ }
2050
+
1942
2051
  // src/lib/commands/parse-combo.ts
1943
2052
  var MOD_ALIASES = /* @__PURE__ */ new Set(["mod", "cmd", "meta"]);
1944
2053
  var FORBIDDEN_EXTRA_MODS = /* @__PURE__ */ new Set(["shift", "alt", "option"]);
@@ -1996,46 +2105,14 @@ function assertNotProtected(combo) {
1996
2105
  }
1997
2106
  }
1998
2107
 
1999
- // src/lib/commands/platform.ts
2000
- var cached;
2001
- function getPlatform() {
2002
- if (cached !== void 0) return cached;
2003
- cached = detect();
2004
- return cached;
2005
- }
2006
- function detect() {
2007
- if (typeof navigator === "undefined") return "other";
2008
- const ua = navigator.userAgentData;
2009
- if (ua?.platform) {
2010
- return /mac/i.test(ua.platform) ? "mac" : "other";
2011
- }
2012
- const legacy = navigator.platform ?? "";
2013
- return /mac/i.test(legacy) ? "mac" : "other";
2014
- }
2015
-
2016
- // src/lib/commands/match-event.ts
2017
- function isEditableTarget(target) {
2018
- if (!(target instanceof HTMLElement)) return false;
2019
- const tag = target.tagName;
2020
- if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
2021
- if (target.isContentEditable) return true;
2022
- const attr = target.getAttribute("contenteditable");
2023
- if (attr === "" || attr === "true" || attr === "plaintext-only") return true;
2024
- return false;
2025
- }
2026
- function matches(event, combo) {
2027
- const platform = getPlatform();
2028
- const modPressed = platform === "mac" ? event.metaKey : event.ctrlKey;
2029
- if (!modPressed) return false;
2030
- if (combo.isLetter) {
2031
- return event.code === `Key${combo.key.toUpperCase()}`;
2032
- }
2033
- return event.key.toLowerCase() === combo.key.toLowerCase();
2034
- }
2035
-
2036
2108
  // src/lib/commands/registry.ts
2037
2109
  var stacks = /* @__PURE__ */ new Map();
2110
+ var listeners2 = /* @__PURE__ */ new Set();
2038
2111
  var listenerInstalled = false;
2112
+ var version = 0;
2113
+ var snapshotVersion = -1;
2114
+ var snapshot = [];
2115
+ var EMPTY = [];
2039
2116
  function onWindowKeyDown(event) {
2040
2117
  for (const entries of stacks.values()) {
2041
2118
  const top = entries[entries.length - 1];
@@ -2054,101 +2131,123 @@ function ensureListener() {
2054
2131
  window.addEventListener("keydown", onWindowKeyDown, { capture: true });
2055
2132
  listenerInstalled = true;
2056
2133
  }
2057
- function register(combo, handler) {
2134
+ function emit2() {
2135
+ version++;
2136
+ for (const listener of listeners2) listener();
2137
+ }
2138
+ function register(combo, handler, options) {
2058
2139
  ensureListener();
2059
2140
  const list = stacks.get(combo.raw) ?? [];
2060
- const entry = { combo, handler };
2141
+ const entry = {
2142
+ combo,
2143
+ handler,
2144
+ ...options?.label !== void 0 ? { label: options.label } : {}
2145
+ };
2061
2146
  list.push(entry);
2062
2147
  stacks.set(combo.raw, list);
2148
+ emit2();
2063
2149
  return () => {
2064
2150
  const current = stacks.get(combo.raw);
2065
2151
  if (!current) return;
2066
2152
  const idx = current.lastIndexOf(entry);
2067
2153
  if (idx >= 0) current.splice(idx, 1);
2068
2154
  if (current.length === 0) stacks.delete(combo.raw);
2155
+ emit2();
2156
+ };
2157
+ }
2158
+ function subscribe2(listener) {
2159
+ listeners2.add(listener);
2160
+ return () => {
2161
+ listeners2.delete(listener);
2069
2162
  };
2070
2163
  }
2164
+ function resolveLabel(label) {
2165
+ const value = typeof label === "function" ? label() : label;
2166
+ const trimmed = value?.trim();
2167
+ return trimmed ? trimmed : void 0;
2168
+ }
2169
+ function invokeEntry(entry) {
2170
+ entry.handler(new KeyboardEvent("keydown", { key: entry.combo.key, cancelable: true }));
2171
+ }
2172
+ function listActiveCommands() {
2173
+ const out = [];
2174
+ for (const entries of stacks.values()) {
2175
+ const top = entries[entries.length - 1];
2176
+ if (!top) continue;
2177
+ const label = resolveLabel(top.label);
2178
+ if (!label) continue;
2179
+ out.push({ combo: top.combo, label, invoke: () => invokeEntry(top) });
2180
+ }
2181
+ return out;
2182
+ }
2183
+ function getActiveCommandsSnapshot() {
2184
+ if (snapshotVersion !== version) {
2185
+ snapshot = listActiveCommands();
2186
+ snapshotVersion = version;
2187
+ }
2188
+ return snapshot;
2189
+ }
2190
+ function getActiveCommandsServerSnapshot() {
2191
+ return EMPTY;
2192
+ }
2071
2193
 
2072
- // src/lib/commands/use-command.ts
2194
+ // src/lib/commands/use-active-commands.ts
2195
+ function useActiveCommands() {
2196
+ return useSyncExternalStore(subscribe2, getActiveCommandsSnapshot, getActiveCommandsServerSnapshot);
2197
+ }
2073
2198
  function useCommand(combo, handler, options) {
2074
2199
  const enabled = options?.enabled ?? true;
2075
2200
  const handlerRef = useRef(handler);
2201
+ const labelRef = useRef(options?.label);
2076
2202
  useEffect(() => {
2077
2203
  handlerRef.current = handler;
2204
+ labelRef.current = options?.label;
2078
2205
  });
2079
2206
  useEffect(() => {
2080
2207
  if (!enabled) return void 0;
2081
2208
  const parsed = parseCombo(combo);
2082
2209
  assertNotProtected(parsed);
2083
- return register(parsed, (event) => handlerRef.current(event));
2210
+ return register(parsed, (event) => handlerRef.current(event), {
2211
+ label: () => {
2212
+ const label = labelRef.current;
2213
+ return typeof label === "function" ? label() : label;
2214
+ }
2215
+ });
2084
2216
  }, [combo, enabled]);
2085
2217
  }
2086
- var cmdHeld = false;
2087
- var shiftHeld = false;
2088
- var initialized = false;
2089
- var listeners = /* @__PURE__ */ new Set();
2090
- function getSnapshot() {
2091
- return cmdHeld && shiftHeld;
2092
- }
2093
- function getServerSnapshot() {
2094
- return false;
2095
- }
2096
- function emit() {
2097
- for (const l of listeners) l();
2098
- }
2099
- function sync(cmdNow, shiftNow) {
2100
- if (cmdNow !== cmdHeld || shiftNow !== shiftHeld) {
2101
- cmdHeld = cmdNow;
2102
- shiftHeld = shiftNow;
2103
- emit();
2104
- }
2105
- }
2106
- function onKeyDown(e) {
2107
- const platform = getPlatform();
2108
- const cmdFlag = platform === "mac" ? e.metaKey : e.ctrlKey;
2109
- if (e.key === "Meta" || e.key === "Control") {
2110
- sync(true, e.shiftKey);
2111
- return;
2112
- }
2113
- if (e.key === "Shift") {
2114
- sync(cmdFlag, true);
2115
- return;
2116
- }
2117
- sync(cmdFlag, e.shiftKey);
2118
- }
2119
- function onKeyUp(e) {
2120
- const platform = getPlatform();
2121
- const cmdFlag = platform === "mac" ? e.metaKey : e.ctrlKey;
2122
- if (e.key === "Meta" || e.key === "Control") {
2123
- sync(false, e.shiftKey);
2124
- return;
2125
- }
2126
- if (e.key === "Shift") {
2127
- sync(cmdFlag, false);
2128
- return;
2129
- }
2130
- sync(cmdFlag, e.shiftKey);
2131
- }
2132
- function onBlur() {
2133
- sync(false, false);
2218
+ var stack = [];
2219
+ var listenerInstalled2 = false;
2220
+ function onWindowKeyDown2(event) {
2221
+ if (event.key !== "Escape") return;
2222
+ if (isEditableTarget(event.target)) return;
2223
+ const top = stack[stack.length - 1];
2224
+ if (!top) return;
2225
+ top.handler(event);
2134
2226
  }
2135
- function ensureInitialized() {
2136
- if (initialized) return;
2227
+ function ensureListener2() {
2228
+ if (listenerInstalled2) return;
2137
2229
  if (typeof window === "undefined") return;
2138
- window.addEventListener("keydown", onKeyDown, { capture: true });
2139
- window.addEventListener("keyup", onKeyUp, { capture: true });
2140
- window.addEventListener("blur", onBlur);
2141
- initialized = true;
2142
- }
2143
- function subscribe(listener) {
2144
- ensureInitialized();
2145
- listeners.add(listener);
2146
- return () => {
2147
- listeners.delete(listener);
2148
- };
2230
+ window.addEventListener("keydown", onWindowKeyDown2, { capture: true });
2231
+ listenerInstalled2 = true;
2149
2232
  }
2150
- function useDiscoveryActive() {
2151
- return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2233
+ function useEscapeKey(handler, options) {
2234
+ const enabled = options?.enabled ?? true;
2235
+ const handlerRef = useRef(handler);
2236
+ useEffect(() => {
2237
+ handlerRef.current = handler;
2238
+ });
2239
+ useEffect(() => {
2240
+ if (!enabled) return void 0;
2241
+ ensureListener2();
2242
+ const entry = {
2243
+ handler: (event) => handlerRef.current(event)
2244
+ };
2245
+ stack.push(entry);
2246
+ return () => {
2247
+ const idx = stack.lastIndexOf(entry);
2248
+ if (idx >= 0) stack.splice(idx, 1);
2249
+ };
2250
+ }, [enabled]);
2152
2251
  }
2153
2252
  function Kbd({ className, children, ...props }) {
2154
2253
  return /* @__PURE__ */ jsx(
@@ -2175,10 +2274,7 @@ function CommandHint({ combo, tone = "subtle", className }) {
2175
2274
  return /* @__PURE__ */ jsx(
2176
2275
  Kbd,
2177
2276
  {
2178
- className: cn(
2179
- tone === "prominent" && "bg-ink text-surface border-transparent",
2180
- className
2181
- ),
2277
+ className: cn(tone === "prominent" && "bg-ink text-surface border-transparent", className),
2182
2278
  children: label
2183
2279
  }
2184
2280
  );
@@ -2187,15 +2283,21 @@ function prettifyKey(key) {
2187
2283
  if (key.length === 0) return key;
2188
2284
  return key[0].toUpperCase() + key.slice(1);
2189
2285
  }
2190
- function Command({ combo, target, className, children }) {
2286
+ function Command({ combo, target, className, label, children }) {
2191
2287
  const wrapperRef = useRef(null);
2192
2288
  const discoveryActive = useDiscoveryActive();
2193
- useCommand(combo, () => {
2289
+ const resolveTarget = () => {
2194
2290
  const root = wrapperRef.current;
2195
- if (!root) return;
2196
- const el = target ? root.querySelector(target) : root.firstElementChild;
2197
- el?.click();
2198
- });
2291
+ if (!root) return null;
2292
+ return target ? root.querySelector(target) : root.firstElementChild;
2293
+ };
2294
+ useCommand(
2295
+ combo,
2296
+ () => {
2297
+ resolveTarget()?.click();
2298
+ },
2299
+ { label: () => label ?? accessibleName(resolveTarget()) }
2300
+ );
2199
2301
  return /* @__PURE__ */ jsxs("div", { ref: wrapperRef, className: cn("relative inline-block", className), children: [
2200
2302
  children,
2201
2303
  discoveryActive ? /* @__PURE__ */ jsx(
@@ -2208,39 +2310,29 @@ function Command({ combo, target, className, children }) {
2208
2310
  ) : null
2209
2311
  ] });
2210
2312
  }
2211
- var stack = [];
2212
- var listenerInstalled2 = false;
2213
- function onWindowKeyDown2(event) {
2214
- if (event.key !== "Escape") return;
2215
- if (isEditableTarget(event.target)) return;
2216
- const top = stack[stack.length - 1];
2217
- if (!top) return;
2218
- top.handler(event);
2219
- }
2220
- function ensureListener2() {
2221
- if (listenerInstalled2) return;
2222
- if (typeof window === "undefined") return;
2223
- window.addEventListener("keydown", onWindowKeyDown2, { capture: true });
2224
- listenerInstalled2 = true;
2225
- }
2226
- function useEscapeKey(handler, options) {
2227
- const enabled = options?.enabled ?? true;
2228
- const handlerRef = useRef(handler);
2229
- useEffect(() => {
2230
- handlerRef.current = handler;
2231
- });
2232
- useEffect(() => {
2233
- if (!enabled) return void 0;
2234
- ensureListener2();
2235
- const entry = {
2236
- handler: (event) => handlerRef.current(event)
2237
- };
2238
- stack.push(entry);
2239
- return () => {
2240
- const idx = stack.lastIndexOf(entry);
2241
- if (idx >= 0) stack.splice(idx, 1);
2242
- };
2243
- }, [enabled]);
2313
+ function accessibleName(el) {
2314
+ if (!el) return void 0;
2315
+ const aria = el.getAttribute("aria-label")?.trim();
2316
+ if (aria) return aria;
2317
+ const pieces = [];
2318
+ const walk = (node) => {
2319
+ if (node.nodeType === Node.TEXT_NODE) {
2320
+ const text = node.textContent?.trim();
2321
+ if (text) pieces.push(text);
2322
+ return;
2323
+ }
2324
+ if (node instanceof Element) {
2325
+ if (node.getAttribute("aria-hidden") === "true") return;
2326
+ const own = node.getAttribute("aria-label")?.trim();
2327
+ if (own) {
2328
+ pieces.push(own);
2329
+ return;
2330
+ }
2331
+ }
2332
+ for (const child of node.childNodes) walk(child);
2333
+ };
2334
+ walk(el);
2335
+ return pieces.length > 0 ? pieces.join(" ") : void 0;
2244
2336
  }
2245
2337
  var conversationBriefCardStyles = tv({
2246
2338
  slots: {
@@ -2320,7 +2412,7 @@ function Select({
2320
2412
  {
2321
2413
  ...props,
2322
2414
  className: (renderProps) => cn(
2323
- "grid grid-cols-1 gap-1.5",
2415
+ "grid grid-cols-1 gap-1.5 content-start",
2324
2416
  typeof className === "function" ? className(renderProps) : className
2325
2417
  ),
2326
2418
  children: [
@@ -2760,7 +2852,7 @@ function CurrencyInput({
2760
2852
  useEffect(() => {
2761
2853
  if (!isEditing) setDraft(formatAmount(amount, locale, { grouped: true }));
2762
2854
  }, [amount, locale, isEditing]);
2763
- const emit2 = (nextAmount, nextCode) => {
2855
+ const emit3 = (nextAmount, nextCode) => {
2764
2856
  if (nextAmount === "" && nextCode === "") {
2765
2857
  onChange(null);
2766
2858
  return;
@@ -2770,7 +2862,7 @@ function CurrencyInput({
2770
2862
  const selectedSymbol = currencyOptions.find((option) => option.code === code)?.symbol ?? code;
2771
2863
  const styles4 = fieldControlStyles({ size, appearance, ...isInvalid ? { invalid: true } : {} });
2772
2864
  const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
2773
- return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-1.5", className), children: [
2865
+ return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-1.5 content-start", className), children: [
2774
2866
  /* @__PURE__ */ jsxs("div", { className: cn(styles4.box(), "flex items-center gap-1 pr-1", focusWithin), children: [
2775
2867
  /* @__PURE__ */ jsx(
2776
2868
  "input",
@@ -2786,7 +2878,7 @@ function CurrencyInput({
2786
2878
  value: draft,
2787
2879
  onChange: (event) => {
2788
2880
  setDraft(event.target.value);
2789
- emit2(parseAmount(event.target.value, locale), code);
2881
+ emit3(parseAmount(event.target.value, locale), code);
2790
2882
  },
2791
2883
  onFocus: () => {
2792
2884
  setIsEditing(true);
@@ -2796,7 +2888,7 @@ function CurrencyInput({
2796
2888
  setIsEditing(false);
2797
2889
  const canonical = parseAmount(draft, locale);
2798
2890
  setDraft(formatAmount(canonical, locale, { grouped: true }));
2799
- emit2(canonical, code);
2891
+ emit3(canonical, code);
2800
2892
  onBlur2?.();
2801
2893
  },
2802
2894
  readOnly: isReadOnly ?? false,
@@ -2810,7 +2902,7 @@ function CurrencyInput({
2810
2902
  {
2811
2903
  "aria-label": ariaLabel ? `${ariaLabel} currency` : "Currency",
2812
2904
  selectedKey: code === "" ? null : code,
2813
- onSelectionChange: (key) => emit2(amount, key == null ? "" : String(key)),
2905
+ onSelectionChange: (key) => emit3(amount, key == null ? "" : String(key)),
2814
2906
  isDisabled: isReadOnly ?? false,
2815
2907
  children: [
2816
2908
  /* @__PURE__ */ jsxs(
@@ -4101,7 +4193,7 @@ function DatePicker({
4101
4193
  {
4102
4194
  ...props,
4103
4195
  className: (renderProps) => cn(
4104
- "grid grid-cols-1 gap-1.5",
4196
+ "grid grid-cols-1 gap-1.5 content-start",
4105
4197
  typeof className === "function" ? className(renderProps) : className
4106
4198
  ),
4107
4199
  children: [
@@ -4256,7 +4348,7 @@ function DateTimePicker({
4256
4348
  hideTimeZone,
4257
4349
  shouldCloseOnSelect,
4258
4350
  className: (renderProps) => cn(
4259
- "grid grid-cols-1 gap-1.5",
4351
+ "grid grid-cols-1 gap-1.5 content-start",
4260
4352
  typeof className === "function" ? className(renderProps) : className
4261
4353
  ),
4262
4354
  children: [
@@ -4433,15 +4525,15 @@ function registerDraftMessageActions(messageId, actions) {
4433
4525
  function useDraftMessageActions(messageId) {
4434
4526
  return useSyncExternalStore(
4435
4527
  (listener) => {
4436
- let listeners3 = listenersByMessageId.get(messageId);
4437
- if (!listeners3) {
4438
- listeners3 = /* @__PURE__ */ new Set();
4439
- listenersByMessageId.set(messageId, listeners3);
4528
+ let listeners4 = listenersByMessageId.get(messageId);
4529
+ if (!listeners4) {
4530
+ listeners4 = /* @__PURE__ */ new Set();
4531
+ listenersByMessageId.set(messageId, listeners4);
4440
4532
  }
4441
- listeners3.add(listener);
4533
+ listeners4.add(listener);
4442
4534
  return () => {
4443
- listeners3.delete(listener);
4444
- if (listeners3.size === 0) listenersByMessageId.delete(messageId);
4535
+ listeners4.delete(listener);
4536
+ if (listeners4.size === 0) listenersByMessageId.delete(messageId);
4445
4537
  };
4446
4538
  },
4447
4539
  () => actionsByMessageId.get(messageId) ?? null,
@@ -4499,7 +4591,7 @@ function MultiSelect({
4499
4591
  openPopover(true);
4500
4592
  }
4501
4593
  };
4502
- return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-1.5", className), children: [
4594
+ return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-1.5 content-start", className), children: [
4503
4595
  label ? /* @__PURE__ */ jsx(Label, { className: fieldLabelStyles, children: label }) : null,
4504
4596
  /* @__PURE__ */ jsxs(
4505
4597
  "div",
@@ -5024,15 +5116,15 @@ function publishDraftMessageOutcome(messageId, outcome) {
5024
5116
  for (const listener of listenersByMessageId2.get(messageId) ?? []) listener();
5025
5117
  }
5026
5118
  function subscribeDraftMessageOutcome(messageId, listener) {
5027
- let listeners3 = listenersByMessageId2.get(messageId);
5028
- if (!listeners3) {
5029
- listeners3 = /* @__PURE__ */ new Set();
5030
- listenersByMessageId2.set(messageId, listeners3);
5119
+ let listeners4 = listenersByMessageId2.get(messageId);
5120
+ if (!listeners4) {
5121
+ listeners4 = /* @__PURE__ */ new Set();
5122
+ listenersByMessageId2.set(messageId, listeners4);
5031
5123
  }
5032
- listeners3.add(listener);
5124
+ listeners4.add(listener);
5033
5125
  return () => {
5034
- listeners3.delete(listener);
5035
- if (listeners3.size === 0) listenersByMessageId2.delete(messageId);
5126
+ listeners4.delete(listener);
5127
+ if (listeners4.size === 0) listenersByMessageId2.delete(messageId);
5036
5128
  };
5037
5129
  }
5038
5130
  function useDraftMessageOutcome(messageId) {
@@ -5113,7 +5205,7 @@ function DraftMessageComposer({
5113
5205
  const [to, setTo] = useState([]);
5114
5206
  const [cc, setCc] = useState([]);
5115
5207
  const [bcc, setBcc] = useState([]);
5116
- const [snapshot, setSnapshot] = useState({
5208
+ const [snapshot2, setSnapshot] = useState({
5117
5209
  text: "",
5118
5210
  subject: "",
5119
5211
  to: [],
@@ -5164,12 +5256,12 @@ function DraftMessageComposer({
5164
5256
  };
5165
5257
  }, [client, messageId, seed, loadNonce]);
5166
5258
  const isDirty = useMemo(() => {
5167
- return value.text !== snapshot.text || isSubjectEditable && (value.subject ?? "") !== snapshot.subject || JSON.stringify(to) !== JSON.stringify(snapshot.to) || JSON.stringify(cc) !== JSON.stringify(snapshot.cc) || JSON.stringify(bcc) !== JSON.stringify(snapshot.bcc);
5168
- }, [value, to, cc, bcc, snapshot, isSubjectEditable]);
5259
+ return value.text !== snapshot2.text || isSubjectEditable && (value.subject ?? "") !== snapshot2.subject || JSON.stringify(to) !== JSON.stringify(snapshot2.to) || JSON.stringify(cc) !== JSON.stringify(snapshot2.cc) || JSON.stringify(bcc) !== JSON.stringify(snapshot2.bcc);
5260
+ }, [value, to, cc, bcc, snapshot2, isSubjectEditable]);
5169
5261
  const buildPatch = useCallback(() => {
5170
5262
  const current = message;
5171
- const isBodyEdited = value.text !== snapshot.text;
5172
- const hasRecipientEdit = areRecipientsEditable && (JSON.stringify(to) !== JSON.stringify(snapshot.to) || JSON.stringify(cc) !== JSON.stringify(snapshot.cc) || JSON.stringify(bcc) !== JSON.stringify(snapshot.bcc));
5263
+ const isBodyEdited = value.text !== snapshot2.text;
5264
+ const hasRecipientEdit = areRecipientsEditable && (JSON.stringify(to) !== JSON.stringify(snapshot2.to) || JSON.stringify(cc) !== JSON.stringify(snapshot2.cc) || JSON.stringify(bcc) !== JSON.stringify(snapshot2.bcc));
5173
5265
  const attachmentRefs = (current.attachments ?? []).map((attachment) => attachment.file);
5174
5266
  return {
5175
5267
  // Body edits collapse to one text block; an untouched body echoes the
@@ -5183,7 +5275,7 @@ function DraftMessageComposer({
5183
5275
  ...hasRecipientEdit ? { to, cc, bcc } : {},
5184
5276
  ...attachmentRefs.length > 0 ? { attachments: attachmentRefs } : {}
5185
5277
  };
5186
- }, [message, value, to, cc, bcc, snapshot, areRecipientsEditable, isSubjectEditable]);
5278
+ }, [message, value, to, cc, bcc, snapshot2, areRecipientsEditable, isSubjectEditable]);
5187
5279
  const persistDirtyEdits = useCallback(async () => {
5188
5280
  const current = message;
5189
5281
  if (!isDirty) return current;
@@ -5792,7 +5884,7 @@ function Input({
5792
5884
  {
5793
5885
  ...props,
5794
5886
  className: (renderProps) => cn(
5795
- "grid grid-cols-1 gap-1.5",
5887
+ "grid grid-cols-1 gap-1.5 content-start",
5796
5888
  typeof className === "function" ? className(renderProps) : className
5797
5889
  ),
5798
5890
  children: [
@@ -6043,6 +6135,8 @@ var progressBarStyles = tv({
6043
6135
  },
6044
6136
  variants: {
6045
6137
  size: {
6138
+ // 2px hairline — an edge meter along a card's bottom, positioned by the consumer.
6139
+ xs: { track: "h-0.5" },
6046
6140
  sm: { track: "h-1" },
6047
6141
  md: { track: "h-2" }
6048
6142
  }
@@ -6059,6 +6153,82 @@ function ProgressBar({ size, className, ...props }) {
6059
6153
  }
6060
6154
  ) }) });
6061
6155
  }
6156
+ var progressRingStyles = tv({
6157
+ slots: {
6158
+ root: "shrink-0 align-middle",
6159
+ svg: "block shrink-0 -rotate-90",
6160
+ track: "fill-none",
6161
+ arc: "fill-none stroke-accent transition-[stroke-dasharray] duration-300 ease-out",
6162
+ value: "font-mono tabular-nums leading-none"
6163
+ },
6164
+ variants: {
6165
+ size: {
6166
+ xs: {
6167
+ root: "inline-flex items-center gap-1.5",
6168
+ svg: "size-3.5",
6169
+ // A hair darker than the larger rings' track: a 2px hairline on a
6170
+ // tinted card vanishes at surface-2.
6171
+ track: "stroke-surface-3",
6172
+ value: "text-[11px] text-ink-4"
6173
+ },
6174
+ sm: {
6175
+ root: "relative inline-grid place-items-center size-7",
6176
+ svg: "col-start-1 row-start-1 size-full",
6177
+ track: "stroke-surface-2",
6178
+ value: "col-start-1 row-start-1 text-[8.5px] text-ink-2"
6179
+ },
6180
+ md: {
6181
+ root: "relative inline-grid place-items-center size-10",
6182
+ svg: "col-start-1 row-start-1 size-full",
6183
+ track: "stroke-surface-2",
6184
+ value: "col-start-1 row-start-1 text-[10px] text-ink-2"
6185
+ }
6186
+ }
6187
+ },
6188
+ defaultVariants: { size: "sm" }
6189
+ });
6190
+ var GEOMETRY = {
6191
+ xs: { box: 14, stroke: 2 },
6192
+ sm: { box: 28, stroke: 2.5 },
6193
+ md: { box: 40, stroke: 3 }
6194
+ };
6195
+ function ProgressRing({ size, className, ...props }) {
6196
+ const resolvedSize = size ?? "sm";
6197
+ const { root, svg, track, arc, value } = progressRingStyles({ size: resolvedSize });
6198
+ const { box, stroke } = GEOMETRY[resolvedSize];
6199
+ const center = box / 2;
6200
+ const radius = (box - stroke) / 2;
6201
+ return /* @__PURE__ */ jsx(ProgressBar$1, { ...props, className: cn(root(), className), children: ({ percentage, valueText, isIndeterminate }) => {
6202
+ const shown = isIndeterminate ? 25 : Math.max(0, Math.min(100, percentage ?? 0));
6203
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6204
+ /* @__PURE__ */ jsxs(
6205
+ "svg",
6206
+ {
6207
+ "aria-hidden": true,
6208
+ viewBox: `0 0 ${box} ${box}`,
6209
+ className: cn(svg(), isIndeterminate && "animate-spin"),
6210
+ children: [
6211
+ /* @__PURE__ */ jsx("circle", { cx: center, cy: center, r: radius, strokeWidth: stroke, className: track() }),
6212
+ shown > 0 ? /* @__PURE__ */ jsx(
6213
+ "circle",
6214
+ {
6215
+ cx: center,
6216
+ cy: center,
6217
+ r: radius,
6218
+ strokeWidth: stroke,
6219
+ strokeLinecap: "round",
6220
+ pathLength: 100,
6221
+ strokeDasharray: `${shown} 100`,
6222
+ className: arc()
6223
+ }
6224
+ ) : null
6225
+ ]
6226
+ }
6227
+ ),
6228
+ isIndeterminate ? null : /* @__PURE__ */ jsx("span", { className: value(), children: valueText })
6229
+ ] });
6230
+ } });
6231
+ }
6062
6232
  function RadioGroup({
6063
6233
  label,
6064
6234
  description,
@@ -6073,7 +6243,10 @@ function RadioGroup({
6073
6243
  {
6074
6244
  ...props,
6075
6245
  orientation,
6076
- className: (renderProps) => cn("grid gap-2", typeof className === "function" ? className(renderProps) : className),
6246
+ className: (renderProps) => cn(
6247
+ "grid gap-2 content-start",
6248
+ typeof className === "function" ? className(renderProps) : className
6249
+ ),
6077
6250
  children: [
6078
6251
  label ? /* @__PURE__ */ jsx(Label, { className: fieldLabelStyles, children: label }) : null,
6079
6252
  /* @__PURE__ */ jsx(
@@ -6596,7 +6769,7 @@ function TagInput({
6596
6769
  onChange(value.slice(0, -1));
6597
6770
  }
6598
6771
  };
6599
- return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-1.5", className), children: [
6772
+ return /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-1.5 content-start", className), children: [
6600
6773
  label ? /* @__PURE__ */ jsx("label", { htmlFor: inputId, className: fieldLabelStyles, children: label }) : null,
6601
6774
  /* @__PURE__ */ jsx(
6602
6775
  "div",
@@ -7673,7 +7846,7 @@ function RecordFilterBuilderPanel({
7673
7846
  ) });
7674
7847
  }
7675
7848
  var stores = /* @__PURE__ */ new Map();
7676
- function listeners2(key) {
7849
+ function listeners3(key) {
7677
7850
  let set = stores.get(key);
7678
7851
  if (!set) {
7679
7852
  set = /* @__PURE__ */ new Set();
@@ -7696,16 +7869,16 @@ function write(key, next) {
7696
7869
  } catch {
7697
7870
  }
7698
7871
  }
7699
- for (const fn of listeners2(key)) fn(next);
7872
+ for (const fn of listeners3(key)) fn(next);
7700
7873
  }
7701
7874
  function useShowDetails(storageKey = "rf.showDetails") {
7702
7875
  const [value, setValue] = useState(() => read(storageKey));
7703
7876
  useEffect(() => {
7704
7877
  const fn = (next) => setValue(next);
7705
- listeners2(storageKey).add(fn);
7878
+ listeners3(storageKey).add(fn);
7706
7879
  setValue(read(storageKey));
7707
7880
  return () => {
7708
- listeners2(storageKey).delete(fn);
7881
+ listeners3(storageKey).delete(fn);
7709
7882
  };
7710
7883
  }, [storageKey]);
7711
7884
  const toggle = () => write(storageKey, !read(storageKey));
@@ -8205,6 +8378,133 @@ function InlineAddFilter({ onClick }) {
8205
8378
  }
8206
8379
  );
8207
8380
  }
8381
+ var recordUpdateStyles = tv({
8382
+ slots: {
8383
+ root: "flex flex-col min-w-0 text-ink",
8384
+ summary: "px-4 pt-3 pb-1 text-[13px] text-ink-3",
8385
+ rows: "flex flex-col px-4 divide-y divide-rule",
8386
+ errors: [
8387
+ "mx-4 my-3 flex gap-2 rounded-md px-3 py-2 text-[13px] text-danger",
8388
+ "bg-[color-mix(in_oklab,var(--color-danger)_8%,var(--color-surface))]"
8389
+ ],
8390
+ footer: "flex items-center justify-end gap-2 px-4 py-3"
8391
+ }
8392
+ });
8393
+ var recordUpdateRowStyles = tv({
8394
+ slots: {
8395
+ // fieldset resets (UA border / padding / min-content width) included.
8396
+ root: "flex flex-col gap-1.5 m-0 border-0 px-0 py-2.5 min-w-0",
8397
+ labelRow: [
8398
+ "flex items-center gap-2 min-h-7",
8399
+ "font-mono text-[10.5px] uppercase tracking-[0.08em] text-ink-4"
8400
+ ],
8401
+ tag: "normal-case tracking-normal text-[10px] rounded-full px-1.5 py-px",
8402
+ cells: "grid grid-cols-1 sm:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center gap-2 sm:gap-3",
8403
+ from: "min-w-0 opacity-70",
8404
+ arrow: "size-3.5 shrink-0 text-ink-4 rotate-90 sm:rotate-0 justify-self-center",
8405
+ to: "min-w-0",
8406
+ hint: "text-[12px] text-ink-4",
8407
+ error: "text-[12px] text-danger",
8408
+ removed: "text-[13px] italic text-ink-4"
8409
+ },
8410
+ variants: {
8411
+ state: {
8412
+ changed: {},
8413
+ unresolved: {
8414
+ tag: "text-warning bg-[color-mix(in_oklab,var(--color-warning)_12%,var(--color-surface))]"
8415
+ },
8416
+ rejected: {
8417
+ tag: "text-danger bg-[color-mix(in_oklab,var(--color-danger)_10%,var(--color-surface))]"
8418
+ },
8419
+ removed: { labelRow: "line-through decoration-ink-4/60" }
8420
+ }
8421
+ },
8422
+ defaultVariants: { state: "changed" }
8423
+ });
8424
+ function RecordUpdate({ className, children, ...props }) {
8425
+ return /* @__PURE__ */ jsx("div", { ...props, className: cn(recordUpdateStyles().root(), className), children });
8426
+ }
8427
+ function RecordUpdateSummary({
8428
+ className,
8429
+ children,
8430
+ ...props
8431
+ }) {
8432
+ return /* @__PURE__ */ jsx("p", { ...props, className: cn(recordUpdateStyles().summary(), className), children });
8433
+ }
8434
+ function RecordUpdateRows({
8435
+ className,
8436
+ children,
8437
+ ...props
8438
+ }) {
8439
+ return /* @__PURE__ */ jsx("div", { ...props, className: cn(recordUpdateStyles().rows(), className), children });
8440
+ }
8441
+ function RecordUpdateErrors({ errors, className, ...props }) {
8442
+ if (errors.length === 0) return null;
8443
+ return /* @__PURE__ */ jsxs("div", { ...props, role: "alert", className: cn(recordUpdateStyles().errors(), className), children: [
8444
+ /* @__PURE__ */ jsx(AlertCircle, { className: "size-4 shrink-0 mt-px", "aria-hidden": true }),
8445
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1 min-w-0", children: errors.map((error) => /* @__PURE__ */ jsx("li", { children: error }, error)) })
8446
+ ] });
8447
+ }
8448
+ function RecordUpdateFooter({
8449
+ className,
8450
+ children,
8451
+ ...props
8452
+ }) {
8453
+ return /* @__PURE__ */ jsx("div", { ...props, className: cn(recordUpdateStyles().footer(), className), children });
8454
+ }
8455
+ function RecordUpdateRow({
8456
+ label,
8457
+ from,
8458
+ to,
8459
+ state = "changed",
8460
+ hint,
8461
+ errorMessage,
8462
+ onRemove,
8463
+ onRestore,
8464
+ removeLabel = "Remove change",
8465
+ restoreLabel = "Restore change",
8466
+ unresolvedLabel = "needs a value",
8467
+ rejectedLabel = "not possible",
8468
+ removedText = "Kept as it is",
8469
+ className,
8470
+ ...props
8471
+ }) {
8472
+ const styles4 = recordUpdateRowStyles({ state });
8473
+ const isRemoved = state === "removed";
8474
+ return /* @__PURE__ */ jsxs(
8475
+ "fieldset",
8476
+ {
8477
+ ...props,
8478
+ "data-state": state,
8479
+ ...errorMessage ? { "aria-invalid": true } : {},
8480
+ className: cn(styles4.root(), className),
8481
+ children: [
8482
+ /* @__PURE__ */ jsxs("div", { className: styles4.labelRow(), children: [
8483
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: label }),
8484
+ state === "unresolved" ? /* @__PURE__ */ jsx("span", { className: styles4.tag(), children: unresolvedLabel }) : null,
8485
+ state === "rejected" ? /* @__PURE__ */ jsx("span", { className: styles4.tag(), children: rejectedLabel }) : null,
8486
+ /* @__PURE__ */ jsx("span", { className: "ml-auto flex items-center", children: isRemoved ? onRestore && /* @__PURE__ */ jsx(
8487
+ Button,
8488
+ {
8489
+ variant: "ghost",
8490
+ size: "icon-sm",
8491
+ "aria-label": restoreLabel,
8492
+ onPress: onRestore,
8493
+ children: /* @__PURE__ */ jsx(Undo2, {})
8494
+ }
8495
+ ) : onRemove && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": removeLabel, onPress: onRemove, children: /* @__PURE__ */ jsx(X, {}) }) })
8496
+ ] }),
8497
+ isRemoved ? /* @__PURE__ */ jsx("div", { className: styles4.removed(), children: removedText }) : from === void 0 ? /* @__PURE__ */ jsx("div", { className: styles4.to(), children: to }) : /* @__PURE__ */ jsxs("div", { className: styles4.cells(), children: [
8498
+ /* @__PURE__ */ jsx("div", { className: styles4.from(), children: from }),
8499
+ /* @__PURE__ */ jsx(ArrowRight, { className: styles4.arrow(), "aria-hidden": true }),
8500
+ /* @__PURE__ */ jsx("div", { className: styles4.to(), children: to })
8501
+ ] }),
8502
+ !isRemoved && hint ? /* @__PURE__ */ jsx("div", { className: styles4.hint(), children: hint }) : null,
8503
+ !isRemoved && errorMessage ? /* @__PURE__ */ jsx("div", { className: styles4.error(), role: "alert", children: errorMessage }) : null
8504
+ ]
8505
+ }
8506
+ );
8507
+ }
8208
8508
  var separatorStyles = tv({
8209
8509
  base: "m-0 border-0 border-rule",
8210
8510
  variants: {
@@ -8247,11 +8547,20 @@ function SuccessAnimation({ className }) {
8247
8547
  }
8248
8548
  );
8249
8549
  }
8250
- function Switch({ children, labelPlacement = "end", className, ...props }) {
8251
- return /* @__PURE__ */ jsxs(
8550
+ function Switch({
8551
+ children,
8552
+ labelPlacement = "end",
8553
+ description,
8554
+ className,
8555
+ ...props
8556
+ }) {
8557
+ const descriptionId = useId();
8558
+ const describedBy = [props["aria-describedby"], description ? descriptionId : void 0].filter(Boolean).join(" ");
8559
+ const control = /* @__PURE__ */ jsxs(
8252
8560
  Switch$1,
8253
8561
  {
8254
8562
  ...props,
8563
+ ...describedBy ? { "aria-describedby": describedBy } : {},
8255
8564
  className: (renderProps) => cn(
8256
8565
  // `relative`: RAC's visually-hidden <input> is absolutely positioned;
8257
8566
  // without a positioned label it escapes an overflow-auto ancestor and
@@ -8293,6 +8602,24 @@ function Switch({ children, labelPlacement = "end", className, ...props }) {
8293
8602
  ]
8294
8603
  }
8295
8604
  );
8605
+ if (!description) return control;
8606
+ return /* @__PURE__ */ jsxs("div", { className: "grid gap-1 content-start", children: [
8607
+ control,
8608
+ /* @__PURE__ */ jsx(
8609
+ "span",
8610
+ {
8611
+ id: descriptionId,
8612
+ className: cn(
8613
+ fieldHintStyles,
8614
+ "leading-[1.45]",
8615
+ // Track (38px) + gap-3 (12px): the copy starts under the label text.
8616
+ labelPlacement === "end" && "pl-[50px]",
8617
+ props.isDisabled && "opacity-45"
8618
+ ),
8619
+ children: description
8620
+ }
8621
+ )
8622
+ ] });
8296
8623
  }
8297
8624
  var tabsStyles = tv({
8298
8625
  slots: {
@@ -8373,6 +8700,25 @@ var Tabs = Object.assign(Root, {
8373
8700
  Trigger,
8374
8701
  Panel
8375
8702
  });
8703
+ var textShimmerStyles = tv({
8704
+ base: [
8705
+ "inline-block bg-clip-text text-transparent",
8706
+ "bg-[length:200%_auto] animate-text-shimmer",
8707
+ "motion-reduce:animate-none motion-reduce:bg-none motion-reduce:text-ink-4"
8708
+ ],
8709
+ variants: {
8710
+ tone: {
8711
+ // Muted band on a muted base — a quiet loading row.
8712
+ muted: "bg-[linear-gradient(90deg,var(--color-ink-4)_0%,var(--color-ink-4)_40%,var(--color-ink)_50%,var(--color-ink-4)_60%,var(--color-ink-4)_100%)]",
8713
+ // Accent band on ink — a glowing heading.
8714
+ accent: "bg-[linear-gradient(90deg,var(--color-ink)_0%,var(--color-ink)_40%,var(--color-accent)_50%,var(--color-ink)_60%,var(--color-ink)_100%)] motion-reduce:text-ink"
8715
+ }
8716
+ },
8717
+ defaultVariants: { tone: "muted" }
8718
+ });
8719
+ function TextShimmer({ tone, className, children, ...props }) {
8720
+ return /* @__PURE__ */ jsx("span", { ...props, className: cn(textShimmerStyles({ tone }), className), children });
8721
+ }
8376
8722
  function Textarea({
8377
8723
  label,
8378
8724
  description,
@@ -8392,7 +8738,7 @@ function Textarea({
8392
8738
  {
8393
8739
  ...props,
8394
8740
  className: (renderProps) => cn(
8395
- "grid grid-cols-1 gap-1.5",
8741
+ "grid grid-cols-1 gap-1.5 content-start",
8396
8742
  typeof className === "function" ? className(renderProps) : className
8397
8743
  ),
8398
8744
  children: [
@@ -8435,7 +8781,7 @@ function TimeField({
8435
8781
  {
8436
8782
  ...props,
8437
8783
  className: (renderProps) => cn(
8438
- "grid grid-cols-1 gap-1.5",
8784
+ "grid grid-cols-1 gap-1.5 content-start",
8439
8785
  typeof className === "function" ? className(renderProps) : className
8440
8786
  ),
8441
8787
  children: [
@@ -8543,6 +8889,6 @@ function ToastRegion({ queue, className }) {
8543
8889
  );
8544
8890
  }
8545
8891
 
8546
- 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, Radio, RadioGroup, RecipientSelect, RecordFilterBuilderPanel, RecordFilterButton, RecordFilterChips, RecordFilterEditor, RenderChipItemProvider, RenderValueInputProvider, SELECTION_COLUMN_ID, SegmentedControl, Select, Separator, SubmenuTrigger, SuccessAnimation, Switch, Table, TableBody, TableCell, TableHeader, TableHeaderCell, TableHeaderSpacer, TableRow, TableScroller, Tabs, TagInput, 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, iconForContentType, imageAttachmentStyles, imageLightboxStyles, isColumnDragData, isDialableConversationBrief, isDraftReviewOutcome, isEditableTarget, isPreviewableImageName, joinFieldLabel, makeActionsColumn, messageComposerStyles, namesOf, navItemStyles, normalizeHexColor, operatorById, operatorsForType, parseCombo, progressBarStyles, publishDraftMessageOutcome, rebaseRowOnFieldChange, rebaseRowOnOperatorChange, registerDraftMessageActions, removeLeaf, removeSubgroup, replaceLeaf, resolveLucideIcon, resolveLucideIconName, segmentedControlStyles, setJoiner, subscribeDraftMessageOutcome, summaryFor, tableCellStyles, tableHeaderCellStyles, tabsStyles, terminalKindFor, toastStyles, updateLeaf, updateSubgroup, useAttributeTypeIcon, useCommand, useDiscoveryActive, useDraftMessageActions, useDraftMessageOutcome, useEscapeKey, useInfiniteScrollSentinel, useRenderChipItem, useRenderValueInput, useShowDetails, viewerKindForContentType, wrapLeafInGroup };
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 };
8547
8893
  //# sourceMappingURL=index.js.map
8548
8894
  //# sourceMappingURL=index.js.map