@ggui-ai/dev-stack 0.27.0 → 0.29.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.
@@ -16016,6 +16016,37 @@ var require_utils = __commonJS({
16016
16016
  }
16017
16017
  return output.join("");
16018
16018
  }
16019
+ function removeDotSegmentsRelative(path) {
16020
+ if (path === "" || path[0] === "/") {
16021
+ return removeDotSegments(path);
16022
+ }
16023
+ const segments = path.split("/");
16024
+ const last = segments.length - 1;
16025
+ const output = [];
16026
+ let trailingDirectory = false;
16027
+ for (let i = 0; i <= last; i++) {
16028
+ const segment = segments[i];
16029
+ if (segment === "." || segment === "..") {
16030
+ if (segment === "..") {
16031
+ if (output.length !== 0 && output[output.length - 1] !== "..") {
16032
+ output.pop();
16033
+ } else {
16034
+ output.push("..");
16035
+ }
16036
+ }
16037
+ trailingDirectory = i === last;
16038
+ } else {
16039
+ output.push(segment);
16040
+ }
16041
+ }
16042
+ if (trailingDirectory && output[output.length - 1] !== "..") {
16043
+ output.push("");
16044
+ }
16045
+ if (output.length === 0 || output[0] === "" || output[0].includes(":")) {
16046
+ output.unshift(".");
16047
+ }
16048
+ return output.join("/");
16049
+ }
16019
16050
  var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
