[{"data":1,"prerenderedAt":4598},["ShallowReactive",2],{"navigation_docs":3,"-getting-started-introduction":188,"-getting-started-introduction-surround":4593},[4,9,27,52,101,130,163],{"title":5,"path":6,"stem":7,"icon":8},"Playground","\u002Fplayground","1.playground","i-lucide-flask-conical",{"title":10,"path":11,"stem":12,"children":13,"page":26},"Getting Started","\u002Fgetting-started","2.getting-started",[14,18,22],{"title":15,"path":16,"stem":17},"Introduction","\u002Fgetting-started\u002Fintroduction","2.getting-started\u002F1.introduction",{"title":19,"path":20,"stem":21},"Installation","\u002Fgetting-started\u002Finstallation","2.getting-started\u002F2.installation",{"title":23,"path":24,"stem":25},"First modal","\u002Fgetting-started\u002Ffirst-modal","2.getting-started\u002F3.first-modal",false,{"title":28,"path":29,"stem":30,"children":31,"page":26},"Concepts","\u002Fconcepts","3.concepts",[32,36,40,44,48],{"title":33,"path":34,"stem":35},"Architecture","\u002Fconcepts\u002Farchitecture","3.concepts\u002F1.architecture",{"title":37,"path":38,"stem":39},"Imperative flow","\u002Fconcepts\u002Fimperative-flow","3.concepts\u002F2.imperative-flow",{"title":41,"path":42,"stem":43},"Stacking","\u002Fconcepts\u002Fstacking","3.concepts\u002F3.stacking",{"title":45,"path":46,"stem":47},"Groups","\u002Fconcepts\u002Fgroups","3.concepts\u002F4.groups",{"title":49,"path":50,"stem":51},"Headless primitives","\u002Fconcepts\u002Fheadless-primitives","3.concepts\u002F5.headless-primitives",{"title":53,"path":54,"stem":55,"children":56,"page":26},"Guide","\u002Fguide","4.guide",[57,61,65,69,73,77,81,85,89,93,97],{"title":58,"path":59,"stem":60},"Writing a modal","\u002Fguide\u002Fwriting-a-modal","4.guide\u002F01.writing-a-modal",{"title":62,"path":63,"stem":64},"Opening & closing","\u002Fguide\u002Fopening-and-closing","4.guide\u002F02.opening-and-closing",{"title":66,"path":67,"stem":68},"Props & results","\u002Fguide\u002Fpassing-props-and-results","4.guide\u002F03.passing-props-and-results",{"title":70,"path":71,"stem":72},"Behavior options","\u002Fguide\u002Fbehavior-options","4.guide\u002F04.behavior-options",{"title":74,"path":75,"stem":76},"Animations & styling","\u002Fguide\u002Fstyling-and-animations","4.guide\u002F05.styling-and-animations",{"title":78,"path":79,"stem":80},"useModal composable","\u002Fguide\u002Fusemodal-composable","4.guide\u002F06.usemodal-composable",{"title":82,"path":83,"stem":84},"Modal context","\u002Fguide\u002Fmodal-context","4.guide\u002F07.modal-context",{"title":86,"path":87,"stem":88},"Multiple targets","\u002Fguide\u002Fmultiple-targets","4.guide\u002F08.multiple-targets",{"title":90,"path":91,"stem":92},"Overlay","\u002Fguide\u002Foverlay","4.guide\u002F09.overlay",{"title":94,"path":95,"stem":96},"Async components","\u002Fguide\u002Fasync-components","4.guide\u002F10.async-components",{"title":98,"path":99,"stem":100},"TypeScript","\u002Fguide\u002Ftypescript","4.guide\u002F11.typescript",{"title":102,"path":103,"stem":104,"children":105,"page":26},"Recipes","\u002Frecipes","5.recipes",[106,110,114,118,122,126],{"title":107,"path":108,"stem":109},"Confirm dialog","\u002Frecipes\u002Fconfirm-dialog","5.recipes\u002F1.confirm-dialog",{"title":111,"path":112,"stem":113},"Form modal with validation","\u002Frecipes\u002Fform-modal-with-validation","5.recipes\u002F2.form-modal-with-validation",{"title":115,"path":116,"stem":117},"Image lightbox","\u002Frecipes\u002Fimage-lightbox","5.recipes\u002F3.image-lightbox",{"title":119,"path":120,"stem":121},"Command palette","\u002Frecipes\u002Fcommand-palette","5.recipes\u002F4.command-palette",{"title":123,"path":124,"stem":125},"Nested flows \u002F wizards","\u002Frecipes\u002Fnested-flows","5.recipes\u002F5.nested-flows",{"title":127,"path":128,"stem":129},"Global error modal","\u002Frecipes\u002Fglobal-error-modal","5.recipes\u002F6.global-error-modal",{"title":131,"path":132,"stem":133,"children":134,"page":26},"Api","\u002Fapi","6.api",[135,139,143,147,151,155,159],{"title":136,"path":137,"stem":138},"Functions","\u002Fapi\u002Ffunctions","6.api\u002F1.functions",{"title":140,"path":141,"stem":142},"Components","\u002Fapi\u002Fcomponents","6.api\u002F2.components",{"title":144,"path":145,"stem":146},"Composables","\u002Fapi\u002Fcomposables","6.api\u002F3.composables",{"title":148,"path":149,"stem":150},"Plugin","\u002Fapi\u002Fplugin","6.api\u002F4.plugin",{"title":152,"path":153,"stem":154},"State helpers","\u002Fapi\u002Fstate","6.api\u002F5.state",{"title":156,"path":157,"stem":158},"Global events","\u002Fapi\u002Fevents","6.api\u002F6.events",{"title":160,"path":161,"stem":162},"Types","\u002Fapi\u002Ftypes","6.api\u002F7.types",{"title":164,"path":165,"stem":166,"children":167,"page":26},"Resources","\u002Fresources","7.resources",[168,172,176,180,184],{"title":169,"path":170,"stem":171},"Migration from v1","\u002Fresources\u002Fmigration-from-v1","7.resources\u002F1.migration-from-v1",{"title":173,"path":174,"stem":175},"FAQ","\u002Fresources\u002Ffaq","7.resources\u002F2.faq",{"title":177,"path":178,"stem":179},"Troubleshooting","\u002Fresources\u002Ftroubleshooting","7.resources\u002F3.troubleshooting",{"title":181,"path":182,"stem":183},"Comparison","\u002Fresources\u002Fcomparison","7.resources\u002F4.comparison",{"title":185,"path":186,"stem":187},"Changelog","\u002Fresources\u002Fchangelog","7.resources\u002F5.changelog",{"id":189,"title":15,"body":190,"description":4587,"extension":4588,"links":4589,"meta":4590,"navigation":347,"path":16,"seo":4591,"stem":17,"__hash__":4592},"docs\u002F2.getting-started\u002F1.introduction.md",{"type":191,"value":192,"toc":4578},"minimark",[193,197,205,210,250,254,259,266,1613,1630,1634,1642,2681,2684,2688,2695,3664,3679,3683,3698,4572,4575],[194,195,15],"h1",{"id":196},"introduction",[198,199,200,204],"p",{},[201,202,203],"code",{},"@kolirt\u002Fvue-modal"," is a lightweight, headless modal package for Vue 3. It lets you open, stack, and control dialogs imperatively from any function — without registering modal components in templates or wiring open\u002Fclose state by hand.",[206,207,209],"h2",{"id":208},"what-you-get","What you get",[211,212,213,221,227,233,239,245],"ul",{},[214,215,216,220],"li",{},[217,218,219],"strong",{},"Open from JS\u002FTS"," — trigger modals from any function and await the user's response. A single call returns a typed promise with full TypeScript inference for props and result.",[214,222,223,226],{},[217,224,225],{},"Less template boilerplate"," — skip placing every modal in your templates and wiring open\u002Fclose state by hand. Register one mount point and trigger any modal from code with a single call.",[214,228,229,232],{},[217,230,231],{},"Cascading modals"," — open multiple modals one after another while preserving their state and context. Layer a confirmation on top of a form without losing the form's data.",[214,234,235,238],{},[217,236,237],{},"Highly customizable"," — headless primitives with no imposed styles. Bring your own CSS, transitions, and animations — compose modals that fit any design system.",[214,240,241,244],{},[217,242,243],{},"Modal groups"," — isolate flows with named groups — the main app stack, confirm dialogs, side panels — each rendering in its own mount point with its own queue.",[214,246,247,249],{},[217,248,94],{}," — open any Vue component, including async ones loaded on demand. Heavy modals stay out of your initial bundle and resolve through the same promise.",[206,251,253],{"id":252},"the-problems-it-solves","The problems it solves",[255,256,258],"h3",{"id":257},"_1-template-clutter-and-scattered-state","1. Template clutter and scattered state",[198,260,261,262,265],{},"Every modal needs a place in the template, a boolean ref for ",[201,263,264],{},"v-if",", and handlers for open\u002Fclose. Five modals on one page means five copies of this dance.",[267,268,269,1134],"code-group",{},[270,271,277],"pre",{"className":272,"code":273,"filename":274,"language":275,"meta":276,"style":276},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup lang=\"ts\">\nimport { ref } from 'vue'\n\nconst isConfirmOpen = ref(false)\nconst isEditOpen = ref(false)\nconst isPreviewOpen = ref(false)\nconst editingId = ref\u003Cnumber | null>(null)\nconst previewUrl = ref\u003Cstring | null>(null)\n\nfunction deleteAccount() {\n  isConfirmOpen.value = true\n}\nfunction onConfirmYes() {\n  isConfirmOpen.value = false\n  api.deleteAccount()\n}\nfunction onConfirmNo() {\n  isConfirmOpen.value = false\n}\n\nfunction edit(id: number) {\n  editingId.value = id\n  isEditOpen.value = true\n}\nfunction onEditSaved() {\n  isEditOpen.value = false\n  editingId.value = null\n}\n\nfunction preview(url: string) {\n  previewUrl.value = url\n  isPreviewOpen.value = true\n}\nfunction onPreviewClose() {\n  isPreviewOpen.value = false\n  previewUrl.value = null\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cbutton @click=\"deleteAccount\">Delete\u003C\u002Fbutton>\n  \u003Cbutton @click=\"edit(42)\">Edit\u003C\u002Fbutton>\n  \u003Cbutton @click=\"preview('\u002Fimg.png')\">Preview\u003C\u002Fbutton>\n\n  \u003CConfirmDialog\n    v-if=\"isConfirmOpen\"\n    title=\"Delete account?\"\n    @confirm=\"onConfirmYes\"\n    @cancel=\"onConfirmNo\"\n  \u002F>\n  \u003CEditDialog\n    v-if=\"isEditOpen && editingId\"\n    :id=\"editingId\"\n    @saved=\"onEditSaved\"\n    @close=\"isEditOpen = false\"\n  \u002F>\n  \u003CPreviewDialog\n    v-if=\"isPreviewOpen && previewUrl\"\n    :url=\"previewUrl\"\n    @close=\"onPreviewClose\"\n  \u002F>\n\u003C\u002Ftemplate>\n","❌ Without the package","vue","",[201,278,279,314,342,349,373,391,409,443,472,477,492,510,516,528,542,556,561,573,586,591,596,621,636,650,655,667,680,694,699,704,726,741,755,760,772,785,798,803,813,818,828,859,888,917,922,930,946,961,976,991,997,1005,1019,1034,1049,1064,1069,1077,1091,1106,1120,1125],{"__ignoreMap":276},[280,281,284,288,292,296,299,302,305,309,311],"span",{"class":282,"line":283},"line",1,[280,285,287],{"class":286},"sMK4o","\u003C",[280,289,291],{"class":290},"swJcz","script",[280,293,295],{"class":294},"spNyl"," setup",[280,297,298],{"class":294}," lang",[280,300,301],{"class":286},"=",[280,303,304],{"class":286},"\"",[280,306,308],{"class":307},"sfazB","ts",[280,310,304],{"class":286},[280,312,313],{"class":286},">\n",[280,315,317,321,324,328,331,334,337,339],{"class":282,"line":316},2,[280,318,320],{"class":319},"s7zQu","import",[280,322,323],{"class":286}," {",[280,325,327],{"class":326},"sTEyZ"," ref",[280,329,330],{"class":286}," }",[280,332,333],{"class":319}," from",[280,335,336],{"class":286}," '",[280,338,275],{"class":307},[280,340,341],{"class":286},"'\n",[280,343,345],{"class":282,"line":344},3,[280,346,348],{"emptyLinePlaceholder":347},true,"\n",[280,350,352,355,358,360,363,366,370],{"class":282,"line":351},4,[280,353,354],{"class":294},"const",[280,356,357],{"class":326}," isConfirmOpen ",[280,359,301],{"class":286},[280,361,327],{"class":362},"s2Zo4",[280,364,365],{"class":326},"(",[280,367,369],{"class":368},"sfNiH","false",[280,371,372],{"class":326},")\n",[280,374,376,378,381,383,385,387,389],{"class":282,"line":375},5,[280,377,354],{"class":294},[280,379,380],{"class":326}," isEditOpen ",[280,382,301],{"class":286},[280,384,327],{"class":362},[280,386,365],{"class":326},[280,388,369],{"class":368},[280,390,372],{"class":326},[280,392,394,396,399,401,403,405,407],{"class":282,"line":393},6,[280,395,354],{"class":294},[280,397,398],{"class":326}," isPreviewOpen ",[280,400,301],{"class":286},[280,402,327],{"class":362},[280,404,365],{"class":326},[280,406,369],{"class":368},[280,408,372],{"class":326},[280,410,412,414,417,419,421,423,427,430,433,436,438,441],{"class":282,"line":411},7,[280,413,354],{"class":294},[280,415,416],{"class":326}," editingId ",[280,418,301],{"class":286},[280,420,327],{"class":362},[280,422,287],{"class":286},[280,424,426],{"class":425},"sBMFI","number",[280,428,429],{"class":286}," |",[280,431,432],{"class":425}," null",[280,434,435],{"class":286},">",[280,437,365],{"class":326},[280,439,440],{"class":286},"null",[280,442,372],{"class":326},[280,444,446,448,451,453,455,457,460,462,464,466,468,470],{"class":282,"line":445},8,[280,447,354],{"class":294},[280,449,450],{"class":326}," previewUrl ",[280,452,301],{"class":286},[280,454,327],{"class":362},[280,456,287],{"class":286},[280,458,459],{"class":425},"string",[280,461,429],{"class":286},[280,463,432],{"class":425},[280,465,435],{"class":286},[280,467,365],{"class":326},[280,469,440],{"class":286},[280,471,372],{"class":326},[280,473,475],{"class":282,"line":474},9,[280,476,348],{"emptyLinePlaceholder":347},[280,478,480,483,486,489],{"class":282,"line":479},10,[280,481,482],{"class":294},"function",[280,484,485],{"class":362}," deleteAccount",[280,487,488],{"class":286},"()",[280,490,491],{"class":286}," {\n",[280,493,495,498,501,504,507],{"class":282,"line":494},11,[280,496,497],{"class":326},"  isConfirmOpen",[280,499,500],{"class":286},".",[280,502,503],{"class":326},"value",[280,505,506],{"class":286}," =",[280,508,509],{"class":368}," true\n",[280,511,513],{"class":282,"line":512},12,[280,514,515],{"class":286},"}\n",[280,517,519,521,524,526],{"class":282,"line":518},13,[280,520,482],{"class":294},[280,522,523],{"class":362}," onConfirmYes",[280,525,488],{"class":286},[280,527,491],{"class":286},[280,529,531,533,535,537,539],{"class":282,"line":530},14,[280,532,497],{"class":326},[280,534,500],{"class":286},[280,536,503],{"class":326},[280,538,506],{"class":286},[280,540,541],{"class":368}," false\n",[280,543,545,548,550,553],{"class":282,"line":544},15,[280,546,547],{"class":326},"  api",[280,549,500],{"class":286},[280,551,552],{"class":362},"deleteAccount",[280,554,555],{"class":290},"()\n",[280,557,559],{"class":282,"line":558},16,[280,560,515],{"class":286},[280,562,564,566,569,571],{"class":282,"line":563},17,[280,565,482],{"class":294},[280,567,568],{"class":362}," onConfirmNo",[280,570,488],{"class":286},[280,572,491],{"class":286},[280,574,576,578,580,582,584],{"class":282,"line":575},18,[280,577,497],{"class":326},[280,579,500],{"class":286},[280,581,503],{"class":326},[280,583,506],{"class":286},[280,585,541],{"class":368},[280,587,589],{"class":282,"line":588},19,[280,590,515],{"class":286},[280,592,594],{"class":282,"line":593},20,[280,595,348],{"emptyLinePlaceholder":347},[280,597,599,601,604,606,610,613,616,619],{"class":282,"line":598},21,[280,600,482],{"class":294},[280,602,603],{"class":362}," edit",[280,605,365],{"class":286},[280,607,609],{"class":608},"sHdIc","id",[280,611,612],{"class":286},":",[280,614,615],{"class":425}," number",[280,617,618],{"class":286},")",[280,620,491],{"class":286},[280,622,624,627,629,631,633],{"class":282,"line":623},22,[280,625,626],{"class":326},"  editingId",[280,628,500],{"class":286},[280,630,503],{"class":326},[280,632,506],{"class":286},[280,634,635],{"class":326}," id\n",[280,637,639,642,644,646,648],{"class":282,"line":638},23,[280,640,641],{"class":326},"  isEditOpen",[280,643,500],{"class":286},[280,645,503],{"class":326},[280,647,506],{"class":286},[280,649,509],{"class":368},[280,651,653],{"class":282,"line":652},24,[280,654,515],{"class":286},[280,656,658,660,663,665],{"class":282,"line":657},25,[280,659,482],{"class":294},[280,661,662],{"class":362}," onEditSaved",[280,664,488],{"class":286},[280,666,491],{"class":286},[280,668,670,672,674,676,678],{"class":282,"line":669},26,[280,671,641],{"class":326},[280,673,500],{"class":286},[280,675,503],{"class":326},[280,677,506],{"class":286},[280,679,541],{"class":368},[280,681,683,685,687,689,691],{"class":282,"line":682},27,[280,684,626],{"class":326},[280,686,500],{"class":286},[280,688,503],{"class":326},[280,690,506],{"class":286},[280,692,693],{"class":286}," null\n",[280,695,697],{"class":282,"line":696},28,[280,698,515],{"class":286},[280,700,702],{"class":282,"line":701},29,[280,703,348],{"emptyLinePlaceholder":347},[280,705,707,709,712,714,717,719,722,724],{"class":282,"line":706},30,[280,708,482],{"class":294},[280,710,711],{"class":362}," preview",[280,713,365],{"class":286},[280,715,716],{"class":608},"url",[280,718,612],{"class":286},[280,720,721],{"class":425}," string",[280,723,618],{"class":286},[280,725,491],{"class":286},[280,727,729,732,734,736,738],{"class":282,"line":728},31,[280,730,731],{"class":326},"  previewUrl",[280,733,500],{"class":286},[280,735,503],{"class":326},[280,737,506],{"class":286},[280,739,740],{"class":326}," url\n",[280,742,744,747,749,751,753],{"class":282,"line":743},32,[280,745,746],{"class":326},"  isPreviewOpen",[280,748,500],{"class":286},[280,750,503],{"class":326},[280,752,506],{"class":286},[280,754,509],{"class":368},[280,756,758],{"class":282,"line":757},33,[280,759,515],{"class":286},[280,761,763,765,768,770],{"class":282,"line":762},34,[280,764,482],{"class":294},[280,766,767],{"class":362}," onPreviewClose",[280,769,488],{"class":286},[280,771,491],{"class":286},[280,773,775,777,779,781,783],{"class":282,"line":774},35,[280,776,746],{"class":326},[280,778,500],{"class":286},[280,780,503],{"class":326},[280,782,506],{"class":286},[280,784,541],{"class":368},[280,786,788,790,792,794,796],{"class":282,"line":787},36,[280,789,731],{"class":326},[280,791,500],{"class":286},[280,793,503],{"class":326},[280,795,506],{"class":286},[280,797,693],{"class":286},[280,799,801],{"class":282,"line":800},37,[280,802,515],{"class":286},[280,804,806,809,811],{"class":282,"line":805},38,[280,807,808],{"class":286},"\u003C\u002F",[280,810,291],{"class":290},[280,812,313],{"class":286},[280,814,816],{"class":282,"line":815},39,[280,817,348],{"emptyLinePlaceholder":347},[280,819,821,823,826],{"class":282,"line":820},40,[280,822,287],{"class":286},[280,824,825],{"class":290},"template",[280,827,313],{"class":286},[280,829,831,834,837,840,842,844,846,848,850,853,855,857],{"class":282,"line":830},41,[280,832,833],{"class":286},"  \u003C",[280,835,836],{"class":290},"button",[280,838,839],{"class":294}," @click",[280,841,301],{"class":286},[280,843,304],{"class":286},[280,845,552],{"class":307},[280,847,304],{"class":286},[280,849,435],{"class":286},[280,851,852],{"class":326},"Delete",[280,854,808],{"class":286},[280,856,836],{"class":290},[280,858,313],{"class":286},[280,860,862,864,866,868,870,872,875,877,879,882,884,886],{"class":282,"line":861},42,[280,863,833],{"class":286},[280,865,836],{"class":290},[280,867,839],{"class":294},[280,869,301],{"class":286},[280,871,304],{"class":286},[280,873,874],{"class":307},"edit(42)",[280,876,304],{"class":286},[280,878,435],{"class":286},[280,880,881],{"class":326},"Edit",[280,883,808],{"class":286},[280,885,836],{"class":290},[280,887,313],{"class":286},[280,889,891,893,895,897,899,901,904,906,908,911,913,915],{"class":282,"line":890},43,[280,892,833],{"class":286},[280,894,836],{"class":290},[280,896,839],{"class":294},[280,898,301],{"class":286},[280,900,304],{"class":286},[280,902,903],{"class":307},"preview('\u002Fimg.png')",[280,905,304],{"class":286},[280,907,435],{"class":286},[280,909,910],{"class":326},"Preview",[280,912,808],{"class":286},[280,914,836],{"class":290},[280,916,313],{"class":286},[280,918,920],{"class":282,"line":919},44,[280,921,348],{"emptyLinePlaceholder":347},[280,923,925,927],{"class":282,"line":924},45,[280,926,833],{"class":286},[280,928,929],{"class":290},"ConfirmDialog\n",[280,931,933,936,938,940,943],{"class":282,"line":932},46,[280,934,935],{"class":294},"    v-if",[280,937,301],{"class":286},[280,939,304],{"class":286},[280,941,942],{"class":307},"isConfirmOpen",[280,944,945],{"class":286},"\"\n",[280,947,949,952,954,956,959],{"class":282,"line":948},47,[280,950,951],{"class":294},"    title",[280,953,301],{"class":286},[280,955,304],{"class":286},[280,957,958],{"class":307},"Delete account?",[280,960,945],{"class":286},[280,962,964,967,969,971,974],{"class":282,"line":963},48,[280,965,966],{"class":294},"    @confirm",[280,968,301],{"class":286},[280,970,304],{"class":286},[280,972,973],{"class":307},"onConfirmYes",[280,975,945],{"class":286},[280,977,979,982,984,986,989],{"class":282,"line":978},49,[280,980,981],{"class":294},"    @cancel",[280,983,301],{"class":286},[280,985,304],{"class":286},[280,987,988],{"class":307},"onConfirmNo",[280,990,945],{"class":286},[280,992,994],{"class":282,"line":993},50,[280,995,996],{"class":286},"  \u002F>\n",[280,998,1000,1002],{"class":282,"line":999},51,[280,1001,833],{"class":286},[280,1003,1004],{"class":290},"EditDialog\n",[280,1006,1008,1010,1012,1014,1017],{"class":282,"line":1007},52,[280,1009,935],{"class":294},[280,1011,301],{"class":286},[280,1013,304],{"class":286},[280,1015,1016],{"class":307},"isEditOpen && editingId",[280,1018,945],{"class":286},[280,1020,1022,1025,1027,1029,1032],{"class":282,"line":1021},53,[280,1023,1024],{"class":294},"    :id",[280,1026,301],{"class":286},[280,1028,304],{"class":286},[280,1030,1031],{"class":307},"editingId",[280,1033,945],{"class":286},[280,1035,1037,1040,1042,1044,1047],{"class":282,"line":1036},54,[280,1038,1039],{"class":294},"    @saved",[280,1041,301],{"class":286},[280,1043,304],{"class":286},[280,1045,1046],{"class":307},"onEditSaved",[280,1048,945],{"class":286},[280,1050,1052,1055,1057,1059,1062],{"class":282,"line":1051},55,[280,1053,1054],{"class":294},"    @close",[280,1056,301],{"class":286},[280,1058,304],{"class":286},[280,1060,1061],{"class":307},"isEditOpen = false",[280,1063,945],{"class":286},[280,1065,1067],{"class":282,"line":1066},56,[280,1068,996],{"class":286},[280,1070,1072,1074],{"class":282,"line":1071},57,[280,1073,833],{"class":286},[280,1075,1076],{"class":290},"PreviewDialog\n",[280,1078,1080,1082,1084,1086,1089],{"class":282,"line":1079},58,[280,1081,935],{"class":294},[280,1083,301],{"class":286},[280,1085,304],{"class":286},[280,1087,1088],{"class":307},"isPreviewOpen && previewUrl",[280,1090,945],{"class":286},[280,1092,1094,1097,1099,1101,1104],{"class":282,"line":1093},59,[280,1095,1096],{"class":294},"    :url",[280,1098,301],{"class":286},[280,1100,304],{"class":286},[280,1102,1103],{"class":307},"previewUrl",[280,1105,945],{"class":286},[280,1107,1109,1111,1113,1115,1118],{"class":282,"line":1108},60,[280,1110,1054],{"class":294},[280,1112,301],{"class":286},[280,1114,304],{"class":286},[280,1116,1117],{"class":307},"onPreviewClose",[280,1119,945],{"class":286},[280,1121,1123],{"class":282,"line":1122},61,[280,1124,996],{"class":286},[280,1126,1128,1130,1132],{"class":282,"line":1127},62,[280,1129,808],{"class":286},[280,1131,825],{"class":290},[280,1133,313],{"class":286},[270,1135,1138],{"className":272,"code":1136,"filename":1137,"language":275,"meta":276,"style":276},"\u003Cscript setup lang=\"ts\">\nimport { openModal } from '@kolirt\u002Fvue-modal'\nimport ConfirmDialog from '.\u002FConfirmDialog.vue'\nimport EditDialog from '.\u002FEditDialog.vue'\nimport PreviewDialog from '.\u002FPreviewDialog.vue'\n\nasync function deleteAccount() {\n  const ok = await openModal\u003Cboolean>(ConfirmDialog, {\n    props: { title: 'Delete account?' }\n  }).catch(() => false)\n  if (ok) await api.deleteAccount()\n}\n\nasync function edit(id: number) {\n  await openModal(EditDialog, {\n    props: { id }\n  }).catch(() => {})\n}\n\nfunction preview(url: string) {\n  openModal(PreviewDialog, {\n    props: { url }\n  }).catch(() => {})\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cbutton @click=\"deleteAccount\">Delete\u003C\u002Fbutton>\n  \u003Cbutton @click=\"edit(42)\">Edit\u003C\u002Fbutton>\n  \u003Cbutton @click=\"preview('\u002Fimg.png')\">Preview\u003C\u002Fbutton>\n\u003C\u002Ftemplate>\n","✅ With the package",[201,1139,1140,1160,1179,1196,1212,1228,1232,1246,1278,1302,1326,1352,1356,1360,1380,1396,1409,1430,1434,1438,1456,1470,1483,1503,1507,1515,1519,1527,1553,1579,1605],{"__ignoreMap":276},[280,1141,1142,1144,1146,1148,1150,1152,1154,1156,1158],{"class":282,"line":283},[280,1143,287],{"class":286},[280,1145,291],{"class":290},[280,1147,295],{"class":294},[280,1149,298],{"class":294},[280,1151,301],{"class":286},[280,1153,304],{"class":286},[280,1155,308],{"class":307},[280,1157,304],{"class":286},[280,1159,313],{"class":286},[280,1161,1162,1164,1166,1169,1171,1173,1175,1177],{"class":282,"line":316},[280,1163,320],{"class":319},[280,1165,323],{"class":286},[280,1167,1168],{"class":326}," openModal",[280,1170,330],{"class":286},[280,1172,333],{"class":319},[280,1174,336],{"class":286},[280,1176,203],{"class":307},[280,1178,341],{"class":286},[280,1180,1181,1183,1186,1189,1191,1194],{"class":282,"line":344},[280,1182,320],{"class":319},[280,1184,1185],{"class":326}," ConfirmDialog ",[280,1187,1188],{"class":319},"from",[280,1190,336],{"class":286},[280,1192,1193],{"class":307},".\u002FConfirmDialog.vue",[280,1195,341],{"class":286},[280,1197,1198,1200,1203,1205,1207,1210],{"class":282,"line":351},[280,1199,320],{"class":319},[280,1201,1202],{"class":326}," EditDialog ",[280,1204,1188],{"class":319},[280,1206,336],{"class":286},[280,1208,1209],{"class":307},".\u002FEditDialog.vue",[280,1211,341],{"class":286},[280,1213,1214,1216,1219,1221,1223,1226],{"class":282,"line":375},[280,1215,320],{"class":319},[280,1217,1218],{"class":326}," PreviewDialog ",[280,1220,1188],{"class":319},[280,1222,336],{"class":286},[280,1224,1225],{"class":307},".\u002FPreviewDialog.vue",[280,1227,341],{"class":286},[280,1229,1230],{"class":282,"line":393},[280,1231,348],{"emptyLinePlaceholder":347},[280,1233,1234,1237,1240,1242,1244],{"class":282,"line":411},[280,1235,1236],{"class":294},"async",[280,1238,1239],{"class":294}," function",[280,1241,485],{"class":362},[280,1243,488],{"class":286},[280,1245,491],{"class":286},[280,1247,1248,1251,1254,1256,1259,1261,1263,1266,1268,1270,1273,1276],{"class":282,"line":445},[280,1249,1250],{"class":294},"  const",[280,1252,1253],{"class":326}," ok",[280,1255,506],{"class":286},[280,1257,1258],{"class":319}," await",[280,1260,1168],{"class":362},[280,1262,287],{"class":286},[280,1264,1265],{"class":425},"boolean",[280,1267,435],{"class":286},[280,1269,365],{"class":290},[280,1271,1272],{"class":326},"ConfirmDialog",[280,1274,1275],{"class":286},",",[280,1277,491],{"class":286},[280,1279,1280,1283,1285,1287,1290,1292,1294,1296,1299],{"class":282,"line":474},[280,1281,1282],{"class":290},"    props",[280,1284,612],{"class":286},[280,1286,323],{"class":286},[280,1288,1289],{"class":290}," title",[280,1291,612],{"class":286},[280,1293,336],{"class":286},[280,1295,958],{"class":307},[280,1297,1298],{"class":286},"'",[280,1300,1301],{"class":286}," }\n",[280,1303,1304,1307,1309,1311,1314,1316,1318,1321,1324],{"class":282,"line":479},[280,1305,1306],{"class":286},"  }",[280,1308,618],{"class":290},[280,1310,500],{"class":286},[280,1312,1313],{"class":362},"catch",[280,1315,365],{"class":290},[280,1317,488],{"class":286},[280,1319,1320],{"class":294}," =>",[280,1322,1323],{"class":368}," false",[280,1325,372],{"class":290},[280,1327,1328,1331,1334,1337,1340,1343,1346,1348,1350],{"class":282,"line":494},[280,1329,1330],{"class":319},"  if",[280,1332,1333],{"class":290}," (",[280,1335,1336],{"class":326},"ok",[280,1338,1339],{"class":290},") ",[280,1341,1342],{"class":319},"await",[280,1344,1345],{"class":326}," api",[280,1347,500],{"class":286},[280,1349,552],{"class":362},[280,1351,555],{"class":290},[280,1353,1354],{"class":282,"line":512},[280,1355,515],{"class":286},[280,1357,1358],{"class":282,"line":518},[280,1359,348],{"emptyLinePlaceholder":347},[280,1361,1362,1364,1366,1368,1370,1372,1374,1376,1378],{"class":282,"line":530},[280,1363,1236],{"class":294},[280,1365,1239],{"class":294},[280,1367,603],{"class":362},[280,1369,365],{"class":286},[280,1371,609],{"class":608},[280,1373,612],{"class":286},[280,1375,615],{"class":425},[280,1377,618],{"class":286},[280,1379,491],{"class":286},[280,1381,1382,1385,1387,1389,1392,1394],{"class":282,"line":544},[280,1383,1384],{"class":319},"  await",[280,1386,1168],{"class":362},[280,1388,365],{"class":290},[280,1390,1391],{"class":326},"EditDialog",[280,1393,1275],{"class":286},[280,1395,491],{"class":286},[280,1397,1398,1400,1402,1404,1407],{"class":282,"line":558},[280,1399,1282],{"class":290},[280,1401,612],{"class":286},[280,1403,323],{"class":286},[280,1405,1406],{"class":326}," id",[280,1408,1301],{"class":286},[280,1410,1411,1413,1415,1417,1419,1421,1423,1425,1428],{"class":282,"line":563},[280,1412,1306],{"class":286},[280,1414,618],{"class":290},[280,1416,500],{"class":286},[280,1418,1313],{"class":362},[280,1420,365],{"class":290},[280,1422,488],{"class":286},[280,1424,1320],{"class":294},[280,1426,1427],{"class":286}," {}",[280,1429,372],{"class":290},[280,1431,1432],{"class":282,"line":575},[280,1433,515],{"class":286},[280,1435,1436],{"class":282,"line":588},[280,1437,348],{"emptyLinePlaceholder":347},[280,1439,1440,1442,1444,1446,1448,1450,1452,1454],{"class":282,"line":593},[280,1441,482],{"class":294},[280,1443,711],{"class":362},[280,1445,365],{"class":286},[280,1447,716],{"class":608},[280,1449,612],{"class":286},[280,1451,721],{"class":425},[280,1453,618],{"class":286},[280,1455,491],{"class":286},[280,1457,1458,1461,1463,1466,1468],{"class":282,"line":598},[280,1459,1460],{"class":362},"  openModal",[280,1462,365],{"class":290},[280,1464,1465],{"class":326},"PreviewDialog",[280,1467,1275],{"class":286},[280,1469,491],{"class":286},[280,1471,1472,1474,1476,1478,1481],{"class":282,"line":623},[280,1473,1282],{"class":290},[280,1475,612],{"class":286},[280,1477,323],{"class":286},[280,1479,1480],{"class":326}," url",[280,1482,1301],{"class":286},[280,1484,1485,1487,1489,1491,1493,1495,1497,1499,1501],{"class":282,"line":638},[280,1486,1306],{"class":286},[280,1488,618],{"class":290},[280,1490,500],{"class":286},[280,1492,1313],{"class":362},[280,1494,365],{"class":290},[280,1496,488],{"class":286},[280,1498,1320],{"class":294},[280,1500,1427],{"class":286},[280,1502,372],{"class":290},[280,1504,1505],{"class":282,"line":652},[280,1506,515],{"class":286},[280,1508,1509,1511,1513],{"class":282,"line":657},[280,1510,808],{"class":286},[280,1512,291],{"class":290},[280,1514,313],{"class":286},[280,1516,1517],{"class":282,"line":669},[280,1518,348],{"emptyLinePlaceholder":347},[280,1520,1521,1523,1525],{"class":282,"line":682},[280,1522,287],{"class":286},[280,1524,825],{"class":290},[280,1526,313],{"class":286},[280,1528,1529,1531,1533,1535,1537,1539,1541,1543,1545,1547,1549,1551],{"class":282,"line":696},[280,1530,833],{"class":286},[280,1532,836],{"class":290},[280,1534,839],{"class":294},[280,1536,301],{"class":286},[280,1538,304],{"class":286},[280,1540,552],{"class":307},[280,1542,304],{"class":286},[280,1544,435],{"class":286},[280,1546,852],{"class":326},[280,1548,808],{"class":286},[280,1550,836],{"class":290},[280,1552,313],{"class":286},[280,1554,1555,1557,1559,1561,1563,1565,1567,1569,1571,1573,1575,1577],{"class":282,"line":701},[280,1556,833],{"class":286},[280,1558,836],{"class":290},[280,1560,839],{"class":294},[280,1562,301],{"class":286},[280,1564,304],{"class":286},[280,1566,874],{"class":307},[280,1568,304],{"class":286},[280,1570,435],{"class":286},[280,1572,881],{"class":326},[280,1574,808],{"class":286},[280,1576,836],{"class":290},[280,1578,313],{"class":286},[280,1580,1581,1583,1585,1587,1589,1591,1593,1595,1597,1599,1601,1603],{"class":282,"line":706},[280,1582,833],{"class":286},[280,1584,836],{"class":290},[280,1586,839],{"class":294},[280,1588,301],{"class":286},[280,1590,304],{"class":286},[280,1592,903],{"class":307},[280,1594,304],{"class":286},[280,1596,435],{"class":286},[280,1598,910],{"class":326},[280,1600,808],{"class":286},[280,1602,836],{"class":290},[280,1604,313],{"class":286},[280,1606,1607,1609,1611],{"class":282,"line":728},[280,1608,808],{"class":286},[280,1610,825],{"class":290},[280,1612,313],{"class":286},[198,1614,1615,1616,1618,1619,1622,1623,1622,1626,1629],{},"No ",[201,1617,264],{},", no boolean refs, no ",[201,1620,1621],{},"@confirm","\u002F",[201,1624,1625],{},"@cancel",[201,1627,1628],{},"@close"," plumbing. Each modal lives in its own file; the caller just awaits a result.",[255,1631,1633],{"id":1632},"_2-manual-stacking-scroll-lock-focus-trap","2. Manual stacking, scroll lock, focus trap",[198,1635,1636,1637,1641],{},"A confirm modal opens on top of an open form modal. Now you have two layers, and each of these has to keep working: only the topmost reacts to Esc, body scroll stays locked while ",[1638,1639,1640],"em",{},"any"," layer is open, focus stays in the topmost one and returns to the trigger when it closes. Forget one and the page scrolls behind the dialog or focus leaks out.",[267,1643,1644,2374],{},[270,1645,1647],{"className":272,"code":1646,"filename":274,"language":275,"meta":276,"style":276},"\u003C!-- EditDialog.vue -->\n\u003Cscript setup lang=\"ts\">\nimport { ref, watch, onUnmounted } from 'vue'\n\n\u002F\u002F Open\u002Fclose state\nconst formOpen = ref(true)\nconst confirmOpen = ref(false)\n\nfunction discard() {\n  formOpen.value = false\n  confirmOpen.value = false\n}\n\n\u002F\u002F Refcounted scroll lock: a naive `body.overflow = formOpen`\n\u002F\u002F breaks the moment confirm closes while form is still open.\nconst locks = ref(0)\n\nfunction lockScroll() {\n  if (locks.value++ === 0) {\n    document.body.style.overflow = 'hidden'\n  }\n}\n\nfunction unlockScroll() {\n  if (--locks.value === 0) {\n    document.body.style.overflow = ''\n  }\n}\n\nwatch(formOpen, (v) => (v ? lockScroll() : unlockScroll()), { immediate: true })\nwatch(confirmOpen, (v) => (v ? lockScroll() : unlockScroll()))\n\nonUnmounted(() => {\n  while (locks.value > 0) unlockScroll()\n})\n\n\u002F\u002F Focus trap, focus restore, and Esc routed to the topmost layer:\n\u002F\u002F ~80 LoC per layer, omitted here.\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CTeleport to=\"body\">\n    \u003Cdiv v-if=\"formOpen\" class=\"fixed inset-0 z-50 ...\">\n      \u003Cform>...\u003C\u002Fform>\n      \u003Cbutton @click=\"confirmOpen = true\">Discard\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n\n    \u003Cdiv v-if=\"confirmOpen\" class=\"fixed inset-0 z-60 ...\">\n      Discard changes?\n      \u003Cbutton @click=\"confirmOpen = false\">Cancel\u003C\u002Fbutton>\n      \u003Cbutton @click=\"discard\">OK\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  \u003C\u002FTeleport>\n\u003C\u002Ftemplate>\n",[201,1648,1649,1655,1675,1703,1707,1712,1730,1747,1751,1762,1775,1788,1792,1796,1801,1806,1825,1829,1840,1867,1896,1901,1905,1909,1920,1943,1964,1968,1972,1976,2029,2061,2065,2078,2103,2110,2114,2119,2124,2132,2136,2144,2164,2198,2217,2245,2254,2258,2288,2293,2321,2349,2357,2366],{"__ignoreMap":276},[280,1650,1651],{"class":282,"line":283},[280,1652,1654],{"class":1653},"sHwdD","\u003C!-- EditDialog.vue -->\n",[280,1656,1657,1659,1661,1663,1665,1667,1669,1671,1673],{"class":282,"line":316},[280,1658,287],{"class":286},[280,1660,291],{"class":290},[280,1662,295],{"class":294},[280,1664,298],{"class":294},[280,1666,301],{"class":286},[280,1668,304],{"class":286},[280,1670,308],{"class":307},[280,1672,304],{"class":286},[280,1674,313],{"class":286},[280,1676,1677,1679,1681,1683,1685,1688,1690,1693,1695,1697,1699,1701],{"class":282,"line":344},[280,1678,320],{"class":319},[280,1680,323],{"class":286},[280,1682,327],{"class":326},[280,1684,1275],{"class":286},[280,1686,1687],{"class":326}," watch",[280,1689,1275],{"class":286},[280,1691,1692],{"class":326}," onUnmounted",[280,1694,330],{"class":286},[280,1696,333],{"class":319},[280,1698,336],{"class":286},[280,1700,275],{"class":307},[280,1702,341],{"class":286},[280,1704,1705],{"class":282,"line":351},[280,1706,348],{"emptyLinePlaceholder":347},[280,1708,1709],{"class":282,"line":375},[280,1710,1711],{"class":1653},"\u002F\u002F Open\u002Fclose state\n",[280,1713,1714,1716,1719,1721,1723,1725,1728],{"class":282,"line":393},[280,1715,354],{"class":294},[280,1717,1718],{"class":326}," formOpen ",[280,1720,301],{"class":286},[280,1722,327],{"class":362},[280,1724,365],{"class":326},[280,1726,1727],{"class":368},"true",[280,1729,372],{"class":326},[280,1731,1732,1734,1737,1739,1741,1743,1745],{"class":282,"line":411},[280,1733,354],{"class":294},[280,1735,1736],{"class":326}," confirmOpen ",[280,1738,301],{"class":286},[280,1740,327],{"class":362},[280,1742,365],{"class":326},[280,1744,369],{"class":368},[280,1746,372],{"class":326},[280,1748,1749],{"class":282,"line":445},[280,1750,348],{"emptyLinePlaceholder":347},[280,1752,1753,1755,1758,1760],{"class":282,"line":474},[280,1754,482],{"class":294},[280,1756,1757],{"class":362}," discard",[280,1759,488],{"class":286},[280,1761,491],{"class":286},[280,1763,1764,1767,1769,1771,1773],{"class":282,"line":479},[280,1765,1766],{"class":326},"  formOpen",[280,1768,500],{"class":286},[280,1770,503],{"class":326},[280,1772,506],{"class":286},[280,1774,541],{"class":368},[280,1776,1777,1780,1782,1784,1786],{"class":282,"line":494},[280,1778,1779],{"class":326},"  confirmOpen",[280,1781,500],{"class":286},[280,1783,503],{"class":326},[280,1785,506],{"class":286},[280,1787,541],{"class":368},[280,1789,1790],{"class":282,"line":512},[280,1791,515],{"class":286},[280,1793,1794],{"class":282,"line":518},[280,1795,348],{"emptyLinePlaceholder":347},[280,1797,1798],{"class":282,"line":530},[280,1799,1800],{"class":1653},"\u002F\u002F Refcounted scroll lock: a naive `body.overflow = formOpen`\n",[280,1802,1803],{"class":282,"line":544},[280,1804,1805],{"class":1653},"\u002F\u002F breaks the moment confirm closes while form is still open.\n",[280,1807,1808,1810,1813,1815,1817,1819,1823],{"class":282,"line":558},[280,1809,354],{"class":294},[280,1811,1812],{"class":326}," locks ",[280,1814,301],{"class":286},[280,1816,327],{"class":362},[280,1818,365],{"class":326},[280,1820,1822],{"class":1821},"sbssI","0",[280,1824,372],{"class":326},[280,1826,1827],{"class":282,"line":563},[280,1828,348],{"emptyLinePlaceholder":347},[280,1830,1831,1833,1836,1838],{"class":282,"line":575},[280,1832,482],{"class":294},[280,1834,1835],{"class":362}," lockScroll",[280,1837,488],{"class":286},[280,1839,491],{"class":286},[280,1841,1842,1844,1846,1849,1851,1853,1856,1859,1862,1864],{"class":282,"line":588},[280,1843,1330],{"class":319},[280,1845,1333],{"class":290},[280,1847,1848],{"class":326},"locks",[280,1850,500],{"class":286},[280,1852,503],{"class":326},[280,1854,1855],{"class":286},"++",[280,1857,1858],{"class":286}," ===",[280,1860,1861],{"class":1821}," 0",[280,1863,1339],{"class":290},[280,1865,1866],{"class":286},"{\n",[280,1868,1869,1872,1874,1877,1879,1882,1884,1887,1889,1891,1894],{"class":282,"line":593},[280,1870,1871],{"class":326},"    document",[280,1873,500],{"class":286},[280,1875,1876],{"class":326},"body",[280,1878,500],{"class":286},[280,1880,1881],{"class":326},"style",[280,1883,500],{"class":286},[280,1885,1886],{"class":326},"overflow",[280,1888,506],{"class":286},[280,1890,336],{"class":286},[280,1892,1893],{"class":307},"hidden",[280,1895,341],{"class":286},[280,1897,1898],{"class":282,"line":598},[280,1899,1900],{"class":286},"  }\n",[280,1902,1903],{"class":282,"line":623},[280,1904,515],{"class":286},[280,1906,1907],{"class":282,"line":638},[280,1908,348],{"emptyLinePlaceholder":347},[280,1910,1911,1913,1916,1918],{"class":282,"line":652},[280,1912,482],{"class":294},[280,1914,1915],{"class":362}," unlockScroll",[280,1917,488],{"class":286},[280,1919,491],{"class":286},[280,1921,1922,1924,1926,1929,1931,1933,1935,1937,1939,1941],{"class":282,"line":657},[280,1923,1330],{"class":319},[280,1925,1333],{"class":290},[280,1927,1928],{"class":286},"--",[280,1930,1848],{"class":326},[280,1932,500],{"class":286},[280,1934,503],{"class":326},[280,1936,1858],{"class":286},[280,1938,1861],{"class":1821},[280,1940,1339],{"class":290},[280,1942,1866],{"class":286},[280,1944,1945,1947,1949,1951,1953,1955,1957,1959,1961],{"class":282,"line":669},[280,1946,1871],{"class":326},[280,1948,500],{"class":286},[280,1950,1876],{"class":326},[280,1952,500],{"class":286},[280,1954,1881],{"class":326},[280,1956,500],{"class":286},[280,1958,1886],{"class":326},[280,1960,506],{"class":286},[280,1962,1963],{"class":286}," ''\n",[280,1965,1966],{"class":282,"line":682},[280,1967,1900],{"class":286},[280,1969,1970],{"class":282,"line":696},[280,1971,515],{"class":286},[280,1973,1974],{"class":282,"line":701},[280,1975,348],{"emptyLinePlaceholder":347},[280,1977,1978,1981,1984,1986,1988,1991,1993,1995,1998,2001,2003,2006,2008,2010,2013,2015,2017,2020,2022,2025,2027],{"class":282,"line":706},[280,1979,1980],{"class":362},"watch",[280,1982,1983],{"class":326},"(formOpen",[280,1985,1275],{"class":286},[280,1987,1333],{"class":286},[280,1989,1990],{"class":608},"v",[280,1992,618],{"class":286},[280,1994,1320],{"class":294},[280,1996,1997],{"class":326}," (v ",[280,1999,2000],{"class":286},"?",[280,2002,1835],{"class":362},[280,2004,2005],{"class":326},"() ",[280,2007,612],{"class":286},[280,2009,1915],{"class":362},[280,2011,2012],{"class":326},"())",[280,2014,1275],{"class":286},[280,2016,323],{"class":286},[280,2018,2019],{"class":290}," immediate",[280,2021,612],{"class":286},[280,2023,2024],{"class":368}," true",[280,2026,330],{"class":286},[280,2028,372],{"class":326},[280,2030,2031,2033,2036,2038,2040,2042,2044,2046,2048,2050,2052,2054,2056,2058],{"class":282,"line":728},[280,2032,1980],{"class":362},[280,2034,2035],{"class":326},"(confirmOpen",[280,2037,1275],{"class":286},[280,2039,1333],{"class":286},[280,2041,1990],{"class":608},[280,2043,618],{"class":286},[280,2045,1320],{"class":294},[280,2047,1997],{"class":326},[280,2049,2000],{"class":286},[280,2051,1835],{"class":362},[280,2053,2005],{"class":326},[280,2055,612],{"class":286},[280,2057,1915],{"class":362},[280,2059,2060],{"class":326},"()))\n",[280,2062,2063],{"class":282,"line":743},[280,2064,348],{"emptyLinePlaceholder":347},[280,2066,2067,2070,2072,2074,2076],{"class":282,"line":757},[280,2068,2069],{"class":362},"onUnmounted",[280,2071,365],{"class":326},[280,2073,488],{"class":286},[280,2075,1320],{"class":294},[280,2077,491],{"class":286},[280,2079,2080,2083,2085,2087,2089,2091,2094,2096,2098,2101],{"class":282,"line":762},[280,2081,2082],{"class":319},"  while",[280,2084,1333],{"class":290},[280,2086,1848],{"class":326},[280,2088,500],{"class":286},[280,2090,503],{"class":326},[280,2092,2093],{"class":286}," >",[280,2095,1861],{"class":1821},[280,2097,1339],{"class":290},[280,2099,2100],{"class":362},"unlockScroll",[280,2102,555],{"class":290},[280,2104,2105,2108],{"class":282,"line":774},[280,2106,2107],{"class":286},"}",[280,2109,372],{"class":326},[280,2111,2112],{"class":282,"line":787},[280,2113,348],{"emptyLinePlaceholder":347},[280,2115,2116],{"class":282,"line":800},[280,2117,2118],{"class":1653},"\u002F\u002F Focus trap, focus restore, and Esc routed to the topmost layer:\n",[280,2120,2121],{"class":282,"line":805},[280,2122,2123],{"class":1653},"\u002F\u002F ~80 LoC per layer, omitted here.\n",[280,2125,2126,2128,2130],{"class":282,"line":815},[280,2127,808],{"class":286},[280,2129,291],{"class":290},[280,2131,313],{"class":286},[280,2133,2134],{"class":282,"line":820},[280,2135,348],{"emptyLinePlaceholder":347},[280,2137,2138,2140,2142],{"class":282,"line":830},[280,2139,287],{"class":286},[280,2141,825],{"class":290},[280,2143,313],{"class":286},[280,2145,2146,2148,2151,2154,2156,2158,2160,2162],{"class":282,"line":861},[280,2147,833],{"class":286},[280,2149,2150],{"class":290},"Teleport",[280,2152,2153],{"class":294}," to",[280,2155,301],{"class":286},[280,2157,304],{"class":286},[280,2159,1876],{"class":307},[280,2161,304],{"class":286},[280,2163,313],{"class":286},[280,2165,2166,2169,2172,2175,2177,2179,2182,2184,2187,2189,2191,2194,2196],{"class":282,"line":890},[280,2167,2168],{"class":286},"    \u003C",[280,2170,2171],{"class":290},"div",[280,2173,2174],{"class":294}," v-if",[280,2176,301],{"class":286},[280,2178,304],{"class":286},[280,2180,2181],{"class":307},"formOpen",[280,2183,304],{"class":286},[280,2185,2186],{"class":294}," class",[280,2188,301],{"class":286},[280,2190,304],{"class":286},[280,2192,2193],{"class":307},"fixed inset-0 z-50 ...",[280,2195,304],{"class":286},[280,2197,313],{"class":286},[280,2199,2200,2203,2206,2208,2211,2213,2215],{"class":282,"line":919},[280,2201,2202],{"class":286},"      \u003C",[280,2204,2205],{"class":290},"form",[280,2207,435],{"class":286},[280,2209,2210],{"class":326},"...",[280,2212,808],{"class":286},[280,2214,2205],{"class":290},[280,2216,313],{"class":286},[280,2218,2219,2221,2223,2225,2227,2229,2232,2234,2236,2239,2241,2243],{"class":282,"line":924},[280,2220,2202],{"class":286},[280,2222,836],{"class":290},[280,2224,839],{"class":294},[280,2226,301],{"class":286},[280,2228,304],{"class":286},[280,2230,2231],{"class":307},"confirmOpen = true",[280,2233,304],{"class":286},[280,2235,435],{"class":286},[280,2237,2238],{"class":326},"Discard",[280,2240,808],{"class":286},[280,2242,836],{"class":290},[280,2244,313],{"class":286},[280,2246,2247,2250,2252],{"class":282,"line":932},[280,2248,2249],{"class":286},"    \u003C\u002F",[280,2251,2171],{"class":290},[280,2253,313],{"class":286},[280,2255,2256],{"class":282,"line":948},[280,2257,348],{"emptyLinePlaceholder":347},[280,2259,2260,2262,2264,2266,2268,2270,2273,2275,2277,2279,2281,2284,2286],{"class":282,"line":963},[280,2261,2168],{"class":286},[280,2263,2171],{"class":290},[280,2265,2174],{"class":294},[280,2267,301],{"class":286},[280,2269,304],{"class":286},[280,2271,2272],{"class":307},"confirmOpen",[280,2274,304],{"class":286},[280,2276,2186],{"class":294},[280,2278,301],{"class":286},[280,2280,304],{"class":286},[280,2282,2283],{"class":307},"fixed inset-0 z-60 ...",[280,2285,304],{"class":286},[280,2287,313],{"class":286},[280,2289,2290],{"class":282,"line":978},[280,2291,2292],{"class":326},"      Discard changes?\n",[280,2294,2295,2297,2299,2301,2303,2305,2308,2310,2312,2315,2317,2319],{"class":282,"line":993},[280,2296,2202],{"class":286},[280,2298,836],{"class":290},[280,2300,839],{"class":294},[280,2302,301],{"class":286},[280,2304,304],{"class":286},[280,2306,2307],{"class":307},"confirmOpen = false",[280,2309,304],{"class":286},[280,2311,435],{"class":286},[280,2313,2314],{"class":326},"Cancel",[280,2316,808],{"class":286},[280,2318,836],{"class":290},[280,2320,313],{"class":286},[280,2322,2323,2325,2327,2329,2331,2333,2336,2338,2340,2343,2345,2347],{"class":282,"line":999},[280,2324,2202],{"class":286},[280,2326,836],{"class":290},[280,2328,839],{"class":294},[280,2330,301],{"class":286},[280,2332,304],{"class":286},[280,2334,2335],{"class":307},"discard",[280,2337,304],{"class":286},[280,2339,435],{"class":286},[280,2341,2342],{"class":326},"OK",[280,2344,808],{"class":286},[280,2346,836],{"class":290},[280,2348,313],{"class":286},[280,2350,2351,2353,2355],{"class":282,"line":1007},[280,2352,2249],{"class":286},[280,2354,2171],{"class":290},[280,2356,313],{"class":286},[280,2358,2359,2362,2364],{"class":282,"line":1021},[280,2360,2361],{"class":286},"  \u003C\u002F",[280,2363,2150],{"class":290},[280,2365,313],{"class":286},[280,2367,2368,2370,2372],{"class":282,"line":1036},[280,2369,808],{"class":286},[280,2371,825],{"class":290},[280,2373,313],{"class":286},[270,2375,2377],{"className":272,"code":2376,"filename":1137,"language":275,"meta":276,"style":276},"\u003C!-- EditDialog.vue -->\n\u003Cscript setup lang=\"ts\">\nimport { ModalRoot, ModalContent, openModal, useModalContext } from '@kolirt\u002Fvue-modal'\nimport ConfirmDialog from '.\u002FConfirmDialog.vue'\n\nconst { close } = useModalContext()\n\nasync function discard() {\n  const ok = await openModal\u003Cboolean>(ConfirmDialog, {\n    props: { title: 'Discard?' }\n  }).catch(() => false)\n\n  if (ok) close()\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CModalRoot>\n    \u003CModalContent>\n      \u003Cform>...\u003C\u002Fform>\n      \u003Cbutton @click=\"discard\">Discard\u003C\u002Fbutton>\n    \u003C\u002FModalContent>\n  \u003C\u002FModalRoot>\n\u003C\u002Ftemplate>\n",[201,2378,2379,2383,2403,2436,2450,2454,2471,2475,2487,2513,2534,2554,2558,2573,2577,2585,2589,2597,2606,2615,2631,2657,2665,2673],{"__ignoreMap":276},[280,2380,2381],{"class":282,"line":283},[280,2382,1654],{"class":1653},[280,2384,2385,2387,2389,2391,2393,2395,2397,2399,2401],{"class":282,"line":316},[280,2386,287],{"class":286},[280,2388,291],{"class":290},[280,2390,295],{"class":294},[280,2392,298],{"class":294},[280,2394,301],{"class":286},[280,2396,304],{"class":286},[280,2398,308],{"class":307},[280,2400,304],{"class":286},[280,2402,313],{"class":286},[280,2404,2405,2407,2409,2412,2414,2417,2419,2421,2423,2426,2428,2430,2432,2434],{"class":282,"line":344},[280,2406,320],{"class":319},[280,2408,323],{"class":286},[280,2410,2411],{"class":326}," ModalRoot",[280,2413,1275],{"class":286},[280,2415,2416],{"class":326}," ModalContent",[280,2418,1275],{"class":286},[280,2420,1168],{"class":326},[280,2422,1275],{"class":286},[280,2424,2425],{"class":326}," useModalContext",[280,2427,330],{"class":286},[280,2429,333],{"class":319},[280,2431,336],{"class":286},[280,2433,203],{"class":307},[280,2435,341],{"class":286},[280,2437,2438,2440,2442,2444,2446,2448],{"class":282,"line":351},[280,2439,320],{"class":319},[280,2441,1185],{"class":326},[280,2443,1188],{"class":319},[280,2445,336],{"class":286},[280,2447,1193],{"class":307},[280,2449,341],{"class":286},[280,2451,2452],{"class":282,"line":375},[280,2453,348],{"emptyLinePlaceholder":347},[280,2455,2456,2458,2460,2463,2465,2467,2469],{"class":282,"line":393},[280,2457,354],{"class":294},[280,2459,323],{"class":286},[280,2461,2462],{"class":326}," close ",[280,2464,2107],{"class":286},[280,2466,506],{"class":286},[280,2468,2425],{"class":362},[280,2470,555],{"class":326},[280,2472,2473],{"class":282,"line":411},[280,2474,348],{"emptyLinePlaceholder":347},[280,2476,2477,2479,2481,2483,2485],{"class":282,"line":445},[280,2478,1236],{"class":294},[280,2480,1239],{"class":294},[280,2482,1757],{"class":362},[280,2484,488],{"class":286},[280,2486,491],{"class":286},[280,2488,2489,2491,2493,2495,2497,2499,2501,2503,2505,2507,2509,2511],{"class":282,"line":474},[280,2490,1250],{"class":294},[280,2492,1253],{"class":326},[280,2494,506],{"class":286},[280,2496,1258],{"class":319},[280,2498,1168],{"class":362},[280,2500,287],{"class":286},[280,2502,1265],{"class":425},[280,2504,435],{"class":286},[280,2506,365],{"class":290},[280,2508,1272],{"class":326},[280,2510,1275],{"class":286},[280,2512,491],{"class":286},[280,2514,2515,2517,2519,2521,2523,2525,2527,2530,2532],{"class":282,"line":479},[280,2516,1282],{"class":290},[280,2518,612],{"class":286},[280,2520,323],{"class":286},[280,2522,1289],{"class":290},[280,2524,612],{"class":286},[280,2526,336],{"class":286},[280,2528,2529],{"class":307},"Discard?",[280,2531,1298],{"class":286},[280,2533,1301],{"class":286},[280,2535,2536,2538,2540,2542,2544,2546,2548,2550,2552],{"class":282,"line":494},[280,2537,1306],{"class":286},[280,2539,618],{"class":290},[280,2541,500],{"class":286},[280,2543,1313],{"class":362},[280,2545,365],{"class":290},[280,2547,488],{"class":286},[280,2549,1320],{"class":294},[280,2551,1323],{"class":368},[280,2553,372],{"class":290},[280,2555,2556],{"class":282,"line":512},[280,2557,348],{"emptyLinePlaceholder":347},[280,2559,2560,2562,2564,2566,2568,2571],{"class":282,"line":518},[280,2561,1330],{"class":319},[280,2563,1333],{"class":290},[280,2565,1336],{"class":326},[280,2567,1339],{"class":290},[280,2569,2570],{"class":362},"close",[280,2572,555],{"class":290},[280,2574,2575],{"class":282,"line":530},[280,2576,515],{"class":286},[280,2578,2579,2581,2583],{"class":282,"line":544},[280,2580,808],{"class":286},[280,2582,291],{"class":290},[280,2584,313],{"class":286},[280,2586,2587],{"class":282,"line":558},[280,2588,348],{"emptyLinePlaceholder":347},[280,2590,2591,2593,2595],{"class":282,"line":563},[280,2592,287],{"class":286},[280,2594,825],{"class":290},[280,2596,313],{"class":286},[280,2598,2599,2601,2604],{"class":282,"line":575},[280,2600,833],{"class":286},[280,2602,2603],{"class":290},"ModalRoot",[280,2605,313],{"class":286},[280,2607,2608,2610,2613],{"class":282,"line":588},[280,2609,2168],{"class":286},[280,2611,2612],{"class":290},"ModalContent",[280,2614,313],{"class":286},[280,2616,2617,2619,2621,2623,2625,2627,2629],{"class":282,"line":593},[280,2618,2202],{"class":286},[280,2620,2205],{"class":290},[280,2622,435],{"class":286},[280,2624,2210],{"class":326},[280,2626,808],{"class":286},[280,2628,2205],{"class":290},[280,2630,313],{"class":286},[280,2632,2633,2635,2637,2639,2641,2643,2645,2647,2649,2651,2653,2655],{"class":282,"line":598},[280,2634,2202],{"class":286},[280,2636,836],{"class":290},[280,2638,839],{"class":294},[280,2640,301],{"class":286},[280,2642,304],{"class":286},[280,2644,2335],{"class":307},[280,2646,304],{"class":286},[280,2648,435],{"class":286},[280,2650,2238],{"class":326},[280,2652,808],{"class":286},[280,2654,836],{"class":290},[280,2656,313],{"class":286},[280,2658,2659,2661,2663],{"class":282,"line":623},[280,2660,2249],{"class":286},[280,2662,2612],{"class":290},[280,2664,313],{"class":286},[280,2666,2667,2669,2671],{"class":282,"line":638},[280,2668,2361],{"class":286},[280,2670,2603],{"class":290},[280,2672,313],{"class":286},[280,2674,2675,2677,2679],{"class":282,"line":652},[280,2676,808],{"class":286},[280,2678,825],{"class":290},[280,2680,313],{"class":286},[198,2682,2683],{},"The package stacks the confirm above the form automatically, keeps body scroll locked while either layer is open, traps focus inside the topmost, and returns focus to the trigger when it closes.",[255,2685,2687],{"id":2686},"_3-close-guards","3. Close guards",[198,2689,2690,2691,2694],{},"Same form, now dirty: the user presses Esc or clicks the overlay. You need to ask \"discard changes?\" before letting the modal go — and you need to handle this for ",[217,2692,2693],{},"every"," close path, not just the explicit Close button.",[267,2696,2697,3282],{},[270,2698,2700],{"className":272,"code":2699,"filename":274,"language":275,"meta":276,"style":276},"\u003C!-- EditDialog.vue -->\n\u003Cscript setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted } from 'vue'\n\nconst isOpen = ref(true)\nconst dirty = ref(true)\nconst showDiscardConfirm = ref(false)\n\nfunction requestClose() {\n  if (dirty.value) showDiscardConfirm.value = true\n  else isOpen.value = false\n}\n\n\u002F\u002F You have to wire the guard into each path manually:\n\n\u002F\u002F Esc key — global listener, only top layer should react\nfunction onKeydown(e: KeyboardEvent) {\n  if (e.key === 'Escape' && isOpen.value && !showDiscardConfirm.value) requestClose()\n}\nonMounted(() => window.addEventListener('keydown', onKeydown))\nonUnmounted(() => window.removeEventListener('keydown', onKeydown))\n\n\u002F\u002F Overlay click — bind it on the overlay div\n\u002F\u002F Manual close button — bind it on the button\n\u002F\u002F Programmatic close from a parent — they have to call requestClose, not isOpen=false\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CTeleport to=\"body\">\n    \u003Cdiv v-if=\"isOpen\" class=\"fixed inset-0 z-50 ...\" @click.self=\"requestClose\">\n      \u003Cform>...\u003C\u002Fform>\n      \u003Cbutton @click=\"requestClose\">Close\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n    \u003Cdiv v-if=\"showDiscardConfirm\" class=\"fixed inset-0 z-60 ...\">\n      Discard changes?\n      \u003Cbutton @click=\"showDiscardConfirm = false\">Keep editing\u003C\u002Fbutton>\n      \u003Cbutton @click=\"isOpen = false; showDiscardConfirm = false\">Discard\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  \u003C\u002FTeleport>\n\u003C\u002Ftemplate>\n",[201,2701,2702,2706,2726,2753,2757,2774,2791,2808,2812,2823,2849,2865,2869,2873,2878,2882,2887,2908,2957,2961,2994,3023,3027,3032,3037,3042,3050,3054,3062,3080,3120,3136,3163,3171,3199,3203,3231,3258,3266,3274],{"__ignoreMap":276},[280,2703,2704],{"class":282,"line":283},[280,2705,1654],{"class":1653},[280,2707,2708,2710,2712,2714,2716,2718,2720,2722,2724],{"class":282,"line":316},[280,2709,287],{"class":286},[280,2711,291],{"class":290},[280,2713,295],{"class":294},[280,2715,298],{"class":294},[280,2717,301],{"class":286},[280,2719,304],{"class":286},[280,2721,308],{"class":307},[280,2723,304],{"class":286},[280,2725,313],{"class":286},[280,2727,2728,2730,2732,2734,2736,2739,2741,2743,2745,2747,2749,2751],{"class":282,"line":344},[280,2729,320],{"class":319},[280,2731,323],{"class":286},[280,2733,327],{"class":326},[280,2735,1275],{"class":286},[280,2737,2738],{"class":326}," onMounted",[280,2740,1275],{"class":286},[280,2742,1692],{"class":326},[280,2744,330],{"class":286},[280,2746,333],{"class":319},[280,2748,336],{"class":286},[280,2750,275],{"class":307},[280,2752,341],{"class":286},[280,2754,2755],{"class":282,"line":351},[280,2756,348],{"emptyLinePlaceholder":347},[280,2758,2759,2761,2764,2766,2768,2770,2772],{"class":282,"line":375},[280,2760,354],{"class":294},[280,2762,2763],{"class":326}," isOpen ",[280,2765,301],{"class":286},[280,2767,327],{"class":362},[280,2769,365],{"class":326},[280,2771,1727],{"class":368},[280,2773,372],{"class":326},[280,2775,2776,2778,2781,2783,2785,2787,2789],{"class":282,"line":393},[280,2777,354],{"class":294},[280,2779,2780],{"class":326}," dirty ",[280,2782,301],{"class":286},[280,2784,327],{"class":362},[280,2786,365],{"class":326},[280,2788,1727],{"class":368},[280,2790,372],{"class":326},[280,2792,2793,2795,2798,2800,2802,2804,2806],{"class":282,"line":411},[280,2794,354],{"class":294},[280,2796,2797],{"class":326}," showDiscardConfirm ",[280,2799,301],{"class":286},[280,2801,327],{"class":362},[280,2803,365],{"class":326},[280,2805,369],{"class":368},[280,2807,372],{"class":326},[280,2809,2810],{"class":282,"line":445},[280,2811,348],{"emptyLinePlaceholder":347},[280,2813,2814,2816,2819,2821],{"class":282,"line":474},[280,2815,482],{"class":294},[280,2817,2818],{"class":362}," requestClose",[280,2820,488],{"class":286},[280,2822,491],{"class":286},[280,2824,2825,2827,2829,2832,2834,2836,2838,2841,2843,2845,2847],{"class":282,"line":479},[280,2826,1330],{"class":319},[280,2828,1333],{"class":290},[280,2830,2831],{"class":326},"dirty",[280,2833,500],{"class":286},[280,2835,503],{"class":326},[280,2837,1339],{"class":290},[280,2839,2840],{"class":326},"showDiscardConfirm",[280,2842,500],{"class":286},[280,2844,503],{"class":326},[280,2846,506],{"class":286},[280,2848,509],{"class":368},[280,2850,2851,2854,2857,2859,2861,2863],{"class":282,"line":494},[280,2852,2853],{"class":319},"  else",[280,2855,2856],{"class":326}," isOpen",[280,2858,500],{"class":286},[280,2860,503],{"class":326},[280,2862,506],{"class":286},[280,2864,541],{"class":368},[280,2866,2867],{"class":282,"line":512},[280,2868,515],{"class":286},[280,2870,2871],{"class":282,"line":518},[280,2872,348],{"emptyLinePlaceholder":347},[280,2874,2875],{"class":282,"line":530},[280,2876,2877],{"class":1653},"\u002F\u002F You have to wire the guard into each path manually:\n",[280,2879,2880],{"class":282,"line":544},[280,2881,348],{"emptyLinePlaceholder":347},[280,2883,2884],{"class":282,"line":558},[280,2885,2886],{"class":1653},"\u002F\u002F Esc key — global listener, only top layer should react\n",[280,2888,2889,2891,2894,2896,2899,2901,2904,2906],{"class":282,"line":563},[280,2890,482],{"class":294},[280,2892,2893],{"class":362}," onKeydown",[280,2895,365],{"class":286},[280,2897,2898],{"class":608},"e",[280,2900,612],{"class":286},[280,2902,2903],{"class":425}," KeyboardEvent",[280,2905,618],{"class":286},[280,2907,491],{"class":286},[280,2909,2910,2912,2914,2916,2918,2921,2923,2925,2928,2930,2933,2935,2937,2939,2941,2944,2946,2948,2950,2952,2955],{"class":282,"line":575},[280,2911,1330],{"class":319},[280,2913,1333],{"class":290},[280,2915,2898],{"class":326},[280,2917,500],{"class":286},[280,2919,2920],{"class":326},"key",[280,2922,1858],{"class":286},[280,2924,336],{"class":286},[280,2926,2927],{"class":307},"Escape",[280,2929,1298],{"class":286},[280,2931,2932],{"class":286}," &&",[280,2934,2856],{"class":326},[280,2936,500],{"class":286},[280,2938,503],{"class":326},[280,2940,2932],{"class":286},[280,2942,2943],{"class":286}," !",[280,2945,2840],{"class":326},[280,2947,500],{"class":286},[280,2949,503],{"class":326},[280,2951,1339],{"class":290},[280,2953,2954],{"class":362},"requestClose",[280,2956,555],{"class":290},[280,2958,2959],{"class":282,"line":588},[280,2960,515],{"class":286},[280,2962,2963,2966,2968,2970,2972,2975,2977,2980,2982,2984,2987,2989,2991],{"class":282,"line":593},[280,2964,2965],{"class":362},"onMounted",[280,2967,365],{"class":326},[280,2969,488],{"class":286},[280,2971,1320],{"class":294},[280,2973,2974],{"class":326}," window",[280,2976,500],{"class":286},[280,2978,2979],{"class":362},"addEventListener",[280,2981,365],{"class":326},[280,2983,1298],{"class":286},[280,2985,2986],{"class":307},"keydown",[280,2988,1298],{"class":286},[280,2990,1275],{"class":286},[280,2992,2993],{"class":326}," onKeydown))\n",[280,2995,2996,2998,3000,3002,3004,3006,3008,3011,3013,3015,3017,3019,3021],{"class":282,"line":598},[280,2997,2069],{"class":362},[280,2999,365],{"class":326},[280,3001,488],{"class":286},[280,3003,1320],{"class":294},[280,3005,2974],{"class":326},[280,3007,500],{"class":286},[280,3009,3010],{"class":362},"removeEventListener",[280,3012,365],{"class":326},[280,3014,1298],{"class":286},[280,3016,2986],{"class":307},[280,3018,1298],{"class":286},[280,3020,1275],{"class":286},[280,3022,2993],{"class":326},[280,3024,3025],{"class":282,"line":623},[280,3026,348],{"emptyLinePlaceholder":347},[280,3028,3029],{"class":282,"line":638},[280,3030,3031],{"class":1653},"\u002F\u002F Overlay click — bind it on the overlay div\n",[280,3033,3034],{"class":282,"line":652},[280,3035,3036],{"class":1653},"\u002F\u002F Manual close button — bind it on the button\n",[280,3038,3039],{"class":282,"line":657},[280,3040,3041],{"class":1653},"\u002F\u002F Programmatic close from a parent — they have to call requestClose, not isOpen=false\n",[280,3043,3044,3046,3048],{"class":282,"line":669},[280,3045,808],{"class":286},[280,3047,291],{"class":290},[280,3049,313],{"class":286},[280,3051,3052],{"class":282,"line":682},[280,3053,348],{"emptyLinePlaceholder":347},[280,3055,3056,3058,3060],{"class":282,"line":696},[280,3057,287],{"class":286},[280,3059,825],{"class":290},[280,3061,313],{"class":286},[280,3063,3064,3066,3068,3070,3072,3074,3076,3078],{"class":282,"line":701},[280,3065,833],{"class":286},[280,3067,2150],{"class":290},[280,3069,2153],{"class":294},[280,3071,301],{"class":286},[280,3073,304],{"class":286},[280,3075,1876],{"class":307},[280,3077,304],{"class":286},[280,3079,313],{"class":286},[280,3081,3082,3084,3086,3088,3090,3092,3095,3097,3099,3101,3103,3105,3107,3110,3112,3114,3116,3118],{"class":282,"line":706},[280,3083,2168],{"class":286},[280,3085,2171],{"class":290},[280,3087,2174],{"class":294},[280,3089,301],{"class":286},[280,3091,304],{"class":286},[280,3093,3094],{"class":307},"isOpen",[280,3096,304],{"class":286},[280,3098,2186],{"class":294},[280,3100,301],{"class":286},[280,3102,304],{"class":286},[280,3104,2193],{"class":307},[280,3106,304],{"class":286},[280,3108,3109],{"class":294}," @click.self",[280,3111,301],{"class":286},[280,3113,304],{"class":286},[280,3115,2954],{"class":307},[280,3117,304],{"class":286},[280,3119,313],{"class":286},[280,3121,3122,3124,3126,3128,3130,3132,3134],{"class":282,"line":728},[280,3123,2202],{"class":286},[280,3125,2205],{"class":290},[280,3127,435],{"class":286},[280,3129,2210],{"class":326},[280,3131,808],{"class":286},[280,3133,2205],{"class":290},[280,3135,313],{"class":286},[280,3137,3138,3140,3142,3144,3146,3148,3150,3152,3154,3157,3159,3161],{"class":282,"line":743},[280,3139,2202],{"class":286},[280,3141,836],{"class":290},[280,3143,839],{"class":294},[280,3145,301],{"class":286},[280,3147,304],{"class":286},[280,3149,2954],{"class":307},[280,3151,304],{"class":286},[280,3153,435],{"class":286},[280,3155,3156],{"class":326},"Close",[280,3158,808],{"class":286},[280,3160,836],{"class":290},[280,3162,313],{"class":286},[280,3164,3165,3167,3169],{"class":282,"line":757},[280,3166,2249],{"class":286},[280,3168,2171],{"class":290},[280,3170,313],{"class":286},[280,3172,3173,3175,3177,3179,3181,3183,3185,3187,3189,3191,3193,3195,3197],{"class":282,"line":762},[280,3174,2168],{"class":286},[280,3176,2171],{"class":290},[280,3178,2174],{"class":294},[280,3180,301],{"class":286},[280,3182,304],{"class":286},[280,3184,2840],{"class":307},[280,3186,304],{"class":286},[280,3188,2186],{"class":294},[280,3190,301],{"class":286},[280,3192,304],{"class":286},[280,3194,2283],{"class":307},[280,3196,304],{"class":286},[280,3198,313],{"class":286},[280,3200,3201],{"class":282,"line":774},[280,3202,2292],{"class":326},[280,3204,3205,3207,3209,3211,3213,3215,3218,3220,3222,3225,3227,3229],{"class":282,"line":787},[280,3206,2202],{"class":286},[280,3208,836],{"class":290},[280,3210,839],{"class":294},[280,3212,301],{"class":286},[280,3214,304],{"class":286},[280,3216,3217],{"class":307},"showDiscardConfirm = false",[280,3219,304],{"class":286},[280,3221,435],{"class":286},[280,3223,3224],{"class":326},"Keep editing",[280,3226,808],{"class":286},[280,3228,836],{"class":290},[280,3230,313],{"class":286},[280,3232,3233,3235,3237,3239,3241,3243,3246,3248,3250,3252,3254,3256],{"class":282,"line":800},[280,3234,2202],{"class":286},[280,3236,836],{"class":290},[280,3238,839],{"class":294},[280,3240,301],{"class":286},[280,3242,304],{"class":286},[280,3244,3245],{"class":307},"isOpen = false; showDiscardConfirm = false",[280,3247,304],{"class":286},[280,3249,435],{"class":286},[280,3251,2238],{"class":326},[280,3253,808],{"class":286},[280,3255,836],{"class":290},[280,3257,313],{"class":286},[280,3259,3260,3262,3264],{"class":282,"line":805},[280,3261,2249],{"class":286},[280,3263,2171],{"class":290},[280,3265,313],{"class":286},[280,3267,3268,3270,3272],{"class":282,"line":815},[280,3269,2361],{"class":286},[280,3271,2150],{"class":290},[280,3273,313],{"class":286},[280,3275,3276,3278,3280],{"class":282,"line":820},[280,3277,808],{"class":286},[280,3279,825],{"class":290},[280,3281,313],{"class":286},[270,3283,3285],{"className":272,"code":3284,"filename":1137,"language":275,"meta":276,"style":276},"\u003C!-- EditDialog.vue -->\n\u003Cscript setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { ModalRoot, ModalContent, openModal, useModalContext } from '@kolirt\u002Fvue-modal'\nimport ConfirmDialog from '.\u002FConfirmDialog.vue'\n\nconst { close, onBeforeClose } = useModalContext()\nconst dirty = ref(true)\n\n\u002F\u002F One guard, every close path: Esc, overlay, manual button, programmatic.\nonBeforeClose(async () => {\n  if (!dirty.value) return\n\n  const discard = await openModal\u003Cboolean>(ConfirmDialog, {\n    props: { title: 'Discard changes?' }\n  }).catch(() => false)\n\n  if (!discard) return false \u002F\u002F veto — keep the form open\n})\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CModalRoot>\n    \u003CModalContent>\n      \u003Cform>...\u003C\u002Fform>\n      \u003Cbutton @click=\"close()\">Close\u003C\u002Fbutton>\n    \u003C\u002FModalContent>\n  \u003C\u002FModalRoot>\n\u003C\u002Ftemplate>\n",[201,3286,3287,3291,3311,3329,3359,3373,3377,3399,3415,3419,3424,3440,3460,3464,3490,3511,3531,3535,3555,3561,3569,3573,3581,3589,3597,3613,3640,3648,3656],{"__ignoreMap":276},[280,3288,3289],{"class":282,"line":283},[280,3290,1654],{"class":1653},[280,3292,3293,3295,3297,3299,3301,3303,3305,3307,3309],{"class":282,"line":316},[280,3294,287],{"class":286},[280,3296,291],{"class":290},[280,3298,295],{"class":294},[280,3300,298],{"class":294},[280,3302,301],{"class":286},[280,3304,304],{"class":286},[280,3306,308],{"class":307},[280,3308,304],{"class":286},[280,3310,313],{"class":286},[280,3312,3313,3315,3317,3319,3321,3323,3325,3327],{"class":282,"line":344},[280,3314,320],{"class":319},[280,3316,323],{"class":286},[280,3318,327],{"class":326},[280,3320,330],{"class":286},[280,3322,333],{"class":319},[280,3324,336],{"class":286},[280,3326,275],{"class":307},[280,3328,341],{"class":286},[280,3330,3331,3333,3335,3337,3339,3341,3343,3345,3347,3349,3351,3353,3355,3357],{"class":282,"line":351},[280,3332,320],{"class":319},[280,3334,323],{"class":286},[280,3336,2411],{"class":326},[280,3338,1275],{"class":286},[280,3340,2416],{"class":326},[280,3342,1275],{"class":286},[280,3344,1168],{"class":326},[280,3346,1275],{"class":286},[280,3348,2425],{"class":326},[280,3350,330],{"class":286},[280,3352,333],{"class":319},[280,3354,336],{"class":286},[280,3356,203],{"class":307},[280,3358,341],{"class":286},[280,3360,3361,3363,3365,3367,3369,3371],{"class":282,"line":375},[280,3362,320],{"class":319},[280,3364,1185],{"class":326},[280,3366,1188],{"class":319},[280,3368,336],{"class":286},[280,3370,1193],{"class":307},[280,3372,341],{"class":286},[280,3374,3375],{"class":282,"line":393},[280,3376,348],{"emptyLinePlaceholder":347},[280,3378,3379,3381,3383,3386,3388,3391,3393,3395,3397],{"class":282,"line":411},[280,3380,354],{"class":294},[280,3382,323],{"class":286},[280,3384,3385],{"class":326}," close",[280,3387,1275],{"class":286},[280,3389,3390],{"class":326}," onBeforeClose ",[280,3392,2107],{"class":286},[280,3394,506],{"class":286},[280,3396,2425],{"class":362},[280,3398,555],{"class":326},[280,3400,3401,3403,3405,3407,3409,3411,3413],{"class":282,"line":445},[280,3402,354],{"class":294},[280,3404,2780],{"class":326},[280,3406,301],{"class":286},[280,3408,327],{"class":362},[280,3410,365],{"class":326},[280,3412,1727],{"class":368},[280,3414,372],{"class":326},[280,3416,3417],{"class":282,"line":474},[280,3418,348],{"emptyLinePlaceholder":347},[280,3420,3421],{"class":282,"line":479},[280,3422,3423],{"class":1653},"\u002F\u002F One guard, every close path: Esc, overlay, manual button, programmatic.\n",[280,3425,3426,3429,3431,3433,3436,3438],{"class":282,"line":494},[280,3427,3428],{"class":362},"onBeforeClose",[280,3430,365],{"class":326},[280,3432,1236],{"class":294},[280,3434,3435],{"class":286}," ()",[280,3437,1320],{"class":294},[280,3439,491],{"class":286},[280,3441,3442,3444,3446,3449,3451,3453,3455,3457],{"class":282,"line":512},[280,3443,1330],{"class":319},[280,3445,1333],{"class":290},[280,3447,3448],{"class":286},"!",[280,3450,2831],{"class":326},[280,3452,500],{"class":286},[280,3454,503],{"class":326},[280,3456,1339],{"class":290},[280,3458,3459],{"class":319},"return\n",[280,3461,3462],{"class":282,"line":518},[280,3463,348],{"emptyLinePlaceholder":347},[280,3465,3466,3468,3470,3472,3474,3476,3478,3480,3482,3484,3486,3488],{"class":282,"line":530},[280,3467,1250],{"class":294},[280,3469,1757],{"class":326},[280,3471,506],{"class":286},[280,3473,1258],{"class":319},[280,3475,1168],{"class":362},[280,3477,287],{"class":286},[280,3479,1265],{"class":425},[280,3481,435],{"class":286},[280,3483,365],{"class":290},[280,3485,1272],{"class":326},[280,3487,1275],{"class":286},[280,3489,491],{"class":286},[280,3491,3492,3494,3496,3498,3500,3502,3504,3507,3509],{"class":282,"line":544},[280,3493,1282],{"class":290},[280,3495,612],{"class":286},[280,3497,323],{"class":286},[280,3499,1289],{"class":290},[280,3501,612],{"class":286},[280,3503,336],{"class":286},[280,3505,3506],{"class":307},"Discard changes?",[280,3508,1298],{"class":286},[280,3510,1301],{"class":286},[280,3512,3513,3515,3517,3519,3521,3523,3525,3527,3529],{"class":282,"line":558},[280,3514,1306],{"class":286},[280,3516,618],{"class":290},[280,3518,500],{"class":286},[280,3520,1313],{"class":362},[280,3522,365],{"class":290},[280,3524,488],{"class":286},[280,3526,1320],{"class":294},[280,3528,1323],{"class":368},[280,3530,372],{"class":290},[280,3532,3533],{"class":282,"line":563},[280,3534,348],{"emptyLinePlaceholder":347},[280,3536,3537,3539,3541,3543,3545,3547,3550,3552],{"class":282,"line":575},[280,3538,1330],{"class":319},[280,3540,1333],{"class":290},[280,3542,3448],{"class":286},[280,3544,2335],{"class":326},[280,3546,1339],{"class":290},[280,3548,3549],{"class":319},"return",[280,3551,1323],{"class":368},[280,3553,3554],{"class":1653}," \u002F\u002F veto — keep the form open\n",[280,3556,3557,3559],{"class":282,"line":588},[280,3558,2107],{"class":286},[280,3560,372],{"class":326},[280,3562,3563,3565,3567],{"class":282,"line":593},[280,3564,808],{"class":286},[280,3566,291],{"class":290},[280,3568,313],{"class":286},[280,3570,3571],{"class":282,"line":598},[280,3572,348],{"emptyLinePlaceholder":347},[280,3574,3575,3577,3579],{"class":282,"line":623},[280,3576,287],{"class":286},[280,3578,825],{"class":290},[280,3580,313],{"class":286},[280,3582,3583,3585,3587],{"class":282,"line":638},[280,3584,833],{"class":286},[280,3586,2603],{"class":290},[280,3588,313],{"class":286},[280,3590,3591,3593,3595],{"class":282,"line":652},[280,3592,2168],{"class":286},[280,3594,2612],{"class":290},[280,3596,313],{"class":286},[280,3598,3599,3601,3603,3605,3607,3609,3611],{"class":282,"line":657},[280,3600,2202],{"class":286},[280,3602,2205],{"class":290},[280,3604,435],{"class":286},[280,3606,2210],{"class":326},[280,3608,808],{"class":286},[280,3610,2205],{"class":290},[280,3612,313],{"class":286},[280,3614,3615,3617,3619,3621,3623,3625,3628,3630,3632,3634,3636,3638],{"class":282,"line":669},[280,3616,2202],{"class":286},[280,3618,836],{"class":290},[280,3620,839],{"class":294},[280,3622,301],{"class":286},[280,3624,304],{"class":286},[280,3626,3627],{"class":307},"close()",[280,3629,304],{"class":286},[280,3631,435],{"class":286},[280,3633,3156],{"class":326},[280,3635,808],{"class":286},[280,3637,836],{"class":290},[280,3639,313],{"class":286},[280,3641,3642,3644,3646],{"class":282,"line":682},[280,3643,2249],{"class":286},[280,3645,2612],{"class":290},[280,3647,313],{"class":286},[280,3649,3650,3652,3654],{"class":282,"line":696},[280,3651,2361],{"class":286},[280,3653,2603],{"class":290},[280,3655,313],{"class":286},[280,3657,3658,3660,3662],{"class":282,"line":701},[280,3659,808],{"class":286},[280,3661,825],{"class":290},[280,3663,313],{"class":286},[198,3665,3666,3668,3669,3671,3672,3675,3676,3678],{},[201,3667,3428],{}," runs before every explicit close — Esc, overlay click, and any ",[201,3670,3627],{}," \u002F ",[201,3673,3674],{},"confirm()"," call — through the same hook. Return ",[201,3677,369],{}," to veto.",[255,3680,3682],{"id":3681},"_4-split-control-flow","4. Split control flow",[198,3684,3685,3686,3689,3690,3671,3692,3694,3695,3697],{},"A flow that opens ",[217,3687,3688],{},"two modals in sequence"," — pick a role, then confirm — exposes how the usual ",[201,3691,1621],{},[201,3693,1625],{}," event pattern fragments. Each modal needs its own state, its own handlers, and the second modal can only start from inside the first one's ",[201,3696,1621],{},". With promises the whole flow stays in one function.",[267,3699,3700,4262],{},[270,3701,3703],{"className":272,"code":3702,"filename":274,"language":275,"meta":276,"style":276},"\u003Cscript setup lang=\"ts\">\nimport { ref } from 'vue'\n\nconst isRoleOpen = ref(false)\nconst isConfirmOpen = ref(false)\nconst chosenRole = ref\u003C'admin' | 'guest' | null>(null)\n\nfunction promote() {\n  isRoleOpen.value = true\n}\n\nfunction onRoleSelected(role: 'admin' | 'guest') {\n  isRoleOpen.value = false\n  chosenRole.value = role\n  isConfirmOpen.value = true\n}\n\nfunction onRoleCancelled() {\n  isRoleOpen.value = false\n}\n\nasync function onConfirmYes() {\n  isConfirmOpen.value = false\n  if (chosenRole.value) {\n    await api.promote(chosenRole.value)\n  }\n  chosenRole.value = null\n}\n\nfunction onConfirmNo() {\n  isConfirmOpen.value = false\n  chosenRole.value = null\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cbutton @click=\"promote\">Promote\u003C\u002Fbutton>\n\n  \u003CSelectRoleDialog\n    v-if=\"isRoleOpen\"\n    @select=\"onRoleSelected\"\n    @cancel=\"onRoleCancelled\"\n  \u002F>\n  \u003CConfirmDialog\n    v-if=\"isConfirmOpen && chosenRole\"\n    :title=\"`Promote to ${chosenRole}?`\"\n    @confirm=\"onConfirmYes\"\n    @cancel=\"onConfirmNo\"\n  \u002F>\n\u003C\u002Ftemplate>\n",[201,3704,3705,3725,3743,3747,3764,3780,3821,3825,3836,3849,3853,3857,3889,3901,3915,3927,3931,3935,3946,3958,3962,3966,3978,3990,4007,4029,4033,4045,4049,4053,4063,4075,4087,4091,4099,4103,4111,4138,4142,4149,4162,4176,4189,4193,4199,4212,4226,4238,4250,4254],{"__ignoreMap":276},[280,3706,3707,3709,3711,3713,3715,3717,3719,3721,3723],{"class":282,"line":283},[280,3708,287],{"class":286},[280,3710,291],{"class":290},[280,3712,295],{"class":294},[280,3714,298],{"class":294},[280,3716,301],{"class":286},[280,3718,304],{"class":286},[280,3720,308],{"class":307},[280,3722,304],{"class":286},[280,3724,313],{"class":286},[280,3726,3727,3729,3731,3733,3735,3737,3739,3741],{"class":282,"line":316},[280,3728,320],{"class":319},[280,3730,323],{"class":286},[280,3732,327],{"class":326},[280,3734,330],{"class":286},[280,3736,333],{"class":319},[280,3738,336],{"class":286},[280,3740,275],{"class":307},[280,3742,341],{"class":286},[280,3744,3745],{"class":282,"line":344},[280,3746,348],{"emptyLinePlaceholder":347},[280,3748,3749,3751,3754,3756,3758,3760,3762],{"class":282,"line":351},[280,3750,354],{"class":294},[280,3752,3753],{"class":326}," isRoleOpen ",[280,3755,301],{"class":286},[280,3757,327],{"class":362},[280,3759,365],{"class":326},[280,3761,369],{"class":368},[280,3763,372],{"class":326},[280,3765,3766,3768,3770,3772,3774,3776,3778],{"class":282,"line":375},[280,3767,354],{"class":294},[280,3769,357],{"class":326},[280,3771,301],{"class":286},[280,3773,327],{"class":362},[280,3775,365],{"class":326},[280,3777,369],{"class":368},[280,3779,372],{"class":326},[280,3781,3782,3784,3787,3789,3791,3793,3795,3798,3800,3802,3804,3807,3809,3811,3813,3815,3817,3819],{"class":282,"line":393},[280,3783,354],{"class":294},[280,3785,3786],{"class":326}," chosenRole ",[280,3788,301],{"class":286},[280,3790,327],{"class":362},[280,3792,287],{"class":286},[280,3794,1298],{"class":286},[280,3796,3797],{"class":307},"admin",[280,3799,1298],{"class":286},[280,3801,429],{"class":286},[280,3803,336],{"class":286},[280,3805,3806],{"class":307},"guest",[280,3808,1298],{"class":286},[280,3810,429],{"class":286},[280,3812,432],{"class":425},[280,3814,435],{"class":286},[280,3816,365],{"class":326},[280,3818,440],{"class":286},[280,3820,372],{"class":326},[280,3822,3823],{"class":282,"line":411},[280,3824,348],{"emptyLinePlaceholder":347},[280,3826,3827,3829,3832,3834],{"class":282,"line":445},[280,3828,482],{"class":294},[280,3830,3831],{"class":362}," promote",[280,3833,488],{"class":286},[280,3835,491],{"class":286},[280,3837,3838,3841,3843,3845,3847],{"class":282,"line":474},[280,3839,3840],{"class":326},"  isRoleOpen",[280,3842,500],{"class":286},[280,3844,503],{"class":326},[280,3846,506],{"class":286},[280,3848,509],{"class":368},[280,3850,3851],{"class":282,"line":479},[280,3852,515],{"class":286},[280,3854,3855],{"class":282,"line":494},[280,3856,348],{"emptyLinePlaceholder":347},[280,3858,3859,3861,3864,3866,3869,3871,3873,3875,3877,3879,3881,3883,3885,3887],{"class":282,"line":512},[280,3860,482],{"class":294},[280,3862,3863],{"class":362}," onRoleSelected",[280,3865,365],{"class":286},[280,3867,3868],{"class":608},"role",[280,3870,612],{"class":286},[280,3872,336],{"class":286},[280,3874,3797],{"class":307},[280,3876,1298],{"class":286},[280,3878,429],{"class":286},[280,3880,336],{"class":286},[280,3882,3806],{"class":307},[280,3884,1298],{"class":286},[280,3886,618],{"class":286},[280,3888,491],{"class":286},[280,3890,3891,3893,3895,3897,3899],{"class":282,"line":518},[280,3892,3840],{"class":326},[280,3894,500],{"class":286},[280,3896,503],{"class":326},[280,3898,506],{"class":286},[280,3900,541],{"class":368},[280,3902,3903,3906,3908,3910,3912],{"class":282,"line":530},[280,3904,3905],{"class":326},"  chosenRole",[280,3907,500],{"class":286},[280,3909,503],{"class":326},[280,3911,506],{"class":286},[280,3913,3914],{"class":326}," role\n",[280,3916,3917,3919,3921,3923,3925],{"class":282,"line":544},[280,3918,497],{"class":326},[280,3920,500],{"class":286},[280,3922,503],{"class":326},[280,3924,506],{"class":286},[280,3926,509],{"class":368},[280,3928,3929],{"class":282,"line":558},[280,3930,515],{"class":286},[280,3932,3933],{"class":282,"line":563},[280,3934,348],{"emptyLinePlaceholder":347},[280,3936,3937,3939,3942,3944],{"class":282,"line":575},[280,3938,482],{"class":294},[280,3940,3941],{"class":362}," onRoleCancelled",[280,3943,488],{"class":286},[280,3945,491],{"class":286},[280,3947,3948,3950,3952,3954,3956],{"class":282,"line":588},[280,3949,3840],{"class":326},[280,3951,500],{"class":286},[280,3953,503],{"class":326},[280,3955,506],{"class":286},[280,3957,541],{"class":368},[280,3959,3960],{"class":282,"line":593},[280,3961,515],{"class":286},[280,3963,3964],{"class":282,"line":598},[280,3965,348],{"emptyLinePlaceholder":347},[280,3967,3968,3970,3972,3974,3976],{"class":282,"line":623},[280,3969,1236],{"class":294},[280,3971,1239],{"class":294},[280,3973,523],{"class":362},[280,3975,488],{"class":286},[280,3977,491],{"class":286},[280,3979,3980,3982,3984,3986,3988],{"class":282,"line":638},[280,3981,497],{"class":326},[280,3983,500],{"class":286},[280,3985,503],{"class":326},[280,3987,506],{"class":286},[280,3989,541],{"class":368},[280,3991,3992,3994,3996,3999,4001,4003,4005],{"class":282,"line":652},[280,3993,1330],{"class":319},[280,3995,1333],{"class":290},[280,3997,3998],{"class":326},"chosenRole",[280,4000,500],{"class":286},[280,4002,503],{"class":326},[280,4004,1339],{"class":290},[280,4006,1866],{"class":286},[280,4008,4009,4012,4014,4016,4019,4021,4023,4025,4027],{"class":282,"line":657},[280,4010,4011],{"class":319},"    await",[280,4013,1345],{"class":326},[280,4015,500],{"class":286},[280,4017,4018],{"class":362},"promote",[280,4020,365],{"class":290},[280,4022,3998],{"class":326},[280,4024,500],{"class":286},[280,4026,503],{"class":326},[280,4028,372],{"class":290},[280,4030,4031],{"class":282,"line":669},[280,4032,1900],{"class":286},[280,4034,4035,4037,4039,4041,4043],{"class":282,"line":682},[280,4036,3905],{"class":326},[280,4038,500],{"class":286},[280,4040,503],{"class":326},[280,4042,506],{"class":286},[280,4044,693],{"class":286},[280,4046,4047],{"class":282,"line":696},[280,4048,515],{"class":286},[280,4050,4051],{"class":282,"line":701},[280,4052,348],{"emptyLinePlaceholder":347},[280,4054,4055,4057,4059,4061],{"class":282,"line":706},[280,4056,482],{"class":294},[280,4058,568],{"class":362},[280,4060,488],{"class":286},[280,4062,491],{"class":286},[280,4064,4065,4067,4069,4071,4073],{"class":282,"line":728},[280,4066,497],{"class":326},[280,4068,500],{"class":286},[280,4070,503],{"class":326},[280,4072,506],{"class":286},[280,4074,541],{"class":368},[280,4076,4077,4079,4081,4083,4085],{"class":282,"line":743},[280,4078,3905],{"class":326},[280,4080,500],{"class":286},[280,4082,503],{"class":326},[280,4084,506],{"class":286},[280,4086,693],{"class":286},[280,4088,4089],{"class":282,"line":757},[280,4090,515],{"class":286},[280,4092,4093,4095,4097],{"class":282,"line":762},[280,4094,808],{"class":286},[280,4096,291],{"class":290},[280,4098,313],{"class":286},[280,4100,4101],{"class":282,"line":774},[280,4102,348],{"emptyLinePlaceholder":347},[280,4104,4105,4107,4109],{"class":282,"line":787},[280,4106,287],{"class":286},[280,4108,825],{"class":290},[280,4110,313],{"class":286},[280,4112,4113,4115,4117,4119,4121,4123,4125,4127,4129,4132,4134,4136],{"class":282,"line":800},[280,4114,833],{"class":286},[280,4116,836],{"class":290},[280,4118,839],{"class":294},[280,4120,301],{"class":286},[280,4122,304],{"class":286},[280,4124,4018],{"class":307},[280,4126,304],{"class":286},[280,4128,435],{"class":286},[280,4130,4131],{"class":326},"Promote",[280,4133,808],{"class":286},[280,4135,836],{"class":290},[280,4137,313],{"class":286},[280,4139,4140],{"class":282,"line":805},[280,4141,348],{"emptyLinePlaceholder":347},[280,4143,4144,4146],{"class":282,"line":815},[280,4145,833],{"class":286},[280,4147,4148],{"class":290},"SelectRoleDialog\n",[280,4150,4151,4153,4155,4157,4160],{"class":282,"line":820},[280,4152,935],{"class":294},[280,4154,301],{"class":286},[280,4156,304],{"class":286},[280,4158,4159],{"class":307},"isRoleOpen",[280,4161,945],{"class":286},[280,4163,4164,4167,4169,4171,4174],{"class":282,"line":830},[280,4165,4166],{"class":294},"    @select",[280,4168,301],{"class":286},[280,4170,304],{"class":286},[280,4172,4173],{"class":307},"onRoleSelected",[280,4175,945],{"class":286},[280,4177,4178,4180,4182,4184,4187],{"class":282,"line":861},[280,4179,981],{"class":294},[280,4181,301],{"class":286},[280,4183,304],{"class":286},[280,4185,4186],{"class":307},"onRoleCancelled",[280,4188,945],{"class":286},[280,4190,4191],{"class":282,"line":890},[280,4192,996],{"class":286},[280,4194,4195,4197],{"class":282,"line":919},[280,4196,833],{"class":286},[280,4198,929],{"class":290},[280,4200,4201,4203,4205,4207,4210],{"class":282,"line":924},[280,4202,935],{"class":294},[280,4204,301],{"class":286},[280,4206,304],{"class":286},[280,4208,4209],{"class":307},"isConfirmOpen && chosenRole",[280,4211,945],{"class":286},[280,4213,4214,4217,4219,4221,4224],{"class":282,"line":932},[280,4215,4216],{"class":294},"    :title",[280,4218,301],{"class":286},[280,4220,304],{"class":286},[280,4222,4223],{"class":307},"`Promote to ${chosenRole}?`",[280,4225,945],{"class":286},[280,4227,4228,4230,4232,4234,4236],{"class":282,"line":948},[280,4229,966],{"class":294},[280,4231,301],{"class":286},[280,4233,304],{"class":286},[280,4235,973],{"class":307},[280,4237,945],{"class":286},[280,4239,4240,4242,4244,4246,4248],{"class":282,"line":963},[280,4241,981],{"class":294},[280,4243,301],{"class":286},[280,4245,304],{"class":286},[280,4247,988],{"class":307},[280,4249,945],{"class":286},[280,4251,4252],{"class":282,"line":978},[280,4253,996],{"class":286},[280,4255,4256,4258,4260],{"class":282,"line":993},[280,4257,808],{"class":286},[280,4259,825],{"class":290},[280,4261,313],{"class":286},[270,4263,4265],{"className":272,"code":4264,"filename":1137,"language":275,"meta":276,"style":276},"\u003Cscript setup lang=\"ts\">\nimport { openModal } from '@kolirt\u002Fvue-modal'\nimport SelectRoleDialog from '.\u002FSelectRoleDialog.vue'\nimport ConfirmDialog from '.\u002FConfirmDialog.vue'\n\nasync function promote() {\n  try {\n    const role = await openModal\u003C'admin' | 'guest'>(SelectRoleDialog)\n\n    const ok = await openModal\u003Cboolean>(ConfirmDialog, {\n      props: { title: `Promote to ${role}?` }\n    })\n\n    if (ok) await api.promote(role)\n  } catch {\n    \u002F\u002F user cancelled at any step — nothing to do\n  }\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cbutton @click=\"promote\">Promote\u003C\u002Fbutton>\n\u003C\u002Ftemplate>\n",[201,4266,4267,4287,4305,4321,4335,4339,4351,4358,4397,4401,4427,4460,4467,4471,4496,4505,4510,4514,4518,4526,4530,4538,4564],{"__ignoreMap":276},[280,4268,4269,4271,4273,4275,4277,4279,4281,4283,4285],{"class":282,"line":283},[280,4270,287],{"class":286},[280,4272,291],{"class":290},[280,4274,295],{"class":294},[280,4276,298],{"class":294},[280,4278,301],{"class":286},[280,4280,304],{"class":286},[280,4282,308],{"class":307},[280,4284,304],{"class":286},[280,4286,313],{"class":286},[280,4288,4289,4291,4293,4295,4297,4299,4301,4303],{"class":282,"line":316},[280,4290,320],{"class":319},[280,4292,323],{"class":286},[280,4294,1168],{"class":326},[280,4296,330],{"class":286},[280,4298,333],{"class":319},[280,4300,336],{"class":286},[280,4302,203],{"class":307},[280,4304,341],{"class":286},[280,4306,4307,4309,4312,4314,4316,4319],{"class":282,"line":344},[280,4308,320],{"class":319},[280,4310,4311],{"class":326}," SelectRoleDialog ",[280,4313,1188],{"class":319},[280,4315,336],{"class":286},[280,4317,4318],{"class":307},".\u002FSelectRoleDialog.vue",[280,4320,341],{"class":286},[280,4322,4323,4325,4327,4329,4331,4333],{"class":282,"line":351},[280,4324,320],{"class":319},[280,4326,1185],{"class":326},[280,4328,1188],{"class":319},[280,4330,336],{"class":286},[280,4332,1193],{"class":307},[280,4334,341],{"class":286},[280,4336,4337],{"class":282,"line":375},[280,4338,348],{"emptyLinePlaceholder":347},[280,4340,4341,4343,4345,4347,4349],{"class":282,"line":393},[280,4342,1236],{"class":294},[280,4344,1239],{"class":294},[280,4346,3831],{"class":362},[280,4348,488],{"class":286},[280,4350,491],{"class":286},[280,4352,4353,4356],{"class":282,"line":411},[280,4354,4355],{"class":319},"  try",[280,4357,491],{"class":286},[280,4359,4360,4363,4366,4368,4370,4372,4374,4376,4378,4380,4382,4384,4386,4388,4390,4392,4395],{"class":282,"line":445},[280,4361,4362],{"class":294},"    const",[280,4364,4365],{"class":326}," role",[280,4367,506],{"class":286},[280,4369,1258],{"class":319},[280,4371,1168],{"class":362},[280,4373,287],{"class":286},[280,4375,1298],{"class":286},[280,4377,3797],{"class":307},[280,4379,1298],{"class":286},[280,4381,429],{"class":286},[280,4383,336],{"class":286},[280,4385,3806],{"class":307},[280,4387,1298],{"class":286},[280,4389,435],{"class":286},[280,4391,365],{"class":290},[280,4393,4394],{"class":326},"SelectRoleDialog",[280,4396,372],{"class":290},[280,4398,4399],{"class":282,"line":474},[280,4400,348],{"emptyLinePlaceholder":347},[280,4402,4403,4405,4407,4409,4411,4413,4415,4417,4419,4421,4423,4425],{"class":282,"line":479},[280,4404,4362],{"class":294},[280,4406,1253],{"class":326},[280,4408,506],{"class":286},[280,4410,1258],{"class":319},[280,4412,1168],{"class":362},[280,4414,287],{"class":286},[280,4416,1265],{"class":425},[280,4418,435],{"class":286},[280,4420,365],{"class":290},[280,4422,1272],{"class":326},[280,4424,1275],{"class":286},[280,4426,491],{"class":286},[280,4428,4429,4432,4434,4436,4438,4440,4443,4446,4449,4451,4453,4455,4458],{"class":282,"line":494},[280,4430,4431],{"class":290},"      props",[280,4433,612],{"class":286},[280,4435,323],{"class":286},[280,4437,1289],{"class":290},[280,4439,612],{"class":286},[280,4441,4442],{"class":286}," `",[280,4444,4445],{"class":307},"Promote to ",[280,4447,4448],{"class":286},"${",[280,4450,3868],{"class":326},[280,4452,2107],{"class":286},[280,4454,2000],{"class":307},[280,4456,4457],{"class":286},"`",[280,4459,1301],{"class":286},[280,4461,4462,4465],{"class":282,"line":512},[280,4463,4464],{"class":286},"    }",[280,4466,372],{"class":290},[280,4468,4469],{"class":282,"line":518},[280,4470,348],{"emptyLinePlaceholder":347},[280,4472,4473,4476,4478,4480,4482,4484,4486,4488,4490,4492,4494],{"class":282,"line":530},[280,4474,4475],{"class":319},"    if",[280,4477,1333],{"class":290},[280,4479,1336],{"class":326},[280,4481,1339],{"class":290},[280,4483,1342],{"class":319},[280,4485,1345],{"class":326},[280,4487,500],{"class":286},[280,4489,4018],{"class":362},[280,4491,365],{"class":290},[280,4493,3868],{"class":326},[280,4495,372],{"class":290},[280,4497,4498,4500,4503],{"class":282,"line":544},[280,4499,1306],{"class":286},[280,4501,4502],{"class":319}," catch",[280,4504,491],{"class":286},[280,4506,4507],{"class":282,"line":558},[280,4508,4509],{"class":1653},"    \u002F\u002F user cancelled at any step — nothing to do\n",[280,4511,4512],{"class":282,"line":563},[280,4513,1900],{"class":286},[280,4515,4516],{"class":282,"line":575},[280,4517,515],{"class":286},[280,4519,4520,4522,4524],{"class":282,"line":588},[280,4521,808],{"class":286},[280,4523,291],{"class":290},[280,4525,313],{"class":286},[280,4527,4528],{"class":282,"line":593},[280,4529,348],{"emptyLinePlaceholder":347},[280,4531,4532,4534,4536],{"class":282,"line":598},[280,4533,287],{"class":286},[280,4535,825],{"class":290},[280,4537,313],{"class":286},[280,4539,4540,4542,4544,4546,4548,4550,4552,4554,4556,4558,4560,4562],{"class":282,"line":623},[280,4541,833],{"class":286},[280,4543,836],{"class":290},[280,4545,839],{"class":294},[280,4547,301],{"class":286},[280,4549,304],{"class":286},[280,4551,4018],{"class":307},[280,4553,304],{"class":286},[280,4555,435],{"class":286},[280,4557,4131],{"class":326},[280,4559,808],{"class":286},[280,4561,836],{"class":290},[280,4563,313],{"class":286},[280,4565,4566,4568,4570],{"class":282,"line":638},[280,4567,808],{"class":286},[280,4569,825],{"class":290},[280,4571,313],{"class":286},[198,4573,4574],{},"One linear function. Two awaits. One try\u002Fcatch wraps the whole sequence. No shared state stuck between handlers.",[1881,4576,4577],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":276,"searchDepth":316,"depth":316,"links":4579},[4580,4581],{"id":208,"depth":316,"text":209},{"id":252,"depth":316,"text":253,"children":4582},[4583,4584,4585,4586],{"id":257,"depth":344,"text":258},{"id":1632,"depth":344,"text":1633},{"id":2686,"depth":344,"text":2687},{"id":3681,"depth":344,"text":3682},"What @kolirt\u002Fvue-modal is and the problems it solves.","md",null,{},{"title":15,"description":4587},"yb8XLQU9awwarvblIrHDllCnFsl_krlpcWP56iEpf7w",[4594,4596],{"title":5,"path":6,"stem":7,"description":4595,"icon":8,"children":-1},"Interactive playground — toggle ModalTarget behavior, modal props, and the action you call, then run it live.",{"title":19,"path":20,"stem":21,"description":4597,"children":-1},"Install the package and register your modal groups.",1779523616803]