@adea-ai/ui 0.123.0 → 0.124.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/NOTICE +18 -0
  2. package/dist/components/layout/split-layout/resize-controller-core-retry.d.ts +13 -0
  3. package/dist/components/layout/split-layout/resize-controller-core-retry.d.ts.map +1 -0
  4. package/dist/components/layout/split-layout/resize-controller-core-retry.js +63 -0
  5. package/dist/components/layout/split-layout/resize-controller-core-retry.js.map +1 -0
  6. package/dist/components/layout/split-layout/resize-controller-core.d.ts +13 -0
  7. package/dist/components/layout/split-layout/resize-controller-core.d.ts.map +1 -0
  8. package/dist/components/layout/split-layout/resize-controller-core.js +63 -0
  9. package/dist/components/layout/split-layout/resize-controller-core.js.map +1 -0
  10. package/dist/components/layout/split-layout/resize-controller-retry-2.d.ts +3 -0
  11. package/dist/components/layout/split-layout/resize-controller-retry-2.d.ts.map +1 -0
  12. package/dist/components/layout/split-layout/resize-controller-retry-2.js +2 -0
  13. package/dist/components/layout/split-layout/resize-controller-retry.d.ts +2 -0
  14. package/dist/components/layout/split-layout/resize-controller-retry.d.ts.map +1 -0
  15. package/dist/components/layout/split-layout/resize-controller-retry.js +2 -0
  16. package/dist/components/layout/split-layout/resize-controller.d.ts +2 -0
  17. package/dist/components/layout/split-layout/resize-controller.d.ts.map +1 -0
  18. package/dist/components/layout/split-layout/resize-controller.js +2 -0
  19. package/dist/components/layout/split-layout/split-layout.d.ts.map +1 -1
  20. package/dist/components/layout/split-layout/split-layout.js +171 -60
  21. package/dist/components/layout/split-layout/split-layout.js.map +1 -1
  22. package/dist/components/theme/appearance-panel.js +1 -1
  23. package/dist/components/theme/index.d.ts +1 -1
  24. package/dist/components/theme/index.d.ts.map +1 -1
  25. package/dist/components/theme/index.js +5 -2
  26. package/dist/components/theme/theme-context.d.ts +13 -0
  27. package/dist/components/theme/theme-context.d.ts.map +1 -0
  28. package/dist/components/theme/theme-context.js +41 -0
  29. package/dist/components/theme/theme-context.js.map +1 -0
  30. package/dist/components/theme/theme-document.d.ts +76 -0
  31. package/dist/components/theme/theme-document.d.ts.map +1 -0
  32. package/dist/components/theme/theme-document.js +93 -0
  33. package/dist/components/theme/theme-document.js.map +1 -0
  34. package/dist/components/theme/theme-persistence.d.ts +50 -0
  35. package/dist/components/theme/theme-persistence.d.ts.map +1 -0
  36. package/dist/components/theme/theme-persistence.js +86 -0
  37. package/dist/components/theme/theme-persistence.js.map +1 -0
  38. package/dist/components/theme/theme-provider.d.ts +43 -75
  39. package/dist/components/theme/theme-provider.d.ts.map +1 -1
  40. package/dist/components/theme/theme-provider.js +50 -116
  41. package/dist/components/theme/theme-provider.js.map +1 -1
  42. package/dist/components/theme/theme-state.d.ts +142 -0
  43. package/dist/components/theme/theme-state.d.ts.map +1 -0
  44. package/dist/components/theme/theme-state.js +104 -0
  45. package/dist/components/theme/theme-state.js.map +1 -0
  46. package/dist/components/theme/theme-toggle.js +1 -1
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +6 -3
  50. package/dist/lib/appearance-font-settings.d.ts +1 -1
  51. package/dist/lib/appearance-font-settings.d.ts.map +1 -1
  52. package/dist/lib/appearance-font-settings.js.map +1 -1
  53. package/dist/lib/themes.d.ts +48 -0
  54. package/dist/lib/themes.d.ts.map +1 -1
  55. package/dist/lib/themes.js +150 -36
  56. package/dist/lib/themes.js.map +1 -1
  57. package/dist/r/registry.json +46 -0
  58. package/dist/r/split-layout.json +26 -0
  59. package/dist/r/src/components/layout/split-layout/resize-controller-core-retry.tsx +66 -0
  60. package/dist/r/src/components/layout/split-layout/resize-controller-core.tsx +66 -0
  61. package/dist/r/src/components/layout/split-layout/resize-controller-retry-2.tsx +2 -0
  62. package/dist/r/src/components/layout/split-layout/resize-controller-retry.tsx +1 -0
  63. package/dist/r/src/components/layout/split-layout/resize-controller.tsx +1 -0
  64. package/dist/r/src/components/layout/split-layout/split-layout.tsx +197 -49
  65. package/dist/r/src/components/theme/index.ts +3 -0
  66. package/dist/r/src/components/theme/theme-context.ts +43 -0
  67. package/dist/r/src/components/theme/theme-document.ts +168 -0
  68. package/dist/r/src/components/theme/theme-persistence.ts +140 -0
  69. package/dist/r/src/components/theme/theme-provider.tsx +126 -253
  70. package/dist/r/src/components/theme/theme-state.ts +225 -0
  71. package/dist/r/src/lib/appearance-font-settings.ts +1 -1
  72. package/dist/r/src/lib/themes.ts +181 -40
  73. package/dist/r/theming.json +20 -0
  74. package/package.json +1 -1
  75. package/registry.json +46 -0
  76. package/src/components/layout/split-layout/resize-controller-core-retry.tsx +66 -0
  77. package/src/components/layout/split-layout/resize-controller-core.tsx +66 -0
  78. package/src/components/layout/split-layout/resize-controller-retry-2.tsx +2 -0
  79. package/src/components/layout/split-layout/resize-controller-retry.tsx +1 -0
  80. package/src/components/layout/split-layout/resize-controller.tsx +1 -0
  81. package/src/components/layout/split-layout/split-layout.tsx +197 -49
  82. package/src/components/theme/index.ts +3 -0
  83. package/src/components/theme/theme-context.ts +43 -0
  84. package/src/components/theme/theme-document.ts +168 -0
  85. package/src/components/theme/theme-persistence.ts +140 -0
  86. package/src/components/theme/theme-provider.tsx +126 -253
  87. package/src/components/theme/theme-state.ts +225 -0
  88. package/src/index.ts +3 -0
  89. package/src/lib/appearance-font-settings.ts +1 -1
  90. package/src/lib/themes.ts +181 -40
package/dist/NOTICE CHANGED
@@ -300,6 +300,24 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
300
300
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
301
301
  SOFTWARE.
302
302
 
