@kubex/zinc 1.1.67 → 1.1.69

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 (37) hide show
  1. package/dist/custom-elements.json +1288 -20
  2. package/dist/vscode.html-custom-data.json +167 -11
  3. package/dist/web-types.json +360 -17
  4. package/dist/zn.d.ts +368 -20
  5. package/dist/zn.min.js +764 -645
  6. package/docs/pages/components/collapsible.md +6 -2
  7. package/docs/pages/components/preview-frame-demo.njk +33 -4
  8. package/docs/pages/components/preview-frame.md +20 -0
  9. package/docs/pages/components/theme-editor.md +269 -0
  10. package/docs/superpowers/plans/2026-08-03-theme-editor.md +1536 -0
  11. package/docs/superpowers/specs/2026-08-03-theme-editor-design.md +327 -0
  12. package/package.json +1 -1
  13. package/src/components/collapsible/collapsible.component.ts +21 -23
  14. package/src/components/collapsible/collapsible.scss +10 -0
  15. package/src/components/data-table/data-table.component.ts +49 -44
  16. package/src/components/data-table/data-table.scss +4 -0
  17. package/src/components/data-table/data-table.test.ts +42 -0
  18. package/src/components/defined-label/defined-label.component.ts +118 -95
  19. package/src/components/defined-label/defined-label.scss +40 -28
  20. package/src/components/dropdown/dropdown.component.ts +9 -0
  21. package/src/components/editor/editor.component.ts +20 -21
  22. package/src/components/file/file.component.ts +70 -0
  23. package/src/components/page-builder/page-builder.scss +1 -1
  24. package/src/components/preview-frame/preview-frame.component.ts +126 -16
  25. package/src/components/preview-frame/preview-frame.scss +27 -0
  26. package/src/components/preview-frame/preview-frame.test.ts +253 -0
  27. package/src/components/theme-editor/index.ts +12 -0
  28. package/src/components/theme-editor/theme-editor.component.ts +761 -0
  29. package/src/components/theme-editor/theme-editor.scss +309 -0
  30. package/src/components/theme-editor/theme-editor.test.ts +1584 -0
  31. package/src/events/events.ts +2 -0
  32. package/src/events/zn-theme-change.ts +13 -0
  33. package/src/events/zn-theme-submit.ts +9 -0
  34. package/src/types/web-test-runner-commands.d.ts +6 -0
  35. package/src/zinc.ts +1 -0
  36. package/tsconfig.json +7 -1
  37. package/web-test-runner.config.js +3 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
3
3
  "name": "@kubex/zinc",
4
- "version": "1.1.67",
4
+ "version": "1.1.69",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
@@ -1663,7 +1663,7 @@
1663
1663
  },