16020
16051
  var HOST_DELIM_RE = /[@/?#:]/g;
16021
16052
  var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
@@ -16276,6 +16307,7 @@ var require_utils = __commonJS({
16276
16307
  encodeFragment,
16277
16308
  escapePreservingEscapes,
16278
16309
  removeDotSegments,
16310
+ removeDotSegmentsRelative,
16279
16311
  isIPv4,
16280
16312
  isUUID,
16281
16313
  normalizeIPv6,
@@ -16499,16 +16531,18 @@ var require_schemes = __commonJS({
16499
16531
  var require_fast_uri = __commonJS({
16500
16532
  "../../node_modules/fast-uri/index.js"(exports, module) {
16501
16533
  "use strict";
16502
- var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
16534
+ var { normalizeIPv6, removeDotSegments, removeDotSegmentsRelative, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
16503
16535
  var { SCHEMES, getSchemeHandler } = require_schemes();
16504
16536
  var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
16505
16537
  var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
16506
- function decodeValidScheme(scheme) {
16507
- const decodedScheme = unescape(String(scheme));
16508
- if (!VALID_SCHEME.test(decodedScheme)) {
16538
+ var MALFORMED_HOST_ERROR = "URI host is malformed.";
16539
+ var FORBIDDEN_DOMAIN_HOST_CHARACTER = /[\0-\x20"#/:<>?@[\\\]^`{|}\x7F]/u;
16540
+ function validateScheme(scheme) {
16541
+ const stringScheme = String(scheme);
16542
+ if (!VALID_SCHEME.test(stringScheme)) {
16509
16543
  throw new TypeError(MALFORMED_SCHEME_ERROR);
16510
16544
  }
16511
- return decodedScheme;
16545
+ return stringScheme;
16512
16546
  }
16513
16547
  function normalize(uri, options) {
16514
16548
  if (typeof uri === "string") {
@@ -16545,6 +16579,9 @@ var require_fast_uri = __commonJS({
16545
16579
  const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
16546
16580
  const resolvedHost = resolved.host;
16547
16581
  const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
16582
+ if (hasForbiddenDomainHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP)) {
16583
+ throw new Error(MALFORMED_HOST_ERROR);
16584
+ }
16548
16585
  canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
16549
16586
  const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !/\P{ASCII}/u.test(resolvedHost);
16550
16587
  if (resolved.error && !encodedASCIIHost) {
@@ -16586,14 +16623,15 @@ var require_fast_uri = __commonJS({
16586
16623
  if (relative.path[0] === "/") {
16587
16624
  target.path = removeDotSegments(relative.path);
16588
16625
  } else {
16589
- if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
16626
+ const baseHasAuthority = base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0;
16627
+ if (baseHasAuthority && !base.path) {
16590
16628
  target.path = "/" + relative.path;
16591
16629
  } else if (!base.path) {
16592
16630
  target.path = relative.path;
16593
16631
  } else {
16594
16632
  target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative.path;
16595
16633
  }
16596
- target.path = removeDotSegments(target.path);
16634
+ target.path = base.scheme === void 0 && !baseHasAuthority && target.path[0] !== "/" ? removeDotSegmentsRelative(target.path) : removeDotSegments(target.path);
16597
16635
  }
16598
16636
  target.query = relative.query;
16599
16637
  }
@@ -16631,12 +16669,13 @@ var require_fast_uri = __commonJS({
16631
16669
  const options = Object.assign({}, opts);
16632
16670
  const uriTokens = [];
16633
16671
  if (component.scheme) {
16634
- component.scheme = decodeValidScheme(component.scheme);
16672
+ component.scheme = validateScheme(component.scheme);
16635
16673
  }
16636
16674
  const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
16637
16675
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
16638
16676
  const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
16639
- const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
16677
+ const schemelessReference = (component.scheme === void 0 || options.reference === "suffix") && !hasAuthority;
16678
+ const pathNoScheme = !options.skipEscape && schemelessReference;
16640
16679
  if (component.path !== void 0) {
16641
16680
  if (!options.skipEscape) {
16642
16681
  component.path = serializePathEncoding(component.path, pathNoScheme);
@@ -16645,7 +16684,7 @@ var require_fast_uri = __commonJS({
16645
16684
  }
16646
16685
  }
16647
16686
  if (options.reference !== "suffix" && component.scheme) {
16648
- component.scheme = decodeValidScheme(component.scheme);
16687
+ component.scheme = validateScheme(component.scheme);
16649
16688
  uriTokens.push(component.scheme, ":");
16650
16689
  }
16651
16690
  const authority = recomposeAuthority(component);
@@ -16661,9 +16700,9 @@ var require_fast_uri = __commonJS({
16661
16700
  if (component.path !== void 0) {
16662
16701
  let s = component.path;
16663
16702
  if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
16664
- s = removeDotSegments(s);
16703
+ s = schemelessReference && s[0] !== "/" ? removeDotSegmentsRelative(s) : removeDotSegments(s);
16665
16704
  }
16666
- if (pathNoScheme) {
16705
+ if (schemelessReference) {
16667
16706
  s = serializePathEncoding(s, true);
16668
16707
  }
16669
16708
  if (authority === void 0 && s[0] === "/" && s[1] === "/") {
@@ -16710,16 +16749,34 @@ var require_fast_uri = __commonJS({
16710
16749
  return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
16711
16750
  }
16712
16751
  function canonicalizeHost(parsed, options, schemeHandler, isIP) {
16752
+ if (hasForbiddenDomainHost(parsed, options, schemeHandler, isIP)) {
16753
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
16754
+ return true;
16755
+ }
16713
16756
  if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
16757
+ let url;
16714
16758
  try {
16715
- parsed.host = new URL("http://" + parsed.host).hostname;
16759
+ url = new URL("http://" + parsed.host);
16716
16760
  } catch (e) {
16717
16761
  parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
16718
16762
  return true;
16719
16763
  }
16764
+ if (!isHostOnlyURL(url)) {
16765
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
16766
+ return true;
16767
+ }
16768
+ parsed.host = url.hostname;
16720
16769
  }
16721
16770
  return false;
16722
16771
  }
16772
+ function hasForbiddenDomainHost(parsed, options, schemeHandler, isIP) {
16773
+ return Boolean(
16774
+ parsed.host && isIP === false && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && FORBIDDEN_DOMAIN_HOST_CHARACTER.test(parsed.host)
16775
+ );
16776
+ }
16777
+ function isHostOnlyURL(url) {
16778
+ return url.username === "" && url.password === "" && url.port === "" && url.pathname === "/" && url.search === "" && url.hash === "" && url.hostname !== "";
16779
+ }
16723
16780
  function parseWithStatus(uri, opts) {
16724
16781
  const options = Object.assign({}, opts);
16725
16782
  const parsed = {
@@ -16774,9 +16831,8 @@ var require_fast_uri = __commonJS({
16774
16831
  parsed.query = matches[7];
16775
16832
  parsed.fragment = matches[8];
16776
16833
  if (parsed.scheme !== void 0) {
16777
- const decodedScheme = unescape(parsed.scheme);
16778
- if (VALID_SCHEME.test(decodedScheme)) {
16779
- parsed.scheme = decodedScheme.toLowerCase();
16834
+ if (VALID_SCHEME.test(parsed.scheme)) {
16835
+ parsed.scheme = parsed.scheme.toLowerCase();
16780
16836
  } else {
16781
16837
  parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
16782
16838
  malformedScheme = true;
@@ -16804,7 +16860,7 @@ var require_fast_uri = __commonJS({
16804
16860
  malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
16805
16861
  parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
16806
16862
  if (malformedIPLiteral) {
16807
- parsed.error = parsed.error || "URI host is malformed.";
16863
+ parsed.error = parsed.error || MALFORMED_HOST_ERROR;
16808
16864
  malformedAuthorityOrPort = true;
16809
16865
  }
16810
16866
  } else {
@@ -16827,13 +16883,14 @@ var require_fast_uri = __commonJS({
16827
16883
  if (!malformedIPLiteral) {
16828
16884
  malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
16829
16885
  }
16830
- if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
16831
- if (uri.indexOf("%") !== -1) {
16832
- if (parsed.host !== void 0 && !malformedIPLiteral) {
16833
- const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
16834
- parsed.host = reescapeHostDelimiters(host, isIP);
16835
- }
16886
+ if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) {
16887
+ let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
16888
+ if (!isIP) {
16889
+ host = normalizePercentEncoding(host.toLowerCase());
16836
16890
  }
16891
+ parsed.host = isIP || options.scheme !== "null" ? reescapeHostDelimiters(host, isIP) : host;
16892
+ }
16893
+ if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
16837
16894
  if (parsed.path) {
16838
16895
  parsed.path = normalizePathEncoding(parsed.path);
16839
16896
  }
@@ -21060,6 +21117,7 @@ __export2(primitives_exports, {
21060
21117
  Spacer: () => Spacer,
21061
21118
  Spinner: () => Spinner,
21062
21119
  Stack: () => Stack,
21120
+ TINT_STEPS: () => TINT_STEPS,
21063
21121
  Table: () => Table,
21064
21122
  Tabs: () => Tabs,
21065
21123
  Text: () => Text,
@@ -21177,7 +21235,7 @@ var maxWidthMap = {
21177
21235
  "3xl": maxWidth["3xl"],
21178
21236
  full: maxWidth.full
21179
21237
  };
21180
- function Container({ children, maxWidth: maxWidth2 = "lg", center = true, padding, style, className }) {
21238
+ function Container({ children, maxWidth: maxWidth2 = "lg", center = false, padding, style, className }) {
21181
21239
  const resolvedMaxWidth = maxWidthMap[maxWidth2] || maxWidth2;
21182
21240
  const resolvedPadding = resolveSpacing(padding);
21183
21241
  return (0, import_jsx_runtime3.jsx)("div", { className, style: {
@@ -21193,7 +21251,9 @@ function frameAttributes(frame) {
21193
21251
  return {};
21194
21252
  return {
21195
21253
  ...frame.surface !== void 0 ? { "data-ggui-surface": frame.surface } : {},
21196
- ...frame.bleed === true ? { "data-ggui-bleed": "" } : {}
21254
+ ...frame.bleed === true ? { "data-ggui-bleed": "" } : {},
21255
+ ...frame.box === true ? { "data-ggui-box": "" } : {},
21256
+ ...frame.card === true ? { "data-ggui-card": "" } : {}
21197
21257
  };
21198
21258
  }
21199
21259
  function renderWithTrait(trait, traitProps, root, children) {
@@ -21290,6 +21350,28 @@ function resolveSurfaceCss(surface) {
21290
21350
  return "transparent";
21291
21351
  }
21292
21352
  }
21353
+ var TINT_STEPS = ["tint-1", "tint-2", "tint-3", "tint-4", "tint-5", "tint-6", "tint-7", "tint-8"];
21354
+ function resolveTintCss(step) {
21355
+ switch (step) {
21356
+ case "tint-1":
21357
+ return "var(--ggui-color-tint-1, #f4c5b3)";
21358
+ case "tint-2":
21359
+ return "var(--ggui-color-tint-2, #e2cfa5)";
21360
+ case "tint-3":
21361
+ return "var(--ggui-color-tint-3, #c3dab1)";
21362
+ case "tint-4":
21363
+ return "var(--ggui-color-tint-4, #a7ded0)";
21364
+ case "tint-5":
21365
+ return "var(--ggui-color-tint-5, #a6dbed)";
21366
+ case "tint-6":
21367
+ return "var(--ggui-color-tint-6, #bfd1f9)";
21368
+ case "tint-7":
21369
+ return "var(--ggui-color-tint-7, #dec6ee)";
21370
+ case "tint-8":
21371
+ return "var(--ggui-color-tint-8, #f3c1d1)";
21372
+ }
21373
+ }
21374
+ var TINT_ON_COLOR_CSS = resolveToneCss("default");
21293
21375
  var RADIUS_SCALE_TOKEN = {
21294
21376
  none: "0",
21295
21377
  sm: "var(--ggui-shape-radius-sm, 4px)",
@@ -21323,6 +21405,7 @@ function Card(props) {
21323
21405
  border = true,
21324
21406
  radius: radius2 = "lg",
21325
21407
  surface,
21408
+ tint,
21326
21409
  style,
21327
21410
  className,
21328
21411
  bleed,
@@ -21330,13 +21413,15 @@ function Card(props) {
21330
21413
  ...traitProps
21331
21414
  } = props;
21332
21415
  const frame = {
21333
- ...surface !== "transparent" ? { surface: surface ?? "default" } : {},
21334
- ...bleed === true ? { bleed: true } : {}
21416
+ ...tint !== void 0 ? { surface: tint } : surface !== "transparent" ? { surface: surface ?? "default" } : {},
21417
+ ...bleed === true ? { bleed: true } : {},
21418
+ card: true
21335
21419
  };
21336
- const resolvedPadding = resolveSpacing(padding);
21337
- const resolvedSurface = resolveSurfaceCss(surface ?? "default");
21338
- const resolvedOnColor = resolveSurfaceOnColorCss(surface ?? "default");
21339
- const scope = resolveSurfaceScope(surface ?? "default");
21420
+ const visible = border || surface !== void 0 && surface !== "transparent" || tint !== void 0;
21421
+ const resolvedPadding = padding === "none" ? resolveSpacing(padding) : `${resolveSpacing(padding)} ${visible ? "var(--ggui-card-inset, var(--ggui-spacing-lg))" : "0"}`;
21422
+ const resolvedSurface = tint !== void 0 ? resolveTintCss(tint) : resolveSurfaceCss(surface ?? "default");
21423
+ const resolvedOnColor = tint !== void 0 ? TINT_ON_COLOR_CSS : resolveSurfaceOnColorCss(surface ?? "default");
21424
+ const scope = tint !== void 0 ? void 0 : resolveSurfaceScope(surface ?? "default");
21340
21425
  const authorStyle = scope !== void 0 ? withoutBackground(style) : style;
21341
21426
  const composedStyle = {
21342
21427
  backgroundColor: resolvedSurface,
@@ -21440,21 +21525,17 @@ function Grid(props) {
21440
21525
  return renderWithTrait(Trait, traitProps, { className, style: composedStyle }, children);
21441
21526
  }
21442
21527
  function Box(props) {
21443
- const { children, padding, paddingX, paddingY, margin, surface, assetColor, assetSemantic, radius: radius2, style, className, bleed, as: Trait, ...traitProps } = props;
21444
- const markedSurface = surface !== void 0 && surface !== "transparent" ? surface : void 0;
21445
- const frame = markedSurface === void 0 && bleed !== true ? void 0 : { ...markedSurface !== void 0 ? { surface: markedSurface } : {}, ...bleed === true ? { bleed: true } : {} };
21446
- let computedPadding;
21447
- if (paddingX !== void 0 || paddingY !== void 0) {
21448
- const px = resolveSpacing(paddingX) || "0";
21449
- const py = resolveSpacing(paddingY) || "0";
21450
- computedPadding = `${py} ${px}`;
21451
- } else {
21452
- computedPadding = resolveSpacing(padding);
21453
- }
21528
+ const { children, padding, paddingX, paddingY, margin, surface, tint, assetColor, assetSemantic, radius: radius2, style, className, bleed, as: Trait, ...traitProps } = props;
21529
+ const markedSurface = tint !== void 0 ? tint : surface !== void 0 && surface !== "transparent" ? surface : void 0;
21530
+ const frame = markedSurface === void 0 && bleed !== true ? void 0 : { ...markedSurface !== void 0 ? { surface: markedSurface } : {}, ...bleed === true ? { bleed: true } : {}, box: true };
21531
+ const blockPadding = resolveSpacing(paddingY ?? padding);
21532
+ const padded = [padding, paddingX, paddingY].some((p) => p !== void 0 && p !== "none");
21533
+ const computedPadding = padded ? `${blockPadding || "0"} ${markedSurface !== void 0 ? "var(--ggui-card-inset, var(--ggui-spacing-lg))" : "0"}` : resolveSpacing(padding);
21454
21534
  const validAsset = assetColor !== void 0 && typeof assetSemantic === "string" && assetSemantic.length > 0 ? assetColor : void 0;
21455
- const resolvedBackground = validAsset ? validAsset : surface ? resolveSurfaceCss(surface) : void 0;
21456
- const resolvedOnColor = !validAsset && surface ? resolveSurfaceOnColorCss(surface) : void 0;
21457
- const scope = !validAsset && surface ? resolveSurfaceScope(surface) : void 0;
21535
+ const tinted = !validAsset && tint !== void 0;
21536
+ const resolvedBackground = validAsset ? validAsset : tint !== void 0 ? resolveTintCss(tint) : surface ? resolveSurfaceCss(surface) : void 0;
21537
+ const resolvedOnColor = tinted ? TINT_ON_COLOR_CSS : !validAsset && surface ? resolveSurfaceOnColorCss(surface) : void 0;
21538
+ const scope = !validAsset && !tinted && surface ? resolveSurfaceScope(surface) : void 0;
21458
21539
  const authorStyle = scope !== void 0 ? withoutBackground(style) : style;
21459
21540
  const composedStyle = {
21460
21541
  padding: computedPadding,
@@ -29560,6 +29641,14 @@ var consumed_tokens_manifest_default = {
29560
29641
  "--ggui-color-successContainer",
29561
29642
  "--ggui-color-sunken",
29562
29643
  "--ggui-color-tertiaryContainer",
29644
+ "--ggui-color-tint-1",
29645
+ "--ggui-color-tint-2",
29646
+ "--ggui-color-tint-3",
29647
+ "--ggui-color-tint-4",
29648
+ "--ggui-color-tint-5",
29649
+ "--ggui-color-tint-6",
29650
+ "--ggui-color-tint-7",
29651
+ "--ggui-color-tint-8",
29563
29652
  "--ggui-color-warning-100",
29564
29653
  "--ggui-color-warning-200",
29565
29654
  "--ggui-color-warning-50",
@@ -29736,6 +29825,135 @@ function contrastRatio(a, b) {
29736
29825
  const [hi, lo] = la > lb ? [la, lb] : [lb, la];
29737
29826
  return (hi + 0.05) / (lo + 0.05);
29738
29827
  }
29828
+ function oklab(hex) {
29829
+ const o = hexToOklch(hex);
29830
+ const r = o.h * Math.PI / 180;
29831
+ return [o.l, o.c * Math.cos(r), o.c * Math.sin(r)];
29832
+ }
29833
+ function labDistance(x, y) {
29834
+ return 100 * Math.hypot(x[0] - y[0], x[1] - y[1], x[2] - y[2]);
29835
+ }
29836
+ function stateContainerPair(ramp, lightSide) {
29837
+ const light = (hex) => hexToOklch(hex).l >= 0.5;
29838
+ const order = lightSide ? ["100", "800"] : ["800", "100"];
29839
+ const cStop = order.find((stop) => light(ramp[stop]) === lightSide) ?? order[0];
29840
+ const inkOrder = cStop === "100" ? lightSide ? ["900", "800"] : ["800", "900"] : ["100", "50"];
29841
+ const inkStop = inkOrder.find((stop) => light(ramp[stop]) !== lightSide) ?? inkOrder[0];
29842
+ return { container: ramp[cStop], ink: ramp[inkStop] };
29843
+ }
29844
+ var TINT_RECIPE = { lightL: 0.87, darkL: 0.34, chroma: 0.06, hueBase: 42, hueStep: 45 };
29845
+ var TINT_SEARCH = {
29846
+ lightL: [0.8, 0.92],
29847
+ darkL: [0.26, 0.5],
29848
+ chroma: [0.04, 0.08],
29849
+ hueSpread: 22,
29850
+ lStep: 0.01,
29851
+ cStep: 0.01,
29852
+ hueStepDeg: 2
29853
+ };
29854
+ var TINT_FLOORS = { ink: 4.5, container: 8, pairwise: 4, state: 4 };
29855
+ var TINT_STATE_CONTAINERS = [
29856
+ "errorContainer",
29857
+ "warningContainer",
29858
+ "successContainer",
29859
+ "infoContainer",
29860
+ "tertiaryContainer",
29861
+ "primaryContainer"
29862
+ ];
29863
+ var round2 = (v) => Math.round(v * 100) / 100;
29864
+ function tintSetAt(l, c, hueBase) {
29865
+ return TINT_STEPS.map((_, k) => oklchToHex({ l, c, h: hueBase + TINT_RECIPE.hueStep * k }));
29866
+ }
29867
+ function tintFloorsOf(tints, container, onContainer, states) {
29868
+ return measureTints(tints, tints.map(oklab), oklab(container), onContainer, states.map(oklab));
29869
+ }
29870
+ function measureTints(tints, labs, container, onContainer, states) {
29871
+ let pairwise = Infinity;
29872
+ for (let i = 0; i < labs.length; i++)
29873
+ for (let j = i + 1; j < labs.length; j++)
29874
+ pairwise = Math.min(pairwise, labDistance(labs[i], labs[j]));
29875
+ let state = Infinity;
29876
+ for (const s of states)
29877
+ for (const t of labs)
29878
+ state = Math.min(state, labDistance(t, s));
29879
+ return {
29880
+ ink: Math.min(...tints.map((t) => contrastRatio(onContainer, t))),
29881
+ container: Math.min(...labs.map((t) => labDistance(t, container))),
29882
+ pairwise,
29883
+ state
29884
+ };
29885
+ }
29886
+ var tintMemo = /* @__PURE__ */ new Map();
29887
+ var TINT_MEMO_MAX = 64;
29888
+ var TINT_SCREEN_MARGIN = 1;
29889
+ function deriveTints(container, onContainer, stateContainers) {
29890
+ const key = `${container} ${onContainer} ${stateContainers.join(" ")}`;
29891
+ const memo = tintMemo.get(key);
29892
+ if (memo !== void 0)
29893
+ return memo;
29894
+ const found = walkTints(container, onContainer, stateContainers);
29895
+ if (tintMemo.size >= TINT_MEMO_MAX)
29896
+ tintMemo.clear();
29897
+ tintMemo.set(key, found);
29898
+ return found;
29899
+ }
29900
+ function walkTints(container, onContainer, stateContainers) {
29901
+ const containerLab = oklab(container);
29902
+ const stateLabs = stateContainers.map(oklab);
29903
+ const lightSide = hexToOklch(container).l >= 0.5;
29904
+ const l0 = lightSide ? TINT_RECIPE.lightL : TINT_RECIPE.darkL;
29905
+ const [lMin, lMax] = lightSide ? TINT_SEARCH.lightL : TINT_SEARCH.darkL;
29906
+ const [cMin, cMax] = TINT_SEARCH.chroma;
29907
+ const candidates = [];
29908
+ const lCount = Math.round((lMax - lMin) / TINT_SEARCH.lStep);
29909
+ const cCount = Math.round((cMax - cMin) / TINT_SEARCH.cStep);
29910
+ const hCount = Math.round(TINT_SEARCH.hueSpread / TINT_SEARCH.hueStepDeg);
29911
+ for (let i = 0; i <= lCount; i++) {
29912
+ const l = round2(lMin + i * TINT_SEARCH.lStep);
29913
+ for (let j = 0; j <= cCount; j++) {
29914
+ const c = round2(cMin + j * TINT_SEARCH.cStep);
29915
+ for (let k = -hCount; k <= hCount; k++) {
29916
+ const dh = k * TINT_SEARCH.hueStepDeg;
29917
+ const d = Math.round(Math.abs(l - l0) / TINT_SEARCH.lStep) + Math.round(Math.abs(c - TINT_RECIPE.chroma) / TINT_SEARCH.cStep) + Math.abs(k);
29918
+ candidates.push({ l, c, hueBase: TINT_RECIPE.hueBase + dh, d });
29919
+ }
29920
+ }
29921
+ }
29922
+ candidates.sort((a, b) => a.d - b.d);
29923
+ let best;
29924
+ for (const cand of candidates) {
29925
+ if (best !== void 0 && stateLabs.length > 0) {
29926
+ let near = Infinity;
29927
+ let screenable = true;
29928
+ for (let k = 0; k < TINT_STEPS.length && screenable && near >= TINT_FLOORS.state - TINT_SCREEN_MARGIN; k++) {
29929
+ const h = (cand.hueBase + TINT_RECIPE.hueStep * k) * Math.PI / 180;
29930
+ const lab = [cand.l, cand.c * Math.cos(h), cand.c * Math.sin(h)];
29931
+ if (!inGamut(oklabToLinear(lab[0], lab[1], lab[2])))
29932
+ screenable = false;
29933
+ else
29934
+ for (const st of stateLabs)
29935
+ near = Math.min(near, labDistance(lab, st));
29936
+ }
29937
+ if (screenable && near < TINT_FLOORS.state - TINT_SCREEN_MARGIN && near + TINT_SCREEN_MARGIN <= best.reached.state)
29938
+ continue;
29939
+ }
29940
+ const tints2 = tintSetAt(cand.l, cand.c, cand.hueBase);
29941
+ if (tints2.some((t) => contrastRatio(onContainer, t) < TINT_FLOORS.ink))
29942
+ continue;
29943
+ const reached = measureTints(tints2, tints2.map(oklab), containerLab, onContainer, stateLabs);
29944
+ if (reached.container < TINT_FLOORS.container || reached.pairwise < TINT_FLOORS.pairwise)
29945
+ continue;
29946
+ const found = { tints: tints2, l: cand.l, c: cand.c, hueBase: cand.hueBase, clears: reached.state >= TINT_FLOORS.state, reached };
29947
+ if (found.clears)
29948
+ return found;
29949
+ if (best === void 0 || reached.state > best.reached.state)
29950
+ best = found;
29951
+ }
29952
+ if (best !== void 0)
29953
+ return best;
29954
+ const tints = tintSetAt(l0, TINT_RECIPE.chroma, TINT_RECIPE.hueBase);
29955
+ return { tints, l: l0, c: TINT_RECIPE.chroma, hueBase: TINT_RECIPE.hueBase, clears: false, reached: tintFloorsOf(tints, container, onContainer, stateContainers) };
29956
+ }
29739
29957
  var STOPS = ["50", "100", "200", "300", "400", "500", "600", "700", "800", "900"];
29740
29958
  var RAMP_L = [0.97, 0.93, 0.86, 0.76, 0.66, NaN, 0.5, 0.42, 0.34, 0.26];
29741
29959
  var RAMP_C = [0.15, 0.3, 0.5, 0.75, 0.9, 1, 0.95, 0.85, 0.7, 0.55];
@@ -29916,13 +30134,17 @@ function deriveThemeVariables(doc, mode, options = {}) {
29916
30134
  V[`--ggui-color-${fam}-${stop}`] = ramp2[stop];
29917
30135
  const cap = fam[0].toUpperCase() + fam.slice(1);
29918
30136
  V[`--ggui-color-on${cap}`] = single(`on${cap}`) ?? onColourFor(ramp2["500"]);
29919
- V[`--ggui-color-${fam}Container`] = single(`${fam}Container`) ?? (mode === "light" ? ramp2["100"] : ramp2["800"]);
29920
- V[`--ggui-color-on${cap}Container`] = single(`on${cap}Container`) ?? (mode === "light" ? ramp2["900"] : ramp2["100"]);
30137
+ const pair = stateContainerPair(ramp2, hexToOklch(container).l >= 0.5);
30138
+ V[`--ggui-color-${fam}Container`] = single(`${fam}Container`) ?? pair.container;
30139
+ V[`--ggui-color-on${cap}Container`] = single(`on${cap}Container`) ?? pair.ink;
29921
30140
  }
29922
30141
  V["--ggui-color-error"] = V["--ggui-color-error-500"];
29923
30142
  V["--ggui-color-link"] = single("link") ?? readableAccent(V, container, onContainer);
29924
- V["--ggui-color-heroGround"] = mode === "light" ? V["--ggui-color-primaryContainer"] : onContainer;
29925
- V["--ggui-color-onHeroGround"] = mode === "light" ? V["--ggui-color-onPrimaryContainer"] : container;
30143
+ const authoredHero = single("heroGround");
30144
+ const authoredOnHero = single("onHeroGround");
30145
+ const heroAuthored = authoredHero !== void 0 && authoredOnHero !== void 0;
30146
+ V["--ggui-color-heroGround"] = heroAuthored ? authoredHero : mode === "light" ? V["--ggui-color-primaryContainer"] : onContainer;
30147
+ V["--ggui-color-onHeroGround"] = heroAuthored ? authoredOnHero : mode === "light" ? V["--ggui-color-onPrimaryContainer"] : container;
29926
30148
  V["--ggui-color-heroLink"] = readableAccent(V, V["--ggui-color-heroGround"], V["--ggui-color-onHeroGround"]);
29927
30149
  V["--ggui-color-inverseLink"] = readableAccent(V, onContainer, container);
29928
30150
  V["--ggui-color-onInverted"] = container;
@@ -29930,6 +30152,10 @@ function deriveThemeVariables(doc, mode, options = {}) {
29930
30152
  V["--ggui-color-heroOutline"] = readableOutline(V["--ggui-color-heroGround"], V["--ggui-color-onHeroGround"]);
29931
30153
  V["--ggui-color-controlOutline"] = readableOutline(container, onContainer);
29932
30154
  V["--ggui-color-controlAccentOutline"] = readableAccent(V, container, onContainer, 3);
30155
+ const tintSet = deriveTints(container, onContainer, TINT_STATE_CONTAINERS.map((n) => V[`--ggui-color-${n}`]).filter((v) => v !== void 0));
30156
+ TINT_STEPS.forEach((step, i) => {
30157
+ V[`--ggui-color-${step}`] = tintSet.tints[i];
30158
+ });
29933
30159
  const family = doc.font.family;
29934
30160
  const sans = tokenValue(family.sans) ?? fontFamily.sans;
29935
30161
  V["--ggui-font-family-sans"] = sans;
@@ -29995,6 +30221,7 @@ function deriveThemeVariables(doc, mode, options = {}) {
29995
30221
  V[`--ggui-spacing-${key}`] = onRhythm(String(value)) ?? stated(sp, key) ?? String(value);
29996
30222
  for (const [key, value] of Object.entries(NAMED_SPACING))
29997
30223
  V[`--ggui-spacing-${key}`] = onRhythm(value) ?? stated(sp, key) ?? value;
30224
+ V["--ggui-card-inset"] = "var(--ggui-spacing-lg)";
29998
30225
  const rad = doc.shape?.radius;
29999
30226
  for (const [key, value] of Object.entries(radius))
30000
30227
  V[`--ggui-shape-radius-${key}`] = stated(rad, key) ?? String(value);
@@ -30432,6 +30659,12 @@ var gguiLight = {
30432
30659
  // paper-2
30433
30660
  onPrimaryContainer: { $value: "#292929", $type: "color" },
30434
30661
  // ink
30662
+ // ggui#1998 — the hero band on a light host is the brand's dark pair: ink ground, paper heading (the CDO's
30663
+ // pick, c.6357369453). Authored as a pair, so the derivation keeps it; a dark host keeps the derived ink pair.
30664
+ heroGround: { $value: "#292929", $type: "color" },
30665
+ // ink
30666
+ onHeroGround: { $value: "#f4f3ed", $type: "color" },
30667
+ // paper
30435
30668
  // Error role pair — onError is paper for high contrast on signal-red.
30436
30669
  onError: { $value: "#f4f3ed", $type: "color" },
30437
30670
  errorContainer: { $value: "#fbe7e3", $type: "color" },
@@ -33140,7 +33373,9 @@ var PRIMITIVES_EXPORTS = [
33140
33373
  "Accordion",
33141
33374
  "MotionKeyframes",
33142
33375
  "useMotion",
33143
- "useAnimationKey"
33376
+ "useAnimationKey",
33377
+ // ggui#1847 — the eight categorical tint names, so a card can map categories to `tint` in order.
33378
+ "TINT_STEPS"
33144
33379
  ];
33145
33380
  var COMPONENTS_EXPORTS = [
33146
33381
  "SearchField",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ggui-ai/dev-stack",
3
- "version": "0.27.0",
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.",
3
+ "version": "0.29.0",
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",
7
7
  "dev-server",
@@ -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.27.0",
32
- "@ggui-ai/project-config": "0.27.0",
33
- "@ggui-ai/ui-registry": "0.27.0"
31
+ "@ggui-ai/agent-runtime": "0.29.0",
32
+ "@ggui-ai/ui-registry": "0.29.0",
33
+ "@ggui-ai/project-config": "0.29.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^24.0.0",
@@ -39,10 +39,10 @@
39
39
  "react": "^19.0.0",
40
40
  "react-dom": "^19.0.0",
41
41
  "typescript": "^5.0.0",
42
- "vitest": "^3.2.6",
43
- "@ggui-ai/design": "0.27.0",
44
- "@ggui-ai/mcp-apps-react": "0.27.0",
45
- "@ggui-ai/wire": "0.27.0"
42
+ "vitest": "^4.1.11",
43
+ "@ggui-ai/design": "0.29.0",
44
+ "@ggui-ai/mcp-apps-react": "0.29.0",
45
+ "@ggui-ai/wire": "0.29.0"
46
46
  },
47
47
  "repository": {
48
48
  "type": "git",