@wildwinter/app-shell 0.55.0 → 0.56.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 +44 -0
- package/dist/controls.css +29 -0
- package/dist/controls.css.map +1 -1
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/tokens.css +1 -1
- package/dist/tokens.css.map +1 -1
- package/dist/value-rows.cjs +89 -10
- package/dist/value-rows.cjs.map +1 -1
- package/dist/value-rows.d.cts +50 -1
- package/dist/value-rows.d.ts +50 -1
- package/dist/value-rows.js +91 -13
- package/dist/value-rows.js.map +1 -1
- package/package.json +1 -1
package/dist/tokens.css
CHANGED
package/dist/tokens.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tokens.css"],"sourcesContent":["/* ============================================================================\n Design-token GRAMMAR - the app-agnostic layer (design-language.md section 4).\n\n The shared half of \"two palettes, one grammar\": the scales that are IDENTICAL\n across the editor family - elevation, motion, radius, scrollbar chrome. Each\n app supplies its own colour + font VALUES (its palette) over this grammar in\n its own theme.css. Do not add app-specific colours here.\n\n SCALE. Chrome is sized in px off a 14px base; the reading surface alone\n scales with the root (\"Chrome has its own scale\", design-language.md\n section 4, 2026-09-16). Every size in the shell's stylesheets (font-size,\n padding, gap, margin, width, height) is a pixel value: the navigator, the\n inspector, the bars, the dialogs and the controls in them read the same in\n every app of the family whatever the reading size is. `em` survives only\n where a rule deliberately scales with its own font; line-heights stay\n unitless. The values are what Storyletter rendered at 0.39.0 (rem x 16, to\n the nearest half pixel), so the conversion moved nothing there and brought\n Patterpad, whose chrome had grown 7 to 10 percent with its reading root,\n back to the same size. No `rem` in a chrome rule; the test suite greps.\n ============================================================================ */\n\n:root {\n color-scheme: light dark;\n\n /* The semantic set's third member, and the only COLOUR in this file.\n\n It is here because it kept not being anywhere. An app's palette owns\n --danger and --warn; neither owned \"all is well\", so a real need - the live\n debug link, an in-sync shard, a saved document - was met with a raw green\n literal that could not theme-shift (surface-audit-shell.md F2). A default\n in the grammar layer means the shell's own widgets may say it, and an app\n that has not thought about green yet still gets a green that works on both\n grounds. Every palette should override it in its theme.css, as it does the\n other two: this is a floor, not a decision. */\n --ok: light-dark(#3f7d49, #79bd80);\n\n /* The ink that sits ON the accent: a primary button's label, a selected\n row's text. Every palette overrides it (a light tan accent on a dark\n palette wants dark ink, not white); this floor only stops the shell's own\n primary buttons from falling back to a raw #fff literal, which is what\n they did until 0.39.0 and which read white-on-tan on Night and Slate. */\n --on-accent: light-dark(#ffffff, #1b1916);\n\n /* The chrome base. `.shell-dialog`, `.pane-shell` and `.swin-head` set it as\n their font-size, so unstyled text inside them lands at 14px regardless of\n the app's root; a rule that wants the base by name reads it here. Not a\n scale factor: the sizes below it are literal px, on purpose. */\n --chrome-size: 14px;\n\n /* The one scrim behind every modal in the family (confirm, settings,\n identity, about, notes). Four recipes had grown across five files. */\n --scrim: color-mix(in oklab, var(--ink) 28%, transparent);\n\n /* Elevation: three tiers by how far a surface floats (resting cards,\n floating menus/popovers, full overlays). Theme-agnostic black so it\n deepens naturally on the dark palettes. */\n --shadow-1: 0 1px 3px rgba(0, 0, 0, 0.05);\n --shadow-2: 0 6px 20px rgba(0, 0, 0, 0.14);\n --shadow-3: 0 16px 48px rgba(0, 0, 0, 0.28);\n\n /* Motion: one easing curve + a small duration scale, plus the shared\n panel/backdrop/screen enter-exit vocabulary. Nothing pops. */\n --ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --dur-quick: 120ms;\n --dur-base: 150ms;\n --dur-settle: 200ms;\n --dur-slow: 1s;\n --dur-panel: 260ms;\n --dur-exit: 170ms;\n --anim-panel-in: panel-in var(--dur-panel) var(--ease-standard);\n --anim-backdrop-in: backdrop-in var(--dur-settle) var(--ease-standard);\n --anim-screen-in: screen-in var(--dur-panel) var(--ease-standard);\n --anim-panel-out: panel-out var(--dur-exit) var(--ease-standard) forwards;\n --anim-backdrop-out: backdrop-out var(--dur-exit) var(--ease-standard) forwards;\n /* The long-job strip's indeterminate band (job.css draws the keyframes). */\n --anim-job-band: job-band 1.4s var(--ease-standard) infinite;\n\n /* Corner radius: four steps cover every surface. */\n --radius-sm: 6px;\n --radius-md: 10px;\n --radius-lg: 14px;\n --radius-pill: 999px;\n\n /* Scrollbar thumb: a translucent ink, so it adapts per palette. */\n --scroll-thumb: color-mix(in oklab, var(--ink) 20%, transparent);\n --scroll-thumb-hover: color-mix(in oklab, var(--ink) 40%, transparent);\n}\n\n/* A drawn icon (`iconNode` / `iconHtml` in icons.ts stamp `data-icon`). A\n block, so it never sits on a text baseline with descender space under it;\n no flex shrink, so a crowded row squeezes the text and not the picture; and\n no pointer events, so a click lands on the button and never on the drawing\n (a handler comparing `event.target` to its button would otherwise miss).\n Colour is inherited: every drawing is currentColor. */\n[data-icon] { display: block; flex: none; pointer-events: none; }\n\n/* The family's keyboard focus ring: one rule, zero specificity (:where), so a\n component may draw its own and win without !important. Until 0.39.0\n Patterpad's main window had no ring at all and Storyletter carried five\n copies of this line. Mouse focus stays quiet; only :focus-visible draws. */\n:where(button, [role=\"button\"], input, select, textarea, summary, a[href], [tabindex]):focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 1px;\n}\n\n/* The tracked uppercase caption, kept for exactly two jobs: table column heads\n and screenplay character cues, where uppercase is the domain's own\n convention (design-language.md, \"Captions are words, not overlines\"). A\n section caption anywhere else is sentence-case text at label size, weight\n 600, in the UI face, which is what the shell's own captions now are. */\n.overline { font: 600 10.5px/1 var(--font-ui); text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }\n\n* { scrollbar-width: thin; scrollbar-color: var(--scroll-thumb) transparent; }\n::-webkit-scrollbar { width: 11px; height: 11px; }\n::-webkit-scrollbar-track { background: transparent; }\n::-webkit-scrollbar-corner { background: transparent; }\n::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: var(--radius-sm); border: 3px solid transparent; background-clip: padding-box; }\n::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); background-clip: padding-box; }\n\n@keyframes panel-in { from { opacity: 0; transform: translateY(-9px) scale(0.965); } to { opacity: 1; transform: none; } }\n@keyframes backdrop-in { from { opacity: 0; } to { opacity: 1; } }\n@keyframes screen-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }\n@keyframes panel-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-6px) scale(0.97); } }\n@keyframes backdrop-out { from { opacity: 1; } to { opacity: 0; } }\n\n@media (prefers-reduced-motion: reduce) {\n :root {\n --anim-panel-in: none; --anim-backdrop-in: none; --anim-screen-in: none;\n --anim-panel-out: none; --anim-backdrop-out: none; --anim-job-band: none;\n }\n}\n\n/* A floating layer from createFloating (floating.ts) carries this attribute, because its class is\n the caller's. Never a window-drag region, even over one: Electron gives a click in a drag area to\n the OS before the page sees it (dialog.css has the whole story, 2026-09-28). */\n[data-shell-layer], [data-shell-layer] * { -webkit-app-region: no-drag; }\n"],"mappings":";AAqBA;AACE,gBAAc,MAAM;AAYpB,QAAM,WAAW,OAAO,EAAE;AAO1B,eAAa,WAAW,OAAO,EAAE;AAMjC,iBAAe;AAIf,WAAS,UAAU,GAAG,KAAK,EAAE,IAAI,OAAO,GAAG,EAAE;AAK7C,cAAY,EAAE,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACpC,cAAY,EAAE,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACrC,cAAY,EAAE,KAAK,KAAK,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAItC,mBAAiB,aAAa,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE;AACzC,eAAa;AACb,cAAY;AACZ,gBAAc;AACd,cAAY;AACZ,eAAa;AACb,cAAY;AACZ,mBAAiB,SAAS,IAAI,aAAa,IAAI;AAC/C,sBAAoB,YAAY,IAAI,cAAc,IAAI;AACtD,oBAAkB,UAAU,IAAI,aAAa,IAAI;AACjD,oBAAkB,UAAU,IAAI,YAAY,IAAI,iBAAiB;AACjE,uBAAqB,aAAa,IAAI,YAAY,IAAI,iBAAiB;AAEvE,mBAAiB,SAAS,KAAK,IAAI,iBAAiB;AAGpD,eAAa;AACb,eAAa;AACb,eAAa;AACb,iBAAe;AAGf,kBAAgB,UAAU,GAAG,KAAK,EAAE,IAAI,OAAO,GAAG,EAAE;AACpD,wBAAsB,UAAU,GAAG,KAAK,EAAE,IAAI,OAAO,GAAG,EAAE;AAC5D;AAQA,CAAC;AAAa,WAAS;AAAO,QAAM;AAAM,kBAAgB;AAAM;AAMhE,OAAO,QAAQ,CAAC,cAAgB,OAAO,QAAQ,UAAU,SAAS,CAAC,CAAC,OAAO,CAAC,UAAU;AACpF,WAAS,IAAI,MAAM,IAAI;AACvB,kBAAgB;AAClB;AAOA,CAAC;AAAW,QAAM,IAAI,MAAM,CAAC,EAAE,IAAI;AAAY,kBAAgB;AAAW,kBAAgB;AAAQ,SAAO,IAAI;AAAU;AAEvH;AAAI,mBAAiB;AAAM,mBAAiB,IAAI,gBAAgB;AAAa;AAC7E;AAAsB,SAAO;AAAM,UAAQ;AAAM;AACjD;AAA4B,cAAY;AAAa;AACrD;AAA6B,cAAY;AAAa;AACtD;AAA4B,cAAY,IAAI;AAAiB,iBAAe,IAAI;AAAc,UAAQ,IAAI,MAAM;AAAa,mBAAiB;AAAa;AAC3J,yBAAyB;AAAS,cAAY,IAAI;AAAuB,mBAAiB;AAAa;AAEvG,WAAW;AAAW;AAAO,aAAS;AAAG,eAAW,WAAW,MAAM,MAAM;AAAQ;AAAE;AAAK,aAAS;AAAG,eAAW;AAAM;AAAE;AACzH,WAAW;AAAc;AAAO,aAAS;AAAG;AAAE;AAAK,aAAS;AAAG;AAAE;AACjE,WAAW;AAAY;AAAO,aAAS;AAAG,eAAW,WAAW;AAAM;AAAE;AAAK,aAAS;AAAG,eAAW;AAAM;AAAE;AAC5G,WAAW;AAAY;AAAO,aAAS;AAAG,eAAW;AAAM;AAAE;AAAK,aAAS;AAAG,eAAW,WAAW,MAAM,MAAM;AAAO;AAAE;AACzH,WAAW;AAAe;AAAO,aAAS;AAAG;AAAE;AAAK,aAAS;AAAG;AAAE;AAElE,QAAO,wBAAyB;AAC9B;AACE,qBAAiB;AAAM,wBAAoB;AAAM,sBAAkB;AACnE,sBAAkB;AAAM,yBAAqB;AAAM,qBAAiB;AACtE;AACF;AAKA,CAAC;AAAmB,CAAC,kBAAkB;AAAI,sBAAoB;AAAS;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/tokens.css"],"sourcesContent":["/* ============================================================================\n Design-token GRAMMAR - the app-agnostic layer (design-language.md section 4).\n\n The shared half of \"two palettes, one grammar\": the scales that are IDENTICAL\n across the editor family - elevation, motion, radius, scrollbar chrome. Each\n app supplies its own colour + font VALUES (its palette) over this grammar in\n its own theme.css. Do not add app-specific colours here.\n\n SCALE. Chrome is sized in px off a 14px base; the reading surface alone\n scales with the root (\"Chrome has its own scale\", design-language.md\n section 4, 2026-09-16). Every size in the shell's stylesheets (font-size,\n padding, gap, margin, width, height) is a pixel value: the navigator, the\n inspector, the bars, the dialogs and the controls in them read the same in\n every app of the family whatever the reading size is. `em` survives only\n where a rule deliberately scales with its own font; line-heights stay\n unitless. The values are what Storyletter rendered at 0.39.0 (rem x 16, to\n the nearest half pixel), so the conversion moved nothing there and brought\n Patterpad, whose chrome had grown 7 to 10 percent with its reading root,\n back to the same size. No `rem` in a chrome rule; the test suite greps.\n ============================================================================ */\n\n:root {\n /* Native controls (an unticked checkbox, a radio, a scrollbar, a select's\n pop-up, a date field) and every light-dark() below follow this, so it must\n follow the palette the author chose, not the OS: a light palette under a\n dark OS drew every unticked checkbox as a dark filled square. Every palette\n block in an app's theme.css declares `--color-scheme: light` or `dark`;\n with no palette chosen the fallback follows the OS, as before. */\n color-scheme: var(--color-scheme, light dark);\n\n /* The semantic set's third member, and the only COLOUR in this file.\n\n It is here because it kept not being anywhere. An app's palette owns\n --danger and --warn; neither owned \"all is well\", so a real need - the live\n debug link, an in-sync shard, a saved document - was met with a raw green\n literal that could not theme-shift (surface-audit-shell.md F2). A default\n in the grammar layer means the shell's own widgets may say it, and an app\n that has not thought about green yet still gets a green that works on both\n grounds. Every palette should override it in its theme.css, as it does the\n other two: this is a floor, not a decision. */\n --ok: light-dark(#3f7d49, #79bd80);\n\n /* The ink that sits ON the accent: a primary button's label, a selected\n row's text. Every palette overrides it (a light tan accent on a dark\n palette wants dark ink, not white); this floor only stops the shell's own\n primary buttons from falling back to a raw #fff literal, which is what\n they did until 0.39.0 and which read white-on-tan on Night and Slate. */\n --on-accent: light-dark(#ffffff, #1b1916);\n\n /* The chrome base. `.shell-dialog`, `.pane-shell` and `.swin-head` set it as\n their font-size, so unstyled text inside them lands at 14px regardless of\n the app's root; a rule that wants the base by name reads it here. Not a\n scale factor: the sizes below it are literal px, on purpose. */\n --chrome-size: 14px;\n\n /* The one scrim behind every modal in the family (confirm, settings,\n identity, about, notes). Four recipes had grown across five files. */\n --scrim: color-mix(in oklab, var(--ink) 28%, transparent);\n\n /* Elevation: three tiers by how far a surface floats (resting cards,\n floating menus/popovers, full overlays). Theme-agnostic black so it\n deepens naturally on the dark palettes. */\n --shadow-1: 0 1px 3px rgba(0, 0, 0, 0.05);\n --shadow-2: 0 6px 20px rgba(0, 0, 0, 0.14);\n --shadow-3: 0 16px 48px rgba(0, 0, 0, 0.28);\n\n /* Motion: one easing curve + a small duration scale, plus the shared\n panel/backdrop/screen enter-exit vocabulary. Nothing pops. */\n --ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --dur-quick: 120ms;\n --dur-base: 150ms;\n --dur-settle: 200ms;\n --dur-slow: 1s;\n --dur-panel: 260ms;\n --dur-exit: 170ms;\n --anim-panel-in: panel-in var(--dur-panel) var(--ease-standard);\n --anim-backdrop-in: backdrop-in var(--dur-settle) var(--ease-standard);\n --anim-screen-in: screen-in var(--dur-panel) var(--ease-standard);\n --anim-panel-out: panel-out var(--dur-exit) var(--ease-standard) forwards;\n --anim-backdrop-out: backdrop-out var(--dur-exit) var(--ease-standard) forwards;\n /* The long-job strip's indeterminate band (job.css draws the keyframes). */\n --anim-job-band: job-band 1.4s var(--ease-standard) infinite;\n\n /* Corner radius: four steps cover every surface. */\n --radius-sm: 6px;\n --radius-md: 10px;\n --radius-lg: 14px;\n --radius-pill: 999px;\n\n /* Scrollbar thumb: a translucent ink, so it adapts per palette. */\n --scroll-thumb: color-mix(in oklab, var(--ink) 20%, transparent);\n --scroll-thumb-hover: color-mix(in oklab, var(--ink) 40%, transparent);\n}\n\n/* A drawn icon (`iconNode` / `iconHtml` in icons.ts stamp `data-icon`). A\n block, so it never sits on a text baseline with descender space under it;\n no flex shrink, so a crowded row squeezes the text and not the picture; and\n no pointer events, so a click lands on the button and never on the drawing\n (a handler comparing `event.target` to its button would otherwise miss).\n Colour is inherited: every drawing is currentColor. */\n[data-icon] { display: block; flex: none; pointer-events: none; }\n\n/* The family's keyboard focus ring: one rule, zero specificity (:where), so a\n component may draw its own and win without !important. Until 0.39.0\n Patterpad's main window had no ring at all and Storyletter carried five\n copies of this line. Mouse focus stays quiet; only :focus-visible draws. */\n:where(button, [role=\"button\"], input, select, textarea, summary, a[href], [tabindex]):focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 1px;\n}\n\n/* The tracked uppercase caption, kept for exactly two jobs: table column heads\n and screenplay character cues, where uppercase is the domain's own\n convention (design-language.md, \"Captions are words, not overlines\"). A\n section caption anywhere else is sentence-case text at label size, weight\n 600, in the UI face, which is what the shell's own captions now are. */\n.overline { font: 600 10.5px/1 var(--font-ui); text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }\n\n* { scrollbar-width: thin; scrollbar-color: var(--scroll-thumb) transparent; }\n::-webkit-scrollbar { width: 11px; height: 11px; }\n::-webkit-scrollbar-track { background: transparent; }\n::-webkit-scrollbar-corner { background: transparent; }\n::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: var(--radius-sm); border: 3px solid transparent; background-clip: padding-box; }\n::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); background-clip: padding-box; }\n\n@keyframes panel-in { from { opacity: 0; transform: translateY(-9px) scale(0.965); } to { opacity: 1; transform: none; } }\n@keyframes backdrop-in { from { opacity: 0; } to { opacity: 1; } }\n@keyframes screen-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }\n@keyframes panel-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-6px) scale(0.97); } }\n@keyframes backdrop-out { from { opacity: 1; } to { opacity: 0; } }\n\n@media (prefers-reduced-motion: reduce) {\n :root {\n --anim-panel-in: none; --anim-backdrop-in: none; --anim-screen-in: none;\n --anim-panel-out: none; --anim-backdrop-out: none; --anim-job-band: none;\n }\n}\n\n/* A floating layer from createFloating (floating.ts) carries this attribute, because its class is\n the caller's. Never a window-drag region, even over one: Electron gives a click in a drag area to\n the OS before the page sees it (dialog.css has the whole story, 2026-09-28). */\n[data-shell-layer], [data-shell-layer] * { -webkit-app-region: no-drag; }\n"],"mappings":";AAqBA;AAOE,gBAAc,IAAI,cAAc,EAAE,MAAM;AAYxC,QAAM,WAAW,OAAO,EAAE;AAO1B,eAAa,WAAW,OAAO,EAAE;AAMjC,iBAAe;AAIf,WAAS,UAAU,GAAG,KAAK,EAAE,IAAI,OAAO,GAAG,EAAE;AAK7C,cAAY,EAAE,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACpC,cAAY,EAAE,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACrC,cAAY,EAAE,KAAK,KAAK,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAItC,mBAAiB,aAAa,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE;AACzC,eAAa;AACb,cAAY;AACZ,gBAAc;AACd,cAAY;AACZ,eAAa;AACb,cAAY;AACZ,mBAAiB,SAAS,IAAI,aAAa,IAAI;AAC/C,sBAAoB,YAAY,IAAI,cAAc,IAAI;AACtD,oBAAkB,UAAU,IAAI,aAAa,IAAI;AACjD,oBAAkB,UAAU,IAAI,YAAY,IAAI,iBAAiB;AACjE,uBAAqB,aAAa,IAAI,YAAY,IAAI,iBAAiB;AAEvE,mBAAiB,SAAS,KAAK,IAAI,iBAAiB;AAGpD,eAAa;AACb,eAAa;AACb,eAAa;AACb,iBAAe;AAGf,kBAAgB,UAAU,GAAG,KAAK,EAAE,IAAI,OAAO,GAAG,EAAE;AACpD,wBAAsB,UAAU,GAAG,KAAK,EAAE,IAAI,OAAO,GAAG,EAAE;AAC5D;AAQA,CAAC;AAAa,WAAS;AAAO,QAAM;AAAM,kBAAgB;AAAM;AAMhE,OAAO,QAAQ,CAAC,cAAgB,OAAO,QAAQ,UAAU,SAAS,CAAC,CAAC,OAAO,CAAC,UAAU;AACpF,WAAS,IAAI,MAAM,IAAI;AACvB,kBAAgB;AAClB;AAOA,CAAC;AAAW,QAAM,IAAI,MAAM,CAAC,EAAE,IAAI;AAAY,kBAAgB;AAAW,kBAAgB;AAAQ,SAAO,IAAI;AAAU;AAEvH;AAAI,mBAAiB;AAAM,mBAAiB,IAAI,gBAAgB;AAAa;AAC7E;AAAsB,SAAO;AAAM,UAAQ;AAAM;AACjD;AAA4B,cAAY;AAAa;AACrD;AAA6B,cAAY;AAAa;AACtD;AAA4B,cAAY,IAAI;AAAiB,iBAAe,IAAI;AAAc,UAAQ,IAAI,MAAM;AAAa,mBAAiB;AAAa;AAC3J,yBAAyB;AAAS,cAAY,IAAI;AAAuB,mBAAiB;AAAa;AAEvG,WAAW;AAAW;AAAO,aAAS;AAAG,eAAW,WAAW,MAAM,MAAM;AAAQ;AAAE;AAAK,aAAS;AAAG,eAAW;AAAM;AAAE;AACzH,WAAW;AAAc;AAAO,aAAS;AAAG;AAAE;AAAK,aAAS;AAAG;AAAE;AACjE,WAAW;AAAY;AAAO,aAAS;AAAG,eAAW,WAAW;AAAM;AAAE;AAAK,aAAS;AAAG,eAAW;AAAM;AAAE;AAC5G,WAAW;AAAY;AAAO,aAAS;AAAG,eAAW;AAAM;AAAE;AAAK,aAAS;AAAG,eAAW,WAAW,MAAM,MAAM;AAAO;AAAE;AACzH,WAAW;AAAe;AAAO,aAAS;AAAG;AAAE;AAAK,aAAS;AAAG;AAAE;AAElE,QAAO,wBAAyB;AAC9B;AACE,qBAAiB;AAAM,wBAAoB;AAAM,sBAAkB;AACnE,sBAAkB;AAAM,yBAAqB;AAAM,qBAAiB;AACtE;AACF;AAKA,CAAC;AAAmB,CAAC,kBAAkB;AAAI,sBAAoB;AAAS;","names":[]}
|
package/dist/value-rows.cjs
CHANGED
|
@@ -826,13 +826,89 @@ var fieldRowFocus = {
|
|
|
826
826
|
settle: (row) => keeper.settle(row),
|
|
827
827
|
restore: (row) => keeper.restore(row)
|
|
828
828
|
};
|
|
829
|
+
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
830
|
+
function isSet(decl, value) {
|
|
831
|
+
if (value === void 0) return false;
|
|
832
|
+
if (decl.type === "record" && decl.default === void 0 && isObject(value)) {
|
|
833
|
+
const fields = decl.fields ?? [];
|
|
834
|
+
const declared = new Set(fields.map((f) => f.name));
|
|
835
|
+
if (Object.entries(value).some(([k, v]) => !declared.has(k) && v !== void 0)) return true;
|
|
836
|
+
return fields.some((f) => isSet(f, value[f.name]));
|
|
837
|
+
}
|
|
838
|
+
return extensions.stableStringify(value) !== extensions.stableStringify(extensions.defaultOf(decl));
|
|
839
|
+
}
|
|
840
|
+
function foldCaption(name, set) {
|
|
841
|
+
return set > 0 ? `${name} (${set} set)` : name;
|
|
842
|
+
}
|
|
843
|
+
function extensionFold() {
|
|
844
|
+
const open = /* @__PURE__ */ new Set();
|
|
845
|
+
const shown = /* @__PURE__ */ new Map();
|
|
846
|
+
const keyOf = (o) => `${o.extension}\0${o.node}`;
|
|
847
|
+
const visible = (o, setNames) => {
|
|
848
|
+
const was = shown.get(keyOf(o));
|
|
849
|
+
const fields = was ? /* @__PURE__ */ new Set([...was.fields, ...setNames]) : new Set(setNames);
|
|
850
|
+
shown.set(keyOf(o), { fields, used: true });
|
|
851
|
+
return fields;
|
|
852
|
+
};
|
|
853
|
+
const fold = {
|
|
854
|
+
isOpen: (extension) => open.has(extension),
|
|
855
|
+
setOpen(extension, on) {
|
|
856
|
+
if (on) open.add(extension);
|
|
857
|
+
else open.delete(extension);
|
|
858
|
+
for (const key of shown.keys()) if (key.startsWith(`${extension}\0`)) shown.delete(key);
|
|
859
|
+
},
|
|
860
|
+
sweep() {
|
|
861
|
+
for (const [key, entry] of shown) {
|
|
862
|
+
if (!entry.used) shown.delete(key);
|
|
863
|
+
else entry.used = false;
|
|
864
|
+
}
|
|
865
|
+
},
|
|
866
|
+
section(o) {
|
|
867
|
+
const sec = el("div", `shell-fold${o.className ? ` ${o.className}` : ""}`);
|
|
868
|
+
sec.dataset["extension"] = o.extension;
|
|
869
|
+
const cap = el("button", `shell-fold-cap${o.captionClassName ? ` ${o.captionClassName}` : ""}`);
|
|
870
|
+
cap.type = "button";
|
|
871
|
+
const body = el("div", "shell-fold-body");
|
|
872
|
+
sec.append(cap, body);
|
|
873
|
+
const draw = () => {
|
|
874
|
+
const isOpen = open.has(o.extension);
|
|
875
|
+
const setNames = new Set(o.fields.filter((f) => isSet(f, o.entry?.[f.name])).map((f) => f.name));
|
|
876
|
+
const show2 = isOpen ? void 0 : visible(o, setNames);
|
|
877
|
+
cap.replaceChildren(iconNode(isOpen ? "expanded" : "collapsed"), el("span", "shell-fold-name", foldCaption(o.caption, setNames.size)));
|
|
878
|
+
cap.setAttribute("aria-expanded", String(isOpen));
|
|
879
|
+
cap.dataset["tip"] = isOpen ? `Show only the fields set here` : `Show every ${o.caption} field`;
|
|
880
|
+
sec.classList.toggle("shell-fold-open", isOpen);
|
|
881
|
+
const rows = [...o.lead ?? []];
|
|
882
|
+
let group;
|
|
883
|
+
for (const decl of o.fields) {
|
|
884
|
+
if (show2 && !show2.has(decl.name)) continue;
|
|
885
|
+
const g = decl.group;
|
|
886
|
+
if (g !== void 0 && g !== group) {
|
|
887
|
+
group = g;
|
|
888
|
+
rows.push(o.group(g));
|
|
889
|
+
}
|
|
890
|
+
rows.push(o.row(decl));
|
|
891
|
+
}
|
|
892
|
+
rows.push(...o.tail ?? []);
|
|
893
|
+
body.replaceChildren(...rows);
|
|
894
|
+
};
|
|
895
|
+
cap.addEventListener("click", () => {
|
|
896
|
+
fold.setOpen(o.extension, !open.has(o.extension));
|
|
897
|
+
draw();
|
|
898
|
+
});
|
|
899
|
+
draw();
|
|
900
|
+
return sec;
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
return fold;
|
|
904
|
+
}
|
|
829
905
|
|
|
830
906
|
// src/value-rows.ts
|
|
831
907
|
function nodeLabel(adapter, kind, id) {
|
|
832
908
|
return adapter.nodes(kind).find((n) => n.id === id)?.label ?? adapter.label?.(kind, id);
|
|
833
909
|
}
|
|
834
910
|
var SCALARS = /* @__PURE__ */ new Set(["text", "multiline", "number", "boolean", "enum", "flags", "quality", "string"]);
|
|
835
|
-
var
|
|
911
|
+
var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
836
912
|
var nameOf = (decl) => decl.label ?? decl.name;
|
|
837
913
|
var asDecl = (d, name) => ({ ...d, name: d.name ?? name });
|
|
838
914
|
function ownProblems(decl, value, adapter) {
|
|
@@ -1071,31 +1147,31 @@ function structuredRow(initial) {
|
|
|
1071
1147
|
}, controls));
|
|
1072
1148
|
};
|
|
1073
1149
|
if (decl.type === "record") {
|
|
1074
|
-
const value =
|
|
1150
|
+
const value = isObject2(o.value) ? o.value : void 0;
|
|
1075
1151
|
const required = value === void 0 ? [] : extensions.valueProblems(decl, value).filter((p) => p.code === "required");
|
|
1076
1152
|
for (const f of decl.fields ?? []) {
|
|
1077
1153
|
const missing = required.find((p) => p.path === f.name);
|
|
1078
1154
|
child(`f:${f.name}`, f, value?.[f.name], (v) => {
|
|
1079
|
-
const next = { ...
|
|
1155
|
+
const next = { ...isObject2(opts.value) ? opts.value : {} };
|
|
1080
1156
|
if (v === void 0) delete next[f.name];
|
|
1081
1157
|
else next[f.name] = v;
|
|
1082
1158
|
commit(Object.keys(next).length > 0 ? next : void 0);
|
|
1083
1159
|
}, void 0, void 0, missing ? "Required." : void 0);
|
|
1084
1160
|
}
|
|
1085
1161
|
} else if (decl.type === "map" && decl.of) {
|
|
1086
|
-
const value =
|
|
1162
|
+
const value = isObject2(o.value) ? o.value : {};
|
|
1087
1163
|
const keyNodes = decl.key?.type === "reference" && o.adapter ? o.adapter.nodes(decl.key.to ?? "") : void 0;
|
|
1088
1164
|
const keyKind = decl.key?.to ?? "";
|
|
1089
1165
|
const keyLabel = (k) => (o.adapter && keyNodes !== void 0 ? nodeLabel(o.adapter, keyKind, k) : void 0) ?? k;
|
|
1090
1166
|
for (const k of Object.keys(value)) {
|
|
1091
1167
|
const remove = editable() ? [iconBtn("close", `Remove ${keyLabel(k)}`, () => {
|
|
1092
|
-
const next = { ...
|
|
1168
|
+
const next = { ...isObject2(opts.value) ? opts.value : {} };
|
|
1093
1169
|
delete next[k];
|
|
1094
1170
|
commit(Object.keys(next).length > 0 ? next : void 0);
|
|
1095
1171
|
})] : [];
|
|
1096
1172
|
const gone = keyNodes !== void 0 && o.adapter && nodeLabel(o.adapter, keyKind, k) === void 0 ? `${k} is not here any more.` : void 0;
|
|
1097
1173
|
child(`k:${k}`, asDecl(decl.of, k), value[k], (v) => {
|
|
1098
|
-
const next = { ...
|
|
1174
|
+
const next = { ...isObject2(opts.value) ? opts.value : {} };
|
|
1099
1175
|
next[k] = v === void 0 ? extensions.defaultOf(decl.of) : v;
|
|
1100
1176
|
commit(next);
|
|
1101
1177
|
}, remove, keyLabel(k), gone);
|
|
@@ -1139,7 +1215,7 @@ function structuredRow(initial) {
|
|
|
1139
1215
|
}
|
|
1140
1216
|
} else if (decl.type === "list" && decl.of) {
|
|
1141
1217
|
const value = Array.isArray(o.value) ? o.value : [];
|
|
1142
|
-
const idOf = (item, i) => decl.id !== void 0 &&
|
|
1218
|
+
const idOf = (item, i) => decl.id !== void 0 && isObject2(item) && typeof item[decl.id] === "string" ? `id:${item[decl.id]}` : `i:${i}`;
|
|
1143
1219
|
value.forEach((item, i) => {
|
|
1144
1220
|
const set = (next) => commit(next.length > 0 ? next : void 0);
|
|
1145
1221
|
const controls = editable() ? [
|
|
@@ -1153,7 +1229,7 @@ function structuredRow(initial) {
|
|
|
1153
1229
|
}, i === value.length - 1),
|
|
1154
1230
|
iconBtn("close", "Remove", () => set(value.filter((_, j) => j !== i)), false, true)
|
|
1155
1231
|
] : [];
|
|
1156
|
-
const itemLabel = decl.id !== void 0 &&
|
|
1232
|
+
const itemLabel = decl.id !== void 0 && isObject2(item) && typeof item[decl.id] === "string" ? item[decl.id] : `${i + 1}`;
|
|
1157
1233
|
child(idOf(item, i), asDecl(decl.of, itemLabel), item, (v) => {
|
|
1158
1234
|
const next = [...Array.isArray(opts.value) ? opts.value : []];
|
|
1159
1235
|
next[i] = v === void 0 ? extensions.defaultOf(decl.of) : v;
|
|
@@ -1164,8 +1240,8 @@ function structuredRow(initial) {
|
|
|
1164
1240
|
if (editable()) {
|
|
1165
1241
|
adder.append(iconBtn("add", "Add", () => {
|
|
1166
1242
|
const fresh = extensions.defaultOf(decl.of);
|
|
1167
|
-
if (decl.id !== void 0 &&
|
|
1168
|
-
const taken = new Set(value.map((x) =>
|
|
1243
|
+
if (decl.id !== void 0 && isObject2(fresh)) {
|
|
1244
|
+
const taken = new Set(value.map((x) => isObject2(x) ? x[decl.id] : void 0));
|
|
1169
1245
|
let n = value.length + 1;
|
|
1170
1246
|
while (taken.has(`item-${n}`)) n++;
|
|
1171
1247
|
fresh[decl.id] = `item-${n}`;
|
|
@@ -1214,6 +1290,9 @@ function valueRows() {
|
|
|
1214
1290
|
};
|
|
1215
1291
|
}
|
|
1216
1292
|
|
|
1293
|
+
exports.extensionFold = extensionFold;
|
|
1294
|
+
exports.foldCaption = foldCaption;
|
|
1295
|
+
exports.isSet = isSet;
|
|
1217
1296
|
exports.valueRow = valueRow;
|
|
1218
1297
|
exports.valueRows = valueRows;
|
|
1219
1298
|
//# sourceMappingURL=value-rows.cjs.map
|