1664
1664
  {
1665
1665
  "name": "zn-collapsible",
1666
- "description": "Toggles between showing and hiding content when clicked\n---\n\n\n### **Slots:**\n - **header** - Clicking will toggle the show state of the data\n\n### **CSS Parts:**\n - **header** - The header row (toggle).\n- **caption** - The caption text.",
1666
+ "description": "Toggles between showing and hiding content when clicked\n---\n\n\n### **Slots:**\n - **header** - Clicking will toggle the show state of the data\n\n### **CSS Parts:**\n - **header** - The header row (toggle).\n- **caption** - The caption text.\n- **content** - The expandable content wrapper.",
1667
1667
  "doc-url": "",
1668
1668
  "attributes": [
1669
1669
  {
@@ -3055,13 +3055,19 @@
3055
3055
  "description": "This component provides a labeled input with support for predefined and custom labels,\nallowing users to select or enter label-value pairs within a dropdown interface.\n---\n\n\n### **CSS Parts:**\n - **input** - The component's main input.\n- **input-value** - The label's value inputs.",
3056
3056
  "doc-url": "",
3057
3057
  "attributes": [
3058
- { "name": "value", "value": { "type": "string", "default": "''" } },
3058
+ {
3059
+ "name": "value",
3060
+ "description": "The selected label key. Also acts as the filter while typing.",
3061
+ "value": { "type": "string", "default": "''" }
3062
+ },
3059
3063
  {
3060
3064
  "name": "inputValue",
3065
+ "description": "The value entered for the selected label. Submitted as `label:value` when present.",
3061
3066
  "value": { "type": "string", "default": "''" }
3062
3067
  },
3063
3068
  {
3064
3069
  "name": "input-size",
3070
+ "description": "The size of the main input.",
3065
3071
  "value": {
3066
3072
  "type": "'x-small' | 'small' | 'medium' | 'large'",
3067
3073
  "default": "'medium'"
@@ -3069,20 +3075,31 @@
3069
3075
  },
3070
3076
  {
3071
3077
  "name": "name",
3078
+ "description": "The name of the control. Used for form submission.",
3072
3079
  "value": { "type": "string", "default": "'label'" }
3073
3080
  },
3074
- { "name": "title", "value": { "type": "string" } },
3081
+ {
3082
+ "name": "title",
3083
+ "description": "The title of the main input.",
3084
+ "value": { "type": "string" }
3085
+ },
3075
3086
  {
3076
3087
  "name": "disabled",
3088
+ "description": "Disables the control.",
3077
3089
  "value": { "type": "boolean", "default": "false" }
3078
3090
  },
3079
3091
  {
3080
3092
  "name": "allow-custom",
3093
+ "description": "Allows labels that aren't in the predefined list.",
3081
3094
  "value": { "type": "boolean", "default": "false" }
3082
3095
  },
3083
3096
  {
3084
3097
  "name": "predefined-labels",
3085
- "value": { "type": "array", "default": "[]" }
3098
+ "description": "The predefined labels. Entries are either a string or `{name, options}`.",
3099
+ "value": {
3100
+ "type": "(PredefinedLabel | string)[]",
3101
+ "default": "[]"
3102
+ }
3086
3103
  }
3087
3104
  ],
3088
3105
  "events": [],
@@ -3090,17 +3107,46 @@
3090
3107
  "properties": [
3091
3108
  { "name": "input", "type": "ZnInput" },
3092
3109
  { "name": "dropdown", "type": "ZnDropdown" },
3093
- { "name": "value", "type": "string" },
3094
- { "name": "inputValue", "type": "string" },
3110
+ {
3111
+ "name": "value",
3112
+ "description": "The selected label key. Also acts as the filter while typing.",
3113
+ "type": "string"
3114
+ },
3115
+ {
3116
+ "name": "inputValue",
3117
+ "description": "The value entered for the selected label. Submitted as `label:value` when present.",
3118
+ "type": "string"
3119
+ },
3095
3120
  {
3096
3121
  "name": "inputSize",
3122
+ "description": "The size of the main input.",
3097
3123
  "type": "'x-small' | 'small' | 'medium' | 'large'"
3098
3124
  },
3099
- { "name": "name", "type": "string" },
3100
- { "name": "title", "type": "string" },
3101
- { "name": "disabled", "type": "boolean" },
3102
- { "name": "allowCustom", "type": "boolean" },
3103
- { "name": "predefinedLabels", "type": "array" },
3125
+ {
3126
+ "name": "name",
3127
+ "description": "The name of the control. Used for form submission.",
3128
+ "type": "string"
3129
+ },
3130
+ {
3131
+ "name": "title",
3132
+ "description": "The title of the main input.",
3133
+ "type": "string"
3134
+ },
3135
+ {
3136
+ "name": "disabled",
3137
+ "description": "Disables the control.",
3138
+ "type": "boolean"
3139
+ },
3140
+ {
3141
+ "name": "allowCustom",
3142
+ "description": "Allows labels that aren't in the predefined list.",
3143
+ "type": "boolean"
3144
+ },
3145
+ {
3146
+ "name": "predefinedLabels",
3147
+ "description": "The predefined labels. Entries are either a string or `{name, options}`.",
3148
+ "type": "(PredefinedLabel | string)[]"
3149
+ },
3104
3150
  { "name": "validationMessage" },
3105
3151
  { "name": "validity" }
3106
3152
  ],
@@ -3717,6 +3763,11 @@
3717
3763
  "name": "show-link",
3718
3764
  "description": "When enabled, render the current link (`previewSrc`) as a clickable URL below the control.\nUseful for showing the existing CDN link alongside the preview.",
3719
3765
  "value": { "type": "boolean", "default": "false" }
3766
+ },
3767
+ {
3768
+ "name": "upload-url",
3769
+ "description": "When set, a chosen file is immediately POSTed (multipart, field `file`) to this URL.\nThe endpoint must respond with JSON `{\"url\": \"...\"}`; that URL becomes the control's\nvalue (and `src` preview) in place of the file bytes, so the control works inside\nJSON-serialising hosts such as `zn-page-builder`. Emits `zn-error` when the upload fails.",
3770
+ "value": { "type": "string", "default": "''" }
3720
3771
  }
3721
3772
  ],
3722
3773
  "slots": [
@@ -3868,6 +3919,11 @@
3868
3919
  "description": "When enabled, render the current link (`previewSrc`) as a clickable URL below the control.\nUseful for showing the existing CDN link alongside the preview.",
3869
3920
  "type": "boolean"
3870
3921
  },
3922
+ {
3923
+ "name": "uploadUrl",
3924
+ "description": "When set, a chosen file is immediately POSTed (multipart, field `file`) to this URL.\nThe endpoint must respond with JSON `{\"url\": \"...\"}`; that URL becomes the control's\nvalue (and `src` preview) in place of the file bytes, so the control works inside\nJSON-serialising hosts such as `zn-page-builder`. Emits `zn-error` when the upload fails.",
3925
+ "type": "string"
3926
+ },
3871
3927
  {
3872
3928
  "name": "validity",
3873
3929
  "description": "Gets the validity state object"
@@ -6845,7 +6901,7 @@
6845
6901
  },
6846
6902
  {
6847
6903
  "name": "zn-preview-frame",
6848
- "description": "Embeds a live preview iframe and drives the hp-preview postMessage\nprotocol: answers the frame's ready handshake with a config payload fetched\nfrom data-uri, auto-saves watched forms on change, and refreshes the\npreview after each save.\n---\n\n\n### **Events:**\n - **zn-error** - Emitted when the preview reports a render error or a save fails.\n\n### **Methods:**\n - **refresh()** - Re-fetches the payload and pushes a fresh config to the preview.\n\n### **CSS Parts:**\n - **base** - The component's base wrapper.\n- **iframe** - The preview iframe.\n- **error** - The error overlay.",
6904
+ "description": "Embeds a live preview iframe and drives the hp-preview postMessage\nprotocol: answers the frame's ready handshake with a config payload fetched\nfrom data-uri, auto-saves watched forms on change, refreshes the preview\nafter each save (its own, or a shell-driven save of a `refresh-on` form),\nand accepts a theme payload via setTheme() that is retained and replayed\nafter every ready handshake.\n---\n\n\n### **Events:**\n - **zn-error** - Emitted when the preview reports a render error or a save fails.\n\n### **Methods:**\n - **refresh()** - Re-fetches the payload and pushes a fresh config to the preview.\n- **setTheme(theme: _Record<string, unknown>_)** - Pushes a theme payload into the preview. The payload is retained and\nre-posted after every ready handshake, so a frame reload doesn't drop an\nin-progress theme.\n\n### **CSS Properties:**\n - **--zn-preview-frame-dot-spacing** - Spacing of the backdrop dot grid (`backdrop=\"dots\"`). Defaults to 20px. _(default: undefined)_\n- **--zn-preview-frame-dot-opacity** - Opacity of the backdrop dots (`backdrop=\"dots\"`). Defaults to 0.08. _(default: undefined)_\n\n### **CSS Parts:**\n - **base** - The component's base wrapper.\n- **stage** - The device-width wrapper around the iframe.\n- **iframe** - The preview iframe.\n- **error** - The error overlay.",
6849
6905
  "doc-url": "",
6850
6906
  "attributes": [
6851
6907
  {
@@ -6868,6 +6924,11 @@
6868
6924
  "description": "Selector (resolved against the component's root node) for the forms to watch.\nDefaults to only forms explicitly opted in via a `data-auto-save` attribute —\nunmarked forms keep normal submit behavior and are never intercepted,\nauto-saved, or used to trigger a preview refresh. Override to widen the scope.",
6869
6925
  "value": { "type": "string", "default": "'form[data-auto-save]'" }
6870
6926
  },
6927
+ {
6928
+ "name": "refresh-on",
6929
+ "description": "Selector for forms whose saves are left to the shell but should still\nrefresh the preview. These are never intercepted: the shell submits them\n(so its own response handling — alerts, refreshes — runs as normal) and the\npreview re-fetches its config once the shell reports the save complete.\nSet empty to disable.",
6930
+ "value": { "type": "string", "default": "'form'" }
6931
+ },
6871
6932
  {
6872
6933
  "name": "debounce",
6873
6934
  "description": "Debounce in ms between a form change and its auto-save.",
@@ -6875,13 +6936,28 @@
6875
6936
  },
6876
6937
  {
6877
6938
  "name": "zoom",
6878
- "description": "Zooms the previewed page out (0–1]. The frame always fills the panel;\nzoom shrinks the content browser-style, so 0.4 shows the page at 40%\nsize with correspondingly more of it visible. 1 = natural size.",
6939
+ "description": "Zooms the previewed page out (0–1]. The frame always fills the panel;\nzoom shrinks the content browser-style, so 0.4 shows the page at 40%\nsize with correspondingly more of it visible. 1 = natural size.\nIgnored when `fill` is set.",
6879
6940
  "value": { "type": "number", "default": "1" }
6880
6941
  },
6881
6942
  {
6882
6943
  "name": "min-height",
6883
- "description": "The visible height (in CSS pixels) of the preview panel. Fixed rather\nthan measured, because a measured height would feed back into the\nscaled iframe's layout box and grow unbounded.",
6944
+ "description": "The visible height (in CSS pixels) of the preview panel. Fixed rather\nthan measured, because a measured height would feed back into the\nscaled iframe's layout box and grow unbounded. With `fill` set, this\nbecomes a `min-height` floor instead of the height.",
6884
6945
  "value": { "type": "number", "default": "480" }
6946
+ },
6947
+ {
6948
+ "name": "fill",
6949
+ "description": "Fills the panel's own column height instead of using a fixed\n`min-height` pixel height — for hosts (like zn-theme-editor) whose\nlayout already stretches the column to match a taller sibling.\n`zoom` is ignored when set: its oversize maths depends on a known\npixel height, which `fill` deliberately doesn't have.",
6950
+ "value": { "type": "boolean", "default": "false" }
6951
+ },
6952
+ {
6953
+ "name": "device",
6954
+ "description": "Constrains and centres the preview to a device width: `desktop` (100%),\n`tablet` (768px) or `mobile` (390px). The iframe element itself is\nnarrowed, so the embedded page's own media queries fire.",
6955
+ "value": { "type": "PreviewFrameDevice", "default": "'desktop'" }
6956
+ },
6957
+ {
6958
+ "name": "backdrop",
6959
+ "description": "Backdrop behind the stage: `dots` (default) is the canvas dot grid; `panel` is a plain `rgb(var(--zn-panel))` fill.",
6960
+ "value": { "type": "'dots' | 'panel'", "default": "'dots'" }
6885
6961
  }
6886
6962
  ],
6887
6963
  "events": [
@@ -6912,6 +6988,11 @@
6912
6988
  "description": "Selector (resolved against the component's root node) for the forms to watch.\nDefaults to only forms explicitly opted in via a `data-auto-save` attribute —\nunmarked forms keep normal submit behavior and are never intercepted,\nauto-saved, or used to trigger a preview refresh. Override to widen the scope.",
6913
6989
  "type": "string"
6914
6990
  },
6991
+ {
6992
+ "name": "refreshOn",
6993
+ "description": "Selector for forms whose saves are left to the shell but should still\nrefresh the preview. These are never intercepted: the shell submits them\n(so its own response handling — alerts, refreshes — runs as normal) and the\npreview re-fetches its config once the shell reports the save complete.\nSet empty to disable.",
6994
+ "type": "string"
6995
+ },
6915
6996
  {
6916
6997
  "name": "debounce",
6917
6998
  "description": "Debounce in ms between a form change and its auto-save.",
@@ -6919,14 +7000,29 @@
6919
7000
  },
6920
7001
  {
6921
7002
  "name": "zoom",
6922
- "description": "Zooms the previewed page out (0–1]. The frame always fills the panel;\nzoom shrinks the content browser-style, so 0.4 shows the page at 40%\nsize with correspondingly more of it visible. 1 = natural size.",
7003
+ "description": "Zooms the previewed page out (0–1]. The frame always fills the panel;\nzoom shrinks the content browser-style, so 0.4 shows the page at 40%\nsize with correspondingly more of it visible. 1 = natural size.\nIgnored when `fill` is set.",
6923
7004
  "type": "number"
6924
7005
  },
6925
7006
  {
6926
7007
  "name": "minHeight",
6927
- "description": "The visible height (in CSS pixels) of the preview panel. Fixed rather\nthan measured, because a measured height would feed back into the\nscaled iframe's layout box and grow unbounded.",
7008
+ "description": "The visible height (in CSS pixels) of the preview panel. Fixed rather\nthan measured, because a measured height would feed back into the\nscaled iframe's layout box and grow unbounded. With `fill` set, this\nbecomes a `min-height` floor instead of the height.",
6928
7009
  "type": "number"
6929
7010
  },
7011
+ {
7012
+ "name": "fill",
7013
+ "description": "Fills the panel's own column height instead of using a fixed\n`min-height` pixel height — for hosts (like zn-theme-editor) whose\nlayout already stretches the column to match a taller sibling.\n`zoom` is ignored when set: its oversize maths depends on a known\npixel height, which `fill` deliberately doesn't have.",
7014
+ "type": "boolean"
7015
+ },
7016
+ {
7017
+ "name": "device",
7018
+ "description": "Constrains and centres the preview to a device width: `desktop` (100%),\n`tablet` (768px) or `mobile` (390px). The iframe element itself is\nnarrowed, so the embedded page's own media queries fire.",
7019
+ "type": "PreviewFrameDevice"
7020
+ },
7021
+ {
7022
+ "name": "backdrop",
7023
+ "description": "Backdrop behind the stage: `dots` (default) is the canvas dot grid; `panel` is a plain `rgb(var(--zn-panel))` fill.",
7024
+ "type": "'dots' | 'panel'"
7025
+ },
6930
7026
  { "name": "frame", "type": "HTMLIFrameElement" }
6931
7027
  ],
6932
7028
  "events": [
@@ -9667,6 +9763,253 @@
9667
9763
  ]
9668
9764
  }
9669
9765
  },
