@datarails-ai/dr-appspace-cli 0.12.10 → 0.12.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +88 -10
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ import { fileURLToPath as fileURLToPath6 } from "url";
13
13
  // package.json
14
14
  var package_default = {
15
15
  name: "@datarails-ai/dr-appspace-cli",
16
- version: "0.12.10",
16
+ version: "0.12.12",
17
17
  description: "Datarails App Space CLI \u2014 build, try, push and publish App Space apps",
18
18
  type: "module",
19
19
  engines: {
@@ -57,7 +57,7 @@ var package_default = {
57
57
  };
58
58
 
59
59
  // src/buildInfo.ts
60
- var BUILD_TIME = "2026-10-14T19:37:21.073Z";
60
+ var BUILD_TIME = "2026-10-14T20:08:09.415Z";
61
61
  function formatBuildTime(iso) {
62
62
  if (iso === "") return "";
63
63
  const d = new Date(iso);
@@ -6435,7 +6435,7 @@ function endOfRegex(text3, start) {
6435
6435
  // ../flows/insights-builder/kit/contract/extract.mjs
6436
6436
  var CONTRACT_V = 1;
6437
6437
  var GENERATED_BY = "dashboard-kit/contract@1";
6438
- var KIT_REGIONS = /* @__PURE__ */ new Set(["header", "asof", "refresh", "nav", "filters", "controls", "band"]);
6438
+ var KIT_REGIONS = /* @__PURE__ */ new Set(["header", "asof", "refresh", "theme", "nav", "filters", "controls", "band"]);
6439
6439
  var DASHBOARD_KIND = "dashboard";
6440
6440
  var BAND_ROLE = "band";
6441
6441
  var GRID_CLASSES = /* @__PURE__ */ new Set(["dr-dash", "dr-grid"]);
@@ -17261,7 +17261,7 @@ var contract_schema_default = {
17261
17261
  properties: {
17262
17262
  file: { type: "string" },
17263
17263
  tokens: { type: "object", additionalProperties: { type: "string" } },
17264
- preset: { type: "string", enum: ["default", "slate", "warm", "contrast", "presentation"], description: "OPTIONAL. A named look from the pinned ui-kit (presentation is refused: ui-kit/v4 shipped without it); absent means default. The compiler fills pages[].theme/density where a page states none from this and app.theme.density, and drops both keys from the filled contract it compares (mirrors fillHeaders)." },
17264
+ preset: { type: "string", enum: ["default", "slate", "warm", "contrast", "presentation"], description: "OPTIONAL. A named look from the pinned ui-kit (presentation is refused: ui-kit/v4 shipped without it); absent means default. A dashboard is built light: slate composes as default, because dark is the viewer's Dark mode switch (the theme region). The compiler fills pages[].theme/density where a page states none from this and app.theme.density, and drops both keys from the filled contract it compares (mirrors fillHeaders)." },
17265
17265
  density: { type: "string", enum: ["comfortable", "compact"], description: "OPTIONAL. app.theme.density; absent means comfortable. Distinct from pages[].density, which is the compiled data-dr-density string." }
17266
17266
  }
17267
17267
  }
@@ -17277,7 +17277,7 @@ var contract_schema_default = {
17277
17277
  module: { type: "string", description: "dr-widgets, dr-insights, dr-fmt, echarts, ui-kit" },
17278
17278
  version: { type: "string", description: "1.1.1 for a vendor module, v3 for the ui-kit" },
17279
17279
  file: { type: "string" },
17280
- path: { type: "string", description: "the platform-root path, e.g. vendor/dr-widgets@1.2.1/widgets.js" },
17280
+ path: { type: "string", description: "the platform-root path, e.g. vendor/dr-widgets@1.2.3/widgets.js" },
17281
17281
  rel: { enum: ["script", "stylesheet"] },
17282
17282
  pages: { type: "array", items: { type: "string" } },
17283
17283
  order: { type: "integer", minimum: 0, description: "load order: where this module is first reached across the bundle" }
@@ -17326,7 +17326,7 @@ var contract_schema_default = {
17326
17326
  }
17327
17327
  },
17328
17328
  scripts: { type: "array", items: { type: "string" }, description: "the bundle scripts this page loads" },
17329
- theme: { type: ["string", "null"], description: "data-dr-theme: default, slate, warm, contrast" },
17329
+ theme: { type: ["string", "null"], description: "data-dr-theme: default, warm, contrast. A dashboard is built light, so slate composes as default (dark is the viewer's Dark mode switch); a page read back from a dashboard built before that may still say slate." },
17330
17330
  density: { type: ["string", "null"], description: "data-dr-density" },
17331
17331
  mount: {
17332
17332
  oneOf: [
@@ -17446,7 +17446,7 @@ var contract_schema_default = {
17446
17446
  enum: ["region", "grid", "widget", "control", "nav", "tab", "slot", "form", "list", "detail", "queue", "action", "filter", "stat", "chart", "custom", "field", "number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns", "slider", "button", "status", "badge", "tag", "empty_state", "stepper", "alert", "checkbox", "radio_group", "file_upload", "skeleton", "progress", "accordion", "tooltip_info", "filter_bar", "filter_chip", "date_range", "fiscal_month", "search_input", "split_pane", "file_viewer", "line_grid", "document", "panel"],
17447
17447
  description: "the dashboard vocabulary (region, grid, widget, control, nav, tab, slot) and the App Builder's component vocabulary (form, list, detail, queue, action, filter, the stat tile that reads one measure out of a summary handler, the chart that draws the rows one list, inbox or custom handler answers, the custom component a module under ui/components draws, and the field that sits inside one). widget is shared: on an app page it is a dashboard card too, drawn by dr-app-widgets in the kind data-dr-kind names, over the one widget payload the handler data-dr-source names answers"
17448
17448
  },
17449
- role: { type: ["string", "null"], description: "a region's data-dr-kit (header, asof, refresh, nav, filters, controls), a widget's kind, a control's kind, a slot's name. Null for a component: its kind IS its type, and the role it is meant for is props.role." },
17449
+ role: { type: ["string", "null"], description: "a region's data-dr-kit (header, asof, refresh, theme, nav, filters, controls), a widget's kind, a control's kind, a slot's name. Null for a component: its kind IS its type, and the role it is meant for is props.role." },
17450
17450
  id: { type: ["string", "null"] },
17451
17451
  tag: { type: ["string", "null"], description: "null for an element read out of a built bundle, which no longer says what it renders" },
17452
17452
  classes: { type: "array", items: { type: "string" } },
@@ -19808,6 +19808,9 @@ import { fileURLToPath as fileURLToPath2 } from "url";
19808
19808
  var THEME_FILE3 = "ui/theme.css";
19809
19809
  var PRESETS2 = ["default", "slate", "warm", "contrast"];
19810
19810
  var DEFAULT_PRESET = "default";
19811
+ var DARK_PRESET = "slate";
19812
+ var CANVAS_TOKENS = /* @__PURE__ */ new Set(["--dr-surface", "--dr-page", "--dr-border"]);
19813
+ var DARK_SURFACE_BELOW = 0.18;
19811
19814
  var SPAN_BY_KIND = {
19812
19815
  kpi: 3,
19813
19816
  line: 6,
@@ -19890,13 +19893,21 @@ function composeLayout(contract) {
19890
19893
  const app = isPlainObject7(out.app) ? out.app : out.app = {};
19891
19894
  const pages = Array.isArray(out.pages) ? out.pages : out.pages = [];
19892
19895
  const elements = isPlainObject7(out.elements) ? out.elements : out.elements = {};
19893
- const preset = presetOf(app, pages);
19896
+ const asked = presetOf(app, pages);
19897
+ const preset = asked === DARK_PRESET ? DEFAULT_PRESET : asked;
19894
19898
  if (isPlainObject7(app.theme) && "preset" in app.theme) delete app.theme.preset;
19895
19899
  for (const page of pages) {
19896
19900
  const path3 = page.path ?? "ui/index.html";
19897
19901
  if (page.theme === void 0 || page.theme === null) {
19898
19902
  page.theme = preset;
19899
19903
  record2("page.theme", path3, `${path3} opens on the "${preset}" theme`);
19904
+ } else if (page.theme === DARK_PRESET) {
19905
+ page.theme = DEFAULT_PRESET;
19906
+ record2(
19907
+ "page.theme",
19908
+ path3,
19909
+ `${path3} opens on the "${DEFAULT_PRESET}" theme: "${DARK_PRESET}" is the viewer's Dark mode switch, not a look a dashboard is built on`
19910
+ );
19900
19911
  }
19901
19912
  if (page.density === void 0) page.density = null;
19902
19913
  if (page.title === void 0 || page.title === null) {
@@ -19971,6 +19982,21 @@ function composeTheme(app, preset, record2) {
19971
19982
  const table = THEME_TOKENS[preset] ?? THEME_TOKENS[DEFAULT_PRESET];
19972
19983
  const theme = isPlainObject7(app.theme) ? app.theme : {};
19973
19984
  const tokens = isPlainObject7(theme.tokens) ? { ...theme.tokens } : {};
19985
+ const dark = THEME_TOKENS[DARK_PRESET];
19986
+ if (isDarkSurface(tokens["--dr-surface"], dark["--dr-surface"], tokens)) {
19987
+ let lightened = 0;
19988
+ for (const [token, value] of Object.entries(dark)) {
19989
+ if (table[token] === void 0 || tokens[token] === table[token]) continue;
19990
+ if (tokens[token] !== value && !CANVAS_TOKENS.has(token)) continue;
19991
+ tokens[token] = table[token];
19992
+ lightened += 1;
19993
+ }
19994
+ record2(
19995
+ "theme.tokens",
19996
+ THEME_FILE3,
19997
+ `${lightened} palette token(s) moved from the "${DARK_PRESET}" preset to "${preset}": a dashboard is built light, and dark is the viewer's Dark mode switch`
19998
+ );
19999
+ }
19974
20000
  let filled = 0;
19975
20001
  for (const [token, value] of Object.entries(table)) {
19976
20002
  if (token in tokens) continue;
@@ -19986,6 +20012,21 @@ function composeTheme(app, preset, record2) {
19986
20012
  );
19987
20013
  }
19988
20014
  }
20015
+ function isDarkSurface(value, darkSurface, tokens, seen = /* @__PURE__ */ new Set()) {
20016
+ if (typeof value !== "string") return false;
20017
+ const alias = /^var\(\s*(--[a-z0-9-]+)\s*(?:,[^)]*)?\)$/i.exec(value.trim());
20018
+ if (alias) {
20019
+ if (seen.has(alias[1])) return false;
20020
+ seen.add(alias[1]);
20021
+ return isDarkSurface(tokens[alias[1]], darkSurface, tokens, seen);
20022
+ }
20023
+ if (value === darkSurface) return true;
20024
+ try {
20025
+ return luminance(value) < DARK_SURFACE_BELOW;
20026
+ } catch {
20027
+ return false;
20028
+ }
20029
+ }
19989
20030
  function presetOf(app, pages) {
19990
20031
  const asked = isPlainObject7(app.theme) ? app.theme.preset : null;
19991
20032
  if (typeof asked === "string" && PRESETS2.includes(asked)) return asked;
@@ -20371,6 +20412,9 @@ function appbar(page, elements) {
20371
20412
  " </div>",
20372
20413
  ' <div class="dr-appbar__actions">',
20373
20414
  ` <button type="button" class="${classesOf2(elements, "region", "refresh", ["dr-btn", "dr-btn--secondary", "dr-btn--sm"])}" data-dr-kit="refresh">Refresh</button>`,
20415
+ // The viewer's light/dark switch: dr-widgets flips the body between this
20416
+ // page's own preset and slate, and remembers the choice per app.
20417
+ ` <button type="button" class="${classesOf2(elements, "region", "theme", ["dr-btn", "dr-btn--secondary", "dr-btn--sm"])}" data-dr-kit="theme" aria-pressed="false">Dark mode</button>`,
20374
20418
  " </div>",
20375
20419
  "</header>"
20376
20420
  ];
@@ -27131,7 +27175,7 @@ var kit_default = {
27131
27175
  fmt: "dr-fmt@2.0.1",
27132
27176
  markdown: "dr-md@1.0.0",
27133
27177
  uiKit: "ui-kit/v4",
27134
- widgets: "dr-widgets@1.2.1"
27178
+ widgets: "dr-widgets@1.2.3"
27135
27179
  };
27136
27180
 
27137
27181
  // ../flows/appspace-builder/kit/kit.json
@@ -27721,7 +27765,7 @@ function roundTripDiffs(input, extracted, compilerProblems = [], { order: order2
27721
27765
  const stated2 = order2 === void 0 ? {} : { order: order2 };
27722
27766
  const read = order2 === void 0 ? {} : { order: "keys" };
27723
27767
  const left = stripPositional(normaliseApp(input), stated2);
27724
- const right = stripPositional(normaliseApp(extracted), read);
27768
+ const right = stripPositional(normaliseApp(withoutUnstatedChrome(input, extracted)), read);
27725
27769
  const declared = compilerProblems.some((problem5) => problem5.code === DECLARED_LOSS);
27726
27770
  const diffs = [];
27727
27771
  for (const section of ["app", "pages", "elements", "data"]) {
@@ -27746,6 +27790,40 @@ function roundTripDiffs(input, extracted, compilerProblems = [], { order: order2
27746
27790
  }
27747
27791
  return diffs.slice(0, 40);
27748
27792
  }
27793
+ var ADDED_CHROME = /* @__PURE__ */ new Set(["theme"]);
27794
+ function withoutUnstatedChrome(input, extracted) {
27795
+ if (!isPlain(input) || !isPlain(extracted)) return extracted;
27796
+ const want = input["elements"];
27797
+ const got = extracted["elements"];
27798
+ if (!isPlain(want) || !isPlain(got)) return extracted;
27799
+ const regionOf = (element) => `${String(element["page"] ?? "")}|${String(element["role"] ?? "")}`;
27800
+ const statedRegions = new Set(
27801
+ Object.values(want).filter((element) => isPlain(element) && element["type"] === "region").map(regionOf)
27802
+ );
27803
+ const unstated = new Set(
27804
+ Object.entries(got).filter(([, element]) => {
27805
+ if (!isPlain(element) || element["type"] !== "region") return false;
27806
+ if (!ADDED_CHROME.has(String(element["role"] ?? ""))) return false;
27807
+ const children = element["children"];
27808
+ return !statedRegions.has(regionOf(element)) && (!Array.isArray(children) || children.length === 0);
27809
+ }).map(([uid]) => uid)
27810
+ );
27811
+ if (unstated.size === 0) return extracted;
27812
+ const out = JSON.parse(JSON.stringify(extracted));
27813
+ const elements = out["elements"];
27814
+ for (const uid of unstated) delete elements[uid];
27815
+ for (const element of Object.values(elements)) {
27816
+ if (isPlain(element) && Array.isArray(element["children"])) {
27817
+ element["children"] = element["children"].filter((uid) => !unstated.has(String(uid)));
27818
+ }
27819
+ }
27820
+ for (const page of Array.isArray(out["pages"]) ? out["pages"] : []) {
27821
+ if (isPlain(page) && Array.isArray(page["tree"])) {
27822
+ page["tree"] = page["tree"].filter((uid) => !unstated.has(String(uid)));
27823
+ }
27824
+ }
27825
+ return out;
27826
+ }
27749
27827
  function normaliseApp(contract) {
27750
27828
  if (typeof contract !== "object" || contract === null) return contract;
27751
27829
  const out = JSON.parse(JSON.stringify(contract));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datarails-ai/dr-appspace-cli",
3
- "version": "0.12.10",
3
+ "version": "0.12.12",
4
4
  "description": "Datarails App Space CLI — build, try, push and publish App Space apps",
5
5
  "type": "module",
6
6
  "engines": {