@stonecrop/desktop 0.16.4 → 0.16.5

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.
@@ -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\">\nimport { useStonecrop, useValidationStore } from '@stonecrop/stonecrop'\nimport { AForm, type AFormLinkNavigator, type ResolvedField, type ResolvedTable } from '@stonecrop/aform'\nimport type { ColumnSchema } 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\nconst {\n\tavailableDoctypes = [],\n\trouteAdapter,\n\tconfirmFn,\n\trecordIdField,\n} = 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\t/**\n\t * Replacement for the native `confirm()` dialog. Desktop calls this before\n\t * performing a destructive action. Return `true` to proceed.\n\t * Defaults to the native `window.confirm` if omitted.\n\t */\n\tconfirmFn?: (message: string) => boolean | Promise<boolean>\n\t/**\n\t * The field name that holds the canonical record ID (e.g., 'rowId' for UUID).\n\t * Used for navigation and table row identification.\n\t * Defaults to 'id' if not specified.\n\t */\n\trecordIdField?: string\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 needs records for a list view.\n\t * The host app should fetch and populate HST.\n\t */\n\t'load-records': [payload: LoadRecordsEventPayload]\n\t/**\n\t * Fired when Desktop needs a single record for a form view.\n\t * The host app should fetch and populate HST.\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// 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 HST record fields for two-way binding.\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\trecord_count: getRecordCount(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\tconst idField = recordIdField || 'id'\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: record[idField] || record.id || '',\n\t\t\t\t\t\tactions: 'Edit | Delete',\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 record = stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)\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> = { ...record?.get('') }\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\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 in HST. Explicit null is allowed (intentional clear).\n\t\t\tconst hstStore = stonecrop.value.getStore()\n\t\t\tconst changedFields: string[] = []\n\t\t\tfor (const [fieldname, value] of Object.entries(flatData)) {\n\t\t\t\tif (value === undefined) continue\n\t\t\t\tconst fieldPath = `${currentDoctype.value}.${currentRecordId.value}.${fieldname}`\n\t\t\t\tconst currentValue = hstStore.has(fieldPath) ? hstStore.get(fieldPath) : undefined\n\t\t\t\tif (currentValue !== value) {\n\t\t\t\t\thstStore.set(fieldPath, value)\n\t\t\t\t\tchangedFields.push(fieldname)\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\tconst node = stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)\n\tconst record = { ...(node?.get('') as Record<string, unknown>) }\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(() => currentRecordId.value?.startsWith('new-'))\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// 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\nconst getRecordCount = (doctype: string): number => {\n\tif (!stonecrop.value) return 0\n\tconst recordIds = stonecrop.value.getRecordIds(doctype)\n\treturn recordIds.length\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\tconst newId = `new-${Date.now()}`\n\tawait doNavigate({ view: 'record', doctype: routeDoctype.value, recordId: newId })\n}\n\n// Flatten Fieldset containers into individual columns for list/table views.\n// A Fieldset groups form fields visually but has no DB column; its children are the\n// actual data fields and should appear as flat columns in a list view.\nconst flattenFieldsets = (fields: ResolvedField[]): ResolvedField[] => {\n\tconst result: ResolvedField[] = []\n\tfor (const field of fields) {\n\t\tif (field.kind === 'fieldset') {\n\t\t\tresult.push(...flattenFieldsets(field.schema))\n\t\t} else {\n\t\t\tresult.push(field)\n\t\t}\n\t}\n\treturn result\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{\n\t\t\t\t\tfieldname: 'record_count',\n\t\t\t\t\tlabel: 'Records',\n\t\t\t\t\tcomponent: 'ANumericInput',\n\t\t\t\t\talign: 'center' as const,\n\t\t\t\t\tedit: false,\n\t\t\t\t\twidth: '15ch',\n\t\t\t\t},\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\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\tschema: [\n\t\t\t\t...(flattenFieldsets(schema) as ColumnSchema[]),\n\t\t\t\t{ fieldname: 'actions', label: 'Actions', component: 'ATextInput' },\n\t\t\t],\n\t\t\tconfig: { view: 'list' as const, fullWidth: true },\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// Desktop does NOT own the delete lifecycle — it asks for confirmation, then emits\n// an 'action' event. The host app is responsible for removing the record from HST\n// and calling the server.\nconst handleDelete = async (recordId?: string) => {\n\tconst targetRecordId = recordId || currentRecordId.value\n\tif (!targetRecordId) return\n\n\tconst confirmed = confirmFn\n\t\t? await confirmFn('Are you sure you want to delete this record?')\n\t\t: confirm('Are you sure you want to delete this record?')\n\n\tif (confirmed) {\n\t\temit('action', {\n\t\t\tname: 'DELETE',\n\t\t\tdoctype: currentDoctype.value,\n\t\t\trecordId: targetRecordId,\n\t\t\tdata: currentViewData.value || {},\n\t\t})\n\t}\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\tconst idField = recordIdField || 'id'\n\treturn record[idField] || record.id || 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?.includes('Edit') && row) {\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} else if (cellText?.includes('Delete') && row) {\n\t\t\tconst recordId = getRecordIdFromRow(row)\n\t\t\tif (recordId) {\n\t\t\t\tawait handleDelete(recordId)\n\t\t\t}\n\t\t}\n\t}\n}\n\nconst loadRecordData = async () => {\n\tif (!stonecrop.value || !currentDoctype.value || isNewRecord.value) return\n\n\t// Record already in HST — nothing to fetch.\n\tif (stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)) return\n\n\t// Record absent and a client is configured — fetch directly so the form\n\t// populates even when the list view was never visited (direct URL navigation).\n\tif (stonecrop.value.getClient()) {\n\t\tloading.value = true\n\t\ttry {\n\t\t\tawait stonecrop.value.getRecord(currentDoctype.value, currentRecordId.value)\n\t\t} catch (error) {\n\t\t\tconsole.warn('Error fetching record:', error)\n\t\t} finally {\n\t\t\tloading.value = false\n\t\t}\n\t}\n}\n\n// Watch for route changes to load appropriate data\nwatch(\n\t[currentView, currentDoctype, currentRecordId],\n\t() => {\n\t\tif (currentView.value === 'records' && currentDoctype.value) {\n\t\t\t// Emit load-records event so host app can populate HST\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// Emit load-record event so host app can fetch and populate HST\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// 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\thandleDelete,\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\nfunction toDisplayString(rec: Record<string, unknown> | undefined): string | undefined {\n\tif (!rec) return undefined\n\tconst val = rec.name ?? rec.title ?? rec.displayText\n\treturn typeof val === 'string' || typeof val === 'number' ? String(val) : undefined\n}\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.\nprovide('aformLinkResolver', async (doctypeSlug: string, id: string): Promise<string | undefined> => {\n\tif (!stonecrop.value) return undefined\n\ttry {\n\t\tconst cached = stonecrop.value.getRecordById(doctypeSlug, id)?.get('') as Record<string, unknown> | undefined\n\t\tconst cachedDisplay = toDisplayString(cached)\n\t\tif (cachedDisplay != null) return cachedDisplay\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 toDisplayString(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","stonecrop","useStonecrop","validationStore","useValidationStore","fieldErrors","currentView","loading","commandPaletteOpen","currentViewData","doctype","formatDoctypeName","getRecordCount","idField","getRecords","record","currentDoctype","currentRecordId","flat","field","nested","child","newData","fieldsetNames","flatData","fieldsetValues","key","value","nestedValue","hstStore","changedFields","fieldname","fieldPath","driveFieldValidation","error","triggers","route","unref","router","pathMatch","routeDoctype","isNewRecord","routeName","getAvailableTransitions","currentState","transitions","recordData","name","getAvailableCommands","commands","actionElements","elements","createNewRecord","recordActions","navigationBreadcrumbs","breadcrumbs","recordPath","searchCommands","doNavigate","cmd","executeCommand","command","word","target","navigateToDoctype","openRecord","recordId","newId","flattenFieldsets","fields","getDoctypesSchema","getRecordsSchema","registry","schema","getRecordFormSchema","recordsData","currentViewSchema","handleActionClick","_label","handleDelete","targetRecordId","getRecordIdFromRow","rowElement","cell","rowIndexAttr","rowIndex","cellText","row","cells","loadRecordData","provide","data","id","toDisplayString","rec","val","doctypeSlug","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, #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\">\nimport { useStonecrop, useValidationStore } from '@stonecrop/stonecrop'\nimport { AForm, type AFormLinkNavigator, type ResolvedField, type ResolvedTable } from '@stonecrop/aform'\nimport type { ColumnSchema } 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\nconst {\n\tavailableDoctypes = [],\n\trouteAdapter,\n\tconfirmFn,\n\trecordIdField,\n} = 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\t/**\n\t * Replacement for the native `confirm()` dialog. Desktop calls this before\n\t * performing a destructive action. Return `true` to proceed.\n\t * Defaults to the native `window.confirm` if omitted.\n\t */\n\tconfirmFn?: (message: string) => boolean | Promise<boolean>\n\t/**\n\t * The field name that holds the canonical record ID (e.g., 'rowId' for UUID).\n\t * Used for navigation and table row identification.\n\t * Defaults to 'id' if not specified.\n\t */\n\trecordIdField?: string\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 needs records for a list view.\n\t * The host app should fetch and populate HST.\n\t */\n\t'load-records': [payload: LoadRecordsEventPayload]\n\t/**\n\t * Fired when Desktop needs a single record for a form view.\n\t * The host app should fetch and populate HST.\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// 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 HST record fields for two-way binding.\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\trecord_count: getRecordCount(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\tactions: 'Edit | Delete',\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 record = stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)\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> = { ...record?.get('') }\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\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 in HST. Explicit null is allowed (intentional clear).\n\t\t\tconst hstStore = stonecrop.value.getStore()\n\t\t\tconst changedFields: string[] = []\n\t\t\tfor (const [fieldname, value] of Object.entries(flatData)) {\n\t\t\t\tif (value === undefined) continue\n\t\t\t\tconst fieldPath = `${currentDoctype.value}.${currentRecordId.value}.${fieldname}`\n\t\t\t\tconst currentValue = hstStore.has(fieldPath) ? hstStore.get(fieldPath) : undefined\n\t\t\t\tif (currentValue !== value) {\n\t\t\t\t\thstStore.set(fieldPath, value)\n\t\t\t\t\tchangedFields.push(fieldname)\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\tconst node = stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)\n\tconst record = { ...(node?.get('') as Record<string, unknown>) }\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(() => currentRecordId.value?.startsWith('new-'))\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// 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\nconst getRecordCount = (doctype: string): number => {\n\tif (!stonecrop.value) return 0\n\tconst recordIds = stonecrop.value.getRecordIds(doctype)\n\treturn recordIds.length\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\tconst newId = `new-${Date.now()}`\n\tawait doNavigate({ view: 'record', doctype: routeDoctype.value, recordId: newId })\n}\n\n// Flatten Fieldset containers into individual columns for list/table views.\n// A Fieldset groups form fields visually but has no DB column; its children are the\n// actual data fields and should appear as flat columns in a list view.\nconst flattenFieldsets = (fields: ResolvedField[]): ResolvedField[] => {\n\tconst result: ResolvedField[] = []\n\tfor (const field of fields) {\n\t\tif (field.kind === 'fieldset') {\n\t\t\tresult.push(...flattenFieldsets(field.schema))\n\t\t} else {\n\t\t\tresult.push(field)\n\t\t}\n\t}\n\treturn result\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{\n\t\t\t\t\tfieldname: 'record_count',\n\t\t\t\t\tlabel: 'Records',\n\t\t\t\t\tcomponent: 'ANumericInput',\n\t\t\t\t\talign: 'center' as const,\n\t\t\t\t\tedit: false,\n\t\t\t\t\twidth: '15ch',\n\t\t\t\t},\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\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\tschema: [\n\t\t\t\t...(flattenFieldsets(schema) as ColumnSchema[]),\n\t\t\t\t{ fieldname: 'actions', label: 'Actions', component: 'ATextInput' },\n\t\t\t],\n\t\t\tconfig: { view: 'list' as const, fullWidth: true },\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// Desktop does NOT own the delete lifecycle — it asks for confirmation, then emits\n// an 'action' event. The host app is responsible for removing the record from HST\n// and calling the server.\nconst handleDelete = async (recordId?: string) => {\n\tconst targetRecordId = recordId || currentRecordId.value\n\tif (!targetRecordId) return\n\n\tconst confirmed = confirmFn\n\t\t? await confirmFn('Are you sure you want to delete this record?')\n\t\t: confirm('Are you sure you want to delete this record?')\n\n\tif (confirmed) {\n\t\temit('action', {\n\t\t\tname: 'DELETE',\n\t\t\tdoctype: currentDoctype.value,\n\t\t\trecordId: targetRecordId,\n\t\t\tdata: currentViewData.value || {},\n\t\t})\n\t}\n}\n\n/**\n * Resolve a record's identity for links and navigation.\n *\n * Precedence: the explicit `recordIdField` prop wins (a host that names a field has said which\n * column it means), then the doctype's declared `primaryKey`, then `id`. Before this, the default\n * was a bare `record.id`, which produced empty links for every natural-keyed doctype.\n *\n * Delegates to `Doctype.getRecordId` so this matches the key `Stonecrop.getRecords` stored the\n * record under — resolving it independently here would let a row render a link to an HST path\n * that does not exist.\n */\nconst resolveRecordId = (record: Record<string, unknown>): string | undefined => {\n\tif (recordIdField) {\n\t\tconst explicit = record[recordIdField]\n\t\tif (typeof explicit === 'number') return String(explicit)\n\t\tif (typeof explicit === 'string' && explicit !== '') return explicit\n\t}\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?.includes('Edit') && row) {\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} else if (cellText?.includes('Delete') && row) {\n\t\t\tconst recordId = getRecordIdFromRow(row)\n\t\t\tif (recordId) {\n\t\t\t\tawait handleDelete(recordId)\n\t\t\t}\n\t\t}\n\t}\n}\n\nconst loadRecordData = async () => {\n\tif (!stonecrop.value || !currentDoctype.value || isNewRecord.value) return\n\n\t// Record already in HST — nothing to fetch.\n\tif (stonecrop.value.getRecordById(currentDoctype.value, currentRecordId.value)) return\n\n\t// Record absent and a client is configured — fetch directly so the form\n\t// populates even when the list view was never visited (direct URL navigation).\n\tif (stonecrop.value.getClient()) {\n\t\tloading.value = true\n\t\ttry {\n\t\t\tawait stonecrop.value.getRecord(currentDoctype.value, currentRecordId.value)\n\t\t} catch (error) {\n\t\t\tconsole.warn('Error fetching record:', error)\n\t\t} finally {\n\t\t\tloading.value = false\n\t\t}\n\t}\n}\n\n// Watch for route changes to load appropriate data\nwatch(\n\t[currentView, currentDoctype, currentRecordId],\n\t() => {\n\t\tif (currentView.value === 'records' && currentDoctype.value) {\n\t\t\t// Emit load-records event so host app can populate HST\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// Emit load-record event so host app can fetch and populate HST\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// 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\thandleDelete,\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\nfunction toDisplayString(rec: Record<string, unknown> | undefined): string | undefined {\n\tif (!rec) return undefined\n\tconst val = rec.name ?? rec.title ?? rec.displayText\n\treturn typeof val === 'string' || typeof val === 'number' ? String(val) : undefined\n}\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.\nprovide('aformLinkResolver', async (doctypeSlug: string, id: string): Promise<string | undefined> => {\n\tif (!stonecrop.value) return undefined\n\ttry {\n\t\tconst cached = stonecrop.value.getRecordById(doctypeSlug, id)?.get('') as Record<string, unknown> | undefined\n\t\tconst cachedDisplay = toDisplayString(cached)\n\t\tif (cachedDisplay != null) return cachedDisplay\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 toDisplayString(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","stonecrop","useStonecrop","validationStore","useValidationStore","fieldErrors","currentView","loading","commandPaletteOpen","currentViewData","doctype","formatDoctypeName","getRecordCount","getRecords","record","resolveRecordId","currentDoctype","currentRecordId","flat","field","nested","child","newData","fieldsetNames","flatData","fieldsetValues","key","value","nestedValue","hstStore","changedFields","fieldname","fieldPath","driveFieldValidation","error","triggers","route","unref","router","pathMatch","routeDoctype","isNewRecord","routeName","getAvailableTransitions","currentState","transitions","recordData","name","getAvailableCommands","commands","actionElements","elements","createNewRecord","recordActions","navigationBreadcrumbs","breadcrumbs","recordPath","searchCommands","doNavigate","cmd","executeCommand","command","word","target","navigateToDoctype","openRecord","recordId","newId","flattenFieldsets","fields","getDoctypesSchema","getRecordsSchema","registry","schema","getRecordFormSchema","recordsData","currentViewSchema","handleActionClick","_label","handleDelete","targetRecordId","explicit","getRecordIdFromRow","rowElement","cell","rowIndexAttr","rowIndex","cellText","row","cells","loadRecordData","provide","data","id","toDisplayString","rec","val","doctypeSlug","cached","cachedDisplay","fetched","onUnmounted","ActionSet","_unref","AForm","SheetNav","CommandPalette","_withCtx","plugin","app","Desktop"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stonecrop/desktop",
3
- "version": "0.16.4",
3
+ "version": "0.16.5",
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/aform": "0.16.4",
37
- "@stonecrop/atable": "0.16.4",
38
- "@stonecrop/stonecrop": "0.16.4",
39
- "@stonecrop/themes": "0.16.4",
40
- "@stonecrop/schema": "0.16.4"
36
+ "@stonecrop/aform": "0.16.5",
37
+ "@stonecrop/atable": "0.16.5",
38
+ "@stonecrop/schema": "0.16.5",
39
+ "@stonecrop/stonecrop": "0.16.5",
40
+ "@stonecrop/themes": "0.16.5"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@microsoft/api-documenter": "^7.30.5",
@@ -152,11 +152,10 @@ const currentViewData = computed<Record<string, any>>({
152
152
 
153
153
  // Records list — rows come from HST store (reactive because HST is Vue reactive())
154
154
  if (currentView.value === 'records') {
155
- const idField = recordIdField || 'id'
156
155
  return {
157
156
  records_table: getRecords().map(record =>
158
157
  Object.assign({}, record, {
159
- id: record[idField] || record.id || '',
158
+ id: resolveRecordId(record) ?? '',
160
159
  actions: 'Edit | Delete',
161
160
  })
162
161
  ),
@@ -778,6 +777,27 @@ const handleDelete = async (recordId?: string) => {
778
777
  }
779
778
  }
780
779
 
780
+ /**
781
+ * Resolve a record's identity for links and navigation.
782
+ *
783
+ * Precedence: the explicit `recordIdField` prop wins (a host that names a field has said which
784
+ * column it means), then the doctype's declared `primaryKey`, then `id`. Before this, the default
785
+ * was a bare `record.id`, which produced empty links for every natural-keyed doctype.
786
+ *
787
+ * Delegates to `Doctype.getRecordId` so this matches the key `Stonecrop.getRecords` stored the
788
+ * record under — resolving it independently here would let a row render a link to an HST path
789
+ * that does not exist.
790
+ */
791
+ const resolveRecordId = (record: Record<string, unknown>): string | undefined => {
792
+ if (recordIdField) {
793
+ const explicit = record[recordIdField]
794
+ if (typeof explicit === 'number') return String(explicit)
795
+ if (typeof explicit === 'string' && explicit !== '') return explicit
796
+ }
797
+ if (!stonecrop.value || !currentDoctype.value) return undefined
798
+ return stonecrop.value.registry.registry[currentDoctype.value]?.getRecordId(record)
799
+ }
800
+
781
801
  // Event handlers
782
802
  const getRecordIdFromRow = (rowElement: HTMLTableRowElement): string | null => {
783
803
  const cell = rowElement.querySelector('td[data-rowindex]')
@@ -793,8 +813,7 @@ const getRecordIdFromRow = (rowElement: HTMLTableRowElement): string | null => {
793
813
  const record = records[rowIndex]
794
814
  if (!record) return null
795
815
 
796
- const idField = recordIdField || 'id'
797
- return record[idField] || record.id || null
816
+ return resolveRecordId(record) ?? null
798
817
  }
799
818
 
800
819
  const handleClick = async (event: Event) => {