303
+ ## Theme resolution fallback translated from Zeron
304
+
305
+ `resolveVariant` in `packages/ui/src/lib/themes.ts` translates the fallback order
306
+ of Zeron's `ThemeRegistry::resolve` (https://github.com/zeronsh/zeron), as Adea's
307
+ accepted port of it in `packages/ui/src/components/appearance.ts` expresses it:
308
+ an id the registry does not hold resolves to the default variant of the same
309
+ appearance, then to any variant of that appearance, and never to a variant of the
310
+ other one. The provider's use of it, which leaves the stored id untouched, is the
311
+ Adea behaviour that port retains.
312
+
313
+ Copyright (c) 2026 Wing
314
+ Licensed under the MIT License.
315
+
316
+ Zeron's MIT notice, reproduced in full under "Appearance editor translated from
317
+ Zeron" above, applies to the translated portion. The ThemeProvider's preview,
318
+ persistence and document-application seams are written against Adea's provider
319
+ contract and introduce no further upstream source.
320
+
303
321
  ## Strict binary layout extracted from the accepted Adea donor port
304
322
 
305
323
  `packages/ui/src/components/layout/split-layout/model.ts` is extracted from
@@ -0,0 +1,13 @@
1
+ import { type Accessor, type JSX } from 'solid-js';
2
+ import { type SplitLayoutBranch, type SplitLayoutLeaf } from './model';
3
+ export type SplitLayoutResizeControllerProps<L extends SplitLayoutLeaf> = {
4
+ branch: Accessor<SplitLayoutBranch<L>>;
5
+ rect: Accessor<JSX.CSSProperties>;
6
+ domId: (id: string) => string;
7
+ root: () => HTMLDivElement | undefined;
8
+ labelForSeparator?: (branch: SplitLayoutBranch<L>) => string;
9
+ onResize: (splitId: string, ratio: number) => void;
10
+ };
11
+ /** Corvu stays behind the first real split while the pane owners remain mounted. */
12
+ export default function SplitLayoutResizeController<L extends SplitLayoutLeaf>(props: SplitLayoutResizeControllerProps<L>): JSX.Element;
13
+ //# sourceMappingURL=resize-controller-core-retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize-controller-core-retry.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/split-layout/resize-controller-core-retry.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACrB,MAAM,SAAS,CAAA;AAEhB,MAAM,MAAM,gCAAgC,CAAC,CAAC,SAAS,eAAe,IAAI;IACxE,MAAM,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAA;IACtC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IACjC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAA;IAC7B,IAAI,EAAE,MAAM,cAAc,GAAG,SAAS,CAAA;IACtC,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,MAAM,CAAA;IAC5D,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACnD,CAAA;AAED,oFAAoF;AACpF,MAAM,CAAC,OAAO,UAAU,2BAA2B,CAAC,CAAC,SAAS,eAAe,EAC3E,KAAK,EAAE,gCAAgC,CAAC,CAAC,CAAC,eA4C3C"}
@@ -0,0 +1,63 @@
1
+ import { MAX_SPLIT_RATIO, MIN_SPLIT_RATIO, listLeaves } from "./tree.js";
2
+ import { createComponent } from "solid-js/web";
3
+ import "solid-js";
4
+ import Resizable from "@corvu/resizable";
5
+ //#region src/components/layout/split-layout/resize-controller-core-retry.tsx
6
+ /** Corvu stays behind the first real split while the pane owners remain mounted. */
7
+ function SplitLayoutResizeController(props) {
8
+ const id = () => props.branch().id;
9
+ return createComponent(Resizable, {
10
+ get orientation() {
11
+ return props.branch().direction === "row" ? "horizontal" : "vertical";
12
+ },
13
+ get sizes() {
14
+ return [props.branch().ratio, 1 - props.branch().ratio];
15
+ },
16
+ keyboardDelta: .05,
17
+ onSizesChange: (sizes) => {
18
+ const root = props.root();
19
+ if (!root?.isConnected || root.getClientRects().length === 0) return;
20
+ if (sizes.length !== 2 || sizes.some((size) => !Number.isFinite(size)) || Math.abs(sizes[0] + sizes[1] - 1) > 1e-6) return;
21
+ if (sizes[0] !== void 0 && Math.abs(sizes[0] - props.branch().ratio) > 1e-6) props.onResize(id(), sizes[0]);
22
+ },
23
+ get style() {
24
+ return props.rect();
25
+ },
26
+ "class": "pointer-events-none absolute flex min-h-0 min-w-0 data-[orientation=vertical]:flex-col",
27
+ get children() {
28
+ return [
29
+ createComponent(Resizable.Panel, {
30
+ minSize: MIN_SPLIT_RATIO,
31
+ maxSize: MAX_SPLIT_RATIO,
32
+ "aria-hidden": "true"
33
+ }),
34
+ createComponent(Resizable.Handle, {
35
+ get ["aria-label"]() {
36
+ return props.labelForSeparator?.(props.branch()) ?? (props.branch().direction === "row" ? "Resize pane columns" : "Resize pane rows");
37
+ },
38
+ get ["aria-orientation"]() {
39
+ return props.branch().direction === "row" ? "vertical" : "horizontal";
40
+ },
41
+ get ["aria-controls"]() {
42
+ return listLeaves(props.branch()).map((leaf) => props.domId(leaf.id)).join(" ");
43
+ },
44
+ "aria-valuemin": 10,
45
+ "aria-valuemax": 90,
46
+ get ["aria-valuenow"]() {
47
+ return Math.round(props.branch().ratio * 100);
48
+ },
49
+ "class": "pointer-events-auto relative w-px shrink-0 bg-border after:absolute after:inset-y-0 after:-inset-x-1 after:w-3 focus-visible:bg-primary focus-visible:outline-none hover:bg-primary data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-1 data-[orientation=vertical]:after:h-3 data-[orientation=vertical]:after:w-full"
50
+ }),
51
+ createComponent(Resizable.Panel, {
52
+ minSize: MIN_SPLIT_RATIO,
53
+ maxSize: MAX_SPLIT_RATIO,
54
+ "aria-hidden": "true"
55
+ })
56
+ ];
57
+ }
58
+ });
59
+ }
60
+ //#endregion
61
+ export { SplitLayoutResizeController as default };
62
+
63
+ //# sourceMappingURL=resize-controller-core-retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize-controller-core-retry.js","names":["Resizable","Accessor","JSX","listLeaves","MIN_SPLIT_RATIO","MAX_SPLIT_RATIO","SplitLayoutBranch","SplitLayoutLeaf","SplitLayoutResizeControllerProps","branch","L","rect","CSSProperties","domId","id","root","HTMLDivElement","labelForSeparator","onResize","splitId","ratio","SplitLayoutResizeController","props","_$createComponent","orientation","direction","sizes","keyboardDelta","onSizesChange","isConnected","getClientRects","length","some","size","Number","isFinite","Math","abs","undefined","style","children","Panel","minSize","maxSize","Handle","aria-label","aria-orientation","aria-controls","map","leaf","join","aria-valuenow","round","_$createComponent"],"sources":["../../../../src/components/layout/split-layout/resize-controller-core-retry.tsx"],"sourcesContent":["import Resizable from '@corvu/resizable'\nimport { type Accessor, type JSX } from 'solid-js'\nimport {\n listLeaves,\n MIN_SPLIT_RATIO,\n MAX_SPLIT_RATIO,\n type SplitLayoutBranch,\n type SplitLayoutLeaf,\n} from './model'\n\nexport type SplitLayoutResizeControllerProps<L extends SplitLayoutLeaf> = {\n branch: Accessor<SplitLayoutBranch<L>>\n rect: Accessor<JSX.CSSProperties>\n domId: (id: string) => string\n root: () => HTMLDivElement | undefined\n labelForSeparator?: (branch: SplitLayoutBranch<L>) => string\n onResize: (splitId: string, ratio: number) => void\n}\n\n/** Corvu stays behind the first real split while the pane owners remain mounted. */\nexport default function SplitLayoutResizeController<L extends SplitLayoutLeaf>(\n props: SplitLayoutResizeControllerProps<L>\n) {\n const id = () => props.branch().id\n return (\n <Resizable\n orientation={props.branch().direction === 'row' ? 'horizontal' : 'vertical'}\n sizes={[props.branch().ratio, 1 - props.branch().ratio]}\n keyboardDelta={0.05}\n onSizesChange={(sizes) => {\n // Corvu also reports panel registration/unregistration while\n // mounting or disposing a controller. Those incomplete or\n // hidden-host sizes are not user resize intent.\n const root = props.root()\n if (!root?.isConnected || root.getClientRects().length === 0) return\n if (\n sizes.length !== 2 ||\n sizes.some((size) => !Number.isFinite(size)) ||\n Math.abs(sizes[0]! + sizes[1]! - 1) > 0.000001\n )\n return\n if (sizes[0] !== undefined && Math.abs(sizes[0] - props.branch().ratio) > 0.000001)\n props.onResize(id(), sizes[0])\n }}\n style={props.rect()}\n class=\"pointer-events-none absolute flex min-h-0 min-w-0 data-[orientation=vertical]:flex-col\"\n >\n <Resizable.Panel minSize={MIN_SPLIT_RATIO} maxSize={MAX_SPLIT_RATIO} aria-hidden=\"true\" />\n <Resizable.Handle\n aria-label={\n props.labelForSeparator?.(props.branch()) ??\n (props.branch().direction === 'row' ? 'Resize pane columns' : 'Resize pane rows')\n }\n aria-orientation={props.branch().direction === 'row' ? 'vertical' : 'horizontal'}\n aria-controls={listLeaves(props.branch())\n .map((leaf) => props.domId(leaf.id))\n .join(' ')}\n aria-valuemin={10}\n aria-valuemax={90}\n aria-valuenow={Math.round(props.branch().ratio * 100)}\n class=\"pointer-events-auto relative w-px shrink-0 bg-border after:absolute after:inset-y-0 after:-inset-x-1 after:w-3 focus-visible:bg-primary focus-visible:outline-none hover:bg-primary data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-1 data-[orientation=vertical]:after:h-3 data-[orientation=vertical]:after:w-full\"\n />\n <Resizable.Panel minSize={MIN_SPLIT_RATIO} maxSize={MAX_SPLIT_RATIO} aria-hidden=\"true\" />\n </Resizable>\n )\n}\n"],"mappings":";;;;;;AAoBA,SAAwBqB,4BACtBC,OACA;CACA,MAAMR,WAAWQ,MAAMb,OAAO,CAAC,CAACK;CAChC,OAAAS,gBACGvB,WAAS;EAAA,IACRwB,cAAW;GAAA,OAAEF,MAAMb,OAAO,CAAC,CAACgB,cAAc,QAAQ,eAAe;EAAU;EAAA,IAC3EC,QAAK;GAAA,OAAE,CAACJ,MAAMb,OAAO,CAAC,CAACW,OAAO,IAAIE,MAAMb,OAAO,CAAC,CAACW,KAAK;EAAC;EACvDO,eAAe;EACfC,gBAAgBF,UAAU;GAIxB,MAAMX,OAAOO,MAAMP,KAAK;GACxB,IAAI,CAACA,MAAMc,eAAed,KAAKe,eAAe,CAAC,CAACC,WAAW,GAAG;GAC9D,IACEL,MAAMK,WAAW,KACjBL,MAAMM,MAAMC,SAAS,CAACC,OAAOC,SAASF,IAAI,CAAC,KAC3CG,KAAKC,IAAIX,MAAM,KAAMA,MAAM,KAAM,CAAC,IAAI,MAEtC;GACF,IAAIA,MAAM,OAAOY,KAAAA,KAAaF,KAAKC,IAAIX,MAAM,KAAKJ,MAAMb,OAAO,CAAC,CAACW,KAAK,IAAI,MACxEE,MAAMJ,SAASJ,GAAG,GAAGY,MAAM,EAAE;EACjC;EAAC,IACDa,QAAK;GAAA,OAAEjB,MAAMX,KAAK;EAAC;EAAA,SAAA;EAAA,IAAA6B,WAAA;GAAA,OAAA;IAAAjB,gBAGlBvB,UAAUyC,OAAK;KAACC,SAAStC;KAAiBuC,SAAStC;KAAe,eAAA;IAAA,CAAA;IAAAkB,gBAClEvB,UAAU4C,QAAM;KAAA,KAAA,gBAAA;MAAA,OAEbtB,MAAML,oBAAoBK,MAAMb,OAAO,CAAC,MACvCa,MAAMb,OAAO,CAAC,CAACgB,cAAc,QAAQ,wBAAwB;KAAmB;KAAA,KAAA,sBAAA;MAAA,OAEjEH,MAAMb,OAAO,CAAC,CAACgB,cAAc,QAAQ,aAAa;KAAY;KAAA,KAAA,mBAAA;MAAA,OACjEtB,WAAWmB,MAAMb,OAAO,CAAC,CAAC,CACtCuC,KAAKC,SAAS3B,MAAMT,MAAMoC,KAAKnC,EAAE,CAAC,CAAC,CACnCoC,KAAK,GAAG;KAAC;KAAA,iBACG;KAAE,iBACF;KAAE,KAAA,mBAAA;MAAA,OACFd,KAAKgB,MAAM9B,MAAMb,OAAO,CAAC,CAACW,QAAQ,GAAG;KAAC;KAAA,SAAA;IAAA,CAAA;IAAAG,gBAGtDvB,UAAUyC,OAAK;KAACC,SAAStC;KAAiBuC,SAAStC;KAAe,eAAA;IAAA,CAAA;GAAA;EAAA;CAAA,CAAA;AAGzE"}
@@ -0,0 +1,13 @@
1
+ import { type Accessor, type JSX } from 'solid-js';
2
+ import { type SplitLayoutBranch, type SplitLayoutLeaf } from './model';
3
+ export type SplitLayoutResizeControllerProps<L extends SplitLayoutLeaf> = {
4
+ branch: Accessor<SplitLayoutBranch<L>>;
5
+ rect: Accessor<JSX.CSSProperties>;
6
+ domId: (id: string) => string;
7
+ root: () => HTMLDivElement | undefined;
8
+ labelForSeparator?: (branch: SplitLayoutBranch<L>) => string;
9
+ onResize: (splitId: string, ratio: number) => void;
10
+ };
11
+ /** Corvu stays behind the first real split while the pane owners remain mounted. */
12
+ export default function SplitLayoutResizeController<L extends SplitLayoutLeaf>(props: SplitLayoutResizeControllerProps<L>): JSX.Element;
13
+ //# sourceMappingURL=resize-controller-core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize-controller-core.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/split-layout/resize-controller-core.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACrB,MAAM,SAAS,CAAA;AAEhB,MAAM,MAAM,gCAAgC,CAAC,CAAC,SAAS,eAAe,IAAI;IACxE,MAAM,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAA;IACtC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IACjC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAA;IAC7B,IAAI,EAAE,MAAM,cAAc,GAAG,SAAS,CAAA;IACtC,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,MAAM,CAAA;IAC5D,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACnD,CAAA;AAED,oFAAoF;AACpF,MAAM,CAAC,OAAO,UAAU,2BAA2B,CAAC,CAAC,SAAS,eAAe,EAC3E,KAAK,EAAE,gCAAgC,CAAC,CAAC,CAAC,eA4C3C"}
@@ -0,0 +1,63 @@
1
+ import { MAX_SPLIT_RATIO, MIN_SPLIT_RATIO, listLeaves } from "./tree.js";
2
+ import { createComponent } from "solid-js/web";
3
+ import "solid-js";
4
+ import Resizable from "@corvu/resizable";
5
+ //#region src/components/layout/split-layout/resize-controller-core.tsx
6
+ /** Corvu stays behind the first real split while the pane owners remain mounted. */
7
+ function SplitLayoutResizeController(props) {
8
+ const id = () => props.branch().id;
9
+ return createComponent(Resizable, {
10
+ get orientation() {
11
+ return props.branch().direction === "row" ? "horizontal" : "vertical";
12
+ },
13
+ get sizes() {
14
+ return [props.branch().ratio, 1 - props.branch().ratio];
15
+ },
16
+ keyboardDelta: .05,
17
+ onSizesChange: (sizes) => {
18
+ const root = props.root();
19
+ if (!root?.isConnected || root.getClientRects().length === 0) return;
20
+ if (sizes.length !== 2 || sizes.some((size) => !Number.isFinite(size)) || Math.abs(sizes[0] + sizes[1] - 1) > 1e-6) return;
21
+ if (sizes[0] !== void 0 && Math.abs(sizes[0] - props.branch().ratio) > 1e-6) props.onResize(id(), sizes[0]);
22
+ },
23
+ get style() {
24
+ return props.rect();
25
+ },
26
+ "class": "pointer-events-none absolute flex min-h-0 min-w-0 data-[orientation=vertical]:flex-col",
27
+ get children() {
28
+ return [
29
+ createComponent(Resizable.Panel, {
30
+ minSize: MIN_SPLIT_RATIO,
31
+ maxSize: MAX_SPLIT_RATIO,
32
+ "aria-hidden": "true"
33
+ }),
34
+ createComponent(Resizable.Handle, {
35
+ get ["aria-label"]() {
36
+ return props.labelForSeparator?.(props.branch()) ?? (props.branch().direction === "row" ? "Resize pane columns" : "Resize pane rows");
37
+ },
38
+ get ["aria-orientation"]() {
39
+ return props.branch().direction === "row" ? "vertical" : "horizontal";
40
+ },
41
+ get ["aria-controls"]() {
42
+ return listLeaves(props.branch()).map((leaf) => props.domId(leaf.id)).join(" ");
43
+ },
44
+ "aria-valuemin": 10,
45
+ "aria-valuemax": 90,
46
+ get ["aria-valuenow"]() {
47
+ return Math.round(props.branch().ratio * 100);
48
+ },
49
+ "class": "pointer-events-auto relative w-px shrink-0 bg-border after:absolute after:inset-y-0 after:-inset-x-1 after:w-3 focus-visible:bg-primary focus-visible:outline-none hover:bg-primary data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-1 data-[orientation=vertical]:after:h-3 data-[orientation=vertical]:after:w-full"
50
+ }),
51
+ createComponent(Resizable.Panel, {
52
+ minSize: MIN_SPLIT_RATIO,
53
+ maxSize: MAX_SPLIT_RATIO,
54
+ "aria-hidden": "true"
55
+ })
56
+ ];
57
+ }
58
+ });
59
+ }
60
+ //#endregion
61
+ export { SplitLayoutResizeController as default };
62
+
63
+ //# sourceMappingURL=resize-controller-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize-controller-core.js","names":["Resizable","Accessor","JSX","listLeaves","MIN_SPLIT_RATIO","MAX_SPLIT_RATIO","SplitLayoutBranch","SplitLayoutLeaf","SplitLayoutResizeControllerProps","branch","L","rect","CSSProperties","domId","id","root","HTMLDivElement","labelForSeparator","onResize","splitId","ratio","SplitLayoutResizeController","props","_$createComponent","orientation","direction","sizes","keyboardDelta","onSizesChange","isConnected","getClientRects","length","some","size","Number","isFinite","Math","abs","undefined","style","children","Panel","minSize","maxSize","Handle","aria-label","aria-orientation","aria-controls","map","leaf","join","aria-valuenow","round","_$createComponent"],"sources":["../../../../src/components/layout/split-layout/resize-controller-core.tsx"],"sourcesContent":["import Resizable from '@corvu/resizable'\nimport { type Accessor, type JSX } from 'solid-js'\nimport {\n listLeaves,\n MIN_SPLIT_RATIO,\n MAX_SPLIT_RATIO,\n type SplitLayoutBranch,\n type SplitLayoutLeaf,\n} from './model'\n\nexport type SplitLayoutResizeControllerProps<L extends SplitLayoutLeaf> = {\n branch: Accessor<SplitLayoutBranch<L>>\n rect: Accessor<JSX.CSSProperties>\n domId: (id: string) => string\n root: () => HTMLDivElement | undefined\n labelForSeparator?: (branch: SplitLayoutBranch<L>) => string\n onResize: (splitId: string, ratio: number) => void\n}\n\n/** Corvu stays behind the first real split while the pane owners remain mounted. */\nexport default function SplitLayoutResizeController<L extends SplitLayoutLeaf>(\n props: SplitLayoutResizeControllerProps<L>\n) {\n const id = () => props.branch().id\n return (\n <Resizable\n orientation={props.branch().direction === 'row' ? 'horizontal' : 'vertical'}\n sizes={[props.branch().ratio, 1 - props.branch().ratio]}\n keyboardDelta={0.05}\n onSizesChange={(sizes) => {\n // Corvu also reports panel registration/unregistration while\n // mounting or disposing a controller. Those incomplete or\n // hidden-host sizes are not user resize intent.\n const root = props.root()\n if (!root?.isConnected || root.getClientRects().length === 0) return\n if (\n sizes.length !== 2 ||\n sizes.some((size) => !Number.isFinite(size)) ||\n Math.abs(sizes[0]! + sizes[1]! - 1) > 0.000001\n )\n return\n if (sizes[0] !== undefined && Math.abs(sizes[0] - props.branch().ratio) > 0.000001)\n props.onResize(id(), sizes[0])\n }}\n style={props.rect()}\n class=\"pointer-events-none absolute flex min-h-0 min-w-0 data-[orientation=vertical]:flex-col\"\n >\n <Resizable.Panel minSize={MIN_SPLIT_RATIO} maxSize={MAX_SPLIT_RATIO} aria-hidden=\"true\" />\n <Resizable.Handle\n aria-label={\n props.labelForSeparator?.(props.branch()) ??\n (props.branch().direction === 'row' ? 'Resize pane columns' : 'Resize pane rows')\n }\n aria-orientation={props.branch().direction === 'row' ? 'vertical' : 'horizontal'}\n aria-controls={listLeaves(props.branch())\n .map((leaf) => props.domId(leaf.id))\n .join(' ')}\n aria-valuemin={10}\n aria-valuemax={90}\n aria-valuenow={Math.round(props.branch().ratio * 100)}\n class=\"pointer-events-auto relative w-px shrink-0 bg-border after:absolute after:inset-y-0 after:-inset-x-1 after:w-3 focus-visible:bg-primary focus-visible:outline-none hover:bg-primary data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-1 data-[orientation=vertical]:after:h-3 data-[orientation=vertical]:after:w-full\"\n />\n <Resizable.Panel minSize={MIN_SPLIT_RATIO} maxSize={MAX_SPLIT_RATIO} aria-hidden=\"true\" />\n </Resizable>\n )\n}\n"],"mappings":";;;;;;AAoBA,SAAwBqB,4BACtBC,OACA;CACA,MAAMR,WAAWQ,MAAMb,OAAO,CAAC,CAACK;CAChC,OAAAS,gBACGvB,WAAS;EAAA,IACRwB,cAAW;GAAA,OAAEF,MAAMb,OAAO,CAAC,CAACgB,cAAc,QAAQ,eAAe;EAAU;EAAA,IAC3EC,QAAK;GAAA,OAAE,CAACJ,MAAMb,OAAO,CAAC,CAACW,OAAO,IAAIE,MAAMb,OAAO,CAAC,CAACW,KAAK;EAAC;EACvDO,eAAe;EACfC,gBAAgBF,UAAU;GAIxB,MAAMX,OAAOO,MAAMP,KAAK;GACxB,IAAI,CAACA,MAAMc,eAAed,KAAKe,eAAe,CAAC,CAACC,WAAW,GAAG;GAC9D,IACEL,MAAMK,WAAW,KACjBL,MAAMM,MAAMC,SAAS,CAACC,OAAOC,SAASF,IAAI,CAAC,KAC3CG,KAAKC,IAAIX,MAAM,KAAMA,MAAM,KAAM,CAAC,IAAI,MAEtC;GACF,IAAIA,MAAM,OAAOY,KAAAA,KAAaF,KAAKC,IAAIX,MAAM,KAAKJ,MAAMb,OAAO,CAAC,CAACW,KAAK,IAAI,MACxEE,MAAMJ,SAASJ,GAAG,GAAGY,MAAM,EAAE;EACjC;EAAC,IACDa,QAAK;GAAA,OAAEjB,MAAMX,KAAK;EAAC;EAAA,SAAA;EAAA,IAAA6B,WAAA;GAAA,OAAA;IAAAjB,gBAGlBvB,UAAUyC,OAAK;KAACC,SAAStC;KAAiBuC,SAAStC;KAAe,eAAA;IAAA,CAAA;IAAAkB,gBAClEvB,UAAU4C,QAAM;KAAA,KAAA,gBAAA;MAAA,OAEbtB,MAAML,oBAAoBK,MAAMb,OAAO,CAAC,MACvCa,MAAMb,OAAO,CAAC,CAACgB,cAAc,QAAQ,wBAAwB;KAAmB;KAAA,KAAA,sBAAA;MAAA,OAEjEH,MAAMb,OAAO,CAAC,CAACgB,cAAc,QAAQ,aAAa;KAAY;KAAA,KAAA,mBAAA;MAAA,OACjEtB,WAAWmB,MAAMb,OAAO,CAAC,CAAC,CACtCuC,KAAKC,SAAS3B,MAAMT,MAAMoC,KAAKnC,EAAE,CAAC,CAAC,CACnCoC,KAAK,GAAG;KAAC;KAAA,iBACG;KAAE,iBACF;KAAE,KAAA,mBAAA;MAAA,OACFd,KAAKgB,MAAM9B,MAAMb,OAAO,CAAC,CAACW,QAAQ,GAAG;KAAC;KAAA,SAAA;IAAA,CAAA;IAAAG,gBAGtDvB,UAAUyC,OAAK;KAACC,SAAStC;KAAiBuC,SAAStC;KAAe,eAAA;IAAA,CAAA;GAAA;EAAA;CAAA,CAAA;AAGzE"}
@@ -0,0 +1,3 @@
1
+ /** Independent module entrypoint to recover from a cached failed primary core import. */
2
+ export { default } from './resize-controller-core-retry';
3
+ //# sourceMappingURL=resize-controller-retry-2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize-controller-retry-2.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/split-layout/resize-controller-retry-2.tsx"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA"}
@@ -0,0 +1,2 @@
1
+ import SplitLayoutResizeController from "./resize-controller-core-retry.js";
2
+ export { SplitLayoutResizeController as default };
@@ -0,0 +1,2 @@
1
+ export { default } from './resize-controller-core';
2
+ //# sourceMappingURL=resize-controller-retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize-controller-retry.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/split-layout/resize-controller-retry.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,2 @@
1
+ import SplitLayoutResizeController from "./resize-controller-core.js";
2
+ export { SplitLayoutResizeController as default };
@@ -0,0 +1,2 @@
1
+ export { default } from './resize-controller-core';
2
+ //# sourceMappingURL=resize-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize-controller.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/split-layout/resize-controller.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,2 @@
1
+ import SplitLayoutResizeController from "./resize-controller-core.js";
2
+ export { SplitLayoutResizeController as default };
@@ -1 +1 @@
1
- {"version":3,"file":"split-layout.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/split-layout/split-layout.tsx"],"names":[],"mappings":"AACA,OAAO,EAQL,KAAK,QAAQ,EACb,KAAK,GAAG,EACT,MAAM,UAAU,CAAA;AAKjB,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,QAAQ,CAAA;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAI5C,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,SAAS,CAAA;AAEhB,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,eAAe,IAAI;IACxD,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,8DAA8D;IAC9D,YAAY,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAA;IACjC,yFAAyF;IACzF,UAAU,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAA;IAC9C,yFAAyF;IACzF,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAA;IACpD,+GAA+G;IAC/G,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IACrB,oFAAoF;IACpF,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,MAAM,CAAA;IAC5D,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,sFAAsF;IACtF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;IAChD,qGAAqG;IACrG,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,KAAK,IAAI,CAAA;IAC3E,qFAAqF;IACrF,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAA;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAqHD,mGAAmG;AACnG,wBAAgB,WAAW,CAAC,CAAC,SAAS,eAAe,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,eAsVhF"}
1
+ {"version":3,"file":"split-layout.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/split-layout/split-layout.tsx"],"names":[],"mappings":"AAAA,OAAO,EAWL,KAAK,QAAQ,EACb,KAAK,GAAG,EACT,MAAM,UAAU,CAAA;AAOjB,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,QAAQ,CAAA;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAI5C,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,SAAS,CAAA;AAQhB,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,eAAe,IAAI;IACxD,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,8DAA8D;IAC9D,YAAY,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAA;IACjC,yFAAyF;IACzF,UAAU,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAA;IAC9C,yFAAyF;IACzF,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAA;IACpD,+GAA+G;IAC/G,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IACrB,oFAAoF;IACpF,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,MAAM,CAAA;IAC5D,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,sFAAsF;IACtF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;IAChD,qGAAqG;IACrG,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,KAAK,IAAI,CAAA;IAC3E,qFAAqF;IACrF,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAA;IACtD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AA+HD,mGAAmG;AACnG,wBAAgB,WAAW,CAAC,CAAC,SAAS,eAAe,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,eAwdhF"}
@@ -1,16 +1,19 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
+ import { Button } from "../../ui/button/button.js";
2
3
  import { ActionButton } from "../../composites/action-button/action-button.js";
