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