@kubex/zinc 1.1.76 → 1.1.77
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/dist/custom-elements.json +885 -885
- package/dist/vscode.html-custom-data.json +31 -31
- package/dist/web-types.json +107 -107
- package/dist/zn.d.ts +8 -1
- package/dist/zn.min.js +9 -6
- package/docs/pages/components/preview-frame.md +14 -6
- package/docs/pages/components/theme-editor.md +4 -0
- package/package.json +1 -1
- package/src/components/preview-frame/preview-frame.component.ts +12 -2
- package/src/components/preview-frame/preview-frame.test.ts +38 -0
- package/src/components/theme-editor/theme-editor.component.ts +7 -4
- package/src/components/theme-editor/theme-editor.scss +4 -2
- package/src/components/theme-editor/theme-editor.test.ts +16 -0
|
@@ -3023,7 +3023,7 @@
|
|
|
3023
3023
|
},
|
|
3024
3024
|
{
|
|
3025
3025
|
"name": "interactive",
|
|
3026
|
-
"description": "Lets pointer input through to the embedded page. The preview is inert by\ndefault: clicks never reach the frame, so the previewed page can't be\nnavigated or submitted from inside the preview. Cross-origin content can't\nbe reached from here to cancel its own handlers, so this blocks pointer\ninput entirely — hover goes with it. Scrolling doesn't: an overflowing\npage is scrolled by the panel rather than by the frame (see _contentHeight).",
|
|
3026
|
+
"description": "Lets pointer input through to the embedded page. The preview is inert by\ndefault: clicks never reach the frame, so the previewed page can't be\nnavigated or submitted from inside the preview. Cross-origin content can't\nbe reached from here to cancel its own handlers, so this blocks pointer\ninput entirely — hover goes with it. Scrolling doesn't: an overflowing\npage is scrolled by the panel rather than by the frame (see _contentHeight).\n\nSet, the frame becomes a real viewport instead: it stays the panel's own\nheight and the embed scrolls itself, so there is one scrollbar rather than\na panel scrolling an oversized frame, and the embed's viewport-relative\nlayout (`100vh`, `position: fixed`, sticky headers) sizes to what's on\nscreen. _contentHeight is ignored while this is set.",
|
|
3027
3027
|
"values": []
|
|
3028
3028
|
}
|
|
3029
3029
|
],
|
|
@@ -3961,6 +3961,36 @@
|
|
|
3961
3961
|
}
|
|
3962
3962
|
]
|
|
3963
3963
|
},
|
|
3964
|
+
{
|
|
3965
|
+
"name": "zn-tabs",
|
|
3966
|
+
"description": "Short summary of the component's intended use.\n---\n\n\n### **Events:**\n - **zn-event-name** - Emitted as an example.\n\n### **Methods:**\n \n\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.",
|
|
3967
|
+
"attributes": [
|
|
3968
|
+
{ "name": "master-id", "values": [] },
|
|
3969
|
+
{ "name": "default-uri", "values": [] },
|
|
3970
|
+
{ "name": "active", "values": [] },
|
|
3971
|
+
{ "name": "split", "values": [] },
|
|
3972
|
+
{ "name": "split-min", "values": [] },
|
|
3973
|
+
{ "name": "split-min-secondary", "values": [] },
|
|
3974
|
+
{ "name": "split-max", "values": [] },
|
|
3975
|
+
{ "name": "primary-caption", "values": [] },
|
|
3976
|
+
{ "name": "secondary-caption", "values": [] },
|
|
3977
|
+
{ "name": "no-prefetch", "values": [] },
|
|
3978
|
+
{ "name": "no-cache", "values": [] },
|
|
3979
|
+
{ "name": "local-storage", "values": [] },
|
|
3980
|
+
{ "name": "store-key", "values": [] },
|
|
3981
|
+
{ "name": "store-ttl", "values": [] },
|
|
3982
|
+
{ "name": "padded", "values": [] },
|
|
3983
|
+
{ "name": "fetch-style", "values": [] },
|
|
3984
|
+
{ "name": "full-width", "values": [] },
|
|
3985
|
+
{ "name": "padded-right", "values": [] },
|
|
3986
|
+
{ "name": "monitor", "values": [] },
|
|
3987
|
+
{ "name": "caption", "values": [] },
|
|
3988
|
+
{ "name": "description", "values": [] }
|
|
3989
|
+
],
|
|
3990
|
+
"references": [
|
|
3991
|
+
{ "name": "Documentation", "url": "https://zinc.style/components/tabs" }
|
|
3992
|
+
]
|
|
3993
|
+
},
|
|
3964
3994
|
{
|
|
3965
3995
|
"name": "zn-textarea",
|
|
3966
3996
|
"description": "Textareas collect data from the user and allow multiple lines of text.\n---\n\n\n### **Events:**\n - **zn-blur** - Emitted when the control loses focus.\n- **zn-change** - Emitted when an alteration to the control's value is committed by the user.\n- **zn-focus** - Emitted when the control gains focus.\n- **zn-input** - Emitted when the control receives input.\n- **zn-invalid** - Emitted when the form control has been checked for validity and its constraints aren't satisfied.\n\n### **Methods:**\n - **focus(options: _FocusOptions_)** - Sets focus on the textarea.\n- **blur()** - Removes focus from the textarea.\n- **select()** - Selects all the text in the textarea.\n- **scrollPosition(position: _{ top?: number; left?: number }_): _{ top: number; left: number } | undefined_** - Gets or sets the textarea scroll position.\n- **setSelectionRange(selectionStart: _number_, selectionEnd: _number_, selectionDirection: _'forward' | 'backward' | 'none'_)** - Sets the start and end positions of the text selection (0-based).\n- **setRangeText(replacement: _string_, start: _number_, end: _number_, selectMode: _'select' | 'start' | 'end' | 'preserve'_)** - Replaces a range of text with a new string.\n- **checkValidity()** - Checks for validity but does not show a validation message. Returns `true` when valid and `false` when invalid.\n- **getForm(): _HTMLFormElement | null_** - Gets the associated form, if one exists.\n- **reportValidity()** - Checks for validity and shows the browser's validation message if the control is invalid.\n- **setCustomValidity(message: _string_)** - Sets a custom validation message. Pass an empty string to restore validity.\n\n### **Slots:**\n - **label** - The textareas label. Alternatively, you can use the `label` attribute.\n- **label-tooltip** - Used to add text that is displayed in a tooltip next to the label. Alternatively, you can use the `label-tooltip` attribute.\n- **context-note** - Used to add contextual text that is displayed above the textarea, on the right. Alternatively, you can use the `context-note` attribute.\n- **help-text** - Text that describes how to use the input. Alternatively, you can use the `help-text` attribute.\n\n### **CSS Parts:**\n - **form-control** - The form control that wraps the label, input, and help text.\n- **form-control-label** - The label's wrapper.\n- **form-control-input** - The input's wrapper.\n- **form-control-help-text** - The help text's wrapper.\n- **base** - The component's base wrapper.\n- **textarea** - The internal `<textarea>` control.",
|
|
@@ -4123,36 +4153,6 @@
|
|
|
4123
4153
|
}
|
|
4124
4154
|
]
|
|
4125
4155
|
},
|
|
4126
|
-
{
|
|
4127
|
-
"name": "zn-tabs",
|
|
4128
|
-
"description": "Short summary of the component's intended use.\n---\n\n\n### **Events:**\n - **zn-event-name** - Emitted as an example.\n\n### **Methods:**\n \n\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.",
|
|
4129
|
-
"attributes": [
|
|
4130
|
-
{ "name": "master-id", "values": [] },
|
|
4131
|
-
{ "name": "default-uri", "values": [] },
|
|
4132
|
-
{ "name": "active", "values": [] },
|
|
4133
|
-
{ "name": "split", "values": [] },
|
|
4134
|
-
{ "name": "split-min", "values": [] },
|
|
4135
|
-
{ "name": "split-min-secondary", "values": [] },
|
|
4136
|
-
{ "name": "split-max", "values": [] },
|
|
4137
|
-
{ "name": "primary-caption", "values": [] },
|
|
4138
|
-
{ "name": "secondary-caption", "values": [] },
|
|
4139
|
-
{ "name": "no-prefetch", "values": [] },
|
|
4140
|
-
{ "name": "no-cache", "values": [] },
|
|
4141
|
-
{ "name": "local-storage", "values": [] },
|
|
4142
|
-
{ "name": "store-key", "values": [] },
|
|
4143
|
-
{ "name": "store-ttl", "values": [] },
|
|
4144
|
-
{ "name": "padded", "values": [] },
|
|
4145
|
-
{ "name": "fetch-style", "values": [] },
|
|
4146
|
-
{ "name": "full-width", "values": [] },
|
|
4147
|
-
{ "name": "padded-right", "values": [] },
|
|
4148
|
-
{ "name": "monitor", "values": [] },
|
|
4149
|
-
{ "name": "caption", "values": [] },
|
|
4150
|
-
{ "name": "description", "values": [] }
|
|
4151
|
-
],
|
|
4152
|
-
"references": [
|
|
4153
|
-
{ "name": "Documentation", "url": "https://zinc.style/components/tabs" }
|
|
4154
|
-
]
|
|
4155
|
-
},
|
|
4156
4156
|
{
|
|
4157
4157
|
"name": "zn-theme-editor",
|
|
4158
4158
|
"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. With `sections` left unset, the structure is instead derived from the controls' own attributes: `group=\"<label>\"` becomes a tab and `category=\"<label>\"` a collapsible within it, and the control is slotted into that collapsible automatically. Either attribute works alone - a control with only `group` sits directly in its tab, and one with only `category` becomes its own top-level section. Setting `sections` explicitly disables the derivation entirely.\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).",
|
package/dist/web-types.json
CHANGED
|
@@ -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.
|
|
4
|
+
"version": "1.1.77",
|
|
5
5
|
"description-markup": "markdown",
|
|
6
6
|
"contributions": {
|
|
7
7
|
"html": {
|
|
@@ -6999,7 +6999,7 @@
|
|
|
6999
6999
|
},
|
|
7000
7000
|
{
|
|
7001
7001
|
"name": "interactive",
|
|
7002
|
-
"description": "Lets pointer input through to the embedded page. The preview is inert by\ndefault: clicks never reach the frame, so the previewed page can't be\nnavigated or submitted from inside the preview. Cross-origin content can't\nbe reached from here to cancel its own handlers, so this blocks pointer\ninput entirely — hover goes with it. Scrolling doesn't: an overflowing\npage is scrolled by the panel rather than by the frame (see _contentHeight).",
|
|
7002
|
+
"description": "Lets pointer input through to the embedded page. The preview is inert by\ndefault: clicks never reach the frame, so the previewed page can't be\nnavigated or submitted from inside the preview. Cross-origin content can't\nbe reached from here to cancel its own handlers, so this blocks pointer\ninput entirely — hover goes with it. Scrolling doesn't: an overflowing\npage is scrolled by the panel rather than by the frame (see _contentHeight).\n\nSet, the frame becomes a real viewport instead: it stays the panel's own\nheight and the embed scrolls itself, so there is one scrollbar rather than\na panel scrolling an oversized frame, and the embed's viewport-relative\nlayout (`100vh`, `position: fixed`, sticky headers) sizes to what's on\nscreen. _contentHeight is ignored while this is set.",
|
|
7003
7003
|
"value": { "type": "boolean", "default": "false" }
|
|
7004
7004
|
}
|
|
7005
7005
|
],
|
|
@@ -7068,7 +7068,7 @@
|
|
|
7068
7068
|
},
|
|
7069
7069
|
{
|
|
7070
7070
|
"name": "interactive",
|
|
7071
|
-
"description": "Lets pointer input through to the embedded page. The preview is inert by\ndefault: clicks never reach the frame, so the previewed page can't be\nnavigated or submitted from inside the preview. Cross-origin content can't\nbe reached from here to cancel its own handlers, so this blocks pointer\ninput entirely — hover goes with it. Scrolling doesn't: an overflowing\npage is scrolled by the panel rather than by the frame (see _contentHeight).",
|
|
7071
|
+
"description": "Lets pointer input through to the embedded page. The preview is inert by\ndefault: clicks never reach the frame, so the previewed page can't be\nnavigated or submitted from inside the preview. Cross-origin content can't\nbe reached from here to cancel its own handlers, so this blocks pointer\ninput entirely — hover goes with it. Scrolling doesn't: an overflowing\npage is scrolled by the panel rather than by the frame (see _contentHeight).\n\nSet, the frame becomes a real viewport instead: it stays the panel's own\nheight and the embed scrolls itself, so there is one scrollbar rather than\na panel scrolling an oversized frame, and the embed's viewport-relative\nlayout (`100vh`, `position: fixed`, sticky headers) sizes to what's on\nscreen. _contentHeight is ignored while this is set.",
|
|
7072
7072
|
"type": "boolean"
|
|
7073
7073
|
},
|
|
7074
7074
|
{ "name": "frame", "type": "HTMLIFrameElement" }
|
|
@@ -9364,6 +9364,110 @@
|
|
|
9364
9364
|
]
|
|
9365
9365
|
}
|
|
9366
9366
|
},
|
|
9367
|
+
{
|
|
9368
|
+
"name": "zn-tabs",
|
|
9369
|
+
"description": "Short summary of the component's intended use.\n---\n\n\n### **Events:**\n - **zn-event-name** - Emitted as an example.\n\n### **Methods:**\n \n\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.",
|
|
9370
|
+
"doc-url": "",
|
|
9371
|
+
"attributes": [
|
|
9372
|
+
{ "name": "master-id", "value": { "type": "string" } },
|
|
9373
|
+
{
|
|
9374
|
+
"name": "default-uri",
|
|
9375
|
+
"value": { "type": "string", "default": "''" }
|
|
9376
|
+
},
|
|
9377
|
+
{
|
|
9378
|
+
"name": "active",
|
|
9379
|
+
"value": { "type": "string", "default": "''" }
|
|
9380
|
+
},
|
|
9381
|
+
{ "name": "split", "value": { "type": "number" } },
|
|
9382
|
+
{
|
|
9383
|
+
"name": "split-min",
|
|
9384
|
+
"value": { "type": "number", "default": "60" }
|
|
9385
|
+
},
|
|
9386
|
+
{ "name": "split-min-secondary", "value": { "type": "number" } },
|
|
9387
|
+
{ "name": "split-max", "value": { "type": "number" } },
|
|
9388
|
+
{
|
|
9389
|
+
"name": "primary-caption",
|
|
9390
|
+
"value": { "type": "string", "default": "'Navigation'" }
|
|
9391
|
+
},
|
|
9392
|
+
{
|
|
9393
|
+
"name": "secondary-caption",
|
|
9394
|
+
"value": { "type": "string", "default": "'Content'" }
|
|
9395
|
+
},
|
|
9396
|
+
{
|
|
9397
|
+
"name": "no-prefetch",
|
|
9398
|
+
"value": { "type": "boolean", "default": "false" }
|
|
9399
|
+
},
|
|
9400
|
+
{
|
|
9401
|
+
"name": "no-cache",
|
|
9402
|
+
"value": { "type": "boolean", "default": "false" }
|
|
9403
|
+
},
|
|
9404
|
+
{ "name": "local-storage", "value": { "type": "boolean" } },
|
|
9405
|
+
{ "name": "store-key", "value": { "type": "string" } },
|
|
9406
|
+
{
|
|
9407
|
+
"name": "store-ttl",
|
|
9408
|
+
"value": { "type": "number", "default": "0" }
|
|
9409
|
+
},
|
|
9410
|
+
{
|
|
9411
|
+
"name": "padded",
|
|
9412
|
+
"value": { "type": "boolean", "default": "false" }
|
|
9413
|
+
},
|
|
9414
|
+
{
|
|
9415
|
+
"name": "fetch-style",
|
|
9416
|
+
"value": { "type": "string", "default": "\"\"" }
|
|
9417
|
+
},
|
|
9418
|
+
{
|
|
9419
|
+
"name": "full-width",
|
|
9420
|
+
"value": { "type": "boolean", "default": "false" }
|
|
9421
|
+
},
|
|
9422
|
+
{
|
|
9423
|
+
"name": "padded-right",
|
|
9424
|
+
"value": { "type": "boolean", "default": "false" }
|
|
9425
|
+
},
|
|
9426
|
+
{ "name": "monitor", "value": { "type": "string" } },
|
|
9427
|
+
{ "name": "caption", "value": { "type": "string" } },
|
|
9428
|
+
{ "name": "description", "value": { "type": "string" } }
|
|
9429
|
+
],
|
|
9430
|
+
"slots": [
|
|
9431
|
+
{ "name": "", "description": "The default slot." },
|
|
9432
|
+
{ "name": "example", "description": "An example slot." }
|
|
9433
|
+
],
|
|
9434
|
+
"events": [
|
|
9435
|
+
{ "name": "zn-event-name", "description": "Emitted as an example." }
|
|
9436
|
+
],
|
|
9437
|
+
"js": {
|
|
9438
|
+
"properties": [
|
|
9439
|
+
{ "name": "masterId", "type": "string" },
|
|
9440
|
+
{ "name": "defaultUri", "type": "string" },
|
|
9441
|
+
{ "name": "_current", "type": "string" },
|
|
9442
|
+
{ "name": "_split", "type": "number" },
|
|
9443
|
+
{ "name": "_splitMin", "type": "number" },
|
|
9444
|
+
{ "name": "_splitMinSecondary", "type": "number" },
|
|
9445
|
+
{ "name": "_splitMax", "type": "number" },
|
|
9446
|
+
{ "name": "primaryCaption", "type": "string" },
|
|
9447
|
+
{ "name": "secondaryCaption", "type": "string" },
|
|
9448
|
+
{ "name": "noPrefetch", "type": "boolean" },
|
|
9449
|
+
{ "name": "noCache", "type": "boolean" },
|
|
9450
|
+
{ "name": "localStorage", "type": "boolean" },
|
|
9451
|
+
{ "name": "storeKey", "type": "string" },
|
|
9452
|
+
{ "name": "storeTtl", "type": "number" },
|
|
9453
|
+
{ "name": "padded", "type": "boolean" },
|
|
9454
|
+
{ "name": "fetchStyle", "type": "string" },
|
|
9455
|
+
{ "name": "fullWidth", "type": "boolean" },
|
|
9456
|
+
{ "name": "paddedRight", "type": "boolean" },
|
|
9457
|
+
{ "name": "monitor", "type": "string" },
|
|
9458
|
+
{ "name": "caption", "type": "string" },
|
|
9459
|
+
{ "name": "description", "type": "string" },
|
|
9460
|
+
{ "name": "reRegisterTabs" },
|
|
9461
|
+
{ "name": "_registerTabs" }
|
|
9462
|
+
],
|
|
9463
|
+
"events": [
|
|
9464
|
+
{
|
|
9465
|
+
"name": "zn-event-name",
|
|
9466
|
+
"description": "Emitted as an example."
|
|
9467
|
+
}
|
|
9468
|
+
]
|
|
9469
|
+
}
|
|
9470
|
+
},
|
|
9367
9471
|
{
|
|
9368
9472
|
"name": "zn-textarea",
|
|
9369
9473
|
"description": "Textareas collect data from the user and allow multiple lines of text.\n---\n\n\n### **Events:**\n - **zn-blur** - Emitted when the control loses focus.\n- **zn-change** - Emitted when an alteration to the control's value is committed by the user.\n- **zn-focus** - Emitted when the control gains focus.\n- **zn-input** - Emitted when the control receives input.\n- **zn-invalid** - Emitted when the form control has been checked for validity and its constraints aren't satisfied.\n\n### **Methods:**\n - **focus(options: _FocusOptions_)** - Sets focus on the textarea.\n- **blur()** - Removes focus from the textarea.\n- **select()** - Selects all the text in the textarea.\n- **scrollPosition(position: _{ top?: number; left?: number }_): _{ top: number; left: number } | undefined_** - Gets or sets the textarea scroll position.\n- **setSelectionRange(selectionStart: _number_, selectionEnd: _number_, selectionDirection: _'forward' | 'backward' | 'none'_)** - Sets the start and end positions of the text selection (0-based).\n- **setRangeText(replacement: _string_, start: _number_, end: _number_, selectMode: _'select' | 'start' | 'end' | 'preserve'_)** - Replaces a range of text with a new string.\n- **checkValidity()** - Checks for validity but does not show a validation message. Returns `true` when valid and `false` when invalid.\n- **getForm(): _HTMLFormElement | null_** - Gets the associated form, if one exists.\n- **reportValidity()** - Checks for validity and shows the browser's validation message if the control is invalid.\n- **setCustomValidity(message: _string_)** - Sets a custom validation message. Pass an empty string to restore validity.\n\n### **Slots:**\n - **label** - The textareas label. Alternatively, you can use the `label` attribute.\n- **label-tooltip** - Used to add text that is displayed in a tooltip next to the label. Alternatively, you can use the `label-tooltip` attribute.\n- **context-note** - Used to add contextual text that is displayed above the textarea, on the right. Alternatively, you can use the `context-note` attribute.\n- **help-text** - Text that describes how to use the input. Alternatively, you can use the `help-text` attribute.\n\n### **CSS Parts:**\n - **form-control** - The form control that wraps the label, input, and help text.\n- **form-control-label** - The label's wrapper.\n- **form-control-input** - The input's wrapper.\n- **form-control-help-text** - The help text's wrapper.\n- **base** - The component's base wrapper.\n- **textarea** - The internal `<textarea>` control.",
|
|
@@ -9707,110 +9811,6 @@
|
|
|
9707
9811
|
]
|
|
9708
9812
|
}
|
|
9709
9813
|
},
|
|
9710
|
-
{
|
|
9711
|
-
"name": "zn-tabs",
|
|
9712
|
-
"description": "Short summary of the component's intended use.\n---\n\n\n### **Events:**\n - **zn-event-name** - Emitted as an example.\n\n### **Methods:**\n \n\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.",
|
|
9713
|
-
"doc-url": "",
|
|
9714
|
-
"attributes": [
|
|
9715
|
-
{ "name": "master-id", "value": { "type": "string" } },
|
|
9716
|
-
{
|
|
9717
|
-
"name": "default-uri",
|
|
9718
|
-
"value": { "type": "string", "default": "''" }
|
|
9719
|
-
},
|
|
9720
|
-
{
|
|
9721
|
-
"name": "active",
|
|
9722
|
-
"value": { "type": "string", "default": "''" }
|
|
9723
|
-
},
|
|
9724
|
-
{ "name": "split", "value": { "type": "number" } },
|
|
9725
|
-
{
|
|
9726
|
-
"name": "split-min",
|
|
9727
|
-
"value": { "type": "number", "default": "60" }
|
|
9728
|
-
},
|
|
9729
|
-
{ "name": "split-min-secondary", "value": { "type": "number" } },
|
|
9730
|
-
{ "name": "split-max", "value": { "type": "number" } },
|
|
9731
|
-
{
|
|
9732
|
-
"name": "primary-caption",
|
|
9733
|
-
"value": { "type": "string", "default": "'Navigation'" }
|
|
9734
|
-
},
|
|
9735
|
-
{
|
|
9736
|
-
"name": "secondary-caption",
|
|
9737
|
-
"value": { "type": "string", "default": "'Content'" }
|
|
9738
|
-
},
|
|
9739
|
-
{
|
|
9740
|
-
"name": "no-prefetch",
|
|
9741
|
-
"value": { "type": "boolean", "default": "false" }
|
|
9742
|
-
},
|
|
9743
|
-
{
|
|
9744
|
-
"name": "no-cache",
|
|
9745
|
-
"value": { "type": "boolean", "default": "false" }
|
|
9746
|
-
},
|
|
9747
|
-
{ "name": "local-storage", "value": { "type": "boolean" } },
|
|
9748
|
-
{ "name": "store-key", "value": { "type": "string" } },
|
|
9749
|
-
{
|
|
9750
|
-
"name": "store-ttl",
|
|
9751
|
-
"value": { "type": "number", "default": "0" }
|
|
9752
|
-
},
|
|
9753
|
-
{
|
|
9754
|
-
"name": "padded",
|
|
9755
|
-
"value": { "type": "boolean", "default": "false" }
|
|
9756
|
-
},
|
|
9757
|
-
{
|
|
9758
|
-
"name": "fetch-style",
|
|
9759
|
-
"value": { "type": "string", "default": "\"\"" }
|
|
9760
|
-
},
|
|
9761
|
-
{
|
|
9762
|
-
"name": "full-width",
|
|
9763
|
-
"value": { "type": "boolean", "default": "false" }
|
|
9764
|
-
},
|
|
9765
|
-
{
|
|
9766
|
-
"name": "padded-right",
|
|
9767
|
-
"value": { "type": "boolean", "default": "false" }
|
|
9768
|
-
},
|
|
9769
|
-
{ "name": "monitor", "value": { "type": "string" } },
|
|
9770
|
-
{ "name": "caption", "value": { "type": "string" } },
|
|
9771
|
-
{ "name": "description", "value": { "type": "string" } }
|
|
9772
|
-
],
|
|
9773
|
-
"slots": [
|
|
9774
|
-
{ "name": "", "description": "The default slot." },
|
|
9775
|
-
{ "name": "example", "description": "An example slot." }
|
|
9776
|
-
],
|
|
9777
|
-
"events": [
|
|
9778
|
-
{ "name": "zn-event-name", "description": "Emitted as an example." }
|
|
9779
|
-
],
|
|
9780
|
-
"js": {
|
|
9781
|
-
"properties": [
|
|
9782
|
-
{ "name": "masterId", "type": "string" },
|
|
9783
|
-
{ "name": "defaultUri", "type": "string" },
|
|
9784
|
-
{ "name": "_current", "type": "string" },
|
|
9785
|
-
{ "name": "_split", "type": "number" },
|
|
9786
|
-
{ "name": "_splitMin", "type": "number" },
|
|
9787
|
-
{ "name": "_splitMinSecondary", "type": "number" },
|
|
9788
|
-
{ "name": "_splitMax", "type": "number" },
|
|
9789
|
-
{ "name": "primaryCaption", "type": "string" },
|
|
9790
|
-
{ "name": "secondaryCaption", "type": "string" },
|
|
9791
|
-
{ "name": "noPrefetch", "type": "boolean" },
|
|
9792
|
-
{ "name": "noCache", "type": "boolean" },
|
|
9793
|
-
{ "name": "localStorage", "type": "boolean" },
|
|
9794
|
-
{ "name": "storeKey", "type": "string" },
|
|
9795
|
-
{ "name": "storeTtl", "type": "number" },
|
|
9796
|
-
{ "name": "padded", "type": "boolean" },
|
|
9797
|
-
{ "name": "fetchStyle", "type": "string" },
|
|
9798
|
-
{ "name": "fullWidth", "type": "boolean" },
|
|
9799
|
-
{ "name": "paddedRight", "type": "boolean" },
|
|
9800
|
-
{ "name": "monitor", "type": "string" },
|
|
9801
|
-
{ "name": "caption", "type": "string" },
|
|
9802
|
-
{ "name": "description", "type": "string" },
|
|
9803
|
-
{ "name": "reRegisterTabs" },
|
|
9804
|
-
{ "name": "_registerTabs" }
|
|
9805
|
-
],
|
|
9806
|
-
"events": [
|
|
9807
|
-
{
|
|
9808
|
-
"name": "zn-event-name",
|
|
9809
|
-
"description": "Emitted as an example."
|
|
9810
|
-
}
|
|
9811
|
-
]
|
|
9812
|
-
}
|
|
9813
|
-
},
|
|
9814
9814
|
{
|
|
9815
9815
|
"name": "zn-theme-editor",
|
|
9816
9816
|
"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. With `sections` left unset, the structure is instead derived from the controls' own attributes: `group=\"<label>\"` becomes a tab and `category=\"<label>\"` a collapsible within it, and the control is slotted into that collapsible automatically. Either attribute works alone - a control with only `group` sits directly in its tab, and one with only `category` becomes its own top-level section. Setting `sections` explicitly disables the derivation entirely.\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).",
|
package/dist/zn.d.ts
CHANGED
|
@@ -10556,6 +10556,12 @@ declare module "components/preview-frame/preview-frame.component" {
|
|
|
10556
10556
|
* be reached from here to cancel its own handlers, so this blocks pointer
|
|
10557
10557
|
* input entirely — hover goes with it. Scrolling doesn't: an overflowing
|
|
10558
10558
|
* page is scrolled by the panel rather than by the frame (see _contentHeight).
|
|
10559
|
+
*
|
|
10560
|
+
* Set, the frame becomes a real viewport instead: it stays the panel's own
|
|
10561
|
+
* height and the embed scrolls itself, so there is one scrollbar rather than
|
|
10562
|
+
* a panel scrolling an oversized frame, and the embed's viewport-relative
|
|
10563
|
+
* layout (`100vh`, `position: fixed`, sticky headers) sizes to what's on
|
|
10564
|
+
* screen. _contentHeight is ignored while this is set.
|
|
10559
10565
|
*/
|
|
10560
10566
|
interactive: boolean;
|
|
10561
10567
|
frame: HTMLIFrameElement;
|
|
@@ -10567,7 +10573,8 @@ declare module "components/preview-frame/preview-frame.component" {
|
|
|
10567
10573
|
* height rather than the panel's, so the page never scrolls inside the frame
|
|
10568
10574
|
* — the panel scrolls instead, which is what makes an overflowing preview
|
|
10569
10575
|
* reachable while pointer input to the frame is blocked. 0 = unknown, and the
|
|
10570
|
-
* frame falls back to filling the panel.
|
|
10576
|
+
* frame falls back to filling the panel. Kept up to date either way, but only
|
|
10577
|
+
* laid out when the frame is inert: an `interactive` frame scrolls itself.
|
|
10571
10578
|
*/
|
|
10572
10579
|
private _contentHeight;
|
|
10573
10580
|
private _generation;
|
package/dist/zn.min.js
CHANGED
|
@@ -5478,7 +5478,7 @@ ${n}`:""}</li></ol>`};return t(0)}parseTable(o,t){this.index++;let r=[],n=[];for
|
|
|
5478
5478
|
${this._renderInspector()}
|
|
5479
5479
|
<slot name="config" class="declarations" @slotchange="${this._registerSlottedTemplates}"></slot>
|
|
5480
5480
|
</div>
|
|
5481
|
-
`}};At.styles=E(y_),At.dependencies={"zn-collapsible":oa,"zn-icon":ct,"zn-input":ke,"zn-page-palette-item":Rf,"zn-page-section-card":Of},c([p()],At.prototype,"name",2),c([p({reflect:!0})],At.prototype,"form",2),c([p()],At.prototype,"config",2),c([p({reflect:!0})],At.prototype,"heading",2),c([p({reflect:!0})],At.prototype,"subheading",2),c([p({attribute:!1})],At.prototype,"sectionTypes",2),c([p({type:Boolean,reflect:!0,attribute:"palette-collapsed"})],At.prototype,"paletteCollapsed",2),c([p({type:Boolean,reflect:!0,attribute:"inspector-collapsed"})],At.prototype,"inspectorCollapsed",2),c([p({attribute:"auto-save",converter:{fromAttribute:t=>{if(t===null)return null;let r=parseFloat(t);return Number.isFinite(r)&&r>0?r:uq},toAttribute:t=>t===null?null:String(t)}})],At.prototype,"autoSave",2),c([O()],At.prototype,"_state",2),c([O()],At.prototype,"_selectedId",2),c([O()],At.prototype,"_search",2),c([O()],At.prototype,"_pickerIndex",2),c([O()],At.prototype,"_dragOverIndex",2),c([O()],At.prototype,"_slotDragOver",2),c([O()],At.prototype,"_slotPicker",2),c([O()],At.prototype,"_form",2),c([K("config")],At.prototype,"handleConfigChange",1),c([K("sectionTypes")],At.prototype,"handleSectionTypesChange",1),c([O()],At.prototype,"_lastSavedAt",2),c([O()],At.prototype,"_justSaved",2),c([O()],At.prototype,"_statusNow",2),c([O()],At.prototype,"_restorePrompt",2);var fq=At;At.define("zn-page-builder");var w_=S`:host{display:block}:host([fill]){flex:1 1 auto;min-height:0}.preview{position:relative;width:100%;overflow-x:hidden;overflow-y:auto;background:radial-gradient(circle,rgba(var(--zn-text),var(--zn-preview-frame-dot-opacity,0.08)) 1px,transparent 1px) 0 0/var(--zn-preview-frame-dot-spacing,20px) var(--zn-preview-frame-dot-spacing,20px),rgb(var(--zn-body))}:host([backdrop=panel]) .preview{background:rgb(var(--zn-panel))}.preview__stage{height:100%;max-width:100%;margin:0 auto;overflow:hidden}iframe{display:block;width:100%;border:0;pointer-events:none;background:rgb(var(--zn-body))}:host([interactive]) iframe{pointer-events:auto}.preview__error{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:1rem;text-align:center;background:rgba(0,0,0,0.65);color:#fff}`;var __={desktop:"100%",tablet:"768px",mobile:"390px"},ye=class extends C{constructor(){super(...arguments);this.src="";this.frameOrigin="";this.dataUri="";this.watch="form[data-auto-save]";this.refreshOn="form";this.debounce=400;this.zoom=1;this.minHeight=480;this.fill=!1;this.device="desktop";this.backdrop="dots";this.interactive=!1;this.error="";this._contentHeight=0;this._generation=0;this._watchedForms=new Set;this._refreshForms=new Set;this._debounceTimers=new Map;this._formObserver=new Lt(this,{target:null,config:{subtree:!0,childList:!0},callback:()=>this._attachForms()});this._onMessage=t=>{if(t.origin!==this.frameOrigin||!this.frame||t.source!==this.frame.contentWindow)return;let r=t.data;switch(r?.type){case"hp-preview:ready":this._sendConfig().then(()=>this._postTheme());break;case"hp-preview:rendered":this.error="",this._applyContentHeight(r.height);break;case"hp-preview:height":this._applyContentHeight(r.height);break;case"hp-preview:error":this._fail(String(r.message??"Preview failed to render"));break}};this._onFrameLoad=()=>{this._contentObserver?.disconnect(),this._contentObserver=void 0;let t;try{t=this.frame?.contentDocument?.documentElement}catch{return}if(!t)return;let r=()=>{let n=t.getBoundingClientRect().height;n>(this.frame?.clientHeight??0)&&this._applyContentHeight(n)};r(),this._contentObserver=new ResizeObserver(r),this._contentObserver.observe(t)};this._onShellSave=()=>{this._sendConfig()};this._onChange=t=>{let r=t.currentTarget,n=this._debounceTimers.get(r);n&&window.clearTimeout(n),this._debounceTimers.set(r,window.setTimeout(()=>{this._debounceTimers.delete(r),r.isConnected&&r.requestSubmit()},this.debounce))};this._onSubmit=t=>{t.preventDefault(),t.stopImmediatePropagation(),this._save(t.currentTarget)}}connectedCallback(){super.connectedCallback(),window.addEventListener("message",this._onMessage),this._attachForms();let t=this.getRootNode();t instanceof Document?this._formObserver.observe(t.body):t instanceof ShadowRoot&&this._formObserver.observe(t)}willUpdate(t){t.has("src")&&this._resetContentHeight()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("message",this._onMessage),this._contentObserver?.disconnect(),this._contentObserver=void 0,this._watchedForms.forEach(t=>this._detachForm(t)),this._watchedForms.clear(),this._refreshForms.forEach(t=>t.removeEventListener("complete",this._onShellSave)),this._refreshForms.clear()}_applyContentHeight(t){let r=Math.round(Number(t));!Number.isFinite(r)||r<=0||(this._contentHeight=r)}_resetContentHeight(){this._contentHeight=0,this._contentObserver?.disconnect(),this._contentObserver=void 0}refresh(){return this._sendConfig()}setTheme(t){this._theme=t,this._postTheme()}_postTheme(){!this._theme||!this.frameOrigin||this.frame?.contentWindow?.postMessage({type:"hp-preview:theme",...this._theme},this.frameOrigin)}async _sendConfig(){if(!this.dataUri||!this.frameOrigin)return;let t=++this._generation;try{let r=await fetch(this.dataUri,{credentials:"same-origin",headers:{"x-kx-fetch-style":"download"}});if(!r.ok)throw new Error(await r.text()||r.statusText);let n=await r.json();if(t!==this._generation)return;this.frame?.contentWindow?.postMessage({type:"hp-preview:config",...n},this.frameOrigin)}catch(r){t===this._generation&&this._fail(r instanceof Error?r.message:String(r))}}_attachForms(){let t=this.getRootNode(),r=new Set;t.querySelectorAll(this.watch).forEach(a=>{a instanceof HTMLFormElement&&r.add(a)}),this._watchedForms.forEach(a=>{r.has(a)||(this._detachForm(a),this._watchedForms.delete(a))}),r.forEach(a=>{this._watchedForms.has(a)||(this._watchedForms.add(a),a.addEventListener("submit",this._onSubmit,{capture:!0}),a.addEventListener("zn-change",this._onChange),a.addEventListener("zn-input",this._onChange),a.addEventListener("change",this._onChange))});let n=new Set;this.refreshOn&&t.querySelectorAll(this.refreshOn).forEach(a=>{a instanceof HTMLFormElement&&!r.has(a)&&n.add(a)}),this._refreshForms.forEach(a=>{n.has(a)||(a.removeEventListener("complete",this._onShellSave),this._refreshForms.delete(a))}),n.forEach(a=>{this._refreshForms.has(a)||(this._refreshForms.add(a),a.addEventListener("complete",this._onShellSave))})}_detachForm(t){t.removeEventListener("submit",this._onSubmit,{capture:!0}),t.removeEventListener("zn-change",this._onChange),t.removeEventListener("zn-input",this._onChange),t.removeEventListener("change",this._onChange);let r=this._debounceTimers.get(t);r&&window.clearTimeout(r),this._debounceTimers.delete(t)}async _save(t){try{let r=await fetch(t.getAttribute("action")||"",{method:"POST",credentials:"same-origin",headers:{"x-kx-fetch-style":"download"},body:new FormData(t)}),n=r.headers.get("x-kubex-alert-danger");if(n)throw new Error(n);if(!r.ok)throw new Error(await r.text()||r.statusText);await this._sendConfig()}catch(r){this._fail(r instanceof Error?r.message:String(r))}}_fail(t){this.error=t,this.emit("zn-error",{detail:{message:t}})}render(){let t=this.zoom>0&&this.zoom<=1?this.zoom:1,r=this.error?0:this._contentHeight,n=this.fill?{width:"100%",height:r?`max(${r}px, 100%)`:"100%"}:{width:`${100/t}%`,height:`${Math.max(r,this.minHeight/t)}px`,transform:`scale(${t})`,transformOrigin:"0 0"},a=this.fill?{height:"100%",minHeight:`${this.minHeight}px`}:{height:`${this.minHeight}px`},s={width:__[this.device]??__.desktop};return r&&(s.height=this.fill?`max(${r}px, 100%)`:`${Math.max(r*t,this.minHeight)}px`),u`
|
|
5481
|
+
`}};At.styles=E(y_),At.dependencies={"zn-collapsible":oa,"zn-icon":ct,"zn-input":ke,"zn-page-palette-item":Rf,"zn-page-section-card":Of},c([p()],At.prototype,"name",2),c([p({reflect:!0})],At.prototype,"form",2),c([p()],At.prototype,"config",2),c([p({reflect:!0})],At.prototype,"heading",2),c([p({reflect:!0})],At.prototype,"subheading",2),c([p({attribute:!1})],At.prototype,"sectionTypes",2),c([p({type:Boolean,reflect:!0,attribute:"palette-collapsed"})],At.prototype,"paletteCollapsed",2),c([p({type:Boolean,reflect:!0,attribute:"inspector-collapsed"})],At.prototype,"inspectorCollapsed",2),c([p({attribute:"auto-save",converter:{fromAttribute:t=>{if(t===null)return null;let r=parseFloat(t);return Number.isFinite(r)&&r>0?r:uq},toAttribute:t=>t===null?null:String(t)}})],At.prototype,"autoSave",2),c([O()],At.prototype,"_state",2),c([O()],At.prototype,"_selectedId",2),c([O()],At.prototype,"_search",2),c([O()],At.prototype,"_pickerIndex",2),c([O()],At.prototype,"_dragOverIndex",2),c([O()],At.prototype,"_slotDragOver",2),c([O()],At.prototype,"_slotPicker",2),c([O()],At.prototype,"_form",2),c([K("config")],At.prototype,"handleConfigChange",1),c([K("sectionTypes")],At.prototype,"handleSectionTypesChange",1),c([O()],At.prototype,"_lastSavedAt",2),c([O()],At.prototype,"_justSaved",2),c([O()],At.prototype,"_statusNow",2),c([O()],At.prototype,"_restorePrompt",2);var fq=At;At.define("zn-page-builder");var w_=S`:host{display:block}:host([fill]){flex:1 1 auto;min-height:0}.preview{position:relative;width:100%;overflow-x:hidden;overflow-y:auto;background:radial-gradient(circle,rgba(var(--zn-text),var(--zn-preview-frame-dot-opacity,0.08)) 1px,transparent 1px) 0 0/var(--zn-preview-frame-dot-spacing,20px) var(--zn-preview-frame-dot-spacing,20px),rgb(var(--zn-body))}:host([backdrop=panel]) .preview{background:rgb(var(--zn-panel))}.preview__stage{height:100%;max-width:100%;margin:0 auto;overflow:hidden}iframe{display:block;width:100%;border:0;pointer-events:none;background:rgb(var(--zn-body))}:host([interactive]) iframe{pointer-events:auto}.preview__error{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:1rem;text-align:center;background:rgba(0,0,0,0.65);color:#fff}`;var __={desktop:"100%",tablet:"768px",mobile:"390px"},ye=class extends C{constructor(){super(...arguments);this.src="";this.frameOrigin="";this.dataUri="";this.watch="form[data-auto-save]";this.refreshOn="form";this.debounce=400;this.zoom=1;this.minHeight=480;this.fill=!1;this.device="desktop";this.backdrop="dots";this.interactive=!1;this.error="";this._contentHeight=0;this._generation=0;this._watchedForms=new Set;this._refreshForms=new Set;this._debounceTimers=new Map;this._formObserver=new Lt(this,{target:null,config:{subtree:!0,childList:!0},callback:()=>this._attachForms()});this._onMessage=t=>{if(t.origin!==this.frameOrigin||!this.frame||t.source!==this.frame.contentWindow)return;let r=t.data;switch(r?.type){case"hp-preview:ready":this._sendConfig().then(()=>this._postTheme());break;case"hp-preview:rendered":this.error="",this._applyContentHeight(r.height);break;case"hp-preview:height":this._applyContentHeight(r.height);break;case"hp-preview:error":this._fail(String(r.message??"Preview failed to render"));break}};this._onFrameLoad=()=>{this._contentObserver?.disconnect(),this._contentObserver=void 0;let t;try{t=this.frame?.contentDocument?.documentElement}catch{return}if(!t)return;let r=()=>{let n=t.getBoundingClientRect().height;n>(this.frame?.clientHeight??0)&&this._applyContentHeight(n)};r(),this._contentObserver=new ResizeObserver(r),this._contentObserver.observe(t)};this._onShellSave=()=>{this._sendConfig()};this._onChange=t=>{let r=t.currentTarget,n=this._debounceTimers.get(r);n&&window.clearTimeout(n),this._debounceTimers.set(r,window.setTimeout(()=>{this._debounceTimers.delete(r),r.isConnected&&r.requestSubmit()},this.debounce))};this._onSubmit=t=>{t.preventDefault(),t.stopImmediatePropagation(),this._save(t.currentTarget)}}connectedCallback(){super.connectedCallback(),window.addEventListener("message",this._onMessage),this._attachForms();let t=this.getRootNode();t instanceof Document?this._formObserver.observe(t.body):t instanceof ShadowRoot&&this._formObserver.observe(t)}willUpdate(t){t.has("src")&&this._resetContentHeight()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("message",this._onMessage),this._contentObserver?.disconnect(),this._contentObserver=void 0,this._watchedForms.forEach(t=>this._detachForm(t)),this._watchedForms.clear(),this._refreshForms.forEach(t=>t.removeEventListener("complete",this._onShellSave)),this._refreshForms.clear()}_applyContentHeight(t){let r=Math.round(Number(t));!Number.isFinite(r)||r<=0||(this._contentHeight=r)}_resetContentHeight(){this._contentHeight=0,this._contentObserver?.disconnect(),this._contentObserver=void 0}refresh(){return this._sendConfig()}setTheme(t){this._theme=t,this._postTheme()}_postTheme(){!this._theme||!this.frameOrigin||this.frame?.contentWindow?.postMessage({type:"hp-preview:theme",...this._theme},this.frameOrigin)}async _sendConfig(){if(!this.dataUri||!this.frameOrigin)return;let t=++this._generation;try{let r=await fetch(this.dataUri,{credentials:"same-origin",headers:{"x-kx-fetch-style":"download"}});if(!r.ok)throw new Error(await r.text()||r.statusText);let n=await r.json();if(t!==this._generation)return;this.frame?.contentWindow?.postMessage({type:"hp-preview:config",...n},this.frameOrigin)}catch(r){t===this._generation&&this._fail(r instanceof Error?r.message:String(r))}}_attachForms(){let t=this.getRootNode(),r=new Set;t.querySelectorAll(this.watch).forEach(a=>{a instanceof HTMLFormElement&&r.add(a)}),this._watchedForms.forEach(a=>{r.has(a)||(this._detachForm(a),this._watchedForms.delete(a))}),r.forEach(a=>{this._watchedForms.has(a)||(this._watchedForms.add(a),a.addEventListener("submit",this._onSubmit,{capture:!0}),a.addEventListener("zn-change",this._onChange),a.addEventListener("zn-input",this._onChange),a.addEventListener("change",this._onChange))});let n=new Set;this.refreshOn&&t.querySelectorAll(this.refreshOn).forEach(a=>{a instanceof HTMLFormElement&&!r.has(a)&&n.add(a)}),this._refreshForms.forEach(a=>{n.has(a)||(a.removeEventListener("complete",this._onShellSave),this._refreshForms.delete(a))}),n.forEach(a=>{this._refreshForms.has(a)||(this._refreshForms.add(a),a.addEventListener("complete",this._onShellSave))})}_detachForm(t){t.removeEventListener("submit",this._onSubmit,{capture:!0}),t.removeEventListener("zn-change",this._onChange),t.removeEventListener("zn-input",this._onChange),t.removeEventListener("change",this._onChange);let r=this._debounceTimers.get(t);r&&window.clearTimeout(r),this._debounceTimers.delete(t)}async _save(t){try{let r=await fetch(t.getAttribute("action")||"",{method:"POST",credentials:"same-origin",headers:{"x-kx-fetch-style":"download"},body:new FormData(t)}),n=r.headers.get("x-kubex-alert-danger");if(n)throw new Error(n);if(!r.ok)throw new Error(await r.text()||r.statusText);await this._sendConfig()}catch(r){this._fail(r instanceof Error?r.message:String(r))}}_fail(t){this.error=t,this.emit("zn-error",{detail:{message:t}})}render(){let t=this.zoom>0&&this.zoom<=1?this.zoom:1,r=this.error||this.interactive?0:this._contentHeight,n=this.fill?{width:"100%",height:r?`max(${r}px, 100%)`:"100%"}:{width:`${100/t}%`,height:`${Math.max(r,this.minHeight/t)}px`,transform:`scale(${t})`,transformOrigin:"0 0"},a=this.fill?{height:"100%",minHeight:`${this.minHeight}px`}:{height:`${this.minHeight}px`},s={width:__[this.device]??__.desktop};return r&&(s.height=this.fill?`max(${r}px, 100%)`:`${Math.max(r*t,this.minHeight)}px`),u`
|
|
5482
5482
|
<div part="base" class="preview" style="${_r(a)}">
|
|
5483
5483
|
<div part="stage" class="preview__stage" style="${_r(s)}">
|
|
5484
5484
|
<iframe part="iframe"
|
|
@@ -5490,7 +5490,7 @@ ${n}`:""}</li></ol>`};return t(0)}parseTable(o,t){this.index++;let r=[],n=[];for
|
|
|
5490
5490
|
</div>
|
|
5491
5491
|
${this.error?u`
|
|
5492
5492
|
<div part="error" class="preview__error">${this.error}</div>`:""}
|
|
5493
|
-
</div>`}};ye.styles=E(w_),c([p()],ye.prototype,"src",2),c([p({attribute:"frame-origin"})],ye.prototype,"frameOrigin",2),c([p({attribute:"data-uri"})],ye.prototype,"dataUri",2),c([p()],ye.prototype,"watch",2),c([p({attribute:"refresh-on"})],ye.prototype,"refreshOn",2),c([p({type:Number})],ye.prototype,"debounce",2),c([p({type:Number})],ye.prototype,"zoom",2),c([p({type:Number,attribute:"min-height"})],ye.prototype,"minHeight",2),c([p({type:Boolean})],ye.prototype,"fill",2),c([p({reflect:!0})],ye.prototype,"device",2),c([p({reflect:!0})],ye.prototype,"backdrop",2),c([p({type:Boolean,reflect:!0})],ye.prototype,"interactive",2),c([F("iframe")],ye.prototype,"frame",2),c([O()],ye.prototype,"error",2),c([O()],ye.prototype,"_contentHeight",2);var Ff=ye;ye.define("zn-preview-frame");var k_=S`@keyframes rotate-gradient{from{--rotate:0deg}to{--rotate:360deg}}:host{text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-transform:none}:host *,:host *::before,:host *::after{box-sizing:border-box;border-width:0;border-style:solid;border-color:rgb(var(--zn-border-color))}[hidden]{display:none !important}.width-container,.form-container,.wide-form-container{height:100%;width:100%;margin:var(--zn-default-margin,0 auto)}.width-container{max-width:var(--zn-container)}.form-container{max-width:var(--zn-container-ph)}.wide-form-container{max-width:var(--zn-container-lg)}:host{display:block;--zn-theme-editor-controls-width:343px;height:100%}.editor{--controls-col:var(--zn-theme-editor-controls-width);display:flex;align-items:stretch;height:100%}.editor--controls-collapsed{--controls-col:0px}.editor--controls-collapsed .editor__controls{border-right:none}.editor--controls-collapsed .editor__controls-header,.editor--controls-collapsed .editor__controls-body{padding:0}:host([standalone]) .editor{background:rgb(var(--zn-panel));border:1px solid rgb(var(--zn-border-color));border-radius:8px;overflow:hidden}.editor__toolbar{display:flex;align-items:center;flex:0 0 auto;min-height:44px;gap:var(--zn-spacing-small);padding:var(--zn-spacing-small) var(--zn-spacing-medium);border-bottom:1px solid rgb(var(--zn-border-color))}.editor__toolbar-actions{display:flex;align-items:center;gap:var(--zn-spacing-small);margin-left:auto}.editor__caption{font-size:14px;font-weight:600;line-height:16px;color:rgb(var(--zn-text))}.editor__controls{position:relative;display:flex;flex-direction:column;flex:0 0 var(--controls-col);min-width:0;max-width:100%;background:rgb(var(--zn-panel));border-right:1px solid rgb(var(--zn-border-color));overflow:hidden;transition:flex-basis 0.2s ease}.editor__controls-inner{position:absolute;inset:0;display:flex;flex-direction:column}.editor__controls-header{display:flex;align-items:center;flex:0 0 auto;min-height:44px;padding:var(--zn-spacing-small) var(--zn-spacing-medium)}.editor__controls-body{display:flex;flex-direction:column;gap:var(--zn-spacing-medium);flex:1 1 auto;min-height:0}.editor__main{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-width:0;min-height:0}.editor__fields{display:flex;flex-direction:column;gap:var(--zn-spacing-medium);flex:1 1 auto;min-height:0;overflow-y:auto}::slotted(zn-collapsible){width:100%}.editor__fields--sections-only .editor__section:first-of-type{border-top:none}.editor__section{display:block;border-top:1px solid rgba(var(--zn-border-color),0.5)}.editor__section::part(header){align-items:center !important;padding-block:calc(var(--zn-base-px) * 2) !important}.editor__section::part(caption){font-size:14px;font-weight:600;line-height:16px;color:rgb(var(--zn-text))}.editor__section-fields{display:flex;flex-direction:column;gap:var(--zn-spacing-medium)}.editor__tabs{display:block}.editor__section-slot{padding-top:var(--zn-spacing-sm)}.editor__tab-panel{display:flex;flex-direction:column}.editor__footer{display:flex;flex:0 0 auto;gap:var(--zn-spacing-small);padding-top:var(--zn-spacing-small);border-top:1px solid rgb(var(--zn-border-color));margin-top:auto}.editor__preview{overflow:auto;flex:1 1 auto;min-width:0;min-height:0;display:flex;flex-direction:column}.panel-toggle{position:absolute;top:50%;left:0;z-index:6;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;width:18px;height:44px;padding:0;border:1px solid rgb(var(--zn-border-color));border-left:0;border-radius:0 6px 6px 0;color:rgb(var(--zn-color-muted-text));background:rgb(var(--zn-panel));cursor:pointer;transition:left 0.2s ease,color 0.12s ease,border-color 0.12s ease}.panel-toggle:hover{color:rgb(var(--zn-text));background:rgba(var(--zn-border-color),0.4)}.panel-toggle--tucked{left:var(--zn-spacing-small);border-left:1px solid rgb(var(--zn-border-color));border-radius:6px}.editor__devices{display:flex;border:1px solid rgb(var(--zn-border-color));border-radius:4px;overflow:hidden}.editor__device,.editor__mode{display:flex;align-items:center;justify-content:center;width:30px;height:28px;padding:0;border:0;background:transparent;color:rgb(var(--zn-text));cursor:pointer}.editor__device+.editor__device{border-left:1px solid rgb(var(--zn-border-color))}.editor__device:hover,.editor__mode:hover{background:rgba(var(--zn-border-color),0.5)}.editor__device[aria-pressed=true]{background:rgb(var(--zn-primary));color:white}.editor__mode{border:1px solid rgb(var(--zn-border-color));border-radius:4px;margin-left:auto}.editor__sources{width:auto;max-width:160px}.editor__sources::part(form-control-label){position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}.editor__error{padding:var(--zn-spacing-small);margin-bottom:var(--zn-spacing-small);border-radius:4px;background:rgba(var(--zn-color-error),0.1);border:1px solid rgb(var(--zn-color-error));color:rgb(var(--zn-color-error));font-size:0.8125rem}@media (max-width:768px){:host{height:auto}.editor{flex-direction:column;height:auto}.editor__fields,.editor__preview{overflow:visible}.editor__controls{flex-basis:auto;width:100%;border-right:none;border-bottom:1px solid rgb(var(--zn-border-color))}.editor__controls-inner{position:static}.editor--controls-collapsed .editor__controls{display:none}.editor__main{width:100%;padding-top:var(--zn-spacing-medium)}.panel-toggle{top:0;left:50%;width:44px;height:18px;border:1px solid rgb(var(--zn-border-color));border-top:0;border-radius:0 0 6px 6px;transform:translateX(-50%)}.panel-toggle--tucked{top:var(--zn-spacing-small);left:50%;border-top:1px solid rgb(var(--zn-border-color));border-radius:6px}}`;var gq=new Set(["zn-checkbox","zn-toggle"]),bq="(max-width: 768px)",vq=[{id:"desktop",icon:"monitor",label:"Desktop"},{id:"tablet",icon:"tablet",label:"Tablet"},{id:"mobile",icon:"smartphone",label:"Mobile"}];function xq(i){return i.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}var Et=class extends C{constructor(){super(...arguments);this.src="";this.frameOrigin="";this.dataUri="";this.mode="light";this.device="desktop";this.minHeight=480;this.debounce=150;this.action="";this.saveDebounce=1e3;this.sections=[];this.sectionLayout="collapsible";this.sources=[];this.controlsCollapsed=!1;this.standalone=!1;this.controlsCaption="";this.previewCaption="";this.submitLabel="";this.manual=!1;this.error="";this._submitting=!1;this._sourceIndex=0;this.hasSlotController=new Q(this,"footer","[default]");this._saving=!1;this._saveQueued=!1;this._saveWaiters=[];this._narrowQuery=window.matchMedia(bq);this._wasNarrow=!1;this._mounted=!1;this._lastControls=[];this._controlsObserverConfig={childList:!0,subtree:!0};this._controlsObserver=new Lt(this,{target:null,config:this._controlsObserverConfig,callback:()=>this._pushIfControlsChanged()});this._modeValues={light:{},dark:{}};this._suppressDepth=0;this._openedInitialCollapsible=!1;this._onNarrowChange=t=>{t.matches&&!this._wasNarrow&&(this.controlsCollapsed=!0),this._wasNarrow=t.matches};this._onSubmit=()=>{if(!this._submitting){if(this._flushPendingEdit(),this._saveTimer&&(window.clearTimeout(this._saveTimer),this._saveTimer=void 0),!this.action){this.emit("zn-theme-submit",{detail:{values:this.values}});return}this._submitting=!0,this._awaitSave().then(t=>{t&&this.emit("zn-theme-submit",{detail:{values:this.values}})}).finally(()=>{this._submitting=!1})}};this._onControlChange=()=>{this._suppressDepth>0||(this._pushTimer&&window.clearTimeout(this._pushTimer),this._pushTimer=window.setTimeout(()=>{this._pushTimer=void 0,this._harvestInto(this.mode),this._push(),this._queueSave()},this.debounce))};this._onSlotChange=()=>{this._pushIfControlsChanged()};this._setDevice=t=>{this.device!==t&&(this.device=t,this._announce())};this._toggleMode=()=>{this._flushPendingEdit(),this.mode=this.mode==="dark"?"light":"dark",this._writeBack(),this._push()};this._onFrameError=t=>{this.error=t.detail.message??"Preview failed to render"};this._onSourceChange=t=>{let r=Number(t.target.value);Number.isNaN(r)||(this._sourceIndex=r)}}get values(){return{light:{...this._modeValues.light},dark:{...this._modeValues.dark}}}get activeValues(){return{...this._modeValues[this.mode]}}_controlSlots(){return[this.controlsSlot,...Array.from(this.sectionSlots??[])].filter(t=>!!t)}_harvestNamed(){let t=[];for(let r of this._controlSlots()){let n=r.assignedElements({flatten:!0});for(let a of n){let s=[a,...Array.from(a.querySelectorAll("[name]"))];for(let l of s){let d=l;!d.getAttribute?.("name")||d.disabled||t.push({name:d.getAttribute("name"),control:d})}}}return t}_hasAssignedControls(t){return Array.from(this.children).some(r=>r.getAttribute("slot")===t)}_isBooleanControl(t){return gq.has(t.tagName.toLowerCase())||t.type==="checkbox"}_readControlValue(t){return this._isBooleanControl(t)?!!t.checked:t.value}_seed(){for(let{name:t,control:r}of this._harvestNamed()){if(t in this._modeValues.light)continue;let n=this._readControlValue(r);this._modeValues.light[t]=n;let a=r.getAttribute("dark-value");this._modeValues.dark[t]=a===null?n:this._isBooleanControl(r)?a==="1"||a==="true":a}}_writeBack(t=this.mode){let r=!1;for(let{name:n,control:a}of this._harvestNamed()){if(!(n in this._modeValues[t]))continue;let s=this._modeValues[t][n],l=this._isBooleanControl(a),d=l?!!a.checked:a.value;(l?d===s:String(d)===String(s))||(r=!0,l?a.checked=!!s:a.value=s)}r&&(this._suppressDepth++,window.setTimeout(()=>{this._suppressDepth--},0))}_harvestInto(t){for(let{name:r,control:n}of this._harvestNamed())this._modeValues[t][r]=this._readControlValue(n)}connectedCallback(){super.connectedCallback(),this._controlsObserver.observe(this),this._narrowQuery.addEventListener("change",this._onNarrowChange),this._onNarrowChange(this._narrowQuery)}disconnectedCallback(){this._pushTimer&&window.clearTimeout(this._pushTimer),this._saveTimer&&window.clearTimeout(this._saveTimer),this._narrowQuery.removeEventListener("change",this._onNarrowChange),super.disconnectedCallback()}firstUpdated(){this._pushIfControlsChanged()}_push(){this.error="",this.frame?.setTheme({mode:this.mode,values:this.activeValues}),this._announce()}_queueSave(){!this.action||this.manual||(this._saveTimer&&window.clearTimeout(this._saveTimer),this._saveTimer=window.setTimeout(()=>{this._saveTimer=void 0,this._save()},this.saveDebounce))}async _save(){if(this._saving){this._saveQueued=!0;return}this._saving=!0;let t=!1;try{let r=new FormData;for(let a of["light","dark"])for(let[s,l]of Object.entries(this._modeValues[a]))r.append(`${a}[${s}]`,typeof l=="boolean"?l?"1":"":String(l??""));let n=await fetch(this.action,{method:"POST",credentials:"same-origin",body:r});if(!n.ok)throw new Error(await n.text()||n.statusText);this.error="",t=!0}catch(r){this._fail(r instanceof Error?r.message:String(r))}finally{if(this._saving=!1,this._saveQueued)this._saveQueued=!1,this._save();else{let r=this._saveWaiters;this._saveWaiters=[],r.forEach(n=>n(t))}}}_awaitSave(){return new Promise(t=>{this._saveWaiters.push(t),this._save()})}_pushIfControlsChanged(){this.requestUpdate();let t=this._harvestNamed().map(({control:n})=>n);(!this._mounted||t.length!==this._lastControls.length||t.some((n,a)=>n!==this._lastControls[a]))&&(this._flushPendingEdit(),this._mounted=!0,this._lastControls=t,this._seed(),this._writeBack(),this._push())}_flushPendingEdit(){this._pushTimer&&(window.clearTimeout(this._pushTimer),this._pushTimer=void 0,this._harvestInto(this.mode),this._queueSave())}_announce(){this.emit("zn-theme-change",{detail:{values:this.values,mode:this.mode,device:this.device}})}_fail(t){this.error=t,this.emit("zn-error",{detail:{message:t}})}_sourcesSafe(){return Array.isArray(this.sources)?this.sources:[]}_frameSrc(){let t=this._sourcesSafe();return t.length>0?(t[this._sourceIndex]??t[0]).src:this.src}_sectionsSafe(){return Array.isArray(this.sections)?this.sections:[]}_groupsFor(t){return Array.isArray(t?.groups)?t.groups:[]}_hasStructureAttributes(){return Array.from(this.children).some(t=>t.hasAttribute("group")||t.hasAttribute("category"))}_usesDerivedSections(){return this._sectionsSafe().length===0&&this._hasStructureAttributes()}_derive(){let t=new Set,r=l=>{let d=xq(l)||"group",h=d;for(let m=2;t.has(h);m++)h=`${d}-${m}`;return t.add(h),h},n=new Map,a=new Map,s=new Map;for(let l of Array.from(this.children)){let d=l.getAttribute("group")?.trim()??"",h=l.getAttribute("category")?.trim()??"";if(!d&&!h)continue;let m=d||h,f=n.get(m);if(f||(f={name:r(m),caption:m,groups:[]},n.set(m,f)),!d||!h){s.set(l,f.name);continue}let b=`${m}\0${h}`,g=a.get(b);g||(g=r(`${m}-${h}`),a.set(b,g),f.groups.push({name:g,caption:h})),s.set(l,g)}return{sections:Array.from(n.values()),assignments:s}}_effectiveSections(){return this._usesDerivedSections()?this._derive().sections:this._sectionsSafe()}_assignDerivedSlots(){if(this._usesDerivedSections())for(let[t,r]of this._derive().assignments)t.getAttribute("slot")!==r&&t.setAttribute("slot",r)}willUpdate(t){super.willUpdate(t),this._assignDerivedSlots()}_hasNestedGroups(){return this._effectiveSections().some(t=>this._groupsFor(t).length>0)}_visibleGroups(t){return this._groupsFor(t).filter(r=>this._hasAssignedControls(r.name))}_visibleSections(){let t=this._effectiveSections();return this._hasNestedGroups()?t.filter(r=>this._visibleGroups(r).length>0):t.filter(r=>this._hasAssignedControls(r.name))}_renderSections(){return this._visibleSections().map(t=>u`
|
|
5493
|
+
</div>`}};ye.styles=E(w_),c([p()],ye.prototype,"src",2),c([p({attribute:"frame-origin"})],ye.prototype,"frameOrigin",2),c([p({attribute:"data-uri"})],ye.prototype,"dataUri",2),c([p()],ye.prototype,"watch",2),c([p({attribute:"refresh-on"})],ye.prototype,"refreshOn",2),c([p({type:Number})],ye.prototype,"debounce",2),c([p({type:Number})],ye.prototype,"zoom",2),c([p({type:Number,attribute:"min-height"})],ye.prototype,"minHeight",2),c([p({type:Boolean})],ye.prototype,"fill",2),c([p({reflect:!0})],ye.prototype,"device",2),c([p({reflect:!0})],ye.prototype,"backdrop",2),c([p({type:Boolean,reflect:!0})],ye.prototype,"interactive",2),c([F("iframe")],ye.prototype,"frame",2),c([O()],ye.prototype,"error",2),c([O()],ye.prototype,"_contentHeight",2);var Ff=ye;ye.define("zn-preview-frame");var k_=S`@keyframes rotate-gradient{from{--rotate:0deg}to{--rotate:360deg}}:host{text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-transform:none}:host *,:host *::before,:host *::after{box-sizing:border-box;border-width:0;border-style:solid;border-color:rgb(var(--zn-border-color))}[hidden]{display:none !important}.width-container,.form-container,.wide-form-container{height:100%;width:100%;margin:var(--zn-default-margin,0 auto)}.width-container{max-width:var(--zn-container)}.form-container{max-width:var(--zn-container-ph)}.wide-form-container{max-width:var(--zn-container-lg)}:host{display:block;--zn-theme-editor-controls-width:343px;height:100%}.editor{--controls-col:var(--zn-theme-editor-controls-width);display:flex;align-items:stretch;height:100%}.editor--controls-collapsed{--controls-col:0px}.editor--controls-collapsed .editor__controls{border-right:none}.editor--controls-collapsed .editor__controls-header,.editor--controls-collapsed .editor__controls-body{padding:0}:host([standalone]) .editor{background:rgb(var(--zn-panel));border:1px solid rgb(var(--zn-border-color));border-radius:8px;overflow:hidden}.editor__toolbar{display:flex;align-items:center;flex:0 0 auto;min-height:44px;gap:var(--zn-spacing-small);padding:var(--zn-spacing-small) var(--zn-spacing-medium);border-bottom:1px solid rgb(var(--zn-border-color))}.editor__toolbar-actions{display:flex;align-items:center;gap:var(--zn-spacing-small);margin-left:auto}.editor__caption{font-size:14px;font-weight:600;line-height:16px;color:rgb(var(--zn-text))}.editor__controls{position:relative;display:flex;flex-direction:column;flex:0 0 var(--controls-col);min-width:0;max-width:100%;background:rgb(var(--zn-panel));border-right:1px solid rgb(var(--zn-border-color));overflow:hidden;transition:flex-basis 0.2s ease}.editor__controls-inner{position:absolute;inset:0;display:flex;flex-direction:column}.editor__controls-header{display:flex;align-items:center;flex:0 0 auto;min-height:44px;padding:var(--zn-spacing-small) var(--zn-spacing-medium)}.editor__controls-body{display:flex;flex-direction:column;gap:var(--zn-spacing-medium);flex:1 1 auto;min-height:0}.editor__main{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-width:0;min-height:0}.editor__fields{display:flex;flex-direction:column;gap:var(--zn-spacing-medium);flex:1 1 auto;min-height:0;overflow-y:auto}::slotted(zn-collapsible){width:100%}.editor__fields--sections-only .editor__section:first-of-type{border-top:none}.editor__section{display:block;border-top:1px solid rgba(var(--zn-border-color),0.5)}.editor__section::part(header){align-items:center !important;padding-block:calc(var(--zn-base-px) * 2) !important}.editor__section::part(caption){font-size:14px;font-weight:600;line-height:16px;color:rgb(var(--zn-text))}.editor__section-fields{display:flex;flex-direction:column;gap:var(--zn-spacing-medium)}.editor__tabs{display:block}.editor__section-slot{padding-top:var(--zn-spacing-sm)}.editor__tab-panel{display:flex;flex-direction:column}.editor__footer{display:flex;flex:0 0 auto;gap:var(--zn-spacing-small);padding-top:var(--zn-spacing-small);border-top:1px solid rgb(var(--zn-border-color));margin-top:auto}.editor__preview{overflow:hidden;flex:1 1 auto;min-width:0;min-height:0;display:flex;flex-direction:column}.panel-toggle{position:absolute;top:50%;left:0;z-index:6;transform:translateY(-50%);display:flex;align-items:center;justify-content:center;width:18px;height:44px;padding:0;border:1px solid rgb(var(--zn-border-color));border-left:0;border-radius:0 6px 6px 0;color:rgb(var(--zn-color-muted-text));background:rgb(var(--zn-panel));cursor:pointer;transition:left 0.2s ease,color 0.12s ease,border-color 0.12s ease}.panel-toggle:hover{color:rgb(var(--zn-text));background:rgba(var(--zn-border-color),0.4)}.panel-toggle--tucked{left:var(--zn-spacing-small);border-left:1px solid rgb(var(--zn-border-color));border-radius:6px}.editor__devices{display:flex;border:1px solid rgb(var(--zn-border-color));border-radius:4px;overflow:hidden}.editor__device,.editor__mode{display:flex;align-items:center;justify-content:center;width:30px;height:28px;padding:0;border:0;background:transparent;color:rgb(var(--zn-text));cursor:pointer}.editor__device+.editor__device{border-left:1px solid rgb(var(--zn-border-color))}.editor__device:hover,.editor__mode:hover{background:rgba(var(--zn-border-color),0.5)}.editor__device[aria-pressed=true]{background:rgb(var(--zn-primary));color:white}.editor__mode{border:1px solid rgb(var(--zn-border-color));border-radius:4px;margin-left:auto}.editor__sources{width:auto;max-width:160px}.editor__sources::part(form-control-label){position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}.editor__error{padding:var(--zn-spacing-small);margin-bottom:var(--zn-spacing-small);border-radius:4px;background:rgba(var(--zn-color-error),0.1);border:1px solid rgb(var(--zn-color-error));color:rgb(var(--zn-color-error));font-size:0.8125rem}@media (max-width:768px){:host{height:auto}.editor{flex-direction:column;height:auto}.editor__fields,.editor__preview{overflow:visible}.editor__controls{flex-basis:auto;width:100%;border-right:none;border-bottom:1px solid rgb(var(--zn-border-color))}.editor__controls-inner{position:static}.editor--controls-collapsed .editor__controls{display:none}.editor__main{width:100%;padding-top:var(--zn-spacing-medium)}.panel-toggle{top:0;left:50%;width:44px;height:18px;border:1px solid rgb(var(--zn-border-color));border-top:0;border-radius:0 0 6px 6px;transform:translateX(-50%)}.panel-toggle--tucked{top:var(--zn-spacing-small);left:50%;border-top:1px solid rgb(var(--zn-border-color));border-radius:6px}}`;var gq=new Set(["zn-checkbox","zn-toggle"]),bq="(max-width: 768px)",vq=[{id:"desktop",icon:"monitor",label:"Desktop"},{id:"tablet",icon:"tablet",label:"Tablet"},{id:"mobile",icon:"smartphone",label:"Mobile"}];function xq(i){return i.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}var Et=class extends C{constructor(){super(...arguments);this.src="";this.frameOrigin="";this.dataUri="";this.mode="light";this.device="desktop";this.minHeight=480;this.debounce=150;this.action="";this.saveDebounce=1e3;this.sections=[];this.sectionLayout="collapsible";this.sources=[];this.controlsCollapsed=!1;this.standalone=!1;this.controlsCaption="";this.previewCaption="";this.submitLabel="";this.manual=!1;this.error="";this._submitting=!1;this._sourceIndex=0;this.hasSlotController=new Q(this,"footer","[default]");this._saving=!1;this._saveQueued=!1;this._saveWaiters=[];this._narrowQuery=window.matchMedia(bq);this._wasNarrow=!1;this._mounted=!1;this._lastControls=[];this._controlsObserverConfig={childList:!0,subtree:!0};this._controlsObserver=new Lt(this,{target:null,config:this._controlsObserverConfig,callback:()=>this._pushIfControlsChanged()});this._modeValues={light:{},dark:{}};this._suppressDepth=0;this._openedInitialCollapsible=!1;this._onNarrowChange=t=>{t.matches&&!this._wasNarrow&&(this.controlsCollapsed=!0),this._wasNarrow=t.matches};this._onSubmit=()=>{if(!this._submitting){if(this._flushPendingEdit(),this._saveTimer&&(window.clearTimeout(this._saveTimer),this._saveTimer=void 0),!this.action){this.emit("zn-theme-submit",{detail:{values:this.values}});return}this._submitting=!0,this._awaitSave().then(t=>{t&&this.emit("zn-theme-submit",{detail:{values:this.values}})}).finally(()=>{this._submitting=!1})}};this._onControlChange=()=>{this._suppressDepth>0||(this._pushTimer&&window.clearTimeout(this._pushTimer),this._pushTimer=window.setTimeout(()=>{this._pushTimer=void 0,this._harvestInto(this.mode),this._push(),this._queueSave()},this.debounce))};this._onSlotChange=()=>{this._pushIfControlsChanged()};this._setDevice=t=>{this.device!==t&&(this.device=t,this._announce())};this._toggleMode=()=>{this._flushPendingEdit(),this.mode=this.mode==="dark"?"light":"dark",this._writeBack(),this._push()};this._onFrameError=t=>{this.error=t.detail.message??"Preview failed to render"};this._onSourceChange=t=>{let r=Number(t.target.value);Number.isNaN(r)||(this._sourceIndex=r)}}get values(){return{light:{...this._modeValues.light},dark:{...this._modeValues.dark}}}get activeValues(){return{...this._modeValues[this.mode]}}_controlSlots(){return[this.controlsSlot,...Array.from(this.sectionSlots??[])].filter(t=>!!t)}_harvestNamed(){let t=[];for(let r of this._controlSlots()){let n=r.assignedElements({flatten:!0});for(let a of n){let s=[a,...Array.from(a.querySelectorAll("[name]"))];for(let l of s){let d=l;!d.getAttribute?.("name")||d.disabled||t.push({name:d.getAttribute("name"),control:d})}}}return t}_hasAssignedControls(t){return Array.from(this.children).some(r=>r.getAttribute("slot")===t)}_isBooleanControl(t){return gq.has(t.tagName.toLowerCase())||t.type==="checkbox"}_readControlValue(t){return this._isBooleanControl(t)?!!t.checked:t.value}_seed(){for(let{name:t,control:r}of this._harvestNamed()){if(t in this._modeValues.light)continue;let n=this._readControlValue(r);this._modeValues.light[t]=n;let a=r.getAttribute("dark-value");this._modeValues.dark[t]=a===null?n:this._isBooleanControl(r)?a==="1"||a==="true":a}}_writeBack(t=this.mode){let r=!1;for(let{name:n,control:a}of this._harvestNamed()){if(!(n in this._modeValues[t]))continue;let s=this._modeValues[t][n],l=this._isBooleanControl(a),d=l?!!a.checked:a.value;(l?d===s:String(d)===String(s))||(r=!0,l?a.checked=!!s:a.value=s)}r&&(this._suppressDepth++,window.setTimeout(()=>{this._suppressDepth--},0))}_harvestInto(t){for(let{name:r,control:n}of this._harvestNamed())this._modeValues[t][r]=this._readControlValue(n)}connectedCallback(){super.connectedCallback(),this._controlsObserver.observe(this),this._narrowQuery.addEventListener("change",this._onNarrowChange),this._onNarrowChange(this._narrowQuery)}disconnectedCallback(){this._pushTimer&&window.clearTimeout(this._pushTimer),this._saveTimer&&window.clearTimeout(this._saveTimer),this._narrowQuery.removeEventListener("change",this._onNarrowChange),super.disconnectedCallback()}firstUpdated(){this._pushIfControlsChanged()}_push(){this.error="",this.frame?.setTheme({mode:this.mode,values:this.activeValues}),this._announce()}_queueSave(){!this.action||this.manual||(this._saveTimer&&window.clearTimeout(this._saveTimer),this._saveTimer=window.setTimeout(()=>{this._saveTimer=void 0,this._save()},this.saveDebounce))}async _save(){if(this._saving){this._saveQueued=!0;return}this._saving=!0;let t=!1;try{let r=new FormData;for(let a of["light","dark"])for(let[s,l]of Object.entries(this._modeValues[a]))r.append(`${a}[${s}]`,typeof l=="boolean"?l?"1":"":String(l??""));let n=await fetch(this.action,{method:"POST",credentials:"same-origin",body:r});if(!n.ok)throw new Error(await n.text()||n.statusText);this.error="",t=!0}catch(r){this._fail(r instanceof Error?r.message:String(r))}finally{if(this._saving=!1,this._saveQueued)this._saveQueued=!1,this._save();else{let r=this._saveWaiters;this._saveWaiters=[],r.forEach(n=>n(t))}}}_awaitSave(){return new Promise(t=>{this._saveWaiters.push(t),this._save()})}_pushIfControlsChanged(){this.requestUpdate();let t=this._harvestNamed().map(({control:n})=>n);(!this._mounted||t.length!==this._lastControls.length||t.some((n,a)=>n!==this._lastControls[a]))&&(this._flushPendingEdit(),this._mounted=!0,this._lastControls=t,this._seed(),this._writeBack(),this._push())}_flushPendingEdit(){this._pushTimer&&(window.clearTimeout(this._pushTimer),this._pushTimer=void 0,this._harvestInto(this.mode),this._queueSave())}_announce(){this.emit("zn-theme-change",{detail:{values:this.values,mode:this.mode,device:this.device}})}_fail(t){this.error=t,this.emit("zn-error",{detail:{message:t}})}_sourcesSafe(){return Array.isArray(this.sources)?this.sources:[]}_frameSrc(){let t=this._sourcesSafe();return t.length>0?(t[this._sourceIndex]??t[0]).src:this.src}_sectionsSafe(){return Array.isArray(this.sections)?this.sections:[]}_groupsFor(t){return Array.isArray(t?.groups)?t.groups:[]}_hasStructureAttributes(){return Array.from(this.children).some(t=>t.hasAttribute("group")||t.hasAttribute("category"))}_usesDerivedSections(){return this._sectionsSafe().length===0&&this._hasStructureAttributes()}_derive(){let t=new Set,r=l=>{let d=xq(l)||"group",h=d;for(let m=2;t.has(h);m++)h=`${d}-${m}`;return t.add(h),h},n=new Map,a=new Map,s=new Map;for(let l of Array.from(this.children)){let d=l.getAttribute("group")?.trim()??"",h=l.getAttribute("category")?.trim()??"";if(!d&&!h)continue;let m=d||h,f=n.get(m);if(f||(f={name:r(m),caption:m,groups:[]},n.set(m,f)),!d||!h){s.set(l,f.name);continue}let b=`${m}\0${h}`,g=a.get(b);g||(g=r(`${m}-${h}`),a.set(b,g),f.groups.push({name:g,caption:h})),s.set(l,g)}return{sections:Array.from(n.values()),assignments:s}}_effectiveSections(){return this._usesDerivedSections()?this._derive().sections:this._sectionsSafe()}_assignDerivedSlots(){if(this._usesDerivedSections())for(let[t,r]of this._derive().assignments)t.getAttribute("slot")!==r&&t.setAttribute("slot",r)}willUpdate(t){super.willUpdate(t),this._assignDerivedSlots()}_hasNestedGroups(){return this._effectiveSections().some(t=>this._groupsFor(t).length>0)}_visibleGroups(t){return this._groupsFor(t).filter(r=>this._hasAssignedControls(r.name))}_visibleSections(){let t=this._effectiveSections();return this._hasNestedGroups()?t.filter(r=>this._visibleGroups(r).length>0):t.filter(r=>this._hasAssignedControls(r.name))}_renderSections(){return this._visibleSections().map(t=>u`
|
|
5494
5494
|
<zn-collapsible
|
|
5495
5495
|
class="editor__section"
|
|
5496
5496
|
part="section"
|
|
@@ -5542,10 +5542,12 @@ ${n}`:""}</li></ol>`};return t(0)}parseTable(o,t){this.index++;let r=[],n=[];for
|
|
|
5542
5542
|
@input="${this._onControlChange}">
|
|
5543
5543
|
<slot @slotchange="${this._onSlotChange}"></slot>
|
|
5544
5544
|
${this._hasNestedGroups()?this._renderTabs(t=>u`
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5545
|
+
${this._hasAssignedControls(t.name)?u`
|
|
5546
|
+
<slot name="${t.name}" class="editor__section-slot"
|
|
5547
|
+
@slotchange="${this._onSlotChange}"></slot>`:V}
|
|
5548
|
+
${this._renderGroups(t)}`):this.sectionLayout==="tabs"?this._renderTabs(t=>u`
|
|
5549
|
+
<slot name="${t.name}" class="editor__section-slot"
|
|
5550
|
+
@slotchange="${this._onSlotChange}"></slot>`):this._renderSections()}
|
|
5549
5551
|
</div>
|
|
5550
5552
|
${this.hasSlotController.test("footer")?u`
|
|
5551
5553
|
<div part="footer" class="editor__footer">
|
|
@@ -5609,6 +5611,7 @@ ${n}`:""}</li></ol>`};return t(0)}parseTable(o,t){this.index++;let r=[],n=[];for
|
|
|
5609
5611
|
device="${this.device}"
|
|
5610
5612
|
min-height="${this.minHeight}"
|
|
5611
5613
|
fill
|
|
5614
|
+
interactive
|
|
5612
5615
|
backdrop="${this.standalone?"panel":"dots"}"
|
|
5613
5616
|
exportparts="base:preview__base,stage:preview__stage,iframe:preview__iframe,error:preview__error"
|
|
5614
5617
|
@zn-error="${this._onFrameError}"></zn-preview-frame>
|
|
@@ -56,7 +56,13 @@ handlers can't be cancelled from out here — blocking pointer input is the only
|
|
|
56
56
|
way to stop them, and hover goes with it. Scrolling doesn't: an overflowing page
|
|
57
57
|
is scrolled by the panel instead, as below.
|
|
58
58
|
|
|
59
|
-
Set `interactive` when the embed is meant to be used rather than looked at.
|
|
59
|
+
Set `interactive` when the embed is meant to be used rather than looked at. The
|
|
60
|
+
frame then behaves as a viewport: it stays the panel's own height and the embed
|
|
61
|
+
scrolls itself, so there's a single scrollbar and the embed's `100vh`,
|
|
62
|
+
`position: fixed` and sticky content size to what's actually on screen. The
|
|
63
|
+
[reported content height](#overflowing-content) is ignored while `interactive`
|
|
64
|
+
is set — it exists to make an *inert* frame's overflow reachable, which an
|
|
65
|
+
interactive one does for itself.
|
|
60
66
|
|
|
61
67
|
```html:preview
|
|
62
68
|
<zn-preview-frame
|
|
@@ -73,11 +79,13 @@ Set `interactive` when the embed is meant to be used rather than looked at.
|
|
|
73
79
|
|
|
74
80
|
## Overflowing Content
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
frame can't do it itself: a cross-origin document can't be scrolled
|
|
78
|
-
(`contentWindow.scrollTo` is blocked), and with pointer input off
|
|
79
|
-
reaches it anyway. So the frame is instead laid out at its full
|
|
80
|
-
nothing scrolls inside it — and the panel scrolls that.
|
|
82
|
+
An inert page taller than the panel is scrolled by the panel, not inside the
|
|
83
|
+
frame. The frame can't do it itself: a cross-origin document can't be scrolled
|
|
84
|
+
from the host (`contentWindow.scrollTo` is blocked), and with pointer input off
|
|
85
|
+
the wheel never reaches it anyway. So the frame is instead laid out at its full
|
|
86
|
+
content height — nothing scrolls inside it — and the panel scrolls that. An
|
|
87
|
+
[`interactive`](#interactivity) frame doesn't need any of this and opts out of
|
|
88
|
+
it: it keeps the panel's height and the embed scrolls itself.
|
|
81
89
|
|
|
82
90
|
For the frame to be sized that way, the embed reports its height alongside
|
|
83
91
|
`hp-preview:rendered`:
|
|
@@ -24,6 +24,10 @@ Set `controls-caption` and `preview-caption` to label each column's header
|
|
|
24
24
|
row — both are empty by default, rendering no text (the controls column's
|
|
25
25
|
header row still renders either way, so the two columns stay aligned).
|
|
26
26
|
|
|
27
|
+
The preview is [interactive](/components/preview-frame/#interactivity): the
|
|
28
|
+
embedded page can be clicked and hovered, and it scrolls itself, so the preview
|
|
29
|
+
column never adds a second scrollbar beside the embed's own.
|
|
30
|
+
|
|
27
31
|
The preview always fills its column, leaving no dead space beneath it.
|
|
28
32
|
`min-height` (default `480`) is a floor for that column, not a fixed height —
|
|
29
33
|
it's still forwarded to the [preview frame](/components/preview-frame/), which
|
package/package.json
CHANGED
|
@@ -111,6 +111,12 @@ export default class ZnPreviewFrame extends ZincElement {
|
|
|
111
111
|
* be reached from here to cancel its own handlers, so this blocks pointer
|
|
112
112
|
* input entirely — hover goes with it. Scrolling doesn't: an overflowing
|
|
113
113
|
* page is scrolled by the panel rather than by the frame (see _contentHeight).
|
|
114
|
+
*
|
|
115
|
+
* Set, the frame becomes a real viewport instead: it stays the panel's own
|
|
116
|
+
* height and the embed scrolls itself, so there is one scrollbar rather than
|
|
117
|
+
* a panel scrolling an oversized frame, and the embed's viewport-relative
|
|
118
|
+
* layout (`100vh`, `position: fixed`, sticky headers) sizes to what's on
|
|
119
|
+
* screen. _contentHeight is ignored while this is set.
|
|
114
120
|
*/
|
|
115
121
|
@property({type: Boolean, reflect: true}) interactive = false;
|
|
116
122
|
|
|
@@ -125,7 +131,8 @@ export default class ZnPreviewFrame extends ZincElement {
|
|
|
125
131
|
* height rather than the panel's, so the page never scrolls inside the frame
|
|
126
132
|
* — the panel scrolls instead, which is what makes an overflowing preview
|
|
127
133
|
* reachable while pointer input to the frame is blocked. 0 = unknown, and the
|
|
128
|
-
* frame falls back to filling the panel.
|
|
134
|
+
* frame falls back to filling the panel. Kept up to date either way, but only
|
|
135
|
+
* laid out when the frame is inert: an `interactive` frame scrolls itself.
|
|
129
136
|
*/
|
|
130
137
|
@state() private _contentHeight = 0;
|
|
131
138
|
|
|
@@ -396,7 +403,10 @@ export default class ZnPreviewFrame extends ZincElement {
|
|
|
396
403
|
// transformed back down, so the frame fills the panel while the content
|
|
397
404
|
// renders smaller and more of the page is visible. Percentage width means
|
|
398
405
|
// nothing is measured — no layout feedback loop.
|
|
399
|
-
|
|
406
|
+
// Growing the frame past the panel is the workaround for an inert frame not
|
|
407
|
+
// being scrollable; interactive, that trades one scrollbar for two and hands
|
|
408
|
+
// the embed a viewport taller than the panel it's shown in.
|
|
409
|
+
const content = this.error || this.interactive ? 0 : this._contentHeight;
|
|
400
410
|
const iframeStyles = this.fill
|
|
401
411
|
? {width: '100%', height: content ? `max(${content}px, 100%)` : '100%'}
|
|
402
412
|
: {
|