3
- import { MAX_SPLIT_RATIO, MIN_SPLIT_RATIO, listLeaves } from "./tree.js";
4
+ import { listLeaves } from "./tree.js";
4
5
  import { computeLayoutFrames } from "./geometry.js";
5
6
  import { paneDropIntent } from "./drop.js";
6
- import { className, createComponent, delegateEvents, effect, insert, memo, setAttribute, style, template, use } from "solid-js/web";
7
+ import { Dynamic, className, createComponent, delegateEvents, effect, insert, memo, setAttribute, style, template, use } from "solid-js/web";
7
8
  import { GripVertical, X } from "lucide-solid";
8
- import { For, createComputed, createMemo, createSignal, createUniqueId, on, onCleanup } from "solid-js";
9
- import Resizable from "@corvu/resizable";
9
+ import { For, Show, createComputed, createEffect, createMemo, createSignal, createUniqueId, on, onCleanup, onMount } from "solid-js";
10
10
  //#region src/components/layout/split-layout/split-layout.tsx
11
11
  var _tmpl$ = /*#__PURE__*/ template(`<div role=group data-slot=split-layout><span class=sr-only role=status>`);
12
12
  var _tmpl$2 = /*#__PURE__*/ template(`<section role=region class="absolute flex min-h-0 min-w-0 flex-col overflow-hidden border border-border transition-opacity motion-reduce:transition-none data-[drag-source]:opacity-40 data-[focused]:border-primary bg-background text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"><header class="flex min-w-0 shrink-0 items-center gap-2 bg-surface px-2"><span data-pane-drag-handle><span class="min-w-0 flex-1 truncate"></span></span></header><div class="min-h-0 min-w-0 flex-1 overflow-auto">`);
