domma-cms 0.3.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/admin/css/admin.css +1 -1
- package/admin/dist/domma/domma-tools.css +2313 -0
- package/admin/dist/domma/domma-tools.min.js +10 -0
- package/admin/index.html +4 -0
- package/admin/js/api.js +1 -1
- package/admin/js/app.js +8 -4
- package/admin/js/config/sidebar-config.js +1 -1
- package/admin/js/lib/markdown-toolbar.js +18 -10
- package/admin/js/templates/action-editor.html +171 -0
- package/admin/js/templates/actions-list.html +19 -0
- package/admin/js/templates/api-reference.html +1411 -0
- package/admin/js/templates/block-editor.html +158 -0
- package/admin/js/templates/blocks.html +8 -0
- package/admin/js/templates/collection-editor.html +47 -0
- package/admin/js/templates/collection-entries.html +3 -0
- package/admin/js/templates/collections.html +51 -4
- package/admin/js/templates/documentation.html +258 -0
- package/{plugins/form-builder/admin → admin/js}/templates/form-editor.html +238 -199
- package/{plugins/form-builder/admin → admin/js}/templates/form-submissions.html +30 -30
- package/{plugins/form-builder/admin/templates/forms-list.html → admin/js/templates/forms.html} +17 -17
- package/admin/js/templates/login.html +29 -4
- package/admin/js/templates/my-profile.html +17 -0
- package/admin/js/templates/page-editor.html +39 -0
- package/admin/js/templates/pages.html +6 -1
- package/admin/js/templates/pro-docs.html +259 -0
- package/admin/js/templates/role-editor.html +59 -0
- package/admin/js/templates/roles.html +10 -0
- package/admin/js/templates/settings.html +167 -23
- package/admin/js/templates/tutorials.html +81 -0
- package/admin/js/templates/user-editor.html +7 -0
- package/admin/js/templates/users.html +3 -26
- package/admin/js/templates/view-editor.html +201 -0
- package/admin/js/templates/view-preview.html +51 -0
- package/admin/js/templates/views-list.html +19 -0
- package/admin/js/views/action-editor.js +1 -0
- package/admin/js/views/actions-list.js +1 -0
- package/admin/js/views/api-reference.js +1 -0
- package/admin/js/views/block-editor.js +8 -0
- package/admin/js/views/blocks.js +4 -0
- package/admin/js/views/collection-editor.js +3 -3
- package/admin/js/views/collection-entries.js +1 -1
- package/admin/js/views/collections.js +1 -1
- package/admin/js/views/dashboard.js +1 -1
- package/admin/js/views/form-editor.js +8 -0
- package/admin/js/views/form-submissions.js +1 -0
- package/admin/js/views/forms.js +1 -0
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/login.js +2 -2
- package/admin/js/views/media.js +1 -1
- package/admin/js/views/my-profile.js +1 -0
- package/admin/js/views/page-editor.js +34 -15
- package/admin/js/views/pages.js +5 -5
- package/admin/js/views/plugins.js +10 -10
- package/admin/js/views/pro-docs.js +1 -0
- package/admin/js/views/role-editor.js +1 -0
- package/admin/js/views/roles.js +4 -0
- package/admin/js/views/settings.js +3 -1
- package/admin/js/views/user-editor.js +1 -1
- package/admin/js/views/users.js +4 -7
- package/admin/js/views/view-editor.js +1 -0
- package/admin/js/views/view-preview.js +1 -0
- package/admin/js/views/views-list.js +1 -0
- package/bin/cli.js +1 -1
- package/config/auth.json +1 -0
- package/config/connections.json.bak +9 -0
- package/config/connections.json.example +9 -0
- package/config/navigation.json +5 -15
- package/config/plugins.json +19 -29
- package/config/server.json +6 -6
- package/config/site.json +16 -6
- package/package.json +25 -10
- package/plugins/example-analytics/stats.json +17 -12
- package/plugins/form-builder/data/forms/contacts.json +62 -62
- package/plugins/form-builder/data/forms/enquiries.json +103 -0
- package/plugins/form-builder/data/forms/feedback.json +17 -16
- package/plugins/form-builder/data/forms/notes.json +79 -0
- package/plugins/form-builder/data/forms/to-do.json +100 -0
- package/plugins/form-builder/data/submissions/contacts.json +1 -26
- package/plugins/form-builder/data/submissions/notes.json +1 -0
- package/plugins/form-builder/data/submissions/to-do.json +1 -0
- package/plugins/theme-roller/admin/templates/theme-roller.html +71 -0
- package/plugins/theme-roller/admin/views/theme-roller-view.js +403 -0
- package/plugins/theme-roller/config.js +1 -0
- package/plugins/theme-roller/plugin.js +233 -0
- package/plugins/theme-roller/plugin.json +31 -0
- package/plugins/theme-roller/public/active-theme.css +0 -0
- package/plugins/theme-roller/public/inject-head-late.html +1 -0
- package/public/css/forms.css +1 -0
- package/public/css/site.css +1 -1
- package/public/js/forms.js +1 -0
- package/public/js/site.js +1 -1
- package/scripts/build.js +194 -129
- package/scripts/pro.js +254 -0
- package/scripts/reset.js +33 -8
- package/scripts/seed.js +677 -128
- package/scripts/setup.js +1 -0
- package/server/middleware/auth.js +136 -120
- package/server/routes/api/actions.js +200 -0
- package/server/routes/api/auth.js +292 -146
- package/server/routes/api/blocks.js +84 -0
- package/server/routes/api/collections.js +79 -27
- package/{plugins/form-builder/plugin.js → server/routes/api/forms.js} +491 -505
- package/server/routes/api/layouts.js +49 -39
- package/server/routes/api/media.js +118 -92
- package/server/routes/api/navigation.js +40 -36
- package/server/routes/api/pages.js +132 -118
- package/server/routes/api/plugins.js +6 -3
- package/server/routes/api/settings.js +104 -88
- package/server/routes/api/users.js +27 -19
- package/server/routes/api/views.js +148 -0
- package/server/routes/public.js +124 -108
- package/server/server.js +269 -181
- package/server/services/actions.js +387 -0
- package/server/services/adapterRegistry.js +98 -0
- package/server/services/adapters/FileAdapter.js +192 -0
- package/server/services/adapters/MongoAdapter.js +220 -0
- package/server/services/blocks.js +162 -0
- package/server/services/collections.js +74 -86
- package/server/services/connectionManager.js +102 -0
- package/server/services/content.js +312 -307
- package/server/services/email.js +126 -0
- package/server/services/forms.js +173 -0
- package/server/services/markdown.js +1378 -747
- package/server/services/permissionRegistry.js +173 -0
- package/server/services/presetCollections.js +251 -0
- package/server/services/renderer.js +98 -2
- package/server/services/roles.js +227 -0
- package/server/services/rowAccess.js +104 -0
- package/server/services/userProfiles.js +199 -0
- package/server/services/users.js +281 -212
- package/server/services/views.js +280 -0
- package/server/templates/page.html +124 -113
- package/plugins/form-builder/admin/templates/form-settings.html +0 -29
- package/plugins/form-builder/admin/views/form-editor.js +0 -1444
- package/plugins/form-builder/admin/views/form-settings.js +0 -38
- package/plugins/form-builder/admin/views/form-submissions.js +0 -295
- package/plugins/form-builder/admin/views/forms-list.js +0 -164
- package/plugins/form-builder/config.js +0 -9
- package/plugins/form-builder/data/forms/consent.json +0 -104
- package/plugins/form-builder/data/forms/contact-details.json +0 -99
- package/plugins/form-builder/data/submissions/consent.json +0 -13
- package/plugins/form-builder/plugin.json +0 -52
- package/plugins/form-builder/public/inject-body.html +0 -352
- package/plugins/form-builder/public/inject-head.html +0 -58
- package/plugins/form-builder/public/package.json +0 -1
- package/scripts/copy-domma.js +0 -48
- package/server/services/userTypes.js +0 -167
- /package/plugins/form-builder/data/submissions/{contact-details.json → enquiries.json} +0 -0
- /package/{plugins/form-builder/public → public/js}/form-logic-engine.js +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Domma Tools v0.19.3
|
|
3
|
+
* Developer tools: Theme Roller & Page Roller
|
|
4
|
+
* (c) 2026 Darryl Waterhouse & DCBW-IT
|
|
5
|
+
* Built: 2026-03-06T15:12:47.301Z
|
|
6
|
+
* Commit: 17c6e27
|
|
7
|
+
*
|
|
8
|
+
* Requires: domma.min.js
|
|
9
|
+
*/
|
|
10
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).DommaTools={})}(this,function(e){"use strict";const t="domma-theme",n="domma-theme-variant",a="dm-theme-",i=["ocean-light","ocean-dark","forest-light","forest-dark","sunset-light","sunset-dark","royal-light","royal-dark","lemon-light","lemon-dark","silver-light","silver-dark","charcoal-light","charcoal-dark","christmas-light","christmas-dark","unicorn-light","unicorn-dark","dreamy-light","dreamy-dark","grayve-light","grayve-dark","core-light"],s="charcoal-dark";const o=new class{constructor(){this._theme=s,this._listeners=[],this._target=null,this._initialised=!1,this._systemMediaQuery=null,this._autoDetect=!1,this._disabled=!1}init(e={}){const{theme:t=null,autoDetect:n=!1,persist:a=!0,disabled:o=!1,target:r=document.body}=e;if(o)return this._disabled=!0,this._initialised=!0,this;this._target="string"==typeof r?document.querySelector(r):r,this._target||(this._target=document.body),this._persist=a,this._autoDetect=n;let l=t;if(a){const e=this._loadFromStorage();e&&!t&&(l=e)}if(n&&!l){l="dark"===this._getSystemPreference()?"charcoal-dark":"charcoal-light",this._setupSystemListener()}return l=l||s,i.includes(l)||(console.warn(`Invalid theme: ${l}. Using default: ${s}`),l=s),this._theme=l,this._applyTheme(),this._initialised=!0,this}get(){return this._theme}getBase(){return this._theme.split("-").slice(0,-1).join("-")}getMode(){return this._theme.split("-").pop()}isDark(){return"dark"===this.getMode()}isLight(){return"light"===this.getMode()}set(e){if(!i.includes(e))return console.warn(`Invalid theme: ${e}. Available themes: ${i.join(", ")}`),this;const t=this._theme;return t===e||(this._theme=e,this._applyTheme(),this._saveToStorage(),this._notifyListeners(t,e)),this}setVariant(){return console.warn('[ThemeEngine] setVariant() is deprecated. Use set() with full theme name (e.g., set("ocean-dark"))'),this}toggle(){return console.warn("[ThemeEngine] toggle() is deprecated. Use variant selector UI or set() method."),this}onChange(e){return"function"!=typeof e?(console.warn("onChange requires a function callback"),()=>{}):(this._listeners.push(e),()=>{const t=this._listeners.indexOf(e);t>-1&&this._listeners.splice(t,1)})}preview(e){if(!i.includes(e))return console.warn(`Invalid theme for preview: ${e}`),()=>{};const t=this._theme;return this._theme=e,this._applyTheme(!1),()=>{this._theme=t,this._applyTheme(!1)}}listThemes(){return[...i]}listBases(){return["ocean","forest","sunset","royal","lemon","silver","charcoal","christmas","unicorn","dreamy","grayve"]}listVariants(){return console.warn("[ThemeEngine] listVariants() is deprecated. Use listThemes() instead."),this.listBases()}getConfig(){return{theme:this._theme,base:this.getBase(),mode:this.getMode(),autoDetect:this._autoDetect,persist:this._persist,disabled:this._disabled}}_updateMetaThemeColor(){const e={light:"#ffffff",dark:"#121212"};let t=document.querySelector('meta[name="theme-color"]');t||(t=document.createElement("meta"),t.name="theme-color",document.head.appendChild(t)),t.content=e[this.getMode()]||e.dark}isDisabled(){return this._disabled}enable(){return this._disabled=!1,this._target||(this._target=document.body),this._applyTheme(),this}disable(){if(this._disabled=!0,this._target){const e=this._target.className.split(" ").filter(e=>!e.startsWith(a));this._target.className=e.join(" ").trim(),this._target.removeAttribute("data-mode")}return this}_applyTheme(e=!0){if(this._disabled)return;const t=this._target||document.body;if(!t)return void console.error("[ThemeEngine] No target element available for theme application");const n=t.className.split(" ").filter(e=>!e.startsWith(a));n.push(`${a}${this._theme}`),t.className=n.join(" ").trim();const i=this.isDark()?"dark":"light";t.setAttribute("data-mode",i),e&&this._updateMetaThemeColor()}_saveToStorage(){if(this._persist&&"undefined"!=typeof localStorage)try{localStorage.setItem(t,this._theme),localStorage.removeItem(n)}catch(e){}}_loadFromStorage(){if("undefined"==typeof localStorage)return null;try{const e=localStorage.getItem(t);if(e&&i.includes(e))return e;const a=e,s=localStorage.getItem(n);if(a&&["light","dark"].includes(a)){const e=`${s||"charcoal"}-${a}`;if(console.log(`[ThemeEngine] Migrating theme: ${a} + ${s} → ${e}`),i.includes(e))return localStorage.setItem(t,e),localStorage.removeItem(n),e}return null}catch(e){return null}}_getSystemPreference(){return"undefined"!=typeof window&&window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}_setupSystemListener(){if("undefined"==typeof window||!window.matchMedia)return;this._systemMediaQuery=window.matchMedia("(prefers-color-scheme: dark)");const e=e=>{if(!this._autoDetect)return;const t=e.matches?"dark":"light",n=`${this.getBase()}-${t}`;i.includes(n)&&this.set(n)};this._systemMediaQuery.addEventListener?this._systemMediaQuery.addEventListener("change",e):this._systemMediaQuery.addListener(e)}_notifyListeners(e,t){this._listeners.forEach(n=>{try{n(e,t)}catch(e){console.error("[ThemeEngine] Error in change listener:",e)}})}destroy(){this._systemMediaQuery&&this._systemMediaQuery.removeEventListener,this._listeners=[],this._target=null,this._initialised=!1}};"undefined"!=typeof document&&("loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{o._initialised||o.init({persist:!0,autoDetect:!1})}):o._initialised||o.init({persist:!0,autoDetect:!1}));const r={_prefix:"domma:",_available:null,isAvailable(){if(null!==this._available)return this._available;try{const e=`${this._prefix}__test__`;localStorage.setItem(e,"test"),localStorage.removeItem(e),this._available=!0}catch(e){this._available=!1}return this._available},_prefixKey(e){return`${this._prefix}${e}`},_unprefixKey(e){return e.slice(this._prefix.length)},get(e,t=null){if(!this.isAvailable())return t;try{const n=this._prefixKey(e),a=localStorage.getItem(n);return null===a?t:JSON.parse(a)}catch(n){return console.warn(`Domma storage: Failed to parse key "${e}"`,n),t}},set(e,t){if(!this.isAvailable())return!1;try{const n=this._prefixKey(e),a=JSON.stringify(t);return localStorage.setItem(n,a),!0}catch(t){return console.warn(`Domma storage: Failed to set key "${e}"`,t),!1}},remove(e){if(!this.isAvailable())return!1;try{const t=this._prefixKey(e);return localStorage.removeItem(t),!0}catch(t){return console.warn(`Domma storage: Failed to remove key "${e}"`,t),!1}},has(e){if(!this.isAvailable())return!1;try{const t=this._prefixKey(e);return null!==localStorage.getItem(t)}catch(e){return!1}},clear(){if(!this.isAvailable())return 0;try{const e=this.keys();return e.forEach(e=>this.remove(e)),e.length}catch(e){return console.warn("Domma storage: Failed to clear storage",e),0}},keys(){if(!this.isAvailable())return[];try{const e=[];for(let t=0;t<localStorage.length;t++){const n=localStorage.key(t);n&&n.startsWith(this._prefix)&&e.push(this._unprefixKey(n))}return e}catch(e){return[]}},size(e){if(!this.isAvailable())return 0;try{const t=this._prefixKey(e),n=localStorage.getItem(t);return n?new Blob([n]).size:0}catch(e){return 0}},totalSize(){if(!this.isAvailable())return 0;try{let e=0;return this.keys().forEach(t=>{e+=this.size(t)}),e}catch(e){return 0}},getAll(){if(!this.isAvailable())return{};const e={};return this.keys().forEach(t=>{e[t]=this.get(t)}),e},setAll(e){if(!this.isAvailable()||!e)return!1;let t=!0;return Object.keys(e).forEach(n=>{this.set(n,e[n])||(t=!1)}),t}},l={chunk(e,t=1){if(!e||t<1)return[];const n=[];for(let a=0;a<e.length;a+=t)n.push(e.slice(a,a+t));return n},compact:e=>e?e.filter(Boolean):[],concat:(e,...t)=>e?e.concat(...t):[],difference(e,...t){if(!e)return[];const n=new Set(t.flat());return e.filter(e=>!n.has(e))},differenceBy(e,t,n){if(!e)return[];const a=new Set(t.map(n));return e.filter(e=>!a.has(n(e)))},differenceWith:(e,t,n)=>e?e.filter(e=>!t.some(t=>n(e,t))):[],drop:(e,t=1)=>e?e.slice(t):[],dropRight(e,t=1){if(!e)return[];const n=e.length-t;return n>0?e.slice(0,n):[]},dropRightWhile(e,t){if(!e)return[];let n=e.length;for(;n--&&t(e[n],n,e););return e.slice(0,n+1)},dropWhile(e,t){if(!e)return[];let n=0;for(;n<e.length&&t(e[n],n,e);)n++;return e.slice(n)},eq:(e,t)=>e===t||e!=e&&t!=t,fill:(e,t,n=0,a)=>e?e.fill(t,n,a):[],findIndex(e,t,n=0){if(!e)return-1;for(let a=n;a<e.length;a++)if(t(e[a],a,e))return a;return-1},findLastIndex(e,t,n){if(!e)return-1;for(let a=void 0!==n?n:e.length-1;a>=0;a--)if(t(e[a],a,e))return a;return-1},first:e=>e?e[0]:void 0,head(e){return this.first(e)},flatten:e=>e?e.flat(1):[],flattenDeep:e=>e?e.flat(1/0):[],flattenDepth:(e,t=1)=>e?e.flat(t):[],fromPairs:e=>e?Object.fromEntries(e):{},indexOf:(e,t,n=0)=>e?e.indexOf(t,n):-1,initial:e=>e?e.slice(0,-1):[],intersection(...e){if(!e.length)return[];return e[0].filter(t=>e.every(e=>e.includes(t)))},join:(e,t=",")=>e?e.join(t):"",last:e=>e?e[e.length-1]:void 0,lastIndexOf:(e,t,n)=>e?void 0!==n?e.lastIndexOf(t,n):e.lastIndexOf(t):-1,nth(e,t=0){if(e)return t<0?e[e.length+t]:e[t]},pull(e,...t){if(!e)return[];const n=new Set(t);for(let t=e.length-1;t>=0;t--)n.has(e[t])&&e.splice(t,1);return e},pullAt(e,...t){if(!e)return[];const n=t.flat().sort((e,t)=>t-e),a=[];return n.forEach(t=>{t>=0&&t<e.length&&a.unshift(e.splice(t,1)[0])}),a},reverse:e=>e?e.reverse():[],slice:(e,t=0,n)=>e?void 0!==n?e.slice(t,n):e.slice(t):[],tail:e=>e?e.slice(1):[],take:(e,t=1)=>e?e.slice(0,t):[],takeRight(e,t=1){if(!e)return[];const n=Math.max(0,e.length-t);return e.slice(n)},union:(...e)=>[...new Set(e.flat())],uniq:e=>e?[...new Set(e)]:[],uniqBy(e,t){if(!e)return[];const n=new Set;return e.filter(e=>{const a=t(e);return!n.has(a)&&(n.add(a),!0)})},without(e,...t){if(!e)return[];const n=new Set(t);return e.filter(e=>!n.has(e))},xor(...e){if(!e.length)return[];const t=new Map;return e.flat().forEach(e=>{t.set(e,(t.get(e)||0)+1)}),[...t.entries()].filter(([,e])=>1===e).map(([e])=>e)},zip(...e){if(!e.length)return[];const t=Math.max(...e.map(e=>e.length)),n=[];for(let a=0;a<t;a++)n.push(e.map(e=>e[a]));return n},zipObject(e,t){if(!e)return{};const n={};return e.forEach((e,a)=>{n[e]=t?t[a]:void 0}),n},times(e,t){if((e=Math.floor(e))<1)return[];const n=new Array(e);for(let a=0;a<e;a++)n[a]=t?t(a):a;return n},range(e,t,n){if(void 0===t&&(t=e,e=0),0===(n=void 0===n?e<t?1:-1:n))return[];const a=Math.max(Math.ceil((t-e)/(n||1)),0),i=new Array(a);for(let t=0;t<a;t++)i[t]=e+t*n;return i},uniqueId:(()=>{let e=0;return function(t=""){const n=++e;return t?`${t}${n}`:String(n)}})(),countBy(e,t){const n={};return this.each(e,e=>{const a=t(e);n[a]=(n[a]||0)+1}),n},each:(e,t)=>(Array.isArray(e)?e.forEach((n,a)=>t(n,a,e)):e&&"object"==typeof e&&Object.keys(e).forEach(n=>t(e[n],n,e)),e),forEach(e,t){return this.each(e,t)},eachRight(e,t){if(Array.isArray(e))for(let n=e.length-1;n>=0;n--)t(e[n],n,e);else if(e&&"object"==typeof e){Object.keys(e).reverse().forEach(n=>t(e[n],n,e))}return e},forEachRight(e,t){return this.eachRight(e,t)},every:(e,t)=>Array.isArray(e)?e.every(t):!e||"object"!=typeof e||Object.values(e).every(t),filter:(e,t)=>Array.isArray(e)?e.filter(t):e&&"object"==typeof e?Object.values(e).filter(t):[],find:(e,t)=>Array.isArray(e)?e.find(t):e&&"object"==typeof e?Object.values(e).find(t):void 0,findLast(e,t){if(Array.isArray(e)){for(let n=e.length-1;n>=0;n--)if(t(e[n],n,e))return e[n]}else if(e&&"object"==typeof e){return Object.values(e).reverse().find(t)}},flatMap(e,t){return this.map(e,t).flat(1)},flatMapDeep(e,t){return this.map(e,t).flat(1/0)},groupBy(e,t){const n={};return this.each(e,e=>{const a="function"==typeof t?t(e):e[t];n[a]||(n[a]=[]),n[a].push(e)}),n},includes:(e,t,n=0)=>"string"==typeof e||Array.isArray(e)?e.includes(t,n):!(!e||"object"!=typeof e)&&Object.values(e).includes(t),keyBy(e,t){const n={};return this.each(e,e=>{const a="function"==typeof t?t(e):e[t];n[a]=e}),n},map:(e,t)=>Array.isArray(e)?e.map(t):e&&"object"==typeof e?Object.entries(e).map(([n,a])=>t(a,n,e)):[],orderBy(e,t,n){const a=Array.isArray(e)?[...e]:Object.values(e),i=Array.isArray(t)?t:[t],s=Array.isArray(n)?n:[n||"asc"];return a.sort((e,t)=>{for(let n=0;n<i.length;n++){const a=i[n],o=s[n]||"asc",r="function"==typeof a?a(e):e[a],l="function"==typeof a?a(t):t[a];if(r<l)return"asc"===o?-1:1;if(r>l)return"asc"===o?1:-1}return 0})},partition(e,t){const n=[],a=[];return this.each(e,(i,s)=>{t(i,s,e)?n.push(i):a.push(i)}),[n,a]},reduce(e,t,n){if(Array.isArray(e))return void 0!==n?e.reduce(t,n):e.reduce(t);if(e&&"object"==typeof e){const a=Object.entries(e);let i=n,s=0;void 0===i&&a.length>0&&(i=a[0][1],s=1);for(let n=s;n<a.length;n++){const[s,o]=a[n];i=t(i,o,s,e)}return i}return n},reduceRight(e,t,n){if(Array.isArray(e))return void 0!==n?e.reduceRight(t,n):e.reduceRight(t);if(e&&"object"==typeof e){const a=Object.entries(e).reverse();let i=n,s=0;void 0===i&&a.length>0&&(i=a[0][1],s=1);for(let n=s;n<a.length;n++){const[s,o]=a[n];i=t(i,o,s,e)}return i}return n},reject(e,t){return this.filter(e,(e,n,a)=>!t(e,n,a))},sample(e){const t=Array.isArray(e)?e:Object.values(e||{});return t[Math.floor(Math.random()*t.length)]},sampleSize(e,t=1){return this.shuffle(Array.isArray(e)?[...e]:Object.values(e||{})).slice(0,t)},shuffle(e){const t=Array.isArray(e)?[...e]:Object.values(e||{});for(let e=t.length-1;e>0;e--){const n=Math.floor(Math.random()*(e+1));[t[e],t[n]]=[t[n],t[e]]}return t},size:e=>null==e?0:"string"==typeof e||Array.isArray(e)?e.length:"object"==typeof e?Object.keys(e).length:0,some:(e,t)=>Array.isArray(e)?e.some(t):!(!e||"object"!=typeof e)&&Object.values(e).some(t),sortBy:(e,t)=>(Array.isArray(e)?[...e]:Object.values(e)).sort((e,n)=>{const a="function"==typeof t?t(e):e[t],i="function"==typeof t?t(n):n[t];return a<i?-1:a>i?1:0}),after(e,t){let n=0;return function(...a){if(++n>=e)return t.apply(this,a)}},ary:(e,t=e.length)=>function(...n){return e.apply(this,n.slice(0,t))},before(e,t){let n,a=0;return function(...i){return++a<e&&(n=t.apply(this,i)),n}},bind:(e,t,...n)=>function(...a){return e.apply(t,[...n,...a])},curry:(e,t=e.length)=>function n(...a){return a.length>=t?e.apply(this,a):function(...e){return n.apply(this,[...a,...e])}},curryRight:(e,t=e.length)=>function n(...a){return a.length>=t?e.apply(this,a):function(...e){return n.apply(this,[...e,...a])}},debounce(e,t=0,n={}){let a,i,s,o,r,l=0;const d=n.leading||!1,c=!1!==n.trailing,p=n.maxWait;function m(t){const n=i,a=s;return i=s=void 0,l=t,o=e.apply(a,n),o}function h(e){const n=e-r;return void 0===r||n>=t||n<0||void 0!==p&&e-l>=p}function u(){const e=Date.now();if(h(e))return g(e);a=setTimeout(u,function(e){const n=e-r,a=e-l,i=t-n;return void 0!==p?Math.min(i,p-a):i}(e))}function g(e){return a=void 0,c&&i?m(e):(i=s=void 0,o)}function b(...e){const n=Date.now(),c=h(n);if(i=e,s=this,r=n,c){if(void 0===a)return function(e){return l=e,a=setTimeout(u,t),d?m(e):o}(r);if(void 0!==p)return a=setTimeout(u,t),m(r)}return void 0===a&&(a=setTimeout(u,t)),o}return b.cancel=function(){void 0!==a&&clearTimeout(a),l=0,i=r=s=a=void 0},b.flush=function(){return void 0===a?o:g(Date.now())},b},defer(e,...t){return setTimeout(()=>e.apply(this,t),1)},delay(e,t,...n){return setTimeout(()=>e.apply(this,n),t)},flip:e=>function(...t){return e.apply(this,t.reverse())},flow(...e){const t=e.length;return 0===t?function(e){return e}:1===t?e[0]:function(...n){let a=e[0].apply(this,n);for(let n=1;n<t;n++)a=e[n].call(this,a);return a}},compose(...e){return this.flow(...e.reverse())},memoize(e,t){const n=new Map,a=function(...a){const i=t?t.apply(this,a):a[0];if(n.has(i))return n.get(i);const s=e.apply(this,a);return n.set(i,s),s};return a.cache=n,a},negate:e=>function(...t){return!e.apply(this,t)},once(e){return this.before(2,e)},partial:(e,...t)=>function(...n){return e.apply(this,[...t,...n])},partialRight:(e,...t)=>function(...n){return e.apply(this,[...n,...t])},throttle(e,t=0,n={}){const a=!1!==n.leading,i=!1!==n.trailing;return this.debounce(e,t,{leading:a,trailing:i,maxWait:t})},unary(e){return this.ary(e,1)},wrap:(e,t)=>function(...n){return t.apply(this,[e,...n])},assign:(e,...t)=>Object.assign(e||{},...t),assignIn(e,...t){const n=e||{};return t.forEach(e=>{if(e)for(const t in e)n[t]=e[t]}),n},extend(e,...t){return this.assignIn(e,...t)},at(e,...t){return t.flat().map(t=>this.get(e,t))},clone:e=>null===e||"object"!=typeof e?e:Array.isArray(e)?[...e]:{...e},cloneDeep(e){if(null===e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(e=>this.cloneDeep(e));if(e instanceof Date)return new Date(e);if(e instanceof RegExp)return new RegExp(e);const t={};for(const n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=this.cloneDeep(e[n]));return t},defaults(e,...t){const n=e||{};return t.forEach(e=>{e&&Object.keys(e).forEach(t=>{void 0===n[t]&&(n[t]=e[t])})}),n},defaultsDeep(e,...t){const n=e||{};return t.forEach(e=>{e&&"object"==typeof e&&Object.keys(e).forEach(t=>{const a=n[t],i=e[t];void 0===a?n[t]=this.cloneDeep(i):a&&"object"==typeof a&&i&&"object"==typeof i&&!Array.isArray(a)&&!Array.isArray(i)&&this.defaultsDeep(a,i)})}),n},entries:e=>e?Object.entries(e):[],toPairs(e){return this.entries(e)},findKey(e,t){if(e)for(const n of Object.keys(e))if(t(e[n],n,e))return n},findLastKey(e,t){if(!e)return;const n=Object.keys(e).reverse();for(const a of n)if(t(e[a],a,e))return a},forIn(e,t){if(e)for(const n in e)if(!1===t(e[n],n,e))break;return e},forOwn(e,t){if(e)for(const n of Object.keys(e))if(!1===t(e[n],n,e))break;return e},get(e,t,n){if(!e)return n;const a=Array.isArray(t)?t:t.replace(/\[(\d+)]/g,".$1").split(".");let i=e;for(const e of a){if(null==i)return n;i=i[e]}return void 0===i?n:i},has(e,t){if(!e)return!1;const n=Array.isArray(t)?t:t.replace(/\[(\d+)]/g,".$1").split(".");let a=e;for(const e of n){if(!Object.prototype.hasOwnProperty.call(a,e))return!1;a=a[e]}return!0},invert(e){const t={};return e&&Object.entries(e).forEach(([e,n])=>{t[n]=e}),t},invertBy(e,t=e=>e){const n={};return e&&Object.entries(e).forEach(([e,a])=>{const i=t(a);n[i]||(n[i]=[]),n[i].push(e)}),n},keys:e=>e?Object.keys(e):[],keysIn(e){const t=[];for(const n in e)t.push(n);return t},mapKeys(e,t){const n={};return e&&Object.entries(e).forEach(([a,i])=>{n[t(i,a,e)]=i}),n},mapValues(e,t){const n={};return e&&Object.entries(e).forEach(([a,i])=>{n[a]=t(i,a,e)}),n},merge(e,...t){const n=e||{};return t.forEach(e=>{e&&"object"==typeof e&&Object.keys(e).forEach(t=>{const a=n[t],i=e[t];a&&"object"==typeof a&&i&&"object"==typeof i&&!Array.isArray(a)&&!Array.isArray(i)?this.merge(a,i):n[t]=i})}),n},omit(e,...t){if(!e)return{};const n=new Set(t.flat()),a={};return Object.keys(e).forEach(t=>{n.has(t)||(a[t]=e[t])}),a},omitBy(e,t){if(!e)return{};const n={};return Object.entries(e).forEach(([e,a])=>{t(a,e)||(n[e]=a)}),n},pick(e,...t){if(!e)return{};const n=new Set(t.flat()),a={};return n.forEach(t=>{t in e&&(a[t]=e[t])}),a},pickBy(e,t){if(!e)return{};const n={};return Object.entries(e).forEach(([e,a])=>{t(a,e)&&(n[e]=a)}),n},set(e,t,n){if(!e)return e;const a=Array.isArray(t)?t:t.replace(/\[(\d+)]/g,".$1").split(".");let i=e;for(let e=0;e<a.length-1;e++){const t=a[e],n=a[e+1];t in i&&null!==i[t]&&"object"==typeof i[t]||(i[t]=/^\d+$/.test(n)?[]:{}),i=i[t]}return i[a[a.length-1]]=n,e},unset(e,t){if(!e)return!0;const n=Array.isArray(t)?t:t.replace(/\[(\d+)]/g,".$1").split(".");let a=e;for(let e=0;e<n.length-1;e++){const t=n[e];if(!(t in a))return!0;a=a[t]}return delete a[n[n.length-1]]},setIfUndefined(e,t,n){return void 0===this.get(e,t)&&this.set(e,t,n),e},values:e=>e?Object.values(e):[],valuesIn(e){const t=[];for(const n in e)t.push(e[n]);return t},isArray:e=>Array.isArray(e),isBoolean:e=>"boolean"==typeof e||e instanceof Boolean,isDate:e=>e instanceof Date,isEmpty:e=>null==e||(Array.isArray(e)||"string"==typeof e?0===e.length:e instanceof Map||e instanceof Set?0===e.size:"object"!=typeof e||0===Object.keys(e).length),isEqual(e,t){if(e===t)return!0;if(null===e||null===t)return e===t;if(typeof e!=typeof t)return!1;if("object"!=typeof e)return!1;if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>this.isEqual(e,t[n]));if(Array.isArray(e)||Array.isArray(t))return!1;const n=Object.keys(e),a=Object.keys(t);return n.length===a.length&&n.every(n=>this.isEqual(e[n],t[n]))},isMatch(e,t){if(e===t)return!0;if(null==e||null==t)return!1;if("object"!=typeof e||"object"!=typeof t)return!1;const n=Object.keys(t);for(const a of n){const n=e[a],i=t[a];if("object"==typeof i&&null!==i){if(!this.isMatch(n,i))return!1}else if(n!==i)return!1}return!0},isFinite:e=>Number.isFinite(e),isFunction:e=>"function"==typeof e,isInteger:e=>Number.isInteger(e),isNaN:e=>Number.isNaN(e),isNil:e=>null==e,isNull:e=>null===e,isNumber:e=>"number"==typeof e||e instanceof Number,isObject:e=>null!==e&&"object"==typeof e,isPlainObject(e){if(null===e||"object"!=typeof e)return!1;const t=Object.getPrototypeOf(e);return null===t||t===Object.prototype},isRegExp:e=>e instanceof RegExp,isString:e=>"string"==typeof e||e instanceof String,isSymbol:e=>"symbol"==typeof e,isUndefined:e=>void 0===e,parseInt:(e,t)=>(void 0===t&&(t=/^0x/i.test(e)?16:10),null==e?NaN:"number"==typeof e?Math.trunc(e):(e=String(e).trim(),parseInt(e,t))),toNumber(e){if("number"==typeof e)return e;if("symbol"==typeof e)return NaN;if(this.isObject(e)){const t="function"==typeof e.valueOf?e.valueOf():e;e=this.isObject(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.trim();const t=/^0b[01]+$/i.test(e),n=/^0o[0-7]+$/i.test(e),a=/^[-+]0x[0-9a-f]+$/i.test(e);return t||n?parseInt(e.slice(2),t?2:8):a?NaN:+e},toInteger(e){const t=this.toNumber(e);return Number.isNaN(t)?0:0!==t&&Number.isFinite(t)?Math.trunc(t):t},toFinite(e){const t=17976931348623157e292;if(!e)return 0===e?e:0;const n=this.toNumber(e);return n===1/0?t:n===-1/0?-t:n==n?n:0},toSafeInteger(e){const t=9007199254740991,n=this.toInteger(e);return n<-9007199254740991?-9007199254740991:n>t?t:n},toString(e){if(null==e)return"";if("string"==typeof e)return e;if(Array.isArray(e))return e.map(e=>null==e?"":this.toString(e)).join(",");if("symbol"==typeof e)return e.toString();const t=String(e);return"0"===t&&1/e==-1/0?"-0":t},toArray(e){return e?this.isArray(e)?[...e]:"string"==typeof e?e.split(""):this.isObject(e)?"function"==typeof e[Symbol.iterator]?[...e]:Object.values(e):[]:[]},castArray(...e){if(!e.length)return[];const t=e[0];return this.isArray(t)?t:[t]},toLength(e){const t=4294967295,n=this.toInteger(e);return n<0?0:n>t?t:n},toPlainObject(e){const t={};for(const n in e)t[n]=e[n];return t},add:(e,t)=>e+t,ceil(e,t=0){const n=Math.pow(10,t);return Math.ceil(e*n)/n},divide:(e,t)=>e/t,floor(e,t=0){const n=Math.pow(10,t);return Math.floor(e*n)/n},max:e=>e&&e.length?Math.max(...e):void 0,maxBy(e,t){if(e&&e.length)return e.reduce((e,n)=>("function"==typeof t?t(n):n[t])>("function"==typeof t?t(e):e[t])?n:e)},mean(e){return e&&e.length?this.sum(e)/e.length:NaN},meanBy(e,t){return e&&e.length?this.sumBy(e,t)/e.length:NaN},min:e=>e&&e.length?Math.min(...e):void 0,minBy(e,t){if(e&&e.length)return e.reduce((e,n)=>("function"==typeof t?t(n):n[t])<("function"==typeof t?t(e):e[t])?n:e)},multiply:(e,t)=>e*t,round(e,t=0){const n=Math.pow(10,t);return Math.round(e*n)/n},subtract:(e,t)=>e-t,sum:e=>e?e.reduce((e,t)=>e+t,0):0,sumBy:(e,t)=>e?e.reduce((e,n)=>e+("function"==typeof t?t(n):n[t]),0):0,clamp:(e,t,n)=>(void 0===n&&(n=t,t=void 0),void 0!==t&&e<t?t:void 0!==n&&e>n?n:e),inRange:(e,t,n)=>(void 0===n&&(n=t,t=0),t>n&&([t,n]=[n,t]),e>=t&&e<n),random:(e=0,t=1,n)=>("boolean"==typeof e?(n=e,e=0,t=1):"boolean"==typeof t&&(n=t,t=e,e=0),e>t&&([e,t]=[t,e]),n||e%1!=0||t%1!=0?e+Math.random()*(t-e):e+Math.floor(Math.random()*(t-e+1))),camelCase:e=>e?e.replace(/[^a-zA-Z0-9]+(.)/g,(e,t)=>t.toUpperCase()).replace(/^[A-Z]/,e=>e.toLowerCase()):"",capitalize:e=>e?e.charAt(0).toUpperCase()+e.slice(1).toLowerCase():"",endsWith:(e,t,n)=>!!e&&(void 0!==n?e.slice(0,n).endsWith(t):e.endsWith(t)),escape(e){if(!e)return"";const t={"&":"&","<":"<",">":">",'"':""","'":"'"};return e.replace(/[&<>"']/g,e=>t[e])},kebabCase:e=>e?e.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase():"",lowerCase(e){return e?this.words(e).join(" ").toLowerCase():""},lowerFirst:e=>e?e.charAt(0).toLowerCase()+e.slice(1):"",pad(e="",t=0,n=" "){const a=e.length;if(a>=t)return e;const i=t-a,s=Math.floor(i/2),o=i-s;return n.repeat(Math.ceil(s/n.length)).slice(0,s)+e+n.repeat(Math.ceil(o/n.length)).slice(0,o)},padEnd(e="",t=0,n=" "){const a=e.length;if(a>=t)return e;const i=t-a;return e+n.repeat(Math.ceil(i/n.length)).slice(0,i)},padStart(e="",t=0,n=" "){const a=e.length;if(a>=t)return e;const i=t-a;return n.repeat(Math.ceil(i/n.length)).slice(0,i)+e},repeat:(e="",t=1)=>e.repeat(Math.max(0,Math.floor(t))),replace:(e="",t,n)=>e.replace(t,n),snakeCase(e){return e?this.words(e).join("_").toLowerCase():""},split:(e="",t,n)=>e.split(t,n),startCase(e){return e?this.words(e).map(e=>this.capitalize(e)).join(" "):""},startsWith:(e,t,n=0)=>!!e&&e.startsWith(t,n),toLower:e=>e?e.toLowerCase():"",toUpper:e=>e?e.toUpperCase():"",trim(e="",t){if(!t)return e.trim();const n=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return e.replace(new RegExp(`^[${n}]+|[${n}]+$`,"g"),"")},trimEnd(e="",t){if(!t)return e.trimEnd();const n=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return e.replace(new RegExp(`[${n}]+$`,"g"),"")},trimStart(e="",t){if(!t)return e.trimStart();const n=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return e.replace(new RegExp(`^[${n}]+`,"g"),"")},truncate(e="",t={}){const n=t.length||30,a=t.omission||"...",i=t.separator;if(e.length<=n)return e;let s=n-a.length;if(s<1)return a;let o=e.slice(0,s);if(i){const e="string"==typeof i?o.lastIndexOf(i):o.search(new RegExp(i.source+"(?!.*"+i.source+")"));e>-1&&(o=o.slice(0,e))}return o+a},unescape(e){if(!e)return"";const t={"&":"&","<":"<",">":">",""":'"',"'":"'"};return e.replace(/&(?:amp|lt|gt|quot|#39);/g,e=>t[e])},upperCase(e){return e?this.words(e).join(" ").toUpperCase():""},upperFirst:e=>e?e.charAt(0).toUpperCase()+e.slice(1):"",words:(e="",t)=>t?e.match(t)||[]:(e=e.replace(/([a-z])([A-Z])/g,"$1 $2")).match(/[a-zA-Z0-9]+/g)||[],sprintf(e,...t){if(!e)return"";let n=0;return e.replace(/%(?:(\d+)\$)?([+-])?(\d+)?(?:\.(\d+))?([sdifojx%])/g,(e,a,i,s,o,r)=>{if("%"===r)return"%";const l=a?parseInt(a,10)-1:n++,d=t[l];if(void 0===d)return e;if(null===d)return"null";let c;switch(r){case"s":default:c=String(d);break;case"d":case"i":c=String(parseInt(d,10));break;case"f":const e=parseFloat(d);c=void 0!==o?e.toFixed(parseInt(o,10)):String(e);break;case"o":c=Object.prototype.toString.call(d);break;case"j":try{c=JSON.stringify(d)}catch(e){c="[Circular]"}break;case"x":c=parseInt(d,10).toString(16)}if(s){const e=parseInt(s,10),t="0"===i?"0":" ";c="-"===i?c.padEnd(e," "):c.padStart(e,t)}if("+"===i&&("d"===r||"i"===r||"f"===r)){parseFloat(c)>=0&&!c.startsWith("+")&&(c="+"+c)}return c})},format(e,...t){return this.sprintf(e,...t)},template(e,t={}){const{partials:n={},helpers:a={}}=t,i=e=>null==e?"":String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),s=(e,t)=>"."===t?e:t.startsWith("@")?e[t]:t.split(".").reduce((e,t)=>e&&void 0!==e[t]?e[t]:"",e),o=(e,t,r=null)=>{let l=e;return l=l.replace(/\{\{#with\s+([^}]+)\}\}([\s\S]*?)\{\{\/with\}\}/g,(e,n,a)=>{const i=s(t,n.trim());return i&&"object"==typeof i?o(a,i,t):""}),l=l.replace(/\{\{#each\s+([^}]+)\}\}([\s\S]*?)\{\{\/each\}\}/g,(e,n,a)=>{const i=s(t,n.trim());return Array.isArray(i)?i.map((e,n)=>{const s="object"==typeof e?{...e,"@index":n,"@first":0===n,"@last":n===i.length-1}:{".":e,"@index":n,"@first":0===n,"@last":n===i.length-1};return o(a,s,t)}).join(""):""}),l=l.replace(/\{\{#if\s+([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g,(e,n,a,i="")=>{const l=s(t,n.trim()),d=Array.isArray(l)?l.length>0:Boolean(l);return o(d?a:i,t,r)}),l=l.replace(/\{\{#unless\s+([^}]+)\}\}([\s\S]*?)\{\{\/unless\}\}/g,(e,n,a)=>{const i=s(t,n.trim());return(Array.isArray(i)?0===i.length:!i)?o(a,t,r):""}),l=l.replace(/\{\{>\s*([^}]+)\}\}/g,(e,a)=>{const i=n[a.trim()];return i?o(i,t,r):""}),l=l.replace(/\{\{\{([^}]+)\}\}\}/g,(e,n)=>{const a=s(t,n.trim());return null!=a?String(a):""}),l=l.replace(/\{\{([^#/>][^}]*)\}\}/g,(e,n)=>{const o=n.trim(),r=o.match(/^(\w+)\s+(.+)$/);if(r&&a[r[1]]){const e=r[2].split(/\s+/).map(e=>/^["'].*["']$/.test(e)?e.slice(1,-1):s(t,e));return i(a[r[1]](...e))}const l=s(t,o);return i(l)}),l};return(t={})=>o(e,t)},render(e,t,n={}){return this.template(e,n)(t)},async copyToClipboard(e){if(navigator.clipboard?.writeText)try{return await navigator.clipboard.writeText(e),!0}catch(e){}const t=document.createElement("textarea");t.value=e,t.style.cssText="position:fixed;opacity:0;pointer-events:none",document.body.appendChild(t),t.select();try{return document.execCommand("copy")}catch(e){return!1}finally{document.body.removeChild(t)}},escapeHtml:e=>null==e?"":String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),chain(e){const t={_value:e,value(){return this._value}};["chunk","compact","concat","difference","drop","dropRight","fill","findIndex","findLastIndex","flatten","flattenDeep","flattenDepth","fromPairs","head","indexOf","initial","intersection","join","last","lastIndexOf","nth","pull","pullAll","pullAt","remove","reverse","slice","sortedIndex","sortedUniq","tail","take","takeRight","union","uniq","uniqBy","unzip","without","xor","zip","countBy","each","every","filter","find","findLast","flatMap","groupBy","includes","invokeMap","keyBy","map","orderBy","partition","reduce","reduceRight","reject","sample","sampleSize","shuffle","size","some","sortBy","assign","assignIn","at","defaults","entries","extend","findKey","findLastKey","forIn","forOwn","functions","get","has","invert","invertBy","invoke","keys","mapKeys","mapValues","merge","omit","omitBy","pick","pickBy","result","set","toPairs","transform","unset","update","values","camelCase","capitalize","deburr","endsWith","escape","escapeRegExp","kebabCase","lowerCase","lowerFirst","pad","padEnd","padStart","parseInt","repeat","replace","snakeCase","split","startCase","startsWith","toLower","toUpper","trim","trimEnd","trimStart","truncate","unescape","upperCase","upperFirst","words"].forEach(e=>{"function"==typeof this[e]&&(t[e]=function(...t){return this._value=l[e](this._value,...t),this})});return["sum","mean","min","max","toArray","toJSON","toString"].forEach(e=>{"function"==typeof this[e]&&(t[e]=function(...t){return l[e](this._value,...t)})}),t}},d={"--dm-primary":{category:"colours",subCategory:"brand",type:"color",label:"Primary",defaultLight:"#6495ED",defaultDark:"#6ea8fe"},"--dm-primary-hover":{category:"colours",subCategory:"brand",type:"color",label:"Primary Hover",defaultLight:"#5280d8",defaultDark:"#8bb9fe"},"--dm-primary-active":{category:"colours",subCategory:"brand",type:"color",label:"Primary Active",defaultLight:"#4169c0",defaultDark:"#a8cafe"},"--dm-secondary":{category:"colours",subCategory:"brand",type:"color",label:"Secondary",defaultLight:"#6c757d",defaultDark:"#adb5bd"},"--dm-secondary-hover":{category:"colours",subCategory:"brand",type:"color",label:"Secondary Hover",defaultLight:"#5c636a",defaultDark:"#b1b8bf"},"--dm-success":{category:"colours",subCategory:"status",type:"color",label:"Success",defaultLight:"#198754",defaultDark:"#75b798"},"--dm-success-hover":{category:"colours",subCategory:"status",type:"color",label:"Success Hover",defaultLight:"#157347",defaultDark:"#8cc5a7"},"--dm-danger":{category:"colours",subCategory:"status",type:"color",label:"Danger",defaultLight:"#dc3545",defaultDark:"#ea868f"},"--dm-danger-hover":{category:"colours",subCategory:"status",type:"color",label:"Danger Hover",defaultLight:"#bb2d3b",defaultDark:"#ee9aa1"},"--dm-warning":{category:"colours",subCategory:"status",type:"color",label:"Warning",defaultLight:"#ffc107",defaultDark:"#ffda6a"},"--dm-warning-hover":{category:"colours",subCategory:"status",type:"color",label:"Warning Hover",defaultLight:"#ffca2c",defaultDark:"#ffe083"},"--dm-info":{category:"colours",subCategory:"status",type:"color",label:"Info",defaultLight:"#0dcaf0",defaultDark:"#6edff6"},"--dm-info-hover":{category:"colours",subCategory:"status",type:"color",label:"Info Hover",defaultLight:"#31d2f2",defaultDark:"#89e5f8"},"--dm-background":{category:"colours",subCategory:"backgrounds",type:"color",label:"Background",defaultLight:"#ffffff",defaultDark:"#121212"},"--dm-background-alt":{category:"colours",subCategory:"backgrounds",type:"color",label:"Background Alt",defaultLight:"#f8f9fa",defaultDark:"#1e1e1e"},"--dm-surface":{category:"colours",subCategory:"backgrounds",type:"color",label:"Surface",defaultLight:"#ffffff",defaultDark:"#1e1e1e"},"--dm-surface-raised":{category:"colours",subCategory:"backgrounds",type:"color",label:"Surface Raised",defaultLight:"#ffffff",defaultDark:"#2d2d2d"},"--dm-text":{category:"colours",subCategory:"text",type:"color",label:"Text",defaultLight:"#212529",defaultDark:"#e9ecef"},"--dm-text-secondary":{category:"colours",subCategory:"text",type:"color",label:"Text Secondary",defaultLight:"#495057",defaultDark:"#adb5bd"},"--dm-text-muted":{category:"colours",subCategory:"text",type:"color",label:"Text Muted",defaultLight:"#6c757d",defaultDark:"#868e96"},"--dm-border":{category:"colours",subCategory:"borders",type:"color",label:"Border",defaultLight:"#dee2e6",defaultDark:"#3d3d3d"},"--dm-border-light":{category:"colours",subCategory:"borders",type:"color",label:"Border Light",defaultLight:"#e9ecef",defaultDark:"#2d2d2d"},"--dm-divider":{category:"colours",subCategory:"borders",type:"color",label:"Divider",defaultLight:"#e9ecef",defaultDark:"#3d3d3d"},"--dm-font-sans":{category:"typography",subCategory:"families",type:"select",label:"Sans-serif Font",default:"system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",options:[{value:"system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",label:"System UI"},{value:"'Inter', sans-serif",label:"Inter"},{value:"'Open Sans', sans-serif",label:"Open Sans"},{value:"'Roboto', sans-serif",label:"Roboto"},{value:"'Lato', sans-serif",label:"Lato"},{value:"'Poppins', sans-serif",label:"Poppins"}]},"--dm-font-mono":{category:"typography",subCategory:"families",type:"select",label:"Monospace Font",default:"'SF Mono', Monaco, 'Cascadia Code', Consolas, monospace",options:[{value:"'SF Mono', Monaco, 'Cascadia Code', Consolas, monospace",label:"SF Mono"},{value:"'Fira Code', monospace",label:"Fira Code"},{value:"'JetBrains Mono', monospace",label:"JetBrains Mono"},{value:"'Source Code Pro', monospace",label:"Source Code Pro"}]},"--dm-text-xs":{category:"typography",subCategory:"sizes",type:"size",label:"Extra Small",default:"0.75rem",unit:"rem",min:.5,max:1,step:.0625},"--dm-text-sm":{category:"typography",subCategory:"sizes",type:"size",label:"Small",default:"0.875rem",unit:"rem",min:.625,max:1.25,step:.0625},"--dm-text-base":{category:"typography",subCategory:"sizes",type:"size",label:"Base",default:"1rem",unit:"rem",min:.75,max:1.5,step:.0625},"--dm-text-lg":{category:"typography",subCategory:"sizes",type:"size",label:"Large",default:"1.125rem",unit:"rem",min:.875,max:1.75,step:.0625},"--dm-text-xl":{category:"typography",subCategory:"sizes",type:"size",label:"Extra Large",default:"1.25rem",unit:"rem",min:1,max:2,step:.0625},"--dm-text-2xl":{category:"typography",subCategory:"sizes",type:"size",label:"2XL",default:"1.5rem",unit:"rem",min:1.25,max:2.5,step:.125},"--dm-space-1":{category:"spacing",subCategory:"scale",type:"size",label:"Space 1 (4px)",default:"0.25rem",unit:"rem",min:0,max:.5,step:.0625},"--dm-space-2":{category:"spacing",subCategory:"scale",type:"size",label:"Space 2 (8px)",default:"0.5rem",unit:"rem",min:.25,max:1,step:.0625},"--dm-space-3":{category:"spacing",subCategory:"scale",type:"size",label:"Space 3 (12px)",default:"0.75rem",unit:"rem",min:.5,max:1.25,step:.0625},"--dm-space-4":{category:"spacing",subCategory:"scale",type:"size",label:"Space 4 (16px)",default:"1rem",unit:"rem",min:.5,max:2,step:.125},"--dm-space-6":{category:"spacing",subCategory:"scale",type:"size",label:"Space 6 (24px)",default:"1.5rem",unit:"rem",min:1,max:3,step:.125},"--dm-space-8":{category:"spacing",subCategory:"scale",type:"size",label:"Space 8 (32px)",default:"2rem",unit:"rem",min:1,max:4,step:.25},"--dm-radius-sm":{category:"borders",subCategory:"radius",type:"size",label:"Small Radius",default:"0.125rem",unit:"rem",min:0,max:.5,step:.0625},"--dm-radius-md":{category:"borders",subCategory:"radius",type:"size",label:"Medium Radius",default:"0.25rem",unit:"rem",min:0,max:.75,step:.0625},"--dm-radius-lg":{category:"borders",subCategory:"radius",type:"size",label:"Large Radius",default:"0.5rem",unit:"rem",min:0,max:1,step:.0625},"--dm-radius-xl":{category:"borders",subCategory:"radius",type:"size",label:"XL Radius",default:"0.75rem",unit:"rem",min:0,max:1.5,step:.125},"--dm-radius-2xl":{category:"borders",subCategory:"radius",type:"size",label:"2XL Radius",default:"1rem",unit:"rem",min:0,max:2,step:.125},"--dm-transition-fast":{category:"transitions",subCategory:"durations",type:"transition",label:"Fast",default:"150ms ease",min:50,max:300,step:25},"--dm-transition-normal":{category:"transitions",subCategory:"durations",type:"transition",label:"Normal",default:"200ms ease",min:100,max:400,step:25},"--dm-transition-slow":{category:"transitions",subCategory:"durations",type:"transition",label:"Slow",default:"300ms ease",min:200,max:600,step:25},"--dm-disabled-opacity":{category:"states",subCategory:"interactive",type:"opacity",label:"Disabled Opacity",default:"0.65",min:.3,max:1,step:.05}},c={colours:{name:"Colours",icon:"palette",subCategories:{brand:"Brand",status:"Status",backgrounds:"Backgrounds",text:"Text",borders:"Borders"}},typography:{name:"Typography",icon:"type",subCategories:{families:"Font Families",sizes:"Font Sizes"}},spacing:{name:"Spacing",icon:"maximize",subCategories:{scale:"Spacing Scale"}},borders:{name:"Borders & Radius",icon:"square",subCategories:{radius:"Border Radius"}},transitions:{name:"Transitions",icon:"zap",subCategories:{durations:"Durations"}},states:{name:"Interactive States",icon:"mouse-pointer",subCategories:{interactive:"States"}}};class p{static defaults={baseTheme:"charcoal-dark",sections:["colours","typography","spacing","borders","transitions","states"],livePreview:!0,showPreviewPanel:!0,onChange:null,onApply:null,onExport:null,onReset:null};constructor(e,t={}){this.element="string"==typeof e?document.querySelector(e):e,this.options={...p.defaults,...t},this._changes={},this._previewStyle=null,this._eventHandlers=[],this._accordionInstance=null,this.element&&this._init()}_init(){this._createPreviewStyle(),this._render(),"undefined"!=typeof Domma&&Domma.elements&&(this._accordionInstance=Domma.elements.accordion("#theme-roller-accordion",{multiExpand:!0,activeIndex:0})),this._bindEvents(),this.options.baseTheme&&o.set(this.options.baseTheme)}_createPreviewStyle(){this._previewStyle=document.getElementById("dm-theme-roller-preview"),this._previewStyle||(this._previewStyle=document.createElement("style"),this._previewStyle.id="dm-theme-roller-preview",document.head.appendChild(this._previewStyle))}_render(){const e=o.get();let t=`\n <div class="dm-theme-roller">\n <div class="dm-theme-roller-header">\n <h3 class="dm-theme-roller-title">Theme Roller</h3>\n <div class="dm-theme-roller-controls">\n <label for="theme-select" class="dm-theme-select-label">Theme:</label>\n <select id="theme-select" class="dm-theme-select form-select">\n <optgroup label="Ocean">\n <option value="ocean-light" ${"ocean-light"===e?"selected":""}>Ocean Light ☀️</option>\n <option value="ocean-dark" ${"ocean-dark"===e?"selected":""}>Ocean Dark 🌙</option>\n </optgroup>\n <optgroup label="Forest">\n <option value="forest-light" ${"forest-light"===e?"selected":""}>Forest Light ☀️</option>\n <option value="forest-dark" ${"forest-dark"===e?"selected":""}>Forest Dark 🌙</option>\n </optgroup>\n <optgroup label="Sunset">\n <option value="sunset-light" ${"sunset-light"===e?"selected":""}>Sunset Light ☀️</option>\n <option value="sunset-dark" ${"sunset-dark"===e?"selected":""}>Sunset Dark 🌙</option>\n </optgroup>\n <optgroup label="Royal">\n <option value="royal-light" ${"royal-light"===e?"selected":""}>Royal Light ☀️</option>\n <option value="royal-dark" ${"royal-dark"===e?"selected":""}>Royal Dark 🌙</option>\n </optgroup>\n <optgroup label="Lemon">\n <option value="lemon-light" ${"lemon-light"===e?"selected":""}>Lemon Light ☀️</option>\n <option value="lemon-dark" ${"lemon-dark"===e?"selected":""}>Lemon Dark 🌙</option>\n </optgroup>\n <optgroup label="Silver">\n <option value="silver-light" ${"silver-light"===e?"selected":""}>Silver Light ☀️</option>\n <option value="silver-dark" ${"silver-dark"===e?"selected":""}>Silver Dark 🌙</option>\n </optgroup>\n <optgroup label="Charcoal">\n <option value="charcoal-light" ${"charcoal-light"===e?"selected":""}>Charcoal Light ☀️</option>\n <option value="charcoal-dark" ${"charcoal-dark"===e?"selected":""}>Charcoal Dark 🌙</option>\n </optgroup>\n <optgroup label="Christmas">\n <option value="christmas-light" ${"christmas-light"===e?"selected":""}>Christmas Light ☀️</option>\n <option value="christmas-dark" ${"christmas-dark"===e?"selected":""}>Christmas Dark 🌙</option>\n </optgroup>\n <optgroup label="Unicorn">\n <option value="unicorn-light" ${"unicorn-light"===e?"selected":""}>Unicorn Light ☀️</option>\n <option value="unicorn-dark" ${"unicorn-dark"===e?"selected":""}>Unicorn Dark 🌙</option>\n </optgroup>\n <optgroup label="Dreamy">\n <option value="dreamy-light" ${"dreamy-light"===e?"selected":""}>Dreamy Light ☀️</option>\n <option value="dreamy-dark" ${"dreamy-dark"===e?"selected":""}>Dreamy Dark 🌙</option>\n </optgroup>\n <optgroup label="Grayve">\n <option value="grayve-light" ${"grayve-light"===e?"selected":""}>Grayve Light ☀️</option>\n <option value="grayve-dark" ${"grayve-dark"===e?"selected":""}>Grayve Dark 🌙</option>\n </optgroup>\n </select>\n </div>\n </div>\n `;t+='<div class="dm-theme-roller-sections accordion" id="theme-roller-accordion">';for(const e of this.options.sections){const n=c[e];n&&(t+=`\n <div class="accordion-item" data-category="${e}">\n <div class="accordion-header">\n <span data-icon="${n.icon}" data-icon-size="18"></span>\n ${n.name}\n <span class="accordion-icon">▼</span>\n </div>\n <div class="accordion-body">\n <div class="accordion-content">\n ${this._renderCategoryContent(e,n)}\n </div>\n </div>\n </div>\n `)}t+="</div>",this.options.showPreviewPanel&&(t+=this._renderPreviewPanel()),t+='\n <div class="dm-theme-roller-actions">\n <button class="dm-btn dm-btn-secondary" data-action="reset">\n <span data-icon="refresh-cw" data-icon-size="16"></span>\n Reset\n </button>\n <button class="dm-btn dm-btn-secondary" data-action="save">\n <span data-icon="save" data-icon-size="16"></span>\n Save\n </button>\n <button class="dm-btn dm-btn-secondary" data-action="copy">\n <span data-icon="copy" data-icon-size="16"></span>\n Copy CSS\n </button>\n <button class="dm-btn dm-btn-primary" data-action="download">\n <span data-icon="download" data-icon-size="16"></span>\n Download\n </button>\n </div>\n ',t+="</div>",this.element.innerHTML=t,this.element.querySelectorAll('input[type="color"]').forEach(e=>{const t=e.getAttribute("value");t&&(e.value=t)}),"undefined"!=typeof Domma&&Domma.icons&&Domma.icons.scan(this.element)}_renderCategoryContent(e,t){let n="";const a=o.isDark();for(const[i,s]of Object.entries(t.subCategories)){const t=Object.entries(d).filter(([,t])=>t.category===e&&t.subCategory===i);if(0!==t.length){n+=`<div class="dm-var-group"><h4 class="dm-var-group-title">${s}</h4><div class="dm-var-grid">`;for(const[e,i]of t){const t=a?i.defaultDark||i.default:i.defaultLight||i.default;let s=getComputedStyle(document.body).getPropertyValue(e).trim();if("color"===i.type&&console.log(`[ThemeRoller] Reading ${e}: "${s}"`),"color"===i.type&&s.startsWith("rgb")){const e=s.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);if(e){s=`#${parseInt(e[1]).toString(16).padStart(2,"0")}${parseInt(e[2]).toString(16).padStart(2,"0")}${parseInt(e[3]).toString(16).padStart(2,"0")}`.toUpperCase()}}const o=this._changes[e]||s||t;n+=this._renderInput(e,i,o)}n+="</div></div>"}}return n}_renderInput(e,t,n){const a=`tr-${e.replace(/--dm-/g,"").replace(/-/g,"_")}`;let i="";switch(t.type){case"color":i=`\n <div class="dm-var-item dm-var-color">\n <label for="${a}">${t.label}</label>\n <div class="dm-color-input-wrapper">\n <input type="color" id="${a}" data-var="${e}" value="${n}">\n <input type="text" class="dm-color-text" data-var="${e}" value="${n}" maxlength="7">\n </div>\n </div>\n `;break;case"size":const s=parseFloat(n);i=`\n <div class="dm-var-item dm-var-size">\n <label for="${a}">${t.label}</label>\n <div class="dm-size-input-wrapper">\n <input type="range" id="${a}" data-var="${e}"\n min="${t.min}" max="${t.max}" step="${t.step}"\n value="${s}">\n <span class="dm-size-value">${n}</span>\n </div>\n </div>\n `;break;case"select":i=`\n <div class="dm-var-item dm-var-select">\n <label for="${a}">${t.label}</label>\n <select id="${a}" data-var="${e}">\n ${t.options.map(e=>`\n <option value="${e.value}" ${e.value===n?"selected":""}>\n ${e.label}\n </option>\n `).join("")}\n </select>\n </div>\n `;break;case"transition":const o=parseInt(n);i=`\n <div class="dm-var-item dm-var-transition">\n <label for="${a}">${t.label}</label>\n <div class="dm-size-input-wrapper">\n <input type="range" id="${a}" data-var="${e}"\n min="${t.min}" max="${t.max}" step="${t.step}"\n value="${o}">\n <span class="dm-size-value">${o}ms</span>\n </div>\n </div>\n `;break;case"opacity":const r=parseFloat(n);i=`\n <div class="dm-var-item dm-var-opacity">\n <label for="${a}">${t.label}</label>\n <div class="dm-size-input-wrapper">\n <input type="range" id="${a}" data-var="${e}"\n min="${t.min}" max="${t.max}" step="${t.step}"\n value="${r}">\n <span class="dm-size-value">${r}</span>\n </div>\n </div>\n `;break;default:i=`\n <div class="dm-var-item">\n <label for="${a}">${t.label}</label>\n <input type="text" id="${a}" data-var="${e}" value="${n}">\n </div>\n `}return i}_renderPreviewPanel(){return'\n <div class="dm-theme-roller-preview">\n <h4>Live Preview</h4>\n <div class="dm-preview-content">\n <div class="dm-preview-buttons">\n <button class="btn btn-primary">Primary</button>\n <button class="btn btn-secondary">Secondary</button>\n <button class="btn btn-success">Success</button>\n <button class="btn btn-danger">Danger</button>\n <button class="btn btn-warning">Warning</button>\n <button class="btn btn-info">Info</button>\n </div>\n <div class="dm-preview-card">\n <h5>Sample Card</h5>\n <p>This card demonstrates the current theme settings including colours, typography, and spacing.</p>\n </div>\n <div class="dm-preview-input">\n <input type="text" placeholder="Sample input field">\n </div>\n <div class="dm-preview-alerts">\n <div class="dm-alert dm-alert-success">Success message</div>\n <div class="dm-alert dm-alert-warning">Warning message</div>\n <div class="dm-alert dm-alert-danger">Error message</div>\n <div class="dm-alert dm-alert-info">Info message</div>\n </div>\n </div>\n </div>\n '}_bindEvents(){const e={"#theme-select":{on:"change",call:(e,t)=>{const n=t.value;console.log("[ThemeRoller] Theme changed to:",n),o.set(n),this._refreshInputs()}},'input[type="color"]':{on:"input",call:(e,t)=>{const n=t.dataset.var;this.set(n,t.value);const a=this.element.querySelector(`.dm-color-text[data-var="${n}"]`);a&&(a.value=t.value)}},".dm-color-text":{on:"change",call:(e,t)=>{const n=t.dataset.var,a=t.value;if(/^#[0-9A-Fa-f]{6}$/.test(a)){this.set(n,a);const e=this.element.querySelector(`input[type="color"][data-var="${n}"]`);e&&(e.value=a)}}},'input[type="range"]':{on:"input",call:(e,t)=>{const n=t.dataset.var,a=d[n];let i=t.value,s=i;"size"===a.type?(i=`${i}${a.unit}`,s=i):"transition"===a.type&&(s=`${i}ms`,i=`${i}ms ease`),this.set(n,i);const o=t.parentElement.querySelector(".dm-size-value");o&&(o.textContent=s)}},"select[data-var]":{on:"change",call:(e,t)=>{const n=t.dataset.var;this.set(n,t.value)}},"[data-action]":{on:"click",call:async(e,t)=>{switch(t.dataset.action){case"reset":this.reset();break;case"save":this.saveToStorage();break;case"copy":await this.copyToClipboard();break;case"download":this.download()}}}};console.log("[ThemeRoller] Setting up event bindings (declarative style)"),Object.keys(e).forEach(t=>{const n=this.element.querySelectorAll(t),{on:a,call:i}=e[t];n.forEach(e=>{e.addEventListener(a,t=>i(t,e))})})}_addEventListener(e,t,n){e.addEventListener(t,n),this._eventHandlers.push({element:e,event:t,handler:n})}_updateThemeDropdown(){const e=o.get(),t=this.element.querySelector("#theme-select");t&&(t.value=e)}_refreshInputs(){console.log("[ThemeRoller] _refreshInputs starting"),this._changes={},this._updatePreview(),console.log("[ThemeRoller] About to re-render"),this._render(),console.log("[ThemeRoller] Re-render completed"),"undefined"!=typeof Domma&&Domma.elements&&this._accordionInstance&&(console.log("[ThemeRoller] Destroying old accordion instance"),this._accordionInstance.destroy()),"undefined"!=typeof Domma&&Domma.elements&&(console.log("[ThemeRoller] Creating new accordion instance"),this._accordionInstance=Domma.elements.accordion("#theme-roller-accordion",{multiExpand:!0,activeIndex:0})),console.log("[ThemeRoller] About to rebind events"),this._bindEvents(),console.log("[ThemeRoller] _refreshInputs complete")}_updatePreview(){if(!this.options.livePreview||!this._previewStyle)return;if(0===Object.keys(this._changes).length)return void(this._previewStyle.textContent="");let e="body, :root {\n";for(const[t,n]of Object.entries(this._changes))e+=` ${t}: ${n} !important;\n`;e+="}",this._previewStyle.textContent=e}_capitalize(e){return e.charAt(0).toUpperCase()+e.slice(1)}get(e){return this._changes[e]||null}set(e,t){return this._changes[e]=t,this._updatePreview(),this.options.onChange&&this.options.onChange(e,t),this}getAll(){return{...this._changes}}setAll(e){for(const[t,n]of Object.entries(e))this._changes[t]=n;return this._updatePreview(),this}reset(){return this._changes={},this._updatePreview(),this._refreshInputs(),this.options.onReset&&this.options.onReset(),this._showToast("Theme reset to defaults"),this}loadPreset(e){return console.warn("[ThemeRoller] loadPreset() is deprecated. Use the theme dropdown instead."),e||(e="charcoal-dark"),o.isDisabled()&&o.enable(),o.set(e),document.body.offsetHeight,setTimeout(()=>{this._refreshInputsDelayed()},50),this._changes={},this._updatePreview(),this._updateThemeDropdown(),this}_refreshInputsDelayed(){console.log("[ThemeRoller] _refreshInputsDelayed called"),this._changes={},this._updatePreview(),this._refreshInputs(),this._showToast("Theme preset loaded")}exportCSS(e={}){const{themeName:t="custom",includeHeader:n=!0,minify:a=!1}=e;if(0===Object.keys(this._changes).length)return"";const i=a?"":"\n",s=a?"":" ";let r="";n&&(r+=`/**${i}`,r+=` * Custom Domma Theme${i}`,r+=` * Generated: ${(new Date).toISOString().split("T")[0]}${i}`,r+=` * Base: ${o.get()}${i}`,r+=` */${i}${i}`),r+=`.dm-theme-${t} {${i}`;for(const[e,t]of Object.entries(this._changes))r+=`${s}${e}: ${t};${i}`;return r+=`}${i}`,this.options.onExport&&this.options.onExport(r),r}download(e="custom-theme"){const t=this.exportCSS();if(!t)return this._showToast("No changes to export","warning"),this;const n=new Blob([t],{type:"text/css"}),a=URL.createObjectURL(n),i=document.createElement("a");return i.href=a,i.download=`${e}.css`,document.body.appendChild(i),i.click(),document.body.removeChild(i),URL.revokeObjectURL(a),this._showToast("Theme downloaded successfully"),this}async copyToClipboard(){const e=this.exportCSS();return e?(await l.copyToClipboard(e),this._showToast("CSS copied to clipboard"),this):(this._showToast("No changes to copy","warning"),this)}saveToStorage(){return r.set("theme-roller-custom",{theme:o.get(),changes:this._changes}),this._showToast("Theme saved to browser"),this}loadFromStorage(){const e=r.get("theme-roller-custom");return e&&(e.theme&&o.set(e.theme),e.changes&&this.setAll(e.changes),this._updateThemeDropdown(),this._showToast("Theme loaded from browser")),this}_showToast(e,t="success"){"undefined"!=typeof Domma&&Domma.elements&&Domma.elements.toast&&Domma.elements.toast[t](e,{position:"bottom-center",duration:2e3})}apply(){return this.options.onApply&&this.options.onApply(this._changes),this._showToast("Theme applied"),this}destroy(){for(const{element:e,event:t,handler:n}of this._eventHandlers)e.removeEventListener(t,n);this._eventHandlers=[],this._previewStyle&&this._previewStyle.remove(),this._accordionInstance&&this._accordionInstance.destroy(),this.element&&(this.element.innerHTML="")}}const m={navbar:{name:"Navigation Bar",icon:"menu",category:"headers",description:"Top navigation bar with logo and menu links",defaults:{brandText:"My Site",brandImage:"",style:"light",sticky:!1,links:[{text:"Home",url:"#"},{text:"About",url:"#"},{text:"Services",url:"#"},{text:"Contact",url:"#"}],showCta:!0,ctaText:"Get Started",ctaUrl:"#"},editableFields:[{key:"brandText",type:"text",label:"Brand Text"},{key:"brandImage",type:"text",label:"Logo URL"},{key:"style",type:"select",label:"Style",options:["light","dark","transparent"]},{key:"sticky",type:"toggle",label:"Sticky"},{key:"links",type:"links",label:"Menu Links"},{key:"showCta",type:"toggle",label:"Show CTA Button"},{key:"ctaText",type:"text",label:"CTA Text",showWhen:{showCta:!0}},{key:"ctaUrl",type:"text",label:"CTA URL",showWhen:{showCta:!0}}],template:e=>`<nav class="navbar ${"dark"===e.style?"navbar-dark":"transparent"===e.style?"navbar-transparent":"navbar-light"} ${e.sticky?"navbar-sticky":""}">\n <div class="container">\n <a href="#" class="navbar-brand">\n ${e.brandImage?`<img src="${e.brandImage}" alt="${e.brandText}" class="navbar-logo">`:`<span class="navbar-brand-text">${e.brandText}</span>`}\n </a>\n <div class="navbar-nav">\n ${e.links.map(e=>`<a href="${e.url}" class="nav-link">${e.text}</a>`).join("\n ")}\n </div>\n <div class="navbar-actions">\n ${e.showCta?`<a href="${e.ctaUrl}" class="btn btn-primary btn-sm">${e.ctaText}</a>`:""}\n </div>\n </div>\n</nav>`},hero:{name:"Hero",icon:"layout",category:"headers",description:"Large header section with title, subtitle and call-to-action",defaults:{title:"Welcome to My Site",subtitle:"A brief description of what you offer.",backgroundType:"gradient",backgroundColor:"var(--dm-primary, #6495ED)",backgroundGradient:"linear-gradient(135deg, var(--dm-primary, #6495ED) 0%, var(--dm-primary-dark, #5280d8) 100%)",backgroundImage:"",textColor:"var(--dm-white, #ffffff)",alignment:"center",size:"large",overlay:!1,buttons:[{text:"Get Started",style:"primary",url:"#"}]},editableFields:[{key:"title",type:"text",label:"Title"},{key:"subtitle",type:"textarea",label:"Subtitle"},{key:"backgroundType",type:"select",label:"Background",options:["solid","gradient","image"]},{key:"backgroundColor",type:"color",label:"Background Colour",showWhen:{backgroundType:"solid"}},{key:"backgroundGradient",type:"text",label:"Gradient CSS",showWhen:{backgroundType:"gradient"}},{key:"backgroundImage",type:"text",label:"Image URL",showWhen:{backgroundType:"image"}},{key:"textColor",type:"color",label:"Text Colour"},{key:"alignment",type:"select",label:"Alignment",options:["left","center","right"]},{key:"size",type:"select",label:"Size",options:["small","medium","large"]},{key:"overlay",type:"toggle",label:"Dark Overlay"},{key:"buttons",type:"buttons",label:"Buttons"}],template:e=>{const t="small"===e.size?"py-8":"large"===e.size?"py-16":"py-12",n="left"===e.alignment?"text-left":"right"===e.alignment?"text-right":"text-center";let a="";"solid"===e.backgroundType?a=`background-color: ${e.backgroundColor};`:"gradient"===e.backgroundType?a=`background: ${e.backgroundGradient};`:"image"===e.backgroundType&&(a=`background-image: url('${e.backgroundImage}'); background-size: cover; background-position: center;`);const i=e.overlay?'<div style="position:absolute;inset:0;background:rgba(0,0,0,0.4);"></div>':"",s=e.buttons.map(e=>{const t="primary"===e.style?"btn btn-primary":"secondary"===e.style?"btn btn-secondary":"outline"===e.style?"btn btn-outline":"btn";return`<a href="${e.url}" class="${t}">${e.text}</a>`}).join("\n ");return`<section class="hero ${t}" style="${a} color: ${e.textColor}; position: relative;">\n ${i}\n <div class="container ${n}" style="position: relative; z-index: 1;">\n <h1 class="hero-title">${e.title}</h1>\n <p class="hero-subtitle">${e.subtitle}</p>\n <div class="hero-buttons" style="margin-top: 2rem;">\n ${s}\n </div>\n </div>\n</section>`}},cardGrid:{name:"Card Grid",icon:"grid",category:"content",description:"Grid of cards for features, products, or team members",defaults:{columns:3,gap:"medium",cardStyle:"default",sectionTitle:"",sectionSubtitle:"",cards:[{title:"Feature One",text:"Description of the first feature.",image:"",icon:"star",link:"#"},{title:"Feature Two",text:"Description of the second feature.",image:"",icon:"zap",link:"#"},{title:"Feature Three",text:"Description of the third feature.",image:"",icon:"check",link:"#"}]},editableFields:[{key:"sectionTitle",type:"text",label:"Section Title"},{key:"sectionSubtitle",type:"textarea",label:"Section Subtitle"},{key:"columns",type:"number",label:"Columns",min:1,max:6},{key:"gap",type:"select",label:"Gap",options:["small","medium","large"]},{key:"cardStyle",type:"select",label:"Card Style",options:["default","bordered","shadow","minimal"]},{key:"cards",type:"cards",label:"Cards"}],template:e=>{const t="small"===e.gap?"gap-2":"large"===e.gap?"gap-6":"gap-4",n=e.sectionTitle?`\n <div class="text-center mb-8">\n <h2 class="text-3xl font-bold mb-2">${e.sectionTitle}</h2>\n ${e.sectionSubtitle?`<p class="text-muted">${e.sectionSubtitle}</p>`:""}\n </div>`:"",a=e.cards.map(t=>` <div class="${"bordered"===e.cardStyle?"card card-bordered":"shadow"===e.cardStyle?"card card-shadow":"minimal"===e.cardStyle?"card card-minimal":"card"}">\n ${t.image?`<img src="${t.image}" alt="${t.title}" class="card-img-top">`:""}\n <div class="card-body">\n ${!t.image&&t.icon?`<div class="card-icon mb-3"><span data-icon="${t.icon}" data-icon-size="32"></span></div>`:""}\n <h3 class="card-title">${t.title}</h3>\n <p class="card-text">${t.text}</p>\n ${t.link&&"#"!==t.link?`<a href="${t.link}" class="btn btn-link">Learn more</a>`:""}\n </div>\n </div>`).join("\n");return`<section class="py-12">\n <div class="container">\n ${n}\n <div class="grid grid-cols-${e.columns} ${t}">\n${a}\n </div>\n </div>\n</section>`}},content:{name:"Content Block",icon:"document-text",category:"content",description:"Rich text content section with optional image",defaults:{title:"About Us",content:"<p>Write your content here. This section supports rich text formatting.</p>",layout:"text-only",imagePosition:"right",image:"",imageAlt:""},editableFields:[{key:"title",type:"text",label:"Title"},{key:"content",type:"richtext",label:"Content"},{key:"layout",type:"select",label:"Layout",options:["text-only","text-image","image-text"]},{key:"image",type:"text",label:"Image URL",showWhen:{layout:["text-image","image-text"]}},{key:"imageAlt",type:"text",label:"Image Alt Text",showWhen:{layout:["text-image","image-text"]}}],template:e=>{if("text-only"===e.layout)return`<section class="py-12">\n <div class="container">\n <div class="max-w-3xl mx-auto">\n ${e.title?`<h2 class="text-3xl font-bold mb-4">${e.title}</h2>`:""}\n <div class="content">\n ${e.content}\n </div>\n </div>\n </div>\n</section>`;const t="image-text"===e.layout,n=`<div class="col-6">\n <img src="${e.image}" alt="${e.imageAlt}" class="img-fluid rounded">\n </div>`,a=`<div class="col-6">\n ${e.title?`<h2 class="text-3xl font-bold mb-4">${e.title}</h2>`:""}\n <div class="content">\n ${e.content}\n </div>\n </div>`;return`<section class="py-12">\n <div class="container">\n <div class="row align-center gap-6">\n ${t?n:a}\n ${t?a:n}\n </div>\n </div>\n</section>`}},form:{name:"Form Section",icon:"edit",category:"interactive",description:"Contact form, newsletter signup, or custom form",defaults:{title:"Contact Us",description:"Get in touch with us and we'll respond within 24 hours.",layout:"stacked",submitText:"Send Message",backgroundColor:"",fields:[{type:"text",name:"name",label:"Name",required:!0,placeholder:"Your name"},{type:"email",name:"email",label:"Email",required:!0,placeholder:"your@email.com"},{type:"textarea",name:"message",label:"Message",required:!1,placeholder:"Your message..."}],action:"",method:"POST"},editableFields:[{key:"title",type:"text",label:"Title"},{key:"description",type:"textarea",label:"Description"},{key:"backgroundColor",type:"color",label:"Background Colour"},{key:"layout",type:"select",label:"Layout",options:["stacked","inline","two-column"]},{key:"submitText",type:"text",label:"Submit Button Text"},{key:"fields",type:"formFields",label:"Form Fields"},{key:"action",type:"text",label:"Form Action URL"},{key:"method",type:"select",label:"Method",options:["GET","POST"]}],template:e=>{const t=e.backgroundColor?`background-color: ${e.backgroundColor};`:"",n="inline"===e.layout?"form-inline":"two-column"===e.layout?"grid grid-cols-2 gap-4":"",a=e.fields.map(e=>{const t=e.required?"required":"",n=e.required?' <span class="text-danger">*</span>':"";return"textarea"===e.type?` <div class="form-group">\n <label for="${e.name}">${e.label}${n}</label>\n <textarea class="form-input" id="${e.name}" name="${e.name}" placeholder="${e.placeholder||""}" rows="4" ${t}></textarea>\n </div>`:` <div class="form-group">\n <label for="${e.name}">${e.label}${n}</label>\n <input type="${e.type}" class="form-input" id="${e.name}" name="${e.name}" placeholder="${e.placeholder||""}" ${t}>\n </div>`}).join("\n");return`<section class="py-12" style="${t}">\n <div class="container">\n <div class="max-w-lg mx-auto">\n <div class="text-center mb-6">\n <h2 class="text-3xl font-bold mb-2">${e.title}</h2>\n ${e.description?`<p class="text-muted">${e.description}</p>`:""}\n </div>\n <form action="${e.action}" method="${e.method}" class="${n}">\n${a}\n <div class="form-group">\n <button type="submit" class="btn btn-primary btn-block">${e.submitText}</button>\n </div>\n </form>\n </div>\n </div>\n</section>`}},footer:{name:"Footer",icon:"layout",category:"footers",description:"Page footer with copyright, links, and social icons",defaults:{style:"simple",backgroundColor:"#1f2937",textColor:"#e9ecef",copyright:"© 2025 My Company. All rights reserved.",showNavLinks:!0,navLinks:[{text:"Home",url:"#"},{text:"About",url:"#"},{text:"Services",url:"#"},{text:"Contact",url:"#"}],columns:[{title:"Company",links:[{text:"About Us",url:"#"},{text:"Careers",url:"#"},{text:"Contact",url:"#"}]},{title:"Resources",links:[{text:"Blog",url:"#"},{text:"Documentation",url:"#"},{text:"Support",url:"#"}]}],showSocial:!0,socialLinks:[{platform:"twitter",url:"#"},{platform:"facebook",url:"#"},{platform:"instagram",url:"#"}]},editableFields:[{key:"style",type:"select",label:"Style",options:["simple","columns","centered"]},{key:"backgroundColor",type:"color",label:"Background"},{key:"textColor",type:"color",label:"Text Colour"},{key:"copyright",type:"text",label:"Copyright Text"},{key:"showNavLinks",type:"toggle",label:"Show Nav Links"},{key:"navLinks",type:"links",label:"Navigation Links",showWhen:{showNavLinks:!0}},{key:"columns",type:"footerColumns",label:"Columns",showWhen:{style:"columns"}},{key:"showSocial",type:"toggle",label:"Show Social Icons"},{key:"socialLinks",type:"socialLinks",label:"Social Links",showWhen:{showSocial:!0}}],template:e=>{const t=`background-color: ${e.backgroundColor}; color: ${e.textColor};`,n=e.showSocial?`\n <div class="footer-social">\n ${e.socialLinks.map(e=>`<a href="${e.url}" class="social-link" aria-label="${e.platform}"><span data-icon="${e.platform}" data-icon-size="20"></span></a>`).join("\n ")}\n </div>`:"";if("simple"===e.style){return`<footer class="footer py-6" style="${t}">\n <div class="container text-center">\n ${e.showNavLinks?`\n <nav class="footer-nav mb-3">\n ${e.navLinks.map(e=>`<a href="${e.url}">${e.text}</a>`).join(" · ")}\n </nav>`:""}\n ${n}\n <p class="footer-copyright mt-3">${e.copyright}</p>\n </div>\n</footer>`}if("columns"===e.style){const a=e.columns.map(e=>`\n <div class="footer-column">\n <h4 class="footer-column-title">${e.title}</h4>\n <ul class="footer-links">\n ${e.links.map(e=>`<li><a href="${e.url}">${e.text}</a></li>`).join("\n ")}\n </ul>\n </div>`).join("");return`<footer class="footer py-8" style="${t}">\n <div class="container">\n <div class="grid grid-cols-${e.columns.length+1} gap-6">\n <div class="footer-brand">\n <h3 class="text-xl font-bold mb-3">My Company</h3>\n <p class="text-sm opacity-75">Building amazing things.</p>\n ${n}\n </div>\n ${a}\n </div>\n <div class="footer-bottom mt-6 pt-4" style="border-top: 1px solid rgba(255,255,255,0.1);">\n <p class="text-center text-sm opacity-75">${e.copyright}</p>\n </div>\n </div>\n</footer>`}return`<footer class="footer py-8" style="${t}">\n <div class="container text-center">\n ${n}\n <p class="footer-copyright mt-4">${e.copyright}</p>\n </div>\n</footer>`}},row:{name:"Row Layout",icon:"grid",category:"layout",description:"Container for multi-column layouts with nested sections",defaults:{layout:"equal-2",columns:[{width:.5},{width:.5}],spacing:{padding:{top:3,right:3,bottom:3,left:3},margin:{top:0,right:0,bottom:0,left:0},gutter:4,locked:!1},height:{type:"auto",value:null,equalize:!1},alignment:{horizontal:"start",vertical:"start"},responsive:{mobile:"stack",tablet:"keep",desktop:"keep"},background:{type:"none",color:"",gradient:"",image:""}},editableFields:[{key:"layout",type:"layout-preset",label:"Layout Preset"},{key:"columns",type:"column-widths",label:"Column Widths"},{key:"spacing",type:"spacing-controls",label:"Spacing"},{key:"height",type:"height-controls",label:"Height"},{key:"alignment",type:"alignment-controls",label:"Alignment"},{key:"responsive",type:"responsive-controls",label:"Responsive"},{key:"background",type:"background-controls",label:"Background"}],template:e=>'<section class="pr-row" data-row-placeholder="true">Row Layout (placeholder)</section>'},carousel:{name:"Carousel",icon:"image",category:"interactive",description:"Image/content carousel with autoplay and navigation",defaults:{slides:[{image:"https://via.placeholder.com/800x400",caption:"Slide 1",content:"First slide content"},{image:"https://via.placeholder.com/800x400",caption:"Slide 2",content:"Second slide content"},{image:"https://via.placeholder.com/800x400",caption:"Slide 3",content:"Third slide content"}],autoplay:!0,interval:5e3,pauseOnHover:!0,loop:!0,animation:"slide",showArrows:!0,showIndicators:!0,height:400},editableFields:[{key:"slides",type:"slides",label:"Slides"},{key:"autoplay",type:"toggle",label:"Autoplay"},{key:"interval",type:"number",label:"Interval (ms)",showWhen:{autoplay:!0}},{key:"pauseOnHover",type:"toggle",label:"Pause on Hover"},{key:"loop",type:"toggle",label:"Loop"},{key:"animation",type:"select",label:"Animation",options:["slide","fade"]},{key:"showArrows",type:"toggle",label:"Show Arrows"},{key:"showIndicators",type:"toggle",label:"Show Indicators"},{key:"height",type:"number",label:"Height (px)"}],template:e=>{const t=e.slides.map((t,n)=>`\n <div class="carousel-slide ${0===n?"active":""}" style="height: ${e.height}px;">\n ${t.image?`<img src="${t.image}" alt="${t.caption}" style="width: 100%; height: 100%; object-fit: cover;">`:""}\n ${t.caption||t.content?`\n <div class="carousel-caption" style="position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); color: white; text-align: center; background: rgba(0,0,0,0.6); padding: 1rem 2rem; border-radius: 8px;">\n ${t.caption?`<h3 style="margin: 0 0 0.5rem 0;">${t.caption}</h3>`:""}\n ${t.content?`<p style="margin: 0;">${t.content}</p>`:""}\n </div>\n `:""}\n </div>`).join("");return`<section class="py-6" data-component="carousel">\n <div class="container">\n <div class="carousel" data-autoplay="${e.autoplay}" data-interval="${e.interval}" data-pause-hover="${e.pauseOnHover}" data-loop="${e.loop}" data-animation="${e.animation}" style="position: relative; overflow: hidden;">\n ${t}\n ${e.showArrows?'\n <button class="carousel-prev" style="position: absolute; left: 10px; top: 50%; transform: translateY(-50%); background: rgba(0,0,0,0.5); color: white; border: none; padding: 1rem; cursor: pointer; font-size: 1.5rem;">‹</button>\n <button class="carousel-next" style="position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: rgba(0,0,0,0.5); color: white; border: none; padding: 1rem; cursor: pointer; font-size: 1.5rem;">›</button>\n ':""}\n ${e.showIndicators?`\n <div class="carousel-indicators" style="position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); display: flex; gap: 0.5rem;">\n ${e.slides.map((e,t)=>`<button data-slide="${t}" class="${0===t?"active":""}" style="width: 12px; height: 12px; border-radius: 50%; border: 2px solid white; background: ${0===t?"white":"transparent"}; cursor: pointer;"></button>`).join("")}\n </div>\n `:""}\n </div>\n </div>\n</section>`}},accordion:{name:"Accordion",icon:"chevron-down",category:"interactive",description:"Expandable FAQ or content blocks",defaults:{title:"Frequently Asked Questions",items:[{title:"What is your return policy?",content:"We offer a 30-day money-back guarantee on all products."},{title:"How long does shipping take?",content:"Standard shipping takes 5-7 business days."},{title:"Do you ship internationally?",content:"Yes, we ship to most countries worldwide."}],allowMultiple:!1,activeIndex:0,animation:!0,style:"default"},editableFields:[{key:"title",type:"text",label:"Section Title"},{key:"items",type:"accordionItems",label:"Items"},{key:"allowMultiple",type:"toggle",label:"Allow Multiple Open"},{key:"activeIndex",type:"number",label:"Initially Active (index)"},{key:"animation",type:"toggle",label:"Animated"},{key:"style",type:"select",label:"Style",options:["default","bordered","minimal"]}],template:e=>{const t=e.items.map((t,n)=>`\n <div class="accordion-item ${n===e.activeIndex?"active":""}" style="border: 1px solid var(--dm-border, #dee2e6); margin-bottom: 0.5rem; border-radius: 4px;">\n <button class="accordion-header" style="width: 100%; padding: 1rem; text-align: left; background: var(--dm-surface, #fff); border: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center; font-weight: 500;">\n ${t.title}\n <span class="accordion-icon" style="transition: transform 0.3s; ${n===e.activeIndex?"transform: rotate(180deg);":""}">▼</span>\n </button>\n <div class="accordion-content" style="padding: ${n===e.activeIndex?"1rem":"0 1rem"}; max-height: ${n===e.activeIndex?"500px":"0"}; overflow: hidden; transition: all 0.3s;">\n ${t.content}\n </div>\n </div>`).join("");return`<section class="py-12" data-component="accordion">\n <div class="container">\n ${e.title?`<h2 class="text-3xl font-bold mb-6 text-center">${e.title}</h2>`:""}\n <div class="accordion accordion-${e.style}" data-allow-multiple="${e.allowMultiple}" data-animation="${e.animation}" style="max-width: 800px; margin: 0 auto;">\n ${t}\n </div>\n </div>\n</section>`}},tabs:{name:"Tabs",icon:"menu",category:"interactive",description:"Tabbed content sections",defaults:{tabs:[{label:"Overview",content:"<p>Overview content goes here.</p>"},{label:"Features",content:"<p>Feature details go here.</p>"},{label:"Pricing",content:"<p>Pricing information goes here.</p>"}],activeIndex:0,style:"default",animation:"fade"},editableFields:[{key:"tabs",type:"tabItems",label:"Tabs"},{key:"activeIndex",type:"number",label:"Initially Active (index)"},{key:"style",type:"select",label:"Style",options:["default","pills","underline"]},{key:"animation",type:"select",label:"Animation",options:["none","fade","slide"]}],template:e=>{const t=e.tabs.map((t,n)=>`\n <button class="tab-button ${n===e.activeIndex?"active":""}" data-tab="${n}" style="padding: 0.75rem 1.5rem; border: 1px solid var(--dm-border, #dee2e6); background: ${n===e.activeIndex?"var(--dm-primary, #6495ED)":"transparent"}; color: ${n===e.activeIndex?"white":"inherit"}; cursor: pointer; border-radius: 4px 4px 0 0; margin-right: 0.25rem;">\n ${t.label}\n </button>`).join(""),n=e.tabs.map((t,n)=>`\n <div class="tab-panel ${n===e.activeIndex?"active":""}" data-panel="${n}" style="display: ${n===e.activeIndex?"block":"none"}; padding: 2rem; border: 1px solid var(--dm-border, #dee2e6); border-top: none;">\n ${t.content}\n </div>`).join("");return`<section class="py-12" data-component="tabs">\n <div class="container">\n <div class="tabs tabs-${e.style}" data-animation="${e.animation}">\n <div class="tabs-nav" style="display: flex; border-bottom: 2px solid var(--dm-border, #dee2e6);">\n ${t}\n </div>\n <div class="tabs-content">\n ${n}\n </div>\n </div>\n </div>\n</section>`}},modal:{name:"Modal",icon:"box",category:"interactive",description:"Popup modal trigger with content",defaults:{triggerText:"Open Modal",triggerStyle:"primary",modalTitle:"Modal Title",modalContent:"<p>Modal content goes here.</p>",backdrop:!0,keyboard:!0,animation:!0},editableFields:[{key:"triggerText",type:"text",label:"Button Text"},{key:"triggerStyle",type:"select",label:"Button Style",options:["primary","secondary","outline"]},{key:"modalTitle",type:"text",label:"Modal Title"},{key:"modalContent",type:"richtext",label:"Modal Content"},{key:"backdrop",type:"toggle",label:"Show Backdrop"},{key:"keyboard",type:"toggle",label:"Close on ESC"},{key:"animation",type:"toggle",label:"Animated"}],template:e=>`<section class="py-12 text-center" data-component="modal">\n <div class="container">\n <button class="${"primary"===e.triggerStyle?"btn btn-primary":"secondary"===e.triggerStyle?"btn btn-secondary":"btn btn-outline"}" data-modal-trigger="modal-1">${e.triggerText}</button>\n <div class="modal" id="modal-1" data-backdrop="${e.backdrop}" data-keyboard="${e.keyboard}" data-animation="${e.animation}" style="display: none; position: fixed; inset: 0; z-index: 1000; background: rgba(0,0,0,0.5); align-items: center; justify-content: center;">\n <div class="modal-content" style="background: white; padding: 2rem; border-radius: 8px; max-width: 600px; width: 90%; position: relative;">\n <button class="modal-close" style="position: absolute; top: 1rem; right: 1rem; background: none; border: none; font-size: 1.5rem; cursor: pointer;">×</button>\n <h2 class="modal-title" style="margin-bottom: 1rem;">${e.modalTitle}</h2>\n <div class="modal-body">${e.modalContent}</div>\n </div>\n </div>\n </div>\n</section>`},toast:{name:"Toast",icon:"document",category:"interactive",description:"Notification toast trigger",defaults:{triggerText:"Show Notification",toastMessage:"This is a toast notification!",toastType:"info",position:"top-right",duration:3e3},editableFields:[{key:"triggerText",type:"text",label:"Button Text"},{key:"toastMessage",type:"textarea",label:"Toast Message"},{key:"toastType",type:"select",label:"Type",options:["info","success","warning","error"]},{key:"position",type:"select",label:"Position",options:["top-left","top-center","top-right","bottom-left","bottom-center","bottom-right"]},{key:"duration",type:"number",label:"Duration (ms)"}],template:e=>`<section class="py-12 text-center" data-component="toast">\n <div class="container">\n <button class="btn btn-primary" data-toast-trigger data-toast-message="${e.toastMessage}" data-toast-type="${e.toastType}" data-toast-position="${e.position}" data-toast-duration="${e.duration}">\n ${e.triggerText}\n </button>\n </div>\n</section>`},breadcrumbs:{name:"Breadcrumbs",icon:"chevron-right",category:"interactive",description:"Navigation breadcrumb trail",defaults:{items:[{text:"Home",url:"#"},{text:"Products",url:"#"},{text:"Category",url:"#"},{text:"Current Page",url:""}],separator:"/",homeIcon:!0},editableFields:[{key:"items",type:"breadcrumbItems",label:"Items"},{key:"separator",type:"select",label:"Separator",options:["/",">","→","chevron"]},{key:"homeIcon",type:"toggle",label:"Show Home Icon"}],template:e=>`<section class="py-6" data-component="breadcrumbs">\n <div class="container">\n <nav class="breadcrumbs" style="display: flex; align-items: center; font-size: 0.875rem;">\n ${e.items.map((t,n)=>{const a=n===e.items.length-1,i="chevron"===e.separator?'<span data-icon="chevron-right" data-icon-size="14"></span>':e.separator;return`\n ${0===n&&e.homeIcon?'<span data-icon="home" data-icon-size="16" style="margin-right: 0.5rem;"></span>':""}\n ${t.url&&!a?`<a href="${t.url}" style="color: var(--dm-primary, #6495ED); text-decoration: none;">${t.text}</a>`:`<span style="color: ${a?"var(--dm-text, #212529)":"var(--dm-text-muted, #6c757d)"};">${t.text}</span>`}\n ${a?"":`<span style="margin: 0 0.5rem; color: var(--dm-text-muted, #6c757d);">${i}</span>`}`}).join("")}\n </nav>\n </div>\n</section>`},buttonGroup:{name:"Button Group",icon:"grid",category:"interactive",description:"Radio or checkbox button group",defaults:{title:"Select an Option",mode:"single",buttons:[{label:"Option 1",value:"opt1"},{label:"Option 2",value:"opt2"},{label:"Option 3",value:"opt3"}],activeIndex:0,vertical:!1},editableFields:[{key:"title",type:"text",label:"Title"},{key:"mode",type:"select",label:"Mode",options:["single","multiple"]},{key:"buttons",type:"buttonGroupItems",label:"Buttons"},{key:"activeIndex",type:"number",label:"Initially Active (index)"},{key:"vertical",type:"toggle",label:"Vertical Layout"}],template:e=>{const t=e.buttons.map((t,n)=>`\n <button class="btn-group-item ${n===e.activeIndex?"active":""}" data-value="${t.value}" style="padding: 0.75rem 1.5rem; border: 1px solid var(--dm-border, #dee2e6); background: ${n===e.activeIndex?"var(--dm-primary, #6495ED)":"transparent"}; color: ${n===e.activeIndex?"white":"inherit"}; cursor: pointer;">\n ${t.label}\n </button>`).join("");return`<section class="py-12" data-component="button-group">\n <div class="container">\n ${e.title?`<h3 class="text-xl font-semibold mb-4">${e.title}</h3>`:""}\n <div class="btn-group ${e.vertical?"btn-group-vertical":""}" data-mode="${e.mode}" style="display: flex; ${e.vertical?"flex-direction: column;":""} gap: ${e.vertical?"0.5rem":"0"};">\n ${t}\n </div>\n </div>\n</section>`}},tagCloud:{name:"Tag Cloud",icon:"star",category:"interactive",description:"Badge/tag collection display",defaults:{title:"Tags",tags:[{text:"JavaScript",color:"primary"},{text:"React",color:"success"},{text:"Node.js",color:"info"},{text:"CSS",color:"warning"},{text:"HTML",color:"danger"}],size:"medium",pill:!0},editableFields:[{key:"title",type:"text",label:"Title"},{key:"tags",type:"tagItems",label:"Tags"},{key:"size",type:"select",label:"Size",options:["small","medium","large"]},{key:"pill",type:"toggle",label:"Pill Style"}],template:e=>{const t="small"===e.size?"text-sm":"large"===e.size?"text-lg":"",n=e.tags.map(n=>{const a={primary:"var(--dm-primary, #6495ED)",success:"var(--dm-success, #28a745)",info:"var(--dm-info, #17a2b8)",warning:"var(--dm-warning, #ffc107)",danger:"var(--dm-danger, #dc3545)"},i=a[n.color]||a.primary;return`<span class="badge ${t}" style="display: inline-block; padding: 0.375rem 0.75rem; background: ${i}; color: white; border-radius: ${e.pill?"50px":"4px"}; margin: 0.25rem; font-size: ${"small"===e.size?"0.75rem":"large"===e.size?"1rem":"0.875rem"};">\n ${n.text}\n </span>`}).join("");return`<section class="py-12" data-component="tag-cloud">\n <div class="container">\n ${e.title?`<h3 class="text-xl font-semibold mb-4">${e.title}</h3>`:""}\n <div class="tag-cloud" style="display: flex; flex-wrap: wrap; gap: 0.5rem;">\n ${n}\n </div>\n </div>\n</section>`}},dropdown:{name:"Dropdown",icon:"chevron-down",category:"interactive",description:"Dropdown menu with items",defaults:{triggerText:"Menu",triggerStyle:"primary",items:[{text:"Action 1",url:"#"},{text:"Action 2",url:"#"},{text:"divider",url:""},{text:"Action 3",url:"#"}],position:"bottom"},editableFields:[{key:"triggerText",type:"text",label:"Button Text"},{key:"triggerStyle",type:"select",label:"Button Style",options:["primary","secondary","outline"]},{key:"items",type:"dropdownItems",label:"Items"},{key:"position",type:"select",label:"Position",options:["bottom","top","left","right"]}],template:e=>{const t="primary"===e.triggerStyle?"btn btn-primary":"secondary"===e.triggerStyle?"btn btn-secondary":"btn btn-outline",n=e.items.map(e=>"divider"===e.text?'<div style="height: 1px; background: var(--dm-border, #dee2e6); margin: 0.5rem 0;"></div>':`<a href="${e.url}" style="display: block; padding: 0.5rem 1rem; color: var(--dm-text, #212529); text-decoration: none; transition: background 0.2s;" onmouseover="this.style.background='var(--dm-hover-bg, #f8f9fa)'" onmouseout="this.style.background='transparent'">${e.text}</a>`).join("");return`<section class="py-12 text-center" data-component="dropdown">\n <div class="container">\n <div class="dropdown" data-position="${e.position}" style="position: relative; display: inline-block;">\n <button class="${t} dropdown-trigger" style="display: flex; align-items: center; gap: 0.5rem;">\n ${e.triggerText}\n <span data-icon="chevron-down" data-icon-size="14"></span>\n </button>\n <div class="dropdown-menu" style="display: none; position: absolute; top: 100%; left: 0; margin-top: 0.5rem; background: white; border: 1px solid var(--dm-border, #dee2e6); border-radius: 4px; box-shadow: var(--dm-shadow-md); min-width: 200px; z-index: 1000;">\n ${n}\n </div>\n </div>\n </div>\n</section>`}}},h={single:{columns:[1],label:"1 Column"},"equal-2":{columns:[.5,.5],label:"1/2 + 1/2"},"third-twothirds":{columns:[.333,.667],label:"1/3 + 2/3"},"twothirds-third":{columns:[.667,.333],label:"2/3 + 1/3"},"quarter-threequarters":{columns:[.25,.75],label:"1/4 + 3/4"},"threequarters-quarter":{columns:[.75,.25],label:"3/4 + 1/4"},"equal-3":{columns:[.333,.333,.333],label:"1/3 × 3"},"quarter-half-quarter":{columns:[.25,.5,.25],label:"1/4 + 1/2 + 1/4"},"equal-4":{columns:[.25,.25,.25,.25],label:"1/4 × 4"},"fifth-fourfifths":{columns:[.2,.8],label:"1/5 + 4/5"},"fourfifths-fifth":{columns:[.8,.2],label:"4/5 + 1/5"},"equal-5":{columns:[.2,.2,.2,.2,.2],label:"1/5 × 5"},"sixth-fivesixths":{columns:[.167,.833],label:"1/6 + 5/6"},"fivesixths-sixth":{columns:[.833,.167],label:"5/6 + 1/6"},"equal-6":{columns:[.167,.167,.167,.167,.167,.167],label:"1/6 × 6"},"sidebar-main":{columns:[.3,.7],label:"Sidebar + Main"},"main-sidebar":{columns:[.7,.3],label:"Main + Sidebar"},"narrow-wide-narrow":{columns:[.2,.6,.2],label:"1/5 + 3/5 + 1/5"},"wide-narrow-wide":{columns:[.4,.2,.4],label:"2/5 + 1/5 + 2/5"},"third-sixth-half":{columns:[.333,.167,.5],label:"1/3 + 1/6 + 1/2"},"asymmetric-3":{columns:[.5,.3,.2],label:"1/2 + 3/10 + 1/5"},"asymmetric-4":{columns:[.4,.3,.2,.1],label:"2/5 + 3/10 + 1/5 + 1/10"}};class u{static STORAGE_KEY="page-roller-templates";static ACTIVE_KEY="page-roller-active";static list(){const e=r.get(this.STORAGE_KEY,{});return Object.keys(e)}static getAll(){return r.get(this.STORAGE_KEY,{})}static load(e){return r.get(this.STORAGE_KEY,{})[e]||null}static save(e,t){const n=r.get(this.STORAGE_KEY,{});return t.name=e,t.modified=(new Date).toISOString(),t.created||(t.created=t.modified),n[e]=t,r.set(this.STORAGE_KEY,n)}static delete(e){const t=r.get(this.STORAGE_KEY,{});return!!t[e]&&(delete t[e],r.set(this.STORAGE_KEY,t))}static rename(e,t){const n=r.get(this.STORAGE_KEY,{});return!(!n[e]||n[t])&&(n[t]={...n[e],name:t,modified:(new Date).toISOString()},delete n[e],r.set(this.STORAGE_KEY,n))}static saveActive(e){r.set(this.ACTIVE_KEY,e)}static loadActive(){return r.get(this.ACTIVE_KEY,null)}static clearActive(){r.remove(this.ACTIVE_KEY)}}class g{static defaults={template:null,theme:"light",themeVariant:null,useGrid:!0,useTheme:!0,useThemeRoller:!1,splitView:!0,autoSave:!0,autoSaveInterval:3e4,onChange:null,onSave:null,onExport:null};constructor(e,t={}){this.element="string"==typeof e?document.querySelector(e):e,this.element?(this.options={...g.defaults,...t},this._sections=[],this._selectedIndex=-1,this._pageConfig={theme:this.options.theme,variant:this.options.themeVariant,useGrid:this.options.useGrid,useTheme:this.options.useTheme,customCSS:"",meta:{title:"My Page",description:"",charset:"UTF-8",viewport:"width=device-width, initial-scale=1.0"}},this._templateName="",this._isDirty=!1,this._autoSaveTimer=null,this._eventHandlers=[],this._init()):console.error("PageRoller: Container element not found")}_init(){if(this.options.template)this.loadTemplate(this.options.template);else{const e=u.loadActive();e&&this._loadPageData(e)}this._render(),this._bindEvents(),"undefined"!=typeof Domma&&Domma.icons&&Domma.icons.scan(this.element),this._refreshPreview(),this.options.autoSave&&(this._autoSaveTimer=setInterval(()=>{this.saveToStorage()},this.options.autoSaveInterval))}_render(){this.element.classList.add("qr-container"),this.element.innerHTML=this._buildHTML(),this._refs={header:this.element.querySelector(".qr-header"),templateName:this.element.querySelector(".qr-template-name"),library:this.element.querySelector(".qr-library"),canvas:this.element.querySelector(".qr-canvas"),editor:this.element.querySelector(".qr-editor"),preview:this.element.querySelector(".qr-preview-frame"),actions:this.element.querySelector(".qr-actions")}}_buildHTML(){const e=Object.entries(m).map(([e,t])=>`\n <div class="qr-library-item" data-section-type="${e}" draggable="true" title="${t.description}">\n <span class="qr-library-icon" data-icon="${t.icon}" data-icon-size="20"></span>\n <span class="qr-library-name">${t.name}</span>\n </div>\n `).join(""),t=`\n <option value="">No Theme</option>\n <option value="light" ${"light"===this._pageConfig.theme?"selected":""}>Light</option>\n <option value="dark" ${"dark"===this._pageConfig.theme?"selected":""}>Dark</option>\n `;return`\n <div class="qr-header">\n <div class="qr-header-left">\n <button class="qr-btn qr-btn-icon" data-action="new" title="New Page">\n <span data-icon="document-add" data-icon-size="18"></span>\n </button>\n <button class="qr-btn qr-btn-icon" data-action="save" title="Save Template">\n <span data-icon="save" data-icon-size="18"></span>\n </button>\n <div class="qr-dropdown">\n <button class="qr-btn qr-btn-icon" data-action="load" title="Load Template">\n <span data-icon="folder-open" data-icon-size="18"></span>\n </button>\n <div class="qr-dropdown-menu qr-templates-menu"></div>\n </div>\n <input type="text" class="qr-template-name" placeholder="Untitled Page" value="${this._escapeHtml(this._templateName)}">\n </div>\n <div class="qr-header-center">\n <span class="qr-title">Page Roller</span>\n </div>\n <div class="qr-header-right">\n <label class="qr-label">Theme:</label>\n <select class="qr-select qr-theme-select">${t}</select>\n <select class="qr-select qr-variant-select">\n <option value="">Default</option>\n <option value="ocean">Ocean</option>\n <option value="forest">Forest</option>\n <option value="sunset">Sunset</option>\n <option value="royal">Royal</option>\n <option value="lemon">Lemon</option>\n <option value="silver">Silver</option>\n <option value="charcoal">Charcoal</option>\n </select>\n <label class="qr-checkbox">\n <input type="checkbox" class="qr-grid-toggle" ${this._pageConfig.useGrid?"checked":""}>\n <span>Grid</span>\n </label>\n </div>\n </div>\n\n <div class="qr-body">\n <div class="qr-sidebar">\n <div class="qr-library">\n <div class="qr-section-title">Sections</div>\n ${e}\n </div>\n <div class="qr-editor">\n <div class="qr-section-title">Properties</div>\n <div class="qr-editor-content">\n <p class="qr-editor-placeholder">Select a section to edit its properties</p>\n </div>\n </div>\n </div>\n\n <div class="qr-main">\n <div class="qr-canvas-container">\n <div class="qr-canvas">\n <div class="qr-drop-zone qr-drop-zone-empty" data-position="0">\n <span data-icon="plus" data-icon-size="24"></span>\n <span>Click a section or drag here to add</span>\n </div>\n </div>\n </div>\n ${this.options.splitView?'\n <div class="qr-preview-container">\n <div class="qr-preview-header">\n <span>Preview</span>\n <button class="qr-btn qr-btn-sm" data-action="preview-full" title="Open in new window">\n <span data-icon="external-link" data-icon-size="14"></span>\n </button>\n </div>\n <iframe class="qr-preview-frame" sandbox="allow-same-origin"></iframe>\n </div>\n ':""}\n </div>\n </div>\n\n <div class="qr-actions">\n <button class="qr-btn" data-action="copy">\n <span data-icon="copy" data-icon-size="16"></span>\n Copy HTML\n </button>\n <button class="qr-btn" data-action="download">\n <span data-icon="download" data-icon-size="16"></span>\n Download\n </button>\n <button class="qr-btn" data-action="save-storage">\n <span data-icon="database" data-icon-size="16"></span>\n Save to Browser\n </button>\n <button class="qr-btn qr-btn-primary" data-action="preview-full">\n <span data-icon="eye" data-icon-size="16"></span>\n Full Preview\n </button>\n </div>\n `}_bindEvents(){this._on(this.element,"click","[data-action]",e=>{const t=e.target.closest("[data-action]").dataset.action;this._handleAction(t)}),this._on(this._refs.templateName,"input",null,e=>{this._templateName=e.target.value,this._markDirty()}),this._on(this.element,"change",".qr-theme-select",e=>{this._pageConfig.theme=e.target.value||null,this._markDirty(),this._refreshPreview()}),this._on(this.element,"change",".qr-variant-select",e=>{this._pageConfig.variant=e.target.value||null,this._markDirty(),this._refreshPreview()}),this._on(this.element,"change",".qr-grid-toggle",e=>{this._pageConfig.useGrid=e.target.checked,this._markDirty(),this._refreshPreview()}),this._on(this._refs.library,"click",".qr-library-item",e=>{const t=e.target.closest(".qr-library-item").dataset.sectionType;this.addSection(t)}),this._on(this._refs.library,"dragstart",".qr-library-item",e=>{e.dataTransfer.setData("section-type",e.target.closest(".qr-library-item").dataset.sectionType),e.dataTransfer.effectAllowed="copy",this._dragSource="library"}),this._on(this._refs.canvas,"click",".qr-section",e=>{if(e.target.closest(".qr-section-controls"))return;const t=parseInt(e.target.closest(".qr-section").dataset.index);this._selectSection(t)}),this._on(this._refs.canvas,"click",".qr-section-controls button",e=>{const t=e.target.closest("button"),n=t.closest(".qr-section"),a=parseInt(n.dataset.index),i=t.dataset.action;"move-up"===i?this.moveSection(a,a-1):"move-down"===i?this.moveSection(a,a+1):"delete"===i?this.removeSection(a):"duplicate"===i&&this._duplicateSection(a)}),this._on(this._refs.canvas,"dragstart",".qr-section",e=>{e.dataTransfer.setData("section-index",e.target.closest(".qr-section").dataset.index),e.dataTransfer.effectAllowed="move",this._dragSource="canvas",e.target.closest(".qr-section").classList.add("qr-dragging")}),this._on(this._refs.canvas,"dragend",".qr-section",e=>{e.target.closest(".qr-section").classList.remove("qr-dragging")}),this._on(this._refs.canvas,"dragover",".qr-drop-zone",e=>{e.preventDefault(),e.target.closest(".qr-drop-zone").classList.add("qr-drop-active")}),this._on(this._refs.canvas,"dragleave",".qr-drop-zone",e=>{e.target.closest(".qr-drop-zone").classList.remove("qr-drop-active")}),this._on(this._refs.canvas,"drop",".qr-drop-zone",e=>{e.preventDefault();const t=e.target.closest(".qr-drop-zone");t.classList.remove("qr-drop-active");const n=parseInt(t.dataset.position);if("library"===this._dragSource){const t=e.dataTransfer.getData("section-type");this.addSection(t,n)}else{const t=parseInt(e.dataTransfer.getData("section-index"));this.moveSection(t,n)}}),this._on(this._refs.editor,"input","input, textarea, select",e=>{this._handleEditorChange(e)}),this._on(this._refs.editor,"change",'input[type="checkbox"], select',e=>{this._handleEditorChange(e)}),this._on(this._refs.editor,"click","button",e=>{const t=e.target.closest("button"),n=t.dataset.action;n?this._handleEditorAction(n,t):t.dataset.field&&this._handleEditorChange(e)}),this._on(this.element,"click",".qr-templates-menu .qr-menu-item",e=>{const t=e.target.closest(".qr-menu-item").dataset.template;t&&this.loadTemplate(t)})}_on(e,t,n,a){const i=t=>{if(n){const i=t.target.closest(n);i&&e.contains(i)&&a.call(i,t)}else a.call(e,t)};e.addEventListener(t,i),this._eventHandlers.push({element:e,event:t,wrapper:i})}async _handleAction(e){switch(e){case"new":this.newPage();break;case"save":this._showSaveDialog();break;case"load":this._toggleTemplatesMenu();break;case"copy":await this.copyToClipboard();break;case"download":this.download();break;case"save-storage":this.saveToStorage();break;case"preview-full":this.openPreviewWindow()}}_handleEditorChange(e){if(this._selectedIndex<0)return;const t=e.target,n=t.closest("[data-field]");if(!n)return;const a=n.dataset.field||t.dataset.field;if(!a)return;let i;if("BUTTON"===t.tagName&&t.dataset.value)i=t.dataset.value;else if("checkbox"===t.type)i=t.checked;else if("number"===t.type)i=parseFloat(t.value)||0;else if("range"===t.type&&t.classList.contains("qr-width-slider"))i=parseFloat(t.value);else if("number"===t.type&&t.classList.contains("qr-width-number"))i=parseFloat(t.value)/100;else if("TEXTAREA"===t.tagName&&t.classList.contains("qr-json"))try{i=JSON.parse(t.value)}catch(e){return void console.warn("Invalid JSON in field:",a,e)}else i=t.value;const s=this._sections[this._selectedIndex];if(a.includes(".")){const e=a.split(".");let t=s.config;for(let n=0;n<e.length-1;n++){const a=e[n],i=e[n+1];isNaN(i)?t=t[a]:(t=t[a][parseInt(i)],n++)}t[e[e.length-1]]=i}else s.config[a]=i;if("layout"===a&&h[i]){const e=h[i];s.config.columns=e.columns.map(e=>({width:e}))}this._markDirty(),this._refreshPreview(),this._renderCanvasSections(),"background.type"!==a&&"height.type"!==a||this._renderEditor()}_handleEditorAction(e,t){if(this._selectedIndex<0)return;const n=this._sections[this._selectedIndex];if("row"===n.type){switch(e){case"add-column":const e=1/(n.config.columns.length+1);n.config.columns.push({width:e}),n.config.columns.forEach(t=>{t.width=e});break;case"remove-column":if(n.config.columns.length>1){n.config.columns.pop();const e=1/n.config.columns.length;n.config.columns.forEach(t=>{t.width=e}),n.children&&(n.children=n.children.filter(e=>e.columnIndex<n.config.columns.length))}break;case"equalize-columns":const t=1/n.config.columns.length;n.config.columns.forEach(e=>{e.width=t});break;case"toggle-lock":n.config.spacing.locked=!n.config.spacing.locked}this._markDirty(),this._renderEditor(),this._refreshPreview(),this._renderCanvasSections()}}_markDirty(){this._isDirty=!0,this.options.onChange&&this.options.onChange(this._getPageData())}_selectSection(e){this._selectedIndex=e,this._refs.canvas.querySelectorAll(".qr-section").forEach((t,n)=>{t.classList.toggle("qr-selected",n===e)}),this._renderEditor()}_renderEditor(){const e=this._refs.editor.querySelector(".qr-editor-content");if(this._selectedIndex<0||!this._sections[this._selectedIndex])return void(e.innerHTML='<p class="qr-editor-placeholder">Select a section to edit its properties</p>');const t=this._sections[this._selectedIndex],n=m[t.type];if(!n)return void(e.innerHTML='<p class="qr-editor-placeholder">Unknown section type</p>');let a="";for(const e of n.editableFields){if(e.showWhen){if(!Object.entries(e.showWhen).every(([e,n])=>Array.isArray(n)?n.includes(t.config[e]):t.config[e]===n))continue}a+=this._renderEditorField(e,t.config[e.key])}e.innerHTML=`\n <div class="qr-editor-section-header">\n <span data-icon="${n.icon}" data-icon-size="18"></span>\n <span>${n.name}</span>\n </div>\n <div class="qr-editor-fields">\n ${a}\n </div>\n `,"undefined"!=typeof Domma&&Domma.icons&&Domma.icons.scan(e)}_renderEditorField(e,t){const n=this._escapeHtml(String(t??""));switch(e.type){case"text":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n <input type="text" class="qr-input" value="${n}">\n </div>\n `;case"textarea":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n <textarea class="qr-input qr-textarea">${n}</textarea>\n </div>\n `;case"richtext":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n <textarea class="qr-input qr-textarea qr-richtext">${n}</textarea>\n </div>\n `;case"number":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n <input type="number" class="qr-input" value="${t}" min="${e.min??""}" max="${e.max??""}">\n </div>\n `;case"color":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n <div class="qr-color-wrapper">\n <input type="color" class="qr-color" value="${n}">\n <input type="text" class="qr-input qr-color-text" value="${n}">\n </div>\n </div>\n `;case"select":const a=e.options.map(e=>`<option value="${e}" ${t===e?"selected":""}>${this._capitalize(e)}</option>`).join("");return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n <select class="qr-select">${a}</select>\n </div>\n `;case"toggle":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-checkbox">\n <input type="checkbox" ${t?"checked":""}>\n <span>${e.label}</span>\n </label>\n </div>\n `;case"buttons":case"cards":case"formFields":case"links":case"footerColumns":case"socialLinks":case"slides":case"accordionItems":case"tabItems":case"breadcrumbItems":case"buttonGroupItems":case"tagItems":case"dropdownItems":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n <p class="qr-field-note" style="font-size: 0.875rem; color: var(--dm-text-muted, #6c757d); margin: 0.25rem 0;">Edit in JSON format</p>\n <textarea class="qr-input qr-textarea qr-json" rows="12" style="font-family: monospace; font-size: 0.875rem;">${JSON.stringify(t,null,2)}</textarea>\n </div>\n `;case"layout-preset":const i=Object.entries(h).map(([e,n])=>{const a=e===t,i=n.columns.map(e=>`<div style="flex: ${e}; background: ${a?"var(--dm-primary, #6495ED)":"var(--dm-gray-300, #dee2e6)"}; height: 100%; border-radius: 2px;"></div>`).join("");return`\n <button class="qr-preset-btn ${a?"active":""}"\n type="button"\n data-preset="${e}"\n data-field="layout"\n title="${n.label}">\n <div class="qr-preset-visual" style="display: flex; gap: 2px; height: 30px; margin-bottom: 4px;">\n ${i}\n </div>\n <span class="qr-preset-label" style="font-size: 0.75rem; display: block;">${n.label}</span>\n </button>\n `}).join("");return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n <div class="qr-preset-grid" style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; margin-top: 0.5rem;">\n ${i}\n </div>\n </div>\n `;case"column-widths":const s=t.map((e,t)=>`\n <div class="qr-width-control" style="margin-bottom: 0.75rem;">\n <label style="display: block; font-size: 0.875rem; margin-bottom: 0.25rem;">Column ${t+1}</label>\n <div style="display: flex; gap: 0.5rem; align-items: center;">\n <input type="range"\n min="0.1"\n max="1"\n step="0.01"\n value="${e.width}"\n data-col-idx="${t}"\n data-field="columns.${t}.width"\n class="qr-width-slider"\n style="flex: 1;">\n <input type="number"\n min="10"\n max="100"\n value="${(100*e.width).toFixed(0)}"\n data-col-idx="${t}"\n data-field="columns.${t}.width"\n class="qr-width-number"\n style="width: 60px;">\n <span>%</span>\n </div>\n </div>\n `).join("");return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n ${s}\n <div class="qr-width-actions" style="display: flex; gap: 0.5rem; margin-top: 0.5rem;">\n <button type="button" class="qr-btn qr-btn-sm qr-btn-equalize" data-action="equalize-columns">Equalize</button>\n <button type="button" class="qr-btn qr-btn-sm qr-btn-add-col" data-action="add-column">+ Column</button>\n ${t.length>1?'<button type="button" class="qr-btn qr-btn-sm qr-btn-remove-col" data-action="remove-column">- Column</button>':""}\n </div>\n </div>\n `;case"spacing-controls":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n\n <div class="qr-spacing-section" style="margin-bottom: 1rem;">\n <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.5rem;">\n <h4 style="margin: 0; font-size: 0.875rem;">Padding</h4>\n <button type="button"\n class="qr-chainlink ${t.locked?"locked":""}"\n data-action="toggle-lock"\n data-field="spacing.locked"\n title="${t.locked?"Unlock":"Lock"} sides"\n style="background: none; border: 1px solid var(--dm-border, #dee2e6); border-radius: 4px; padding: 4px 8px; cursor: pointer;">\n ${t.locked?"🔒":"🔓"}\n </button>\n </div>\n <div class="qr-spacing-inputs" style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem;">\n <input type="number" data-field="spacing.padding.top" value="${t.padding.top}" placeholder="Top" class="qr-input" style="width: 100%;">\n <input type="number" data-field="spacing.padding.right" value="${t.padding.right}" placeholder="Right" class="qr-input" style="width: 100%;">\n <input type="number" data-field="spacing.padding.bottom" value="${t.padding.bottom}" placeholder="Bottom" class="qr-input" style="width: 100%;">\n <input type="number" data-field="spacing.padding.left" value="${t.padding.left}" placeholder="Left" class="qr-input" style="width: 100%;">\n </div>\n </div>\n\n <div class="qr-spacing-section" style="margin-bottom: 1rem;">\n <h4 style="margin: 0 0 0.5rem 0; font-size: 0.875rem;">Margin</h4>\n <div class="qr-spacing-inputs" style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem;">\n <input type="number" data-field="spacing.margin.top" value="${t.margin.top}" placeholder="Top" class="qr-input" style="width: 100%;">\n <input type="number" data-field="spacing.margin.right" value="${t.margin.right}" placeholder="Right" class="qr-input" style="width: 100%;">\n <input type="number" data-field="spacing.margin.bottom" value="${t.margin.bottom}" placeholder="Bottom" class="qr-input" style="width: 100%;">\n <input type="number" data-field="spacing.margin.left" value="${t.margin.left}" placeholder="Left" class="qr-input" style="width: 100%;">\n </div>\n </div>\n\n <div class="qr-spacing-section">\n <h4 style="margin: 0 0 0.5rem 0; font-size: 0.875rem;">Gutter (Column Gap)</h4>\n <div style="display: flex; gap: 0.5rem; align-items: center;">\n <input type="range"\n min="0"\n max="10"\n step="0.5"\n value="${t.gutter}"\n data-field="spacing.gutter"\n class="qr-gutter-slider"\n style="flex: 1;">\n <span class="qr-gutter-value" style="min-width: 50px;">${t.gutter}rem</span>\n </div>\n </div>\n </div>\n `;case"height-controls":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n <select class="qr-select" data-field="height.type" style="margin-bottom: 0.5rem;">\n <option value="auto" ${"auto"===t.type?"selected":""}>Auto</option>\n <option value="min" ${"min"===t.type?"selected":""}>Minimum</option>\n <option value="max" ${"max"===t.type?"selected":""}>Maximum</option>\n <option value="fixed" ${"fixed"===t.type?"selected":""}>Fixed</option>\n </select>\n ${"auto"!==t.type?`\n <div style="display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.5rem;">\n <input type="number"\n class="qr-input qr-height-value"\n data-field="height.value"\n value="${t.value||300}"\n min="0"\n step="10"\n style="flex: 1;">\n <span>px</span>\n </div>\n `:""}\n <label class="qr-checkbox">\n <input type="checkbox"\n ${t.equalize?"checked":""}\n data-field="height.equalize">\n <span>Equalize Column Heights</span>\n </label>\n </div>\n `;case"alignment-controls":const o=t.horizontal||"start",r=t.vertical||"start";return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n\n <div class="qr-align-section" style="margin-bottom: 1rem;">\n <label style="display: block; font-size: 0.875rem; margin-bottom: 0.5rem;">Horizontal</label>\n <div class="qr-btn-group" style="display: flex; gap: 0.25rem;">\n ${["start","center","end","stretch"].map(e=>`\n <button type="button"\n class="qr-align-btn ${o===e?"active":""}"\n data-field="alignment.horizontal"\n data-value="${e}"\n style="flex: 1; padding: 0.5rem; border: 1px solid var(--dm-border, #dee2e6); background: ${o===e?"var(--dm-primary, #6495ED)":"var(--dm-surface, #fff)"}; color: ${o===e?"white":"inherit"}; border-radius: 4px; cursor: pointer;">\n ${e}\n </button>\n `).join("")}\n </div>\n </div>\n\n <div class="qr-align-section">\n <label style="display: block; font-size: 0.875rem; margin-bottom: 0.5rem;">Vertical</label>\n <div class="qr-btn-group" style="display: flex; gap: 0.25rem;">\n ${["start","center","end","stretch"].map(e=>`\n <button type="button"\n class="qr-align-btn ${r===e?"active":""}"\n data-field="alignment.vertical"\n data-value="${e}"\n style="flex: 1; padding: 0.5rem; border: 1px solid var(--dm-border, #dee2e6); background: ${r===e?"var(--dm-primary, #6495ED)":"var(--dm-surface, #fff)"}; color: ${r===e?"white":"inherit"}; border-radius: 4px; cursor: pointer;">\n ${e}\n </button>\n `).join("")}\n </div>\n </div>\n </div>\n `;case"responsive-controls":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n\n <div class="qr-responsive-section" style="margin-bottom: 0.75rem;">\n <label style="display: block; font-size: 0.875rem; margin-bottom: 0.25rem;">Mobile (<576px)</label>\n <select data-field="responsive.mobile" class="qr-select">\n <option value="stack" ${"stack"===t.mobile?"selected":""}>Stack</option>\n <option value="keep" ${"keep"===t.mobile?"selected":""}>Keep Layout</option>\n <option value="hide" ${"hide"===t.mobile?"selected":""}>Hide</option>\n </select>\n </div>\n\n <div class="qr-responsive-section" style="margin-bottom: 0.75rem;">\n <label style="display: block; font-size: 0.875rem; margin-bottom: 0.25rem;">Tablet (576-768px)</label>\n <select data-field="responsive.tablet" class="qr-select">\n <option value="stack" ${"stack"===t.tablet?"selected":""}>Stack</option>\n <option value="keep" ${"keep"===t.tablet?"selected":""}>Keep Layout</option>\n <option value="hide" ${"hide"===t.tablet?"selected":""}>Hide</option>\n </select>\n </div>\n\n <div class="qr-responsive-section">\n <label style="display: block; font-size: 0.875rem; margin-bottom: 0.25rem;">Desktop (>768px)</label>\n <select data-field="responsive.desktop" class="qr-select">\n <option value="keep" ${"keep"===t.desktop?"selected":""}>Keep Layout</option>\n <option value="hide" ${"hide"===t.desktop?"selected":""}>Hide</option>\n </select>\n </div>\n </div>\n `;case"background-controls":return`\n <div class="qr-field" data-field="${e.key}">\n <label class="qr-field-label">${e.label}</label>\n <select class="qr-select qr-bg-type" data-field="background.type" style="margin-bottom: 0.5rem;">\n <option value="none" ${"none"===t.type?"selected":""}>None</option>\n <option value="color" ${"color"===t.type?"selected":""}>Solid Colour</option>\n <option value="gradient" ${"gradient"===t.type?"selected":""}>Gradient</option>\n <option value="image" ${"image"===t.type?"selected":""}>Image</option>\n </select>\n ${"color"===t.type?`\n <input type="color"\n class="qr-bg-color"\n data-field="background.color"\n value="${t.color||"#ffffff"}"\n style="width: 100%; height: 40px;">\n `:""}\n ${"gradient"===t.type?`\n <input type="text"\n class="qr-input qr-bg-gradient"\n data-field="background.gradient"\n value="${this._escapeHtml(t.gradient||"")}"\n placeholder="linear-gradient(...)">\n `:""}\n ${"image"===t.type?`\n <input type="text"\n class="qr-input qr-bg-image"\n data-field="background.image"\n value="${this._escapeHtml(t.image||"")}"\n placeholder="Image URL">\n `:""}\n </div>\n `;default:return""}}_renderCanvasSections(){let e="";0===this._sections.length?e='\n <div class="qr-drop-zone qr-drop-zone-empty" data-position="0">\n <span data-icon="plus" data-icon-size="24"></span>\n <span>Click a section or drag here to add</span>\n </div>\n ':(e='<div class="qr-drop-zone" data-position="0"></div>',this._sections.forEach((t,n)=>{const a=m[t.type],i=n===this._selectedIndex;e+=`\n <div class="qr-section ${i?"qr-selected":""}"\n data-index="${n}"\n data-type="${t.type}"\n draggable="true">\n <div class="qr-section-header">\n <span data-icon="${a?.icon||"box"}" data-icon-size="16"></span>\n <span class="qr-section-name">${a?.name||t.type}</span>\n </div>\n <div class="qr-section-preview">\n ${this._getSectionPreviewLabel(t)}\n </div>\n <div class="qr-section-controls">\n <button data-action="move-up" title="Move Up" ${0===n?"disabled":""}>\n <span data-icon="chevron-up" data-icon-size="14"></span>\n </button>\n <button data-action="move-down" title="Move Down" ${n===this._sections.length-1?"disabled":""}>\n <span data-icon="chevron-down" data-icon-size="14"></span>\n </button>\n <button data-action="duplicate" title="Duplicate">\n <span data-icon="copy" data-icon-size="14"></span>\n </button>\n <button data-action="delete" title="Delete">\n <span data-icon="trash" data-icon-size="14"></span>\n </button>\n </div>\n </div>\n <div class="qr-drop-zone" data-position="${n+1}"></div>\n `})),this._refs.canvas.innerHTML=e,"undefined"!=typeof Domma&&Domma.icons&&Domma.icons.scan(this._refs.canvas)}_getSectionPreviewLabel(e){const t=e.config;switch(e.type){case"hero":return this._escapeHtml(t.title||"Untitled Hero");case"cardGrid":return`${t.cards?.length||0} cards, ${t.columns} columns`;case"form":return this._escapeHtml(t.title||"Untitled Form");case"footer":return`${this._capitalize(t.style)} style`;case"content":return this._escapeHtml(t.title||"Content Block");case"navbar":return this._escapeHtml(t.brandText||"Navigation");default:return e.type}}_refreshPreview(){if(!this._refs.preview)return;const e=this._generatePreviewHTML();this._refs.preview.srcdoc=e}_generatePreviewHTML(){const e=getComputedStyle(document.documentElement),t=["--dm-primary","--dm-primary-hover","--dm-secondary","--dm-success","--dm-danger","--dm-warning","--dm-info","--dm-text","--dm-text-muted","--dm-background","--dm-surface","--dm-border","--dm-hover-bg","--dm-gray-100","--dm-gray-200","--dm-gray-300","--dm-gray-400","--dm-gray-500","--dm-gray-600","--dm-gray-700","--dm-gray-800","--dm-gray-900","--dm-radius-sm","--dm-radius-md","--dm-radius-lg","--dm-radius-xl","--dm-radius-full","--dm-shadow-sm","--dm-shadow-md","--dm-shadow-lg","--dm-shadow-xl","--dm-font-sans","--dm-font-mono","--dm-text-xs","--dm-text-sm","--dm-text-base","--dm-text-lg","--dm-text-xl","--dm-text-2xl","--dm-text-3xl","--dm-transition-fast","--dm-transition-normal"];let n=":root {\n";for(const a of t){const t=e.getPropertyValue(a);t&&(n+=` ${a}: ${t.trim()};\n`)}n+="}\n";const a=`\n ${n}\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: var(--dm-font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n color: var(--dm-text, #212529);\n background: var(--dm-background, #fff);\n line-height: 1.5;\n }\n .container { max-width: 1200px; margin: 0 auto; padding: 0 1rem; }\n .text-center { text-align: center; }\n .text-left { text-align: left; }\n .text-right { text-align: right; }\n .text-muted { color: var(--dm-text-muted, #6c757d); }\n .mb-2 { margin-bottom: 0.5rem; }\n .mb-3 { margin-bottom: 0.75rem; }\n .mb-4 { margin-bottom: 1rem; }\n .mb-6 { margin-bottom: 1.5rem; }\n .mb-8 { margin-bottom: 2rem; }\n .mt-3 { margin-top: 0.75rem; }\n .mt-4 { margin-top: 1rem; }\n .mt-6 { margin-top: 1.5rem; }\n .py-6 { padding-top: 1.5rem; padding-bottom: 1.5rem; }\n .py-8 { padding-top: 2rem; padding-bottom: 2rem; }\n .py-12 { padding-top: 3rem; padding-bottom: 3rem; }\n .py-16 { padding-top: 4rem; padding-bottom: 4rem; }\n .pt-4 { padding-top: 1rem; }\n .text-sm { font-size: 0.875rem; }\n .text-xl { font-size: 1.25rem; }\n .text-2xl { font-size: 1.5rem; }\n .text-3xl { font-size: 1.875rem; }\n .font-bold { font-weight: 700; }\n .font-semibold { font-weight: 600; }\n .max-w-lg { max-width: 32rem; }\n .max-w-3xl { max-width: 48rem; }\n .mx-auto { margin-left: auto; margin-right: auto; }\n .opacity-75 { opacity: 0.75; }\n\n /* Grid */\n .grid { display: grid; }\n .grid-cols-1 { grid-template-columns: repeat(1, 1fr); }\n .grid-cols-2 { grid-template-columns: repeat(2, 1fr); }\n .grid-cols-3 { grid-template-columns: repeat(3, 1fr); }\n .grid-cols-4 { grid-template-columns: repeat(4, 1fr); }\n .grid-cols-5 { grid-template-columns: repeat(5, 1fr); }\n .grid-cols-6 { grid-template-columns: repeat(6, 1fr); }\n .gap-2 { gap: 0.5rem; }\n .gap-4 { gap: 1rem; }\n .gap-6 { gap: 1.5rem; }\n\n /* Row/Col */\n .row { display: flex; flex-wrap: wrap; gap: 1rem; }\n .col-6 { flex: 0 0 calc(50% - 0.5rem); }\n .align-center { align-items: center; }\n\n /* Hero */\n .hero { position: relative; }\n .hero-title { font-size: 2.5rem; font-weight: 700; margin-bottom: 1rem; }\n .hero-subtitle { font-size: 1.125rem; opacity: 0.9; max-width: 600px; margin: 0 auto; }\n .hero-buttons { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }\n\n /* Buttons */\n .btn {\n display: inline-flex; align-items: center; justify-content: center;\n padding: 0.625rem 1.25rem; border-radius: var(--dm-radius-md, 0.375rem);\n font-weight: 500; text-decoration: none; cursor: pointer;\n border: 1px solid transparent; transition: all 0.15s ease;\n }\n .btn-primary { background: var(--dm-primary, #6495ED); color: white; }\n .btn-primary:hover { background: var(--dm-primary-hover, #5280d8); }\n .btn-secondary { background: var(--dm-secondary, #6c757d); color: white; }\n .btn-outline { background: transparent; border-color: currentColor; }\n .btn-link { background: none; border: none; color: var(--dm-primary, #6495ED); padding: 0; }\n .btn-block { width: 100%; }\n .btn-sm { padding: 0.375rem 0.75rem; font-size: 0.875rem; }\n\n /* Cards */\n .card {\n background: var(--dm-surface, #fff);\n border: 1px solid var(--dm-border, #dee2e6);\n border-radius: var(--dm-radius-lg, 0.5rem);\n overflow: hidden;\n }\n .card-bordered { border-width: 2px; }\n .card-shadow { box-shadow: var(--dm-shadow-md); }\n .card-minimal { border: none; background: transparent; }\n .card-body { padding: 1.25rem; }\n .card-title { font-size: 1.125rem; font-weight: 600; margin-bottom: 0.5rem; }\n .card-text { color: var(--dm-text-muted, #6c757d); font-size: 0.875rem; }\n .card-img-top { width: 100%; height: auto; }\n .card-icon { color: var(--dm-primary, #6495ED); }\n\n /* Forms */\n .form-group { margin-bottom: 1rem; }\n .form-group label { display: block; margin-bottom: 0.375rem; font-weight: 500; }\n .form-input {\n width: 100%; padding: 0.625rem 0.875rem;\n border: 1px solid var(--dm-border, #dee2e6);\n border-radius: var(--dm-radius-md, 0.375rem);\n font-size: 1rem; font-family: inherit;\n background: var(--dm-background, #fff);\n color: var(--dm-text, #212529);\n }\n .form-input:focus { outline: none; border-color: var(--dm-primary, #6495ED); }\n textarea.form-input { resize: vertical; min-height: 100px; }\n .text-danger { color: var(--dm-danger, #dc3545); }\n\n /* Footer */\n .footer { color: inherit; }\n .footer a { color: inherit; text-decoration: none; opacity: 0.8; }\n .footer a:hover { opacity: 1; }\n .footer-nav { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }\n .footer-social { display: flex; gap: 1rem; justify-content: center; margin-bottom: 1rem; }\n .footer-copyright { opacity: 0.7; font-size: 0.875rem; }\n .footer-column-title { font-weight: 600; margin-bottom: 0.75rem; }\n .footer-links { list-style: none; }\n .footer-links li { margin-bottom: 0.5rem; }\n .footer-bottom { border-top: 1px solid rgba(255,255,255,0.1); }\n\n /* Navbar */\n .navbar {\n display: flex; align-items: center; padding: 1rem 0;\n background: var(--dm-surface, #fff);\n }\n .navbar-dark { background: var(--dm-gray-800, #343a40); color: white; }\n .navbar-light { background: var(--dm-surface, #fff); color: var(--dm-text, #212529); }\n .navbar-transparent { background: transparent; }\n .navbar-sticky { position: sticky; top: 0; z-index: 100; }\n .navbar .container { display: flex; align-items: center; justify-content: space-between; width: 100%; }\n .navbar-brand { font-weight: 600; font-size: 1.25rem; text-decoration: none; color: inherit; }\n .navbar-nav { display: flex; gap: 1.5rem; }\n .nav-link { text-decoration: none; color: inherit; opacity: 0.8; }\n .nav-link:hover { opacity: 1; }\n .navbar-actions { display: flex; gap: 0.5rem; }\n\n /* Images */\n .img-fluid { max-width: 100%; height: auto; }\n .rounded { border-radius: var(--dm-radius-lg, 0.5rem); }\n\n /* Content */\n .content p { margin-bottom: 1rem; }\n .content h1, .content h2, .content h3 { margin-bottom: 0.75rem; }\n `,i=[];this._pageConfig.theme&&i.push(`dm-theme-${this._pageConfig.theme}`),this._pageConfig.variant&&i.push(`dm-theme-${this._pageConfig.variant}`);let s="";for(const e of this._sections){const t=m[e.type];t?.template&&(s+=t.template(e.config),s+="\n")}s||(s='\n <div style="display: flex; align-items: center; justify-content: center; height: 100vh; color: var(--dm-text-muted);">\n <div style="text-align: center;">\n <p style="font-size: 1.25rem; margin-bottom: 0.5rem;">No sections yet</p>\n <p style="font-size: 0.875rem;">Click a section from the library to add it</p>\n </div>\n </div>\n ');let o="";const r=document.querySelector('link[href*="domma-themes"]');return r&&(o=new URL(r.getAttribute("href"),window.location.href).href),`<!DOCTYPE html>\n<html lang="en">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>Preview</title>\n ${o?`<link rel="stylesheet" href="${o}">`:""}\n <style>${a}</style>\n</head>\n<body${i.length?` class="${i.join(" ")}"`:""}>\n${s}\n</body>\n</html>`}_renderSectionHTML(e){if("row"===e.type)return this._renderRowHTML(e);const t=m[e.type];return t?.template(e.config)||""}_renderRowHTML(e){const t=e.config,n=e.children||[],a=["display: grid",`grid-template-columns: ${t.columns.map(e=>`${(100*e.width).toFixed(2)}%`).join(" ")}`,`gap: ${t.spacing.gutter}rem`,`padding: ${t.spacing.padding.top}rem ${t.spacing.padding.right}rem ${t.spacing.padding.bottom}rem ${t.spacing.padding.left}rem`,`margin: ${t.spacing.margin.top}rem ${t.spacing.margin.right}rem ${t.spacing.margin.bottom}rem ${t.spacing.margin.left}rem`,"min"===t.height.type?`min-height: ${t.height.value}px`:"","max"===t.height.type?`max-height: ${t.height.value}px`:"","fixed"===t.height.type?`height: ${t.height.value}px`:"",`align-items: ${t.alignment.vertical}`,`justify-items: ${t.alignment.horizontal}`,"color"===t.background.type?`background-color: ${t.background.color}`:"","gradient"===t.background.type?`background: ${t.background.gradient}`:"","image"===t.background.type?`background-image: url('${t.background.image}'); background-size: cover; background-position: center`:""].filter(Boolean).join("; ");let i="pr-row";"stack"===t.responsive.mobile&&(i+=" pr-row-stack-mobile"),"stack"===t.responsive.tablet&&(i+=" pr-row-stack-tablet"),"hide"!==t.responsive.mobile&&"hide"!==t.responsive.tablet&&"hide"!==t.responsive.desktop||(i+=" pr-row-responsive");const s=t.columns.map((e,t)=>n.filter(e=>e.columnIndex===t)).map((e,t)=>` <div class="pr-column" data-column="${t}">\n${e.map(e=>this._renderSectionHTML(e.section)).join("\n")||" \x3c!-- Empty column --\x3e"}\n </div>`).join("\n");return`<section class="${i}" style="${a}"${"hide"===t.responsive.mobile?' data-hide-mobile="true"':""}${"hide"===t.responsive.tablet?' data-hide-tablet="true"':""}${"hide"===t.responsive.desktop?' data-hide-desktop="true"':""}>\n${s}\n</section>`}_showSaveDialog(){const e=prompt("Enter template name:",this._templateName||"My Template");e&&this.saveTemplate(e)}_toggleTemplatesMenu(){const e=this.element.querySelector(".qr-templates-menu"),t=u.list();0===t.length?e.innerHTML='<div class="qr-menu-empty">No saved templates</div>':e.innerHTML=t.map(e=>`\n <div class="qr-menu-item" data-template="${this._escapeHtml(e)}">\n <span data-icon="document" data-icon-size="14"></span>\n <span>${this._escapeHtml(e)}</span>\n </div>\n `).join(""),e.classList.toggle("qr-visible"),"undefined"!=typeof Domma&&Domma.icons&&Domma.icons.scan(e)}_duplicateSection(e){if(e<0||e>=this._sections.length)return;const t=this._sections[e],n={type:t.type,config:JSON.parse(JSON.stringify(t.config))};this._sections.splice(e+1,0,n),this._markDirty(),this._renderCanvasSections(),this._refreshPreview(),this._selectSection(e+1)}_getPageData(){return{version:2,name:this._templateName,config:{...this._pageConfig},sections:this._sections.map(e=>this._serializeSection(e))}}_serializeSection(e){const t={type:e.type,config:{...e.config}};return"row"===e.type&&e.children&&(t.children=e.children.map(e=>({columnIndex:e.columnIndex,section:this._serializeSection(e.section)}))),t}_loadPageData(e){if(!e)return;const t=this._migrateV1ToV2(e);this._templateName=t.name||"",this._pageConfig={...this._pageConfig,...t.config},this._sections=(t.sections||[]).map(e=>this._deserializeSection(e)),this._selectedIndex=-1}_migrateV1ToV2(e){return 2===e.version?e:{version:2,name:e.name||"Untitled",config:e.config||{},sections:e.sections?e.sections.map(e=>({type:"row",config:{...m.row.defaults,layout:"single",columns:[{width:1}]},children:[{columnIndex:0,section:e}]})):[]}}_deserializeSection(e){const t={type:e.type,config:{...m[e.type]?.defaults||{},...e.config}};return"row"===e.type&&e.children&&(t.children=e.children.map(e=>({columnIndex:e.columnIndex,section:this._deserializeSection(e.section)}))),t}_escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}_capitalize(e){return e.charAt(0).toUpperCase()+e.slice(1)}_showToast(e,t="info"){"undefined"!=typeof Domma&&Domma.elements?.toast?Domma.elements.toast[t]?.(e,{position:"bottom-center",duration:3e3})||Domma.elements.toast.show(e):console.log(`[PageRoller] ${e}`)}addSection(e,t){const n=m[e];if(!n)return console.error(`PageRoller: Unknown section type "${e}"`),this;const a={type:e,config:{...n.defaults}};return"number"==typeof t&&t>=0&&t<=this._sections.length?(this._sections.splice(t,0,a),this._selectedIndex=t):(this._sections.push(a),this._selectedIndex=this._sections.length-1),this._markDirty(),this._renderCanvasSections(),this._renderEditor(),this._refreshPreview(),this}removeSection(e){return e<0||e>=this._sections.length||(this._sections.splice(e,1),this._selectedIndex===e?this._selectedIndex=-1:this._selectedIndex>e&&this._selectedIndex--,this._markDirty(),this._renderCanvasSections(),this._renderEditor(),this._refreshPreview()),this}moveSection(e,t){if(e<0||e>=this._sections.length)return this;if(t<0||t>this._sections.length)return this;if(e===t)return this;const[n]=this._sections.splice(e,1),a=t>e?t-1:t;return this._sections.splice(a,0,n),this._selectedIndex===e&&(this._selectedIndex=a),this._markDirty(),this._renderCanvasSections(),this._refreshPreview(),this}updateSection(e,t){return e<0||e>=this._sections.length||(this._sections[e].config={...this._sections[e].config,...t},this._markDirty(),this._refreshPreview(),e===this._selectedIndex&&this._renderEditor()),this}getSection(e){return this._sections[e]||null}getSections(){return[...this._sections]}setTheme(e,t){this._pageConfig.theme=e,void 0!==t&&(this._pageConfig.variant=t);const n=this.element.querySelector(".qr-theme-select"),a=this.element.querySelector(".qr-variant-select");return n&&(n.value=e||""),a&&(a.value=t||""),this._markDirty(),this._refreshPreview(),this}setGridEnabled(e){this._pageConfig.useGrid=e;const t=this.element.querySelector(".qr-grid-toggle");return t&&(t.checked=e),this._markDirty(),this._refreshPreview(),this}getPageConfig(){return{...this._pageConfig}}exportHTML(e={}){const{minify:t=!1,includeComments:n=!0,standalone:a=!0}=e;let i="";if(a){i+="<!DOCTYPE html>\n",i+='<html lang="en">\n',i+="<head>\n",i+=` <meta charset="${this._pageConfig.meta.charset}">\n`,i+=` <meta name="viewport" content="${this._pageConfig.meta.viewport}">\n`,i+=` <title>${this._escapeHtml(this._pageConfig.meta.title)}</title>\n`,this._pageConfig.meta.description&&(i+=` <meta name="description" content="${this._escapeHtml(this._pageConfig.meta.description)}">\n`),this._pageConfig.useTheme&&(i+=' <link rel="stylesheet" href="domma-themes.css">\n'),this._pageConfig.useGrid&&(i+=' <link rel="stylesheet" href="domma.css">\n'),this._pageConfig.customCSS&&(i+=" <style>\n",i+=this._pageConfig.customCSS,i+="\n </style>\n"),i+="</head>\n";const e=[];this._pageConfig.theme&&e.push(`dm-theme-${this._pageConfig.theme}`),this._pageConfig.variant&&e.push(`dm-theme-${this._pageConfig.variant}`),i+=`<body${e.length?` class="${e.join(" ")}"`:""}>\n`}for(const e of this._sections){const t=m[e.type];t&&(n&&(i+=`\n\x3c!-- ${t.name} Section --\x3e\n`),i+=this._renderSectionHTML(e),i+="\n")}return a&&(i+='\n <script src="domma.min.js"><\/script>\n',i+=" <script>\n",i+=" // Initialise Domma\n",i+=' document.addEventListener("DOMContentLoaded", function() {\n',i+=" // Scan and initialise icons\n",i+=" if (window.Domma && Domma.icons) Domma.icons.scan();\n",i+="\n",i+=" // Auto-init carousels\n",i+=" document.querySelectorAll(\"[data-component='carousel']\").forEach(function(el) {\n",i+=' var carousel = el.querySelector(".carousel");\n',i+=" if (carousel && Domma.elements && Domma.elements.carousel) {\n",i+=" Domma.elements.carousel(carousel, {\n",i+=' autoplay: carousel.dataset.autoplay === "true",\n',i+=" interval: parseInt(carousel.dataset.interval) || 5000,\n",i+=' pauseOnHover: carousel.dataset.pauseHover === "true",\n',i+=' loop: carousel.dataset.loop === "true",\n',i+=' animation: carousel.dataset.animation || "slide"\n',i+=" });\n",i+=" }\n",i+=" });\n",i+="\n",i+=" // Auto-init accordions\n",i+=" document.querySelectorAll(\"[data-component='accordion']\").forEach(function(el) {\n",i+=' var accordion = el.querySelector(".accordion");\n',i+=" if (accordion && Domma.elements && Domma.elements.accordion) {\n",i+=" Domma.elements.accordion(accordion, {\n",i+=' allowMultiple: accordion.dataset.allowMultiple === "true",\n',i+=' animation: accordion.dataset.animation !== "false"\n',i+=" });\n",i+=" }\n",i+=" });\n",i+="\n",i+=" // Auto-init tabs\n",i+=" document.querySelectorAll(\"[data-component='tabs']\").forEach(function(el) {\n",i+=' var tabs = el.querySelector(".tabs");\n',i+=" if (tabs && Domma.elements && Domma.elements.tabs) {\n",i+=" Domma.elements.tabs(tabs, {\n",i+=' animation: tabs.dataset.animation || "fade"\n',i+=" });\n",i+=" }\n",i+=" });\n",i+="\n",i+=" // Auto-init modals\n",i+=" document.querySelectorAll(\"[data-component='modal']\").forEach(function(el) {\n",i+=' var modal = el.querySelector(".modal");\n',i+=' var trigger = el.querySelector("[data-modal-trigger]");\n',i+=" if (modal && trigger && Domma.elements && Domma.elements.modal) {\n",i+=" var instance = Domma.elements.modal(modal, {\n",i+=' backdrop: modal.dataset.backdrop !== "false",\n',i+=' keyboard: modal.dataset.keyboard !== "false",\n',i+=' animation: modal.dataset.animation !== "false"\n',i+=" });\n",i+=' trigger.addEventListener("click", function() { instance.open(); });\n',i+=" }\n",i+=" });\n",i+="\n",i+=" // Auto-init toast triggers\n",i+=' document.querySelectorAll("[data-toast-trigger]").forEach(function(trigger) {\n',i+=' trigger.addEventListener("click", function() {\n',i+=" if (Domma.elements && Domma.elements.toast) {\n",i+=" Domma.elements.toast({\n",i+=' message: trigger.dataset.toastMessage || "Notification",\n',i+=' type: trigger.dataset.toastType || "info",\n',i+=' position: trigger.dataset.toastPosition || "top-right",\n',i+=" duration: parseInt(trigger.dataset.toastDuration) || 3000\n",i+=" });\n",i+=" }\n",i+=" });\n",i+=" });\n",i+="\n",i+=" // Auto-init breadcrumbs\n",i+=" document.querySelectorAll(\"[data-component='breadcrumbs']\").forEach(function(el) {\n",i+=' var breadcrumbs = el.querySelector(".breadcrumbs");\n',i+=" if (breadcrumbs && Domma.elements && Domma.elements.breadcrumbs) {\n",i+=" Domma.elements.breadcrumbs(breadcrumbs);\n",i+=" }\n",i+=" });\n",i+="\n",i+=" // Auto-init button groups\n",i+=" document.querySelectorAll(\"[data-component='button-group']\").forEach(function(el) {\n",i+=' var btnGroup = el.querySelector(".btn-group");\n',i+=" if (btnGroup && Domma.elements && Domma.elements.buttonGroup) {\n",i+=" Domma.elements.buttonGroup(btnGroup, {\n",i+=' mode: btnGroup.dataset.mode || "single"\n',i+=" });\n",i+=" }\n",i+=" });\n",i+="\n",i+=" // Auto-init dropdowns\n",i+=" document.querySelectorAll(\"[data-component='dropdown']\").forEach(function(el) {\n",i+=' var dropdown = el.querySelector(".dropdown");\n',i+=" if (dropdown && Domma.elements && Domma.elements.dropdown) {\n",i+=" Domma.elements.dropdown(dropdown, {\n",i+=' position: dropdown.dataset.position || "bottom"\n',i+=" });\n",i+=" }\n",i+=" });\n",i+=" });\n",i+=" <\/script>\n",i+="</body>\n",i+="</html>\n"),t?i.replace(/\n\s*/g,""):i}async copyToClipboard(){const e=this.exportHTML({standalone:!0});return await l.copyToClipboard(e),this._showToast("HTML copied to clipboard","success"),this.options.onExport&&this.options.onExport({type:"copy",html:e}),this}download(e){const t=e||this._templateName||"page",n=this.exportHTML({standalone:!0}),a=new Blob([n],{type:"text/html"}),i=URL.createObjectURL(a),s=document.createElement("a");return s.href=i,s.download=`${t}.html`,document.body.appendChild(s),s.click(),document.body.removeChild(s),URL.revokeObjectURL(i),this._showToast("Page downloaded","success"),this.options.onExport&&this.options.onExport({type:"download",filename:t,html:n}),this}saveToStorage(){return u.saveActive(this._getPageData()),this._isDirty=!1,this._showToast("Page saved to browser","success"),this}saveTemplate(e){return this._templateName=e,this._refs.templateName.value=e,u.save(e,this._getPageData()),this._isDirty=!1,this._showToast(`Template "${e}" saved`,"success"),this.options.onSave&&this.options.onSave({name:e,data:this._getPageData()}),this}loadTemplate(e){const t=u.load(e);if(!t)return this._showToast(`Template "${e}" not found`,"error"),this;this._loadPageData(t),this._refs.templateName.value=this._templateName;const n=this.element.querySelector(".qr-theme-select"),a=this.element.querySelector(".qr-variant-select"),i=this.element.querySelector(".qr-grid-toggle");return n&&(n.value=this._pageConfig.theme||""),a&&(a.value=this._pageConfig.variant||""),i&&(i.checked=this._pageConfig.useGrid),this._renderCanvasSections(),this._renderEditor(),this._refreshPreview(),this._isDirty=!1,this._showToast(`Template "${e}" loaded`,"success"),this}deleteTemplate(e){return u.delete(e)&&this._showToast(`Template "${e}" deleted`,"success"),this}listTemplates(){return u.list()}newPage(){return this._isDirty&&!confirm("You have unsaved changes. Start a new page anyway?")||(this._sections=[],this._selectedIndex=-1,this._templateName="",this._pageConfig={theme:"light",variant:null,useGrid:!0,useTheme:!0,customCSS:"",meta:{title:"My Page",description:"",charset:"UTF-8",viewport:"width=device-width, initial-scale=1.0"}},this._refs.templateName.value="",this.element.querySelector(".qr-theme-select").value="light",this.element.querySelector(".qr-variant-select").value="",this.element.querySelector(".qr-grid-toggle").checked=!0,this._renderCanvasSections(),this._renderEditor(),this._refreshPreview(),this._isDirty=!1,u.clearActive()),this}openPreviewWindow(){const e=this._generatePreviewHTML(),t=window.open("","_blank");return t.document.write(e),t.document.close(),this}refreshPreview(){return this._refreshPreview(),this}destroy(){this._autoSaveTimer&&clearInterval(this._autoSaveTimer);for(const{element:e,event:t,wrapper:n}of this._eventHandlers)e.removeEventListener(t,n);this._eventHandlers=[],this.element.classList.remove("qr-container"),this.element.innerHTML=""}}class b{constructor(e,t={}){this.element="string"==typeof e?document.querySelector(e):e,this.options={...this.constructor.defaults,...t},this._eventHandlers=[],this.element&&(this.element._dommaComponent=this)}on(e,t){this.options[e]&&"function"==typeof this.options[e]&&this.options[e](t)}setOptions(e){return this.options={...this.options,...e},"function"==typeof this._applyOptions&&this._applyOptions(),this}_addEventListener(e,t,n){e.addEventListener(t,n),this._eventHandlers.push({element:e,event:t,handler:n})}destroy(){for(const{element:e,event:t,handler:n}of this._eventHandlers)e.removeEventListener(t,n);this._eventHandlers=[],this.element&&delete this.element._dommaComponent}}const y={string:{name:"Text",icon:"type",category:"basic",description:"Single-line text input",defaults:{type:"string",required:!1,minLength:null,maxLength:null,default:"",label:"",placeholder:"",help:""}},number:{name:"Number",icon:"hash",category:"basic",description:"Numeric input",defaults:{type:"number",required:!1,min:null,max:null,default:0,label:"",placeholder:"",help:""}},boolean:{name:"Checkbox",icon:"check-square",category:"basic",description:"True/false checkbox",defaults:{type:"boolean",required:!1,default:!1,label:"",help:""}},email:{name:"Email",icon:"mail",category:"inputs",description:"Email input with validation",defaults:{type:"email",required:!1,default:"",label:"",placeholder:"",help:""}},password:{name:"Password",icon:"lock",category:"inputs",description:"Password input",defaults:{type:"password",required:!1,minLength:null,default:"",label:"",placeholder:"",help:""}},textarea:{name:"Textarea",icon:"file-text",category:"basic",description:"Multi-line text",defaults:{type:"textarea",required:!1,default:"",label:"",placeholder:"",help:"",formConfig:{rows:3}}},select:{name:"Select",icon:"chevron-down",category:"selection",description:"Dropdown select",defaults:{type:"select",required:!1,options:[],default:"",label:"",help:""}},multiselect:{name:"Multi-select",icon:"list",category:"selection",description:"Multiple selection dropdown",defaults:{type:"multiselect",required:!1,options:[],default:[],label:"",help:""}},radio:{name:"Radio Group",icon:"circle",category:"selection",description:"Radio button group",defaults:{type:"radio",required:!1,options:[],default:"",label:"",help:""}},"checkbox-group":{name:"Checkbox Group",icon:"check-square",category:"selection",description:"Multiple checkboxes",defaults:{type:"checkbox-group",required:!1,options:[],default:[],label:"",help:""}},url:{name:"URL",icon:"link",category:"inputs",description:"URL input with validation",defaults:{type:"url",required:!1,default:"",label:"",placeholder:"https://example.com",help:""}},tel:{name:"Phone",icon:"phone",category:"inputs",description:"Telephone number input",defaults:{type:"tel",required:!1,default:"",label:"",placeholder:"",help:""}},color:{name:"Color",icon:"droplet",category:"inputs",description:"Color picker",defaults:{type:"color",required:!1,default:"#000000",label:"",help:""}},range:{name:"Range",icon:"sliders",category:"inputs",description:"Slider input",defaults:{type:"range",required:!1,min:0,max:100,step:1,default:50,label:"",help:""}},hidden:{name:"Hidden",icon:"eye-off",category:"inputs",description:"Hidden field",defaults:{type:"hidden",required:!1,default:"",label:"",help:""}},file:{name:"File",icon:"paperclip",category:"advanced",description:"File upload",defaults:{type:"file",required:!1,accept:"",multiple:!1,label:"",help:""}},date:{name:"Date",icon:"calendar",category:"datetime",description:"Date picker",defaults:{type:"string",required:!1,default:"",label:"",help:"",validate:e=>{if(!e||""===e)return!0;if(e instanceof Date&&!isNaN(e.getTime()))return!0;if("string"==typeof e){const t=new Date(e);if(!isNaN(t.getTime()))return!0}return"Invalid date format"}}},datetime:{name:"Date & Time",icon:"calendar",category:"datetime",description:"Date and time picker",defaults:{type:"datetime-local",required:!1,default:"",label:"",help:""}},time:{name:"Time",icon:"clock",category:"datetime",description:"Time picker",defaults:{type:"time",required:!1,default:"",label:"",help:""}},array:{name:"Array",icon:"layers",category:"advanced",description:"Array field type",defaults:{type:"array",required:!1,default:[],label:"",help:""}},object:{name:"Object",icon:"box",category:"advanced",description:"Object field type",defaults:{type:"object",required:!1,default:{},label:"",help:""}}};class f{static STORAGE_KEY="domma:schema-builder-templates";static ACTIVE_KEY="domma:schema-builder-active";static list(){try{const e=localStorage.getItem(this.STORAGE_KEY);return e?Object.keys(JSON.parse(e)):[]}catch(e){return[]}}static load(e){try{const t=localStorage.getItem(this.STORAGE_KEY);if(!t)return null;return JSON.parse(t)[e]||null}catch(e){return null}}static save(e,t){try{const n=localStorage.getItem(this.STORAGE_KEY),a=n?JSON.parse(n):{};return a[e]={...t,updatedAt:Date.now()},localStorage.setItem(this.STORAGE_KEY,JSON.stringify(a)),!0}catch(e){return!1}}static delete(e){try{const t=localStorage.getItem(this.STORAGE_KEY);if(!t)return!1;const n=JSON.parse(t);return delete n[e],localStorage.setItem(this.STORAGE_KEY,JSON.stringify(n)),!0}catch(e){return!1}}static saveActive(e){try{return localStorage.setItem(this.ACTIVE_KEY,JSON.stringify(e)),!0}catch(e){return!1}}static loadActive(){try{const e=localStorage.getItem(this.ACTIVE_KEY);return e?JSON.parse(e):null}catch(e){return null}}}"undefined"!=typeof window&&(window.SchemaTemplateManager=f);class v extends b{static defaults={theme:"light",autoSave:!0,autoSaveInterval:3e4,showPreview:!0,previewLayout:"stacked",onChange:null,onSave:null,onExport:null};constructor(e,t={}){super(e,t),this.options={...v.defaults,...t},this._fields=[],this._selectedIndex=-1,this._schemaName="",this._isDirty=!1,this._dragSource=null,this._autoSaveTimer=null,this._previewForm=null,this._refs={},this.element&&this._init()}_init(){this._render(),this._attachEvents();const e=this.element.querySelector(".sb-preview-layout");e&&(e.value=this.options.previewLayout),this.options.showPreview&&this._refs.previewPanel&&(this._refs.previewPanel.style.display="flex",this._refs.previewPanel.style.transform="translateX(0)"),this.options.autoSave&&this._startAutoSave();const t=f.loadActive();t&&t.length>0&&(this._fields=t,this._renderCanvas(),this._renderPreview())}_render(){this.element.innerHTML='\n <div class="sb-container">\n <div class="sb-header">\n <div class="sb-header-left">\n <button class="btn btn-primary btn-sm" data-action="new"><span data-icon="plus-circle"></span> New</button>\n <button class="btn btn-sm" data-action="save"><span data-icon="save"></span> Save</button>\n <button class="btn btn-sm" data-action="load"><span data-icon="folder-open"></span> Load</button>\n <input type="text" class="sb-schema-name" placeholder="Schema Name" value="">\n </div>\n <div class="sb-header-center">\n <h2 class="sb-title">Schema Builder</h2>\n </div>\n <div class="sb-header-right">\n <button class="btn btn-sm btn-primary" data-action="toggle-preview"><span data-icon="eye"></span> Preview</button>\n <button class="btn btn-sm" data-action="import"><span data-icon="upload"></span> Import</button>\n <button class="btn btn-primary btn-sm" data-action="export"><span data-icon="download"></span> Export</button>\n </div>\n </div>\n <div class="sb-body">\n <div class="sb-sidebar sb-library">\n <div class="sb-library-header">\n <h3 style="text-align: center;">Field Library</h3>\n <input type="text" class="sb-search form-input" placeholder="Search fields..." />\n </div>\n <div class="sb-library-content"></div>\n </div>\n <div class="sb-main">\n <div class="sb-canvas"></div>\n </div>\n <div class="sb-sidebar sb-editor">\n <h3 style="text-align: center;">Properties</h3>\n <div class="sb-editor-content">\n <p class="text-muted">Select a field to edit properties</p>\n </div>\n </div>\n </div>\n </div>\n\n \x3c!-- Floating Preview Panel --\x3e\n <div class="sb-preview-panel" style="display: none;">\n <div class="sb-preview-header">\n <h3>Live Preview</h3>\n <div class="sb-preview-controls">\n <label style="font-size: 0.875rem; margin-right: 0.5rem;">Layout:</label>\n <select class="sb-preview-layout form-select" style="display: inline-block; width: auto;">\n <option value="stacked">Stacked</option>\n <option value="inline">Inline</option>\n <option value="grid-2">Grid (2 cols)</option>\n <option value="grid-3">Grid (3 cols)</option>\n <option value="grid-4">Grid (4 cols)</option>\n <option value="grid-6">Grid (6 cols)</option>\n <option value="grid-12">Grid (12 cols)</option>\n </select>\n <button class="btn btn-sm" data-action="close-preview"><span data-icon="x"></span></button>\n </div>\n </div>\n <div class="sb-preview-body">\n <div class="sb-preview-split">\n <div class="sb-preview-form-container">\n <h4>Form</h4>\n <div class="sb-preview-form"></div>\n </div>\n <div class="sb-preview-state-container">\n <h4>Model State</h4>\n <pre class="sb-state-display">{}</pre>\n </div>\n </div>\n </div>\n </div>\n ',this._refs={library:this.element.querySelector(".sb-library-content"),canvas:this.element.querySelector(".sb-canvas"),editor:this.element.querySelector(".sb-editor-content"),previewPanel:this.element.querySelector(".sb-preview-panel"),previewForm:this.element.querySelector(".sb-preview-form"),previewState:this.element.querySelector(".sb-state-display"),schemaName:this.element.querySelector(".sb-schema-name")},this._renderLibrary(),"undefined"!=typeof Domma&&Domma.icons&&Domma.icons.scan(this.element)}_renderLibrary(){const e={basic:[],inputs:[],selection:[],datetime:[]};for(const[t,n]of Object.entries(y))e[n.category]&&e[n.category].push({type:t,...n});let t="";for(const[n,a]of Object.entries(e))if(0!==a.length){t+=`<div class="sb-library-category"><h4 class="sb-category-title">${this._capitalize(n)}</h4><div class="sb-category-items">`;for(const e of a)t+=`<div class="sb-library-item" draggable="true" data-type="${e.type}" title="${this._escapeHtml(e.description)}"><span data-icon="${e.icon}"></span><span class="sb-item-name">${this._escapeHtml(e.name)}</span></div>`;t+="</div></div>"}this._refs.library.innerHTML=t,"undefined"!=typeof Domma&&Domma.icons&&Domma.icons.scan(this._refs.library)}_renderCanvas(){let e='<div class="sb-drop-zone" data-position="0"></div>';this._fields.forEach((t,n)=>{const a=n===this._selectedIndex,i=y[t.type]||{name:t.type,icon:"help-circle"};e+=`\n <div class="sb-field-card ${a?"sb-selected":""}" draggable="true" data-index="${n}">\n <div class="sb-field-header">\n <span data-icon="${i.icon}"></span>\n <span class="sb-field-name">${this._escapeHtml(t.name||"field"+n)}</span>\n <span class="sb-field-type">[${i.name}]</span>\n </div>\n <div class="sb-field-meta">\n ${t.required?'<span class="sb-badge sb-badge-required">Required</span>':""}\n ${t.label?'<span class="sb-field-label">'+this._escapeHtml(t.label)+"</span>":""}\n </div>\n <div class="sb-field-actions">\n <button class="btn btn-sm" data-action="duplicate" data-index="${n}"><span data-icon="copy"></span></button>\n <button class="btn btn-danger btn-sm" data-action="remove" data-index="${n}"><span data-icon="trash"></span></button>\n </div>\n </div>\n <div class="sb-drop-zone" data-position="${n+1}"></div>\n `}),0===this._fields.length&&(e='\n <div class="sb-empty-state">\n <span data-icon="inbox" data-icon-size="48"></span>\n <h3>No fields yet</h3>\n <p>Drag fields from the library or click to add</p>\n </div>\n <div class="sb-drop-zone" data-position="0"></div>\n '),this._refs.canvas.innerHTML=e,"undefined"!=typeof Domma&&Domma.icons&&Domma.icons.scan(this._refs.canvas)}_renderEditor(e){if(e<0||e>=this._fields.length)return void(this._refs.editor.innerHTML='<p class="text-muted">Select a field to edit properties</p>');const t=this._fields[e];let n=`\n <div class="sb-editor-section">\n <h4>Core Properties</h4>\n <div class="sb-editor-field">\n <label>Field Name</label>\n <input type="text" class="form-input" data-prop="name" value="${this._escapeHtml(t.name||"")}" placeholder="fieldName" />\n </div>\n <div class="sb-editor-field">\n <label>Type</label>\n <select class="form-select" data-prop="type">\n ${Object.entries(y).map(([e,n])=>`<option value="${e}" ${t.type===e?"selected":""}>${this._escapeHtml(n.name)}</option>`).join("")}\n </select>\n </div>\n <div class="sb-editor-field">\n <label><input type="checkbox" data-prop="required" ${t.required?"checked":""} /> Required</label>\n </div>\n </div>\n <div class="sb-editor-section">\n <h4>Form Display</h4>\n <div class="sb-editor-field">\n <label>Label</label>\n <input type="text" class="form-input" data-prop="label" value="${this._escapeHtml(t.label||"")}" />\n </div>\n <div class="sb-editor-field">\n <label>Placeholder</label>\n <input type="text" class="form-input" data-prop="placeholder" value="${this._escapeHtml(t.placeholder||"")}" />\n </div>\n <div class="sb-editor-field">\n <label>Help Text</label>\n <input type="text" class="form-input" data-prop="help" value="${this._escapeHtml(t.help||"")}" />\n </div>\n <div class="sb-editor-field">\n <label>Column Span (Grid Layout)</label>\n <select class="form-select" data-prop="formConfig.columns">\n ${[1,2,3,4,5,6,7,8,9,10,11,12].map(e=>`<option value="${e}" ${(t.formConfig?.columns||12)===e?"selected":""}>${e} ${12===e?"(Full Width)":"col"+(e>1?"s":"")}</option>`).join("")}\n </select>\n <small class="text-muted">Width in grid layouts (1-12 columns)</small>\n </div>\n </div>\n `;n+=this._renderFieldSpecificProperties(t),this._refs.editor.innerHTML=n,["select","multiselect","radio","checkbox-group"].includes(t.type)&&this._attachOptionsEditor()}_renderFieldSpecificProperties(e){let t="";if(["string","textarea","email","url","tel","password"].includes(e.type)&&(t+=`\n <div class="sb-editor-section">\n <h4>Validation</h4>\n <div class="sb-editor-field">\n <label>Min Length</label>\n <input type="number" class="form-input" data-prop="minLength" value="${e.minLength||""}" min="0" />\n </div>\n <div class="sb-editor-field">\n <label>Max Length</label>\n <input type="number" class="form-input" data-prop="maxLength" value="${e.maxLength||""}" min="0" />\n </div>\n <div class="sb-editor-field">\n <label>Pattern (Regex)</label>\n <input type="text" class="form-input" data-prop="pattern" value="${this._escapeHtml(e.pattern||"")}" placeholder="^[A-Za-z]+$" />\n </div>\n </div>\n `),"number"!==e.type&&"range"!==e.type||(t+=`\n <div class="sb-editor-section">\n <h4>Validation</h4>\n <div class="sb-editor-field">\n <label>Min Value</label>\n <input type="number" class="form-input" data-prop="min" value="${void 0!==e.min?e.min:""}" />\n </div>\n <div class="sb-editor-field">\n <label>Max Value</label>\n <input type="number" class="form-input" data-prop="max" value="${void 0!==e.max?e.max:""}" />\n </div>\n <div class="sb-editor-field">\n <label>Step</label>\n <input type="number" class="form-input" data-prop="step" value="${e.step||""}" min="0" step="0.01" />\n </div>\n </div>\n `),["date","datetime","time"].includes(e.type)&&(t+=`\n <div class="sb-editor-section">\n <h4>Validation</h4>\n <div class="sb-editor-field">\n <label>Min ${"time"===e.type?"Time":"Date"}</label>\n <input type="${e.type}" class="form-input" data-prop="min" value="${e.min||""}" />\n </div>\n <div class="sb-editor-field">\n <label>Max ${"time"===e.type?"Time":"Date"}</label>\n <input type="${e.type}" class="form-input" data-prop="max" value="${e.max||""}" />\n </div>\n </div>\n `),"file"===e.type&&(t+=`\n <div class="sb-editor-section">\n <h4>File Options</h4>\n <div class="sb-editor-field">\n <label>Accept (file types)</label>\n <input type="text" class="form-input" data-prop="accept" value="${this._escapeHtml(e.accept||"")}" placeholder=".jpg,.png,.pdf" />\n </div>\n <div class="sb-editor-field">\n <label><input type="checkbox" data-prop="multiple" ${e.multiple?"checked":""} /> Allow Multiple Files</label>\n </div>\n </div>\n `),["select","multiselect","radio","checkbox-group"].includes(e.type)){const n=e.options||[];t+=`\n <div class="sb-editor-section">\n <h4>Options</h4>\n <div class="sb-options-editor">\n <div class="sb-options-list" data-options-list>\n ${n.map((e,t)=>`\n <div class="sb-option-item" data-option-index="${t}">\n <div class="sb-option-inputs">\n <input type="text" class="form-input sb-option-value" placeholder="value" value="${this._escapeHtml(e.value||"")}" data-option-part="value" />\n <input type="text" class="form-input sb-option-label" placeholder="Label" value="${this._escapeHtml(e.label||"")}" data-option-part="label" />\n </div>\n <div class="sb-option-actions">\n <button class="btn btn-sm" data-action="move-up" ${0===t?"disabled":""}><span data-icon="chevron-up"></span></button>\n <button class="btn btn-sm" data-action="move-down" ${t===n.length-1?"disabled":""}><span data-icon="chevron-down"></span></button>\n <button class="btn btn-danger btn-sm" data-action="remove-option"><span data-icon="trash"></span></button>\n </div>\n </div>\n `).join("")}\n </div>\n <button class="btn btn-primary btn-sm" data-action="add-option"><span data-icon="plus"></span> Add Option</button>\n </div>\n </div>\n `}return t}_attachOptionsEditor(){this._refs.editor.querySelector("[data-options-list]")&&(this._on(this._refs.editor,"click",'[data-action="add-option"]',()=>{const e=this._fields[this._selectedIndex];e.options||(e.options=[]),e.options.push({value:"",label:""}),this.updateField(this._selectedIndex,{options:e.options}),this._renderEditor(this._selectedIndex)}),this._on(this._refs.editor,"click",'[data-action="remove-option"]',e=>{const t=e.target.closest(".sb-option-item"),n=parseInt(t.dataset.optionIndex),a=this._fields[this._selectedIndex];a.options.splice(n,1),this.updateField(this._selectedIndex,{options:a.options}),this._renderEditor(this._selectedIndex)}),this._on(this._refs.editor,"click",'[data-action="move-up"]',e=>{const t=e.target.closest(".sb-option-item"),n=parseInt(t.dataset.optionIndex);if(0===n)return;const a=this._fields[this._selectedIndex],i=a.options[n];a.options[n]=a.options[n-1],a.options[n-1]=i,this.updateField(this._selectedIndex,{options:a.options}),this._renderEditor(this._selectedIndex)}),this._on(this._refs.editor,"click",'[data-action="move-down"]',e=>{const t=e.target.closest(".sb-option-item"),n=parseInt(t.dataset.optionIndex),a=this._fields[this._selectedIndex];if(n===a.options.length-1)return;const i=a.options[n];a.options[n]=a.options[n+1],a.options[n+1]=i,this.updateField(this._selectedIndex,{options:a.options}),this._renderEditor(this._selectedIndex)}),this._on(this._refs.editor,"input","[data-option-part]",e=>{const t=e.target.closest(".sb-option-item"),n=parseInt(t.dataset.optionIndex),a=e.target.dataset.optionPart,i=this._fields[this._selectedIndex];i.options[n][a]=e.target.value,this.updateField(this._selectedIndex,{options:i.options})}))}_renderPreview(){if(!this.options.showPreview)return;if(this._refs.previewForm&&this._refs.previewState||(this._refs.previewForm=this.element.querySelector(".sb-preview-form"),this._refs.previewState=this.element.querySelector(".sb-state-display"),this._refs.previewPanel=this.element.querySelector(".sb-preview-panel")),!this._refs.previewForm||!this._refs.previewState)return;this._previewForm&&this._previewForm.destroy&&this._previewForm.destroy();const e=this._toBlueprint();if(0===Object.keys(e).length)return this._refs.previewForm.innerHTML='<p class="text-muted">No fields to preview</p>',void(this._refs.previewState.textContent="{}");if("undefined"!=typeof Domma&&Domma.forms)try{this._refs.previewForm.innerHTML="";let t=this.options.previewLayout,n=2;"grid-2"===t?(t="grid",n=2):"grid-3"===t?(t="grid",n=3):"grid-4"===t?(t="grid",n=4):"grid-6"===t?(t="grid",n=6):"grid-12"===t&&(t="grid",n=12),this._previewForm=Domma.forms.create(e,{},{layout:t,columns:n,submitText:"Test Submit",showReset:!1,onSubmit:async e=>{const t=this._previewForm.model.validate();if(!0===t)"undefined"!=typeof Domma&&Domma.elements&&Domma.elements.alert?await Domma.elements.alert(`<strong>✓ Validation Passed!</strong><br><br>Submitted Data:<br><pre style="text-align: left; margin-top: 10px;">${JSON.stringify(e,null,2)}</pre>`,{title:"Form Submission Test"}):alert("✓ Validation passed!\n\nSubmitted data:\n"+JSON.stringify(e,null,2));else{const e=Object.entries(t).map(([e,t])=>`• ${e}: ${t}`).join("\n");"undefined"!=typeof Domma&&Domma.elements&&Domma.elements.alert?await Domma.elements.alert(`<strong>✗ Validation Failed</strong><br><br>${e.replace(/\n/g,"<br>")}`,{title:"Form Validation Errors"}):alert("✗ Validation failed:\n\n"+e)}}}),this._previewForm.renderTo(this._refs.previewForm);const a=()=>{this._previewForm&&this._previewForm.model&&(this._refs.previewState.textContent=JSON.stringify(this._previewForm.model.toJSON(),null,2))};this._refs.previewForm.querySelectorAll("input, select, textarea").forEach(e=>{e.addEventListener("input",a),e.addEventListener("change",a)}),a()}catch(e){console.error("Preview error:",e),this._refs.previewForm.innerHTML='<p class="text-danger">Preview error: '+e.message+"</p>"}}_attachEvents(){this._on(this.element,"click",'[data-action="new"]',()=>this.newSchema()),this._on(this.element,"click",'[data-action="save"]',()=>this._showSaveModal()),this._on(this.element,"click",'[data-action="load"]',()=>this._showLoadModal()),this._on(this.element,"click",'[data-action="export"]',()=>this._showExportModal()),this._on(this.element,"click",'[data-action="toggle-preview"]',()=>this._togglePreview()),this._on(this.element,"click",'[data-action="close-preview"]',()=>this._togglePreview()),this._on(this.element,"click",".sb-library-item",e=>{const t=e.target.closest(".sb-library-item").dataset.type;this.addField(t,this._fields.length)}),this._on(this.element,"dragstart",".sb-library-item",e=>{e.dataTransfer.setData("field-type",e.target.closest(".sb-library-item").dataset.type),this._dragSource="library"}),this._on(this.element,"dragover",".sb-drop-zone",e=>{e.preventDefault(),e.target.closest(".sb-drop-zone").classList.add("sb-drop-active")}),this._on(this.element,"dragleave",".sb-drop-zone",e=>{e.target.closest(".sb-drop-zone").classList.remove("sb-drop-active")}),this._on(this.element,"drop",".sb-drop-zone",e=>{e.preventDefault();const t=e.target.closest(".sb-drop-zone");t.classList.remove("sb-drop-active");const n=parseInt(t.dataset.position);if("library"===this._dragSource){const t=e.dataTransfer.getData("field-type");this.addField(t,n)}}),this._on(this.element,"click",".sb-field-card",e=>{if(e.target.closest(".sb-field-actions"))return;const t=parseInt(e.target.closest(".sb-field-card").dataset.index);this._selectField(t)}),this._on(this.element,"click",'[data-action="remove"]',e=>{e.stopPropagation(),this.removeField(parseInt(e.target.closest('[data-action="remove"]').dataset.index))}),this._on(this.element,"click",'[data-action="duplicate"]',e=>{e.stopPropagation(),this.duplicateField(parseInt(e.target.closest('[data-action="duplicate"]').dataset.index))}),this._on(this.element,"input",".sb-editor [data-prop]",e=>this._handlePropertyChange(e)),this._on(this.element,"change",".sb-editor [data-prop]",e=>this._handlePropertyChange(e)),this._on(this.element,"change",".sb-preview-layout",e=>{this.setPreviewLayout(e.target.value)}),document.addEventListener("keydown",e=>{"Escape"===e.key&&this._refs.previewPanel&&"flex"===this._refs.previewPanel.style.display&&this._togglePreview()})}_on(e,t,n,a){const i=t=>{if(n){const i=t.target.closest(n);i&&e.contains(i)&&a.call(i,t)}else a.call(e,t)};e.addEventListener(t,i),this._eventHandlers.push({element:e,event:t,handler:i})}_handlePropertyChange(e){if(this._selectedIndex<0)return;const t=e.target.dataset.prop;let n="checkbox"===e.target.type?e.target.checked:e.target.value;if("number"===e.target.type&&""!==n){const e=parseFloat(n);isNaN(e)||(n=e)}if(t.includes(".")){const e=t.split("."),a=this._fields[this._selectedIndex];a[e[0]]||(a[e[0]]={}),a[e[0]][e[1]]=n,this.updateField(this._selectedIndex,{[e[0]]:a[e[0]]})}else this.updateField(this._selectedIndex,{[t]:n})}_selectField(e){this._selectedIndex=e,this._renderCanvas(),this._renderEditor(e)}addField(e,t){const n=y[e];if(!n)return this;const a={name:`field${this._fields.length}`,...JSON.parse(JSON.stringify(n.defaults)),formConfig:{columns:12}};return this._fields.splice(t,0,a),this._markDirty(),this._renderCanvas(),this._renderPreview(),this._selectField(t),this}removeField(e){return e<0||e>=this._fields.length||(this._fields.splice(e,1),this._markDirty(),this._selectedIndex===e?this._selectedIndex=-1:this._selectedIndex>e&&this._selectedIndex--,this._renderCanvas(),this._renderEditor(this._selectedIndex),this._renderPreview()),this}duplicateField(e){if(e<0||e>=this._fields.length)return this;const t=JSON.parse(JSON.stringify(this._fields[e]));return t.name=t.name+"_copy",this._fields.splice(e+1,0,t),this._markDirty(),this._renderCanvas(),this._renderPreview(),this._selectField(e+1),this}updateField(e,t){return e<0||e>=this._fields.length||(Object.assign(this._fields[e],t),this._markDirty(),this._renderCanvas(),this._renderPreview()),this}getFields(){return JSON.parse(JSON.stringify(this._fields))}getBlueprint(){return this._toBlueprint()}exportJS(e={}){const t=this._toBlueprint();let n="const blueprint = ";return n+=JSON.stringify(t,null,4),n+=";\n",this.options.onExport&&this.options.onExport("js",n),n}exportJSON(e={}){const t=this._toBlueprint(),n=JSON.stringify(t,null,2);return this.options.onExport&&this.options.onExport("json",n),n}exportTypeScript(e={}){const{interfaceName:t="FormData"}=e,n=this._toBlueprint();let a=`interface ${t} {\n`;for(const[e,t]of Object.entries(n)){const n=this._mapToTSType(t.type);a+=` ${e}${t.required?"":"?"}: ${n};\n`}return a+="}\n",this.options.onExport&&this.options.onExport("typescript",a),a}importBlueprint(e,t){const n=[];for(const[t,a]of Object.entries(e))n.push({name:t,...a});return this._fields=n,this._schemaName=t||"",this._selectedIndex=-1,this._refs.schemaName&&(this._refs.schemaName.value=this._schemaName),this._renderCanvas(),this._renderEditor(-1),this._renderPreview(),this}saveTemplate(e){const t={name:this._schemaName,fields:this.getFields()};return f.save(e,t),this._isDirty=!1,this.options.onSave&&this.options.onSave(e,t),this}loadTemplate(e){const t=f.load(e);return t?(this._fields=t.fields||[],this._schemaName=t.name||e,this._selectedIndex=-1,this._refs.schemaName&&(this._refs.schemaName.value=this._schemaName),this._renderCanvas(),this._renderEditor(-1),this._renderPreview(),this):this}newSchema(e=""){return this._fields=[],this._schemaName=e,this._selectedIndex=-1,this._refs.schemaName&&(this._refs.schemaName.value=this._schemaName),this._renderCanvas(),this._renderEditor(-1),this._renderPreview(),this}setPreviewLayout(e){this.options.previewLayout=e;const t=this.element.querySelector(".sb-preview-layout");return t&&(t.value=e),this._renderPreview(),this}_togglePreview(){if(!this._refs.previewPanel&&(this._refs.previewPanel=this.element.querySelector(".sb-preview-panel"),!this._refs.previewPanel))return;return"none"!==this._refs.previewPanel.style.display?(this._refs.previewPanel.style.transform="translateX(100%)",setTimeout(()=>{this._refs.previewPanel.style.display="none"},300)):(this._refs.previewPanel.style.display="flex",this._refs.previewPanel.offsetHeight,setTimeout(()=>{this._refs.previewPanel.style.transform="translateX(0)",this._renderPreview()},10)),this}_toBlueprint(){const e={};for(const t of this._fields){if(!t.name)continue;const{name:n,...a}=t;e[n]=a}return e}_mapToTSType(e){return{string:"string",email:"string",password:"string",number:"number",boolean:"boolean",date:"Date | string",select:"string",textarea:"string"}[e]||"any"}_showSaveModal(){const e=this._createModal("Save Template",`\n <div class="sb-modal-body">\n <div class="form-group">\n <label class="form-label">Template Name</label>\n <input type="text" class="form-input sb-modal-input" placeholder="My Template" value="${this._escapeHtml(this._schemaName)}" />\n </div>\n </div>\n <div class="sb-modal-footer">\n <button class="btn" data-modal-action="cancel">Cancel</button>\n <button class="btn btn-primary" data-modal-action="save">Save</button>\n </div>\n `);this._on(e,"click",'[data-modal-action="save"]',()=>{const t=e.querySelector(".sb-modal-input").value.trim();t&&(this.saveTemplate(t),e.remove())}),this._on(e,"click",'[data-modal-action="cancel"]',()=>e.remove())}_showLoadModal(){const e=f.list();if(0===e.length)return void alert("No saved templates");const t=this._createModal("Load Template",`\n <div class="sb-modal-body">\n <div class="form-group">\n <label class="form-label">Select Template</label>\n <select class="form-select sb-modal-select">\n ${e.map(e=>`<option value="${this._escapeHtml(e)}">${this._escapeHtml(e)}</option>`).join("")}\n </select>\n </div>\n </div>\n <div class="sb-modal-footer">\n <button class="btn" data-modal-action="cancel">Cancel</button>\n <button class="btn btn-primary" data-modal-action="load">Load</button>\n </div>\n `);this._on(t,"click",'[data-modal-action="load"]',()=>{this.loadTemplate(t.querySelector(".sb-modal-select").value),t.remove()}),this._on(t,"click",'[data-modal-action="cancel"]',()=>t.remove())}_showExportModal(){const e=this._createModal("Export Blueprint",'\n <div class="sb-modal-body sb-export-modal">\n <div class="sb-export-tabs">\n <button class="sb-tab-btn active" data-format="js">JavaScript</button>\n <button class="sb-tab-btn" data-format="json">JSON</button>\n <button class="sb-tab-btn" data-format="typescript">TypeScript</button>\n </div>\n <div class="sb-export-content">\n <textarea class="form-input sb-export-output" readonly rows="15"></textarea>\n </div>\n </div>\n <div class="sb-modal-footer">\n <button class="btn" data-modal-action="close">Close</button>\n <button class="btn btn-primary" data-modal-action="copy">Copy</button>\n </div>\n '),t=e.querySelector(".sb-export-output");t.value=this.exportJS(),this._on(e,"click",".sb-tab-btn",n=>{const a=n.target.dataset.format;e.querySelectorAll(".sb-tab-btn").forEach(e=>e.classList.toggle("active",e.dataset.format===a)),"js"===a?t.value=this.exportJS():"json"===a?t.value=this.exportJSON():"typescript"===a&&(t.value=this.exportTypeScript())}),this._on(e,"click",'[data-modal-action="copy"]',async()=>{try{await navigator.clipboard.writeText(t.value),alert("Copied to clipboard!")}catch(e){alert("Failed to copy")}}),this._on(e,"click",'[data-modal-action="close"]',()=>e.remove())}_createModal(e,t){const n=document.createElement("div");return n.className="sb-modal-overlay",n.innerHTML=`<div class="sb-modal"><div class="sb-modal-header"><h3>${this._escapeHtml(e)}</h3></div>${t}</div>`,document.body.appendChild(n),n}_startAutoSave(){this._autoSaveTimer&&clearInterval(this._autoSaveTimer),this._autoSaveTimer=setInterval(()=>{this._isDirty&&f.saveActive(this._fields)},this.options.autoSaveInterval)}_markDirty(){this._isDirty=!0,this.options.onChange&&this.options.onChange(this.getFields())}_capitalize(e){return e.charAt(0).toUpperCase()+e.slice(1)}_escapeHtml(e){if(!e)return"";const t=document.createElement("div");return t.textContent=e.toString(),t.innerHTML}destroy(){this._autoSaveTimer&&clearInterval(this._autoSaveTimer),this._previewForm&&this._previewForm.destroy&&this._previewForm.destroy(),super.destroy()}}class _ extends b{constructor(e,t={}){super(e,t),this.mode=t.mode||"text",this.model=t.model||null,this.modelKey=t.modelKey||null,this.autosave=void 0!==t.autosave&&t.autosave,this.autosaveInterval=t.autosaveInterval||3e3,this.storageKey=t.storage||null,this.toolbar=t.toolbar||this._getDefaultToolbar(),this.showToolbar=!1!==t.showToolbar,this.imagePaste=!1!==t.imagePaste,this.imageMode=t.imageMode||"base64",this.imageUpload=t.imageUpload||null,this.language=t.language||"javascript",this.lineNumbers=!1!==t.lineNumbers,this.theme=t.theme||"light",this.placeholder=t.placeholder||"",this.minHeight=t.minHeight||200,this.maxHeight=t.maxHeight||null,this.characterCount=t.characterCount||!1,this.wordCount=t.wordCount||!1,this.onChange=t.onChange||null,this.onSave=t.onSave||null,this.onImagePaste=t.onImagePaste||null,this._content="",this._history=[],this._historyIndex=-1,this._maxHistory=50,this._autosaveTimer=null,this._container=null,this._editorEl=null,this._toolbarEl=null,this._counterEl=null,this._init()}_init(){if(!this.element)return;this.element.style.display="none",this._createContainer(),!this.showToolbar||"rich"!==this.mode&&"code"!==this.mode||this._createToolbar(),this._createEditor(),(this.characterCount||this.wordCount)&&this._createCounter(),this.storageKey&&this._loadFromStorage();const e=this.element.value||this.element.textContent||"";e&&this.setValue(e),this.autosave&&this._setupAutosave(),this.model&&"function"==typeof this.model.onChange&&(this._modelUnsubscribe=this.model.onChange((e,t)=>{e===this.modelKey&&t!==this.getValue()&&this.setValue(t)}))}_getDefaultToolbar(){return"rich"===this.mode?[["bold","italic","underline","strikethrough"],["h1","h2","h3"],["ul","ol","blockquote"],["link","image","code"],["codeblock","embed"],["undo","redo","clear"]]:"code"===this.mode?[["undo","redo"],["format","clear"]]:[]}_createContainer(){this._container=document.createElement("div"),this._container.className=`dm-editor dm-editor-${this.mode} dm-theme-${this.theme}`,this._container.style.minHeight=`${this.minHeight}px`,this.maxHeight&&(this._container.style.maxHeight=`${this.maxHeight}px`),this.element.parentNode.insertBefore(this._container,this.element.nextSibling)}_createToolbar(){this._toolbarEl=document.createElement("div"),this._toolbarEl.className="dm-editor-toolbar",this.toolbar.forEach(e=>{const t=document.createElement("div");t.className="dm-editor-toolbar-group",e.forEach(e=>{const n=this._createToolbarButton(e);n&&t.appendChild(n)}),this._toolbarEl.appendChild(t)}),this._container.appendChild(this._toolbarEl)}_createToolbarButton(e){const t=document.createElement("button");t.type="button",t.className=`dm-editor-toolbar-btn dm-editor-btn-${e}`,t.title=this._getButtonTitle(e),t.setAttribute("data-action",e);const n=this._getIconName(e);if(n&&window.Domma&&window.Domma.icons){const a=window.Domma.icons.render(n,{size:16});a?t.appendChild(a):t.innerHTML=this._getFallbackIcon(e)}else t.innerHTML=this._getFallbackIcon(e);return t.addEventListener("click",t=>{t.preventDefault(),this._executeCommand(e)}),t}_getButtonTitle(e){return{bold:"Bold (Ctrl+B)",italic:"Italic (Ctrl+I)",underline:"Underline (Ctrl+U)",strikethrough:"Strikethrough",h1:"Heading 1",h2:"Heading 2",h3:"Heading 3",ul:"Bullet List",ol:"Numbered List",blockquote:"Quote",link:"Insert Link",image:"Insert Image",code:"Inline Code",codeblock:"Code Block",embed:"Embed Media",undo:"Undo (Ctrl+Z)",redo:"Redo (Ctrl+Y)",clear:"Clear Formatting",format:"Auto Format"}[e]||e}_getIconName(e){return{bold:"bold",italic:"italic",underline:"underline",strikethrough:"strikethrough",h1:"heading-1",h2:"heading-2",h3:"heading-3",ul:"list-bullet",ol:"list-numbered",blockquote:"quote",link:"link-add",image:"image-add",code:"code-inline",codeblock:"code-block",embed:"embed",undo:"undo",redo:"redo",clear:"clear-format",format:"clear-format"}[e]}_getFallbackIcon(e){return{bold:"<strong>B</strong>",italic:"<em>I</em>",underline:"<u>U</u>",strikethrough:"<s>S</s>",h1:"H1",h2:"H2",h3:"H3",ul:"•",ol:"1.",blockquote:'"',link:"⚓",image:"🖼",code:"</>",codeblock:"{ }",embed:"▶",undo:"↶",redo:"↷",clear:"✕",format:"✨"}[e]||e}_createEditor(){"text"===this.mode?this._createTextEditor():"rich"===this.mode?this._createRichEditor():"code"===this.mode&&this._createCodeEditor()}_createTextEditor(){const e=document.createElement("div");e.className="dm-editor-body",this._editorEl=document.createElement("textarea"),this._editorEl.className="dm-editor-textarea",this._editorEl.placeholder=this.placeholder,this._editorEl.style.minHeight=`${this.minHeight}px`,this._editorEl.addEventListener("input",()=>{this._autoResize(),this._handleChange()}),e.appendChild(this._editorEl),this._container.appendChild(e)}_createRichEditor(){const e=document.createElement("div");e.className="dm-editor-body",this._editorEl=document.createElement("div"),this._editorEl.className="dm-editor-content",this._editorEl.contentEditable="true",this._editorEl.setAttribute("data-placeholder",this.placeholder),this._editorEl.addEventListener("input",()=>this._handleChange()),this._editorEl.addEventListener("keydown",e=>this._handleKeydown(e)),this.imagePaste&&this._editorEl.addEventListener("paste",e=>this._handlePaste(e)),e.appendChild(this._editorEl),this._container.appendChild(e)}_createCodeEditor(){const e=document.createElement("div");e.className="dm-editor-code-wrapper",this.lineNumbers&&(this._lineNumbersEl=document.createElement("div"),this._lineNumbersEl.className="dm-editor-line-numbers",e.appendChild(this._lineNumbersEl)),this._editorEl=document.createElement("textarea"),this._editorEl.className="dm-editor-code-textarea",this._editorEl.placeholder=this.placeholder,this._editorEl.spellcheck=!1,this._editorEl.setAttribute("data-language",this.language),this._editorEl.addEventListener("input",()=>{this._updateLineNumbers(),this._highlightSyntax(),this._handleChange()}),this._editorEl.addEventListener("scroll",()=>{this._lineNumbersEl&&(this._lineNumbersEl.scrollTop=this._editorEl.scrollTop)}),this._editorEl.addEventListener("keydown",e=>this._handleCodeKeydown(e)),e.appendChild(this._editorEl),this._container.appendChild(e)}_createCounter(){const e=document.createElement("div");e.className="dm-editor-footer";const t=document.createElement("div");t.className="dm-editor-status",(this.characterCount||this.wordCount)&&(this._counterEl=document.createElement("div"),this._counterEl.className="dm-editor-count",t.appendChild(this._counterEl)),this.autosave&&(this._autosaveIndicator=document.createElement("div"),this._autosaveIndicator.className="dm-editor-autosave",this._autosaveIndicator.textContent="Auto-save enabled",t.appendChild(this._autosaveIndicator)),e.appendChild(t);const n=document.createElement("div");n.className="dm-editor-history";const a=document.createElement("button");a.type="button",a.className="dm-editor-history-btn",a.textContent="Undo",a.disabled=!0,a.onclick=()=>this.undo(),this._undoBtn=a;const i=document.createElement("button");i.type="button",i.className="dm-editor-history-btn",i.textContent="Redo",i.disabled=!0,i.onclick=()=>this.redo(),this._redoBtn=i,n.appendChild(a),n.appendChild(i),e.appendChild(n),this._container.appendChild(e),this._updateCounter()}_autoResize(){"text"===this.mode&&(this._editorEl.style.height="auto",this._editorEl.style.height=this._editorEl.scrollHeight+"px")}_updateLineNumbers(){if(!this._lineNumbersEl)return;const e=this._editorEl.value.split("\n").length,t=Array.from({length:e},(e,t)=>t+1).join("\n");this._lineNumbersEl.textContent=t}_highlightSyntax(){this._editorEl.setAttribute("data-language",this.language)}_updateCounter(){if(!this._counterEl)return;const e=this.getValue(),t=e.length,n=e.trim().split(/\s+/).filter(e=>e.length>0).length;let a="";this.characterCount&&(a+=`${t} characters`),this.characterCount&&this.wordCount&&(a+=" • "),this.wordCount&&(a+=`${n} words`),this._counterEl.textContent=a}_handleChange(){const e=this.getValue();this._counterEl&&this._updateCounter(),this.model&&this.modelKey&&this.model.set(this.modelKey,e),this.onChange&&this.onChange(e),this._addToHistory(e),this.autosave&&this._triggerAutosave()}_handleKeydown(e){if(e.ctrlKey||e.metaKey)switch(e.key.toLowerCase()){case"b":e.preventDefault(),this._executeCommand("bold");break;case"i":e.preventDefault(),this._executeCommand("italic");break;case"u":e.preventDefault(),this._executeCommand("underline");break;case"z":e.preventDefault(),this.undo();break;case"y":e.preventDefault(),this.redo()}}_handleCodeKeydown(e){if("Tab"===e.key){e.preventDefault();const t=this._editorEl.selectionStart,n=this._editorEl.selectionEnd,a=this._editorEl.value;this._editorEl.value=a.substring(0,t)+" "+a.substring(n),this._editorEl.selectionStart=this._editorEl.selectionEnd=t+4,this._handleChange()}}_handlePaste(e){const t=e.clipboardData?.items;if(t)for(let n=0;n<t.length;n++)if(-1!==t[n].type.indexOf("image")){e.preventDefault();const a=t[n].getAsFile();return void this._insertImage(a)}}async _insertImage(e){let t;if(this.imageUpload&&"function"==typeof this.imageUpload)t=await this.imageUpload(e);else{if("base64"!==this.imageMode)return void console.warn("No image upload handler provided");t=await this._fileToBase64(e)}t&&(document.execCommand("insertImage",!1,t),this.onImagePaste&&this.onImagePaste(t,e))}_fileToBase64(e){return new Promise((t,n)=>{const a=new FileReader;a.onload=()=>t(a.result),a.onerror=n,a.readAsDataURL(e)})}_executeCommand(e){if("rich"===this.mode){switch(e){case"bold":case"italic":case"underline":case"strikethrough":document.execCommand(e);break;case"h1":case"h2":case"h3":document.execCommand("formatBlock",!1,e);break;case"ul":document.execCommand("insertUnorderedList");break;case"ol":document.execCommand("insertOrderedList");break;case"blockquote":document.execCommand("formatBlock",!1,"blockquote");break;case"link":this._insertLink();break;case"image":this._promptImage();break;case"code":document.execCommand("insertHTML",!1,"<code></code>");break;case"codeblock":this._insertCodeBlock();break;case"embed":this._insertEmbed();break;case"undo":this.undo();break;case"redo":this.redo();break;case"clear":this.clear()}this._editorEl.focus()}}_insertLink(){const e=prompt("Enter URL:");e&&document.execCommand("createLink",!1,e)}_promptImage(){const e=prompt("Enter image URL:");e&&document.execCommand("insertImage",!1,e)}_insertCodeBlock(){const e=prompt("Enter code:");if(e){const t=`<pre><code>${this._escapeHtml(e)}</code></pre>`;document.execCommand("insertHTML",!1,t)}}_insertEmbed(){const e=prompt("Enter embed URL (YouTube, Twitter, etc.):");if(!e)return;const t=this._createEmbed(e);t&&document.execCommand("insertHTML",!1,t)}_createEmbed(e){const t=e.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&]+)/);if(t)return`<iframe width="560" height="315" src="https://www.youtube.com/embed/${t[1]}" frameborder="0" allowfullscreen></iframe>`;if(e.match(/twitter\.com\/\w+\/status\/(\d+)/))return`<blockquote class="twitter-tweet"><a href="${e}"></a></blockquote>`;const n=e.match(/codepen\.io\/([^\/]+)\/pen\/([^\/]+)/);return n?`<iframe height="400" style="width: 100%;" src="https://codepen.io/${n[1]}/embed/${n[2]}" frameborder="0"></iframe>`:`<a href="${e}" target="_blank">${e}</a>`}_escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}_addToHistory(e){this._historyIndex<this._history.length-1&&(this._history=this._history.slice(0,this._historyIndex+1)),this._history.push(e),this._history.length>this._maxHistory?this._history.shift():this._historyIndex++,this._updateHistoryButtons()}_setupAutosave(){}_triggerAutosave(){this._autosaveTimer&&clearTimeout(this._autosaveTimer),this._autosaveIndicator&&(this._autosaveIndicator.textContent="Saving...",this._autosaveIndicator.className="dm-editor-autosave saving"),this._autosaveTimer=setTimeout(()=>{this._saveToStorage(),this.onSave&&this.onSave(this.getValue()),this._autosaveIndicator&&(this._autosaveIndicator.textContent="Saved",this._autosaveIndicator.className="dm-editor-autosave saved",setTimeout(()=>{this._autosaveIndicator&&(this._autosaveIndicator.textContent="Auto-save enabled",this._autosaveIndicator.className="dm-editor-autosave")},2e3))},this.autosaveInterval)}_saveToStorage(){if(!this.storageKey)return;const e=this.getValue();localStorage.setItem(`domma:editor:${this.storageKey}`,e)}_loadFromStorage(){if(!this.storageKey)return;const e=localStorage.getItem(`domma:editor:${this.storageKey}`);e&&this.setValue(e)}getValue(){return"rich"===this.mode?this._editorEl.innerHTML:this._editorEl.value}setValue(e){return"rich"===this.mode?this._editorEl.innerHTML=e:this._editorEl.value=e,"code"===this.mode&&(this._updateLineNumbers(),this._highlightSyntax()),"text"===this.mode&&this._autoResize(),this._updateCounter(),this}getText(){return"rich"===this.mode?this._editorEl.textContent:this._editorEl.value}clear(){return this.setValue(""),this._history=[],this._historyIndex=-1,this}focus(){return this._editorEl.focus(),this}blur(){return this._editorEl.blur(),this}undo(){return this._historyIndex>0&&(this._historyIndex--,this.setValue(this._history[this._historyIndex]),this._updateHistoryButtons()),this}redo(){return this._historyIndex<this._history.length-1&&(this._historyIndex++,this.setValue(this._history[this._historyIndex]),this._updateHistoryButtons()),this}_updateHistoryButtons(){this._undoBtn&&(this._undoBtn.disabled=this._historyIndex<=0),this._redoBtn&&(this._redoBtn.disabled=this._historyIndex>=this._history.length-1)}save(){return this._saveToStorage(),this.onSave&&this.onSave(this.getValue()),this}setMode(e){if(e===this.mode)return this;const t=this.getText();return this.mode=e,this._container.innerHTML="",this._container.className=`dm-editor dm-editor-${this.mode} dm-theme-${this.theme}`,!this.showToolbar||"rich"!==this.mode&&"code"!==this.mode||(this.toolbar=this._getDefaultToolbar(),this._createToolbar()),this._createEditor(),(this.characterCount||this.wordCount)&&this._createCounter(),this.setValue(t),this}getMode(){return this.mode}destroy(){this._autosaveTimer&&clearTimeout(this._autosaveTimer),this._modelUnsubscribe&&this._modelUnsubscribe(),this._container&&this._container.parentNode&&this._container.parentNode.removeChild(this._container),this.element.style.display="",super.destroy()}}class x extends b{constructor(e,t={}){super(e,{pageSize:"A4",orientation:"portrait",margins:"normal",title:null,removeBackgrounds:!1,optimizeImages:!0,header:null,footer:null,showPageNumbers:!1,preview:!1,hideElements:[],pageBreaks:"auto",onBeforePrint:null,onAfterPrint:null,onPreview:null,...t}),this._styleElement=null,this._boundBeforePrint=null,this._boundAfterPrint=null,this._hiddenElements=[],this._init()}_init(){this.element?(this._boundBeforePrint=this._handleBeforePrint.bind(this),this._boundAfterPrint=this._handleAfterPrint.bind(this)):console.error("PrintToPDF: Element not found")}_generatePrintCSS(){const{pageSize:e,orientation:t,margins:n,removeBackgrounds:a,optimizeImages:i,pageBreaks:s}=this.options,o={A4:{width:210,height:297},Letter:{width:215.9,height:279.4},Legal:{width:215.9,height:355.6}},r={none:0,narrow:12.7,normal:20,wide:25.4};let l="";if("string"==typeof e&&o[e]){const t=o[e];l=`${t.width}mm ${t.height}mm`}else l="object"==typeof e&&e.width&&e.height?`${e.width}mm ${e.height}mm`:"A4";let d="";return d="string"==typeof n&&void 0!==r[n]?`${r[n]}mm`:"object"==typeof n?`${n.top||20}mm ${n.right||20}mm ${n.bottom||20}mm ${n.left||20}mm`:"20mm",`\n@media print {\n @page {\n size: ${l} ${t};\n margin: ${d};\n }\n\n /* Hide non-printable elements */\n .no-print,\n .dm-modal,\n .dm-toast-container,\n .dm-loader-overlay {\n display: none !important;\n }\n\n /* Optimize body */\n body {\n ${a?"background: white !important;":""}\n print-color-adjust: exact;\n -webkit-print-color-adjust: exact;\n }\n\n /* Table optimizations */\n table {\n page-break-inside: ${"avoid"===s?"avoid":"auto"};\n border-collapse: collapse;\n }\n\n thead {\n display: table-header-group;\n }\n\n tfoot {\n display: table-footer-group;\n }\n\n tr {\n page-break-inside: avoid;\n }\n\n /* Image optimizations */\n ${i?"\n img {\n max-width: 100% !important;\n page-break-inside: avoid;\n }\n ":""}\n\n /* Page break helpers */\n h1, h2, h3, h4, h5, h6 {\n page-break-after: avoid;\n }\n\n .page-break-before {\n page-break-before: always;\n }\n\n .page-break-after {\n page-break-after: always;\n }\n\n .page-break-avoid {\n page-break-inside: avoid;\n }\n\n /* Code blocks */\n pre, code {\n page-break-inside: avoid;\n }\n\n /* Remove backgrounds if requested */\n ${a?"\n * {\n background: transparent !important;\n background-image: none !important;\n }\n\n body {\n background: white !important;\n }\n ":""}\n}\n`}_injectPrintStyles(){if(this._styleElement)return;const e=this._generatePrintCSS();this._styleElement=document.createElement("style"),this._styleElement.setAttribute("data-domma-print-styles","true"),this._styleElement.textContent=e,document.head.appendChild(this._styleElement)}_removePrintStyles(){this._styleElement&&this._styleElement.parentNode&&(this._styleElement.parentNode.removeChild(this._styleElement),this._styleElement=null)}_hideElements(){const{hideElements:e}=this.options;e&&0!==e.length&&e.forEach(e=>{document.querySelectorAll(e).forEach(e=>{"none"!==e.style.display&&(this._hiddenElements.push({element:e,originalDisplay:e.style.display}),e.style.display="none")})})}_restoreElements(){this._hiddenElements.forEach(({element:e,originalDisplay:t})=>{e.style.display=t}),this._hiddenElements=[]}_handleBeforePrint(){this._hideElements(),"function"==typeof this.options.onBeforePrint&&this.options.onBeforePrint()}_handleAfterPrint(){this._restoreElements(),this._removePrintStyles(),window.removeEventListener("beforeprint",this._boundBeforePrint),window.removeEventListener("afterprint",this._boundAfterPrint),"function"==typeof this.options.onAfterPrint&&this.options.onAfterPrint()}preview(){console.warn("PrintToPDF: preview() is not implemented. Configure options and call print() directly."),this.print()}print(){if(!this.element)return void console.error("PrintToPDF: No element to print");const e=document.title;this.options.title&&(document.title=this.options.title),this._injectPrintStyles(),window.addEventListener("beforeprint",this._boundBeforePrint),window.addEventListener("afterprint",this._boundAfterPrint),window.print(),this.options.title&&(document.title=e)}destroy(){this._removePrintStyles(),this._restoreElements(),this._previewContainer&&this._previewContainer.parentNode&&(this._previewContainer.parentNode.removeChild(this._previewContainer),this._previewContainer=null),this._boundBeforePrint&&window.removeEventListener("beforeprint",this._boundBeforePrint),this._boundAfterPrint&&window.removeEventListener("afterprint",this._boundAfterPrint),super.destroy()}}const w={themeRoller(e,t={}){const n=new p(e,t);return n.element&&"undefined"!=typeof Domma&&Domma.elements._instances.set(n.element,n),n},pageRoller(e,t={}){const n=new g(e,t);return n.element&&"undefined"!=typeof Domma&&Domma.elements._instances.set(n.element,n),n},schemaBuilder(e,t={}){const n=new v(e,t);return n.element&&"undefined"!=typeof Domma&&Domma.elements._instances.set(n.element,n),n},editor(e,t={}){const n=new _(e,t);return n.element&&"undefined"!=typeof Domma&&Domma.elements._instances.set(n.element,n),n},printToPDF(e,t={}){const n=new x(e,t);return n.element&&"undefined"!=typeof Domma&&Domma.elements._instances.set(n.element,n),n}};"undefined"!=typeof Domma&&Domma.elements&&(Domma.elements.themeRoller=w.themeRoller,Domma.elements.pageRoller=w.pageRoller,Domma.elements.schemaBuilder=w.schemaBuilder,Domma.elements.editor=w.editor,Domma.elements.printToPDF=w.printToPDF),"undefined"!=typeof window&&(window.DommaTools=w),e.Editor=_,e.PageRoller=g,e.PrintToPDF=x,e.SchemaBuilder=v,e.ThemeRoller=p,e.default=w,e.tools=w,Object.defineProperty(e,"__esModule",{value:!0})});
|