@stonecrop/desktop 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/desktop.css +1 -1
- package/dist/desktop.js +2 -2
- package/dist/desktop.js.map +1 -1
- package/package.json +6 -6
- package/src/components/ActionSet.vue +2 -2
- package/src/components/SheetNav.vue +23 -23
package/dist/desktop.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
#cross[data-v-
|
|
1
|
+
#cross[data-v-8e18f635]{position:relative;transform:rotate(45deg);cursor:pointer;transition:all .2s ease-in-out;-webkit-user-select:none;user-select:none;line-height:1rem}#cross.rotated[data-v-8e18f635],.cross.rotated[data-v-8e18f635]{transform:rotate(0)}#cross svg[data-v-8e18f635]{width:1.5em;height:1.5em}.action-set[data-v-8e18f635]{position:fixed;top:300px;right:10px;padding:10px;display:flex;flex-direction:column;align-items:flex-end;background:var(--sc-form-background);border:1px solid var(--sc-gray-20);border-left:4px solid var(--sc-gray-20);border-radius:0;overflow:hidden;z-index:1001;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out}.action-menu-icon[data-v-8e18f635]{position:relative;font-size:2rem;display:inline-block;color:var(--sc-gray-60);transition:all .2s ease-in-out}.action-set.collapsed[data-v-8e18f635]{max-width:46px;max-height:40px;overflow:hidden}.action-set.collapsed .action-element[data-v-8e18f635]{opacity:0;-webkit-transition:opacity .25s ease-in-out;-moz-transition:opacity .25s ease-in-out;-o-transition:opacity .25s ease-in-out;transition:opacity .25s ease-in-out}.action-element[data-v-8e18f635]{width:100%;text-align:right;border:1px solid var(--sc-gray-20);background:none;font-size:1.5rem;font-family:var(--sc-font-family);font-weight:600;margin-top:10px;position:relative}.action-element-header[data-v-8e18f635]{display:flex;justify-content:end}button.button-default[data-v-8e18f635]{background-color:transparent;border-radius:0;box-shadow:none;border:none;cursor:pointer;white-space:nowrap;font-weight:700;font-size:1rem;text-align:right;color:var(--sc-gray-80);padding:5px 12px 5px 50px;font-family:var(--sc-font-family)}.dropdown-header:hover button.button-default[data-v-8e18f635],.dropdown-header[data-v-8e18f635]:hover,.action-element-header[data-v-8e18f635]:hover{background-color:#f2f2f2}.dropdown-title[data-v-8e18f635]{position:relative}.dropdown-header[data-v-8e18f635]{display:flex;align-items:center}.cross[data-v-8e18f635]{pointer-events:all;margin-left:5px;font-family:var(--sc-font-family);color:var(--sc-gray-60);cursor:pointer;transform:rotate(45deg);-webkit-user-select:none;user-select:none;transition:all .2s ease-in-out;line-height:1rem}button.dropdown-item[data-v-8e18f635]{width:100%;padding:5px 12px;text-align:right;border:none;background-color:#fff;cursor:pointer;border-radius:5px;font-size:1rem}button.dropdown-item[data-v-8e18f635]:hover{background-color:#f2f2f2}.fade-enter-active,.fade-leave-active{transition:opacity .2s ease}.fade-enter-from,.fade-leave-to{opacity:0}.command-palette-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;display:flex;align-items:flex-start;justify-content:center;z-index:300;padding-top:100px}.command-palette{width:600px;max-width:90%;background-color:#fff;border-radius:8px;box-shadow:0 4px 20px #00000026;overflow:hidden;max-height:80vh;display:flex;flex-direction:column}.command-palette-header{display:flex;border-bottom:1px solid #eaeaea;padding:12px}.command-palette-input{flex:1;border:none;outline:none;font-size:16px;padding:8px 12px;background-color:transparent}.command-palette-close{background:transparent;border:none;font-size:24px;cursor:pointer;color:#666;padding:0 8px}.command-palette-close:hover{color:#333}.command-palette-results{overflow-y:auto;max-height:60vh}.command-palette-result{padding:12px 16px;cursor:pointer;border-bottom:1px solid #f0f0f0}.command-palette-result:hover,.command-palette-result.selected{background-color:#f5f5f5}.command-palette-result.selected{background-color:#843c031a}.result-title{font-weight:500;margin-bottom:4px;color:#333}.result-content{font-size:14px;color:#666;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.command-palette-no-results{padding:20px 16px;text-align:center;color:#666}footer[data-v-cd118b06]{position:fixed;bottom:0;width:100%;background-color:transparent;height:auto;min-height:2.4rem;z-index:100;text-align:left;font-size:100%;display:flex;justify-content:right;padding:0 .75rem 0 0;box-sizing:border-box}ul[data-v-cd118b06]{display:flex;flex-direction:row-reverse;margin:0;padding:0;list-style:none}.tabs li[data-v-cd118b06]{float:left;list-style-type:none;position:relative;margin-left:-1px}.tabs a[data-v-cd118b06]{float:left;padding:.5rem 1rem;height:2.4rem;box-sizing:border-box;display:flex;align-items:center;justify-content:center;text-decoration:none;color:var(--sc-gray-60);background:var(--sc-btn-color);border:1px solid var(--sc-btn-border);font-size:.85rem;font-family:var(--sc-font-family);transition:all .15s ease;border-top-left-radius:2px;border-top-right-radius:2px}.tabs a[data-v-cd118b06]:hover{background:var(--sc-btn-hover)}.tabs .router-link-active[data-v-cd118b06]{z-index:3;background:var(--sc-primary-color)!important;border-color:var(--sc-primary-color)!important;color:var(--sc-primary-text-color)!important}.hidebreadcrumbs a[data-v-cd118b06]{min-width:2.4rem;width:2.4rem;height:2.4rem;padding:.5rem;background:var(--sc-btn-color);border:1px solid var(--sc-btn-border);color:var(--sc-gray-60)}.hidebreadcrumbs a div[data-v-cd118b06]{font-size:1.2rem}.rotated[data-v-cd118b06]{transform:rotate(45deg);-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transition:transform .25s ease}.unrotated[data-v-cd118b06]{transform:rotate(0);-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transition:transform .25s ease}li[data-v-cd118b06]:active,li[data-v-cd118b06]:hover,li[data-v-cd118b06]:focus,li>a[data-v-cd118b06]:active,li>a[data-v-cd118b06]:hover,li>a[data-v-cd118b06]:focus{z-index:3}a[data-v-cd118b06]:active,a[data-v-cd118b06]:hover,a[data-v-cd118b06]:focus{outline:2px solid var(--sc-input-active-border-color);z-index:3}.hometab a[data-v-cd118b06]{min-width:2.4rem;width:2.4rem;height:2.4rem;padding:.5rem;background:var(--sc-btn-color);border:1px solid var(--sc-btn-border);color:var(--sc-gray-60)}.icon[data-v-cd118b06]{width:1rem;height:1rem;stroke:currentColor;flex-shrink:0}.searchtab[data-v-cd118b06]{overflow:hidden}.searchtab a[data-v-cd118b06]{min-width:2.4rem;height:2.4rem;padding:.5rem;background:var(--sc-btn-color);border:1px solid var(--sc-btn-border);color:var(--sc-gray-60);overflow:hidden;max-width:2.4rem;transition:max-width .35s ease-in-out,padding .35s ease-in-out,background .2s ease}.searchtab .search-icon[data-v-cd118b06]{cursor:pointer}.searchtab input[data-v-cd118b06]{outline:none;border:1px solid var(--sc-input-border-color);border-radius:.25rem;background-color:var(--sc-form-background);color:var(--sc-gray-80);text-align:left;font-size:.875rem;padding:.25rem .5rem;width:180px;height:1.5rem;flex-shrink:0;opacity:0;transition:opacity .2s ease-in-out;transition-delay:0s}.searchtab input[data-v-cd118b06]:focus{border-color:var(--sc-input-active-border-color);outline:none}.searchtab input[data-v-cd118b06]::placeholder{color:var(--sc-input-label-color)}.searchtab.search-active a[data-v-cd118b06]{max-width:200px;min-width:auto;width:auto;padding:.5rem .75rem}.searchtab.search-active input[data-v-cd118b06]{opacity:1;transition-delay:.15s}
|
package/dist/desktop.js
CHANGED
|
@@ -86,7 +86,7 @@ const Ue = { class: "action-menu-icon" }, We = { class: "action-element-header"
|
|
|
86
86
|
for (const [w, d] of S)
|
|
87
87
|
D[w] = d;
|
|
88
88
|
return D;
|
|
89
|
-
}, he = /* @__PURE__ */ ye(at, [["__scopeId", "data-v-
|
|
89
|
+
}, he = /* @__PURE__ */ ye(at, [["__scopeId", "data-v-8e18f635"]]), nt = { class: "command-palette-header" }, rt = ["placeholder"], lt = {
|
|
90
90
|
key: 0,
|
|
91
91
|
class: "command-palette-results"
|
|
92
92
|
}, st = ["onClick", "onMouseover"], ct = { class: "result-title" }, it = { class: "result-content" }, ut = {
|
|
@@ -304,7 +304,7 @@ const Ue = { class: "action-menu-icon" }, We = { class: "action-element-header"
|
|
|
304
304
|
]);
|
|
305
305
|
};
|
|
306
306
|
}
|
|
307
|
-
}), we = /* @__PURE__ */ ye(ft, [["__scopeId", "data-v-
|
|
307
|
+
}), we = /* @__PURE__ */ ye(ft, [["__scopeId", "data-v-cd118b06"]]), mt = {
|
|
308
308
|
key: 1,
|
|
309
309
|
class: "loading"
|
|
310
310
|
}, yt = {
|
package/dist/desktop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"desktop.js","sources":["../src/components/ActionSet.vue","../src/components/CommandPalette.vue","../src/components/SheetNav.vue","../src/components/Desktop.vue","../src/plugins/index.ts"],"sourcesContent":["<template>\n\t<div :class=\"{ collapsed: !isOpen }\" class=\"action-set\">\n\t\t<div class=\"action-menu-icon\">\n\t\t\t<div id=\"cross\" :class=\"{ rotated: isOpen }\" @click=\"onClick\">×</div>\n\t\t</div>\n\t\t<div style=\"margin-right: 30px\"></div>\n\t\t<div v-for=\"(el, index) in elements\" :key=\"el.label\" class=\"action-element\">\n\t\t\t<div class=\"action-element-header\">\n\t\t\t\t<button\n\t\t\t\t\tv-if=\"el.type == 'button'\"\n\t\t\t\t\t:disabled=\"el.disabled\"\n\t\t\t\t\tclass=\"button-default\"\n\t\t\t\t\t@click=\"handleClick(el.action, el.label)\">\n\t\t\t\t\t{{ el.label }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<div v-if=\"el.type == 'dropdown'\">\n\t\t\t\t<div class=\"dropdown-header\">\n\t\t\t\t\t<div class=\"cross\" :class=\"{ rotated: dropdownOpen[index] }\" @click=\"toggleDropdown(index)\">×</div>\n\t\t\t\t\t<button class=\"button-default dropdown-title\" @click=\"toggleDropdown(index)\">\n\t\t\t\t\t\t{{ el.label }}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t\t<div v-show=\"dropdownStates[index]\" class=\"dropdown-container\">\n\t\t\t\t\t<div class=\"dropdown\">\n\t\t\t\t\t\t<div v-for=\"item in el.actions\" :key=\"item.label\">\n\t\t\t\t\t\t\t<button v-if=\"item.action != null\" class=\"dropdown-item\" @click=\"handleClick(item.action, item.label)\">\n\t\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<a v-else-if=\"item.link != null\" :href=\"item.link\"\n\t\t\t\t\t\t\t\t><button class=\"dropdown-item\">{{ item.label }}</button></a\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, ref } from 'vue'\n\nimport type { ActionElements } from '../types'\n\nconst { elements = [] } = defineProps<{ elements?: ActionElements[] }>()\nconst emit = defineEmits<{\n\tactionClick: [label: string, action: (() => void | Promise<void>) | undefined]\n}>()\n\n// Track dropdown open state separately (index -> boolean)\nconst dropdownStates = ref<Record<number, boolean>>({})\n\nconst isOpen = ref(true)\nconst dropdownOpen = ref<boolean[]>([])\n\nonMounted(() => {\n\tcloseDropdowns()\n})\n\nconst closeDropdowns = () => {\n\tdropdownStates.value = {}\n\tdropdownOpen.value = []\n}\n\nconst onClick = () => {\n\tisOpen.value = !isOpen.value\n}\n\nconst toggleDropdown = (index: number) => {\n\tconst showDropdown = !dropdownStates.value[index]\n\tcloseDropdowns()\n\tif (showDropdown) {\n\t\tdropdownStates.value[index] = true\n\t\tdropdownOpen.value[index] = true\n\t}\n}\n\nconst handleClick = (action: (() => void | Promise<void>) | undefined, label: string) => {\n\t// Emit event to parent - parent will handle execution\n\temit('actionClick', label, action)\n}\n</script>\n\n<style scoped>\n#cross {\n\tposition: relative;\n\ttransform: rotate(45deg);\n\tcursor: pointer;\n\ttransition: all 0.2s ease-in-out;\n\tuser-select: none;\n\tline-height: 1rem;\n}\n#cross.rotated,\n.cross.rotated {\n\ttransform: rotate(0deg);\n}\n#cross svg {\n\twidth: 1.5em;\n\theight: 1.5em;\n}\n\n.action-set {\n\tposition: fixed;\n\ttop: 300px;\n\tright: 10px;\n\tpadding: 10px;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-end;\n\tbackground: var(--sc-form-background);\n\tborder: 1px solid var(--sc-gray-20);\n\tborder-left: 4px solid var(--sc-gray-20);\n\tborder-radius: 0;\n\toverflow: hidden;\n\tz-index: 1001; /* Above SheetNav (100) and operation log button (999) */\n\t-webkit-transition: all 0.5s ease-in-out;\n\t-moz-transition: all 0.5s ease-in-out;\n\t-o-transition: all 0.5s ease-in-out;\n\ttransition: all 0.5s ease-in-out;\n}\n.action-menu-icon {\n\tposition: relative;\n\tfont-size: 2rem;\n\tdisplay: inline-block;\n\tcolor: var(--sc-gray-60, #666);\n\ttransition: all 0.2s ease-in-out;\n}\n.action-set.collapsed {\n\tmax-width: 46px;\n\tmax-height: 40px;\n\toverflow: hidden;\n}\n.action-set.collapsed .action-element {\n\topacity: 0;\n\t-webkit-transition: opacity 0.25s ease-in-out;\n\t-moz-transition: opacity 0.25s ease-in-out;\n\t-o-transition: opacity 0.25s ease-in-out;\n\ttransition: opacity 0.25s ease-in-out;\n}\n\n.action-element {\n\twidth: 100%;\n\ttext-align: right;\n\tborder: 1px solid var(--sc-gray-20);\n\tbackground: none;\n\tfont-size: 1.5rem;\n\tfont-family: var(--sc-font-family);\n\tfont-weight: 600;\n\tmargin-top: 10px;\n\tposition: relative; /* Make this the positioning context for absolute children */\n}\n.action-element-header {\n\tdisplay: flex;\n\tjustify-content: end;\n}\nbutton.button-default {\n\tbackground-color: transparent;\n\tpadding: 5px 12px;\n\tborder-radius: 0px;\n\tbox-shadow: none;\n\tborder: none;\n\tcursor: pointer;\n\twhite-space: nowrap;\n\tfont-weight: bold;\n\tfont-size: 1rem;\n\ttext-align: right;\n\tcolor: var(--sc-gray-80);\n\tpadding-left: 50px;\n\tfont-family: var(--sc-font-family);\n}\n.dropdown-header:hover button.button-default,\n.dropdown-header:hover,\n.action-element-header:hover {\n\tbackground-color: #f2f2f2;\n}\n\n.dropdown-title {\n\tposition: relative;\n}\n.dropdown-header {\n\tdisplay: flex;\n\talign-items: center;\n}\n.cross {\n\tpointer-events: all;\n\tmargin-left: 5px;\n\tfont-family: var(--sc-font-family);\n\tcolor: var(--sc-gray-60, #666);\n\tcursor: pointer;\n\ttransform: rotate(45deg);\n\tuser-select: none;\n\ttransition: all 0.2s ease-in-out;\n\tline-height: 1rem;\n}\n\nbutton.dropdown-item {\n\twidth: 100%;\n\tpadding: 5px 12px;\n\ttext-align: right;\n\tborder: none;\n\tbackground-color: #ffffff;\n\tcursor: pointer;\n\tborder-radius: 5px;\n\tfont-size: 1rem;\n}\n\nbutton.dropdown-item:hover {\n\tbackground-color: #f2f2f2;\n}\n</style>\n","<template>\n\t<Teleport to=\"body\">\n\t\t<Transition name=\"fade\">\n\t\t\t<div v-if=\"isOpen\" class=\"command-palette-overlay\" @click=\"closeModal\">\n\t\t\t\t<div class=\"command-palette\" @click.stop>\n\t\t\t\t\t<div class=\"command-palette-header\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\tref=\"input\"\n\t\t\t\t\t\t\tv-model=\"query\"\n\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\tclass=\"command-palette-input\"\n\t\t\t\t\t\t\t:placeholder=\"placeholder\"\n\t\t\t\t\t\t\tautofocus\n\t\t\t\t\t\t\t@keydown=\"handleKeydown\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div v-if=\"results.length\" class=\"command-palette-results\">\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tv-for=\"(result, index) in results\"\n\t\t\t\t\t\t\t:key=\"index\"\n\t\t\t\t\t\t\tclass=\"command-palette-result\"\n\t\t\t\t\t\t\t:class=\"{ selected: index === selectedIndex }\"\n\t\t\t\t\t\t\t@click=\"selectResult(result)\"\n\t\t\t\t\t\t\t@mouseover=\"selectedIndex = index\">\n\t\t\t\t\t\t\t<div class=\"result-title\">\n\t\t\t\t\t\t\t\t<slot name=\"title\" :result=\"result\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"result-content\">\n\t\t\t\t\t\t\t\t<slot name=\"content\" :result=\"result\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div v-else-if=\"query && !results.length\" class=\"command-palette-no-results\">\n\t\t\t\t\t\t<slot name=\"empty\"> No results found for \"{{ query }}\" </slot>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</Transition>\n\t</Teleport>\n</template>\n\n<script setup lang=\"ts\" generic=\"T\">\nimport { ref, computed, watch, nextTick, useTemplateRef } from 'vue'\n\ndefineSlots<{\n\ttitle?: { result: T }\n\tcontent?: { result: T }\n\tempty?: null\n}>()\n\nconst {\n\tsearch,\n\tisOpen = false,\n\tplaceholder = 'Type a command or search...',\n\tmaxResults = 10,\n} = defineProps<{\n\tsearch: (query: string) => T[]\n\tisOpen?: boolean\n\tplaceholder?: string\n\tmaxResults?: number\n}>()\n\nconst emit = defineEmits<{\n\tselect: [T]\n\tclose: []\n}>()\n\nconst query = ref('')\nconst selectedIndex = ref(0)\nconst inputRef = useTemplateRef('input')\n\nconst results = computed(() => {\n\tif (!query.value) return []\n\tconst searchResults = search(query.value)\n\treturn searchResults.slice(0, maxResults)\n})\n\n// reset search query when modal opens\nwatch(\n\t() => isOpen,\n\tasync open => {\n\t\tif (open) {\n\t\t\tquery.value = ''\n\t\t\tselectedIndex.value = 0\n\t\t\tawait nextTick()\n\t\t\t;(inputRef.value as HTMLInputElement)?.focus()\n\t\t}\n\t}\n)\n\n// reset selected index when results change\nwatch(results, () => {\n\tselectedIndex.value = 0\n})\n\nconst closeModal = () => {\n\temit('close')\n}\n\nconst handleKeydown = (e: KeyboardEvent) => {\n\tswitch (e.key) {\n\t\tcase 'Escape':\n\t\t\tcloseModal()\n\t\t\tbreak\n\t\tcase 'ArrowDown':\n\t\t\te.preventDefault()\n\t\t\tif (results.value.length) {\n\t\t\t\tselectedIndex.value = (selectedIndex.value + 1) % results.value.length\n\t\t\t}\n\t\t\tbreak\n\t\tcase 'ArrowUp':\n\t\t\te.preventDefault()\n\t\t\tif (results.value.length) {\n\t\t\t\tselectedIndex.value = (selectedIndex.value - 1 + results.value.length) % results.value.length\n\t\t\t}\n\t\t\tbreak\n\t\tcase 'Enter':\n\t\t\tif (results.value.length && selectedIndex.value >= 0) {\n\t\t\t\tselectResult(results.value[selectedIndex.value])\n\t\t\t}\n\t\t\tbreak\n\t}\n}\n\nconst selectResult = (result: T) => {\n\temit('select', result)\n\tcloseModal()\n}\n</script>\n\n<style>\n.fade-enter-active,\n.fade-leave-active {\n\ttransition: opacity 0.2s ease;\n}\n\n.fade-enter-from,\n.fade-leave-to {\n\topacity: 0;\n}\n\n.command-palette-overlay {\n\tposition: fixed;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tbackground-color: rgba(0, 0, 0, 0.5);\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: center;\n\tz-index: 300;\n\tpadding-top: 100px;\n}\n\n.command-palette {\n\twidth: 600px;\n\tmax-width: 90%;\n\tbackground-color: white;\n\tborder-radius: 8px;\n\tbox-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n\toverflow: hidden;\n\tmax-height: 80vh;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.command-palette-header {\n\tdisplay: flex;\n\tborder-bottom: 1px solid #eaeaea;\n\tpadding: 12px;\n}\n\n.command-palette-input {\n\tflex: 1;\n\tborder: none;\n\toutline: none;\n\tfont-size: 16px;\n\tpadding: 8px 12px;\n\tbackground-color: transparent;\n}\n\n.command-palette-close {\n\tbackground: transparent;\n\tborder: none;\n\tfont-size: 24px;\n\tcursor: pointer;\n\tcolor: #666;\n\tpadding: 0 8px;\n}\n\n.command-palette-close:hover {\n\tcolor: #333;\n}\n\n.command-palette-results {\n\toverflow-y: auto;\n\tmax-height: 60vh;\n}\n\n.command-palette-result {\n\tpadding: 12px 16px;\n\tcursor: pointer;\n\tborder-bottom: 1px solid #f0f0f0;\n}\n\n.command-palette-result:hover,\n.command-palette-result.selected {\n\tbackground-color: #f5f5f5;\n}\n\n.command-palette-result.selected {\n\tbackground-color: rgba(132, 60, 3, 0.1);\n}\n\n.result-title {\n\tfont-weight: 500;\n\tmargin-bottom: 4px;\n\tcolor: #333;\n}\n\n.result-content {\n\tfont-size: 14px;\n\tcolor: #666;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.command-palette-no-results {\n\tpadding: 20px 16px;\n\ttext-align: center;\n\tcolor: #666;\n}\n</style>\n","<template>\n\t<footer>\n\t\t<ul class=\"tabs\">\n\t\t\t<li class=\"hidebreadcrumbs\" @click=\"toggleBreadcrumbs\" @keydown.enter=\"toggleBreadcrumbs\">\n\t\t\t\t<a tabindex=\"0\"><div :class=\"rotateHideTabIcon\">×</div></a>\n\t\t\t</li>\n\t\t\t<li\n\t\t\t\tclass=\"hometab\"\n\t\t\t\t:style=\"{ display: breadcrumbsVisibile ? 'block' : 'none' }\"\n\t\t\t\t@click=\"navigateHome\"\n\t\t\t\t@keydown.enter=\"navigateHome\">\n\t\t\t\t<router-link to=\"/\" tabindex=\"0\">\n\t\t\t\t\t<svg class=\"icon\" aria-label=\"Home\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n\t\t\t\t\t\t<path d=\"M3 12l9-9 9 9\" />\n\t\t\t\t\t\t<path d=\"M9 21V12h6v9\" />\n\t\t\t\t\t</svg>\n\t\t\t\t</router-link>\n\t\t\t</li>\n\t\t\t<li\n\t\t\t\t:class=\"['searchtab', { 'search-active': searchVisible }]\"\n\t\t\t\t:style=\"{ display: breadcrumbsVisibile ? 'block' : 'none' }\">\n\t\t\t\t<a tabindex=\"0\">\n\t\t\t\t\t<svg\n\t\t\t\t\t\tv-show=\"!searchVisible\"\n\t\t\t\t\t\tclass=\"icon search-icon\"\n\t\t\t\t\t\trole=\"button\"\n\t\t\t\t\t\taria-label=\"Search\"\n\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\t\t@click=\"toggleSearch\"\n\t\t\t\t\t\t@keydown.enter=\"toggleSearch\">\n\t\t\t\t\t\t<circle cx=\"11\" cy=\"11\" r=\"7\" />\n\t\t\t\t\t\t<path d=\"M21 21l-4.35-4.35\" />\n\t\t\t\t\t</svg>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-show=\"searchVisible\"\n\t\t\t\t\t\tref=\"searchinput\"\n\t\t\t\t\t\tv-model=\"searchText\"\n\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\tplaceholder=\"Search...\"\n\t\t\t\t\t\t@click.stop\n\t\t\t\t\t\t@input=\"handleSearchInput($event)\"\n\t\t\t\t\t\t@blur=\"handleSearch($event)\"\n\t\t\t\t\t\t@keydown.enter=\"handleSearch($event)\"\n\t\t\t\t\t\t@keydown.escape=\"toggleSearch\" />\n\t\t\t\t</a>\n\t\t\t</li>\n\t\t\t<li\n\t\t\t\tv-for=\"breadcrumb in breadcrumbs\"\n\t\t\t\t:key=\"breadcrumb.title\"\n\t\t\t\t:style=\"{ display: breadcrumbsVisibile ? 'block' : 'none' }\">\n\t\t\t\t<router-link tabindex=\"0\" :to=\"breadcrumb.to\"> {{ breadcrumb.title }} </router-link>\n\t\t\t</li>\n\t\t</ul>\n\t</footer>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, nextTick, ref, useTemplateRef } from 'vue'\n\nconst { breadcrumbs = [] } = defineProps<{ breadcrumbs?: { title: string; to: string }[] }>()\n\nconst breadcrumbsVisibile = ref(true)\nconst searchVisible = ref(false)\nconst searchText = ref('')\nconst inputRef = useTemplateRef<HTMLInputElement>('searchinput')\n\nconst rotateHideTabIcon = computed(() => {\n\treturn breadcrumbsVisibile.value ? 'unrotated' : 'rotated'\n})\n\nconst toggleBreadcrumbs = () => {\n\tbreadcrumbsVisibile.value = !breadcrumbsVisibile.value\n}\n\nconst toggleSearch = async () => {\n\tsearchVisible.value = !searchVisible.value\n\tawait nextTick(() => {\n\t\tinputRef.value?.focus()\n\t})\n}\n\nconst handleSearchInput = (event: Event | MouseEvent) => {\n\tevent.preventDefault()\n\tevent.stopPropagation()\n}\n\nconst handleSearch = async (event: FocusEvent | KeyboardEvent) => {\n\tevent.preventDefault()\n\tevent.stopPropagation()\n\tawait toggleSearch()\n}\n\nconst navigateHome = (/* event: MouseEvent | KeyboardEvent */) => {\n\t// navigate home\n}\n</script>\n\n<style scoped>\nfooter {\n\tposition: fixed;\n\tbottom: 0px;\n\twidth: 100%;\n\tbackground-color: transparent;\n\theight: auto;\n\tmin-height: 2.4rem;\n\tz-index: 100;\n\ttext-align: left;\n\tfont-size: 100%;\n\tdisplay: flex;\n\tjustify-content: right;\n\tpadding: 0 0.75rem 0 0;\n\tbox-sizing: border-box;\n}\nul {\n\tdisplay: flex;\n\tflex-direction: row-reverse;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.tabs li {\n\tfloat: left;\n\tlist-style-type: none;\n\tposition: relative;\n\tmargin-left: -1px;\n}\n\n/* Base tab styling */\n.tabs a {\n\tfloat: left;\n\tpadding: 0.5rem 1rem;\n\theight: 2.4rem;\n\tbox-sizing: border-box;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\ttext-decoration: none;\n\tcolor: var(--sc-gray-60, #666);\n\tbackground: var(--sc-btn-color, #ffffff);\n\tborder: 1px solid var(--sc-btn-border, #ccc);\n\tfont-size: 0.85rem;\n\tfont-family: var(--sc-font-family, system-ui, sans-serif);\n\ttransition: all 0.15s ease;\n\n\t/* Minimal ornamentation - subtle top radius only */\n\tborder-top-left-radius: 2px;\n\tborder-top-right-radius: 2px;\n}\n\n.tabs a:hover {\n\tbackground: var(--sc-btn-hover, #f2f2f2);\n}\n\n.tabs .router-link-active {\n\tz-index: 3;\n\tbackground: var(--sc-primary-color, #827553) !important;\n\tborder-color: var(--sc-primary-color, #827553) !important;\n\tcolor: var(--sc-primary-text-color, #fff) !important;\n}\n\n/* Pseudo-elements removed - minimal ornamentation style */\n\n/* Hide breadcrumbs tab */\n.hidebreadcrumbs a {\n\tmin-width: 2.4rem;\n\twidth: 2.4rem;\n\theight: 2.4rem;\n\tpadding: 0.5rem;\n\tbackground: var(--sc-btn-color, #ffffff);\n\tborder: 1px solid var(--sc-btn-border, #ccc);\n\tcolor: var(--sc-gray-60, #666);\n}\n\n.hidebreadcrumbs a div {\n\tfont-size: 1.2rem;\n}\n\n.rotated {\n\ttransform: rotate(45deg);\n\t-webkit-transform: rotate(45deg);\n\t-moz-transform: rotate(45deg);\n\t-ms-transform: rotate(45deg);\n\t-o-transform: rotate(45deg);\n\ttransition: transform 250ms ease;\n}\n.unrotated {\n\ttransform: rotate(0deg);\n\t-webkit-transform: rotate(0deg);\n\t-moz-transform: rotate(0deg);\n\t-ms-transform: rotate(0deg);\n\t-o-transform: rotate(0deg);\n\ttransition: transform 250ms ease;\n}\n\nli:active,\nli:hover,\nli:focus,\nli > a:active,\nli > a:hover,\nli > a:focus {\n\tz-index: 3;\n}\n\na:active,\na:hover,\na:focus {\n\toutline: 2px solid var(--sc-input-active-border-color, black);\n\tz-index: 3;\n}\n\n/* Home tab */\n.hometab a {\n\tmin-width: 2.4rem;\n\twidth: 2.4rem;\n\theight: 2.4rem;\n\tpadding: 0.5rem;\n\tbackground: var(--sc-btn-color, #ffffff);\n\tborder: 1px solid var(--sc-btn-border, #ccc);\n\tcolor: var(--sc-gray-60, #666);\n}\n\n/* SVG icon styling */\n.icon {\n\twidth: 1rem;\n\theight: 1rem;\n\tstroke: currentColor;\n\tflex-shrink: 0;\n}\n\n/* Search tab with animation */\n.searchtab {\n\toverflow: hidden;\n}\n\n.searchtab a {\n\tmin-width: 2.4rem;\n\theight: 2.4rem;\n\tpadding: 0.5rem;\n\tbackground: var(--sc-btn-color, #ffffff);\n\tborder: 1px solid var(--sc-btn-border, #ccc);\n\tcolor: var(--sc-gray-60, #666);\n\toverflow: hidden;\n\t/* Animation for smooth expand/collapse */\n\tmax-width: 2.4rem;\n\ttransition:\n\t\tmax-width 0.35s ease-in-out,\n\t\tpadding 0.35s ease-in-out,\n\t\tbackground 0.2s ease;\n}\n\n.searchtab .search-icon {\n\tcursor: pointer;\n}\n\n.searchtab input {\n\toutline: none;\n\tborder: 1px solid var(--sc-input-border-color, #ccc);\n\tborder-radius: 0.25rem;\n\tbackground-color: var(--sc-form-background, #ffffff);\n\tcolor: var(--sc-gray-80, #333);\n\ttext-align: left;\n\tfont-size: 0.875rem;\n\tpadding: 0.25rem 0.5rem;\n\twidth: 180px;\n\theight: 1.5rem;\n\tflex-shrink: 0;\n\topacity: 0;\n\ttransition: opacity 0.2s ease-in-out;\n\ttransition-delay: 0s;\n}\n\n.searchtab input:focus {\n\tborder-color: var(--sc-input-active-border-color, #4f46e5);\n\toutline: none;\n}\n\n.searchtab input::placeholder {\n\tcolor: var(--sc-input-label-color, #999);\n}\n\n/* Search active state - expanded with animation */\n.searchtab.search-active a {\n\tmax-width: 200px;\n\tmin-width: auto;\n\twidth: auto;\n\tpadding: 0.5rem 0.75rem;\n}\n\n.searchtab.search-active input {\n\topacity: 1;\n\ttransition-delay: 0.15s;\n}\n</style>\n","<template>\n\t<div class=\"desktop\" @click=\"handleClick\">\n\t\t<!-- Action Set -->\n\t\t<ActionSet :elements=\"actionElements\" @action-click=\"handleActionClick\" />\n\n\t\t<!-- Main content using AForm -->\n\t\t<AForm\n\t\t\tv-if=\"currentViewSchema.length > 0\"\n\t\t\tv-model:data=\"currentViewData\"\n\t\t\t:schema=\"currentViewSchema\"\n\t\t\t:errors=\"fieldErrors\" />\n\t\t<div v-else-if=\"!stonecrop\" class=\"loading\"><p>Initializing Stonecrop...</p></div>\n\t\t<div v-else class=\"loading\">\n\t\t\t<p>Loading {{ currentView }} data...</p>\n\t\t</div>\n\n\t\t<!-- Sheet Navigation -->\n\t\t<SheetNav :breadcrumbs=\"navigationBreadcrumbs\" />\n\n\t\t<!-- Command Palette -->\n\t\t<CommandPalette\n\t\t\t:is-open=\"commandPaletteOpen\"\n\t\t\t:search=\"searchCommands\"\n\t\t\tplaceholder=\"Type a command or search...\"\n\t\t\t@select=\"executeCommand\"\n\t\t\t@close=\"commandPaletteOpen = false\">\n\t\t\t<template #title=\"{ result }\">\n\t\t\t\t{{ result.title }}\n\t\t\t</template>\n\t\t\t<template #content=\"{ result }\">\n\t\t\t\t{{ result.description }}\n\t\t\t</template>\n\t\t</CommandPalette>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\n// The draft segment comes from @stonecrop/stonecrop rather than being spelled out here: that\n// package guards fetching, field initialization and workflow readiness on the same question, and\n// when the two were written separately they disagreed and every guard over there went dead.\nimport { DRAFT_RECORD_ID, isDraftRecordId, useStonecrop, useValidationStore } from '@stonecrop/stonecrop'\nimport {\n\tAForm,\n\ttype AFormLinkNavigator,\n\tresolvedFieldsToColumns,\n\ttype ResolvedField,\n\ttype ResolvedTable,\n} from '@stonecrop/aform'\nimport { componentLinkExpansion, type DoctypeField, flattenFields } from '@stonecrop/schema'\nimport { computed, onMounted, onUnmounted, provide, ref, unref, watch } from 'vue'\n\nimport ActionSet from './ActionSet.vue'\nimport SheetNav from './SheetNav.vue'\nimport CommandPalette from './CommandPalette.vue'\nimport type {\n\tActionElements,\n\tRouteAdapter,\n\tNavigationTarget,\n\tActionEventPayload,\n\tRecordOpenEventPayload,\n\tLoadRecordsEventPayload,\n\tLoadRecordEventPayload,\n} from '../types'\n\n/**\n * Inline link fields on a doctype — only these may be unwrapped back to a scalar id on write.\n *\n * Both the component and the doctype declaration decide what a field's value holds. An\n * *inline* link's value (`{ id, displayText }`) is indistinguishable by inspection from an\n * *expanded* one (`{ id, ...the whole target record }`), so the component is what tells them\n * apart.\n *\n * `componentLinkExpansion` is the same rule the adapter reads when it decides which links to\n * expand, so the two sides agree on what a field's value contains.\n */\nfunction inlineLinkFieldnames(fields: DoctypeField[]): Set<string> {\n\tconst links = flattenFields(fields).filter(field => field.kind === 'field' && Boolean(field.doctype))\n\n\treturn new Set(\n\t\tlinks.filter(field => componentLinkExpansion(field.component) === 'inline').map(field => field.fieldname)\n\t)\n}\n\n/**\n * Unwrap an inline link's value back to the id that gets persisted. Applied only to fields in\n * `inlineLinks` — the display text is a rendering concern and was never part of the record, while\n * an expanded link's object is the record and must survive the round trip intact.\n */\nfunction unwrapLinkValue(value: unknown): unknown {\n\tif (value !== null && typeof value === 'object' && !Array.isArray(value) && 'id' in value) {\n\t\treturn (value as { id: unknown }).id\n\t}\n\treturn value\n}\n\nconst { availableDoctypes = [], routeAdapter } = defineProps<{\n\tavailableDoctypes?: string[]\n\t/**\n\t * Pluggable router adapter. When provided, Desktop uses these functions for all\n\t * routing instead of reaching into the registry's internal Vue Router instance.\n\t * Nuxt hosts (or any host with custom route conventions) should supply this.\n\t */\n\trouteAdapter?: RouteAdapter\n}>()\n\nconst emit = defineEmits<{\n\t/**\n\t * Fired when the user triggers an FSM transition (action button click).\n\t * The host app is responsible for calling the server, persisting state, etc.\n\t */\n\taction: [payload: ActionEventPayload]\n\t/**\n\t * Fired when Desktop wants to navigate to a different view.\n\t * Also calls routeAdapter.navigate() if an adapter is provided.\n\t */\n\tnavigate: [target: NavigationTarget]\n\t/**\n\t * Fired when the user opens a specific record.\n\t */\n\t'record:open': [payload: RecordOpenEventPayload]\n\t/**\n\t * Fired when Desktop is about to read records for a list view. A notification, not a request:\n\t * Desktop performs the read itself through `Stonecrop.getRecords`. A host that fetches here\n\t * races that read into the same HST key.\n\t */\n\t'load-records': [payload: LoadRecordsEventPayload]\n\t/**\n\t * Fired when Desktop is about to read a single record for a form view. A notification, not a\n\t * request — see `load-records`. Not emitted for a draft, which has nothing to fetch.\n\t */\n\t'load-record': [payload: LoadRecordEventPayload]\n}>()\n\nconst { stonecrop } = useStonecrop()\n\n// Field-validation store (advisory, client-side). Pinia is a declared peerDependency, kept external\n// in this package's build (rollupOptions), so `useValidationStore()` resolves the host app's single\n// active Pinia directly — the old `getCurrentInstance().$pinia` workaround for the bundled-Pinia bug\n// is no longer needed. Still guarded: validation is optional and Desktop predates it, so a host that\n// mounts Desktop without Pinia disables validation gracefully instead of crashing on mount.\nlet validationStore: ReturnType<typeof useValidationStore> | null = null\ntry {\n\tvalidationStore = useValidationStore()\n} catch {\n\tvalidationStore = null\n}\n\n// Inline field errors handed to AForm. Only surfaced in the record form view (currentView is\n// defined below); empty elsewhere so a previous record's errors never bleed into a list view.\nconst fieldErrors = computed<Record<string, string[]>>(() =>\n\tcurrentView.value === 'record' ? (validationStore?.errorsByField ?? {}) : {}\n)\n\n// State\nconst loading = ref(false)\nconst commandPaletteOpen = ref(false)\n\n// The record being composed on a `/{doctype}/new` route. Deliberately not in HST: a draft has no\n// identity to be keyed by, and both ways of faking one fail — see `DRAFT_RECORD_ID`.\nconst draftRecord = ref<Record<string, any>>({})\n\n// Form/list data management — each view produces a different data shape.\n// List views (doctypes, records) return table row data keyed by fieldname.\n// Record view returns the record's fields for two-way binding — from HST, or from `draftRecord`\n// when the route is a draft.\nconst currentViewData = computed<Record<string, any>>({\n\tget() {\n\t\t// Doctypes list — rows come from availableDoctypes prop (reactive via availableDoctypes)\n\t\tif (currentView.value === 'doctypes') {\n\t\t\treturn {\n\t\t\t\tdoctypes_table:\n\t\t\t\t\tavailableDoctypes?.map(doctype => ({\n\t\t\t\t\t\tid: doctype,\n\t\t\t\t\t\tdoctype,\n\t\t\t\t\t\tdisplay_name: formatDoctypeName(doctype),\n\t\t\t\t\t\tactions: 'View Records',\n\t\t\t\t\t})) ?? [],\n\t\t\t}\n\t\t}\n\n\t\t// Records list — rows come from HST store (reactive because HST is Vue reactive())\n\t\tif (currentView.value === 'records') {\n\t\t\treturn {\n\t\t\t\trecords_table: getRecords().map(record =>\n\t\t\t\t\tObject.assign({}, record, {\n\t\t\t\t\t\tid: resolveRecordId(record) ?? '',\n\t\t\t\t\t\t// A list row is navigation. Actions live on the record view, where the Actions\n\t\t\t\t\t\t// dropdown is built from what the doctype declares and what the record's\n\t\t\t\t\t\t// current state allows. This cell used to also offer Delete, which dispatched\n\t\t\t\t\t\t// an action named `DELETE` that Desktop invented — no doctype in a\n\t\t\t\t\t\t// WorkflowMeta app declares it, so it failed on every click. Removal is a\n\t\t\t\t\t\t// workflow outcome (`archive`, `cancel`) and belongs in the doctype.\n\t\t\t\t\t\tactions: 'Edit',\n\t\t\t\t\t})\n\t\t\t\t),\n\t\t\t}\n\t\t}\n\n\t\t// Record form — read single record from HST\n\t\tif (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) {\n\t\t\treturn {}\n\t\t}\n\n\t\ttry {\n\t\t\tconst source = isNewRecord.value\n\t\t\t\t? draftRecord.value\n\t\t\t\t: (stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)?.get('') as\n\t\t\t\t\t\tRecord<string, any> | undefined)\n\t\t\t// Return a plain shallow copy so AForm mutations don't propagate directly into\n\t\t\t// the HST reactive object, which would bypass field-trigger diffing and cause\n\t\t\t// setupDeepReactivity to fire triggers for all fields on every keystroke.\n\t\t\tconst flat: Record<string, any> = { ...source }\n\n\t\t\t// AFieldset receives data[fieldsetFieldname] as its data prop, so the fieldset's\n\t\t\t// children must be grouped under the fieldset key. The server returns flat SQL rows,\n\t\t\t// so we nest fieldset children here before AForm renders them.\n\t\t\tconst doctype = stonecrop.value.registry.registry[currentDoctype.value]\n\t\t\tif (doctype) {\n\t\t\t\tfor (const field of doctype.getSchemaArray()) {\n\t\t\t\t\tif (field.kind === 'fieldset') {\n\t\t\t\t\t\tconst nested: Record<string, any> = {}\n\t\t\t\t\t\tfor (const child of field.schema) {\n\t\t\t\t\t\t\tif (child.fieldname) nested[child.fieldname] = flat[child.fieldname]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tflat[field.fieldname] = nested\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn flat\n\t\t} catch {\n\t\t\treturn {}\n\t\t}\n\t},\n\tset(newData: Record<string, any>) {\n\t\t// List views are read-only from AForm's perspective — HST writes only apply to record form\n\t\tif (currentView.value !== 'record') return\n\t\tif (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) {\n\t\t\treturn\n\t\t}\n\n\t\ttry {\n\t\t\t// AForm emits nested data for fieldsets: { fieldsetKey: { childA: val } }.\n\t\t\t// HST and the server both expect flat rows, so flatten fieldset values back before writing.\n\t\t\tconst doctype = stonecrop.value.registry.registry[currentDoctype.value]\n\t\t\tconst fieldsetNames = new Set<string>()\n\t\t\tif (doctype) {\n\t\t\t\tfor (const field of doctype.getSchemaArray()) {\n\t\t\t\t\tif (field.kind === 'fieldset') {\n\t\t\t\t\t\tfieldsetNames.add(field.fieldname)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst inlineLinks = inlineLinkFieldnames(doctype ? doctype.getSchemaArray() : [])\n\n\t\t\t// Two-pass flatten: non-fieldset keys first, then fieldset children.\n\t\t\t// Fieldset children must be applied last — AForm may emit stale flat copies\n\t\t\t// of fieldset children alongside the updated nested value, and the nested\n\t\t\t// value must win regardless of key insertion order.\n\t\t\tconst flatData: Record<string, any> = {}\n\t\t\tconst fieldsetValues: Record<string, any>[] = []\n\t\t\tfor (const [key, value] of Object.entries(newData)) {\n\t\t\t\tif (fieldsetNames.has(key) && value && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t\t\tfieldsetValues.push(value)\n\t\t\t\t} else {\n\t\t\t\t\tflatData[key] = value\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const nestedValue of fieldsetValues) {\n\t\t\t\tObject.assign(flatData, nestedValue)\n\t\t\t}\n\n\t\t\t// Only update fields that actually changed. Never write undefined — AForm may emit\n\t\t\t// schema fields absent from the record as undefined; writing them would silently\n\t\t\t// clear values that exist. Explicit null is allowed (intentional clear).\n\t\t\tconst changedFields: string[] = []\n\t\t\tif (isNewRecord.value) {\n\t\t\t\t// Reassigned, not mutated, so the getter re-runs. Relying on in-place mutation of the\n\t\t\t\t// cached object is what made a draft's edits vanish on any invalidation.\n\t\t\t\tconst next = { ...draftRecord.value }\n\t\t\t\tfor (const [fieldname, value] of Object.entries(flatData)) {\n\t\t\t\t\tif (value === undefined) continue\n\t\t\t\t\tconst normalized = inlineLinks.has(fieldname) ? unwrapLinkValue(value) : value\n\t\t\t\t\tif (next[fieldname] !== normalized) {\n\t\t\t\t\t\tnext[fieldname] = normalized\n\t\t\t\t\t\tchangedFields.push(fieldname)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdraftRecord.value = next\n\t\t\t} else {\n\t\t\t\tconst hstStore = stonecrop.value.getStore()\n\t\t\t\tfor (const [fieldname, value] of Object.entries(flatData)) {\n\t\t\t\t\tif (value === undefined) continue\n\t\t\t\t\tconst normalized = inlineLinks.has(fieldname) ? unwrapLinkValue(value) : value\n\t\t\t\t\tconst fieldPath = `${currentDoctype.value}.${currentRecordId.value}.${fieldname}`\n\t\t\t\t\tconst currentValue = hstStore.has(fieldPath) ? hstStore.get(fieldPath) : undefined\n\t\t\t\t\tif (currentValue !== normalized) {\n\t\t\t\t\t\thstStore.set(fieldPath, normalized)\n\t\t\t\t\t\tchangedFields.push(fieldname)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Advisory field-validation runs on the fields that actually changed (honors each\n\t\t\t// trigger's `on` set). Driven here, after the HST writes, so HST stays value-only.\n\t\t\tif (changedFields.length > 0) {\n\t\t\t\tdriveFieldValidation(changedFields)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('HST update failed:', error)\n\t\t}\n\t},\n})\n\n// Advisory field-validation: run the doctype's triggers for the fields that changed on this edit.\n// Snapshots the post-edit record as a plain, flat object so validators read siblings read-only\n// (the core store freezes it). Fire-and-forget — the reactive error store repaints AForm on resolve.\nfunction driveFieldValidation(changedFields: string[]) {\n\tif (!validationStore || !stonecrop.value || !currentDoctype.value || !currentRecordId.value) return\n\n\tconst doctype = stonecrop.value.registry.getDoctype(currentDoctype.value)\n\tconst triggers = doctype?.getTriggers()\n\tif (!triggers || Object.keys(triggers).length === 0) return\n\n\t// A draft's siblings come from the buffer; reading HST would hand every validator an empty record.\n\tconst record = isNewRecord.value\n\t\t? { ...draftRecord.value }\n\t\t: {\n\t\t\t\t...(stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)?.get('') as Record<\n\t\t\t\t\tstring,\n\t\t\t\t\tunknown\n\t\t\t\t>),\n\t\t\t}\n\n\tfor (const field of changedFields) {\n\t\tvoid validationStore.validateField(triggers, field, record)\n\t}\n}\n\n// Computed properties for current route context.\n// When a routeAdapter is provided it takes full precedence over the registry's internal router.\nconst route = computed(() => (routeAdapter ? null : unref(stonecrop.value?.registry.router?.currentRoute)))\nconst router = computed(() => (routeAdapter ? null : stonecrop.value?.registry.router))\nconst currentDoctype = computed(() => {\n\tif (routeAdapter) return routeAdapter.getCurrentDoctype()\n\tif (!route.value) return ''\n\n\t// First check if we have actualDoctype in meta (from registered routes)\n\tif (route.value.meta?.actualDoctype) {\n\t\treturn route.value.meta.actualDoctype as string\n\t}\n\n\t// For named routes, use params.doctype\n\tif (route.value.params.doctype) {\n\t\treturn route.value.params.doctype.toString()\n\t}\n\n\t// For catch-all routes that haven't been registered yet, extract from path\n\tconst pathMatch = route.value.params.pathMatch as string[] | undefined\n\tif (pathMatch && pathMatch.length > 0) {\n\t\treturn pathMatch[0]\n\t}\n\n\treturn ''\n})\n\n// The route doctype for display and navigation (e.g., 'todo')\nconst routeDoctype = computed(() => {\n\tif (routeAdapter) return routeAdapter.getCurrentDoctype()\n\tif (!route.value) return ''\n\n\t// Check route meta first\n\tif (route.value.meta?.doctype) {\n\t\treturn route.value.meta.doctype as string\n\t}\n\n\t// For named routes, use params.doctype\n\tif (route.value.params.doctype) {\n\t\treturn route.value.params.doctype.toString()\n\t}\n\n\t// For catch-all routes, extract from path\n\tconst pathMatch = route.value.params.pathMatch as string[] | undefined\n\tif (pathMatch && pathMatch.length > 0) {\n\t\treturn pathMatch[0]\n\t}\n\n\treturn ''\n})\n\nconst currentRecordId = computed(() => {\n\tif (routeAdapter) return routeAdapter.getCurrentRecordId()\n\tif (!route.value) return ''\n\n\t// For named routes, use params.recordId\n\tif (route.value.params.recordId) {\n\t\treturn route.value.params.recordId.toString()\n\t}\n\n\t// For catch-all routes that haven't been registered yet, extract from path\n\tconst pathMatch = route.value.params.pathMatch as string[] | undefined\n\tif (pathMatch && pathMatch.length > 1) {\n\t\treturn pathMatch[1]\n\t}\n\n\treturn ''\n})\nconst isNewRecord = computed(() => isDraftRecordId(currentRecordId.value))\n\n// Determine current view based on route\nconst currentView = computed(() => {\n\tif (routeAdapter) return routeAdapter.getCurrentView()\n\tif (!route.value) {\n\t\treturn 'doctypes'\n\t}\n\n\t// Home route\n\tif (route.value.name === 'home' || route.value.path === '/') {\n\t\treturn 'doctypes'\n\t}\n\n\t// Named routes from registered doctypes\n\tif (route.value.name && route.value.name !== 'catch-all') {\n\t\tconst routeName = route.value.name as string\n\t\tif (routeName.includes('form') || route.value.params.recordId) {\n\t\t\treturn 'record'\n\t\t} else if (routeName.includes('list') || route.value.params.doctype) {\n\t\t\treturn 'records'\n\t\t}\n\t}\n\n\t// Catch-all route - determine from path structure\n\tconst pathMatch = route.value.params.pathMatch as string[] | undefined\n\tif (pathMatch && pathMatch.length > 0) {\n\t\tconst view = pathMatch.length === 1 ? 'records' : 'record'\n\t\treturn view\n\t}\n\n\treturn 'doctypes'\n})\n\n// Computed properties (now that all helper functions are defined)\n// Helper function to get available transitions for current record.\n// Reads the actual FSM state from the record's `status` field (or falls back to the\n// workflow initial state) so the available action buttons always reflect reality.\nconst getAvailableTransitions = () => {\n\tif (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) {\n\t\treturn []\n\t}\n\n\ttry {\n\t\tconst doctype = stonecrop.value.registry.getDoctype(currentDoctype.value)\n\t\tif (!doctype?.workflow) return []\n\n\t\t// Delegate state resolution to Stonecrop — reads record 'status', falls back to workflow.initial\n\t\tconst currentState = stonecrop.value.getRecordState(currentDoctype.value, currentRecordId.value)\n\n\t\t// Delegate transition lookup to Doctype — no more manual workflow introspection\n\t\tconst transitions = doctype.getAvailableTransitions(currentState)\n\n\t\tconst recordData = currentViewData.value || {}\n\n\t\t// Each transition emits an 'action' event. The host app decides what to do\n\t\t// (call the server, trigger an FSM actor, update HST, etc.).\n\t\treturn transitions.map(({ name }) => ({\n\t\t\t// Prefer the workflow action's human-readable label (WorkflowMeta format);\n\t\t\t// fall back to the raw transition name for XState workflows with no action meta.\n\t\t\tlabel: doctype.getActionMeta(name)?.label ?? name,\n\t\t\taction: () => {\n\t\t\t\temit('action', {\n\t\t\t\t\tname,\n\t\t\t\t\tdoctype: currentDoctype.value,\n\t\t\t\t\trecordId: currentRecordId.value,\n\t\t\t\t\tdata: recordData,\n\t\t\t\t})\n\t\t\t},\n\t\t}))\n\t} catch (error) {\n\t\tconsole.warn('Error getting available transitions:', error)\n\t\treturn []\n\t}\n}\n\n// Helper: stateless Commands available for the current record — side-effect actions that\n// change no workflow state. Surfaced in the same Actions dropdown as transitions; each emits\n// the same 'action' event, so the host's handler runs a Command's clientHandler identically.\nconst getAvailableCommands = () => {\n\tif (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) {\n\t\treturn []\n\t}\n\n\ttry {\n\t\tconst doctype = stonecrop.value.registry.getDoctype(currentDoctype.value)\n\t\tif (!doctype?.workflow) return []\n\n\t\tconst currentState = stonecrop.value.getRecordState(currentDoctype.value, currentRecordId.value)\n\t\tconst commands = doctype.getAvailableCommands(currentState)\n\t\tconst recordData = currentViewData.value || {}\n\n\t\treturn commands.map(({ name }) => ({\n\t\t\tlabel: doctype.getActionMeta(name)?.label ?? name,\n\t\t\taction: () => {\n\t\t\t\temit('action', {\n\t\t\t\t\tname,\n\t\t\t\t\tdoctype: currentDoctype.value,\n\t\t\t\t\trecordId: currentRecordId.value,\n\t\t\t\t\tdata: recordData,\n\t\t\t\t})\n\t\t\t},\n\t\t}))\n\t} catch (error) {\n\t\tconsole.warn('Error getting available commands:', error)\n\t\treturn []\n\t}\n}\n\nconst actionElements = computed(() => {\n\tconst elements: ActionElements[] = []\n\n\tswitch (currentView.value) {\n\t\tcase 'records':\n\t\t\telements.push({\n\t\t\t\ttype: 'button',\n\t\t\t\tlabel: 'New Record',\n\t\t\t\taction: () => void createNewRecord(),\n\t\t\t})\n\t\t\tbreak\n\t\tcase 'record': {\n\t\t\t// Populate the Actions dropdown with every FSM transition AND stateless Command\n\t\t\t// available in the record's current state. Clicking either emits 'action'.\n\t\t\tconst recordActions = [...getAvailableTransitions(), ...getAvailableCommands()]\n\t\t\tif (recordActions.length > 0) {\n\t\t\t\telements.push({\n\t\t\t\t\ttype: 'dropdown',\n\t\t\t\t\tlabel: 'Actions',\n\t\t\t\t\tactions: recordActions,\n\t\t\t\t})\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn elements\n})\n\nconst navigationBreadcrumbs = computed(() => {\n\tconst breadcrumbs: { title: string; to: string }[] = []\n\n\tif (currentView.value === 'records' && routeDoctype.value) {\n\t\tbreadcrumbs.push(\n\t\t\t{ title: 'Home', to: '/' },\n\t\t\t{ title: formatDoctypeName(routeDoctype.value), to: `/${routeDoctype.value}` }\n\t\t)\n\t} else if (currentView.value === 'record' && routeDoctype.value) {\n\t\tconst recordPath = currentRecordId.value\n\t\t\t? `/${routeDoctype.value}/${currentRecordId.value}`\n\t\t\t: (route.value?.fullPath ?? '')\n\t\tbreadcrumbs.push(\n\t\t\t{ title: 'Home', to: '/' },\n\t\t\t{ title: formatDoctypeName(routeDoctype.value), to: `/${routeDoctype.value}` },\n\t\t\t{ title: isNewRecord.value ? 'New Record' : 'Edit Record', to: recordPath }\n\t\t)\n\t}\n\n\treturn breadcrumbs\n})\n\n// Command palette functionality\ntype Command = {\n\ttitle: string\n\tdescription: string\n\taction: () => void\n}\n\nconst searchCommands = (query: string): Command[] => {\n\tconst commands: Command[] = [\n\t\t{\n\t\t\ttitle: 'Go Home',\n\t\t\tdescription: 'Navigate to the home page',\n\t\t\taction: () => void doNavigate({ view: 'doctypes' }),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Toggle Command Palette',\n\t\t\tdescription: 'Open/close the command palette',\n\t\t\taction: () => (commandPaletteOpen.value = !commandPaletteOpen.value),\n\t\t},\n\t]\n\n\t// Add doctype-specific commands\n\tif (routeDoctype.value) {\n\t\tcommands.push({\n\t\t\ttitle: `View ${formatDoctypeName(routeDoctype.value)} Records`,\n\t\t\tdescription: `Navigate to ${routeDoctype.value} list`,\n\t\t\taction: () => void doNavigate({ view: 'records', doctype: routeDoctype.value }),\n\t\t})\n\n\t\tcommands.push({\n\t\t\ttitle: `Create New ${formatDoctypeName(routeDoctype.value)}`,\n\t\t\tdescription: `Create a new ${routeDoctype.value} record`,\n\t\t\taction: () => void createNewRecord(),\n\t\t})\n\t}\n\n\t// Add available doctypes as commands\n\tavailableDoctypes.forEach(doctype => {\n\t\tcommands.push({\n\t\t\ttitle: `View ${formatDoctypeName(doctype)}`,\n\t\t\tdescription: `Navigate to ${doctype} list`,\n\t\t\taction: () => void doNavigate({ view: 'records', doctype }),\n\t\t})\n\t})\n\n\t// Filter commands based on query\n\tif (!query) return commands\n\n\treturn commands.filter(\n\t\tcmd =>\n\t\t\tcmd.title.toLowerCase().includes(query.toLowerCase()) ||\n\t\t\tcmd.description.toLowerCase().includes(query.toLowerCase())\n\t)\n}\n\nconst executeCommand = (command: Command) => {\n\tcommand.action()\n\tcommandPaletteOpen.value = false\n}\n\n// List reads are wired on the records table; ATable owns the fetch via getRecords.\nconst listRecordsFetcher = (options?: import('@stonecrop/schema').GetRecordsOptions) => {\n\tif (!stonecrop.value || !currentDoctype.value) {\n\t\treturn Promise.resolve({ data: [], hasMore: false })\n\t}\n\tconst doctype = stonecrop.value.registry.getDoctype(currentDoctype.value)\n\tif (!doctype) {\n\t\treturn Promise.resolve({ data: [], hasMore: false })\n\t}\n\treturn stonecrop.value.getRecords(doctype, options)\n}\n\n// Helper functions - moved here to avoid \"before initialization\" errors\nconst formatDoctypeName = (doctype: string): string => {\n\treturn doctype\n\t\t.split('-')\n\t\t.map(word => word.charAt(0).toUpperCase() + word.slice(1))\n\t\t.join(' ')\n}\n\n// Internal navigation helper: emits 'navigate', then calls the adapter (if any)\n// or falls back to the registry's Vue Router instance.\nconst doNavigate = async (target: NavigationTarget) => {\n\temit('navigate', target)\n\tif (routeAdapter) {\n\t\tawait routeAdapter.navigate(target)\n\t} else {\n\t\tif (target.view === 'doctypes') {\n\t\t\tawait router.value?.push('/')\n\t\t} else if (target.view === 'records' && target.doctype) {\n\t\t\tawait router.value?.push(`/${target.doctype}`)\n\t\t} else if (target.view === 'record' && target.doctype && target.recordId) {\n\t\t\tawait router.value?.push(`/${target.doctype}/${target.recordId}`)\n\t\t}\n\t}\n}\n\nconst navigateToDoctype = async (doctype: string) => {\n\tawait doNavigate({ view: 'records', doctype })\n}\n\nconst openRecord = async (recordId: string) => {\n\tconst doctype = routeDoctype.value\n\temit('record:open', { doctype, recordId })\n\tawait doNavigate({ view: 'record', doctype, recordId })\n}\n\nconst createNewRecord = async () => {\n\tawait doNavigate({ view: 'record', doctype: routeDoctype.value, recordId: DRAFT_RECORD_ID })\n}\n\n// Schema generator functions - moved here to be available to computed properties\nconst getDoctypesSchema = (): ResolvedField[] => {\n\tif (!availableDoctypes?.length) return []\n\n\treturn [\n\t\t{\n\t\t\tkind: 'table' as const,\n\t\t\tfieldname: 'doctypes_table',\n\t\t\tcomponent: 'ATable',\n\t\t\tlabel: 'Doctypes',\n\t\t\tschema: [\n\t\t\t\t{\n\t\t\t\t\tfieldname: 'doctype',\n\t\t\t\t\tlabel: 'Doctype',\n\t\t\t\t\tcomponent: 'ATextInput',\n\t\t\t\t\talign: 'left' as const,\n\t\t\t\t\tedit: false,\n\t\t\t\t\twidth: '20ch',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfieldname: 'display_name',\n\t\t\t\t\tlabel: 'Name',\n\t\t\t\t\tcomponent: 'ATextInput',\n\t\t\t\t\talign: 'left' as const,\n\t\t\t\t\tedit: false,\n\t\t\t\t\twidth: '30ch',\n\t\t\t\t},\n\t\t\t\t// No record count column. It read `getRecordIds(doctype).length`, which is how many\n\t\t\t\t// records HST happens to hold — zero for a doctype never opened, and the page size\n\t\t\t\t// for one that was. The real total belongs to the backend and Desktop never asks\n\t\t\t\t// for it, so this shell cannot answer it. Same reason the `recordIdField` prop went.\n\t\t\t\t{\n\t\t\t\t\tfieldname: 'actions',\n\t\t\t\t\tlabel: 'Actions',\n\t\t\t\t\tcomponent: 'ATextInput',\n\t\t\t\t\talign: 'center' as const,\n\t\t\t\t\tedit: false,\n\t\t\t\t\twidth: '20ch',\n\t\t\t\t},\n\t\t\t],\n\t\t\tconfig: { view: 'list' as const, fullWidth: true },\n\t\t} satisfies ResolvedTable,\n\t]\n}\n\nconst getRecordsSchema = (): ResolvedField[] => {\n\tif (!currentDoctype.value) return []\n\tif (!stonecrop.value) return []\n\n\tconst registry = stonecrop.value.registry\n\tconst doctype = registry.registry[currentDoctype.value]\n\n\tif (!doctype) return []\n\n\tconst schema = registry.resolveSchema(doctype)\n\n\t// If no schema is available, let the template fallback handle the loading state\n\tif (schema.length === 0) return []\n\n\tconst doctypeSlug = currentDoctype.value\n\tconst clientConfigured = Boolean(stonecrop.value.getClient())\n\n\treturn [\n\t\t{\n\t\t\tkind: 'table' as const,\n\t\t\tfieldname: 'records_table',\n\t\t\tcomponent: 'ATable',\n\t\t\t// Which resolved fields a cell can render is answered once, in @stonecrop/aform, and\n\t\t\t// called by the child-table builder too. Flattening alone is not the rule: it kept the\n\t\t\t// expanding links, whose value is a nested record or an array of them.\n\t\t\tschema: [...resolvedFieldsToColumns(schema), { fieldname: 'actions', label: 'Actions', component: 'ATextInput' }],\n\t\t\tconfig: { view: 'list' as const, fullWidth: true },\n\t\t\t...(clientConfigured ? { getRecords: listRecordsFetcher, sourceKey: doctypeSlug } : {}),\n\t\t} satisfies ResolvedTable,\n\t]\n}\n\nconst getRecordFormSchema = (): ResolvedField[] => {\n\tif (!currentDoctype.value) return []\n\tif (!stonecrop.value) return []\n\n\ttry {\n\t\tconst registry = stonecrop.value?.registry\n\t\tconst doctype = registry?.registry[currentDoctype.value]\n\n\t\tif (!doctype?.schema) {\n\t\t\t// Let the template fallback handle the loading state\n\t\t\treturn []\n\t\t}\n\n\t\treturn registry.resolveSchema(doctype)\n\t} catch {\n\t\treturn []\n\t}\n}\n\n// Additional data helper functions\nconst getRecords = () => {\n\tif (!stonecrop.value || !currentDoctype.value) {\n\t\treturn []\n\t}\n\n\tconst recordsNode = stonecrop.value.records(currentDoctype.value)\n\tconst recordsData = recordsNode?.get('')\n\n\tif (recordsData && typeof recordsData === 'object' && !Array.isArray(recordsData)) {\n\t\treturn Object.values(recordsData as Record<string, any>)\n\t}\n\n\treturn []\n}\n\n// Schema for different views - defined here after all helper functions are available\nconst currentViewSchema = computed(() => {\n\tswitch (currentView.value) {\n\t\tcase 'doctypes':\n\t\t\treturn getDoctypesSchema()\n\t\tcase 'records':\n\t\t\treturn getRecordsSchema()\n\t\tcase 'record':\n\t\t\treturn getRecordFormSchema()\n\t\tdefault:\n\t\t\treturn []\n\t}\n})\n\nconst handleActionClick = (_label: string, action: (() => void | Promise<void>) | undefined) => {\n\tif (action) {\n\t\tvoid action()\n\t}\n}\n\n/**\n * Resolve a record's identity for links and navigation.\n *\n * Identity is declared once, on the doctype: `primaryKey`, or `id` when nothing is declared.\n * Delegating to `Doctype.getRecordId` is what guarantees this matches the key\n * `Stonecrop.getRecords` stored the record under — resolving it independently here would let a\n * row render a link to an HST path that does not exist.\n *\n * There is deliberately no per-shell override. Identity is a per-doctype fact and one shell\n * renders many doctypes, so a single prop cannot answer it; a shell that named a field would\n * also be overriding the very declaration the store keyed on, which is the bug above.\n */\nconst resolveRecordId = (record: Record<string, unknown>): string | undefined => {\n\tif (!stonecrop.value || !currentDoctype.value) return undefined\n\treturn stonecrop.value.registry.registry[currentDoctype.value]?.getRecordId(record)\n}\n\n// Event handlers\nconst getRecordIdFromRow = (rowElement: HTMLTableRowElement): string | null => {\n\tconst cell = rowElement.querySelector('td[data-rowindex]')\n\tif (!cell) return null\n\n\tconst rowIndexAttr = cell.getAttribute('data-rowindex')\n\tif (rowIndexAttr === null) return null\n\n\tconst rowIndex = parseInt(rowIndexAttr, 10)\n\tif (isNaN(rowIndex)) return null\n\n\tconst records = getRecords()\n\tconst record = records[rowIndex]\n\tif (!record) return null\n\n\treturn resolveRecordId(record) ?? null\n}\n\nconst handleClick = async (event: Event) => {\n\tconst target = event.target as HTMLElement\n\tconst action = target.getAttribute('data-action')\n\n\tif (action === 'create') {\n\t\tawait createNewRecord()\n\t}\n\n\tconst cell = target.closest('td, th')\n\tif (cell) {\n\t\tconst cellText = cell.textContent?.trim()\n\t\tconst row = cell.closest('tr')\n\n\t\tif (cellText === 'View Records' && row) {\n\t\t\t// Get the doctype from the row data\n\t\t\tconst cells = row.querySelectorAll('td')\n\t\t\tif (cells.length > 0) {\n\t\t\t\tconst doctypeCell = cells[1] // Assuming doctype is in second column (first column is index)\n\t\t\t\tconst doctype = doctypeCell.textContent?.trim()\n\t\t\t\tif (doctype) {\n\t\t\t\t\tawait navigateToDoctype(doctype)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cellText === 'Edit' && row) {\n\t\t\t// Matched exactly, not by substring. This handler is bound to the whole desktop, so a\n\t\t\t// substring match fired on any cell whose *data* happened to contain the word — a task\n\t\t\t// titled \"Delete old backups\" popped a delete confirmation when you clicked it.\n\t\t\tconst recordId = getRecordIdFromRow(row)\n\t\t\tif (recordId) {\n\t\t\t\tawait openRecord(recordId)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Reads go through Stonecrop, which owns whether to fetch, how to key the result, and where to\n// put it. Desktop asks for data and renders what arrives; it decides none of that itself.\n//\n// Both loaders are no-ops without a client, so a host that populates HST some other way keeps\n// working unchanged rather than taking a thrown error on every navigation.\nconst loadRecordData = async () => {\n\tif (!stonecrop.value || !currentDoctype.value || !stonecrop.value.getClient()) return\n\n\tloading.value = true\n\ttry {\n\t\tawait stonecrop.value.getRecord(currentDoctype.value, currentRecordId.value)\n\t} catch (error) {\n\t\tconsole.warn('Error fetching record:', error)\n\t} finally {\n\t\tloading.value = false\n\t}\n}\n\n// Watch for route changes to load appropriate data\nwatch(\n\t[currentView, currentDoctype, currentRecordId],\n\t() => {\n\t\t// The events are notifications, not fetch requests: they announce what Desktop is about to\n\t\t// read so a host can hang analytics or a prefetch off them. The read itself is Stonecrop's.\n\t\tif (currentView.value === 'records' && currentDoctype.value) {\n\t\t\temit('load-records', { doctype: currentDoctype.value })\n\t\t} else if (currentView.value === 'record' && currentDoctype.value && currentRecordId.value) {\n\t\t\t// A draft has nothing to fetch — the record does not exist on the server yet. Desktop\n\t\t\t// used to emit anyway and leave the host to work it out, which meant every host had to\n\t\t\t// recognise the private draft-id scheme above just to suppress a doomed request; all of\n\t\t\t// them did, identically. `getRecord` declines the same case for the same reason.\n\t\t\tif (isNewRecord.value) return\n\n\t\t\temit('load-record', { doctype: currentDoctype.value, recordId: currentRecordId.value })\n\t\t\tvoid loadRecordData()\n\t\t}\n\t},\n\t{ immediate: true }\n)\n\n// Clear advisory validation errors when the target record changes, so errors from a previously\n// edited record never bleed into a newly opened one.\nwatch([currentDoctype, currentRecordId], () => {\n\tvalidationStore?.clearAll()\n})\n\n// Seeding on entry gives a new record the doctype's declared defaults, which it never used to get.\n// Discarding on exit matters as much: the draft segment is one shared literal, so a stale buffer\n// would open the next New Record pre-filled with the abandoned one's values.\nwatch(\n\t[currentDoctype, currentRecordId],\n\t() => {\n\t\tif (!isNewRecord.value) {\n\t\t\tdraftRecord.value = {}\n\t\t\treturn\n\t\t}\n\t\tconst registry = stonecrop.value?.registry\n\t\tdraftRecord.value = registry ? registry.initializeRecord(getRecordFormSchema()) : {}\n\t},\n\t{ immediate: true }\n)\n\n// Stonecrop reactive computed properties update automatically when the instance\n// becomes available — no manual watcher needed.\n\n// Provide navigation helpers and an emitAction convenience function to child components.\nconst desktopMethods = {\n\tnavigateToDoctype,\n\topenRecord,\n\tcreateNewRecord,\n\t/**\n\t * Convenience wrapper so child components (e.g. slot content) can emit\n\t * an action event without needing a direct reference to the emit function.\n\t */\n\temitAction: (name: string, data?: Record<string, any>) => {\n\t\temit('action', {\n\t\t\tname,\n\t\t\tdoctype: currentDoctype.value,\n\t\t\trecordId: currentRecordId.value,\n\t\t\tdata: data ?? currentViewData.value ?? {},\n\t\t})\n\t},\n}\n\nprovide('desktopMethods', desktopMethods)\n\n// Provide a navigator for AFormLink so the arrow button navigates to the linked record.\nprovide('aformLinkNavigator', {\n\tnavigate: (doctype: string, id: string | number) => {\n\t\tvoid doNavigate({ view: 'record', doctype, recordId: String(id) })\n\t},\n} satisfies AFormLinkNavigator)\n\n// Provide a resolver for AFormLink to look up display text by doctype + id.\n// Checks HST first (sync); falls back to an async client fetch if not cached.\n// Uses the target doctype's declared displayField — no heuristic field guessing.\nprovide('aformLinkResolver', async (doctypeSlug: string, id: string): Promise<string | undefined> => {\n\tif (!stonecrop.value) return undefined\n\ttry {\n\t\tconst meta = await stonecrop.value.getMeta({ path: `/${doctypeSlug}`, segments: [doctypeSlug] })\n\t\tconst displayField = meta?.displayField\n\t\tif (!displayField) return undefined\n\n\t\tconst readDisplay = (rec: Record<string, unknown> | undefined): string | undefined => {\n\t\t\tif (!rec) return undefined\n\t\t\tconst val = rec[displayField]\n\t\t\treturn typeof val === 'string' || typeof val === 'number' ? String(val) : undefined\n\t\t}\n\n\t\tconst cached = stonecrop.value.getRecordById(doctypeSlug, id)?.get('') as Record<string, unknown> | undefined\n\t\tconst cachedDisplay = readDisplay(cached)\n\t\tif (cachedDisplay != null) return cachedDisplay\n\n\t\tawait stonecrop.value.getRecord(doctypeSlug, id)\n\t\tconst fetched = stonecrop.value.getRecordById(doctypeSlug, id)?.get('') as Record<string, unknown> | undefined\n\t\treturn readDisplay(fetched)\n\t} catch {\n\t\treturn undefined\n\t}\n})\n\nconst handleKeydown = (event: KeyboardEvent) => {\n\tif ((event.ctrlKey || event.metaKey) && event.key === 'k') {\n\t\tevent.preventDefault()\n\t\tcommandPaletteOpen.value = true\n\t}\n\tif (event.key === 'Escape' && commandPaletteOpen.value) {\n\t\tcommandPaletteOpen.value = false\n\t}\n}\n\nonMounted(() => {\n\tdocument.addEventListener('keydown', handleKeydown)\n})\n\nonUnmounted(() => {\n\tdocument.removeEventListener('keydown', handleKeydown)\n})\n</script>\n","import { App, type Plugin } from 'vue'\n\nimport ActionSet from '../components/ActionSet.vue'\nimport CommandPalette from '../components/CommandPalette.vue'\nimport Desktop from '../components/Desktop.vue'\nimport SheetNav from '../components/SheetNav.vue'\n\n/**\n * This is the main plugin that will be used to register all the desktop components.\n * @public\n */\nconst plugin: Plugin = {\n\tinstall: (app: App) => {\n\t\tapp.component('ActionSet', ActionSet)\n\t\tapp.component('CommandPalette', CommandPalette)\n\t\tapp.component('Desktop', Desktop)\n\t\tapp.component('SheetNav', SheetNav)\n\t},\n}\n\nexport default plugin\n"],"names":["emit","__emit","dropdownStates","ref","isOpen","dropdownOpen","onMounted","closeDropdowns","onClick","toggleDropdown","index","showDropdown","handleClick","action","label","_createElementBlock","_normalizeClass","_createElementVNode","_hoisted_1","_openBlock","_Fragment","_renderList","__props","el","_hoisted_2","$event","_toDisplayString","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_withDirectives","_hoisted_8","_hoisted_9","item","_hoisted_10","_hoisted_12","_vShow","query","selectedIndex","inputRef","useTemplateRef","results","computed","watch","open","nextTick","closeModal","handleKeydown","e","selectResult","result","_createBlock","_Teleport","_createVNode","_Transition","_renderSlot","_ctx","breadcrumbsVisibile","searchVisible","searchText","rotateHideTabIcon","toggleBreadcrumbs","toggleSearch","handleSearchInput","event","handleSearch","navigateHome","_component_router_link","_cache","_withKeys","breadcrumb","_createTextVNode","inlineLinkFieldnames","fields","links","flattenFields","field","componentLinkExpansion","unwrapLinkValue","value","stonecrop","useStonecrop","validationStore","useValidationStore","fieldErrors","currentView","loading","commandPaletteOpen","draftRecord","currentViewData","doctype","formatDoctypeName","getRecords","record","resolveRecordId","currentDoctype","currentRecordId","flat","isNewRecord","nested","child","newData","fieldsetNames","inlineLinks","flatData","fieldsetValues","key","nestedValue","changedFields","next","fieldname","normalized","hstStore","fieldPath","driveFieldValidation","error","triggers","route","unref","router","pathMatch","routeDoctype","isDraftRecordId","routeName","getAvailableTransitions","currentState","transitions","recordData","name","getAvailableCommands","commands","actionElements","elements","createNewRecord","recordActions","navigationBreadcrumbs","breadcrumbs","recordPath","searchCommands","doNavigate","cmd","executeCommand","command","listRecordsFetcher","options","word","target","navigateToDoctype","openRecord","recordId","DRAFT_RECORD_ID","getDoctypesSchema","getRecordsSchema","registry","schema","doctypeSlug","clientConfigured","resolvedFieldsToColumns","getRecordFormSchema","recordsData","currentViewSchema","handleActionClick","_label","getRecordIdFromRow","rowElement","cell","rowIndexAttr","rowIndex","cellText","row","cells","loadRecordData","provide","data","id","displayField","readDisplay","rec","val","cached","cachedDisplay","fetched","onUnmounted","ActionSet","_unref","AForm","SheetNav","CommandPalette","_withCtx","plugin","app","Desktop"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"desktop.js","sources":["../src/components/ActionSet.vue","../src/components/CommandPalette.vue","../src/components/SheetNav.vue","../src/components/Desktop.vue","../src/plugins/index.ts"],"sourcesContent":["<template>\n\t<div :class=\"{ collapsed: !isOpen }\" class=\"action-set\">\n\t\t<div class=\"action-menu-icon\">\n\t\t\t<div id=\"cross\" :class=\"{ rotated: isOpen }\" @click=\"onClick\">×</div>\n\t\t</div>\n\t\t<div style=\"margin-right: 30px\"></div>\n\t\t<div v-for=\"(el, index) in elements\" :key=\"el.label\" class=\"action-element\">\n\t\t\t<div class=\"action-element-header\">\n\t\t\t\t<button\n\t\t\t\t\tv-if=\"el.type == 'button'\"\n\t\t\t\t\t:disabled=\"el.disabled\"\n\t\t\t\t\tclass=\"button-default\"\n\t\t\t\t\t@click=\"handleClick(el.action, el.label)\">\n\t\t\t\t\t{{ el.label }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<div v-if=\"el.type == 'dropdown'\">\n\t\t\t\t<div class=\"dropdown-header\">\n\t\t\t\t\t<div class=\"cross\" :class=\"{ rotated: dropdownOpen[index] }\" @click=\"toggleDropdown(index)\">×</div>\n\t\t\t\t\t<button class=\"button-default dropdown-title\" @click=\"toggleDropdown(index)\">\n\t\t\t\t\t\t{{ el.label }}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t\t<div v-show=\"dropdownStates[index]\" class=\"dropdown-container\">\n\t\t\t\t\t<div class=\"dropdown\">\n\t\t\t\t\t\t<div v-for=\"item in el.actions\" :key=\"item.label\">\n\t\t\t\t\t\t\t<button v-if=\"item.action != null\" class=\"dropdown-item\" @click=\"handleClick(item.action, item.label)\">\n\t\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<a v-else-if=\"item.link != null\" :href=\"item.link\"\n\t\t\t\t\t\t\t\t><button class=\"dropdown-item\">{{ item.label }}</button></a\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, ref } from 'vue'\n\nimport type { ActionElements } from '../types'\n\nconst { elements = [] } = defineProps<{ elements?: ActionElements[] }>()\nconst emit = defineEmits<{\n\tactionClick: [label: string, action: (() => void | Promise<void>) | undefined]\n}>()\n\n// Track dropdown open state separately (index -> boolean)\nconst dropdownStates = ref<Record<number, boolean>>({})\n\nconst isOpen = ref(true)\nconst dropdownOpen = ref<boolean[]>([])\n\nonMounted(() => {\n\tcloseDropdowns()\n})\n\nconst closeDropdowns = () => {\n\tdropdownStates.value = {}\n\tdropdownOpen.value = []\n}\n\nconst onClick = () => {\n\tisOpen.value = !isOpen.value\n}\n\nconst toggleDropdown = (index: number) => {\n\tconst showDropdown = !dropdownStates.value[index]\n\tcloseDropdowns()\n\tif (showDropdown) {\n\t\tdropdownStates.value[index] = true\n\t\tdropdownOpen.value[index] = true\n\t}\n}\n\nconst handleClick = (action: (() => void | Promise<void>) | undefined, label: string) => {\n\t// Emit event to parent - parent will handle execution\n\temit('actionClick', label, action)\n}\n</script>\n\n<style scoped>\n#cross {\n\tposition: relative;\n\ttransform: rotate(45deg);\n\tcursor: pointer;\n\ttransition: all 0.2s ease-in-out;\n\tuser-select: none;\n\tline-height: 1rem;\n}\n#cross.rotated,\n.cross.rotated {\n\ttransform: rotate(0deg);\n}\n#cross svg {\n\twidth: 1.5em;\n\theight: 1.5em;\n}\n\n.action-set {\n\tposition: fixed;\n\ttop: 300px;\n\tright: 10px;\n\tpadding: 10px;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-end;\n\tbackground: var(--sc-form-background);\n\tborder: 1px solid var(--sc-gray-20);\n\tborder-left: 4px solid var(--sc-gray-20);\n\tborder-radius: 0;\n\toverflow: hidden;\n\tz-index: 1001; /* Above SheetNav (100) and operation log button (999) */\n\t-webkit-transition: all 0.5s ease-in-out;\n\t-moz-transition: all 0.5s ease-in-out;\n\t-o-transition: all 0.5s ease-in-out;\n\ttransition: all 0.5s ease-in-out;\n}\n.action-menu-icon {\n\tposition: relative;\n\tfont-size: 2rem;\n\tdisplay: inline-block;\n\tcolor: var(--sc-gray-60);\n\ttransition: all 0.2s ease-in-out;\n}\n.action-set.collapsed {\n\tmax-width: 46px;\n\tmax-height: 40px;\n\toverflow: hidden;\n}\n.action-set.collapsed .action-element {\n\topacity: 0;\n\t-webkit-transition: opacity 0.25s ease-in-out;\n\t-moz-transition: opacity 0.25s ease-in-out;\n\t-o-transition: opacity 0.25s ease-in-out;\n\ttransition: opacity 0.25s ease-in-out;\n}\n\n.action-element {\n\twidth: 100%;\n\ttext-align: right;\n\tborder: 1px solid var(--sc-gray-20);\n\tbackground: none;\n\tfont-size: 1.5rem;\n\tfont-family: var(--sc-font-family);\n\tfont-weight: 600;\n\tmargin-top: 10px;\n\tposition: relative; /* Make this the positioning context for absolute children */\n}\n.action-element-header {\n\tdisplay: flex;\n\tjustify-content: end;\n}\nbutton.button-default {\n\tbackground-color: transparent;\n\tpadding: 5px 12px;\n\tborder-radius: 0px;\n\tbox-shadow: none;\n\tborder: none;\n\tcursor: pointer;\n\twhite-space: nowrap;\n\tfont-weight: bold;\n\tfont-size: 1rem;\n\ttext-align: right;\n\tcolor: var(--sc-gray-80);\n\tpadding-left: 50px;\n\tfont-family: var(--sc-font-family);\n}\n.dropdown-header:hover button.button-default,\n.dropdown-header:hover,\n.action-element-header:hover {\n\tbackground-color: #f2f2f2;\n}\n\n.dropdown-title {\n\tposition: relative;\n}\n.dropdown-header {\n\tdisplay: flex;\n\talign-items: center;\n}\n.cross {\n\tpointer-events: all;\n\tmargin-left: 5px;\n\tfont-family: var(--sc-font-family);\n\tcolor: var(--sc-gray-60);\n\tcursor: pointer;\n\ttransform: rotate(45deg);\n\tuser-select: none;\n\ttransition: all 0.2s ease-in-out;\n\tline-height: 1rem;\n}\n\nbutton.dropdown-item {\n\twidth: 100%;\n\tpadding: 5px 12px;\n\ttext-align: right;\n\tborder: none;\n\tbackground-color: #ffffff;\n\tcursor: pointer;\n\tborder-radius: 5px;\n\tfont-size: 1rem;\n}\n\nbutton.dropdown-item:hover {\n\tbackground-color: #f2f2f2;\n}\n</style>\n","<template>\n\t<Teleport to=\"body\">\n\t\t<Transition name=\"fade\">\n\t\t\t<div v-if=\"isOpen\" class=\"command-palette-overlay\" @click=\"closeModal\">\n\t\t\t\t<div class=\"command-palette\" @click.stop>\n\t\t\t\t\t<div class=\"command-palette-header\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\tref=\"input\"\n\t\t\t\t\t\t\tv-model=\"query\"\n\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\tclass=\"command-palette-input\"\n\t\t\t\t\t\t\t:placeholder=\"placeholder\"\n\t\t\t\t\t\t\tautofocus\n\t\t\t\t\t\t\t@keydown=\"handleKeydown\" />\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div v-if=\"results.length\" class=\"command-palette-results\">\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tv-for=\"(result, index) in results\"\n\t\t\t\t\t\t\t:key=\"index\"\n\t\t\t\t\t\t\tclass=\"command-palette-result\"\n\t\t\t\t\t\t\t:class=\"{ selected: index === selectedIndex }\"\n\t\t\t\t\t\t\t@click=\"selectResult(result)\"\n\t\t\t\t\t\t\t@mouseover=\"selectedIndex = index\">\n\t\t\t\t\t\t\t<div class=\"result-title\">\n\t\t\t\t\t\t\t\t<slot name=\"title\" :result=\"result\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"result-content\">\n\t\t\t\t\t\t\t\t<slot name=\"content\" :result=\"result\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div v-else-if=\"query && !results.length\" class=\"command-palette-no-results\">\n\t\t\t\t\t\t<slot name=\"empty\"> No results found for \"{{ query }}\" </slot>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</Transition>\n\t</Teleport>\n</template>\n\n<script setup lang=\"ts\" generic=\"T\">\nimport { ref, computed, watch, nextTick, useTemplateRef } from 'vue'\n\ndefineSlots<{\n\ttitle?: { result: T }\n\tcontent?: { result: T }\n\tempty?: null\n}>()\n\nconst {\n\tsearch,\n\tisOpen = false,\n\tplaceholder = 'Type a command or search...',\n\tmaxResults = 10,\n} = defineProps<{\n\tsearch: (query: string) => T[]\n\tisOpen?: boolean\n\tplaceholder?: string\n\tmaxResults?: number\n}>()\n\nconst emit = defineEmits<{\n\tselect: [T]\n\tclose: []\n}>()\n\nconst query = ref('')\nconst selectedIndex = ref(0)\nconst inputRef = useTemplateRef('input')\n\nconst results = computed(() => {\n\tif (!query.value) return []\n\tconst searchResults = search(query.value)\n\treturn searchResults.slice(0, maxResults)\n})\n\n// reset search query when modal opens\nwatch(\n\t() => isOpen,\n\tasync open => {\n\t\tif (open) {\n\t\t\tquery.value = ''\n\t\t\tselectedIndex.value = 0\n\t\t\tawait nextTick()\n\t\t\t;(inputRef.value as HTMLInputElement)?.focus()\n\t\t}\n\t}\n)\n\n// reset selected index when results change\nwatch(results, () => {\n\tselectedIndex.value = 0\n})\n\nconst closeModal = () => {\n\temit('close')\n}\n\nconst handleKeydown = (e: KeyboardEvent) => {\n\tswitch (e.key) {\n\t\tcase 'Escape':\n\t\t\tcloseModal()\n\t\t\tbreak\n\t\tcase 'ArrowDown':\n\t\t\te.preventDefault()\n\t\t\tif (results.value.length) {\n\t\t\t\tselectedIndex.value = (selectedIndex.value + 1) % results.value.length\n\t\t\t}\n\t\t\tbreak\n\t\tcase 'ArrowUp':\n\t\t\te.preventDefault()\n\t\t\tif (results.value.length) {\n\t\t\t\tselectedIndex.value = (selectedIndex.value - 1 + results.value.length) % results.value.length\n\t\t\t}\n\t\t\tbreak\n\t\tcase 'Enter':\n\t\t\tif (results.value.length && selectedIndex.value >= 0) {\n\t\t\t\tselectResult(results.value[selectedIndex.value])\n\t\t\t}\n\t\t\tbreak\n\t}\n}\n\nconst selectResult = (result: T) => {\n\temit('select', result)\n\tcloseModal()\n}\n</script>\n\n<style>\n.fade-enter-active,\n.fade-leave-active {\n\ttransition: opacity 0.2s ease;\n}\n\n.fade-enter-from,\n.fade-leave-to {\n\topacity: 0;\n}\n\n.command-palette-overlay {\n\tposition: fixed;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tbackground-color: rgba(0, 0, 0, 0.5);\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: center;\n\tz-index: 300;\n\tpadding-top: 100px;\n}\n\n.command-palette {\n\twidth: 600px;\n\tmax-width: 90%;\n\tbackground-color: white;\n\tborder-radius: 8px;\n\tbox-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n\toverflow: hidden;\n\tmax-height: 80vh;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.command-palette-header {\n\tdisplay: flex;\n\tborder-bottom: 1px solid #eaeaea;\n\tpadding: 12px;\n}\n\n.command-palette-input {\n\tflex: 1;\n\tborder: none;\n\toutline: none;\n\tfont-size: 16px;\n\tpadding: 8px 12px;\n\tbackground-color: transparent;\n}\n\n.command-palette-close {\n\tbackground: transparent;\n\tborder: none;\n\tfont-size: 24px;\n\tcursor: pointer;\n\tcolor: #666;\n\tpadding: 0 8px;\n}\n\n.command-palette-close:hover {\n\tcolor: #333;\n}\n\n.command-palette-results {\n\toverflow-y: auto;\n\tmax-height: 60vh;\n}\n\n.command-palette-result {\n\tpadding: 12px 16px;\n\tcursor: pointer;\n\tborder-bottom: 1px solid #f0f0f0;\n}\n\n.command-palette-result:hover,\n.command-palette-result.selected {\n\tbackground-color: #f5f5f5;\n}\n\n.command-palette-result.selected {\n\tbackground-color: rgba(132, 60, 3, 0.1);\n}\n\n.result-title {\n\tfont-weight: 500;\n\tmargin-bottom: 4px;\n\tcolor: #333;\n}\n\n.result-content {\n\tfont-size: 14px;\n\tcolor: #666;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.command-palette-no-results {\n\tpadding: 20px 16px;\n\ttext-align: center;\n\tcolor: #666;\n}\n</style>\n","<template>\n\t<footer>\n\t\t<ul class=\"tabs\">\n\t\t\t<li class=\"hidebreadcrumbs\" @click=\"toggleBreadcrumbs\" @keydown.enter=\"toggleBreadcrumbs\">\n\t\t\t\t<a tabindex=\"0\"><div :class=\"rotateHideTabIcon\">×</div></a>\n\t\t\t</li>\n\t\t\t<li\n\t\t\t\tclass=\"hometab\"\n\t\t\t\t:style=\"{ display: breadcrumbsVisibile ? 'block' : 'none' }\"\n\t\t\t\t@click=\"navigateHome\"\n\t\t\t\t@keydown.enter=\"navigateHome\">\n\t\t\t\t<router-link to=\"/\" tabindex=\"0\">\n\t\t\t\t\t<svg class=\"icon\" aria-label=\"Home\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n\t\t\t\t\t\t<path d=\"M3 12l9-9 9 9\" />\n\t\t\t\t\t\t<path d=\"M9 21V12h6v9\" />\n\t\t\t\t\t</svg>\n\t\t\t\t</router-link>\n\t\t\t</li>\n\t\t\t<li\n\t\t\t\t:class=\"['searchtab', { 'search-active': searchVisible }]\"\n\t\t\t\t:style=\"{ display: breadcrumbsVisibile ? 'block' : 'none' }\">\n\t\t\t\t<a tabindex=\"0\">\n\t\t\t\t\t<svg\n\t\t\t\t\t\tv-show=\"!searchVisible\"\n\t\t\t\t\t\tclass=\"icon search-icon\"\n\t\t\t\t\t\trole=\"button\"\n\t\t\t\t\t\taria-label=\"Search\"\n\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\t\t@click=\"toggleSearch\"\n\t\t\t\t\t\t@keydown.enter=\"toggleSearch\">\n\t\t\t\t\t\t<circle cx=\"11\" cy=\"11\" r=\"7\" />\n\t\t\t\t\t\t<path d=\"M21 21l-4.35-4.35\" />\n\t\t\t\t\t</svg>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-show=\"searchVisible\"\n\t\t\t\t\t\tref=\"searchinput\"\n\t\t\t\t\t\tv-model=\"searchText\"\n\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\tplaceholder=\"Search...\"\n\t\t\t\t\t\t@click.stop\n\t\t\t\t\t\t@input=\"handleSearchInput($event)\"\n\t\t\t\t\t\t@blur=\"handleSearch($event)\"\n\t\t\t\t\t\t@keydown.enter=\"handleSearch($event)\"\n\t\t\t\t\t\t@keydown.escape=\"toggleSearch\" />\n\t\t\t\t</a>\n\t\t\t</li>\n\t\t\t<li\n\t\t\t\tv-for=\"breadcrumb in breadcrumbs\"\n\t\t\t\t:key=\"breadcrumb.title\"\n\t\t\t\t:style=\"{ display: breadcrumbsVisibile ? 'block' : 'none' }\">\n\t\t\t\t<router-link tabindex=\"0\" :to=\"breadcrumb.to\"> {{ breadcrumb.title }} </router-link>\n\t\t\t</li>\n\t\t</ul>\n\t</footer>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, nextTick, ref, useTemplateRef } from 'vue'\n\nconst { breadcrumbs = [] } = defineProps<{ breadcrumbs?: { title: string; to: string }[] }>()\n\nconst breadcrumbsVisibile = ref(true)\nconst searchVisible = ref(false)\nconst searchText = ref('')\nconst inputRef = useTemplateRef<HTMLInputElement>('searchinput')\n\nconst rotateHideTabIcon = computed(() => {\n\treturn breadcrumbsVisibile.value ? 'unrotated' : 'rotated'\n})\n\nconst toggleBreadcrumbs = () => {\n\tbreadcrumbsVisibile.value = !breadcrumbsVisibile.value\n}\n\nconst toggleSearch = async () => {\n\tsearchVisible.value = !searchVisible.value\n\tawait nextTick(() => {\n\t\tinputRef.value?.focus()\n\t})\n}\n\nconst handleSearchInput = (event: Event | MouseEvent) => {\n\tevent.preventDefault()\n\tevent.stopPropagation()\n}\n\nconst handleSearch = async (event: FocusEvent | KeyboardEvent) => {\n\tevent.preventDefault()\n\tevent.stopPropagation()\n\tawait toggleSearch()\n}\n\nconst navigateHome = (/* event: MouseEvent | KeyboardEvent */) => {\n\t// navigate home\n}\n</script>\n\n<style scoped>\nfooter {\n\tposition: fixed;\n\tbottom: 0px;\n\twidth: 100%;\n\tbackground-color: transparent;\n\theight: auto;\n\tmin-height: 2.4rem;\n\tz-index: 100;\n\ttext-align: left;\n\tfont-size: 100%;\n\tdisplay: flex;\n\tjustify-content: right;\n\tpadding: 0 0.75rem 0 0;\n\tbox-sizing: border-box;\n}\nul {\n\tdisplay: flex;\n\tflex-direction: row-reverse;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.tabs li {\n\tfloat: left;\n\tlist-style-type: none;\n\tposition: relative;\n\tmargin-left: -1px;\n}\n\n/* Base tab styling */\n.tabs a {\n\tfloat: left;\n\tpadding: 0.5rem 1rem;\n\theight: 2.4rem;\n\tbox-sizing: border-box;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\ttext-decoration: none;\n\tcolor: var(--sc-gray-60);\n\tbackground: var(--sc-btn-color);\n\tborder: 1px solid var(--sc-btn-border);\n\tfont-size: 0.85rem;\n\tfont-family: var(--sc-font-family);\n\ttransition: all 0.15s ease;\n\n\t/* Minimal ornamentation - subtle top radius only */\n\tborder-top-left-radius: 2px;\n\tborder-top-right-radius: 2px;\n}\n\n.tabs a:hover {\n\tbackground: var(--sc-btn-hover);\n}\n\n.tabs .router-link-active {\n\tz-index: 3;\n\tbackground: var(--sc-primary-color) !important;\n\tborder-color: var(--sc-primary-color) !important;\n\tcolor: var(--sc-primary-text-color) !important;\n}\n\n/* Pseudo-elements removed - minimal ornamentation style */\n\n/* Hide breadcrumbs tab */\n.hidebreadcrumbs a {\n\tmin-width: 2.4rem;\n\twidth: 2.4rem;\n\theight: 2.4rem;\n\tpadding: 0.5rem;\n\tbackground: var(--sc-btn-color);\n\tborder: 1px solid var(--sc-btn-border);\n\tcolor: var(--sc-gray-60);\n}\n\n.hidebreadcrumbs a div {\n\tfont-size: 1.2rem;\n}\n\n.rotated {\n\ttransform: rotate(45deg);\n\t-webkit-transform: rotate(45deg);\n\t-moz-transform: rotate(45deg);\n\t-ms-transform: rotate(45deg);\n\t-o-transform: rotate(45deg);\n\ttransition: transform 250ms ease;\n}\n.unrotated {\n\ttransform: rotate(0deg);\n\t-webkit-transform: rotate(0deg);\n\t-moz-transform: rotate(0deg);\n\t-ms-transform: rotate(0deg);\n\t-o-transform: rotate(0deg);\n\ttransition: transform 250ms ease;\n}\n\nli:active,\nli:hover,\nli:focus,\nli > a:active,\nli > a:hover,\nli > a:focus {\n\tz-index: 3;\n}\n\na:active,\na:hover,\na:focus {\n\toutline: 2px solid var(--sc-input-active-border-color);\n\tz-index: 3;\n}\n\n/* Home tab */\n.hometab a {\n\tmin-width: 2.4rem;\n\twidth: 2.4rem;\n\theight: 2.4rem;\n\tpadding: 0.5rem;\n\tbackground: var(--sc-btn-color);\n\tborder: 1px solid var(--sc-btn-border);\n\tcolor: var(--sc-gray-60);\n}\n\n/* SVG icon styling */\n.icon {\n\twidth: 1rem;\n\theight: 1rem;\n\tstroke: currentColor;\n\tflex-shrink: 0;\n}\n\n/* Search tab with animation */\n.searchtab {\n\toverflow: hidden;\n}\n\n.searchtab a {\n\tmin-width: 2.4rem;\n\theight: 2.4rem;\n\tpadding: 0.5rem;\n\tbackground: var(--sc-btn-color);\n\tborder: 1px solid var(--sc-btn-border);\n\tcolor: var(--sc-gray-60);\n\toverflow: hidden;\n\t/* Animation for smooth expand/collapse */\n\tmax-width: 2.4rem;\n\ttransition:\n\t\tmax-width 0.35s ease-in-out,\n\t\tpadding 0.35s ease-in-out,\n\t\tbackground 0.2s ease;\n}\n\n.searchtab .search-icon {\n\tcursor: pointer;\n}\n\n.searchtab input {\n\toutline: none;\n\tborder: 1px solid var(--sc-input-border-color);\n\tborder-radius: 0.25rem;\n\tbackground-color: var(--sc-form-background);\n\tcolor: var(--sc-gray-80);\n\ttext-align: left;\n\tfont-size: 0.875rem;\n\tpadding: 0.25rem 0.5rem;\n\twidth: 180px;\n\theight: 1.5rem;\n\tflex-shrink: 0;\n\topacity: 0;\n\ttransition: opacity 0.2s ease-in-out;\n\ttransition-delay: 0s;\n}\n\n.searchtab input:focus {\n\tborder-color: var(--sc-input-active-border-color);\n\toutline: none;\n}\n\n.searchtab input::placeholder {\n\tcolor: var(--sc-input-label-color);\n}\n\n/* Search active state - expanded with animation */\n.searchtab.search-active a {\n\tmax-width: 200px;\n\tmin-width: auto;\n\twidth: auto;\n\tpadding: 0.5rem 0.75rem;\n}\n\n.searchtab.search-active input {\n\topacity: 1;\n\ttransition-delay: 0.15s;\n}\n</style>\n","<template>\n\t<div class=\"desktop\" @click=\"handleClick\">\n\t\t<!-- Action Set -->\n\t\t<ActionSet :elements=\"actionElements\" @action-click=\"handleActionClick\" />\n\n\t\t<!-- Main content using AForm -->\n\t\t<AForm\n\t\t\tv-if=\"currentViewSchema.length > 0\"\n\t\t\tv-model:data=\"currentViewData\"\n\t\t\t:schema=\"currentViewSchema\"\n\t\t\t:errors=\"fieldErrors\" />\n\t\t<div v-else-if=\"!stonecrop\" class=\"loading\"><p>Initializing Stonecrop...</p></div>\n\t\t<div v-else class=\"loading\">\n\t\t\t<p>Loading {{ currentView }} data...</p>\n\t\t</div>\n\n\t\t<!-- Sheet Navigation -->\n\t\t<SheetNav :breadcrumbs=\"navigationBreadcrumbs\" />\n\n\t\t<!-- Command Palette -->\n\t\t<CommandPalette\n\t\t\t:is-open=\"commandPaletteOpen\"\n\t\t\t:search=\"searchCommands\"\n\t\t\tplaceholder=\"Type a command or search...\"\n\t\t\t@select=\"executeCommand\"\n\t\t\t@close=\"commandPaletteOpen = false\">\n\t\t\t<template #title=\"{ result }\">\n\t\t\t\t{{ result.title }}\n\t\t\t</template>\n\t\t\t<template #content=\"{ result }\">\n\t\t\t\t{{ result.description }}\n\t\t\t</template>\n\t\t</CommandPalette>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\n// The draft segment comes from @stonecrop/stonecrop rather than being spelled out here: that\n// package guards fetching, field initialization and workflow readiness on the same question, and\n// when the two were written separately they disagreed and every guard over there went dead.\nimport { DRAFT_RECORD_ID, isDraftRecordId, useStonecrop, useValidationStore } from '@stonecrop/stonecrop'\nimport {\n\tAForm,\n\ttype AFormLinkNavigator,\n\tresolvedFieldsToColumns,\n\ttype ResolvedField,\n\ttype ResolvedTable,\n} from '@stonecrop/aform'\nimport { componentLinkExpansion, type DoctypeField, flattenFields } from '@stonecrop/schema'\nimport { computed, onMounted, onUnmounted, provide, ref, unref, watch } from 'vue'\n\nimport ActionSet from './ActionSet.vue'\nimport SheetNav from './SheetNav.vue'\nimport CommandPalette from './CommandPalette.vue'\nimport type {\n\tActionElements,\n\tRouteAdapter,\n\tNavigationTarget,\n\tActionEventPayload,\n\tRecordOpenEventPayload,\n\tLoadRecordsEventPayload,\n\tLoadRecordEventPayload,\n} from '../types'\n\n/**\n * Inline link fields on a doctype — only these may be unwrapped back to a scalar id on write.\n *\n * Both the component and the doctype declaration decide what a field's value holds. An\n * *inline* link's value (`{ id, displayText }`) is indistinguishable by inspection from an\n * *expanded* one (`{ id, ...the whole target record }`), so the component is what tells them\n * apart.\n *\n * `componentLinkExpansion` is the same rule the adapter reads when it decides which links to\n * expand, so the two sides agree on what a field's value contains.\n */\nfunction inlineLinkFieldnames(fields: DoctypeField[]): Set<string> {\n\tconst links = flattenFields(fields).filter(field => field.kind === 'field' && Boolean(field.doctype))\n\n\treturn new Set(\n\t\tlinks.filter(field => componentLinkExpansion(field.component) === 'inline').map(field => field.fieldname)\n\t)\n}\n\n/**\n * Unwrap an inline link's value back to the id that gets persisted. Applied only to fields in\n * `inlineLinks` — the display text is a rendering concern and was never part of the record, while\n * an expanded link's object is the record and must survive the round trip intact.\n */\nfunction unwrapLinkValue(value: unknown): unknown {\n\tif (value !== null && typeof value === 'object' && !Array.isArray(value) && 'id' in value) {\n\t\treturn (value as { id: unknown }).id\n\t}\n\treturn value\n}\n\nconst { availableDoctypes = [], routeAdapter } = defineProps<{\n\tavailableDoctypes?: string[]\n\t/**\n\t * Pluggable router adapter. When provided, Desktop uses these functions for all\n\t * routing instead of reaching into the registry's internal Vue Router instance.\n\t * Nuxt hosts (or any host with custom route conventions) should supply this.\n\t */\n\trouteAdapter?: RouteAdapter\n}>()\n\nconst emit = defineEmits<{\n\t/**\n\t * Fired when the user triggers an FSM transition (action button click).\n\t * The host app is responsible for calling the server, persisting state, etc.\n\t */\n\taction: [payload: ActionEventPayload]\n\t/**\n\t * Fired when Desktop wants to navigate to a different view.\n\t * Also calls routeAdapter.navigate() if an adapter is provided.\n\t */\n\tnavigate: [target: NavigationTarget]\n\t/**\n\t * Fired when the user opens a specific record.\n\t */\n\t'record:open': [payload: RecordOpenEventPayload]\n\t/**\n\t * Fired when Desktop is about to read records for a list view. A notification, not a request:\n\t * Desktop performs the read itself through `Stonecrop.getRecords`. A host that fetches here\n\t * races that read into the same HST key.\n\t */\n\t'load-records': [payload: LoadRecordsEventPayload]\n\t/**\n\t * Fired when Desktop is about to read a single record for a form view. A notification, not a\n\t * request — see `load-records`. Not emitted for a draft, which has nothing to fetch.\n\t */\n\t'load-record': [payload: LoadRecordEventPayload]\n}>()\n\nconst { stonecrop } = useStonecrop()\n\n// Field-validation store (advisory, client-side). Pinia is a declared peerDependency, kept external\n// in this package's build (rollupOptions), so `useValidationStore()` resolves the host app's single\n// active Pinia directly — the old `getCurrentInstance().$pinia` workaround for the bundled-Pinia bug\n// is no longer needed. Still guarded: validation is optional and Desktop predates it, so a host that\n// mounts Desktop without Pinia disables validation gracefully instead of crashing on mount.\nlet validationStore: ReturnType<typeof useValidationStore> | null = null\ntry {\n\tvalidationStore = useValidationStore()\n} catch {\n\tvalidationStore = null\n}\n\n// Inline field errors handed to AForm. Only surfaced in the record form view (currentView is\n// defined below); empty elsewhere so a previous record's errors never bleed into a list view.\nconst fieldErrors = computed<Record<string, string[]>>(() =>\n\tcurrentView.value === 'record' ? (validationStore?.errorsByField ?? {}) : {}\n)\n\n// State\nconst loading = ref(false)\nconst commandPaletteOpen = ref(false)\n\n// The record being composed on a `/{doctype}/new` route. Deliberately not in HST: a draft has no\n// identity to be keyed by, and both ways of faking one fail — see `DRAFT_RECORD_ID`.\nconst draftRecord = ref<Record<string, any>>({})\n\n// Form/list data management — each view produces a different data shape.\n// List views (doctypes, records) return table row data keyed by fieldname.\n// Record view returns the record's fields for two-way binding — from HST, or from `draftRecord`\n// when the route is a draft.\nconst currentViewData = computed<Record<string, any>>({\n\tget() {\n\t\t// Doctypes list — rows come from availableDoctypes prop (reactive via availableDoctypes)\n\t\tif (currentView.value === 'doctypes') {\n\t\t\treturn {\n\t\t\t\tdoctypes_table:\n\t\t\t\t\tavailableDoctypes?.map(doctype => ({\n\t\t\t\t\t\tid: doctype,\n\t\t\t\t\t\tdoctype,\n\t\t\t\t\t\tdisplay_name: formatDoctypeName(doctype),\n\t\t\t\t\t\tactions: 'View Records',\n\t\t\t\t\t})) ?? [],\n\t\t\t}\n\t\t}\n\n\t\t// Records list — rows come from HST store (reactive because HST is Vue reactive())\n\t\tif (currentView.value === 'records') {\n\t\t\treturn {\n\t\t\t\trecords_table: getRecords().map(record =>\n\t\t\t\t\tObject.assign({}, record, {\n\t\t\t\t\t\tid: resolveRecordId(record) ?? '',\n\t\t\t\t\t\t// A list row is navigation. Actions live on the record view, where the Actions\n\t\t\t\t\t\t// dropdown is built from what the doctype declares and what the record's\n\t\t\t\t\t\t// current state allows. This cell used to also offer Delete, which dispatched\n\t\t\t\t\t\t// an action named `DELETE` that Desktop invented — no doctype in a\n\t\t\t\t\t\t// WorkflowMeta app declares it, so it failed on every click. Removal is a\n\t\t\t\t\t\t// workflow outcome (`archive`, `cancel`) and belongs in the doctype.\n\t\t\t\t\t\tactions: 'Edit',\n\t\t\t\t\t})\n\t\t\t\t),\n\t\t\t}\n\t\t}\n\n\t\t// Record form — read single record from HST\n\t\tif (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) {\n\t\t\treturn {}\n\t\t}\n\n\t\ttry {\n\t\t\tconst source = isNewRecord.value\n\t\t\t\t? draftRecord.value\n\t\t\t\t: (stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)?.get('') as\n\t\t\t\t\t\tRecord<string, any> | undefined)\n\t\t\t// Return a plain shallow copy so AForm mutations don't propagate directly into\n\t\t\t// the HST reactive object, which would bypass field-trigger diffing and cause\n\t\t\t// setupDeepReactivity to fire triggers for all fields on every keystroke.\n\t\t\tconst flat: Record<string, any> = { ...source }\n\n\t\t\t// AFieldset receives data[fieldsetFieldname] as its data prop, so the fieldset's\n\t\t\t// children must be grouped under the fieldset key. The server returns flat SQL rows,\n\t\t\t// so we nest fieldset children here before AForm renders them.\n\t\t\tconst doctype = stonecrop.value.registry.registry[currentDoctype.value]\n\t\t\tif (doctype) {\n\t\t\t\tfor (const field of doctype.getSchemaArray()) {\n\t\t\t\t\tif (field.kind === 'fieldset') {\n\t\t\t\t\t\tconst nested: Record<string, any> = {}\n\t\t\t\t\t\tfor (const child of field.schema) {\n\t\t\t\t\t\t\tif (child.fieldname) nested[child.fieldname] = flat[child.fieldname]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tflat[field.fieldname] = nested\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn flat\n\t\t} catch {\n\t\t\treturn {}\n\t\t}\n\t},\n\tset(newData: Record<string, any>) {\n\t\t// List views are read-only from AForm's perspective — HST writes only apply to record form\n\t\tif (currentView.value !== 'record') return\n\t\tif (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) {\n\t\t\treturn\n\t\t}\n\n\t\ttry {\n\t\t\t// AForm emits nested data for fieldsets: { fieldsetKey: { childA: val } }.\n\t\t\t// HST and the server both expect flat rows, so flatten fieldset values back before writing.\n\t\t\tconst doctype = stonecrop.value.registry.registry[currentDoctype.value]\n\t\t\tconst fieldsetNames = new Set<string>()\n\t\t\tif (doctype) {\n\t\t\t\tfor (const field of doctype.getSchemaArray()) {\n\t\t\t\t\tif (field.kind === 'fieldset') {\n\t\t\t\t\t\tfieldsetNames.add(field.fieldname)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst inlineLinks = inlineLinkFieldnames(doctype ? doctype.getSchemaArray() : [])\n\n\t\t\t// Two-pass flatten: non-fieldset keys first, then fieldset children.\n\t\t\t// Fieldset children must be applied last — AForm may emit stale flat copies\n\t\t\t// of fieldset children alongside the updated nested value, and the nested\n\t\t\t// value must win regardless of key insertion order.\n\t\t\tconst flatData: Record<string, any> = {}\n\t\t\tconst fieldsetValues: Record<string, any>[] = []\n\t\t\tfor (const [key, value] of Object.entries(newData)) {\n\t\t\t\tif (fieldsetNames.has(key) && value && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t\t\tfieldsetValues.push(value)\n\t\t\t\t} else {\n\t\t\t\t\tflatData[key] = value\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const nestedValue of fieldsetValues) {\n\t\t\t\tObject.assign(flatData, nestedValue)\n\t\t\t}\n\n\t\t\t// Only update fields that actually changed. Never write undefined — AForm may emit\n\t\t\t// schema fields absent from the record as undefined; writing them would silently\n\t\t\t// clear values that exist. Explicit null is allowed (intentional clear).\n\t\t\tconst changedFields: string[] = []\n\t\t\tif (isNewRecord.value) {\n\t\t\t\t// Reassigned, not mutated, so the getter re-runs. Relying on in-place mutation of the\n\t\t\t\t// cached object is what made a draft's edits vanish on any invalidation.\n\t\t\t\tconst next = { ...draftRecord.value }\n\t\t\t\tfor (const [fieldname, value] of Object.entries(flatData)) {\n\t\t\t\t\tif (value === undefined) continue\n\t\t\t\t\tconst normalized = inlineLinks.has(fieldname) ? unwrapLinkValue(value) : value\n\t\t\t\t\tif (next[fieldname] !== normalized) {\n\t\t\t\t\t\tnext[fieldname] = normalized\n\t\t\t\t\t\tchangedFields.push(fieldname)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdraftRecord.value = next\n\t\t\t} else {\n\t\t\t\tconst hstStore = stonecrop.value.getStore()\n\t\t\t\tfor (const [fieldname, value] of Object.entries(flatData)) {\n\t\t\t\t\tif (value === undefined) continue\n\t\t\t\t\tconst normalized = inlineLinks.has(fieldname) ? unwrapLinkValue(value) : value\n\t\t\t\t\tconst fieldPath = `${currentDoctype.value}.${currentRecordId.value}.${fieldname}`\n\t\t\t\t\tconst currentValue = hstStore.has(fieldPath) ? hstStore.get(fieldPath) : undefined\n\t\t\t\t\tif (currentValue !== normalized) {\n\t\t\t\t\t\thstStore.set(fieldPath, normalized)\n\t\t\t\t\t\tchangedFields.push(fieldname)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Advisory field-validation runs on the fields that actually changed (honors each\n\t\t\t// trigger's `on` set). Driven here, after the HST writes, so HST stays value-only.\n\t\t\tif (changedFields.length > 0) {\n\t\t\t\tdriveFieldValidation(changedFields)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('HST update failed:', error)\n\t\t}\n\t},\n})\n\n// Advisory field-validation: run the doctype's triggers for the fields that changed on this edit.\n// Snapshots the post-edit record as a plain, flat object so validators read siblings read-only\n// (the core store freezes it). Fire-and-forget — the reactive error store repaints AForm on resolve.\nfunction driveFieldValidation(changedFields: string[]) {\n\tif (!validationStore || !stonecrop.value || !currentDoctype.value || !currentRecordId.value) return\n\n\tconst doctype = stonecrop.value.registry.getDoctype(currentDoctype.value)\n\tconst triggers = doctype?.getTriggers()\n\tif (!triggers || Object.keys(triggers).length === 0) return\n\n\t// A draft's siblings come from the buffer; reading HST would hand every validator an empty record.\n\tconst record = isNewRecord.value\n\t\t? { ...draftRecord.value }\n\t\t: {\n\t\t\t\t...(stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)?.get('') as Record<\n\t\t\t\t\tstring,\n\t\t\t\t\tunknown\n\t\t\t\t>),\n\t\t\t}\n\n\tfor (const field of changedFields) {\n\t\tvoid validationStore.validateField(triggers, field, record)\n\t}\n}\n\n// Computed properties for current route context.\n// When a routeAdapter is provided it takes full precedence over the registry's internal router.\nconst route = computed(() => (routeAdapter ? null : unref(stonecrop.value?.registry.router?.currentRoute)))\nconst router = computed(() => (routeAdapter ? null : stonecrop.value?.registry.router))\nconst currentDoctype = computed(() => {\n\tif (routeAdapter) return routeAdapter.getCurrentDoctype()\n\tif (!route.value) return ''\n\n\t// First check if we have actualDoctype in meta (from registered routes)\n\tif (route.value.meta?.actualDoctype) {\n\t\treturn route.value.meta.actualDoctype as string\n\t}\n\n\t// For named routes, use params.doctype\n\tif (route.value.params.doctype) {\n\t\treturn route.value.params.doctype.toString()\n\t}\n\n\t// For catch-all routes that haven't been registered yet, extract from path\n\tconst pathMatch = route.value.params.pathMatch as string[] | undefined\n\tif (pathMatch && pathMatch.length > 0) {\n\t\treturn pathMatch[0]\n\t}\n\n\treturn ''\n})\n\n// The route doctype for display and navigation (e.g., 'todo')\nconst routeDoctype = computed(() => {\n\tif (routeAdapter) return routeAdapter.getCurrentDoctype()\n\tif (!route.value) return ''\n\n\t// Check route meta first\n\tif (route.value.meta?.doctype) {\n\t\treturn route.value.meta.doctype as string\n\t}\n\n\t// For named routes, use params.doctype\n\tif (route.value.params.doctype) {\n\t\treturn route.value.params.doctype.toString()\n\t}\n\n\t// For catch-all routes, extract from path\n\tconst pathMatch = route.value.params.pathMatch as string[] | undefined\n\tif (pathMatch && pathMatch.length > 0) {\n\t\treturn pathMatch[0]\n\t}\n\n\treturn ''\n})\n\nconst currentRecordId = computed(() => {\n\tif (routeAdapter) return routeAdapter.getCurrentRecordId()\n\tif (!route.value) return ''\n\n\t// For named routes, use params.recordId\n\tif (route.value.params.recordId) {\n\t\treturn route.value.params.recordId.toString()\n\t}\n\n\t// For catch-all routes that haven't been registered yet, extract from path\n\tconst pathMatch = route.value.params.pathMatch as string[] | undefined\n\tif (pathMatch && pathMatch.length > 1) {\n\t\treturn pathMatch[1]\n\t}\n\n\treturn ''\n})\nconst isNewRecord = computed(() => isDraftRecordId(currentRecordId.value))\n\n// Determine current view based on route\nconst currentView = computed(() => {\n\tif (routeAdapter) return routeAdapter.getCurrentView()\n\tif (!route.value) {\n\t\treturn 'doctypes'\n\t}\n\n\t// Home route\n\tif (route.value.name === 'home' || route.value.path === '/') {\n\t\treturn 'doctypes'\n\t}\n\n\t// Named routes from registered doctypes\n\tif (route.value.name && route.value.name !== 'catch-all') {\n\t\tconst routeName = route.value.name as string\n\t\tif (routeName.includes('form') || route.value.params.recordId) {\n\t\t\treturn 'record'\n\t\t} else if (routeName.includes('list') || route.value.params.doctype) {\n\t\t\treturn 'records'\n\t\t}\n\t}\n\n\t// Catch-all route - determine from path structure\n\tconst pathMatch = route.value.params.pathMatch as string[] | undefined\n\tif (pathMatch && pathMatch.length > 0) {\n\t\tconst view = pathMatch.length === 1 ? 'records' : 'record'\n\t\treturn view\n\t}\n\n\treturn 'doctypes'\n})\n\n// Computed properties (now that all helper functions are defined)\n// Helper function to get available transitions for current record.\n// Reads the actual FSM state from the record's `status` field (or falls back to the\n// workflow initial state) so the available action buttons always reflect reality.\nconst getAvailableTransitions = () => {\n\tif (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) {\n\t\treturn []\n\t}\n\n\ttry {\n\t\tconst doctype = stonecrop.value.registry.getDoctype(currentDoctype.value)\n\t\tif (!doctype?.workflow) return []\n\n\t\t// Delegate state resolution to Stonecrop — reads record 'status', falls back to workflow.initial\n\t\tconst currentState = stonecrop.value.getRecordState(currentDoctype.value, currentRecordId.value)\n\n\t\t// Delegate transition lookup to Doctype — no more manual workflow introspection\n\t\tconst transitions = doctype.getAvailableTransitions(currentState)\n\n\t\tconst recordData = currentViewData.value || {}\n\n\t\t// Each transition emits an 'action' event. The host app decides what to do\n\t\t// (call the server, trigger an FSM actor, update HST, etc.).\n\t\treturn transitions.map(({ name }) => ({\n\t\t\t// Prefer the workflow action's human-readable label (WorkflowMeta format);\n\t\t\t// fall back to the raw transition name for XState workflows with no action meta.\n\t\t\tlabel: doctype.getActionMeta(name)?.label ?? name,\n\t\t\taction: () => {\n\t\t\t\temit('action', {\n\t\t\t\t\tname,\n\t\t\t\t\tdoctype: currentDoctype.value,\n\t\t\t\t\trecordId: currentRecordId.value,\n\t\t\t\t\tdata: recordData,\n\t\t\t\t})\n\t\t\t},\n\t\t}))\n\t} catch (error) {\n\t\tconsole.warn('Error getting available transitions:', error)\n\t\treturn []\n\t}\n}\n\n// Helper: stateless Commands available for the current record — side-effect actions that\n// change no workflow state. Surfaced in the same Actions dropdown as transitions; each emits\n// the same 'action' event, so the host's handler runs a Command's clientHandler identically.\nconst getAvailableCommands = () => {\n\tif (!stonecrop.value || !currentDoctype.value || !currentRecordId.value) {\n\t\treturn []\n\t}\n\n\ttry {\n\t\tconst doctype = stonecrop.value.registry.getDoctype(currentDoctype.value)\n\t\tif (!doctype?.workflow) return []\n\n\t\tconst currentState = stonecrop.value.getRecordState(currentDoctype.value, currentRecordId.value)\n\t\tconst commands = doctype.getAvailableCommands(currentState)\n\t\tconst recordData = currentViewData.value || {}\n\n\t\treturn commands.map(({ name }) => ({\n\t\t\tlabel: doctype.getActionMeta(name)?.label ?? name,\n\t\t\taction: () => {\n\t\t\t\temit('action', {\n\t\t\t\t\tname,\n\t\t\t\t\tdoctype: currentDoctype.value,\n\t\t\t\t\trecordId: currentRecordId.value,\n\t\t\t\t\tdata: recordData,\n\t\t\t\t})\n\t\t\t},\n\t\t}))\n\t} catch (error) {\n\t\tconsole.warn('Error getting available commands:', error)\n\t\treturn []\n\t}\n}\n\nconst actionElements = computed(() => {\n\tconst elements: ActionElements[] = []\n\n\tswitch (currentView.value) {\n\t\tcase 'records':\n\t\t\telements.push({\n\t\t\t\ttype: 'button',\n\t\t\t\tlabel: 'New Record',\n\t\t\t\taction: () => void createNewRecord(),\n\t\t\t})\n\t\t\tbreak\n\t\tcase 'record': {\n\t\t\t// Populate the Actions dropdown with every FSM transition AND stateless Command\n\t\t\t// available in the record's current state. Clicking either emits 'action'.\n\t\t\tconst recordActions = [...getAvailableTransitions(), ...getAvailableCommands()]\n\t\t\tif (recordActions.length > 0) {\n\t\t\t\telements.push({\n\t\t\t\t\ttype: 'dropdown',\n\t\t\t\t\tlabel: 'Actions',\n\t\t\t\t\tactions: recordActions,\n\t\t\t\t})\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn elements\n})\n\nconst navigationBreadcrumbs = computed(() => {\n\tconst breadcrumbs: { title: string; to: string }[] = []\n\n\tif (currentView.value === 'records' && routeDoctype.value) {\n\t\tbreadcrumbs.push(\n\t\t\t{ title: 'Home', to: '/' },\n\t\t\t{ title: formatDoctypeName(routeDoctype.value), to: `/${routeDoctype.value}` }\n\t\t)\n\t} else if (currentView.value === 'record' && routeDoctype.value) {\n\t\tconst recordPath = currentRecordId.value\n\t\t\t? `/${routeDoctype.value}/${currentRecordId.value}`\n\t\t\t: (route.value?.fullPath ?? '')\n\t\tbreadcrumbs.push(\n\t\t\t{ title: 'Home', to: '/' },\n\t\t\t{ title: formatDoctypeName(routeDoctype.value), to: `/${routeDoctype.value}` },\n\t\t\t{ title: isNewRecord.value ? 'New Record' : 'Edit Record', to: recordPath }\n\t\t)\n\t}\n\n\treturn breadcrumbs\n})\n\n// Command palette functionality\ntype Command = {\n\ttitle: string\n\tdescription: string\n\taction: () => void\n}\n\nconst searchCommands = (query: string): Command[] => {\n\tconst commands: Command[] = [\n\t\t{\n\t\t\ttitle: 'Go Home',\n\t\t\tdescription: 'Navigate to the home page',\n\t\t\taction: () => void doNavigate({ view: 'doctypes' }),\n\t\t},\n\t\t{\n\t\t\ttitle: 'Toggle Command Palette',\n\t\t\tdescription: 'Open/close the command palette',\n\t\t\taction: () => (commandPaletteOpen.value = !commandPaletteOpen.value),\n\t\t},\n\t]\n\n\t// Add doctype-specific commands\n\tif (routeDoctype.value) {\n\t\tcommands.push({\n\t\t\ttitle: `View ${formatDoctypeName(routeDoctype.value)} Records`,\n\t\t\tdescription: `Navigate to ${routeDoctype.value} list`,\n\t\t\taction: () => void doNavigate({ view: 'records', doctype: routeDoctype.value }),\n\t\t})\n\n\t\tcommands.push({\n\t\t\ttitle: `Create New ${formatDoctypeName(routeDoctype.value)}`,\n\t\t\tdescription: `Create a new ${routeDoctype.value} record`,\n\t\t\taction: () => void createNewRecord(),\n\t\t})\n\t}\n\n\t// Add available doctypes as commands\n\tavailableDoctypes.forEach(doctype => {\n\t\tcommands.push({\n\t\t\ttitle: `View ${formatDoctypeName(doctype)}`,\n\t\t\tdescription: `Navigate to ${doctype} list`,\n\t\t\taction: () => void doNavigate({ view: 'records', doctype }),\n\t\t})\n\t})\n\n\t// Filter commands based on query\n\tif (!query) return commands\n\n\treturn commands.filter(\n\t\tcmd =>\n\t\t\tcmd.title.toLowerCase().includes(query.toLowerCase()) ||\n\t\t\tcmd.description.toLowerCase().includes(query.toLowerCase())\n\t)\n}\n\nconst executeCommand = (command: Command) => {\n\tcommand.action()\n\tcommandPaletteOpen.value = false\n}\n\n// List reads are wired on the records table; ATable owns the fetch via getRecords.\nconst listRecordsFetcher = (options?: import('@stonecrop/schema').GetRecordsOptions) => {\n\tif (!stonecrop.value || !currentDoctype.value) {\n\t\treturn Promise.resolve({ data: [], hasMore: false })\n\t}\n\tconst doctype = stonecrop.value.registry.getDoctype(currentDoctype.value)\n\tif (!doctype) {\n\t\treturn Promise.resolve({ data: [], hasMore: false })\n\t}\n\treturn stonecrop.value.getRecords(doctype, options)\n}\n\n// Helper functions - moved here to avoid \"before initialization\" errors\nconst formatDoctypeName = (doctype: string): string => {\n\treturn doctype\n\t\t.split('-')\n\t\t.map(word => word.charAt(0).toUpperCase() + word.slice(1))\n\t\t.join(' ')\n}\n\n// Internal navigation helper: emits 'navigate', then calls the adapter (if any)\n// or falls back to the registry's Vue Router instance.\nconst doNavigate = async (target: NavigationTarget) => {\n\temit('navigate', target)\n\tif (routeAdapter) {\n\t\tawait routeAdapter.navigate(target)\n\t} else {\n\t\tif (target.view === 'doctypes') {\n\t\t\tawait router.value?.push('/')\n\t\t} else if (target.view === 'records' && target.doctype) {\n\t\t\tawait router.value?.push(`/${target.doctype}`)\n\t\t} else if (target.view === 'record' && target.doctype && target.recordId) {\n\t\t\tawait router.value?.push(`/${target.doctype}/${target.recordId}`)\n\t\t}\n\t}\n}\n\nconst navigateToDoctype = async (doctype: string) => {\n\tawait doNavigate({ view: 'records', doctype })\n}\n\nconst openRecord = async (recordId: string) => {\n\tconst doctype = routeDoctype.value\n\temit('record:open', { doctype, recordId })\n\tawait doNavigate({ view: 'record', doctype, recordId })\n}\n\nconst createNewRecord = async () => {\n\tawait doNavigate({ view: 'record', doctype: routeDoctype.value, recordId: DRAFT_RECORD_ID })\n}\n\n// Schema generator functions - moved here to be available to computed properties\nconst getDoctypesSchema = (): ResolvedField[] => {\n\tif (!availableDoctypes?.length) return []\n\n\treturn [\n\t\t{\n\t\t\tkind: 'table' as const,\n\t\t\tfieldname: 'doctypes_table',\n\t\t\tcomponent: 'ATable',\n\t\t\tlabel: 'Doctypes',\n\t\t\tschema: [\n\t\t\t\t{\n\t\t\t\t\tfieldname: 'doctype',\n\t\t\t\t\tlabel: 'Doctype',\n\t\t\t\t\tcomponent: 'ATextInput',\n\t\t\t\t\talign: 'left' as const,\n\t\t\t\t\tedit: false,\n\t\t\t\t\twidth: '20ch',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfieldname: 'display_name',\n\t\t\t\t\tlabel: 'Name',\n\t\t\t\t\tcomponent: 'ATextInput',\n\t\t\t\t\talign: 'left' as const,\n\t\t\t\t\tedit: false,\n\t\t\t\t\twidth: '30ch',\n\t\t\t\t},\n\t\t\t\t// No record count column. It read `getRecordIds(doctype).length`, which is how many\n\t\t\t\t// records HST happens to hold — zero for a doctype never opened, and the page size\n\t\t\t\t// for one that was. The real total belongs to the backend and Desktop never asks\n\t\t\t\t// for it, so this shell cannot answer it. Same reason the `recordIdField` prop went.\n\t\t\t\t{\n\t\t\t\t\tfieldname: 'actions',\n\t\t\t\t\tlabel: 'Actions',\n\t\t\t\t\tcomponent: 'ATextInput',\n\t\t\t\t\talign: 'center' as const,\n\t\t\t\t\tedit: false,\n\t\t\t\t\twidth: '20ch',\n\t\t\t\t},\n\t\t\t],\n\t\t\tconfig: { view: 'list' as const, fullWidth: true },\n\t\t} satisfies ResolvedTable,\n\t]\n}\n\nconst getRecordsSchema = (): ResolvedField[] => {\n\tif (!currentDoctype.value) return []\n\tif (!stonecrop.value) return []\n\n\tconst registry = stonecrop.value.registry\n\tconst doctype = registry.registry[currentDoctype.value]\n\n\tif (!doctype) return []\n\n\tconst schema = registry.resolveSchema(doctype)\n\n\t// If no schema is available, let the template fallback handle the loading state\n\tif (schema.length === 0) return []\n\n\tconst doctypeSlug = currentDoctype.value\n\tconst clientConfigured = Boolean(stonecrop.value.getClient())\n\n\treturn [\n\t\t{\n\t\t\tkind: 'table' as const,\n\t\t\tfieldname: 'records_table',\n\t\t\tcomponent: 'ATable',\n\t\t\t// Which resolved fields a cell can render is answered once, in @stonecrop/aform, and\n\t\t\t// called by the child-table builder too. Flattening alone is not the rule: it kept the\n\t\t\t// expanding links, whose value is a nested record or an array of them.\n\t\t\tschema: [...resolvedFieldsToColumns(schema), { fieldname: 'actions', label: 'Actions', component: 'ATextInput' }],\n\t\t\tconfig: { view: 'list' as const, fullWidth: true },\n\t\t\t...(clientConfigured ? { getRecords: listRecordsFetcher, sourceKey: doctypeSlug } : {}),\n\t\t} satisfies ResolvedTable,\n\t]\n}\n\nconst getRecordFormSchema = (): ResolvedField[] => {\n\tif (!currentDoctype.value) return []\n\tif (!stonecrop.value) return []\n\n\ttry {\n\t\tconst registry = stonecrop.value?.registry\n\t\tconst doctype = registry?.registry[currentDoctype.value]\n\n\t\tif (!doctype?.schema) {\n\t\t\t// Let the template fallback handle the loading state\n\t\t\treturn []\n\t\t}\n\n\t\treturn registry.resolveSchema(doctype)\n\t} catch {\n\t\treturn []\n\t}\n}\n\n// Additional data helper functions\nconst getRecords = () => {\n\tif (!stonecrop.value || !currentDoctype.value) {\n\t\treturn []\n\t}\n\n\tconst recordsNode = stonecrop.value.records(currentDoctype.value)\n\tconst recordsData = recordsNode?.get('')\n\n\tif (recordsData && typeof recordsData === 'object' && !Array.isArray(recordsData)) {\n\t\treturn Object.values(recordsData as Record<string, any>)\n\t}\n\n\treturn []\n}\n\n// Schema for different views - defined here after all helper functions are available\nconst currentViewSchema = computed(() => {\n\tswitch (currentView.value) {\n\t\tcase 'doctypes':\n\t\t\treturn getDoctypesSchema()\n\t\tcase 'records':\n\t\t\treturn getRecordsSchema()\n\t\tcase 'record':\n\t\t\treturn getRecordFormSchema()\n\t\tdefault:\n\t\t\treturn []\n\t}\n})\n\nconst handleActionClick = (_label: string, action: (() => void | Promise<void>) | undefined) => {\n\tif (action) {\n\t\tvoid action()\n\t}\n}\n\n/**\n * Resolve a record's identity for links and navigation.\n *\n * Identity is declared once, on the doctype: `primaryKey`, or `id` when nothing is declared.\n * Delegating to `Doctype.getRecordId` is what guarantees this matches the key\n * `Stonecrop.getRecords` stored the record under — resolving it independently here would let a\n * row render a link to an HST path that does not exist.\n *\n * There is deliberately no per-shell override. Identity is a per-doctype fact and one shell\n * renders many doctypes, so a single prop cannot answer it; a shell that named a field would\n * also be overriding the very declaration the store keyed on, which is the bug above.\n */\nconst resolveRecordId = (record: Record<string, unknown>): string | undefined => {\n\tif (!stonecrop.value || !currentDoctype.value) return undefined\n\treturn stonecrop.value.registry.registry[currentDoctype.value]?.getRecordId(record)\n}\n\n// Event handlers\nconst getRecordIdFromRow = (rowElement: HTMLTableRowElement): string | null => {\n\tconst cell = rowElement.querySelector('td[data-rowindex]')\n\tif (!cell) return null\n\n\tconst rowIndexAttr = cell.getAttribute('data-rowindex')\n\tif (rowIndexAttr === null) return null\n\n\tconst rowIndex = parseInt(rowIndexAttr, 10)\n\tif (isNaN(rowIndex)) return null\n\n\tconst records = getRecords()\n\tconst record = records[rowIndex]\n\tif (!record) return null\n\n\treturn resolveRecordId(record) ?? null\n}\n\nconst handleClick = async (event: Event) => {\n\tconst target = event.target as HTMLElement\n\tconst action = target.getAttribute('data-action')\n\n\tif (action === 'create') {\n\t\tawait createNewRecord()\n\t}\n\n\tconst cell = target.closest('td, th')\n\tif (cell) {\n\t\tconst cellText = cell.textContent?.trim()\n\t\tconst row = cell.closest('tr')\n\n\t\tif (cellText === 'View Records' && row) {\n\t\t\t// Get the doctype from the row data\n\t\t\tconst cells = row.querySelectorAll('td')\n\t\t\tif (cells.length > 0) {\n\t\t\t\tconst doctypeCell = cells[1] // Assuming doctype is in second column (first column is index)\n\t\t\t\tconst doctype = doctypeCell.textContent?.trim()\n\t\t\t\tif (doctype) {\n\t\t\t\t\tawait navigateToDoctype(doctype)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (cellText === 'Edit' && row) {\n\t\t\t// Matched exactly, not by substring. This handler is bound to the whole desktop, so a\n\t\t\t// substring match fired on any cell whose *data* happened to contain the word — a task\n\t\t\t// titled \"Delete old backups\" popped a delete confirmation when you clicked it.\n\t\t\tconst recordId = getRecordIdFromRow(row)\n\t\t\tif (recordId) {\n\t\t\t\tawait openRecord(recordId)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Reads go through Stonecrop, which owns whether to fetch, how to key the result, and where to\n// put it. Desktop asks for data and renders what arrives; it decides none of that itself.\n//\n// Both loaders are no-ops without a client, so a host that populates HST some other way keeps\n// working unchanged rather than taking a thrown error on every navigation.\nconst loadRecordData = async () => {\n\tif (!stonecrop.value || !currentDoctype.value || !stonecrop.value.getClient()) return\n\n\tloading.value = true\n\ttry {\n\t\tawait stonecrop.value.getRecord(currentDoctype.value, currentRecordId.value)\n\t} catch (error) {\n\t\tconsole.warn('Error fetching record:', error)\n\t} finally {\n\t\tloading.value = false\n\t}\n}\n\n// Watch for route changes to load appropriate data\nwatch(\n\t[currentView, currentDoctype, currentRecordId],\n\t() => {\n\t\t// The events are notifications, not fetch requests: they announce what Desktop is about to\n\t\t// read so a host can hang analytics or a prefetch off them. The read itself is Stonecrop's.\n\t\tif (currentView.value === 'records' && currentDoctype.value) {\n\t\t\temit('load-records', { doctype: currentDoctype.value })\n\t\t} else if (currentView.value === 'record' && currentDoctype.value && currentRecordId.value) {\n\t\t\t// A draft has nothing to fetch — the record does not exist on the server yet. Desktop\n\t\t\t// used to emit anyway and leave the host to work it out, which meant every host had to\n\t\t\t// recognise the private draft-id scheme above just to suppress a doomed request; all of\n\t\t\t// them did, identically. `getRecord` declines the same case for the same reason.\n\t\t\tif (isNewRecord.value) return\n\n\t\t\temit('load-record', { doctype: currentDoctype.value, recordId: currentRecordId.value })\n\t\t\tvoid loadRecordData()\n\t\t}\n\t},\n\t{ immediate: true }\n)\n\n// Clear advisory validation errors when the target record changes, so errors from a previously\n// edited record never bleed into a newly opened one.\nwatch([currentDoctype, currentRecordId], () => {\n\tvalidationStore?.clearAll()\n})\n\n// Seeding on entry gives a new record the doctype's declared defaults, which it never used to get.\n// Discarding on exit matters as much: the draft segment is one shared literal, so a stale buffer\n// would open the next New Record pre-filled with the abandoned one's values.\nwatch(\n\t[currentDoctype, currentRecordId],\n\t() => {\n\t\tif (!isNewRecord.value) {\n\t\t\tdraftRecord.value = {}\n\t\t\treturn\n\t\t}\n\t\tconst registry = stonecrop.value?.registry\n\t\tdraftRecord.value = registry ? registry.initializeRecord(getRecordFormSchema()) : {}\n\t},\n\t{ immediate: true }\n)\n\n// Stonecrop reactive computed properties update automatically when the instance\n// becomes available — no manual watcher needed.\n\n// Provide navigation helpers and an emitAction convenience function to child components.\nconst desktopMethods = {\n\tnavigateToDoctype,\n\topenRecord,\n\tcreateNewRecord,\n\t/**\n\t * Convenience wrapper so child components (e.g. slot content) can emit\n\t * an action event without needing a direct reference to the emit function.\n\t */\n\temitAction: (name: string, data?: Record<string, any>) => {\n\t\temit('action', {\n\t\t\tname,\n\t\t\tdoctype: currentDoctype.value,\n\t\t\trecordId: currentRecordId.value,\n\t\t\tdata: data ?? currentViewData.value ?? {},\n\t\t})\n\t},\n}\n\nprovide('desktopMethods', desktopMethods)\n\n// Provide a navigator for AFormLink so the arrow button navigates to the linked record.\nprovide('aformLinkNavigator', {\n\tnavigate: (doctype: string, id: string | number) => {\n\t\tvoid doNavigate({ view: 'record', doctype, recordId: String(id) })\n\t},\n} satisfies AFormLinkNavigator)\n\n// Provide a resolver for AFormLink to look up display text by doctype + id.\n// Checks HST first (sync); falls back to an async client fetch if not cached.\n// Uses the target doctype's declared displayField — no heuristic field guessing.\nprovide('aformLinkResolver', async (doctypeSlug: string, id: string): Promise<string | undefined> => {\n\tif (!stonecrop.value) return undefined\n\ttry {\n\t\tconst meta = await stonecrop.value.getMeta({ path: `/${doctypeSlug}`, segments: [doctypeSlug] })\n\t\tconst displayField = meta?.displayField\n\t\tif (!displayField) return undefined\n\n\t\tconst readDisplay = (rec: Record<string, unknown> | undefined): string | undefined => {\n\t\t\tif (!rec) return undefined\n\t\t\tconst val = rec[displayField]\n\t\t\treturn typeof val === 'string' || typeof val === 'number' ? String(val) : undefined\n\t\t}\n\n\t\tconst cached = stonecrop.value.getRecordById(doctypeSlug, id)?.get('') as Record<string, unknown> | undefined\n\t\tconst cachedDisplay = readDisplay(cached)\n\t\tif (cachedDisplay != null) return cachedDisplay\n\n\t\tawait stonecrop.value.getRecord(doctypeSlug, id)\n\t\tconst fetched = stonecrop.value.getRecordById(doctypeSlug, id)?.get('') as Record<string, unknown> | undefined\n\t\treturn readDisplay(fetched)\n\t} catch {\n\t\treturn undefined\n\t}\n})\n\nconst handleKeydown = (event: KeyboardEvent) => {\n\tif ((event.ctrlKey || event.metaKey) && event.key === 'k') {\n\t\tevent.preventDefault()\n\t\tcommandPaletteOpen.value = true\n\t}\n\tif (event.key === 'Escape' && commandPaletteOpen.value) {\n\t\tcommandPaletteOpen.value = false\n\t}\n}\n\nonMounted(() => {\n\tdocument.addEventListener('keydown', handleKeydown)\n})\n\nonUnmounted(() => {\n\tdocument.removeEventListener('keydown', handleKeydown)\n})\n</script>\n","import { App, type Plugin } from 'vue'\n\nimport ActionSet from '../components/ActionSet.vue'\nimport CommandPalette from '../components/CommandPalette.vue'\nimport Desktop from '../components/Desktop.vue'\nimport SheetNav from '../components/SheetNav.vue'\n\n/**\n * This is the main plugin that will be used to register all the desktop components.\n * @public\n */\nconst plugin: Plugin = {\n\tinstall: (app: App) => {\n\t\tapp.component('ActionSet', ActionSet)\n\t\tapp.component('CommandPalette', CommandPalette)\n\t\tapp.component('Desktop', Desktop)\n\t\tapp.component('SheetNav', SheetNav)\n\t},\n}\n\nexport default plugin\n"],"names":["emit","__emit","dropdownStates","ref","isOpen","dropdownOpen","onMounted","closeDropdowns","onClick","toggleDropdown","index","showDropdown","handleClick","action","label","_createElementBlock","_normalizeClass","_createElementVNode","_hoisted_1","_openBlock","_Fragment","_renderList","__props","el","_hoisted_2","$event","_toDisplayString","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_withDirectives","_hoisted_8","_hoisted_9","item","_hoisted_10","_hoisted_12","_vShow","query","selectedIndex","inputRef","useTemplateRef","results","computed","watch","open","nextTick","closeModal","handleKeydown","e","selectResult","result","_createBlock","_Teleport","_createVNode","_Transition","_renderSlot","_ctx","breadcrumbsVisibile","searchVisible","searchText","rotateHideTabIcon","toggleBreadcrumbs","toggleSearch","handleSearchInput","event","handleSearch","navigateHome","_component_router_link","_cache","_withKeys","breadcrumb","_createTextVNode","inlineLinkFieldnames","fields","links","flattenFields","field","componentLinkExpansion","unwrapLinkValue","value","stonecrop","useStonecrop","validationStore","useValidationStore","fieldErrors","currentView","loading","commandPaletteOpen","draftRecord","currentViewData","doctype","formatDoctypeName","getRecords","record","resolveRecordId","currentDoctype","currentRecordId","flat","isNewRecord","nested","child","newData","fieldsetNames","inlineLinks","flatData","fieldsetValues","key","nestedValue","changedFields","next","fieldname","normalized","hstStore","fieldPath","driveFieldValidation","error","triggers","route","unref","router","pathMatch","routeDoctype","isDraftRecordId","routeName","getAvailableTransitions","currentState","transitions","recordData","name","getAvailableCommands","commands","actionElements","elements","createNewRecord","recordActions","navigationBreadcrumbs","breadcrumbs","recordPath","searchCommands","doNavigate","cmd","executeCommand","command","listRecordsFetcher","options","word","target","navigateToDoctype","openRecord","recordId","DRAFT_RECORD_ID","getDoctypesSchema","getRecordsSchema","registry","schema","doctypeSlug","clientConfigured","resolvedFieldsToColumns","getRecordFormSchema","recordsData","currentViewSchema","handleActionClick","_label","getRecordIdFromRow","rowElement","cell","rowIndexAttr","rowIndex","cellText","row","cells","loadRecordData","provide","data","id","displayField","readDisplay","rec","val","cached","cachedDisplay","fetched","onUnmounted","ActionSet","_unref","AForm","SheetNav","CommandPalette","_withCtx","plugin","app","Desktop"],"mappings":";;;;;;;;;;;AA8CA,UAAMA,IAAOC,GAKPC,IAAiBC,EAA6B,EAAE,GAEhDC,IAASD,EAAI,EAAI,GACjBE,IAAeF,EAAe,EAAE;AAEtC,IAAAG,GAAU,MAAM;AACf,MAAAC,EAAA;AAAA,IACD,CAAC;AAED,UAAMA,IAAiB,MAAM;AAC5B,MAAAL,EAAe,QAAQ,CAAA,GACvBG,EAAa,QAAQ,CAAA;AAAA,IACtB,GAEMG,IAAU,MAAM;AACrB,MAAAJ,EAAO,QAAQ,CAACA,EAAO;AAAA,IACxB,GAEMK,IAAiB,CAACC,MAAkB;AACzC,YAAMC,IAAe,CAACT,EAAe,MAAMQ,CAAK;AAChD,MAAAH,EAAA,GACII,MACHT,EAAe,MAAMQ,CAAK,IAAI,IAC9BL,EAAa,MAAMK,CAAK,IAAI;AAAA,IAE9B,GAEME,IAAc,CAACC,GAAkDC,MAAkB;AAExF,MAAAd,EAAK,eAAec,GAAOD,CAAM;AAAA,IAClC;2BAhFCE,EAoCM,OAAA;AAAA,MApCA,OAAKC,EAAA,CAAA,EAAA,WAAA,CAAgBZ,EAAA,MAAA,GAAgB,YAAY,CAAA;AAAA,IAAA;MACtDa,EAEM,OAFNC,IAEM;AAAA,QADLD,EAAqE,OAAA;AAAA,UAAhE,IAAG;AAAA,UAAS,oBAAkBb,EAAA,OAAM;AAAA,UAAK,SAAAI;AAAA,QAAA,GAAgB,KAAC,CAAA;AAAA,MAAA;sBAEhES,EAAsC,OAAA,EAAjC,OAAA,EAAA,gBAAA,OAAA,EAAA,GAA0B,MAAA,EAAA;AAAA,OAC/BE,EAAA,EAAA,GAAAJ,EA8BMK,GAAA,MAAAC,EA9BqBC,EAAA,UAAQ,CAAtBC,GAAIb,YAAjBK,EA8BM,OAAA;AAAA,QA9BgC,KAAKQ,EAAG;AAAA,QAAO,OAAM;AAAA,MAAA;QAC1DN,EAQM,OARNO,IAQM;AAAA,UANED,EAAG,QAAI,iBADdR,EAMS,UAAA;AAAA;YAJP,UAAUQ,EAAG;AAAA,YACd,OAAM;AAAA,YACL,SAAK,CAAAE,MAAEb,EAAYW,EAAG,QAAQA,EAAG,KAAK;AAAA,UAAA,GACpCG,EAAAH,EAAG,KAAK,GAAA,GAAAI,EAAA;;QAGFJ,EAAG,QAAI,mBAAlBR,EAmBM,OAAAa,IAAA;AAAA,UAlBLX,EAKM,OALNY,IAKM;AAAA,YAJLZ,EAAmG,OAAA;AAAA,cAA9F,OAAKD,EAAA,CAAC,SAAO,EAAA,SAAoBX,EAAA,MAAaK,CAAK,EAAA,CAAA,CAAA;AAAA,cAAM,SAAK,CAAAe,MAAEhB,EAAeC,CAAK;AAAA,YAAA,GAAG,KAAC,IAAAoB,EAAA;AAAA,YAC7Fb,EAES,UAAA;AAAA,cAFD,OAAM;AAAA,cAAiC,SAAK,CAAAQ,MAAEhB,EAAeC,CAAK;AAAA,YAAA,GACtEgB,EAAAH,EAAG,KAAK,GAAA,GAAAQ,EAAA;AAAA,UAAA;UAGbC,EAAAf,EAWM,OAXNgB,IAWM;AAAA,YAVLhB,EASM,OATNiB,IASM;AAAA,eARLf,EAAA,EAAA,GAAAJ,EAOMK,GAAA,MAAAC,EAPcE,EAAG,UAAXY,YAAZpB,EAOM,OAAA;AAAA,gBAP2B,KAAKoB,EAAK;AAAA,cAAA;gBAC5BA,EAAK,UAAM,aAAzBpB,EAES,UAAA;AAAA;kBAF0B,OAAM;AAAA,kBAAiB,SAAK,CAAAU,MAAEb,EAAYuB,EAAK,QAAQA,EAAK,KAAK;AAAA,gBAAA,GAChGT,EAAAS,EAAK,KAAK,GAAA,GAAAC,EAAA,KAEAD,EAAK,QAAI,aAAvBpB,EAEC,KAAA;AAAA;kBAFiC,MAAMoB,EAAK;AAAA,gBAAA;kBAC3ClB,EAAuD,UAAvDoB,IAAuDX,EAAtBS,EAAK,KAAK,GAAA,CAAA;AAAA,gBAAA;;;;YAPnC,CAAAG,IAAApC,EAAA,MAAeQ,CAAK,CAAA;AAAA,UAAA;;;;;;;;;;;;;;;;;;;;;;;;;;ACuCrC,UAAMV,IAAOC,GAKPsC,IAAQpC,EAAI,EAAE,GACdqC,IAAgBrC,EAAI,CAAC,GACrBsC,IAAWC,GAAe,OAAO,GAEjCC,IAAUC,EAAS,MACnBL,EAAM,QACWjB,EAAA,OAAOiB,EAAM,KAAK,EACnB,MAAM,GAAGjB,EAAA,UAAU,IAFf,CAAA,CAGzB;AAGD,IAAAuB;AAAA,MACC,MAAMvB,EAAA;AAAA,MACN,OAAMwB,MAAQ;AACb,QAAIA,MACHP,EAAM,QAAQ,IACdC,EAAc,QAAQ,GACtB,MAAMO,GAAA,GACJN,EAAS,OAA4B,MAAA;AAAA,MAEzC;AAAA,IAAA,GAIDI,EAAMF,GAAS,MAAM;AACpB,MAAAH,EAAc,QAAQ;AAAA,IACvB,CAAC;AAED,UAAMQ,IAAa,MAAM;AACxB,MAAAhD,EAAK,OAAO;AAAA,IACb,GAEMiD,IAAgB,CAACC,MAAqB;AAC3C,cAAQA,EAAE,KAAA;AAAA,QACT,KAAK;AACJ,UAAAF,EAAA;AACA;AAAA,QACD,KAAK;AACJ,UAAAE,EAAE,eAAA,GACEP,EAAQ,MAAM,WACjBH,EAAc,SAASA,EAAc,QAAQ,KAAKG,EAAQ,MAAM;AAEjE;AAAA,QACD,KAAK;AACJ,UAAAO,EAAE,eAAA,GACEP,EAAQ,MAAM,WACjBH,EAAc,SAASA,EAAc,QAAQ,IAAIG,EAAQ,MAAM,UAAUA,EAAQ,MAAM;AAExF;AAAA,QACD,KAAK;AACJ,UAAIA,EAAQ,MAAM,UAAUH,EAAc,SAAS,KAClDW,EAAaR,EAAQ,MAAMH,EAAc,KAAK,CAAC;AAEhD;AAAA,MAAA;AAAA,IAEH,GAEMW,IAAe,CAACC,MAAc;AACnC,MAAApD,EAAK,UAAUoD,CAAM,GACrBJ,EAAA;AAAA,IACD;2BA9HCK,GAqCWC,IAAA,EArCD,IAAG,UAAM;AAAA,MAClBC,EAmCaC,IAAA,EAnCD,MAAK,UAAM;AAAA,mBACtB,MAiCM;AAAA,UAjCKlC,EAAA,eAAXP,EAiCM,OAAA;AAAA;YAjCa,OAAM;AAAA,YAA2B,SAAOiC;AAAA,UAAA;YAC1D/B,EA+BM,OAAA;AAAA,cA/BD,OAAM;AAAA,cAAmB,4BAAD,MAAA;AAAA,cAAA,GAAW,CAAA,MAAA,CAAA;AAAA,YAAA;cACvCA,EASM,OATNC,IASM;AAAA,kBARLD,EAO4B,SAAA;AAAA,kBAN3B,KAAI;AAAA,gEACKsB,EAAK,QAAAd;AAAA,kBACd,MAAK;AAAA,kBACL,OAAM;AAAA,kBACL,aAAaH,EAAA;AAAA,kBACd,WAAA;AAAA,kBACC,WAAS2B;AAAA,gBAAA;uBALDV,EAAA,KAAK;AAAA,gBAAA;;cAQLI,EAAA,MAAQ,UAAnBxB,KAAAJ,EAeM,OAfNY,IAeM;AAAA,iBAdLR,EAAA,EAAA,GAAAJ,EAaMK,GAAA,MAAAC,EAZqBsB,EAAA,OAAO,CAAzBS,GAAQ1C,YADjBK,EAaM,OAAA;AAAA,kBAXJ,KAAKL;AAAA,kBACN,OAAKM,EAAA,CAAC,0BAAwB,EAAA,UACVN,MAAU8B,EAAA,MAAA,CAAa,CAAA;AAAA,kBAC1C,SAAK,CAAAf,MAAE0B,EAAaC,CAAM;AAAA,kBAC1B,aAAS,CAAA3B,MAAEe,EAAA,QAAgB9B;AAAA,gBAAA;kBAC5BO,EAEM,OAFNY,IAEM;AAAA,oBADL4B,EAAsCC,EAAA,QAAA,SAAA,EAAlB,QAAAN,GAAc;AAAA,kBAAA;kBAEnCnC,EAEM,OAFNa,IAEM;AAAA,oBADL2B,EAAwCC,EAAA,QAAA,WAAA,EAAlB,QAAAN,GAAc;AAAA,kBAAA;;oBAIvBb,EAAA,SAAK,CAAKI,EAAA,MAAQ,UAAlCxB,EAAA,GAAAJ,EAEM,OAFNgB,IAEM;AAAA,gBADL0B,EAA8DC,uBAA9D,MAA8D;AAAA,oBAA3C,4BAAuBhC,EAAGa,EAAA,KAAK,IAAG,MAAE,CAAA;AAAA,gBAAA;;;;;;;;;;;;;;;AC+B7D,UAAMoB,IAAsBxD,EAAI,EAAI,GAC9ByD,IAAgBzD,EAAI,EAAK,GACzB0D,IAAa1D,EAAI,EAAE,GACnBsC,IAAWC,GAAiC,aAAa,GAEzDoB,IAAoBlB,EAAS,MAC3Be,EAAoB,QAAQ,cAAc,SACjD,GAEKI,IAAoB,MAAM;AAC/B,MAAAJ,EAAoB,QAAQ,CAACA,EAAoB;AAAA,IAClD,GAEMK,IAAe,YAAY;AAChC,MAAAJ,EAAc,QAAQ,CAACA,EAAc,OACrC,MAAMb,GAAS,MAAM;AACpB,QAAAN,EAAS,OAAO,MAAA;AAAA,MACjB,CAAC;AAAA,IACF,GAEMwB,IAAoB,CAACC,MAA8B;AACxD,MAAAA,EAAM,eAAA,GACNA,EAAM,gBAAA;AAAA,IACP,GAEMC,IAAe,OAAOD,MAAsC;AACjE,MAAAA,EAAM,eAAA,GACNA,EAAM,gBAAA,GACN,MAAMF,EAAA;AAAA,IACP,GAEMI,IAAe,MAA6C;AAAA,IAElE;;;kBAhGCrD,EAuDS,UAAA,MAAA;AAAA,QAtDRE,EAqDK,MArDLC,IAqDK;AAAA,UApDJD,EAEK,MAAA;AAAA,YAFD,OAAM;AAAA,YAAmB,SAAO8C;AAAA,YAAoB,aAAeA,GAAiB,CAAA,OAAA,CAAA;AAAA,UAAA;YACvF9C,EAA2D,KAA3DO,IAA2D;AAAA,cAA3CP,EAAuC,OAAA;AAAA,gBAAjC,SAAO6C,EAAA,KAAiB;AAAA,cAAA,GAAE,KAAC,CAAA;AAAA,YAAA;;UAElD7C,EAWK,MAAA;AAAA,YAVJ,OAAM;AAAA,YACL,oBAAkB0C,EAAA,QAAmB,UAAA,QAAA;AAAA,YACrC,SAAOS;AAAA,YACP,aAAeA,GAAY,CAAA,OAAA,CAAA;AAAA,UAAA;YAC5Bb,EAKcc,GAAA;AAAA,cALD,IAAG;AAAA,cAAI,UAAS;AAAA,YAAA;yBAC5B,MAGM,CAAA,GAAAC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,gBAHNrD,EAGM,OAAA;AAAA,kBAHD,OAAM;AAAA,kBAAO,cAAW;AAAA,kBAAO,SAAQ;AAAA,kBAAY,MAAK;AAAA,kBAAO,QAAO;AAAA,kBAAe,gBAAa;AAAA,gBAAA;kBACtGA,EAA0B,QAAA,EAApB,GAAE,iBAAe;AAAA,kBACvBA,EAAyB,QAAA,EAAnB,GAAE,gBAAc;AAAA,gBAAA;;;;;UAIzBA,EA8BK,MAAA;AAAA,YA7BH,0CAAwC2C,EAAA,MAAA,CAAa,CAAA;AAAA,YACrD,oBAAkBD,EAAA,QAAmB,UAAA,QAAA;AAAA,UAAA;YACtC1C,EA0BI,KA1BJU,IA0BI;AAAA,sBAzBHZ,EAaM,OAAA;AAAA,gBAXL,OAAM;AAAA,gBACN,MAAK;AAAA,gBACL,cAAW;AAAA,gBACX,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,QAAO;AAAA,gBACP,gBAAa;AAAA,gBACZ,SAAOiD;AAAA,gBACP,aAAeA,GAAY,CAAA,OAAA,CAAA;AAAA,cAAA;gBAC5B/C,EAAgC,UAAA;AAAA,kBAAxB,IAAG;AAAA,kBAAK,IAAG;AAAA,kBAAK,GAAE;AAAA,gBAAA;gBAC1BA,EAA8B,QAAA,EAAxB,GAAE,oBAAA,GAAmB,MAAA,EAAA;AAAA,cAAA;sBAXlB2C,EAAA,KAAa;AAAA,cAAA;gBAavB3C,EAUkC,SAAA;AAAA,gBARjC,KAAI;AAAA,8DACK4C,EAAU,QAAApC;AAAA,gBACnB,MAAK;AAAA,gBACL,aAAY;AAAA,gBACX,4BAAD,MAAA;AAAA,gBAAA,GAAW,CAAA,MAAA,CAAA;AAAA,gBACV,SAAK6C,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAA7C,MAAEwC,EAAkBxC,CAAM;AAAA,gBAC/B,QAAI6C,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAA7C,MAAE0C,EAAa1C,CAAM;AAAA,gBACzB,WAAO;AAAA,kBAAQ6C,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAC,EAAA,CAAA9C,MAAA0C,EAAa1C,CAAM,GAAA,CAAA,OAAA,CAAA;AAAA,oBAClBuC,GAAY,CAAA,QAAA,CAAA;AAAA,gBAAA;AAAA;qBATrBJ,EAAA,KAAa;AAAA,qBAEZC,EAAA,KAAU;AAAA,cAAA;;;kBAUtB9C,EAKKK,GAAA,MAAAC,EAJiBC,EAAA,aAAW,CAAzBkD,YADRzD,EAKK,MAAA;AAAA,YAHH,KAAKyD,EAAW;AAAA,YAChB,oBAAkBb,EAAA,QAAmB,UAAA,QAAA;AAAA,UAAA;YACtCJ,EAAoFc,GAAA;AAAA,cAAvE,UAAS;AAAA,cAAK,IAAIG,EAAW;AAAA,YAAA;yBAAK,MAAsB;AAAA,gBAAnBC,EAAA/C,EAAA8C,EAAW,KAAK,GAAA,CAAA;AAAA,cAAA;;;;;;;;;;;;;;;;;;;;;;ACsBtE,aAASE,EAAqBC,GAAqC;AAClE,YAAMC,IAAQC,GAAcF,CAAM,EAAE,OAAO,CAAAG,MAASA,EAAM,SAAS,WAAW,EAAQA,EAAM,OAAQ;AAEpG,aAAO,IAAI;AAAA,QACVF,EAAM,OAAO,CAAAE,MAASC,GAAuBD,EAAM,SAAS,MAAM,QAAQ,EAAE,IAAI,CAAAA,MAASA,EAAM,SAAS;AAAA,MAAA;AAAA,IAE1G;AAOA,aAASE,EAAgBC,GAAyB;AACjD,aAAIA,MAAU,QAAQ,OAAOA,KAAU,YAAY,CAAC,MAAM,QAAQA,CAAK,KAAK,QAAQA,IAC3EA,EAA0B,KAE5BA;AAAA,IACR;AAYA,UAAMjF,IAAOC,GA4BP,EAAE,WAAAiF,EAAA,IAAcC,GAAA;AAOtB,QAAIC,IAAgE;AACpE,QAAI;AACH,MAAAA,IAAkBC,GAAA;AAAA,IACnB,QAAQ;AACP,MAAAD,IAAkB;AAAA,IACnB;AAIA,UAAME,IAAc1C;AAAA,MAAmC,MACtD2C,EAAY,UAAU,WAAYH,GAAiB,iBAAiB,CAAA,IAAM,CAAA;AAAA,IAAC,GAItEI,IAAUrF,EAAI,EAAK,GACnBsF,IAAqBtF,EAAI,EAAK,GAI9BuF,IAAcvF,EAAyB,EAAE,GAMzCwF,IAAkB/C,EAA8B;AAAA,MACrD,MAAM;AAEL,YAAI2C,EAAY,UAAU;AACzB,iBAAO;AAAA,YACN,gBACCjE,qBAAmB,IAAI,CAAAsE,OAAY;AAAA,cAClC,IAAIA;AAAA,cACJ,SAAAA;AAAA,cACA,cAAcC,EAAkBD,CAAO;AAAA,cACvC,SAAS;AAAA,YAAA,EACR,KAAK,CAAA;AAAA,UAAC;AAKX,YAAIL,EAAY,UAAU;AACzB,iBAAO;AAAA,YACN,eAAeO,KAAa;AAAA,cAAI,CAAAC,MAC/B,OAAO,OAAO,CAAA,GAAIA,GAAQ;AAAA,gBACzB,IAAIC,GAAgBD,CAAM,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAO/B,SAAS;AAAA,cAAA,CACT;AAAA,YAAA;AAAA,UACF;AAKF,YAAI,CAACb,EAAU,SAAS,CAACe,EAAe,SAAS,CAACC,EAAgB;AACjE,iBAAO,CAAA;AAGR,YAAI;AAQH,gBAAMC,IAA4B,EAAE,GAPrBC,EAAY,QACxBV,EAAY,QACXR,EAAU,MAAM,cAAce,EAAe,OAAOC,EAAgB,KAAK,GAAG,IAAI,EAAE,EAK/C,GAKjCN,IAAUV,EAAU,MAAM,SAAS,SAASe,EAAe,KAAK;AACtE,cAAIL;AACH,uBAAWd,KAASc,EAAQ;AAC3B,kBAAId,EAAM,SAAS,YAAY;AAC9B,sBAAMuB,IAA8B,CAAA;AACpC,2BAAWC,KAASxB,EAAM;AACzB,kBAAIwB,EAAM,cAAWD,EAAOC,EAAM,SAAS,IAAIH,EAAKG,EAAM,SAAS;AAEpE,gBAAAH,EAAKrB,EAAM,SAAS,IAAIuB;AAAA,cACzB;AAAA;AAGF,iBAAOF;AAAA,QACR,QAAQ;AACP,iBAAO,CAAA;AAAA,QACR;AAAA,MACD;AAAA,MACA,IAAII,GAA8B;AAEjC,YAAIhB,EAAY,UAAU,YACtB,GAACL,EAAU,SAAS,CAACe,EAAe,SAAS,CAACC,EAAgB;AAIlE,cAAI;AAGH,kBAAMN,IAAUV,EAAU,MAAM,SAAS,SAASe,EAAe,KAAK,GAChEO,wBAAoB,IAAA;AAC1B,gBAAIZ;AACH,yBAAWd,KAASc,EAAQ;AAC3B,gBAAId,EAAM,SAAS,cAClB0B,EAAc,IAAI1B,EAAM,SAAS;AAIpC,kBAAM2B,IAAc/B,EAAqBkB,IAAUA,EAAQ,eAAA,IAAmB,EAAE,GAM1Ec,IAAgC,CAAA,GAChCC,IAAwC,CAAA;AAC9C,uBAAW,CAACC,GAAK3B,CAAK,KAAK,OAAO,QAAQsB,CAAO;AAChD,cAAIC,EAAc,IAAII,CAAG,KAAK3B,KAAS,OAAOA,KAAU,YAAY,CAAC,MAAM,QAAQA,CAAK,IACvF0B,EAAe,KAAK1B,CAAK,IAEzByB,EAASE,CAAG,IAAI3B;AAGlB,uBAAW4B,KAAeF;AACzB,qBAAO,OAAOD,GAAUG,CAAW;AAMpC,kBAAMC,IAA0B,CAAA;AAChC,gBAAIV,EAAY,OAAO;AAGtB,oBAAMW,IAAO,EAAE,GAAGrB,EAAY,MAAA;AAC9B,yBAAW,CAACsB,GAAW/B,CAAK,KAAK,OAAO,QAAQyB,CAAQ,GAAG;AAC1D,oBAAIzB,MAAU,OAAW;AACzB,sBAAMgC,IAAaR,EAAY,IAAIO,CAAS,IAAIhC,EAAgBC,CAAK,IAAIA;AACzE,gBAAI8B,EAAKC,CAAS,MAAMC,MACvBF,EAAKC,CAAS,IAAIC,GAClBH,EAAc,KAAKE,CAAS;AAAA,cAE9B;AACA,cAAAtB,EAAY,QAAQqB;AAAA,YACrB,OAAO;AACN,oBAAMG,IAAWhC,EAAU,MAAM,SAAA;AACjC,yBAAW,CAAC8B,GAAW/B,CAAK,KAAK,OAAO,QAAQyB,CAAQ,GAAG;AAC1D,oBAAIzB,MAAU,OAAW;AACzB,sBAAMgC,IAAaR,EAAY,IAAIO,CAAS,IAAIhC,EAAgBC,CAAK,IAAIA,GACnEkC,IAAY,GAAGlB,EAAe,KAAK,IAAIC,EAAgB,KAAK,IAAIc,CAAS;AAE/E,iBADqBE,EAAS,IAAIC,CAAS,IAAID,EAAS,IAAIC,CAAS,IAAI,YACpDF,MACpBC,EAAS,IAAIC,GAAWF,CAAU,GAClCH,EAAc,KAAKE,CAAS;AAAA,cAE9B;AAAA,YACD;AAIA,YAAIF,EAAc,SAAS,KAC1BM,EAAqBN,CAAa;AAAA,UAEpC,SAASO,GAAO;AACf,oBAAQ,KAAK,sBAAsBA,CAAK;AAAA,UACzC;AAAA,MACD;AAAA,IAAA,CACA;AAKD,aAASD,EAAqBN,GAAyB;AACtD,UAAI,CAAC1B,KAAmB,CAACF,EAAU,SAAS,CAACe,EAAe,SAAS,CAACC,EAAgB,MAAO;AAG7F,YAAMoB,IADUpC,EAAU,MAAM,SAAS,WAAWe,EAAe,KAAK,GAC9C,YAAA;AAC1B,UAAI,CAACqB,KAAY,OAAO,KAAKA,CAAQ,EAAE,WAAW,EAAG;AAGrD,YAAMvB,IAASK,EAAY,QACxB,EAAE,GAAGV,EAAY,UACjB;AAAA,QACA,GAAIR,EAAU,MAAM,cAAce,EAAe,OAAOC,EAAgB,KAAK,GAAG,IAAI,EAAE;AAAA,MAAA;AAMzF,iBAAWpB,KAASgC;AACnB,QAAK1B,EAAgB,cAAckC,GAAUxC,GAAOiB,CAAM;AAAA,IAE5D;AAIA,UAAMwB,IAAQ3E,EAAS,MAAOtB,EAAA,eAAe,OAAOkG,GAAMtC,EAAU,OAAO,SAAS,QAAQ,YAAY,CAAE,GACpGuC,IAAS7E,EAAS,MAAOtB,EAAA,eAAe,OAAO4D,EAAU,OAAO,SAAS,MAAO,GAChFe,IAAiBrD,EAAS,MAAM;AACrC,UAAItB,eAAc,QAAOA,EAAA,aAAa,kBAAA;AACtC,UAAI,CAACiG,EAAM,MAAO,QAAO;AAGzB,UAAIA,EAAM,MAAM,MAAM;AACrB,eAAOA,EAAM,MAAM,KAAK;AAIzB,UAAIA,EAAM,MAAM,OAAO;AACtB,eAAOA,EAAM,MAAM,OAAO,QAAQ,SAAA;AAInC,YAAMG,IAAYH,EAAM,MAAM,OAAO;AACrC,aAAIG,KAAaA,EAAU,SAAS,IAC5BA,EAAU,CAAC,IAGZ;AAAA,IACR,CAAC,GAGKC,IAAe/E,EAAS,MAAM;AACnC,UAAItB,eAAc,QAAOA,EAAA,aAAa,kBAAA;AACtC,UAAI,CAACiG,EAAM,MAAO,QAAO;AAGzB,UAAIA,EAAM,MAAM,MAAM;AACrB,eAAOA,EAAM,MAAM,KAAK;AAIzB,UAAIA,EAAM,MAAM,OAAO;AACtB,eAAOA,EAAM,MAAM,OAAO,QAAQ,SAAA;AAInC,YAAMG,IAAYH,EAAM,MAAM,OAAO;AACrC,aAAIG,KAAaA,EAAU,SAAS,IAC5BA,EAAU,CAAC,IAGZ;AAAA,IACR,CAAC,GAEKxB,IAAkBtD,EAAS,MAAM;AACtC,UAAItB,eAAc,QAAOA,eAAa,mBAAA;AACtC,UAAI,CAACiG,EAAM,MAAO,QAAO;AAGzB,UAAIA,EAAM,MAAM,OAAO;AACtB,eAAOA,EAAM,MAAM,OAAO,SAAS,SAAA;AAIpC,YAAMG,IAAYH,EAAM,MAAM,OAAO;AACrC,aAAIG,KAAaA,EAAU,SAAS,IAC5BA,EAAU,CAAC,IAGZ;AAAA,IACR,CAAC,GACKtB,IAAcxD,EAAS,MAAMgF,GAAgB1B,EAAgB,KAAK,CAAC,GAGnEX,IAAc3C,EAAS,MAAM;AAClC,UAAItB,EAAA,aAAc,QAAOA,EAAA,aAAa,eAAA;AAMtC,UALI,CAACiG,EAAM,SAKPA,EAAM,MAAM,SAAS,UAAUA,EAAM,MAAM,SAAS;AACvD,eAAO;AAIR,UAAIA,EAAM,MAAM,QAAQA,EAAM,MAAM,SAAS,aAAa;AACzD,cAAMM,IAAYN,EAAM,MAAM;AAC9B,YAAIM,EAAU,SAAS,MAAM,KAAKN,EAAM,MAAM,OAAO;AACpD,iBAAO;AACR,YAAWM,EAAU,SAAS,MAAM,KAAKN,EAAM,MAAM,OAAO;AAC3D,iBAAO;AAAA,MAET;AAGA,YAAMG,IAAYH,EAAM,MAAM,OAAO;AACrC,aAAIG,KAAaA,EAAU,SAAS,IACtBA,EAAU,WAAW,IAAI,YAAY,WAI5C;AAAA,IACR,CAAC,GAMKI,KAA0B,MAAM;AACrC,UAAI,CAAC5C,EAAU,SAAS,CAACe,EAAe,SAAS,CAACC,EAAgB;AACjE,eAAO,CAAA;AAGR,UAAI;AACH,cAAMN,IAAUV,EAAU,MAAM,SAAS,WAAWe,EAAe,KAAK;AACxE,YAAI,CAACL,GAAS,SAAU,QAAO,CAAA;AAG/B,cAAMmC,IAAe7C,EAAU,MAAM,eAAee,EAAe,OAAOC,EAAgB,KAAK,GAGzF8B,IAAcpC,EAAQ,wBAAwBmC,CAAY,GAE1DE,IAAatC,EAAgB,SAAS,CAAA;AAI5C,eAAOqC,EAAY,IAAI,CAAC,EAAE,MAAAE,SAAY;AAAA;AAAA;AAAA,UAGrC,OAAOtC,EAAQ,cAAcsC,CAAI,GAAG,SAASA;AAAA,UAC7C,QAAQ,MAAM;AACb,YAAAlI,EAAK,UAAU;AAAA,cACd,MAAAkI;AAAA,cACA,SAASjC,EAAe;AAAA,cACxB,UAAUC,EAAgB;AAAA,cAC1B,MAAM+B;AAAA,YAAA,CACN;AAAA,UACF;AAAA,QAAA,EACC;AAAA,MACH,SAASZ,GAAO;AACf,uBAAQ,KAAK,wCAAwCA,CAAK,GACnD,CAAA;AAAA,MACR;AAAA,IACD,GAKMc,KAAuB,MAAM;AAClC,UAAI,CAACjD,EAAU,SAAS,CAACe,EAAe,SAAS,CAACC,EAAgB;AACjE,eAAO,CAAA;AAGR,UAAI;AACH,cAAMN,IAAUV,EAAU,MAAM,SAAS,WAAWe,EAAe,KAAK;AACxE,YAAI,CAACL,GAAS,SAAU,QAAO,CAAA;AAE/B,cAAMmC,IAAe7C,EAAU,MAAM,eAAee,EAAe,OAAOC,EAAgB,KAAK,GACzFkC,IAAWxC,EAAQ,qBAAqBmC,CAAY,GACpDE,IAAatC,EAAgB,SAAS,CAAA;AAE5C,eAAOyC,EAAS,IAAI,CAAC,EAAE,MAAAF,SAAY;AAAA,UAClC,OAAOtC,EAAQ,cAAcsC,CAAI,GAAG,SAASA;AAAA,UAC7C,QAAQ,MAAM;AACb,YAAAlI,EAAK,UAAU;AAAA,cACd,MAAAkI;AAAA,cACA,SAASjC,EAAe;AAAA,cACxB,UAAUC,EAAgB;AAAA,cAC1B,MAAM+B;AAAA,YAAA,CACN;AAAA,UACF;AAAA,QAAA,EACC;AAAA,MACH,SAASZ,GAAO;AACf,uBAAQ,KAAK,qCAAqCA,CAAK,GAChD,CAAA;AAAA,MACR;AAAA,IACD,GAEMgB,KAAiBzF,EAAS,MAAM;AACrC,YAAM0F,IAA6B,CAAA;AAEnC,cAAQ/C,EAAY,OAAA;AAAA,QACnB,KAAK;AACJ,UAAA+C,EAAS,KAAK;AAAA,YACb,MAAM;AAAA,YACN,OAAO;AAAA,YACP,QAAQ,MAAA;AAAM,cAAKC,EAAA;AAAA;AAAA,UAAgB,CACnC;AACD;AAAA,QACD,KAAK,UAAU;AAGd,gBAAMC,IAAgB,CAAC,GAAGV,MAA2B,GAAGK,IAAsB;AAC9E,UAAIK,EAAc,SAAS,KAC1BF,EAAS,KAAK;AAAA,YACb,MAAM;AAAA,YACN,OAAO;AAAA,YACP,SAASE;AAAA,UAAA,CACT;AAEF;AAAA,QACD;AAAA,MAAA;AAGD,aAAOF;AAAA,IACR,CAAC,GAEKG,KAAwB7F,EAAS,MAAM;AAC5C,YAAM8F,IAA+C,CAAA;AAErD,UAAInD,EAAY,UAAU,aAAaoC,EAAa;AACnD,QAAAe,EAAY;AAAA,UACX,EAAE,OAAO,QAAQ,IAAI,IAAA;AAAA,UACrB,EAAE,OAAO7C,EAAkB8B,EAAa,KAAK,GAAG,IAAI,IAAIA,EAAa,KAAK,GAAA;AAAA,QAAG;AAAA,eAEpEpC,EAAY,UAAU,YAAYoC,EAAa,OAAO;AAChE,cAAMgB,IAAazC,EAAgB,QAChC,IAAIyB,EAAa,KAAK,IAAIzB,EAAgB,KAAK,KAC9CqB,EAAM,OAAO,YAAY;AAC7B,QAAAmB,EAAY;AAAA,UACX,EAAE,OAAO,QAAQ,IAAI,IAAA;AAAA,UACrB,EAAE,OAAO7C,EAAkB8B,EAAa,KAAK,GAAG,IAAI,IAAIA,EAAa,KAAK,GAAA;AAAA,UAC1E,EAAE,OAAOvB,EAAY,QAAQ,eAAe,eAAe,IAAIuC,EAAA;AAAA,QAAW;AAAA,MAE5E;AAEA,aAAOD;AAAA,IACR,CAAC,GASKE,KAAiB,CAACrG,MAA6B;AACpD,YAAM6F,IAAsB;AAAA,QAC3B;AAAA,UACC,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ,MAAA;AAAM,YAAKS,EAAW,EAAE,MAAM,YAAY;AAAA;AAAA,QAAA;AAAA,QAEnD;AAAA,UACC,OAAO;AAAA,UACP,aAAa;AAAA,UACb,QAAQ,MAAOpD,EAAmB,QAAQ,CAACA,EAAmB;AAAA,QAAA;AAAA,MAC/D;AA4BD,aAxBIkC,EAAa,UAChBS,EAAS,KAAK;AAAA,QACb,OAAO,QAAQvC,EAAkB8B,EAAa,KAAK,CAAC;AAAA,QACpD,aAAa,eAAeA,EAAa,KAAK;AAAA,QAC9C,QAAQ,MAAA;AAAM,UAAKkB,EAAW,EAAE,MAAM,WAAW,SAASlB,EAAa,MAAA,CAAO;AAAA;AAAA,MAAA,CAC9E,GAEDS,EAAS,KAAK;AAAA,QACb,OAAO,cAAcvC,EAAkB8B,EAAa,KAAK,CAAC;AAAA,QAC1D,aAAa,gBAAgBA,EAAa,KAAK;AAAA,QAC/C,QAAQ,MAAA;AAAM,UAAKY,EAAA;AAAA;AAAA,MAAgB,CACnC,IAIFjH,EAAA,kBAAkB,QAAQ,CAAAsE,MAAW;AACpC,QAAAwC,EAAS,KAAK;AAAA,UACb,OAAO,QAAQvC,EAAkBD,CAAO,CAAC;AAAA,UACzC,aAAa,eAAeA,CAAO;AAAA,UACnC,QAAQ,MAAA;AAAM,YAAKiD,EAAW,EAAE,MAAM,WAAW,SAAAjD,GAAS;AAAA;AAAA,QAAA,CAC1D;AAAA,MACF,CAAC,GAGIrD,IAEE6F,EAAS;AAAA,QACf,OACCU,EAAI,MAAM,YAAA,EAAc,SAASvG,EAAM,YAAA,CAAa,KACpDuG,EAAI,YAAY,YAAA,EAAc,SAASvG,EAAM,aAAa;AAAA,MAAA,IALzC6F;AAAA,IAOpB,GAEMW,KAAiB,CAACC,MAAqB;AAC5C,MAAAA,EAAQ,OAAA,GACRvD,EAAmB,QAAQ;AAAA,IAC5B,GAGMwD,KAAqB,CAACC,MAA4D;AACvF,UAAI,CAAChE,EAAU,SAAS,CAACe,EAAe;AACvC,eAAO,QAAQ,QAAQ,EAAE,MAAM,CAAA,GAAI,SAAS,IAAO;AAEpD,YAAML,IAAUV,EAAU,MAAM,SAAS,WAAWe,EAAe,KAAK;AACxE,aAAKL,IAGEV,EAAU,MAAM,WAAWU,GAASsD,CAAO,IAF1C,QAAQ,QAAQ,EAAE,MAAM,CAAA,GAAI,SAAS,IAAO;AAAA,IAGrD,GAGMrD,IAAoB,CAACD,MACnBA,EACL,MAAM,GAAG,EACT,IAAI,CAAAuD,MAAQA,EAAK,OAAO,CAAC,EAAE,YAAA,IAAgBA,EAAK,MAAM,CAAC,CAAC,EACxD,KAAK,GAAG,GAKLN,IAAa,OAAOO,MAA6B;AACtD,MAAApJ,EAAK,YAAYoJ,CAAM,GACnB9H,EAAA,eACH,MAAMA,EAAA,aAAa,SAAS8H,CAAM,IAE9BA,EAAO,SAAS,aACnB,MAAM3B,EAAO,OAAO,KAAK,GAAG,IAClB2B,EAAO,SAAS,aAAaA,EAAO,UAC9C,MAAM3B,EAAO,OAAO,KAAK,IAAI2B,EAAO,OAAO,EAAE,IACnCA,EAAO,SAAS,YAAYA,EAAO,WAAWA,EAAO,YAC/D,MAAM3B,EAAO,OAAO,KAAK,IAAI2B,EAAO,OAAO,IAAIA,EAAO,QAAQ,EAAE;AAAA,IAGnE,GAEMC,KAAoB,OAAOzD,MAAoB;AACpD,YAAMiD,EAAW,EAAE,MAAM,WAAW,SAAAjD,GAAS;AAAA,IAC9C,GAEM0D,KAAa,OAAOC,MAAqB;AAC9C,YAAM3D,IAAU+B,EAAa;AAC7B,MAAA3H,EAAK,eAAe,EAAE,SAAA4F,GAAS,UAAA2D,EAAA,CAAU,GACzC,MAAMV,EAAW,EAAE,MAAM,UAAU,SAAAjD,GAAS,UAAA2D,GAAU;AAAA,IACvD,GAEMhB,IAAkB,YAAY;AACnC,YAAMM,EAAW,EAAE,MAAM,UAAU,SAASlB,EAAa,OAAO,UAAU6B,IAAiB;AAAA,IAC5F,GAGMC,KAAoB,MACpBnI,EAAA,mBAAmB,SAEjB;AAAA,MACN;AAAA,QACC,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW;AAAA,QACX,OAAO;AAAA,QACP,QAAQ;AAAA,UACP;AAAA,YACC,WAAW;AAAA,YACX,OAAO;AAAA,YACP,WAAW;AAAA,YACX,OAAO;AAAA,YACP,MAAM;AAAA,YACN,OAAO;AAAA,UAAA;AAAA,UAER;AAAA,YACC,WAAW;AAAA,YACX,OAAO;AAAA,YACP,WAAW;AAAA,YACX,OAAO;AAAA,YACP,MAAM;AAAA,YACN,OAAO;AAAA,UAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAMR;AAAA,YACC,WAAW;AAAA,YACX,OAAO;AAAA,YACP,WAAW;AAAA,YACX,OAAO;AAAA,YACP,MAAM;AAAA,YACN,OAAO;AAAA,UAAA;AAAA,QACR;AAAA,QAED,QAAQ,EAAE,MAAM,QAAiB,WAAW,GAAA;AAAA,MAAK;AAAA,IAClD,IAvCsC,CAAA,GA2ClCoI,KAAmB,MAAuB;AAC/C,UAAI,CAACzD,EAAe,MAAO,QAAO,CAAA;AAClC,UAAI,CAACf,EAAU,MAAO,QAAO,CAAA;AAE7B,YAAMyE,IAAWzE,EAAU,MAAM,UAC3BU,IAAU+D,EAAS,SAAS1D,EAAe,KAAK;AAEtD,UAAI,CAACL,EAAS,QAAO,CAAA;AAErB,YAAMgE,IAASD,EAAS,cAAc/D,CAAO;AAG7C,UAAIgE,EAAO,WAAW,EAAG,QAAO,CAAA;AAEhC,YAAMC,IAAc5D,EAAe,OAC7B6D,IAAmB,EAAQ5E,EAAU,MAAM;AAEjD,aAAO;AAAA,QACN;AAAA,UACC,MAAM;AAAA,UACN,WAAW;AAAA,UACX,WAAW;AAAA;AAAA;AAAA;AAAA,UAIX,QAAQ,CAAC,GAAG6E,GAAwBH,CAAM,GAAG,EAAE,WAAW,WAAW,OAAO,WAAW,WAAW,cAAc;AAAA,UAChH,QAAQ,EAAE,MAAM,QAAiB,WAAW,GAAA;AAAA,UAC5C,GAAIE,IAAmB,EAAE,YAAYb,IAAoB,WAAWY,EAAA,IAAgB,CAAA;AAAA,QAAC;AAAA,MACtF;AAAA,IAEF,GAEMG,KAAsB,MAAuB;AAClD,UAAI,CAAC/D,EAAe,MAAO,QAAO,CAAA;AAClC,UAAI,CAACf,EAAU,MAAO,QAAO,CAAA;AAE7B,UAAI;AACH,cAAMyE,IAAWzE,EAAU,OAAO,UAC5BU,IAAU+D,GAAU,SAAS1D,EAAe,KAAK;AAEvD,eAAKL,GAAS,SAKP+D,EAAS,cAAc/D,CAAO,IAH7B,CAAA;AAAA,MAIT,QAAQ;AACP,eAAO,CAAA;AAAA,MACR;AAAA,IACD,GAGME,KAAa,MAAM;AACxB,UAAI,CAACZ,EAAU,SAAS,CAACe,EAAe;AACvC,eAAO,CAAA;AAIR,YAAMgE,IADc/E,EAAU,MAAM,QAAQe,EAAe,KAAK,GAC/B,IAAI,EAAE;AAEvC,aAAIgE,KAAe,OAAOA,KAAgB,YAAY,CAAC,MAAM,QAAQA,CAAW,IACxE,OAAO,OAAOA,CAAkC,IAGjD,CAAA;AAAA,IACR,GAGMC,KAAoBtH,EAAS,MAAM;AACxC,cAAQ2C,EAAY,OAAA;AAAA,QACnB,KAAK;AACJ,iBAAOkE,GAAA;AAAA,QACR,KAAK;AACJ,iBAAOC,GAAA;AAAA,QACR,KAAK;AACJ,iBAAOM,GAAA;AAAA,QACR;AACC,iBAAO,CAAA;AAAA,MAAC;AAAA,IAEX,CAAC,GAEKG,KAAoB,CAACC,GAAgBvJ,MAAqD;AAC/F,MAAIA,KACEA,EAAA;AAAA,IAEP,GAcMmF,KAAkB,CAACD,MAAwD;AAChF,UAAI,GAACb,EAAU,SAAS,CAACe,EAAe;AACxC,eAAOf,EAAU,MAAM,SAAS,SAASe,EAAe,KAAK,GAAG,YAAYF,CAAM;AAAA,IACnF,GAGMsE,KAAqB,CAACC,MAAmD;AAC9E,YAAMC,IAAOD,EAAW,cAAc,mBAAmB;AACzD,UAAI,CAACC,EAAM,QAAO;AAElB,YAAMC,IAAeD,EAAK,aAAa,eAAe;AACtD,UAAIC,MAAiB,KAAM,QAAO;AAElC,YAAMC,IAAW,SAASD,GAAc,EAAE;AAC1C,UAAI,MAAMC,CAAQ,EAAG,QAAO;AAG5B,YAAM1E,IADUD,GAAA,EACO2E,CAAQ;AAC/B,aAAK1E,IAEEC,GAAgBD,CAAM,KAAK,OAFd;AAAA,IAGrB,GAEMnF,KAAc,OAAOsD,MAAiB;AAC3C,YAAMkF,IAASlF,EAAM;AAGrB,MAFekF,EAAO,aAAa,aAAa,MAEjC,YACd,MAAMb,EAAA;AAGP,YAAMgC,IAAOnB,EAAO,QAAQ,QAAQ;AACpC,UAAImB,GAAM;AACT,cAAMG,IAAWH,EAAK,aAAa,KAAA,GAC7BI,IAAMJ,EAAK,QAAQ,IAAI;AAE7B,YAAIG,MAAa,kBAAkBC,GAAK;AAEvC,gBAAMC,IAAQD,EAAI,iBAAiB,IAAI;AACvC,cAAIC,EAAM,SAAS,GAAG;AAErB,kBAAMhF,IADcgF,EAAM,CAAC,EACC,aAAa,KAAA;AACzC,YAAIhF,KACH,MAAMyD,GAAkBzD,CAAO;AAAA,UAEjC;AAAA,QACD,WAAW8E,MAAa,UAAUC,GAAK;AAItC,gBAAMpB,IAAWc,GAAmBM,CAAG;AACvC,UAAIpB,KACH,MAAMD,GAAWC,CAAQ;AAAA,QAE3B;AAAA,MACD;AAAA,IACD,GAOMsB,KAAiB,YAAY;AAClC,UAAI,GAAC3F,EAAU,SAAS,CAACe,EAAe,SAAS,CAACf,EAAU,MAAM,cAElE;AAAA,QAAAM,EAAQ,QAAQ;AAChB,YAAI;AACH,gBAAMN,EAAU,MAAM,UAAUe,EAAe,OAAOC,EAAgB,KAAK;AAAA,QAC5E,SAASmB,GAAO;AACf,kBAAQ,KAAK,0BAA0BA,CAAK;AAAA,QAC7C,UAAA;AACC,UAAA7B,EAAQ,QAAQ;AAAA,QACjB;AAAA;AAAA,IACD;AAGA,IAAA3C;AAAA,MACC,CAAC0C,GAAaU,GAAgBC,CAAe;AAAA,MAC7C,MAAM;AAGL,YAAIX,EAAY,UAAU,aAAaU,EAAe;AACrD,UAAAjG,EAAK,gBAAgB,EAAE,SAASiG,EAAe,OAAO;AAAA,iBAC5CV,EAAY,UAAU,YAAYU,EAAe,SAASC,EAAgB,OAAO;AAK3F,cAAIE,EAAY,MAAO;AAEvB,UAAApG,EAAK,eAAe,EAAE,SAASiG,EAAe,OAAO,UAAUC,EAAgB,OAAO,GACjF2E,GAAA;AAAA,QACN;AAAA,MACD;AAAA,MACA,EAAE,WAAW,GAAA;AAAA,IAAK,GAKnBhI,EAAM,CAACoD,GAAgBC,CAAe,GAAG,MAAM;AAC9C,MAAAd,GAAiB,SAAA;AAAA,IAClB,CAAC,GAKDvC;AAAA,MACC,CAACoD,GAAgBC,CAAe;AAAA,MAChC,MAAM;AACL,YAAI,CAACE,EAAY,OAAO;AACvB,UAAAV,EAAY,QAAQ,CAAA;AACpB;AAAA,QACD;AACA,cAAMiE,IAAWzE,EAAU,OAAO;AAClC,QAAAQ,EAAY,QAAQiE,IAAWA,EAAS,iBAAiBK,GAAA,CAAqB,IAAI,CAAA;AAAA,MACnF;AAAA,MACA,EAAE,WAAW,GAAA;AAAA,IAAK,GAyBnBc,GAAQ,kBAlBe;AAAA,MACtB,mBAAAzB;AAAA,MACA,YAAAC;AAAA,MACA,iBAAAf;AAAA;AAAA;AAAA;AAAA;AAAA,MAKA,YAAY,CAACL,GAAc6C,MAA+B;AACzD,QAAA/K,EAAK,UAAU;AAAA,UACd,MAAAkI;AAAA,UACA,SAASjC,EAAe;AAAA,UACxB,UAAUC,EAAgB;AAAA,UAC1B,MAAM6E,KAAQpF,EAAgB,SAAS,CAAA;AAAA,QAAC,CACxC;AAAA,MACF;AAAA,IAAA,CAGuC,GAGxCmF,GAAQ,sBAAsB;AAAA,MAC7B,UAAU,CAAClF,GAAiBoF,MAAwB;AACnD,QAAKnC,EAAW,EAAE,MAAM,UAAU,SAAAjD,GAAS,UAAU,OAAOoF,CAAE,GAAG;AAAA,MAClE;AAAA,IAAA,CAC6B,GAK9BF,GAAQ,qBAAqB,OAAOjB,GAAqBmB,MAA4C;AACpG,UAAK9F,EAAU;AACf,YAAI;AAEH,gBAAM+F,KADO,MAAM/F,EAAU,MAAM,QAAQ,EAAE,MAAM,IAAI2E,CAAW,IAAI,UAAU,CAACA,CAAW,GAAG,IACpE;AAC3B,cAAI,CAACoB,EAAc;AAEnB,gBAAMC,IAAc,CAACC,MAAiE;AACrF,gBAAI,CAACA,EAAK;AACV,kBAAMC,IAAMD,EAAIF,CAAY;AAC5B,mBAAO,OAAOG,KAAQ,YAAY,OAAOA,KAAQ,WAAW,OAAOA,CAAG,IAAI;AAAA,UAC3E,GAEMC,IAASnG,EAAU,MAAM,cAAc2E,GAAamB,CAAE,GAAG,IAAI,EAAE,GAC/DM,IAAgBJ,EAAYG,CAAM;AACxC,cAAIC,KAAiB,KAAM,QAAOA;AAElC,gBAAMpG,EAAU,MAAM,UAAU2E,GAAamB,CAAE;AAC/C,gBAAMO,IAAUrG,EAAU,MAAM,cAAc2E,GAAamB,CAAE,GAAG,IAAI,EAAE;AACtE,iBAAOE,EAAYK,CAAO;AAAA,QAC3B,QAAQ;AACP;AAAA,QACD;AAAA,IACD,CAAC;AAED,UAAMtI,KAAgB,CAACiB,MAAyB;AAC/C,OAAKA,EAAM,WAAWA,EAAM,YAAYA,EAAM,QAAQ,QACrDA,EAAM,eAAA,GACNuB,EAAmB,QAAQ,KAExBvB,EAAM,QAAQ,YAAYuB,EAAmB,UAChDA,EAAmB,QAAQ;AAAA,IAE7B;AAEA,WAAAnF,GAAU,MAAM;AACf,eAAS,iBAAiB,WAAW2C,EAAa;AAAA,IACnD,CAAC,GAEDuI,GAAY,MAAM;AACjB,eAAS,oBAAoB,WAAWvI,EAAa;AAAA,IACtD,CAAC,mBAv/BAlC,EAgCM,OAAA;AAAA,MAhCD,OAAM;AAAA,MAAW,SAAOH;AAAA,IAAA;MAE5B2C,EAA0EkI,IAAA;AAAA,QAA9D,UAAUpD,GAAA;AAAA,QAAiB,eAAc8B;AAAA,MAAA;MAI9CD,GAAA,MAAkB,SAAM,UAD/B7G,GAIyBqI,GAAAC,EAAA,GAAA;AAAA;QAFhB,MAAMhG,EAAA;AAAA,gDAAAA,EAAe,QAAAlE;AAAA,QAC5B,QAAQyI,GAAA;AAAA,QACR,QAAQ5E,EAAA;AAAA,MAAA,6CACOoG,GAAAxG,CAAA,KACjB/D,KAAAJ,EAEM,OAFNS,IAEM;AAAA,QADLP,EAAwC,KAAA,MAArC,aAAQS,EAAG6D,EAAA,KAAW,IAAG,YAAQ,CAAA;AAAA,MAAA,OAFrCpE,EAAA,GAAAJ,EAAkF,OAAlFG,IAAkF,CAAA,GAAAoD,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,QAAtCrD,EAAgC,WAA7B,6BAAyB,EAAA;AAAA,MAAA;MAMxEsC,EAAiDqI,IAAA,EAAtC,aAAanD,GAAA,MAAA,GAAqB,MAAA,GAAA,CAAA,aAAA,CAAA;AAAA,MAG7ClF,EAYiBsI,IAAA;AAAA,QAXf,WAASpG,EAAA;AAAA,QACT,QAAQmD;AAAA,QACT,aAAY;AAAA,QACX,UAAQG;AAAA,QACR,gCAAOtD,EAAA,QAAkB;AAAA,MAAA;QACf,OAAKqG,EACf,CAAkB,EADC,QAAA1I,QAAM;AAAA,UACtBqB,EAAA/C,EAAA0B,EAAO,KAAK,GAAA,CAAA;AAAA,QAAA;QAEL,SAAO0I,EACjB,CAAwB,EADH,QAAA1I,QAAM;AAAA,UACxBqB,EAAA/C,EAAA0B,EAAO,WAAW,GAAA,CAAA;AAAA,QAAA;;;;;ICnBnB2I,KAAiB;AAAA,EACtB,SAAS,CAACC,MAAa;AACtB,IAAAA,EAAI,UAAU,aAAaP,EAAS,GACpCO,EAAI,UAAU,kBAAkBH,EAAc,GAC9CG,EAAI,UAAU,WAAWC,EAAO,GAChCD,EAAI,UAAU,YAAYJ,EAAQ;AAAA,EACnC;AACD;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stonecrop/desktop",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "Desktop-specific components for Stonecrop UI",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/agritheory/stonecrop/issues"
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"src/*"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@stonecrop/
|
|
37
|
-
"@stonecrop/
|
|
38
|
-
"@stonecrop/
|
|
39
|
-
"@stonecrop/
|
|
40
|
-
"@stonecrop/
|
|
36
|
+
"@stonecrop/stonecrop": "0.29.0",
|
|
37
|
+
"@stonecrop/schema": "0.29.0",
|
|
38
|
+
"@stonecrop/themes": "0.29.0",
|
|
39
|
+
"@stonecrop/aform": "0.29.0",
|
|
40
|
+
"@stonecrop/atable": "0.29.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@microsoft/api-documenter": "^7.30.5",
|
|
@@ -123,7 +123,7 @@ const handleClick = (action: (() => void | Promise<void>) | undefined, label: st
|
|
|
123
123
|
position: relative;
|
|
124
124
|
font-size: 2rem;
|
|
125
125
|
display: inline-block;
|
|
126
|
-
color: var(--sc-gray-60
|
|
126
|
+
color: var(--sc-gray-60);
|
|
127
127
|
transition: all 0.2s ease-in-out;
|
|
128
128
|
}
|
|
129
129
|
.action-set.collapsed {
|
|
@@ -186,7 +186,7 @@ button.button-default {
|
|
|
186
186
|
pointer-events: all;
|
|
187
187
|
margin-left: 5px;
|
|
188
188
|
font-family: var(--sc-font-family);
|
|
189
|
-
color: var(--sc-gray-60
|
|
189
|
+
color: var(--sc-gray-60);
|
|
190
190
|
cursor: pointer;
|
|
191
191
|
transform: rotate(45deg);
|
|
192
192
|
user-select: none;
|
|
@@ -139,11 +139,11 @@ ul {
|
|
|
139
139
|
align-items: center;
|
|
140
140
|
justify-content: center;
|
|
141
141
|
text-decoration: none;
|
|
142
|
-
color: var(--sc-gray-60
|
|
143
|
-
background: var(--sc-btn-color
|
|
144
|
-
border: 1px solid var(--sc-btn-border
|
|
142
|
+
color: var(--sc-gray-60);
|
|
143
|
+
background: var(--sc-btn-color);
|
|
144
|
+
border: 1px solid var(--sc-btn-border);
|
|
145
145
|
font-size: 0.85rem;
|
|
146
|
-
font-family: var(--sc-font-family
|
|
146
|
+
font-family: var(--sc-font-family);
|
|
147
147
|
transition: all 0.15s ease;
|
|
148
148
|
|
|
149
149
|
/* Minimal ornamentation - subtle top radius only */
|
|
@@ -152,14 +152,14 @@ ul {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
.tabs a:hover {
|
|
155
|
-
background: var(--sc-btn-hover
|
|
155
|
+
background: var(--sc-btn-hover);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
.tabs .router-link-active {
|
|
159
159
|
z-index: 3;
|
|
160
|
-
background: var(--sc-primary-color
|
|
161
|
-
border-color: var(--sc-primary-color
|
|
162
|
-
color: var(--sc-primary-text-color
|
|
160
|
+
background: var(--sc-primary-color) !important;
|
|
161
|
+
border-color: var(--sc-primary-color) !important;
|
|
162
|
+
color: var(--sc-primary-text-color) !important;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
/* Pseudo-elements removed - minimal ornamentation style */
|
|
@@ -170,9 +170,9 @@ ul {
|
|
|
170
170
|
width: 2.4rem;
|
|
171
171
|
height: 2.4rem;
|
|
172
172
|
padding: 0.5rem;
|
|
173
|
-
background: var(--sc-btn-color
|
|
174
|
-
border: 1px solid var(--sc-btn-border
|
|
175
|
-
color: var(--sc-gray-60
|
|
173
|
+
background: var(--sc-btn-color);
|
|
174
|
+
border: 1px solid var(--sc-btn-border);
|
|
175
|
+
color: var(--sc-gray-60);
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
.hidebreadcrumbs a div {
|
|
@@ -208,7 +208,7 @@ li > a:focus {
|
|
|
208
208
|
a:active,
|
|
209
209
|
a:hover,
|
|
210
210
|
a:focus {
|
|
211
|
-
outline: 2px solid var(--sc-input-active-border-color
|
|
211
|
+
outline: 2px solid var(--sc-input-active-border-color);
|
|
212
212
|
z-index: 3;
|
|
213
213
|
}
|
|
214
214
|
|
|
@@ -218,9 +218,9 @@ a:focus {
|
|
|
218
218
|
width: 2.4rem;
|
|
219
219
|
height: 2.4rem;
|
|
220
220
|
padding: 0.5rem;
|
|
221
|
-
background: var(--sc-btn-color
|
|
222
|
-
border: 1px solid var(--sc-btn-border
|
|
223
|
-
color: var(--sc-gray-60
|
|
221
|
+
background: var(--sc-btn-color);
|
|
222
|
+
border: 1px solid var(--sc-btn-border);
|
|
223
|
+
color: var(--sc-gray-60);
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
/* SVG icon styling */
|
|
@@ -240,9 +240,9 @@ a:focus {
|
|
|
240
240
|
min-width: 2.4rem;
|
|
241
241
|
height: 2.4rem;
|
|
242
242
|
padding: 0.5rem;
|
|
243
|
-
background: var(--sc-btn-color
|
|
244
|
-
border: 1px solid var(--sc-btn-border
|
|
245
|
-
color: var(--sc-gray-60
|
|
243
|
+
background: var(--sc-btn-color);
|
|
244
|
+
border: 1px solid var(--sc-btn-border);
|
|
245
|
+
color: var(--sc-gray-60);
|
|
246
246
|
overflow: hidden;
|
|
247
247
|
/* Animation for smooth expand/collapse */
|
|
248
248
|
max-width: 2.4rem;
|
|
@@ -258,10 +258,10 @@ a:focus {
|
|
|
258
258
|
|
|
259
259
|
.searchtab input {
|
|
260
260
|
outline: none;
|
|
261
|
-
border: 1px solid var(--sc-input-border-color
|
|
261
|
+
border: 1px solid var(--sc-input-border-color);
|
|
262
262
|
border-radius: 0.25rem;
|
|
263
|
-
background-color: var(--sc-form-background
|
|
264
|
-
color: var(--sc-gray-80
|
|
263
|
+
background-color: var(--sc-form-background);
|
|
264
|
+
color: var(--sc-gray-80);
|
|
265
265
|
text-align: left;
|
|
266
266
|
font-size: 0.875rem;
|
|
267
267
|
padding: 0.25rem 0.5rem;
|
|
@@ -274,12 +274,12 @@ a:focus {
|
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
.searchtab input:focus {
|
|
277
|
-
border-color: var(--sc-input-active-border-color
|
|
277
|
+
border-color: var(--sc-input-active-border-color);
|
|
278
278
|
outline: none;
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
.searchtab input::placeholder {
|
|
282
|
-
color: var(--sc-input-label-color
|
|
282
|
+
color: var(--sc-input-label-color);
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
/* Search active state - expanded with animation */
|