9766
+ {
9767
+ "name": "zn-theme-editor",
9768
+ "description": "A theme editor: slotted form controls drive a live preview frame,\nwith a toolbar for the preview's light/dark mode and device width.\n---\n\n\n### **Events:**\n - **zn-theme-change** - Emitted when the values, mode or device change.\n- **zn-theme-submit** - Emitted on submit (button click), carrying the current values. With `action` set, only fires after a successful save.\n- **zn-error** - Emitted when a save fails. Also seen for preview render failures: the frame's zn-error is composed and not stopped, so it bubbles out through the editor too.\n\n### **Slots:**\n - _default_ - Ungrouped theme controls, rendered above any sections. Controls assigned `slot=\"<name>\"` matching a `sections` entry (or, when nested, a `groups` entry) render inside that section/group instead. Harvesting and change detection walk every slot's full assigned subtree, not just direct children.\n- **toolbar** - Actions in the toolbar, right-aligned beside the device controls. Where a save button belongs.\n- **footer** - Actions pinned beneath the controls. The built-in submit button lives in the toolbar, not here.\n\n### **CSS Properties:**\n - **--zn-theme-editor-controls-width** - Width of the controls column. _(default: undefined)_\n\n### **CSS Parts:**\n - **base** - The component's base wrapper.\n- **controls** - The left-hand controls column, full height.\n- **controls-header** - The controls column's header row: `controls-caption` on the left, the light/dark mode toggle on the right.\n- **toolbar** - The preview column's header row: `preview-caption` on the left, the device switcher (and sources/submit) on the right. Spans the preview column only.\n- **section** - A rendered section's or group's collapsible (`section-layout=\"collapsible\"`, or any nested group).\n- **footer** - The footer wrapper beneath the controls.\n- **preview** - The preview column.\n- **error** - The inline error strip.\n- **preview__base** - The frame's base wrapper (forwarded from zn-preview-frame).\n- **preview__stage** - The frame's device-width wrapper (forwarded from zn-preview-frame).\n- **preview__iframe** - The frame's iframe (forwarded from zn-preview-frame).\n- **preview__error** - The frame's own error overlay (forwarded from zn-preview-frame).",
9769
+ "doc-url": "",
9770
+ "attributes": [
9771
+ {
9772
+ "name": "src",
9773
+ "description": "URL of the preview shell page; forwarded to the frame.",
9774
+ "value": { "type": "string", "default": "''" }
9775
+ },
9776
+ {
9777
+ "name": "frame-origin",
9778
+ "description": "Expected origin of the iframe; forwarded to the frame.",
9779
+ "value": { "type": "string", "default": "''" }
9780
+ },
9781
+ {
9782
+ "name": "data-uri",
9783
+ "description": "Optional endpoint returning the base hp-preview:config payload.",
9784
+ "value": { "type": "string", "default": "''" }
9785
+ },
9786
+ {
9787
+ "name": "mode",
9788
+ "description": "Which mode the preview renders in. Travels in the theme payload.",
9789
+ "value": { "type": "ThemeEditorMode", "default": "'light'" }
9790
+ },
9791
+ {
9792
+ "name": "device",
9793
+ "description": "Preview viewport width. Resizes the frame only; not part of the payload.",
9794
+ "value": { "type": "ThemeEditorDevice", "default": "'desktop'" }
9795
+ },
9796
+ {
9797
+ "name": "min-height",
9798
+ "description": "Minimum height of the preview row, in pixels; forwarded to the frame as its own floor.",
9799
+ "value": { "type": "number", "default": "480" }
9800
+ },
9801
+ {
9802
+ "name": "debounce",
9803
+ "description": "Debounce in ms between a control change and the push to the preview.",
9804
+ "value": { "type": "number", "default": "150" }
9805
+ },
9806
+ {
9807
+ "name": "action",
9808
+ "description": "Optional endpoint the values are POSTed to. Empty = no persistence.",
9809
+ "value": { "type": "string", "default": "''" }
9810
+ },
9811
+ {
9812
+ "name": "save-debounce",
9813
+ "description": "Debounce in ms between a control change and the save POST.",
9814
+ "value": { "type": "number", "default": "1000" }
9815
+ },
9816
+ {
9817
+ "name": "sections",
9818
+ "description": "Groups controls into named sections. Empty/unset renders one ungrouped\ncolumn. A section with a non-empty `groups` nests a collapsible per\ngroup inside a `zn-tabs` tab for that section - see `groups` on\n`ThemeEditorSection`.",
9819
+ "value": { "type": "ThemeEditorSection[]", "default": "[]" }
9820
+ },
9821
+ {
9822
+ "name": "section-layout",
9823
+ "description": "Presentation for flat, group-less `sections`: stacked `zn-collapsible`s\n(default) or a `zn-tabs` strip. Ignored once any section has `groups` -\nnested sections always render as tabs.",
9824
+ "value": {
9825
+ "type": "'collapsible' | 'tabs'",
9826
+ "default": "'collapsible'"
9827
+ }
9828
+ },
9829
+ {
9830
+ "name": "sources",
9831
+ "description": "Dropdown of preview sources, `{label, src}`, rendered in the toolbar. Empty/unset renders no dropdown; the first entry wins over an explicit `src` when non-empty.",
9832
+ "value": { "type": "ThemeEditorSource[]", "default": "[]" }
9833
+ },
9834
+ {
9835
+ "name": "controls-collapsed",
9836
+ "description": "Collapses the controls column.",
9837
+ "value": { "type": "boolean", "default": "false" }
9838
+ },
9839
+ {
9840
+ "name": "standalone",
9841
+ "description": "Presents the editor as its own bordered, rounded panel with a plain preview backdrop, rather than embedded in a dotted canvas.",
9842
+ "value": { "type": "boolean", "default": "false" }
9843
+ },
9844
+ {
9845
+ "name": "controls-caption",
9846
+ "description": "Caption in the controls column's header row. Empty (default) renders no text; the row itself always renders.",
9847
+ "value": { "type": "string", "default": "''" }
9848
+ },
9849
+ {
9850
+ "name": "preview-caption",
9851
+ "description": "Caption at the left of the toolbar, opposite the device and mode controls. Empty (default) renders no text.",
9852
+ "value": { "type": "string", "default": "''" }
9853
+ },
9854
+ {
9855
+ "name": "submit-label",
9856
+ "description": "Label for the built-in submit button. Empty (default) renders no button.",
9857
+ "value": { "type": "string", "default": "''" }
9858
+ },
9859
+ {
9860
+ "name": "manual",
9861
+ "description": "Disables the debounced auto-save; saving then happens only via submit. Preview pushes are unaffected.",
9862
+ "value": { "type": "boolean", "default": "false" }
9863
+ }
9864
+ ],
9865
+ "slots": [
9866
+ {
9867
+ "name": "",
9868
+ "description": "Ungrouped theme controls, rendered above any sections. Controls assigned `slot=\"<name>\"` matching a `sections` entry (or, when nested, a `groups` entry) render inside that section/group instead. Harvesting and change detection walk every slot's full assigned subtree, not just direct children."
9869
+ },
9870
+ {
9871
+ "name": "toolbar",
9872
+ "description": "Actions in the toolbar, right-aligned beside the device controls. Where a save button belongs."
9873
+ },
9874
+ {
9875
+ "name": "footer",
9876
+ "description": "Actions pinned beneath the controls. The built-in submit button lives in the toolbar, not here."
9877
+ }
9878
+ ],
9879
+ "events": [
9880
+ {
9881
+ "name": "zn-theme-change",
9882
+ "description": "Emitted when the values, mode or device change."
9883
+ },
9884
+ {
9885
+ "name": "zn-theme-submit",
9886
+ "description": "Emitted on submit (button click), carrying the current values. With `action` set, only fires after a successful save."
9887
+ },
9888
+ {
9889
+ "name": "zn-error",
9890
+ "description": "Emitted when a save fails. Also seen for preview render failures: the frame's zn-error is composed and not stopped, so it bubbles out through the editor too."
9891
+ }
9892
+ ],
9893
+ "js": {
9894
+ "properties": [
9895
+ {
9896
+ "name": "src",
9897
+ "description": "URL of the preview shell page; forwarded to the frame.",
9898
+ "type": "string"
9899
+ },
9900
+ {
9901
+ "name": "frameOrigin",
9902
+ "description": "Expected origin of the iframe; forwarded to the frame.",
9903
+ "type": "string"
9904
+ },
9905
+ {
9906
+ "name": "dataUri",
9907
+ "description": "Optional endpoint returning the base hp-preview:config payload.",
9908
+ "type": "string"
9909
+ },
9910
+ {
9911
+ "name": "mode",
9912
+ "description": "Which mode the preview renders in. Travels in the theme payload.",
9913
+ "type": "ThemeEditorMode"
9914
+ },
9915
+ {
9916
+ "name": "device",
9917
+ "description": "Preview viewport width. Resizes the frame only; not part of the payload.",
9918
+ "type": "ThemeEditorDevice"
9919
+ },
9920
+ {
9921
+ "name": "minHeight",
9922
+ "description": "Minimum height of the preview row, in pixels; forwarded to the frame as its own floor.",
9923
+ "type": "number"
9924
+ },
9925
+ {
9926
+ "name": "debounce",
9927
+ "description": "Debounce in ms between a control change and the push to the preview.",
9928
+ "type": "number"
9929
+ },
9930
+ {
9931
+ "name": "action",
9932
+ "description": "Optional endpoint the values are POSTed to. Empty = no persistence.",
9933
+ "type": "string"
9934
+ },
9935
+ {
9936
+ "name": "saveDebounce",
9937
+ "description": "Debounce in ms between a control change and the save POST.",
9938
+ "type": "number"
9939
+ },
9940
+ {
9941
+ "name": "sections",
9942
+ "description": "Groups controls into named sections. Empty/unset renders one ungrouped\ncolumn. A section with a non-empty `groups` nests a collapsible per\ngroup inside a `zn-tabs` tab for that section - see `groups` on\n`ThemeEditorSection`.",
9943
+ "type": "ThemeEditorSection[]"
9944
+ },
9945
+ {
9946
+ "name": "sectionLayout",
9947
+ "description": "Presentation for flat, group-less `sections`: stacked `zn-collapsible`s\n(default) or a `zn-tabs` strip. Ignored once any section has `groups` -\nnested sections always render as tabs.",
9948
+ "type": "'collapsible' | 'tabs'"
9949
+ },
9950
+ {
9951
+ "name": "sources",
9952
+ "description": "Dropdown of preview sources, `{label, src}`, rendered in the toolbar. Empty/unset renders no dropdown; the first entry wins over an explicit `src` when non-empty.",
9953
+ "type": "ThemeEditorSource[]"
9954
+ },
9955
+ {
9956
+ "name": "controlsCollapsed",
9957
+ "description": "Collapses the controls column.",
9958
+ "type": "boolean"
9959
+ },
9960
+ {
9961
+ "name": "standalone",
9962
+ "description": "Presents the editor as its own bordered, rounded panel with a plain preview backdrop, rather than embedded in a dotted canvas.",
9963
+ "type": "boolean"
9964
+ },
9965
+ {
9966
+ "name": "controlsCaption",
9967
+ "description": "Caption in the controls column's header row. Empty (default) renders no text; the row itself always renders.",
9968
+ "type": "string"
9969
+ },
9970
+ {
9971
+ "name": "previewCaption",
9972
+ "description": "Caption at the left of the toolbar, opposite the device and mode controls. Empty (default) renders no text.",
9973
+ "type": "string"
9974
+ },
9975
+ {
9976
+ "name": "submitLabel",
9977
+ "description": "Label for the built-in submit button. Empty (default) renders no button.",
9978
+ "type": "string"
9979
+ },
9980
+ {
9981
+ "name": "manual",
9982
+ "description": "Disables the debounced auto-save; saving then happens only via submit. Preview pushes are unaffected.",
9983
+ "type": "boolean"
9984
+ },
9985
+ { "name": "frame", "type": "ZnPreviewFrame" },
9986
+ {
9987
+ "name": "values",
9988
+ "description": "The current per-mode value sets. Returns copies.",
9989
+ "type": "{ light: Record<string, unknown>; dark: Record<string, unknown> }"
9990
+ },
9991
+ {
9992
+ "name": "activeValues",
9993
+ "description": "The active mode's values - what gets pushed to the preview frame.",
9994
+ "type": "Record<string, unknown>"
9995
+ }
9996
+ ],
9997
+ "events": [
9998
+ {
9999
+ "name": "zn-theme-change",
10000
+ "description": "Emitted when the values, mode or device change."
10001
+ },
10002
+ {
10003
+ "name": "zn-theme-submit",
10004
+ "description": "Emitted on submit (button click), carrying the current values. With `action` set, only fires after a successful save."
10005
+ },
10006
+ {
10007
+ "name": "zn-error",
10008
+ "description": "Emitted when a save fails. Also seen for preview render failures: the frame's zn-error is composed and not stopped, so it bubbles out through the editor too."
10009
+ }
10010
+ ]
10011
+ }
10012
+ },
9670
10013
  {
9671
10014
  "name": "zn-tile",
9672
10015
  "description": "Short summary of the component's intended use.\n---\n\n\n### **Events:**\n - **zn-event-name** - Emitted as an example.\n\n### **Slots:**\n - _default_ - The default slot.\n- **example** - An example slot.\n\n### **CSS Properties:**\n - **--example** - An example CSS custom property. _(default: undefined)_\n\n### **CSS Parts:**\n - **base** - The component's base wrapper.",