13
13
  var _tmpl$3 = /*#__PURE__*/ template(`<div aria-hidden=true>`);
14
+ var _tmpl$4 = /*#__PURE__*/ template(`<div role=separator aria-valuemin=10 aria-valuemax=90 aria-disabled=true tabindex=-1 class="pointer-events-none absolute bg-border">`);
15
+ var _tmpl$5 = /*#__PURE__*/ template(`<div class="absolute top-2 right-2 z-(--z-menu) flex max-w-sm flex-col items-end gap-2">`);
16
+ var _tmpl$6 = /*#__PURE__*/ template(`<p role=alert class="rounded-md border bg-background p-2 text-sm shadow-md">Reloading may discard unsaved pane content.`);
14
17
  var PANE_DRAG_TYPE = "application/x-adea-pane-move";
15
18
  var DRAG_PREVIEW_MAX_WIDTH = 384;
16
19
  var DRAG_PREVIEW_MAX_HEIGHT = 256;
@@ -22,6 +25,16 @@ function rectStyle(rect) {
22
25
  height: `${rect.height * 100}%`
23
26
  };
24
27
  }
28
+ function separatorPlaceholderStyle(branch, rect) {
29
+ const horizontal = branch.direction === "row";
30
+ return {
31
+ left: `${(rect.x + (horizontal ? rect.width * branch.ratio : 0)) * 100}%`,
32
+ top: `${(rect.y + (horizontal ? 0 : rect.height * branch.ratio)) * 100}%`,
33
+ width: horizontal ? "1px" : `${rect.width * 100}%`,
34
+ height: horizontal ? `${rect.height * 100}%` : "1px",
35
+ transform: horizontal ? "translateX(-50%)" : "translateY(-50%)"
36
+ };
37
+ }
25
38
  function dragPreviewPlaceholder(source, message) {
26
39
  const placeholder = document.createElement("div");
27
40
  placeholder.className = cn(source.getAttribute("class"), "flex min-h-8 min-w-0 items-center justify-center bg-muted px-2 text-center text-xs text-muted-foreground");
@@ -119,14 +132,40 @@ function cloneDragPreviewNode(source) {
119
132
  function SplitLayout(props) {
120
133
  let root;
121
134
  let pendingFrame;
135
+ let disposed = false;
136
+ let resizeLoadGeneration = 0;
137
+ let retryWithAlternateImport = false;
138
+ let alternateImportAttempts = 0;
139
+ let focusHandleAfterRetry = false;
140
+ let focusRecoveryButtonAfterError = false;
141
+ let focusRestoreEpoch = 0;
142
+ let focusEpoch = 0;
143
+ let pendingFocusFrame;
122
144
  const refs = /* @__PURE__ */ new Map();
123
145
  const domIds = /* @__PURE__ */ new Map();
124
146
  const prefix = createUniqueId();
147
+ const resizeReloadWarningId = `${prefix}-resize-reload-warning`;
125
148
  let nextDomId = 0;
126
149
  let nextDragId = 0;
127
150
  let dragPreview;
128
151
  const [drag, setDrag] = createSignal();
129
152
  const [drop, setDrop] = createSignal();
153
+ const [resizeController, setResizeController] = createSignal();
154
+ const cancelPendingFocusRestore = () => {
155
+ if (pendingFocusFrame !== void 0) cancelAnimationFrame(pendingFocusFrame);
156
+ pendingFocusFrame = void 0;
157
+ };
158
+ const trackFocusChange = (event) => {
159
+ if (event.target === document.body) return;
160
+ focusEpoch += 1;
161
+ focusHandleAfterRetry = false;
162
+ focusRecoveryButtonAfterError = false;
163
+ cancelPendingFocusRestore();
164
+ };
165
+ onMount(() => {
166
+ document.addEventListener("focusin", trackFocusChange);
167
+ onCleanup(() => document.removeEventListener("focusin", trackFocusChange));
168
+ });
130
169
  const clearDrag = () => {
131
170
  setDrag(void 0);
132
171
  setDrop(void 0);
@@ -164,6 +203,46 @@ function SplitLayout(props) {
164
203
  const leafMap = createMemo(() => new Map(leaves().map((leaf) => [leaf.id, leaf])));
165
204
  const frames = createMemo(() => computeLayoutFrames(props.state.center));
166
205
  const branches = createMemo(() => Array.from(frames().values()).flatMap((frame) => frame.node.kind === "split" ? [frame.node] : []));
206
+ createEffect(() => {
207
+ if (branches().length === 0) {
208
+ resizeLoadGeneration += 1;
209
+ focusHandleAfterRetry = false;
210
+ focusRecoveryButtonAfterError = false;
211
+ cancelPendingFocusRestore();
212
+ if (resizeController() === false || resizeController() === "error") setResizeController(void 0);
213
+ return;
214
+ }
215
+ if (resizeController() !== void 0) return;
216
+ const retry = retryWithAlternateImport;
217
+ const generation = ++resizeLoadGeneration;
218
+ setResizeController(false);
219
+ (retry ? alternateImportAttempts++ === 0 ? import("./resize-controller-retry.js") : import("./resize-controller-retry-2.js") : import("./resize-controller.js")).then(({ default: Controller }) => {
220
+ if (disposed || generation !== resizeLoadGeneration || branches().length === 0) return;
221
+ const shouldFocusHandle = focusHandleAfterRetry && focusEpoch === focusRestoreEpoch;
222
+ focusHandleAfterRetry = false;
223
+ focusRecoveryButtonAfterError = false;
224
+ retryWithAlternateImport = false;
225
+ alternateImportAttempts = 0;
226
+ setResizeController(() => Controller);
227
+ if (shouldFocusHandle) pendingFocusFrame = requestAnimationFrame(() => {
228
+ pendingFocusFrame = void 0;
229
+ if (disposed || generation !== resizeLoadGeneration || branches().length === 0 || focusEpoch !== focusRestoreEpoch) return;
230
+ const currentFocus = root?.ownerDocument.activeElement;
231
+ if (currentFocus && currentFocus !== root?.ownerDocument.body && currentFocus !== root) return;
232
+ root?.querySelector("[data-corvu-resizable-handle]")?.focus({ preventScroll: true });
233
+ });
234
+ }, () => {
235
+ retryWithAlternateImport = true;
236
+ if (!disposed && generation === resizeLoadGeneration && branches().length > 0) {
237
+ setResizeController("error");
238
+ if (focusRecoveryButtonAfterError && focusEpoch === focusRestoreEpoch) pendingFocusFrame = requestAnimationFrame(() => {
239
+ pendingFocusFrame = void 0;
240
+ if (disposed || generation !== resizeLoadGeneration || branches().length === 0 || focusEpoch !== focusRestoreEpoch) return;
241
+ root?.querySelector("[data-resize-retry]")?.focus({ preventScroll: true });
242
+ });
243
+ }
244
+ });
245
+ });
167
246
  createComputed(() => {
168
247
  const current = drag();
169
248
  if (current && (!props.onMove || !leafMap().has(current.id))) clearDrag();
@@ -205,6 +284,10 @@ function SplitLayout(props) {
205
284
  });
206
285
  }));
207
286
  onCleanup(() => {
287
+ disposed = true;
288
+ focusHandleAfterRetry = false;
289
+ focusRecoveryButtonAfterError = false;
290
+ cancelPendingFocusRestore();
208
291
  if (pendingFrame !== void 0) cancelAnimationFrame(pendingFrame);
209
292
  clearDrag();
210
293
  refs.clear();
@@ -291,8 +374,8 @@ function SplitLayout(props) {
291
374
  }
292
375
  });
293
376
  insert(_el$5, (() => {
294
- var _c$ = memo(() => !!props.onMove);
295
- return () => _c$() ? createComponent(GripVertical, {
377
+ var _c$2 = memo(() => !!props.onMove);
378
+ return () => _c$2() ? createComponent(GripVertical, {
296
379
  "class": "size-3 shrink-0",
297
380
  "aria-hidden": "true"
298
381
  }) : null;
@@ -300,8 +383,8 @@ function SplitLayout(props) {
300
383
  insert(_el$6, () => paneLabel ?? props.labelForLeaf(leaf()));
301
384
  insert(_el$4, actions, null);
302
385
  insert(_el$4, (() => {
303
- var _c$2 = memo(() => !!props.onClose);
304
- return () => _c$2() ? createComponent(ActionButton, {
386
+ var _c$3 = memo(() => !!props.onClose);
387
+ return () => _c$3() ? createComponent(ActionButton, {
305
388
  variant: "ghost",
306
389
  size: "icon-xs",
307
390
  get ["aria-label"]() {
@@ -318,8 +401,8 @@ function SplitLayout(props) {
318
401
  })(), null);
319
402
  insert(_el$7, content);
320
403
  insert(_el$3, (() => {
321
- var _c$3 = memo(() => !!intent());
322
- return () => _c$3() ? (() => {
404
+ var _c$4 = memo(() => !!intent());
405
+ return () => _c$4() ? (() => {
323
406
  var _el$8 = _tmpl$3();
324
407
  effect(() => className(_el$8, cn("pointer-events-none absolute border-2 border-primary bg-primary/10", {
325
408
  "inset-y-0 left-0 w-1/2": intent()?.direction === "row" && intent()?.placement === "before",
@@ -369,7 +452,7 @@ function SplitLayout(props) {
369
452
  })();
370
453
  }
371
454
  }), _el$2);
372
- insert(_el$2, dropLabel);
455
+ insert(_el$2, () => dropLabel() || (resizeController() === "error" ? alternateImportAttempts >= 2 ? "Resize controls did not load after repeated attempts. Reloading may discard unsaved pane content." : "Resize controls did not load." : ""));
373
456
  insert(_el$, createComponent(For, {
374
457
  get each() {
375
458
  return branches().map((branch) => branch.id);
@@ -377,62 +460,90 @@ function SplitLayout(props) {
377
460
  children: (id) => {
378
461
  const initial = branchMap().get(id);
379
462
  const branch = () => branchMap().get(id) ?? initial;
380
- return createComponent(Resizable, {
381
- get orientation() {
382
- return branch().direction === "row" ? "horizontal" : "vertical";
383
- },
384
- get sizes() {
385
- return [branch().ratio, 1 - branch().ratio];
463
+ const rect = () => frames().get(id)?.rect ?? {
464
+ x: 0,
465
+ y: 0,
466
+ width: 0,
467
+ height: 0
468
+ };
469
+ return createComponent(Show, {
470
+ get when() {
471
+ return typeof resizeController() === "function";
386
472
  },
387
- keyboardDelta: .05,
388
- onSizesChange: (sizes) => {
389
- if (!root?.isConnected || root.getClientRects().length === 0) return;
390
- if (sizes.length !== 2 || sizes.some((size) => !Number.isFinite(size)) || Math.abs(sizes[0] + sizes[1] - 1) > 1e-6) return;
391
- if (sizes[0] !== void 0 && Math.abs(sizes[0] - branch().ratio) > 1e-6) props.onResize(id, sizes[0]);
473
+ get fallback() {
474
+ return (() => {
475
+ var _el$9 = _tmpl$4();
476
+ effect((_p$) => {
477
+ var _v$13 = props.labelForSeparator?.(branch()) ?? (branch().direction === "row" ? "Resize pane columns" : "Resize pane rows"), _v$14 = branch().direction === "row" ? "vertical" : "horizontal", _v$15 = listLeaves(branch()).map((leaf) => domId(leaf.id)).join(" "), _v$16 = Math.round(branch().ratio * 100), _v$17 = branch().direction, _v$18 = separatorPlaceholderStyle(branch(), rect());
478
+ _v$13 !== _p$.e && setAttribute(_el$9, "aria-label", _p$.e = _v$13);
479
+ _v$14 !== _p$.t && setAttribute(_el$9, "aria-orientation", _p$.t = _v$14);
480
+ _v$15 !== _p$.a && setAttribute(_el$9, "aria-controls", _p$.a = _v$15);
481
+ _v$16 !== _p$.o && setAttribute(_el$9, "aria-valuenow", _p$.o = _v$16);
482
+ _v$17 !== _p$.i && setAttribute(_el$9, "data-direction", _p$.i = _v$17);
483
+ _p$.n = style(_el$9, _v$18, _p$.n);
484
+ return _p$;
485
+ }, {
486
+ e: void 0,
487
+ t: void 0,
488
+ a: void 0,
489
+ o: void 0,
490
+ i: void 0,
491
+ n: void 0
492
+ });
493
+ return _el$9;
494
+ })();
392
495
  },
393
- get style() {
394
- return rectStyle(frames().get(id)?.rect ?? {
395
- x: 0,
396
- y: 0,
397
- width: 0,
398
- height: 0
399
- });
400
- },
401
- "class": "pointer-events-none absolute flex min-h-0 min-w-0 data-[orientation=vertical]:flex-col",
402
496
  get children() {
403
- return [
404
- createComponent(Resizable.Panel, {
405
- minSize: MIN_SPLIT_RATIO,
406
- maxSize: MAX_SPLIT_RATIO,
407
- "aria-hidden": "true"
408
- }),
409
- createComponent(Resizable.Handle, {
410
- get ["aria-label"]() {
411
- return props.labelForSeparator?.(branch()) ?? (branch().direction === "row" ? "Resize pane columns" : "Resize pane rows");
412
- },
413
- get ["aria-orientation"]() {
414
- return branch().direction === "row" ? "vertical" : "horizontal";
415
- },
416
- get ["aria-controls"]() {
417
- return listLeaves(branch()).map((leaf) => domId(leaf.id)).join(" ");
418
- },
419
- "aria-valuemin": 10,
420
- "aria-valuemax": 90,
421
- get ["aria-valuenow"]() {
422
- return Math.round(branch().ratio * 100);
423
- },
424
- "class": "pointer-events-auto relative w-px shrink-0 bg-border after:absolute after:inset-y-0 after:-inset-x-1 after:w-3 focus-visible:bg-primary focus-visible:outline-none hover:bg-primary data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-1 data-[orientation=vertical]:after:h-3 data-[orientation=vertical]:after:w-full"
425
- }),
426
- createComponent(Resizable.Panel, {
427
- minSize: MIN_SPLIT_RATIO,
428
- maxSize: MAX_SPLIT_RATIO,
429
- "aria-hidden": "true"
430
- })
431
- ];
497
+ return createComponent(Dynamic, {
498
+ get component() {
499
+ return resizeController();
500
+ },
501
+ branch,
502
+ rect: () => rectStyle(rect()),
503
+ domId,
504
+ root: () => root,
505
+ get labelForSeparator() {
506
+ return props.labelForSeparator;
507
+ },
508
+ get onResize() {
509
+ return props.onResize;
510
+ }
511
+ });
432
512
  }
433
513
  });
434
514
  }
435
515
  }), null);
516
+ insert(_el$, (() => {
517
+ var _c$ = memo(() => resizeController() === "error");
518
+ return () => _c$() ? (() => {
519
+ var _el$0 = _tmpl$5();
520
+ insert(_el$0, alternateImportAttempts >= 2 ? (() => {
521
+ var _el$1 = _tmpl$6();
522
+ setAttribute(_el$1, "id", resizeReloadWarningId);
523
+ return _el$1;
524
+ })() : null, null);
525
+ insert(_el$0, createComponent(Button, {
526
+ variant: "outline",
527
+ size: "sm",
528
+ "data-resize-retry": true,
529
+ "aria-describedby": alternateImportAttempts >= 2 ? resizeReloadWarningId : void 0,
530
+ onClick: (event) => {
531
+ if (alternateImportAttempts >= 2) {
532
+ window.location.reload();
533
+ return;
534
+ }
535
+ const ownsFocus = document.activeElement === event.currentTarget;
536
+ focusHandleAfterRetry = ownsFocus;
537
+ focusRecoveryButtonAfterError = ownsFocus;
538
+ focusRestoreEpoch = focusEpoch;
539
+ retryWithAlternateImport = true;
540
+ setResizeController(void 0);
541
+ },
542
+ children: alternateImportAttempts >= 2 ? "Reload page to retry resizing" : "Retry pane resizing"
543
+ }), null);
544
+ return _el$0;
545
+ })() : null;
546
+ })(), null);
436
547
  effect((_p$) => {
437
548
  var _v$ = props.label, _v$2 = drag() ? "" : void 0, _v$3 = cn("relative size-full min-h-0 min-w-0 data-[dragging]:cursor-grabbing", props.class);
438
549
  _v$ !== _p$.e && setAttribute(_el$, "aria-label", _p$.e = _v$);