@ggui-ai/dev-stack 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ggui-ai/dev-stack
2
2
 
3
- > Shared local dev engine for the [ggui](https://github.com/ggui-ai/ggui) protocol.
3
+ > Shared local dev engine for the [GGUI](https://github.com/ggui-ai/ggui) protocol.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@ggui-ai/dev-stack.svg)](https://www.npmjs.com/package/@ggui-ai/dev-stack)
6
6
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](./LICENSE)
@@ -19920,7 +19920,7 @@ var require_jsx_runtime = __commonJS({
19920
19920
  });
19921
19921
 
19922
19922
  // hub-preview-client/main.tsx
19923
- var import_react45 = __toESM(require_react(), 1);
19923
+ var import_react46 = __toESM(require_react(), 1);
19924
19924
  var import_client = __toESM(require_client(), 1);
19925
19925
 
19926
19926
  // ../mcp-apps-react/dist/chunk-7P6ASYW6.mjs
@@ -20437,8 +20437,8 @@ function makeActionEnvelope(parts) {
20437
20437
  }
20438
20438
 
20439
20439
  // ../mcp-apps-react/dist/index.mjs
20440
- var import_react7 = __toESM(require_react(), 1);
20441
20440
  var import_react8 = __toESM(require_react(), 1);
20441
+ var import_react9 = __toESM(require_react(), 1);
20442
20442
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
20443
20443
 
20444
20444
  // ../wire/dist/index.js
@@ -20452,6 +20452,7 @@ __export(dist_exports, {
20452
20452
  buildWireConfig: () => buildWireConfig,
20453
20453
  connectionSource: () => connectionSource,
20454
20454
  useAction: () => useAction,
20455
+ useActionPending: () => useActionPending,
20455
20456
  useActionSpent: () => useActionSpent,
20456
20457
  useApp: () => useApp,
20457
20458
  useAuth: () => useAuth,
@@ -20554,8 +20555,19 @@ function useActionSpent(actionName) {
20554
20555
  return (0, import_react3.useSyncExternalStore)(subscribe, read, read);
20555
20556
  }
20556
20557
 
20557
- // ../wire/dist/useGguiContext.js
20558
+ // ../wire/dist/action-pending.js
20558
20559
  var import_react4 = __toESM(require_react(), 1);
20560
+ var ActionPendingContext = (0, import_react4.createContext)(null);
20561
+ var noSubscription2 = () => () => void 0;
20562
+ function useActionPending(actionName) {
20563
+ const source = (0, import_react4.useContext)(ActionPendingContext);
20564
+ const subscribe = (0, import_react4.useCallback)((listener) => source === null ? noSubscription2() : source.subscribe(listener), [source]);
20565
+ const read = (0, import_react4.useCallback)(() => source === null ? false : source.isPending(actionName), [source, actionName]);
20566
+ return (0, import_react4.useSyncExternalStore)(subscribe, read, read);
20567
+ }
20568
+
20569
+ // ../wire/dist/useGguiContext.js
20570
+ var import_react5 = __toESM(require_react(), 1);
20559
20571
  function useGguiContext(slotName) {
20560
20572
  const contextName = slotName.length === 0 ? "Context" : slotName.charAt(0).toUpperCase() + slotName.slice(1) + "Context";
20561
20573
  const registry = globalThis.__ggui__?.contexts;
@@ -20563,19 +20575,19 @@ function useGguiContext(slotName) {
20563
20575
  if (!ctx) {
20564
20576
  throw new Error(`[ggui] useGguiContext('${slotName}'): no Context registered. The contract must declare 'contextSpec.${slotName}' AND the runtime must have synthesized the per-slot React Context at boot. If you see this in production code generated by the LLM, the boilerplate's destructure line drifted from the contract.`);
20565
20577
  }
20566
- return (0, import_react4.useContext)(ctx);
20578
+ return (0, import_react5.useContext)(ctx);
20567
20579
  }
20568
20580
 
20569
20581
  // ../wire/dist/useStream.js
20570
- var import_react5 = __toESM(require_react(), 1);
20582
+ var import_react6 = __toESM(require_react(), 1);
20571
20583
  function useStream(channelName) {
20572
20584
  const { subscribe } = useWireContext();
20573
- const [latest, setLatest] = (0, import_react5.useState)(null);
20574
- const [all, setAll] = (0, import_react5.useState)([]);
20575
- const [isComplete, setIsComplete] = (0, import_react5.useState)(false);
20576
- const allRef = (0, import_react5.useRef)(all);
20585
+ const [latest, setLatest] = (0, import_react6.useState)(null);
20586
+ const [all, setAll] = (0, import_react6.useState)([]);
20587
+ const [isComplete, setIsComplete] = (0, import_react6.useState)(false);
20588
+ const allRef = (0, import_react6.useRef)(all);
20577
20589
  allRef.current = all;
20578
- (0, import_react5.useEffect)(() => {
20590
+ (0, import_react6.useEffect)(() => {
20579
20591
  return subscribe(channelName, (delivery) => {
20580
20592
  const typed = delivery.payload;
20581
20593
  setLatest(typed);
@@ -20613,7 +20625,7 @@ function useApp() {
20613
20625
  }
20614
20626
 
20615
20627
  // ../wire/dist/useRender.js
20616
- var import_react6 = __toESM(require_react(), 1);
20628
+ var import_react7 = __toESM(require_react(), 1);
20617
20629
 
20618
20630
  // ../wire/dist/connection-store.js
20619
20631
  var ConnectionWriterConflictError = class extends Error {
@@ -20710,7 +20722,7 @@ var connectionSource = documentStore.source;
20710
20722
  // ../wire/dist/useRender.js
20711
20723
  function useRender() {
20712
20724
  const { render } = useWireContext();
20713
- const isConnected = (0, import_react6.useSyncExternalStore)(connectionSource.subscribe, connectionSource.getSnapshot, connectionSource.getSnapshot);
20725
+ const isConnected = (0, import_react7.useSyncExternalStore)(connectionSource.subscribe, connectionSource.getSnapshot, connectionSource.getSnapshot);
20714
20726
  return { sessionId: render.sessionId, isConnected };
20715
20727
  }
20716
20728
 
@@ -20804,6 +20816,7 @@ var StreamBus = class {
20804
20816
  }
20805
20817
  }
20806
20818
  };
20819
+ var DEFAULT_ACTION_PENDING_BOUND_MS = 2e4;
20807
20820
  function buildWireConfig(opts) {
20808
20821
  let internalSeq = 0;
20809
20822
  const nextClientSeq = opts.nextClientSeq ?? (() => {
@@ -20828,8 +20841,43 @@ function buildWireConfig(opts) {
20828
20841
  }
20829
20842
  };
20830
20843
  opts.spentInputsChanged?.(notifySpent);
20844
+ const pendingBoundMs = opts.actionPendingBoundMs ?? DEFAULT_ACTION_PENDING_BOUND_MS;
20845
+ const pending = /* @__PURE__ */ new Map();
20846
+ const pendingListeners = /* @__PURE__ */ new Set();
20847
+ const notifyPending = () => {
20848
+ for (const listener of [...pendingListeners])
20849
+ listener();
20850
+ };
20851
+ const markPending = (actionName) => {
20852
+ const previous = pending.get(actionName);
20853
+ if (previous !== void 0)
20854
+ clearTimeout(previous);
20855
+ pending.set(actionName, setTimeout(() => {
20856
+ pending.delete(actionName);
20857
+ notifyPending();
20858
+ }, pendingBoundMs));
20859
+ notifyPending();
20860
+ };
20861
+ const actionPending = {
20862
+ isPending: (actionName) => pending.has(actionName),
20863
+ subscribe: (listener) => {
20864
+ pendingListeners.add(listener);
20865
+ return () => {
20866
+ pendingListeners.delete(listener);
20867
+ };
20868
+ }
20869
+ };
20870
+ opts.pendingInputsChanged?.(() => {
20871
+ if (pending.size === 0)
20872
+ return;
20873
+ for (const timer of pending.values())
20874
+ clearTimeout(timer);
20875
+ pending.clear();
20876
+ notifyPending();
20877
+ });
20831
20878
  return {
20832
20879
  actionSpent,
20880
+ actionPending,
20833
20881
  app: opts.app,
20834
20882
  render: opts.render,
20835
20883
  auth: opts.auth,
@@ -20862,6 +20910,7 @@ function buildWireConfig(opts) {
20862
20910
  const result = validateEnvelope(actionSpec, envelope);
20863
20911
  if (!result.valid) {
20864
20912
  opts.onViolation(new ClientContractViolationError("outbound-action", result.violations));
20913
+ opts.onDispatchRefused?.({ actionName, violations: result.violations });
20865
20914
  return;
20866
20915
  }
20867
20916
  if (isOneShot && !spentOneShots.has(actionName)) {
@@ -20869,6 +20918,7 @@ function buildWireConfig(opts) {
20869
20918
  notifySpent();
20870
20919
  }
20871
20920
  opts.emitEnvelope(envelope);
20921
+ markPending(actionName);
20872
20922
  },
20873
20923
  subscribe: (channelName, handler) => {
20874
20924
  return opts.streamBus.subscribe(channelName, (env) => {
@@ -20883,65 +20933,65 @@ function buildWireConfig(opts) {
20883
20933
  }
20884
20934
 
20885
20935
  // ../mcp-apps-react/dist/index.mjs
20886
- var import_react9 = __toESM(require_react(), 1);
20936
+ var import_react10 = __toESM(require_react(), 1);
20887
20937
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
20888
20938
  var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
20889
- var import_react10 = __toESM(require_react(), 1);
20890
20939
  var import_react11 = __toESM(require_react(), 1);
20940
+ var import_react12 = __toESM(require_react(), 1);
20891
20941
  var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
20892
20942
  var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
20893
20943
  var import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
20894
20944
  var import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
20895
- var import_react12 = __toESM(require_react(), 1);
20896
20945
  var import_react13 = __toESM(require_react(), 1);
20946
+ var import_react14 = __toESM(require_react(), 1);
20897
20947
  var import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
20898
20948
  var import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
20899
20949
  var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
20900
- var import_react14 = __toESM(require_react(), 1);
20901
- var import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
20902
20950
  var import_react15 = __toESM(require_react(), 1);
20903
- var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
20951
+ var import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
20904
20952
  var import_react16 = __toESM(require_react(), 1);
20953
+ var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
20954
+ var import_react17 = __toESM(require_react(), 1);
20905
20955
  var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
20906
20956
  var import_jsx_runtime15 = __toESM(require_jsx_runtime(), 1);
20907
- var import_react17 = __toESM(require_react(), 1);
20908
- var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
20909
20957
  var import_react18 = __toESM(require_react(), 1);
20910
- var import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
20958
+ var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
20911
20959
  var import_react19 = __toESM(require_react(), 1);
20960
+ var import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
20961
+ var import_react20 = __toESM(require_react(), 1);
20912
20962
  var import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
20913
20963
  var import_jsx_runtime19 = __toESM(require_jsx_runtime(), 1);
20914
20964
  var import_jsx_runtime20 = __toESM(require_jsx_runtime(), 1);
20915
- var import_react20 = __toESM(require_react(), 1);
20965
+ var import_react21 = __toESM(require_react(), 1);
20916
20966
  var import_jsx_runtime21 = __toESM(require_jsx_runtime(), 1);
20917
20967
  var import_jsx_runtime22 = __toESM(require_jsx_runtime(), 1);
20918
20968
  var import_jsx_runtime23 = __toESM(require_jsx_runtime(), 1);
20919
- var import_react21 = __toESM(require_react(), 1);
20920
- var import_jsx_runtime24 = __toESM(require_jsx_runtime(), 1);
20921
20969
  var import_react22 = __toESM(require_react(), 1);
20970
+ var import_jsx_runtime24 = __toESM(require_jsx_runtime(), 1);
20971
+ var import_react23 = __toESM(require_react(), 1);
20922
20972
  var import_jsx_runtime25 = __toESM(require_jsx_runtime(), 1);
20923
20973
  var import_jsx_runtime26 = __toESM(require_jsx_runtime(), 1);
20924
- var import_react23 = __toESM(require_react(), 1);
20925
- var import_jsx_runtime27 = __toESM(require_jsx_runtime(), 1);
20926
20974
  var import_react24 = __toESM(require_react(), 1);
20927
- var import_jsx_runtime28 = __toESM(require_jsx_runtime(), 1);
20975
+ var import_jsx_runtime27 = __toESM(require_jsx_runtime(), 1);
20928
20976
  var import_react25 = __toESM(require_react(), 1);
20929
- var import_jsx_runtime29 = __toESM(require_jsx_runtime(), 1);
20977
+ var import_jsx_runtime28 = __toESM(require_jsx_runtime(), 1);
20930
20978
  var import_react26 = __toESM(require_react(), 1);
20931
- var import_jsx_runtime30 = __toESM(require_jsx_runtime(), 1);
20979
+ var import_jsx_runtime29 = __toESM(require_jsx_runtime(), 1);
20932
20980
  var import_react27 = __toESM(require_react(), 1);
20981
+ var import_jsx_runtime30 = __toESM(require_jsx_runtime(), 1);
20933
20982
  var import_react28 = __toESM(require_react(), 1);
20934
- var import_jsx_runtime31 = __toESM(require_jsx_runtime(), 1);
20935
20983
  var import_react29 = __toESM(require_react(), 1);
20984
+ var import_jsx_runtime31 = __toESM(require_jsx_runtime(), 1);
20985
+ var import_react30 = __toESM(require_react(), 1);
20936
20986
  var import_jsx_runtime32 = __toESM(require_jsx_runtime(), 1);
20937
20987
  var import_jsx_runtime33 = __toESM(require_jsx_runtime(), 1);
20938
20988
  var import_jsx_runtime34 = __toESM(require_jsx_runtime(), 1);
20939
20989
  var import_jsx_runtime35 = __toESM(require_jsx_runtime(), 1);
20940
- var import_react30 = __toESM(require_react(), 1);
20941
- var import_jsx_runtime36 = __toESM(require_jsx_runtime(), 1);
20942
20990
  var import_react31 = __toESM(require_react(), 1);
20943
- var import_jsx_runtime37 = __toESM(require_jsx_runtime(), 1);
20991
+ var import_jsx_runtime36 = __toESM(require_jsx_runtime(), 1);
20944
20992
  var import_react32 = __toESM(require_react(), 1);
20993
+ var import_jsx_runtime37 = __toESM(require_jsx_runtime(), 1);
20994
+ var import_react33 = __toESM(require_react(), 1);
20945
20995
  var import_jsx_runtime38 = __toESM(require_jsx_runtime(), 1);
20946
20996
  var import_jsx_runtime39 = __toESM(require_jsx_runtime(), 1);
20947
20997
  var import_jsx_runtime40 = __toESM(require_jsx_runtime(), 1);
@@ -20949,38 +20999,38 @@ var import_jsx_runtime41 = __toESM(require_jsx_runtime(), 1);
20949
20999
  var import_jsx_runtime42 = __toESM(require_jsx_runtime(), 1);
20950
21000
  var import_jsx_runtime43 = __toESM(require_jsx_runtime(), 1);
20951
21001
  var import_jsx_runtime44 = __toESM(require_jsx_runtime(), 1);
20952
- var import_react33 = __toESM(require_react(), 1);
21002
+ var import_react34 = __toESM(require_react(), 1);
20953
21003
  var import_jsx_runtime45 = __toESM(require_jsx_runtime(), 1);
20954
21004
  var import_jsx_runtime46 = __toESM(require_jsx_runtime(), 1);
20955
- var import_react34 = __toESM(require_react(), 1);
21005
+ var import_react35 = __toESM(require_react(), 1);
20956
21006
  var import_jsx_runtime47 = __toESM(require_jsx_runtime(), 1);
20957
21007
  var import_jsx_runtime48 = __toESM(require_jsx_runtime(), 1);
20958
- var import_react35 = __toESM(require_react(), 1);
21008
+ var import_react36 = __toESM(require_react(), 1);
20959
21009
  var import_jsx_runtime49 = __toESM(require_jsx_runtime(), 1);
20960
21010
  var import_jsx_runtime50 = __toESM(require_jsx_runtime(), 1);
20961
- var import_react36 = __toESM(require_react(), 1);
21011
+ var import_react37 = __toESM(require_react(), 1);
20962
21012
  var import_jsx_runtime51 = __toESM(require_jsx_runtime(), 1);
20963
21013
  var import_jsx_runtime52 = __toESM(require_jsx_runtime(), 1);
20964
- var import_react37 = __toESM(require_react(), 1);
20965
- var import_jsx_runtime53 = __toESM(require_jsx_runtime(), 1);
20966
21014
  var import_react38 = __toESM(require_react(), 1);
21015
+ var import_jsx_runtime53 = __toESM(require_jsx_runtime(), 1);
21016
+ var import_react39 = __toESM(require_react(), 1);
20967
21017
  var import_jsx_runtime54 = __toESM(require_jsx_runtime(), 1);
20968
21018
  var import_jsx_runtime55 = __toESM(require_jsx_runtime(), 1);
20969
21019
  var import_jsx_runtime56 = __toESM(require_jsx_runtime(), 1);
20970
- var import_react39 = __toESM(require_react(), 1);
20971
- var import_jsx_runtime57 = __toESM(require_jsx_runtime(), 1);
20972
21020
  var import_react40 = __toESM(require_react(), 1);
20973
- var import_jsx_runtime58 = __toESM(require_jsx_runtime(), 1);
21021
+ var import_jsx_runtime57 = __toESM(require_jsx_runtime(), 1);
20974
21022
  var import_react41 = __toESM(require_react(), 1);
20975
- var import_jsx_runtime59 = __toESM(require_jsx_runtime(), 1);
21023
+ var import_jsx_runtime58 = __toESM(require_jsx_runtime(), 1);
20976
21024
  var import_react42 = __toESM(require_react(), 1);
21025
+ var import_jsx_runtime59 = __toESM(require_jsx_runtime(), 1);
21026
+ var import_react43 = __toESM(require_react(), 1);
20977
21027
  var import_jsx_runtime60 = __toESM(require_jsx_runtime(), 1);
20978
21028
  var import_jsx_runtime61 = __toESM(require_jsx_runtime(), 1);
20979
- var import_react43 = __toESM(require_react(), 1);
21029
+ var import_react44 = __toESM(require_react(), 1);
20980
21030
  var import_jsx_runtime62 = __toESM(require_jsx_runtime(), 1);
20981
21031
  var import_jsx_runtime63 = __toESM(require_jsx_runtime(), 1);
20982
- var import_react44 = __toESM(require_react(), 1);
20983
- var GguiContext = (0, import_react8.createContext)(null);
21032
+ var import_react45 = __toESM(require_react(), 1);
21033
+ var GguiContext = (0, import_react9.createContext)(null);
20984
21034
  var KNOWN_PERMISSION_NAMES_SET2 = new Set(KNOWN_PERMISSION_NAMES);
20985
21035
  var primitives_exports = {};
20986
21036
  __export2(primitives_exports, {
@@ -21149,9 +21199,9 @@ function frameAttributes(frame) {
21149
21199
  function renderWithTrait(trait, traitProps, root, children) {
21150
21200
  const marks = frameAttributes(root.frame);
21151
21201
  if (trait === void 0) {
21152
- return (0, import_react10.createElement)("div", { className: root.className, style: root.style, ...marks }, children);
21202
+ return (0, import_react11.createElement)("div", { className: root.className, style: root.style, ...marks }, children);
21153
21203
  }
21154
- return (0, import_react10.createElement)(trait, { ...traitProps, className: root.className, style: root.style, ...marks }, children);
21204
+ return (0, import_react11.createElement)(trait, { ...traitProps, className: root.className, style: root.style, ...marks }, children);
21155
21205
  }
21156
21206
  function resolveToneCss(tone) {
21157
21207
  switch (tone) {
@@ -21196,7 +21246,7 @@ function surfaceScopeCss(cls, name, bg, ink, accent, outlineOpen) {
21196
21246
  const inkAlias = "--ggui-surface-" + name + "-ink";
21197
21247
  const B = "var(" + bgAlias + ")";
21198
21248
  const I = "var(" + inkAlias + ")";
21199
- return `.${cls}{${bgAlias}:${bg};${inkAlias}:${ink};--ggui-color-onInverted:${ink}}.${cls}>*{--ggui-color-container:${B};--ggui-color-onContainer:${I};--ggui-color-elevated:${B};--ggui-color-onElevated:${I};--ggui-color-sunken:${B};--ggui-color-onSunken:${I};--ggui-color-neutral-500:${I};--ggui-color-ground:${B};--ggui-color-onGround:${I};--ggui-color-link:${accent}}@supports (color: color-mix(in srgb, red, blue)){.${cls}>*{--ggui-color-container:color-mix(in srgb, ${B} 94%, ${I});--ggui-color-elevated:color-mix(in srgb, ${B} 92%, ${I});--ggui-color-sunken:color-mix(in srgb, ${B} 88%, ${I});--ggui-color-onSunken:color-mix(in srgb, ${I} 76%, ${B});--ggui-color-neutral-500:color-mix(in srgb, ${I} 62%, ${B});--ggui-color-outline:${outlineOpen}color-mix(in srgb, ${I} 32%, ${B}));--ggui-color-outlineVariant:color-mix(in srgb, ${I} 18%, ${B})}}`;
21249
+ return `.${cls}{${bgAlias}:${bg};${inkAlias}:${ink};--ggui-color-onInverted:${ink}}.${cls}>*{--ggui-color-container:${B};--ggui-color-onContainer:${I};--ggui-color-elevated:${B};--ggui-color-onElevated:${I};--ggui-color-sunken:${B};--ggui-color-onSunken:${I};--ggui-color-neutral-500:${I};--ggui-color-ground:${B};--ggui-color-onGround:${I};--ggui-color-link:${accent};--ggui-color-controlAccentOutline:${accent}}@supports (color: color-mix(in srgb, red, blue)){.${cls}>*{--ggui-color-container:color-mix(in srgb, ${B} 94%, ${I});--ggui-color-elevated:color-mix(in srgb, ${B} 92%, ${I});--ggui-color-sunken:color-mix(in srgb, ${B} 88%, ${I});--ggui-color-onSunken:color-mix(in srgb, ${I} 76%, ${B});--ggui-color-neutral-500:color-mix(in srgb, ${I} 62%, ${B});--ggui-color-outline:${outlineOpen}color-mix(in srgb, ${I} 32%, ${B}));--ggui-color-controlOutline:${outlineOpen}color-mix(in srgb, ${I} 32%, ${B}));--ggui-color-outlineVariant:color-mix(in srgb, ${I} 18%, ${B})}}`;
21200
21250
  }
21201
21251
  var INVERTED_SCOPE_CSS = surfaceScopeCss(
21202
21252
  INVERTED_SCOPE_CLASS,
@@ -21335,7 +21385,7 @@ function Stack(props) {
21335
21385
  return renderWithTrait(Trait, traitProps, { className, style: composedStyle }, children);
21336
21386
  }
21337
21387
  function Row(props) {
21338
- return (0, import_react11.createElement)(Stack, { ...props, direction: "horizontal" });
21388
+ return (0, import_react12.createElement)(Stack, { ...props, direction: "horizontal" });
21339
21389
  }
21340
21390
  var BREAKPOINTS = [
21341
21391
  ["sm", 640],
@@ -21504,7 +21554,7 @@ function Text({ children, size = "base", weight = "normal", caps = false, tone,
21504
21554
  ...style
21505
21555
  };
21506
21556
  const elementProps = { id, htmlFor, className, style: textStyle };
21507
- return (0, import_react12.createElement)(is, elementProps, children);
21557
+ return (0, import_react13.createElement)(is, elementProps, children);
21508
21558
  }
21509
21559
  var fontFamily = {
21510
21560
  sans: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
@@ -21606,7 +21656,7 @@ function Heading({ children, level = 2, tone, align, style, className }) {
21606
21656
  letterSpacing: `var(--ggui-letter-spacing-heading, ${fallback.letterSpacing})`
21607
21657
  };
21608
21658
  const resolvedColor = tone ? resolveToneCss(tone) : "var(--ggui-color-onContainer, #18181b)";
21609
- return (0, import_react13.createElement)(tag, {
21659
+ return (0, import_react14.createElement)(tag, {
21610
21660
  className,
21611
21661
  style: {
21612
21662
  ...headingStyle,
@@ -21695,7 +21745,8 @@ var variantStyles = {
21695
21745
  },
21696
21746
  secondary: {
21697
21747
  backgroundColor: "var(--ggui-color-sunken, #f4f4f5)",
21698
- color: "var(--ggui-color-onSunken, #52525b)",
21748
+ // The label reads at full strength; the chip marks the rank (ggui#1566).
21749
+ color: "var(--ggui-color-onContainer, #18181b)",
21699
21750
  border: "none"
21700
21751
  },
21701
21752
  outline: {
@@ -21704,13 +21755,15 @@ var variantStyles = {
21704
21755
  // label is the surface's own on-colour, never a brand-ladder stop
21705
21756
  // (ggui#1034): `primary-600` as the label read mid-grey on a monochrome
21706
21757
  // dark theme's ground — 2.41:1 / 3.5:1 on served reply chips. The brand
21707
- // stays on the border, where contrast is decorative.
21758
+ // stays on the border, and the border identifies the control, so it is the
21759
+ // first brand stop that clears 3:1 on the container (ggui#1494).
21708
21760
  color: "var(--ggui-color-onContainer, #18181b)",
21709
- border: "1px solid var(--ggui-color-primary-600, #0284c7)"
21761
+ border: "1px solid var(--ggui-color-controlAccentOutline, var(--ggui-color-primary-600, #0284c7))"
21710
21762
  },
21711
21763
  ghost: {
21712
21764
  backgroundColor: "transparent",
21713
- color: "var(--ggui-color-onSunken, #52525b)",
21765
+ // A dimmed label reads as disabled; ghost's rank is its missing chrome (ggui#1566).
21766
+ color: "var(--ggui-color-onContainer, #18181b)",
21714
21767
  border: "none"
21715
21768
  },
21716
21769
  danger: {
@@ -21754,7 +21807,7 @@ var sizeStyles2 = {
21754
21807
  }
21755
21808
  };
21756
21809
  function Input({ label, placeholder, value, onChange, type = "text", error, helperText, required, disabled, size = "md", style, className, ...rest }) {
21757
- const uniqueId = (0, import_react14.useId)();
21810
+ const uniqueId = (0, import_react15.useId)();
21758
21811
  const inputId = `${uniqueId}-input`;
21759
21812
  const messageId = `${uniqueId}-message`;
21760
21813
  const hasError = Boolean(error);
@@ -21772,7 +21825,7 @@ function Input({ label, placeholder, value, onChange, type = "text", error, help
21772
21825
  ...sizeStyles2[size],
21773
21826
  width: "100%",
21774
21827
  borderRadius: "var(--ggui-shape-radius-control, var(--ggui-shape-radius-md, 8px))",
21775
- border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-outline, #d4d4d8)"}`,
21828
+ border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
21776
21829
  backgroundColor: disabled ? "var(--ggui-color-sunken, #fafafa)" : "var(--ggui-color-sunken, #ffffff)",
21777
21830
  color: "var(--ggui-color-onContainer, #18181b)",
21778
21831
  transition: `border-color ${motionVar.duration.base} ${motionVar.easing.standard}, box-shadow ${motionVar.duration.base} ${motionVar.easing.standard}`,
@@ -21783,7 +21836,7 @@ function Input({ label, placeholder, value, onChange, type = "text", error, help
21783
21836
  }, children: error || helperText })] });
21784
21837
  }
21785
21838
  function TextArea({ label, placeholder, value, onChange, rows = 4, error, helperText, required, disabled, maxLength, showCount, autoResize, style, className, ...rest }) {
21786
- const uniqueId = (0, import_react15.useId)();
21839
+ const uniqueId = (0, import_react16.useId)();
21787
21840
  const textareaId = `${uniqueId}-textarea`;
21788
21841
  const messageId = `${uniqueId}-message`;
21789
21842
  const hasError = Boolean(error);
@@ -21802,7 +21855,7 @@ function TextArea({ label, placeholder, value, onChange, rows = 4, error, helper
21802
21855
  padding: "10px 12px",
21803
21856
  width: "100%",
21804
21857
  borderRadius: "var(--ggui-shape-radius-control, var(--ggui-shape-radius-md, 8px))",
21805
- border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-outline, #d4d4d8)"}`,
21858
+ border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
21806
21859
  backgroundColor: disabled ? "var(--ggui-color-sunken, #fafafa)" : "var(--ggui-color-sunken, #ffffff)",
21807
21860
  color: "var(--ggui-color-onContainer, #18181b)",
21808
21861
  fontSize: "var(--ggui-font-size-sm, 14px)",
@@ -21825,22 +21878,30 @@ var sizeStyles3 = {
21825
21878
  lg: { padding: "12px 14px", fontSize: "var(--ggui-font-size-base, 16px)" }
21826
21879
  };
21827
21880
  function Select({ label, value, onChange, options, placeholder, error, helperText, required, disabled, size = "md", style, className, ...rest }) {
21828
- const uniqueId = (0, import_react16.useId)();
21881
+ const uniqueId = (0, import_react17.useId)();
21829
21882
  const selectId = `${uniqueId}-select`;
21830
21883
  const messageId = `${uniqueId}-message`;
21831
21884
  const hasError = Boolean(error);
21832
21885
  const hasMessage = Boolean(error || helperText);
21886
+ const startsOnPlaceholder = Boolean(placeholder) && value === void 0 && rest.defaultValue === void 0;
21887
+ const [uncontrolledValue, setUncontrolledValue] = (0, import_react17.useState)(startsOnPlaceholder ? "" : typeof rest.defaultValue === "string" ? rest.defaultValue : void 0);
21888
+ const showingPlaceholder = Boolean(placeholder) && (value ?? uncontrolledValue) === "";
21833
21889
  return (0, import_jsx_runtime13.jsxs)("div", { className, style: { display: "flex", flexDirection: "column", gap: "var(--ggui-spacing-1, 4px)", ...style }, children: [label && (0, import_jsx_runtime13.jsxs)("label", { htmlFor: selectId, style: {
21834
21890
  fontSize: "var(--ggui-font-size-sm, 14px)",
21835
21891
  fontWeight: "var(--ggui-font-weight-medium, 500)",
21836
21892
  color: "var(--ggui-color-onSunken, #52525b)"
21837
- }, children: [label, required && (0, import_jsx_runtime13.jsx)("span", { "aria-hidden": "true", style: { color: "var(--ggui-color-error-500, #ef4444)", marginLeft: "2px" }, children: "*" })] }), (0, import_jsx_runtime13.jsxs)("select", { id: selectId, value, onChange: (e) => onChange?.(e.target.value), disabled, required, "aria-invalid": hasError || void 0, "aria-describedby": hasMessage ? messageId : void 0, style: {
21893
+ }, children: [label, required && (0, import_jsx_runtime13.jsx)("span", { "aria-hidden": "true", style: { color: "var(--ggui-color-error-500, #ef4444)", marginLeft: "2px" }, children: "*" })] }), (0, import_jsx_runtime13.jsxs)("select", { id: selectId, value, ...startsOnPlaceholder ? { defaultValue: "" } : {}, onChange: (e) => {
21894
+ if (value === void 0)
21895
+ setUncontrolledValue(e.target.value);
21896
+ onChange?.(e.target.value);
21897
+ }, disabled, required, "aria-invalid": hasError || void 0, "aria-describedby": hasMessage ? messageId : void 0, style: {
21838
21898
  ...sizeStyles3[size],
21839
21899
  width: "100%",
21840
21900
  borderRadius: "var(--ggui-shape-radius-control, var(--ggui-shape-radius-md, 8px))",
21841
- border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-outline, #d4d4d8)"}`,
21901
+ border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
21842
21902
  backgroundColor: disabled ? "var(--ggui-color-sunken, #fafafa)" : "var(--ggui-color-sunken, #ffffff)",
21843
- color: value ? "var(--ggui-color-onContainer, #18181b)" : "var(--ggui-color-onSunken, #52525b)",
21903
+ // Muted only while the placeholder is what shows (ggui#1566, #1569).
21904
+ color: showingPlaceholder ? "var(--ggui-color-onSunken, #52525b)" : "var(--ggui-color-onContainer, #18181b)",
21844
21905
  cursor: disabled ? "not-allowed" : "pointer",
21845
21906
  appearance: "none",
21846
21907
  backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M3 4.5L6 7.5L9 4.5'/%3E%3C/svg%3E")`,
@@ -21882,7 +21943,7 @@ function Checkbox({ label, checked, onChange, disabled, description, indetermina
21882
21943
  width: "18px",
21883
21944
  height: "18px",
21884
21945
  borderRadius: "var(--ggui-shape-radius-sm, 4px)",
21885
- border: `2px solid ${checked || indeterminate ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-outline, #d4d4d8)"}`,
21946
+ border: `2px solid ${checked || indeterminate ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
21886
21947
  backgroundColor: checked || indeterminate ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-sunken, #ffffff)",
21887
21948
  display: "flex",
21888
21949
  alignItems: "center",
@@ -21891,7 +21952,7 @@ function Checkbox({ label, checked, onChange, disabled, description, indetermina
21891
21952
  }, children: (checked || indeterminate) && (0, import_jsx_runtime14.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: { color: "var(--ggui-color-onPrimary, #ffffff)" }, children: indeterminate ? (0, import_jsx_runtime14.jsx)("path", { d: "M2.5 6H9.5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) : (0, import_jsx_runtime14.jsx)("path", { d: "M2.5 6L5 8.5L9.5 3.5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] }), (label || description) && (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [label && (0, import_jsx_runtime14.jsx)("span", { style: {
21892
21953
  fontSize: "var(--ggui-font-size-sm, 14px)",
21893
21954
  fontWeight: "var(--ggui-font-weight-medium, 500)",
21894
- color: "var(--ggui-color-onSunken, #52525b)"
21955
+ color: "var(--ggui-color-onContainer, #18181b)"
21895
21956
  }, children: label }), description && (0, import_jsx_runtime14.jsx)("span", { style: {
21896
21957
  fontSize: "var(--ggui-font-size-xs, 12px)",
21897
21958
  color: "var(--ggui-color-onSunken, #52525b)"
@@ -21904,7 +21965,7 @@ var sizeConfig = {
21904
21965
  };
21905
21966
  function Toggle({ label, checked, onChange, disabled, size = "md", style, className }) {
21906
21967
  const config = sizeConfig[size];
21907
- const [focused, setFocused] = (0, import_react17.useState)(false);
21968
+ const [focused, setFocused] = (0, import_react18.useState)(false);
21908
21969
  return (0, import_jsx_runtime15.jsxs)("label", { className, style: {
21909
21970
  display: "flex",
21910
21971
  alignItems: "center",
@@ -21923,7 +21984,7 @@ function Toggle({ label, checked, onChange, disabled, size = "md", style, classN
21923
21984
  width: config.width,
21924
21985
  height: config.height,
21925
21986
  borderRadius: "9999px",
21926
- backgroundColor: checked ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-outline, #d4d4d8)",
21987
+ backgroundColor: checked ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))",
21927
21988
  position: "relative",
21928
21989
  transition: `background-color ${motionVar.duration.base} ${motionVar.easing.standard}, box-shadow ${motionVar.duration.base} ${motionVar.easing.standard}`,
21929
21990
  flexShrink: 0,
@@ -21942,11 +22003,11 @@ function Toggle({ label, checked, onChange, disabled, size = "md", style, classN
21942
22003
  } }) }), label && (0, import_jsx_runtime15.jsx)("span", { style: {
21943
22004
  fontSize: "var(--ggui-font-size-sm, 14px)",
21944
22005
  fontWeight: "var(--ggui-font-weight-medium, 500)",
21945
- color: "var(--ggui-color-onSunken, #52525b)"
22006
+ color: "var(--ggui-color-onContainer, #18181b)"
21946
22007
  }, children: label })] });
21947
22008
  }
21948
22009
  function RadioGroup({ label, value, onChange, options, direction = "vertical", disabled, error, style, className }) {
21949
- const uniqueId = (0, import_react18.useId)();
22010
+ const uniqueId = (0, import_react19.useId)();
21950
22011
  const labelId = `${uniqueId}-label`;
21951
22012
  const errorId = `${uniqueId}-error`;
21952
22013
  const groupName = `${uniqueId}-radio`;
@@ -21986,7 +22047,7 @@ function RadioGroup({ label, value, onChange, options, direction = "vertical", d
21986
22047
  width: "18px",
21987
22048
  height: "18px",
21988
22049
  borderRadius: "var(--ggui-shape-radius-full, 9999px)",
21989
- border: `2px solid ${isSelected ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-outline, #d4d4d8)"}`,
22050
+ border: `2px solid ${isSelected ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
21990
22051
  backgroundColor: "var(--ggui-color-sunken, #ffffff)",
21991
22052
  display: "flex",
21992
22053
  alignItems: "center",
@@ -22000,7 +22061,7 @@ function RadioGroup({ label, value, onChange, options, direction = "vertical", d
22000
22061
  } }) })] }), (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [(0, import_jsx_runtime16.jsx)("span", { style: {
22001
22062
  fontSize: "var(--ggui-font-size-sm, 14px)",
22002
22063
  fontWeight: "var(--ggui-font-weight-medium, 500)",
22003
- color: "var(--ggui-color-onSunken, #52525b)"
22064
+ color: "var(--ggui-color-onContainer, #18181b)"
22004
22065
  }, children: option.label }), option.description && (0, import_jsx_runtime16.jsx)("span", { style: {
22005
22066
  fontSize: "var(--ggui-font-size-xs, 12px)",
22006
22067
  color: "var(--ggui-color-onSunken, #52525b)"
@@ -22011,7 +22072,7 @@ function RadioGroup({ label, value, onChange, options, direction = "vertical", d
22011
22072
  }, children: error })] });
22012
22073
  }
22013
22074
  function Slider({ label, value = 0, onChange, min = 0, max = 100, step = 1, disabled, showValue, style, className }) {
22014
- const uniqueId = (0, import_react19.useId)();
22075
+ const uniqueId = (0, import_react20.useId)();
22015
22076
  const sliderId = `${uniqueId}-slider`;
22016
22077
  const labelId = `${uniqueId}-label`;
22017
22078
  const percentage = (value - min) / (max - min) * 100;
@@ -22142,7 +22203,7 @@ var avatarColors = [
22142
22203
  "var(--ggui-color-info-500, #06b6d4)"
22143
22204
  ];
22144
22205
  function Avatar({ src, name, size = "md", shape = "circle", style, className }) {
22145
- const [imageError, setImageError] = (0, import_react20.useState)(false);
22206
+ const [imageError, setImageError] = (0, import_react21.useState)(false);
22146
22207
  const resolvedSize = typeof size === "number" ? size : sizeMap2[size] || 40;
22147
22208
  const initials = name ? name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2) : "?";
22148
22209
  const getColorFromName = (name2) => {
@@ -22278,7 +22339,7 @@ function Progress({ value, max = 100, variant = "default", size = "md", label, s
22278
22339
  }` })] })] });
22279
22340
  }
22280
22341
  function Image({ src, alt, width, height, objectFit = "cover", radius: radius2, fallback, style, className }) {
22281
- const [error, setError] = (0, import_react21.useState)(false);
22342
+ const [error, setError] = (0, import_react22.useState)(false);
22282
22343
  const resolveSize2 = (value) => {
22283
22344
  if (value === void 0)
22284
22345
  return void 0;
@@ -26839,7 +26900,7 @@ function resolveLucideName(name) {
26839
26900
  return LUCIDE_LOOKUP.get(normalized);
26840
26901
  }
26841
26902
  function renderLucideIcon(data, size, color) {
26842
- return (0, import_jsx_runtime24.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: data.map(([tag, attrs], i) => import_react22.default.createElement(tag, { key: i, ...attrs })) });
26903
+ return (0, import_jsx_runtime24.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: data.map(([tag, attrs], i) => import_react23.default.createElement(tag, { key: i, ...attrs })) });
26843
26904
  }
26844
26905
  function Icon({ name, size = 24, tone, children, style, className, "aria-label": ariaLabel }) {
26845
26906
  const iconColor = tone ? resolveToneCss(tone) : "currentColor";
@@ -26895,10 +26956,10 @@ function Link({ children, href, external, tone, underline = "hover", style, clas
26895
26956
  }, ...rest, children: [children, external && (0, import_jsx_runtime25.jsxs)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", style: { marginLeft: "4px", verticalAlign: "middle" }, children: [(0, import_jsx_runtime25.jsx)("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), (0, import_jsx_runtime25.jsx)("polyline", { points: "15 3 21 3 21 9" }), (0, import_jsx_runtime25.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] })] });
26896
26957
  }
26897
26958
  function Tooltip({ children, content, position = "top", delay = 200, style, className }) {
26898
- const [visible, setVisible] = (0, import_react23.useState)(false);
26899
- const [coords, setCoords] = (0, import_react23.useState)({ top: 0, left: 0 });
26900
- const triggerRef = (0, import_react23.useRef)(null);
26901
- const timeoutRef = (0, import_react23.useRef)(null);
26959
+ const [visible, setVisible] = (0, import_react24.useState)(false);
26960
+ const [coords, setCoords] = (0, import_react24.useState)({ top: 0, left: 0 });
26961
+ const triggerRef = (0, import_react24.useRef)(null);
26962
+ const timeoutRef = (0, import_react24.useRef)(null);
26902
26963
  const showTooltip = () => {
26903
26964
  timeoutRef.current = setTimeout(() => {
26904
26965
  setVisible(true);
@@ -26910,7 +26971,7 @@ function Tooltip({ children, content, position = "top", delay = 200, style, clas
26910
26971
  }
26911
26972
  setVisible(false);
26912
26973
  };
26913
- (0, import_react23.useEffect)(() => {
26974
+ (0, import_react24.useEffect)(() => {
26914
26975
  if (visible && triggerRef.current) {
26915
26976
  const rect = triggerRef.current.getBoundingClientRect();
26916
26977
  const offset = 8;
@@ -26937,7 +26998,7 @@ function Tooltip({ children, content, position = "top", delay = 200, style, clas
26937
26998
  setCoords({ top, left });
26938
26999
  }
26939
27000
  }, [visible, position]);
26940
- (0, import_react23.useEffect)(() => {
27001
+ (0, import_react24.useEffect)(() => {
26941
27002
  return () => {
26942
27003
  if (timeoutRef.current) {
26943
27004
  clearTimeout(timeoutRef.current);
@@ -26986,7 +27047,7 @@ var sortIndicator = (active, direction) => (0, import_jsx_runtime27.jsxs)("span"
26986
27047
  opacity: active ? 1 : 0.3
26987
27048
  }, children: [(0, import_jsx_runtime27.jsx)("span", { style: { opacity: active && direction === "asc" ? 1 : 0.4 }, children: "\u25B2" }), (0, import_jsx_runtime27.jsx)("span", { style: { opacity: active && direction === "desc" ? 1 : 0.4 }, children: "\u25BC" })] });
26988
27049
  function Table({ columns, data, sortKey, sortDirection = "asc", onSort, striped = false, hoverable = true, compact = false, bordered = false, caption, style, className }) {
26989
- const [hoveredRow, setHoveredRow] = (0, import_react24.useState)(null);
27050
+ const [hoveredRow, setHoveredRow] = (0, import_react25.useState)(null);
26990
27051
  const cellPadding = compact ? "var(--ggui-spacing-1, 4px) var(--ggui-spacing-2, 8px)" : "var(--ggui-spacing-2, 8px) var(--ggui-spacing-4, 16px)";
26991
27052
  const handleSort = (key) => {
26992
27053
  if (!onSort)
@@ -27015,7 +27076,9 @@ function Table({ columns, data, sortKey, sortDirection = "asc", onSort, striped
27015
27076
  width: "100%",
27016
27077
  borderCollapse: "collapse",
27017
27078
  fontSize: "var(--ggui-font-size-sm, 14px)",
27018
- color: "var(--ggui-color-onSunken, #52525b)"
27079
+ // Body cells are the data and inherit this (ggui#1566); the header and
27080
+ // caption set the muted tier themselves.
27081
+ color: "var(--ggui-color-onContainer, #18181b)"
27019
27082
  }, children: [caption && (0, import_jsx_runtime27.jsx)("caption", { style: {
27020
27083
  padding: cellPadding,
27021
27084
  fontSize: "var(--ggui-font-size-sm, 14px)",
@@ -27057,10 +27120,10 @@ var sizeStyles5 = {
27057
27120
  }
27058
27121
  };
27059
27122
  function Tabs({ items, activeKey, onChange, variant = "line", size = "md", fullWidth = false, style, className }) {
27060
- const uniqueId = (0, import_react25.useId)();
27061
- const [internalKey, setInternalKey] = (0, import_react25.useState)(items[0]?.key);
27123
+ const uniqueId = (0, import_react26.useId)();
27124
+ const [internalKey, setInternalKey] = (0, import_react26.useState)(items[0]?.key);
27062
27125
  const currentKey = activeKey ?? internalKey;
27063
- const handleChange = (0, import_react25.useCallback)((key) => {
27126
+ const handleChange = (0, import_react26.useCallback)((key) => {
27064
27127
  if (onChange) {
27065
27128
  onChange(key);
27066
27129
  } else {
@@ -27068,8 +27131,8 @@ function Tabs({ items, activeKey, onChange, variant = "line", size = "md", fullW
27068
27131
  }
27069
27132
  }, [onChange]);
27070
27133
  const activeItem = items.find((item) => item.key === currentKey);
27071
- const tabListRef = (0, import_react25.useRef)(null);
27072
- const handleTabKeyDown = (0, import_react25.useCallback)((e) => {
27134
+ const tabListRef = (0, import_react26.useRef)(null);
27135
+ const handleTabKeyDown = (0, import_react26.useCallback)((e) => {
27073
27136
  const enabledItems = items.filter((item) => !item.disabled);
27074
27137
  const currentIndex = enabledItems.findIndex((item) => item.key === currentKey);
27075
27138
  let nextIndex;
@@ -27333,7 +27396,7 @@ var defaultIcons2 = {
27333
27396
  error: (0, import_jsx_runtime29.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "currentColor", children: (0, import_jsx_runtime29.jsx)("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z", clipRule: "evenodd" }) })
27334
27397
  };
27335
27398
  function Toast({ message, variant = "info", title, duration: duration2 = 5e3, onClose, visible = true, style, className }) {
27336
- (0, import_react26.useEffect)(() => {
27399
+ (0, import_react27.useEffect)(() => {
27337
27400
  if (!visible || duration2 === 0 || !onClose)
27338
27401
  return;
27339
27402
  const timer = setTimeout(onClose, duration2);
@@ -27391,8 +27454,8 @@ var chevron = (expanded) => (0, import_jsx_runtime30.jsx)("svg", { width: "16",
27391
27454
  flexShrink: 0
27392
27455
  }, children: (0, import_jsx_runtime30.jsx)("path", { fillRule: "evenodd", d: "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z", clipRule: "evenodd" }) });
27393
27456
  function Accordion({ items, expandedKeys, onChange, multiple = false, variant = "default", style, className }) {
27394
- const uniqueId = (0, import_react27.useId)();
27395
- const [internalExpanded, setInternalExpanded] = (0, import_react27.useState)([]);
27457
+ const uniqueId = (0, import_react28.useId)();
27458
+ const [internalExpanded, setInternalExpanded] = (0, import_react28.useState)([]);
27396
27459
  const currentExpanded = expandedKeys ?? internalExpanded;
27397
27460
  const handleToggle = (key) => {
27398
27461
  let newExpanded;
@@ -27465,14 +27528,14 @@ function Accordion({ items, expandedKeys, onChange, multiple = false, variant =
27465
27528
  }, children: isExpanded && (0, import_jsx_runtime30.jsx)("div", { style: {
27466
27529
  padding: "0 var(--ggui-spacing-4, 16px) var(--ggui-spacing-4, 16px)",
27467
27530
  fontSize: "var(--ggui-font-size-sm, 14px)",
27468
- color: "var(--ggui-color-onSunken, #52525b)",
27531
+ color: "var(--ggui-color-onContainer, #18181b)",
27469
27532
  lineHeight: "var(--ggui-font-lineHeight-normal, 1.5)"
27470
27533
  }, children: item.content }) })] }, item.key);
27471
27534
  }) });
27472
27535
  }
27473
27536
  var STYLE_ID = "ggui-motion-keyframes";
27474
27537
  function MotionKeyframes() {
27475
- (0, import_react28.useEffect)(() => {
27538
+ (0, import_react29.useEffect)(() => {
27476
27539
  if (document.getElementById(STYLE_ID))
27477
27540
  return;
27478
27541
  const styleEl = document.createElement("style");
@@ -27489,12 +27552,12 @@ function MotionKeyframes() {
27489
27552
  return null;
27490
27553
  }
27491
27554
  function useMotion() {
27492
- const [motionEnabled, setMotionEnabled] = (0, import_react28.useState)(() => {
27555
+ const [motionEnabled, setMotionEnabled] = (0, import_react29.useState)(() => {
27493
27556
  if (typeof window === "undefined")
27494
27557
  return true;
27495
27558
  return !window.matchMedia("(prefers-reduced-motion: reduce)").matches;
27496
27559
  });
27497
- (0, import_react28.useEffect)(() => {
27560
+ (0, import_react29.useEffect)(() => {
27498
27561
  const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
27499
27562
  const handler = (e) => setMotionEnabled(!e.matches);
27500
27563
  mq.addEventListener("change", handler);
@@ -27503,9 +27566,9 @@ function useMotion() {
27503
27566
  return { motionEnabled };
27504
27567
  }
27505
27568
  function useAnimationKey(dep) {
27506
- const [key, setKey] = (0, import_react28.useState)(0);
27507
- const isFirst = (0, import_react28.useRef)(true);
27508
- (0, import_react28.useEffect)(() => {
27569
+ const [key, setKey] = (0, import_react29.useState)(0);
27570
+ const isFirst = (0, import_react29.useRef)(true);
27571
+ (0, import_react29.useEffect)(() => {
27509
27572
  if (isFirst.current) {
27510
27573
  isFirst.current = false;
27511
27574
  return;
@@ -27532,7 +27595,7 @@ __export2(components_exports, {
27532
27595
  renderRichTextInlines: () => renderRichTextInlines
27533
27596
  });
27534
27597
  function SearchField({ value: controlledValue, onChange, onSearch, placeholder = "Search...", showButton = false, buttonText = "Search", loading, disabled, size = "md", style, className }) {
27535
- const [internalValue, setInternalValue] = (0, import_react29.useState)("");
27598
+ const [internalValue, setInternalValue] = (0, import_react30.useState)("");
27536
27599
  const value = controlledValue !== void 0 ? controlledValue : internalValue;
27537
27600
  const handleChange = (newValue) => {
27538
27601
  if (controlledValue === void 0) {
@@ -27573,7 +27636,7 @@ function SearchField({ value: controlledValue, onChange, onSearch, placeholder =
27573
27636
  paddingLeft: "36px",
27574
27637
  fontSize: size === "lg" ? "16px" : "14px",
27575
27638
  borderRadius: "6px",
27576
- border: `1px solid var(--ggui-color-outline, #d1d5db)`,
27639
+ border: `1px solid var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))`,
27577
27640
  backgroundColor: disabled ? "var(--ggui-color-sunken, #f9fafb)" : "var(--ggui-color-container, #ffffff)",
27578
27641
  color: "var(--ggui-color-onContainer, #111827)",
27579
27642
  outline: "none",
@@ -27693,9 +27756,9 @@ function Tag({ children, variant = "default", size = "md", closable, onClose, ic
27693
27756
  }, "aria-label": "Remove", children: (0, import_jsx_runtime34.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "currentColor", children: (0, import_jsx_runtime34.jsx)("path", { d: "M9.5 3.205L8.795 2.5 6 5.295 3.205 2.5l-.705.705L5.295 6 2.5 8.795l.705.705L6 6.705 8.795 9.5l.705-.705L6.705 6 9.5 3.205z" }) }) })] });
27694
27757
  }
27695
27758
  function Dropdown({ trigger, options, value, onChange, placement = "bottom-start", disabled, style, className }) {
27696
- const [isOpen, setIsOpen] = (0, import_react30.useState)(false);
27697
- const containerRef = (0, import_react30.useRef)(null);
27698
- (0, import_react30.useEffect)(() => {
27759
+ const [isOpen, setIsOpen] = (0, import_react31.useState)(false);
27760
+ const containerRef = (0, import_react31.useRef)(null);
27761
+ (0, import_react31.useEffect)(() => {
27699
27762
  const handleClickOutside = (event) => {
27700
27763
  if (containerRef.current && !containerRef.current.contains(event.target)) {
27701
27764
  setIsOpen(false);
@@ -27706,7 +27769,7 @@ function Dropdown({ trigger, options, value, onChange, placement = "bottom-start
27706
27769
  return () => document.removeEventListener("mousedown", handleClickOutside);
27707
27770
  }
27708
27771
  }, [isOpen]);
27709
- (0, import_react30.useEffect)(() => {
27772
+ (0, import_react31.useEffect)(() => {
27710
27773
  const handleEscape = (event) => {
27711
27774
  if (event.key === "Escape") {
27712
27775
  setIsOpen(false);
@@ -27753,16 +27816,16 @@ function Dropdown({ trigger, options, value, onChange, placement = "bottom-start
27753
27816
  }, children: options.map((option) => (0, import_jsx_runtime35.jsx)(MenuItem, { label: option.label, icon: option.icon, onClick: () => handleSelect(option.value), disabled: option.disabled, active: value === option.value, danger: option.danger }, option.value)) })] });
27754
27817
  }
27755
27818
  function Autocomplete({ value = "", onChange, onSelect, options, placeholder, label, loading, disabled, error, noResultsText = "No results found", style, className }) {
27756
- const [isOpen, setIsOpen] = (0, import_react31.useState)(false);
27757
- const [highlightedIndex, setHighlightedIndex] = (0, import_react31.useState)(-1);
27758
- const containerRef = (0, import_react31.useRef)(null);
27759
- const filteredOptions = (0, import_react31.useMemo)(() => {
27819
+ const [isOpen, setIsOpen] = (0, import_react32.useState)(false);
27820
+ const [highlightedIndex, setHighlightedIndex] = (0, import_react32.useState)(-1);
27821
+ const containerRef = (0, import_react32.useRef)(null);
27822
+ const filteredOptions = (0, import_react32.useMemo)(() => {
27760
27823
  if (!value)
27761
27824
  return options;
27762
27825
  const lowerValue = value.toLowerCase();
27763
27826
  return options.filter((opt) => opt.label.toLowerCase().includes(lowerValue) || opt.value.toLowerCase().includes(lowerValue));
27764
27827
  }, [options, value]);
27765
- (0, import_react31.useEffect)(() => {
27828
+ (0, import_react32.useEffect)(() => {
27766
27829
  const handleClickOutside = (event) => {
27767
27830
  if (containerRef.current && !containerRef.current.contains(event.target)) {
27768
27831
  setIsOpen(false);
@@ -27851,7 +27914,7 @@ function Breadcrumb({ items, separator = "/", onItemClick, style, className }) {
27851
27914
  ...style
27852
27915
  }, children: items.map((item, index) => {
27853
27916
  const isLast = index === items.length - 1;
27854
- return (0, import_jsx_runtime37.jsxs)(import_react32.Fragment, { children: [index > 0 && (0, import_jsx_runtime37.jsx)("span", { style: { color: "var(--ggui-color-neutral-400, #9ca3af)" }, children: separator }), item.icon && (0, import_jsx_runtime37.jsx)("span", { style: {
27917
+ return (0, import_jsx_runtime37.jsxs)(import_react33.Fragment, { children: [index > 0 && (0, import_jsx_runtime37.jsx)("span", { style: { color: "var(--ggui-color-neutral-400, #9ca3af)" }, children: separator }), item.icon && (0, import_jsx_runtime37.jsx)("span", { style: {
27855
27918
  display: "flex",
27856
27919
  alignItems: "center",
27857
27920
  color: isLast ? "var(--ggui-color-onContainer, #111827)" : "var(--ggui-color-neutral-500, #6b7280)"
@@ -28499,7 +28562,7 @@ function Header({ logo, navigation: navigation2, actions, sticky = false, backgr
28499
28562
  }, children: [logo && (0, import_jsx_runtime43.jsx)("div", { style: { flexShrink: 0 }, children: logo }), navigation2 && (0, import_jsx_runtime43.jsx)("nav", { style: { display: "flex", alignItems: "center", flex: 1, marginLeft: "32px" }, children: navigation2 }), actions && (0, import_jsx_runtime43.jsx)("div", { style: { display: "flex", alignItems: "center", gap: "12px", flexShrink: 0 }, children: actions })] });
28500
28563
  }
28501
28564
  function SidebarItem({ item, activeId, onItemClick, collapsed, depth = 0 }) {
28502
- const [expanded, setExpanded] = (0, import_react33.useState)(false);
28565
+ const [expanded, setExpanded] = (0, import_react34.useState)(false);
28503
28566
  const hasChildren = item.children && item.children.length > 0;
28504
28567
  const isActive = activeId === item.id;
28505
28568
  const handleClick = () => {
@@ -28568,8 +28631,8 @@ function CardGrid({ children, columns = 3, gap = 16, style, className }) {
28568
28631
  }, children });
28569
28632
  }
28570
28633
  function CommentItem({ comment, onReply, onReaction, depth = 0 }) {
28571
- const [showReplyInput, setShowReplyInput] = (0, import_react34.useState)(false);
28572
- const [replyContent, setReplyContent] = (0, import_react34.useState)("");
28634
+ const [showReplyInput, setShowReplyInput] = (0, import_react35.useState)(false);
28635
+ const [replyContent, setReplyContent] = (0, import_react35.useState)("");
28573
28636
  const handleSubmitReply = () => {
28574
28637
  if (replyContent.trim()) {
28575
28638
  onReply?.(comment.id, replyContent);
@@ -28594,7 +28657,7 @@ function CommentItem({ comment, onReply, onReaction, depth = 0 }) {
28594
28657
  }, children: "Reply" })] }), showReplyInput && (0, import_jsx_runtime46.jsxs)("div", { style: { marginTop: "12px" }, children: [(0, import_jsx_runtime46.jsx)(TextArea, { value: replyContent, onChange: setReplyContent, placeholder: "Write a reply...", rows: 2 }), (0, import_jsx_runtime46.jsxs)("div", { style: { display: "flex", gap: "8px", marginTop: "8px" }, children: [(0, import_jsx_runtime46.jsx)(Button, { size: "sm", onClick: handleSubmitReply, children: "Reply" }), (0, import_jsx_runtime46.jsx)(Button, { size: "sm", variant: "ghost", onClick: () => setShowReplyInput(false), children: "Cancel" })] })] })] })] }), comment.replies?.map((reply) => (0, import_jsx_runtime46.jsx)("div", { style: { marginTop: "16px" }, children: (0, import_jsx_runtime46.jsx)(CommentItem, { comment: reply, onReply, onReaction, depth: depth + 1 }) }, reply.id))] });
28595
28658
  }
28596
28659
  function CommentThread({ comments, currentUser, onAddComment, onReply, onReaction, loading, style, className }) {
28597
- const [newComment, setNewComment] = (0, import_react34.useState)("");
28660
+ const [newComment, setNewComment] = (0, import_react35.useState)("");
28598
28661
  const handleSubmit = () => {
28599
28662
  if (newComment.trim()) {
28600
28663
  onAddComment?.(newComment);
@@ -28659,9 +28722,9 @@ function DataTable({ columns, data, rowKey = "id", loading, emptyText = "No data
28659
28722
  }) })] }) });
28660
28723
  }
28661
28724
  function ChatWindow({ messages, currentUserId, onSendMessage, loading, typing, placeholder = "Type a message...", header, style, className }) {
28662
- const [inputValue, setInputValue] = (0, import_react35.useState)("");
28663
- const messagesEndRef = (0, import_react35.useRef)(null);
28664
- (0, import_react35.useEffect)(() => {
28725
+ const [inputValue, setInputValue] = (0, import_react36.useState)("");
28726
+ const messagesEndRef = (0, import_react36.useRef)(null);
28727
+ (0, import_react36.useEffect)(() => {
28665
28728
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
28666
28729
  }, [messages]);
28667
28730
  const handleSend = () => {
@@ -28708,14 +28771,17 @@ function ChatWindow({ messages, currentUserId, onSendMessage, loading, typing, p
28708
28771
  padding: "10px 14px",
28709
28772
  borderRadius: radius.lg,
28710
28773
  backgroundColor: isOwn ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-sunken, #f3f4f6)",
28711
- color: isOwn ? "var(--ggui-color-onPrimary, #ffffff)" : "var(--ggui-color-onSunken, #111827)"
28774
+ color: isOwn ? "var(--ggui-color-onPrimary, #ffffff)" : "var(--ggui-color-onContainer, #111827)"
28712
28775
  }, children: [(0, import_jsx_runtime48.jsx)("p", { style: { margin: 0, fontSize: fontSize.sm }, children: message.content }), (0, import_jsx_runtime48.jsxs)("div", { style: {
28713
28776
  display: "flex",
28714
28777
  alignItems: "center",
28715
28778
  gap: "4px",
28716
28779
  marginTop: "4px",
28717
28780
  fontSize: fontSize.xs,
28718
- opacity: 0.7
28781
+ // Own messages derive the muted line from onPrimary; the other
28782
+ // party's message now reads at onContainer, so its timestamp
28783
+ // takes the muted tier itself (ggui#1566).
28784
+ ...isOwn ? { opacity: 0.7 } : { color: "var(--ggui-color-onSunken, #52525b)" }
28719
28785
  }, children: [(0, import_jsx_runtime48.jsx)("span", { children: timestamp }), isOwn && message.status && (0, import_jsx_runtime48.jsxs)("span", { children: [message.status === "sending" && "\u2022", message.status === "sent" && "\u2713", message.status === "delivered" && "\u2713\u2713", message.status === "read" && "\u2713\u2713", message.status === "error" && "!"] })] })] })] }, message.id);
28720
28786
  }), typing && (0, import_jsx_runtime48.jsx)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: (0, import_jsx_runtime48.jsxs)("span", { style: { fontSize: fontSize.xs, color: "var(--ggui-color-neutral-500, #6b7280)" }, children: [typing.name, " is typing..."] }) }), (0, import_jsx_runtime48.jsx)("div", { ref: messagesEndRef })] }), (0, import_jsx_runtime48.jsxs)("div", { style: {
28721
28787
  padding: "12px 16px",
@@ -28725,7 +28791,7 @@ function ChatWindow({ messages, currentUserId, onSendMessage, loading, typing, p
28725
28791
  }, children: [(0, import_jsx_runtime48.jsx)("input", { type: "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyDown: handleKeyDown, placeholder, style: {
28726
28792
  flex: 1,
28727
28793
  padding: "10px 14px",
28728
- border: `1px solid var(--ggui-color-outline, #d1d5db)`,
28794
+ border: `1px solid var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))`,
28729
28795
  borderRadius: radius.full,
28730
28796
  fontSize: fontSize.sm,
28731
28797
  outline: "none"
@@ -28799,8 +28865,8 @@ function formatFileSize(bytes) {
28799
28865
  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
28800
28866
  }
28801
28867
  function FileUploader({ files = [], onFilesSelected, onFileRemove, accept, multiple = true, maxSize, maxFiles, disabled, dragDrop = true, style, className }) {
28802
- const [isDragOver, setIsDragOver] = (0, import_react36.useState)(false);
28803
- const inputRef = (0, import_react36.useRef)(null);
28868
+ const [isDragOver, setIsDragOver] = (0, import_react37.useState)(false);
28869
+ const inputRef = (0, import_react37.useRef)(null);
28804
28870
  const handleFiles = (fileList) => {
28805
28871
  if (!fileList)
28806
28872
  return;
@@ -28830,7 +28896,7 @@ function FileUploader({ files = [], onFilesSelected, onFileRemove, accept, multi
28830
28896
  setIsDragOver(false);
28831
28897
  };
28832
28898
  return (0, import_jsx_runtime50.jsxs)("div", { className, style: { ...style }, children: [(0, import_jsx_runtime50.jsxs)("div", { onClick: () => !disabled && inputRef.current?.click(), onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, style: {
28833
- border: `2px dashed ${isDragOver ? "var(--ggui-color-primary-400, #38bdf8)" : "var(--ggui-color-outline, #d1d5db)"}`,
28899
+ border: `2px dashed ${isDragOver ? "var(--ggui-color-primary-400, #38bdf8)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))"}`,
28834
28900
  borderRadius: radius.lg,
28835
28901
  padding: "32px",
28836
28902
  textAlign: "center",
@@ -28939,12 +29005,12 @@ var sizeWidths = {
28939
29005
  full: "100vw"
28940
29006
  };
28941
29007
  function Modal({ open, onClose, title, children, footer, size = "md", closeOnOverlayClick = true, closeOnEscape = true, showCloseButton = true, style, className }) {
28942
- const handleEscape = (0, import_react37.useCallback)((e) => {
29008
+ const handleEscape = (0, import_react38.useCallback)((e) => {
28943
29009
  if (e.key === "Escape" && closeOnEscape) {
28944
29010
  onClose();
28945
29011
  }
28946
29012
  }, [closeOnEscape, onClose]);
28947
- (0, import_react37.useEffect)(() => {
29013
+ (0, import_react38.useEffect)(() => {
28948
29014
  if (open) {
28949
29015
  document.addEventListener("keydown", handleEscape);
28950
29016
  document.body.style.overflow = "hidden";
@@ -29009,9 +29075,9 @@ function Modal({ open, onClose, title, children, footer, size = "md", closeOnOve
29009
29075
  }, children: footer })] })] });
29010
29076
  }
29011
29077
  function CommandPalette({ open, onClose, commands, onSelect, placeholder = "Search commands...", recentIds = [], loading, style, className }) {
29012
- const [query, setQuery] = (0, import_react38.useState)("");
29013
- const [selectedIndex, setSelectedIndex] = (0, import_react38.useState)(0);
29014
- const filteredCommands = (0, import_react38.useMemo)(() => {
29078
+ const [query, setQuery] = (0, import_react39.useState)("");
29079
+ const [selectedIndex, setSelectedIndex] = (0, import_react39.useState)(0);
29080
+ const filteredCommands = (0, import_react39.useMemo)(() => {
29015
29081
  const filtered = query ? commands.filter((cmd) => cmd.label.toLowerCase().includes(query.toLowerCase()) || cmd.description?.toLowerCase().includes(query.toLowerCase())) : commands;
29016
29082
  const groups = /* @__PURE__ */ new Map();
29017
29083
  if (!query && recentIds.length > 0) {
@@ -29032,21 +29098,21 @@ function CommandPalette({ open, onClose, commands, onSelect, placeholder = "Sear
29032
29098
  });
29033
29099
  return groups;
29034
29100
  }, [commands, query, recentIds]);
29035
- const flatCommands = (0, import_react38.useMemo)(() => {
29101
+ const flatCommands = (0, import_react39.useMemo)(() => {
29036
29102
  const flat = [];
29037
29103
  filteredCommands.forEach((cmds) => flat.push(...cmds));
29038
29104
  return flat;
29039
29105
  }, [filteredCommands]);
29040
- (0, import_react38.useEffect)(() => {
29106
+ (0, import_react39.useEffect)(() => {
29041
29107
  setSelectedIndex(0);
29042
29108
  }, [query]);
29043
- (0, import_react38.useEffect)(() => {
29109
+ (0, import_react39.useEffect)(() => {
29044
29110
  if (open) {
29045
29111
  setQuery("");
29046
29112
  setSelectedIndex(0);
29047
29113
  }
29048
29114
  }, [open]);
29049
- const handleKeyDown = (0, import_react38.useCallback)((e) => {
29115
+ const handleKeyDown = (0, import_react39.useCallback)((e) => {
29050
29116
  if (e.key === "Escape") {
29051
29117
  onClose();
29052
29118
  return;
@@ -29066,7 +29132,7 @@ function CommandPalette({ open, onClose, commands, onSelect, placeholder = "Sear
29066
29132
  }
29067
29133
  }
29068
29134
  }, [flatCommands, selectedIndex, onSelect, onClose]);
29069
- (0, import_react38.useEffect)(() => {
29135
+ (0, import_react39.useEffect)(() => {
29070
29136
  if (open) {
29071
29137
  document.addEventListener("keydown", handleKeyDown);
29072
29138
  return () => document.removeEventListener("keydown", handleKeyDown);
@@ -29296,7 +29362,7 @@ function Hero({ heading, description, primaryAction, secondaryAction, media, ali
29296
29362
  fontWeight: fontWeight.semibold,
29297
29363
  color: showOverlay ? "#ffffff" : "var(--ggui-color-onContainer, #374151)",
29298
29364
  backgroundColor: "transparent",
29299
- border: `1px solid ${showOverlay ? "rgba(255,255,255,0.3)" : "var(--ggui-color-outline, #d1d5db)"}`,
29365
+ border: `1px solid ${showOverlay ? "rgba(255,255,255,0.3)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))"}`,
29300
29366
  borderRadius: "8px",
29301
29367
  cursor: "pointer",
29302
29368
  transition: "all 0.15s",
@@ -29315,9 +29381,9 @@ __export2(interact_exports, {
29315
29381
  Hoverable: () => Hoverable,
29316
29382
  Pressable: () => Pressable
29317
29383
  });
29318
- var Clickable = (0, import_react39.forwardRef)(function Clickable2({ children, onClick, onDoubleClick, hoverStyle, activeStyle, cursor, transition: transition2 = "all 200ms ease", disabled = false, role, "aria-label": ariaLabel, tabIndex, style, className, ...rest }, ref) {
29319
- const [hovered, setHovered] = (0, import_react39.useState)(false);
29320
- const [active, setActive] = (0, import_react39.useState)(false);
29384
+ var Clickable = (0, import_react40.forwardRef)(function Clickable2({ children, onClick, onDoubleClick, hoverStyle, activeStyle, cursor, transition: transition2 = "all 200ms ease", disabled = false, role, "aria-label": ariaLabel, tabIndex, style, className, ...rest }, ref) {
29385
+ const [hovered, setHovered] = (0, import_react40.useState)(false);
29386
+ const [active, setActive] = (0, import_react40.useState)(false);
29321
29387
  const hasClick = !!onClick;
29322
29388
  const resolvedCursor = disabled ? "not-allowed" : cursor ?? (hasClick ? "pointer" : void 0);
29323
29389
  const resolvedRole = role ?? (hasClick ? "button" : void 0);
@@ -29343,8 +29409,8 @@ var Clickable = (0, import_react39.forwardRef)(function Clickable2({ children, o
29343
29409
  setActive(false);
29344
29410
  }, onMouseDown: () => setActive(true), onMouseUp: () => setActive(false), onKeyDown: handleKeyDown, role: resolvedRole, "aria-label": ariaLabel, "aria-disabled": disabled || void 0, tabIndex: resolvedTabIndex, ...rest, children });
29345
29411
  });
29346
- var Hoverable = (0, import_react40.forwardRef)(function Hoverable2({ children, hoverStyle, onHoverChange, transition: transition2 = "all 200ms ease", style, className, ...rest }, ref) {
29347
- const [hovered, setHovered] = (0, import_react40.useState)(false);
29412
+ var Hoverable = (0, import_react41.forwardRef)(function Hoverable2({ children, hoverStyle, onHoverChange, transition: transition2 = "all 200ms ease", style, className, ...rest }, ref) {
29413
+ const [hovered, setHovered] = (0, import_react41.useState)(false);
29348
29414
  const mergedStyle = {
29349
29415
  ...style,
29350
29416
  transition: transition2,
@@ -29358,10 +29424,10 @@ var Hoverable = (0, import_react40.forwardRef)(function Hoverable2({ children, h
29358
29424
  onHoverChange?.(false);
29359
29425
  }, ...rest, children });
29360
29426
  });
29361
- var Pressable = (0, import_react41.forwardRef)(function Pressable2({ children, onPress, onLongPress, longPressDelay = 500, hoverStyle, pressStyle, disabled = false, transition: transition2 = "all 150ms ease", role, "aria-label": ariaLabel, tabIndex, style, className, ...rest }, ref) {
29362
- const [hovered, setHovered] = (0, import_react41.useState)(false);
29363
- const [pressed, setPressed] = (0, import_react41.useState)(false);
29364
- const [longPressTimer, setLongPressTimer] = (0, import_react41.useState)(null);
29427
+ var Pressable = (0, import_react42.forwardRef)(function Pressable2({ children, onPress, onLongPress, longPressDelay = 500, hoverStyle, pressStyle, disabled = false, transition: transition2 = "all 150ms ease", role, "aria-label": ariaLabel, tabIndex, style, className, ...rest }, ref) {
29428
+ const [hovered, setHovered] = (0, import_react42.useState)(false);
29429
+ const [pressed, setPressed] = (0, import_react42.useState)(false);
29430
+ const [longPressTimer, setLongPressTimer] = (0, import_react42.useState)(null);
29365
29431
  const hasPress = !!onPress || !!onLongPress;
29366
29432
  const handleMouseDown = (e) => {
29367
29433
  if (disabled)
@@ -29418,6 +29484,8 @@ var consumed_tokens_manifest_default = {
29418
29484
  version: 2,
29419
29485
  tokens: [
29420
29486
  "--ggui-color-container",
29487
+ "--ggui-color-controlAccentOutline",
29488
+ "--ggui-color-controlOutline",
29421
29489
  "--ggui-color-elevated",
29422
29490
  "--ggui-color-error",
29423
29491
  "--ggui-color-error-100",
@@ -29715,17 +29783,20 @@ function scrimTint(tone) {
29715
29783
  return "#000000";
29716
29784
  return tokenValue(tone);
29717
29785
  }
29718
- function familyRamp(group, anchor) {
29786
+ function familyRamp(group, anchor, ground) {
29719
29787
  const statedStops = {};
29720
29788
  for (const stop of STOPS) {
29721
29789
  const v = stated(group, stop);
29722
29790
  if (v !== void 0)
29723
29791
  statedStops[stop] = v;
29724
29792
  }
29725
- return rampFrom(statedStops, anchor);
29793
+ return rampFrom(statedStops, anchor, ground);
29726
29794
  }
29727
- function rampFrom(statedStops, anchor) {
29795
+ var NEUTRAL_ANCHOR_CHROMA = 0.02;
29796
+ var LIGHT_STOP_COUNT = 5;
29797
+ function rampFrom(statedStops, anchor, ground) {
29728
29798
  const a = hexToOklch(anchor);
29799
+ const g = ground !== void 0 && a.c < NEUTRAL_ANCHOR_CHROMA ? hexToOklch(ground) : void 0;
29729
29800
  const out = {};
29730
29801
  STOPS.forEach((stop, i) => {
29731
29802
  const v = statedStops[stop];
@@ -29733,7 +29804,16 @@ function rampFrom(statedStops, anchor) {
29733
29804
  out[stop] = v;
29734
29805
  return;
29735
29806
  }
29736
- out[stop] = stop === "500" ? anchor : oklchToHex({ l: RAMP_L[i], c: a.c * RAMP_C[i], h: a.h });
29807
+ if (stop === "500") {
29808
+ out[stop] = anchor;
29809
+ return;
29810
+ }
29811
+ if (g !== void 0 && i < LIGHT_STOP_COUNT) {
29812
+ const t = g.l === a.l ? 1 : Math.min(1, Math.max(0, (RAMP_L[i] - g.l) / (a.l - g.l)));
29813
+ out[stop] = oklchToHex({ l: RAMP_L[i], c: g.c + (a.c - g.c) * t, h: g.h });
29814
+ return;
29815
+ }
29816
+ out[stop] = oklchToHex({ l: RAMP_L[i], c: a.c * RAMP_C[i], h: a.h });
29737
29817
  });
29738
29818
  return out;
29739
29819
  }
@@ -29759,11 +29839,11 @@ function readableOutline(bg, ink) {
29759
29839
  }
29760
29840
  return ink;
29761
29841
  }
29762
- function readableAccent(V, surface, ink) {
29842
+ function readableAccent(V, surface, ink, floor = 4.5) {
29763
29843
  const light = contrastRatio("#000000", surface) >= contrastRatio("#ffffff", surface);
29764
29844
  for (const stop of light ? ACCENT_WALK.light : ACCENT_WALK.dark) {
29765
29845
  const hex = V[`--ggui-color-primary-${stop}`];
29766
- if (hex !== void 0 && contrastRatio(hex, surface) >= 4.5)
29846
+ if (hex !== void 0 && contrastRatio(hex, surface) >= floor)
29767
29847
  return hex;
29768
29848
  }
29769
29849
  return ink;
@@ -29828,7 +29908,7 @@ function deriveThemeVariables(doc, mode, options = {}) {
29828
29908
  anchor = "#000000";
29829
29909
  }
29830
29910
  }
29831
- const ramp2 = familyRamp(g, anchor);
29911
+ const ramp2 = familyRamp(g, anchor, ground);
29832
29912
  for (const stop of STOPS)
29833
29913
  V[`--ggui-color-${fam}-${stop}`] = ramp2[stop];
29834
29914
  const cap = fam[0].toUpperCase() + fam.slice(1);
@@ -29845,6 +29925,8 @@ function deriveThemeVariables(doc, mode, options = {}) {
29845
29925
  V["--ggui-color-onInverted"] = container;
29846
29926
  V["--ggui-color-inverseOutline"] = readableOutline(onContainer, container);
29847
29927
  V["--ggui-color-heroOutline"] = readableOutline(V["--ggui-color-heroGround"], V["--ggui-color-onHeroGround"]);
29928
+ V["--ggui-color-controlOutline"] = readableOutline(container, onContainer);
29929
+ V["--ggui-color-controlAccentOutline"] = readableAccent(V, container, onContainer, 3);
29848
29930
  const family = doc.font.family;
29849
29931
  const sans = tokenValue(family.sans) ?? fontFamily.sans;
29850
29932
  V["--ggui-font-family-sans"] = sans;
@@ -30482,8 +30564,10 @@ var gguiDark = {
30482
30564
  // paper
30483
30565
  sunken: { $value: "#292929", $type: "color" },
30484
30566
  // ink
30485
- onSunken: { $value: "#d9d9d9", $type: "color" },
30486
- // chrome
30567
+ // Muted text, and text on sunken grounds (ggui#1566): the kit's dark muted
30568
+ // value, 6.57:1 on container and 5.80:1 on sunken. Light's onSunken is ink-3,
30569
+ // the same tier, so dark now reads as light already does.
30570
+ onSunken: { $value: "#a3a3a9", $type: "color" },
30487
30571
  container: { $value: "#1f1f1f", $type: "color" },
30488
30572
  // ink
30489
30573
  onContainer: { $value: "#f4f3ed", $type: "color" },
@@ -32841,7 +32925,7 @@ function getTheme(id, mode = "light") {
32841
32925
  function getDefaultThemeId() {
32842
32926
  return "ggui";
32843
32927
  }
32844
- var ThemeContext = (0, import_react42.createContext)(null);
32928
+ var ThemeContext = (0, import_react43.createContext)(null);
32845
32929
  var COLOR_MIX_SUPPORTS = "@supports (color: color-mix(in srgb, red, blue))";
32846
32930
  function resolvePrimary500Hex(cssVariables) {
32847
32931
  const match = cssVariables.match(/--ggui-color-primary-500:\s*(#[0-9a-fA-F]{3}|#[0-9a-fA-F]{6})\s*;/);
@@ -32942,13 +33026,21 @@ function framelessSuppressionRule(scopeClass) {
32942
33026
  }
32943
33027
  var EXPANDED_FRAME = { outerRadiusVar: "--ggui-shape-radius-xl", insetPx: 16 };
32944
33028
  var EXPANDED_FRAME_INNER_RADIUS = `max(0px, calc(var(${EXPANDED_FRAME.outerRadiusVar}) - ${EXPANDED_FRAME.insetPx}px))`;
33029
+ var EXPANDED_FRAME_CHROME = {
33030
+ radius: `var(${EXPANDED_FRAME.outerRadiusVar})`,
33031
+ hairline: "color-mix(in srgb, var(--ggui-color-onGround) 6%, transparent)",
33032
+ shadowVar: "--ggui-shape-shadow-sm",
33033
+ ground: "var(--ggui-color-neutral-50)"
33034
+ };
32945
33035
  function structuralScaffolding(scopeClass) {
32946
33036
  return `.${scopeClass} *, .${scopeClass} *::before, .${scopeClass} *::after { box-sizing: border-box; }
32947
33037
  .${scopeClass} h1, .${scopeClass} h2, .${scopeClass} h3, .${scopeClass} h4, .${scopeClass} h5, .${scopeClass} h6, .${scopeClass} button, .${scopeClass} input, .${scopeClass} textarea, .${scopeClass} select { font-family: inherit; }`;
32948
33038
  }
33039
+ var BODY_COPY_SIZE = "font-size: var(--ggui-font-size-base);";
32949
33040
  function baseInheritsRule(scopeClass) {
32950
33041
  return `.${scopeClass} {
32951
33042
  font-family: var(--ggui-font-family-sans);
33043
+ ${BODY_COPY_SIZE}
32952
33044
  color: var(--ggui-color-onGround);
32953
33045
  background-color: transparent;
32954
33046
  }`;
@@ -33003,6 +33095,10 @@ var WIRE_EXPORTS = [
33003
33095
  // its runtime's shim lacks fails at module link. A card generated to use it
33004
33096
  // must never meet a runtime without it.
33005
33097
  "useActionSpent",
33098
+ // ggui#1398: whether a dispatched action is waiting for the agent's answer,
33099
+ // as data. Served one release before the triad teaches it, for the same
33100
+ // reason as `useActionSpent` above.
33101
+ "useActionPending",
33006
33102
  // Provider component
33007
33103
  "GguiWireProvider"
33008
33104
  ];
@@ -33421,7 +33517,7 @@ function makeScopeClass(reactId) {
33421
33517
  }
33422
33518
  var AUTO_RETRY_LIMIT = 1;
33423
33519
  var AUTO_RETRY_DELAY = 500;
33424
- var ErrorBoundary = class extends import_react9.default.Component {
33520
+ var ErrorBoundary = class extends import_react10.default.Component {
33425
33521
  state = { error: null, catchCount: 0, autoRetrying: false };
33426
33522
  retryTimer = null;
33427
33523
  static getDerivedStateFromError(error) {
@@ -33537,12 +33633,12 @@ function ReactComponentRenderer({
33537
33633
  fallback = /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { children: "Loading component..." }),
33538
33634
  onError
33539
33635
  }) {
33540
- const reactId = (0, import_react9.useId)();
33541
- const [scopeClass] = (0, import_react9.useState)(() => makeScopeClass(reactId) || `ggui-rcr-${++scopeCounter}`);
33542
- const [Component, setComponent] = (0, import_react9.useState)(null);
33543
- const [error, setError] = (0, import_react9.useState)(null);
33544
- const [loading, setLoading] = (0, import_react9.useState)(true);
33545
- (0, import_react9.useEffect)(() => {
33636
+ const reactId = (0, import_react10.useId)();
33637
+ const [scopeClass] = (0, import_react10.useState)(() => makeScopeClass(reactId) || `ggui-rcr-${++scopeCounter}`);
33638
+ const [Component, setComponent] = (0, import_react10.useState)(null);
33639
+ const [error, setError] = (0, import_react10.useState)(null);
33640
+ const [loading, setLoading] = (0, import_react10.useState)(true);
33641
+ (0, import_react10.useEffect)(() => {
33546
33642
  if (!code || code.trim().length === 0) {
33547
33643
  setComponent(null);
33548
33644
  setLoading(false);
@@ -33570,7 +33666,7 @@ function ReactComponentRenderer({
33570
33666
  } catch {
33571
33667
  }
33572
33668
  w.__ggui__ = {
33573
- react: import_react9.default,
33669
+ react: import_react10.default,
33574
33670
  reactDom: reactDomModule,
33575
33671
  primitives: primitives_exports,
33576
33672
  components: components_exports,
@@ -33578,7 +33674,7 @@ function ReactComponentRenderer({
33578
33674
  interact: interact_exports,
33579
33675
  wire: dist_exports
33580
33676
  };
33581
- w.__REACT = import_react9.default;
33677
+ w.__REACT = import_react10.default;
33582
33678
  w.__GGUI_PRIMITIVES = primitives_exports;
33583
33679
  w.__GGUI_COMPONENTS = components_exports;
33584
33680
  w.__GGUI_COMPOSITIONS = compositions_exports;
@@ -33724,11 +33820,11 @@ function PreviewApp({
33724
33820
  token,
33725
33821
  selectedId
33726
33822
  }) {
33727
- const [state, setState] = (0, import_react45.useState)(
33823
+ const [state, setState] = (0, import_react46.useState)(
33728
33824
  selectedId ? { kind: "loading" } : { kind: "idle" }
33729
33825
  );
33730
- const [version, setVersion] = (0, import_react45.useState)(0);
33731
- (0, import_react45.useEffect)(() => {
33826
+ const [version, setVersion] = (0, import_react46.useState)(0);
33827
+ (0, import_react46.useEffect)(() => {
33732
33828
  if (!selectedId) {
33733
33829
  setState({ kind: "idle" });
33734
33830
  return;
@@ -33741,7 +33837,7 @@ function PreviewApp({
33741
33837
  });
33742
33838
  return () => controller.abort();
33743
33839
  }, [selectedId, token, version]);
33744
- (0, import_react45.useEffect)(() => {
33840
+ (0, import_react46.useEffect)(() => {
33745
33841
  if (!selectedId) return;
33746
33842
  const controller = new AbortController();
33747
33843
  subscribeToRegistry(token, controller.signal, (event) => {
@@ -33903,7 +33999,7 @@ function mount() {
33903
33999
  if (!root) throw new Error("preview-root element not found in shell");
33904
34000
  const { token, selectedId } = bootstrap();
33905
34001
  (0, import_client.createRoot)(root).render(
33906
- /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_react45.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(PreviewApp, { token, selectedId }) })
34002
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(import_react46.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(PreviewApp, { token, selectedId }) })
33907
34003
  );
33908
34004
  }
33909
34005
  mount();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggui-ai/dev-stack",
3
- "version": "0.24.0",
3
+ "version": "0.26.0",
4
4
  "description": "Shared local dev engine for the ggui protocol: local UI registry discovery, compile-on-demand, filesystem watcher with SSE, and a read-only HTTP surface for dev tooling. Framework-neutral — agent runtime supervision plugs in via an adapter seam, so no agent SDK is hardcoded.",
5
5
  "keywords": [
6
6
  "ggui",
@@ -28,9 +28,9 @@
28
28
  "dependencies": {
29
29
  "chokidar": "^4.0.3",
30
30
  "esbuild": "^0.28.2",
31
- "@ggui-ai/agent-runtime": "0.24.0",
32
- "@ggui-ai/project-config": "0.24.0",
33
- "@ggui-ai/ui-registry": "0.24.0"
31
+ "@ggui-ai/agent-runtime": "0.26.0",
32
+ "@ggui-ai/ui-registry": "0.26.0",
33
+ "@ggui-ai/project-config": "0.26.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^24.0.0",
@@ -40,9 +40,9 @@
40
40
  "react-dom": "^19.0.0",
41
41
  "typescript": "^5.0.0",
42
42
  "vitest": "^3.2.6",
43
- "@ggui-ai/design": "0.24.0",
44
- "@ggui-ai/mcp-apps-react": "0.24.0",
45
- "@ggui-ai/wire": "0.24.0"
43
+ "@ggui-ai/design": "0.26.0",
44
+ "@ggui-ai/mcp-apps-react": "0.26.0",
45
+ "@ggui-ai/wire": "0.26.0"
46
46
  },
47
47
  "repository": {
48
48
  "type": "git",