@kywi-software/core 0.11.0 → 0.12.1

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 (216) hide show
  1. package/AGENT-PATTERNS.md +96 -10
  2. package/dist/admin/content-form.d.ts.map +1 -1
  3. package/dist/admin/content-form.js +97 -10
  4. package/dist/admin/content-form.js.map +1 -1
  5. package/dist/admin/layout-editor/component-actions.d.ts +219 -22
  6. package/dist/admin/layout-editor/component-actions.d.ts.map +1 -1
  7. package/dist/admin/layout-editor/component-actions.js +356 -36
  8. package/dist/admin/layout-editor/component-actions.js.map +1 -1
  9. package/dist/admin/layout-editor/component-fork.d.ts +224 -0
  10. package/dist/admin/layout-editor/component-fork.d.ts.map +1 -0
  11. package/dist/admin/layout-editor/component-fork.js +342 -0
  12. package/dist/admin/layout-editor/component-fork.js.map +1 -0
  13. package/dist/admin/layout-editor/editor-canvas.d.ts +12 -0
  14. package/dist/admin/layout-editor/editor-canvas.d.ts.map +1 -1
  15. package/dist/admin/layout-editor/editor-canvas.js +76 -12
  16. package/dist/admin/layout-editor/editor-canvas.js.map +1 -1
  17. package/dist/admin/layout-editor/editor-dialog.d.ts +164 -0
  18. package/dist/admin/layout-editor/editor-dialog.d.ts.map +1 -0
  19. package/dist/admin/layout-editor/editor-dialog.js +195 -0
  20. package/dist/admin/layout-editor/editor-dialog.js.map +1 -0
  21. package/dist/admin/layout-editor/editor-state.d.ts +76 -0
  22. package/dist/admin/layout-editor/editor-state.d.ts.map +1 -1
  23. package/dist/admin/layout-editor/editor-state.js +47 -1
  24. package/dist/admin/layout-editor/editor-state.js.map +1 -1
  25. package/dist/admin/layout-editor/editor.css +279 -2
  26. package/dist/admin/layout-editor/index.d.ts +10 -1
  27. package/dist/admin/layout-editor/index.d.ts.map +1 -1
  28. package/dist/admin/layout-editor/index.js +11 -1
  29. package/dist/admin/layout-editor/index.js.map +1 -1
  30. package/dist/admin/layout-editor/layout-editor.d.ts +58 -1
  31. package/dist/admin/layout-editor/layout-editor.d.ts.map +1 -1
  32. package/dist/admin/layout-editor/layout-editor.js +161 -190
  33. package/dist/admin/layout-editor/layout-editor.js.map +1 -1
  34. package/dist/admin/layout-editor/linked-component.d.ts +38 -0
  35. package/dist/admin/layout-editor/linked-component.d.ts.map +1 -0
  36. package/dist/admin/layout-editor/linked-component.js +42 -0
  37. package/dist/admin/layout-editor/linked-component.js.map +1 -0
  38. package/dist/admin/layout-editor/module-overlay.d.ts +10 -1
  39. package/dist/admin/layout-editor/module-overlay.d.ts.map +1 -1
  40. package/dist/admin/layout-editor/module-overlay.js +33 -4
  41. package/dist/admin/layout-editor/module-overlay.js.map +1 -1
  42. package/dist/admin/layout-editor/node-lookup.d.ts +34 -0
  43. package/dist/admin/layout-editor/node-lookup.d.ts.map +1 -1
  44. package/dist/admin/layout-editor/node-lookup.js +90 -0
  45. package/dist/admin/layout-editor/node-lookup.js.map +1 -1
  46. package/dist/admin/layout-editor/overlay-shell.d.ts.map +1 -1
  47. package/dist/admin/layout-editor/overlay-shell.js +114 -23
  48. package/dist/admin/layout-editor/overlay-shell.js.map +1 -1
  49. package/dist/admin/layout-editor/props-panel.d.ts +55 -1
  50. package/dist/admin/layout-editor/props-panel.d.ts.map +1 -1
  51. package/dist/admin/layout-editor/props-panel.js +118 -9
  52. package/dist/admin/layout-editor/props-panel.js.map +1 -1
  53. package/dist/admin/layout-editor/section-overlay.d.ts +9 -1
  54. package/dist/admin/layout-editor/section-overlay.d.ts.map +1 -1
  55. package/dist/admin/layout-editor/section-overlay.js +14 -4
  56. package/dist/admin/layout-editor/section-overlay.js.map +1 -1
  57. package/dist/admin/layout-editor/section-template-picker.d.ts +27 -1
  58. package/dist/admin/layout-editor/section-template-picker.d.ts.map +1 -1
  59. package/dist/admin/layout-editor/section-template-picker.js +71 -17
  60. package/dist/admin/layout-editor/section-template-picker.js.map +1 -1
  61. package/dist/admin/layout-editor/use-component-connect.d.ts +65 -0
  62. package/dist/admin/layout-editor/use-component-connect.d.ts.map +1 -0
  63. package/dist/admin/layout-editor/use-component-connect.js +294 -0
  64. package/dist/admin/layout-editor/use-component-connect.js.map +1 -0
  65. package/dist/admin/layout-editor/use-component-fork.d.ts +123 -0
  66. package/dist/admin/layout-editor/use-component-fork.d.ts.map +1 -0
  67. package/dist/admin/layout-editor/use-component-fork.js +346 -0
  68. package/dist/admin/layout-editor/use-component-fork.js.map +1 -0
  69. package/dist/admin/layout-editor/use-component-library.d.ts +94 -0
  70. package/dist/admin/layout-editor/use-component-library.d.ts.map +1 -0
  71. package/dist/admin/layout-editor/use-component-library.js +55 -0
  72. package/dist/admin/layout-editor/use-component-library.js.map +1 -0
  73. package/dist/admin/registry.d.ts +11 -2
  74. package/dist/admin/registry.d.ts.map +1 -1
  75. package/dist/admin/registry.js +40 -4
  76. package/dist/admin/registry.js.map +1 -1
  77. package/dist/admin/server.d.ts +1 -0
  78. package/dist/admin/server.d.ts.map +1 -1
  79. package/dist/admin/server.js +5 -0
  80. package/dist/admin/server.js.map +1 -1
  81. package/dist/admin/styles/admin.css +43 -0
  82. package/dist/admin/surfaces/components/component-edit.d.ts +3 -0
  83. package/dist/admin/surfaces/components/component-edit.d.ts.map +1 -0
  84. package/dist/admin/surfaces/components/component-edit.js +235 -0
  85. package/dist/admin/surfaces/components/component-edit.js.map +1 -0
  86. package/dist/admin/surfaces/components/components-data.d.ts +153 -0
  87. package/dist/admin/surfaces/components/components-data.d.ts.map +1 -0
  88. package/dist/admin/surfaces/components/components-data.js +154 -0
  89. package/dist/admin/surfaces/components/components-data.js.map +1 -0
  90. package/dist/admin/surfaces/components/components-list.d.ts +3 -0
  91. package/dist/admin/surfaces/components/components-list.d.ts.map +1 -0
  92. package/dist/admin/surfaces/components/components-list.js +196 -0
  93. package/dist/admin/surfaces/components/components-list.js.map +1 -0
  94. package/dist/admin/surfaces/components/definition-canvas.d.ts +73 -0
  95. package/dist/admin/surfaces/components/definition-canvas.d.ts.map +1 -0
  96. package/dist/admin/surfaces/components/definition-canvas.js +207 -0
  97. package/dist/admin/surfaces/components/definition-canvas.js.map +1 -0
  98. package/dist/admin/surfaces/layouts/layout-editor-client.d.ts.map +1 -1
  99. package/dist/admin/surfaces/layouts/layout-editor-client.js +14 -2
  100. package/dist/admin/surfaces/layouts/layout-editor-client.js.map +1 -1
  101. package/dist/admin/surfaces/layouts/layouts-data.d.ts +3 -14
  102. package/dist/admin/surfaces/layouts/layouts-data.d.ts.map +1 -1
  103. package/dist/admin/surfaces/layouts/layouts-data.js +4 -7
  104. package/dist/admin/surfaces/layouts/layouts-data.js.map +1 -1
  105. package/dist/admin/surfaces/layouts/layouts-list.d.ts.map +1 -1
  106. package/dist/admin/surfaces/layouts/layouts-list.js +16 -22
  107. package/dist/admin/surfaces/layouts/layouts-list.js.map +1 -1
  108. package/dist/admin/surfaces/settings/admin-features.d.ts.map +1 -1
  109. package/dist/admin/surfaces/settings/admin-features.js +1 -0
  110. package/dist/admin/surfaces/settings/admin-features.js.map +1 -1
  111. package/dist/api/bulk-routes.d.ts.map +1 -1
  112. package/dist/api/bulk-routes.js +25 -0
  113. package/dist/api/bulk-routes.js.map +1 -1
  114. package/dist/api/changeset-routes.d.ts.map +1 -1
  115. package/dist/api/changeset-routes.js +17 -3
  116. package/dist/api/changeset-routes.js.map +1 -1
  117. package/dist/api/component-routes.d.ts.map +1 -1
  118. package/dist/api/component-routes.js +228 -8
  119. package/dist/api/component-routes.js.map +1 -1
  120. package/dist/api/content-routes.d.ts.map +1 -1
  121. package/dist/api/content-routes.js +64 -0
  122. package/dist/api/content-routes.js.map +1 -1
  123. package/dist/api/feed-routes.d.ts +6 -6
  124. package/dist/api/graphql/resolvers.d.ts +4 -4
  125. package/dist/api/layout-routes.d.ts.map +1 -1
  126. package/dist/api/layout-routes.js +4 -17
  127. package/dist/api/layout-routes.js.map +1 -1
  128. package/dist/api/layout-write-guard.d.ts +80 -0
  129. package/dist/api/layout-write-guard.d.ts.map +1 -0
  130. package/dist/api/layout-write-guard.js +88 -0
  131. package/dist/api/layout-write-guard.js.map +1 -0
  132. package/dist/api/section-template-routes.d.ts.map +1 -1
  133. package/dist/api/section-template-routes.js +11 -0
  134. package/dist/api/section-template-routes.js.map +1 -1
  135. package/dist/api/translation-routes.d.ts.map +1 -1
  136. package/dist/api/translation-routes.js +8 -0
  137. package/dist/api/translation-routes.js.map +1 -1
  138. package/dist/api/version-routes.d.ts.map +1 -1
  139. package/dist/api/version-routes.js +20 -8
  140. package/dist/api/version-routes.js.map +1 -1
  141. package/dist/api/workflow-routes.d.ts.map +1 -1
  142. package/dist/api/workflow-routes.js +53 -8
  143. package/dist/api/workflow-routes.js.map +1 -1
  144. package/dist/db/analytics-queries.d.ts +3 -3
  145. package/dist/db/apply-snapshot.d.ts +75 -8
  146. package/dist/db/apply-snapshot.d.ts.map +1 -1
  147. package/dist/db/apply-snapshot.js +104 -8
  148. package/dist/db/apply-snapshot.js.map +1 -1
  149. package/dist/db/audit-queries.d.ts +12 -12
  150. package/dist/db/category-queries.d.ts +3 -3
  151. package/dist/db/changeset-audit-queries.d.ts +4 -4
  152. package/dist/db/changeset-queries.d.ts +7 -7
  153. package/dist/db/comment-queries.d.ts +8 -8
  154. package/dist/db/comment-subscription-queries.d.ts +2 -2
  155. package/dist/db/component-instance-queries.d.ts +197 -0
  156. package/dist/db/component-instance-queries.d.ts.map +1 -0
  157. package/dist/db/component-instance-queries.js +405 -0
  158. package/dist/db/component-instance-queries.js.map +1 -0
  159. package/dist/db/content-queries.d.ts.map +1 -1
  160. package/dist/db/content-queries.js +39 -2
  161. package/dist/db/content-queries.js.map +1 -1
  162. package/dist/db/extension-queries.d.ts +7 -7
  163. package/dist/db/feed-queries.d.ts +3 -3
  164. package/dist/db/index.d.ts +1 -0
  165. package/dist/db/index.d.ts.map +1 -1
  166. package/dist/db/index.js +1 -0
  167. package/dist/db/index.js.map +1 -1
  168. package/dist/db/layout-queries.d.ts +13 -1
  169. package/dist/db/layout-queries.d.ts.map +1 -1
  170. package/dist/db/layout-queries.js +52 -7
  171. package/dist/db/layout-queries.js.map +1 -1
  172. package/dist/db/locale-queries.d.ts.map +1 -1
  173. package/dist/db/locale-queries.js +0 -0
  174. package/dist/db/locale-queries.js.map +1 -1
  175. package/dist/db/media-queries.d.ts +12 -12
  176. package/dist/db/revision-queries.d.ts +3 -3
  177. package/dist/db/site-admin-queries.d.ts +2 -2
  178. package/dist/db/site-membership-queries.d.ts +3 -3
  179. package/dist/db/site-plugin-queries.d.ts +2 -2
  180. package/dist/db/site-queries.d.ts +6 -6
  181. package/dist/db/version-queries.d.ts +12 -12
  182. package/dist/db/webhook-queries.d.ts +11 -11
  183. package/dist/db/workflow-queries.d.ts +6 -6
  184. package/dist/db/workflow-queries.d.ts.map +1 -1
  185. package/dist/db/workflow-queries.js +11 -2
  186. package/dist/db/workflow-queries.js.map +1 -1
  187. package/dist/layout/component-refs.d.ts +465 -0
  188. package/dist/layout/component-refs.d.ts.map +1 -0
  189. package/dist/layout/component-refs.js +848 -0
  190. package/dist/layout/component-refs.js.map +1 -0
  191. package/dist/layout/index.d.ts +2 -1
  192. package/dist/layout/index.d.ts.map +1 -1
  193. package/dist/layout/index.js +1 -0
  194. package/dist/layout/index.js.map +1 -1
  195. package/dist/layout/module-permissions.d.ts +49 -1
  196. package/dist/layout/module-permissions.d.ts.map +1 -1
  197. package/dist/layout/module-permissions.js +117 -6
  198. package/dist/layout/module-permissions.js.map +1 -1
  199. package/dist/layout/renderer.d.ts +51 -4
  200. package/dist/layout/renderer.d.ts.map +1 -1
  201. package/dist/layout/renderer.js +36 -38
  202. package/dist/layout/renderer.js.map +1 -1
  203. package/dist/layout/types.d.ts +42 -0
  204. package/dist/layout/types.d.ts.map +1 -1
  205. package/dist/layout/types.js +54 -11
  206. package/dist/layout/types.js.map +1 -1
  207. package/dist/schema/base.d.ts +1 -1
  208. package/dist/schema/components.d.ts +150 -0
  209. package/dist/schema/components.d.ts.map +1 -1
  210. package/dist/schema/components.js +50 -4
  211. package/dist/schema/components.js.map +1 -1
  212. package/dist/versioning/scheduler.d.ts +8 -0
  213. package/dist/versioning/scheduler.d.ts.map +1 -1
  214. package/dist/versioning/scheduler.js +21 -7
  215. package/dist/versioning/scheduler.js.map +1 -1
  216. package/package.json +1 -1
@@ -0,0 +1,123 @@
1
+ import React from 'react';
2
+ import type { LayoutDocument } from '../../layout/types.js';
3
+ import type { EditorAction } from './editor-state.js';
4
+ import { type ComponentForkSaveMode } from './editor-dialog.js';
5
+ import type { ComponentLibrary } from './use-component-library.js';
6
+ /**
7
+ * use-component-fork.tsx
8
+ * The save fork, driven (kywi-cms#147 T4). One implementation for both editor
9
+ * shells, as with the connect flow.
10
+ *
11
+ * WHAT IT DOES TO A SAVE. Every save path in both shells goes through
12
+ * {@link ComponentFork.guardSave} instead of handing `state.layout` straight to
13
+ * its callback. With no edited linked instances that is a pass-through — the
14
+ * document goes out unchanged, and nothing about saving has changed. With one or
15
+ * more, the save is INTERRUPTED: the owner answers per component, the answers are
16
+ * applied to the document, the definitions that need writing are written, and
17
+ * only then does the save proceed — with the resolved document, so the page that
18
+ * lands on the server is one whose linked instances are all coherent again.
19
+ *
20
+ * ORDERING, AND THE PARTIAL STATE IT ADMITS TO. Component definitions are PUT
21
+ * first, the page second. That is the safer order of the two: a definition write
22
+ * is idempotent and self-contained (it makes every instance render the edit, on
23
+ * this page too — resolution is live), whereas a page write that landed before a
24
+ * failed definition write would leave the page storing a CLEAN instance of a
25
+ * definition that never received the edit, i.e. the edit deleted. The remaining
26
+ * failure — definitions written, page save failed — is real and is SAID rather
27
+ * than hidden: the message names it, nothing is marked saved, the document stays
28
+ * dirty, and retrying re-runs the same idempotent PUT and saves again.
29
+ *
30
+ * THE SECOND DOOR, AND WHY IT IS NOW SHUT (kywi-cms#147 T4 review, I1). The fork
31
+ * sits on the EDITOR's own save paths. The admin Layout tab used to also stage
32
+ * every edit into the surrounding content form (`onChange` → `handleChange`), so a
33
+ * page-level form Submit persisted a layout the fork had never seen, and switching
34
+ * tabs remounted the editor with that staged document as its new baseline — which
35
+ * made the staged state permanent rather than provisional. For a SECTION or
36
+ * CONTAINER instance the consequence was worse than a stray override: those resolve
37
+ * WHOLESALE, so the edit sat in a fallback copy the renderer never reads. It was
38
+ * persisted and never rendered, and the following editor session took it as the
39
+ * baseline, so nothing normalised it either.
40
+ *
41
+ * `content-form.tsx` therefore no longer stages the layout, and no longer sends it
42
+ * with the page form — the Layout tab's own Save is the layout's save path, and the
43
+ * fork is on it. The one exception is a page being CREATED, where there is no
44
+ * content row to PUT a layout against and the create payload is the only door
45
+ * there is; a first-save page's linked instances were all connected in this same
46
+ * session, so their definitions were written by the connect flow moments earlier.
47
+ * The front-of-site overlay — the primary editing surface — never had a second door.
48
+ */
49
+ /** What the shell hands over: persist this document, report whether it landed. */
50
+ export type PerformSave = (layout: LayoutDocument) => boolean | void | Promise<boolean | void>;
51
+ export interface ComponentFork {
52
+ /** The open fork dialog, or null. Render anywhere — it portals to the body. */
53
+ dialog: React.ReactNode;
54
+ /**
55
+ * Run a save, asking about edited linked instances first.
56
+ *
57
+ * `perform` must be the shell's own persist step and must REPORT the outcome
58
+ * the way `onSave` does (`false`/rejection = did not persist), or a failed page
59
+ * save after a successful definition write cannot be told apart from a clean
60
+ * one.
61
+ *
62
+ * `mode` is which button was pressed, and only changes what the dialog SAYS: a
63
+ * component write is immediate whichever one it was, which is exactly the thing
64
+ * "Save Draft" and "Schedule" imply is not happening.
65
+ */
66
+ guardSave: (perform: PerformSave, mode?: ComponentForkSaveMode) => void;
67
+ }
68
+ export declare function useComponentFork({ layout, originalLayout, dispatch, library, inlineEditActive, inert, }: {
69
+ layout: LayoutDocument;
70
+ /** The last-saved document — the baseline an instance is "edited" against. */
71
+ originalLayout: LayoutDocument;
72
+ dispatch: React.Dispatch<EditorAction>;
73
+ library: ComponentLibrary;
74
+ /**
75
+ * True while the front-of-site overlay has a LIVE inline text edit open —
76
+ * i.e. `OverlayShell`'s own `textEdit.id !== null` (kywi-cms#147 T4 review
77
+ * round 2). The admin canvas never has one (module-overlay.tsx: "admin canvas
78
+ * never carries `inlineEdit`"), so it simply never passes this.
79
+ *
80
+ * Why the fallback-copy refresh below needs to know: an inline edit's
81
+ * keystrokes live in the DOM only until commit (blur/Enter), so
82
+ * `state.isDirty` — which the reducer's REFRESH_COMPONENT_COPIES case already
83
+ * refuses to touch — never sees them. A library load landing mid-session finds
84
+ * a document the reducer calls pristine and refreshes it anyway. Worse than an
85
+ * ordinary stale-copy overwrite: `rekeyResolvedSection` gives the refreshed
86
+ * copy the exact ids the placement already had, so React updates the bound
87
+ * element's text IN PLACE instead of remounting it — the #145 orphan recovery
88
+ * (`isOrphanedEdit` in module-overlay.tsx) exists for a bound element that
89
+ * DISCONNECTS, and this element never does, so recovery never fires. The
90
+ * result (pinned in `overlay-refresh-mid-inline-edit.test.tsx`) is a session
91
+ * that looks perfectly healthy — still `contenteditable`, no cancel, no error
92
+ * — while the refresh has silently overwritten whatever was typed with the
93
+ * definition's current value.
94
+ */
95
+ inlineEditActive?: boolean;
96
+ /**
97
+ * THE DOCUMENT IS NOT A PAGE, so there is no fork (kywi-cms#147 T5 review I1,
98
+ * final review M2). Set only by `LayoutEditor`'s `canvasKind` — the admin
99
+ * `components.edit` definition canvas, and the standalone Layouts editor's
100
+ * blueprint canvas.
101
+ *
102
+ * WHY INERT AND NOT "CAREFUL". The fork's question is "does this edit belong to
103
+ * the component, or to this page only?" — and on neither canvas is there a "this
104
+ * page". On a definition canvas the answer is fixed before the question (a
105
+ * definition save IS the propagation) and every branch behind it is wrong:
106
+ * "update all" would PUT some OTHER component's definition (whatever the edited
107
+ * node happened to link to) and only then let the definition save be refused by
108
+ * the extract's nested-link check — a site-wide write nobody asked for, in place
109
+ * of the one they did — while "this page only" would detach a node inside a
110
+ * definition. On a blueprint canvas the blast radius the dialog would name is not
111
+ * even readable: blueprints are outside the instance index, so a linked node in
112
+ * one reports "0 instances across 0 pages" and every number in the fork's copy
113
+ * would be a lie.
114
+ *
115
+ * `guardSave` therefore passes straight through, no dialog is ever built, and the
116
+ * fallback-copy refresh is skipped too: refreshing rewrites a linked node's
117
+ * inline copy from the library, which inside a definition would be silently
118
+ * editing stored content the owner never touched, and inside a blueprint would
119
+ * rewrite a stencil nobody opened for that.
120
+ */
121
+ inert?: boolean;
122
+ }): ComponentFork;
123
+ //# sourceMappingURL=use-component-fork.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-component-fork.d.ts","sourceRoot":"","sources":["../../../src/admin/layout-editor/use-component-fork.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAE,cAAc,EAA+C,MAAM,uBAAuB,CAAA;AAUxG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAUrD,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAA;AAE3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAIH,kFAAkF;AAClF,MAAM,MAAM,WAAW,GAAG,CACxB,MAAM,EAAE,cAAc,KACnB,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;AAE7C,MAAM,WAAW,aAAa;IAC5B,+EAA+E;IAC/E,MAAM,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;;;;;;;;;OAWG;IACH,SAAS,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,qBAAqB,KAAK,IAAI,CAAA;CACxE;AA6BD,wBAAgB,gBAAgB,CAAC,EAC/B,MAAM,EACN,cAAc,EACd,QAAQ,EACR,OAAO,EACP,gBAAwB,EACxB,KAAa,GACd,EAAE;IACD,MAAM,EAAE,cAAc,CAAA;IACtB,8EAA8E;IAC9E,cAAc,EAAE,cAAc,CAAA;IAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAA;IACtC,OAAO,EAAE,gBAAgB,CAAA;IACzB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,GAAG,aAAa,CA+RhB"}
@@ -0,0 +1,346 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React from 'react';
4
+ import { collectComponentInstances, componentDetachSource, componentRefKey, refreshComponentCopies, } from '../../layout/component-refs.js';
5
+ import { adminFetch } from '../../host-client/index.js';
6
+ import { applyInstanceReplacements, buildUpdateAll, detachInstanceKeepingEdits, diffLinkedInstances, isBaselineStale, linkedInstanceContentEquals, } from './component-fork.js';
7
+ import { ComponentForkDialog, EditorDialog, } from './editor-dialog.js';
8
+ import { componentErrorMessage } from './use-component-connect.js';
9
+ // ── The hook ─────────────────────────────────────────────────────────────────
10
+ export function useComponentFork({ layout, originalLayout, dispatch, library, inlineEditActive = false, inert = false, }) {
11
+ const [session, setSession] = React.useState(null);
12
+ const [phase, setPhase] = React.useState({ kind: 'asking', index: 0 });
13
+ const [usage, setUsage] = React.useState({});
14
+ // ── Session baselines ──────────────────────────────────────────────────────
15
+ //
16
+ // A link created during this session has no stored self to be compared with,
17
+ // and connecting/placing already wrote the definition — so its baseline is what
18
+ // it looked like the moment the link appeared. Recorded here, first sight
19
+ // winning, because otherwise "save as component, then fix the typo you just
20
+ // spotted" would write the fix into a fallback copy the page never renders.
21
+ // Entries for placements that later reach the server are simply ignored (the
22
+ // stored document wins in `diffLinkedInstances`), so this never goes stale in a
23
+ // way that matters.
24
+ const sessionBaselines = React.useRef(new Map());
25
+ React.useEffect(() => {
26
+ const stored = new Set(collectComponentInstances(originalLayout).map(componentRefKey));
27
+ for (const instance of collectComponentInstances(layout)) {
28
+ const key = componentRefKey(instance);
29
+ if (stored.has(key) || sessionBaselines.current.has(key))
30
+ continue;
31
+ sessionBaselines.current.set(key, instance);
32
+ }
33
+ }, [layout, originalLayout]);
34
+ // ── Fallback-copy refresh (kywi-cms#147 T4 review, C1) ─────────────────────
35
+ //
36
+ // A linked section/container stores an inline copy of its definition and the
37
+ // editor edits THAT — so before anything can be edited, the copies are brought
38
+ // back in line with the definitions the library just loaded. Without it,
39
+ // update-all built the new definition out of a stale copy and reverted every
40
+ // newer edit of that component everywhere, silently, published pages included.
41
+ //
42
+ // Once per library SNAPSHOT: the components array is a fresh identity on load, on
43
+ // `add` (a component this session created) and on `update` (a definition this
44
+ // session wrote), and each of those genuinely changes what a copy should hold.
45
+ // The layout is a dependency because the effect reads it, not because a layout
46
+ // change should re-run this — the ref guard is what stops that, and it has to,
47
+ // since every edit changes the layout.
48
+ //
49
+ // The reducer refuses the dispatch on a document that is no longer pristine (see
50
+ // REFRESH_COMPONENT_COPIES), so an author already mid-edit when a slow library
51
+ // arrives keeps their work and is protected by `isBaselineStale` instead.
52
+ const refreshedForRef = React.useRef(null);
53
+ React.useEffect(() => {
54
+ // A definition canvas has no placements to refresh — see `inert`.
55
+ if (inert)
56
+ return;
57
+ // Deliberately does NOT update `refreshedForRef` on this branch, so the
58
+ // effect retries against the SAME library snapshot once the session ends
59
+ // (`inlineEditActive` flipping back to false is itself a dependency below,
60
+ // which re-runs this effect) — see `inlineEditActive`'s doc for why landing
61
+ // mid-session is unsafe rather than merely late.
62
+ if (inlineEditActive)
63
+ return;
64
+ if (refreshedForRef.current === library.components)
65
+ return;
66
+ refreshedForRef.current = library.components;
67
+ const refreshed = refreshComponentCopies(layout, library.lookup);
68
+ if (refreshed === layout)
69
+ return;
70
+ dispatch({ type: 'REFRESH_COMPONENT_COPIES', layout: refreshed });
71
+ }, [library, layout, dispatch, inlineEditActive, inert]);
72
+ const close = React.useCallback(() => {
73
+ setSession(null);
74
+ setPhase({ kind: 'asking', index: 0 });
75
+ }, []);
76
+ // ── Opening ────────────────────────────────────────────────────────────────
77
+ const guardSave = React.useCallback((perform, mode = 'save') => {
78
+ // A definition save is the propagation; there is nothing to ask (see `inert`).
79
+ if (inert) {
80
+ void perform(layout);
81
+ return;
82
+ }
83
+ // A save while the dialog is open would ask twice about the same edits.
84
+ if (session)
85
+ return;
86
+ const edits = diffLinkedInstances(originalLayout, layout, ref => sessionBaselines.current.get(componentRefKey(ref)));
87
+ if (edits.length === 0) {
88
+ void perform(layout);
89
+ return;
90
+ }
91
+ const groups = groupEdits(edits, library);
92
+ setSession({ layout, groups, decisions: {}, perform, mode });
93
+ setPhase({ kind: 'asking', index: 0 });
94
+ // Blast radius, best-effort and in parallel: one usage read per component,
95
+ // fired now so the numbers are there by the time the owner reads them.
96
+ setUsage(Object.fromEntries(groups.map(g => [g.componentId, { state: 'pending' }])));
97
+ for (const group of groups) {
98
+ void fetchUsage(group.componentId).then(radius => {
99
+ setUsage(prev => ({ ...prev, [group.componentId]: radius }));
100
+ });
101
+ }
102
+ }, [session, layout, originalLayout, library, inert]);
103
+ // ── Executing ──────────────────────────────────────────────────────────────
104
+ const execute = React.useCallback(async (current) => {
105
+ setPhase({ kind: 'saving' });
106
+ const replacements = new Map();
107
+ const updated = [];
108
+ // Definitions this save has written, so the OTHER placements of the same
109
+ // component — the ones nobody edited — can be refreshed to it before the page
110
+ // is stored (kywi-cms#147 T4 review, C1). Without this, editing placement A,
111
+ // updating everywhere, then editing placement B and updating again rebuilt the
112
+ // definition from B's now-stale copy and destroyed A's edit inside one session.
113
+ const written = new Map();
114
+ for (const group of current.groups) {
115
+ const decision = current.decisions[group.componentId] ?? 'this-page-only';
116
+ if (decision === 'this-page-only') {
117
+ for (const edit of group.edits) {
118
+ replacements.set(componentRefKey(edit), detachInstanceKeepingEdits(edit, library.lookup(edit.componentId)));
119
+ }
120
+ continue;
121
+ }
122
+ // Every edit in the group agrees (that is what makes update-all
123
+ // available), so any of them defines the component; each placement still
124
+ // gets its own clean instance, since a clean module instance is built
125
+ // from the node it replaces.
126
+ const plans = group.edits.map(edit => buildUpdateAll(edit, {
127
+ source: library.lookup(edit.componentId),
128
+ resolveLink: library.lookup,
129
+ }));
130
+ const definition = plans[0]?.definition;
131
+ if (!definition || plans.some(plan => plan === null)) {
132
+ // Only reachable if the library changed under us between the question
133
+ // and the answer (`groupEdits` already withdrew update-all otherwise).
134
+ setPhase({
135
+ kind: 'failed',
136
+ message: `${alreadyUpdated(updated)}Could not work out what to save for ` +
137
+ `“${group.name ?? 'this component'}”, so the page was not saved.`,
138
+ });
139
+ return;
140
+ }
141
+ let res;
142
+ try {
143
+ res = await adminFetch(`/api/v1/components/${group.componentId}`, {
144
+ method: 'PUT',
145
+ body: JSON.stringify({ definition }),
146
+ });
147
+ }
148
+ catch {
149
+ setPhase({
150
+ kind: 'failed',
151
+ message: `${alreadyUpdated(updated)}Could not reach the server, so “${group.name ?? 'this component'}” was not updated and the page was not saved.`,
152
+ });
153
+ return;
154
+ }
155
+ if (!res.ok) {
156
+ setPhase({
157
+ kind: 'failed',
158
+ message: `${alreadyUpdated(updated)}“${group.name ?? 'This component'}” was not updated: ${await componentErrorMessage(res)} The page was not saved.`,
159
+ });
160
+ return;
161
+ }
162
+ updated.push(group.name ?? 'the component');
163
+ group.edits.forEach((edit, index) => {
164
+ replacements.set(componentRefKey(edit), plans[index].cleanInstance);
165
+ });
166
+ // The library is the editor's copy of what the server now holds — every
167
+ // later read of it (the rail's values, the canvas preview, the next
168
+ // staleness check) must see the definition this save just wrote.
169
+ const row = library.byId(group.componentId);
170
+ if (row) {
171
+ written.set(group.componentId, componentDetachSource({ ...row, definition }));
172
+ }
173
+ library.update(group.componentId, definition);
174
+ }
175
+ // One document, one history entry, handed to the reducer BY REFERENCE so
176
+ // the shell's MARK_SAVED can recognise it (see the action's doc).
177
+ //
178
+ // Two passes, in this order: the answers first (each edited placement becomes
179
+ // a clean instance of the new definition), then the copy refresh for the
180
+ // placements nobody edited. The refresh is a no-op on the ones just replaced —
181
+ // `buildUpdateAll` builds `cleanInstance` by applying the new definition to the
182
+ // placement, which is precisely what refreshing would compute.
183
+ const answered = applyInstanceReplacements(current.layout, replacements);
184
+ const resolved = written.size > 0
185
+ ? refreshComponentCopies(answered, id => written.get(id) ?? null)
186
+ : answered;
187
+ dispatch({ type: 'APPLY_COMPONENT_FORK', layout: resolved });
188
+ let ok;
189
+ try {
190
+ ok = await Promise.resolve(current.perform(resolved));
191
+ }
192
+ catch {
193
+ ok = false;
194
+ }
195
+ if (ok === false) {
196
+ setPhase({
197
+ kind: 'failed',
198
+ message: `${alreadyUpdated(updated)}This page could not be saved, so it still has unsaved changes. ` +
199
+ 'Try again — updating a component twice changes nothing.',
200
+ });
201
+ return;
202
+ }
203
+ close();
204
+ }, [library, dispatch, close]);
205
+ const decide = React.useCallback((decision) => {
206
+ if (!session)
207
+ return;
208
+ if (phase.kind !== 'asking')
209
+ return;
210
+ const group = session.groups[phase.index];
211
+ if (!group)
212
+ return;
213
+ const next = {
214
+ ...session,
215
+ decisions: { ...session.decisions, [group.componentId]: decision },
216
+ };
217
+ setSession(next);
218
+ if (phase.index + 1 < next.groups.length) {
219
+ setPhase({ kind: 'asking', index: phase.index + 1 });
220
+ return;
221
+ }
222
+ void execute(next);
223
+ }, [session, phase, execute]);
224
+ const retry = React.useCallback(() => {
225
+ if (session)
226
+ void execute(session);
227
+ }, [session, execute]);
228
+ // ── The dialog ─────────────────────────────────────────────────────────────
229
+ const dialog = React.useMemo(() => {
230
+ if (!session)
231
+ return null;
232
+ // A failure replaces the question rather than decorating it: the answers have
233
+ // already been given, and re-offering "Save to this page only" here would
234
+ // re-run whatever was decided instead of what the label says. One honest
235
+ // action — try the same thing again — plus a way to walk away.
236
+ if (phase.kind === 'failed') {
237
+ return (_jsx(EditorDialog, { title: "Could not finish saving", error: phase.message, cancelLabel: "Close", actions: [{ label: 'Try again', action: 'fork-retry', onClick: retry }], onCancel: close }));
238
+ }
239
+ // While saving, the last question stays on screen with its actions disabled —
240
+ // the owner keeps the context of what they just decided.
241
+ const index = phase.kind === 'asking' ? phase.index : session.groups.length - 1;
242
+ const group = session.groups[Math.min(index, session.groups.length - 1)];
243
+ if (!group)
244
+ return null;
245
+ return (_jsx(ComponentForkDialog, { componentName: group.name, blastRadius: usage[group.componentId] ?? { state: 'pending' }, saveMode: session.mode, step: index + 1, stepCount: session.groups.length, updateAllUnavailable: group.updateAllUnavailable, busy: phase.kind === 'saving', onUpdateAll: () => decide('update-all'), onThisPageOnly: () => decide('this-page-only'),
246
+ // Cancel/Escape aborts the WHOLE save: nothing is written, the document
247
+ // keeps every edit, and the page stays dirty. A half-applied fork would
248
+ // be worse than no save at all.
249
+ onCancel: close }));
250
+ }, [session, phase, usage, decide, retry, close]);
251
+ return React.useMemo(() => ({ dialog, guardSave }), [dialog, guardSave]);
252
+ }
253
+ // ── Helpers ──────────────────────────────────────────────────────────────────
254
+ function alreadyUpdated(updated) {
255
+ if (updated.length === 0)
256
+ return '';
257
+ const names = updated.map(name => `“${name}”`).join(', ');
258
+ return `${names} ${updated.length === 1 ? 'was' : 'were'} already updated everywhere. `;
259
+ }
260
+ /**
261
+ * Group the edits by component — one question per component, not per node.
262
+ *
263
+ * MULTIPLE COMPONENTS IN ONE SAVE are asked about one after another ("Component 1
264
+ * of 2"), because the answers are genuinely independent: updating the shared
265
+ * footer everywhere and keeping a hero tweak local is a perfectly ordinary pair
266
+ * of intentions, and a single combined dialog would either force one answer for
267
+ * both or turn into a form.
268
+ *
269
+ * TWO PLACEMENTS OF ONE COMPONENT edited DIFFERENTLY on the same page cannot both
270
+ * become the definition. Rather than picking one silently, "update all" is
271
+ * withdrawn with the reason; "this page only" still works and detaches both.
272
+ * Identical edits to both placements are fine and stay offered.
273
+ *
274
+ * A STALE COPY withdraws it too (kywi-cms#147 T4 review, C1). If what this page
275
+ * stored as the component's content is not what the component now holds, the
276
+ * definition built from it would revert whatever changed in between — everywhere,
277
+ * published pages included. `isBaselineStale` decides; the copies are normally
278
+ * refreshed long before this point, so reaching it means the library never loaded
279
+ * or arrived too late to be applied safely.
280
+ */
281
+ function groupEdits(edits, library) {
282
+ const groups = new Map();
283
+ for (const edit of edits) {
284
+ const existing = groups.get(edit.componentId);
285
+ if (existing) {
286
+ existing.edits.push(edit);
287
+ continue;
288
+ }
289
+ groups.set(edit.componentId, {
290
+ componentId: edit.componentId,
291
+ name: library.nameOf(edit.componentId),
292
+ edits: [edit],
293
+ updateAllUnavailable: null,
294
+ });
295
+ }
296
+ for (const group of groups.values()) {
297
+ const first = group.edits[0];
298
+ const divergent = group.edits.some(edit => !linkedInstanceContentEquals(first.instance, edit.instance));
299
+ if (divergent) {
300
+ group.updateAllUnavailable =
301
+ `${group.edits.length} instances of this component on this page were edited differently, ` +
302
+ 'so they cannot all become the component. Save them to this page only, or undo one of the edits.';
303
+ continue;
304
+ }
305
+ const source = library.lookup(group.componentId);
306
+ const buildable = group.edits.every(edit => buildUpdateAll(edit, { source, resolveLink: library.lookup }) !== null);
307
+ if (!buildable) {
308
+ group.updateAllUnavailable =
309
+ 'This component’s current content could not be loaded, so the editor cannot tell which of ' +
310
+ 'its settings you changed. Save to this page only, or reload the page and try again.';
311
+ continue;
312
+ }
313
+ // The belt on C1: a definition built out of an out-of-date copy would revert
314
+ // whatever changed in between, everywhere.
315
+ if (group.edits.some(edit => isBaselineStale(edit, source))) {
316
+ group.updateAllUnavailable =
317
+ 'This page’s copy of the component is out of date, so saving it to every instance would ' +
318
+ 'undo newer changes. Save to this page only, then re-edit the component from an ' +
319
+ 'up-to-date page.';
320
+ }
321
+ }
322
+ return [...groups.values()];
323
+ }
324
+ /** Where a component is placed — best-effort; a failure degrades the wording. */
325
+ async function fetchUsage(componentId) {
326
+ try {
327
+ const res = await adminFetch(`/api/v1/components/${componentId}/usage`);
328
+ if (!res.ok)
329
+ return { state: 'unknown' };
330
+ const body = (await res.json());
331
+ const data = body.data;
332
+ if (!data || typeof data.instances !== 'number' || typeof data.pages !== 'number') {
333
+ return { state: 'unknown' };
334
+ }
335
+ return {
336
+ state: 'known',
337
+ instances: data.instances,
338
+ pages: data.pages,
339
+ trashedInstances: typeof data.trashedInstances === 'number' ? data.trashedInstances : 0,
340
+ };
341
+ }
342
+ catch {
343
+ return { state: 'unknown' };
344
+ }
345
+ }
346
+ //# sourceMappingURL=use-component-fork.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-component-fork.js","sourceRoot":"","sources":["../../../src/admin/layout-editor/use-component-fork.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import type { ComponentPlacementLookup } from '../../layout/component-refs.js';
2
+ import type { ModuleNode } from '../../layout/types.js';
3
+ import type { ComponentOption } from './component-picker-field.js';
4
+ /**
5
+ * use-component-library.ts
6
+ * The saved components an editor shell has loaded, and the projections both
7
+ * shells need from them (kywi-cms#147).
8
+ *
9
+ * WHY ONE HOOK FOR BOTH SHELLS. The admin Layout tab fetched module components
10
+ * and section components in two separate effects and kept them in two states; the
11
+ * front-of-site overlay fetched neither, which is why "Save as component" and the
12
+ * linked badge existed only in the admin editor even though the overlay is the
13
+ * PRIMARY editing surface (kywi-cms#94). One hook, one request, three types.
14
+ *
15
+ * The request is deliberately unfiltered (`GET /components`, no `?type=`): a
16
+ * document can hold links of all three kinds at once, every one of them needs a
17
+ * name for its pill and a definition for detach, and one round trip is cheaper
18
+ * than three. Best-effort throughout — a failed load leaves the library empty,
19
+ * which degrades pills to the generic "Component" and leaves save-as-component
20
+ * fully working (it only ever POSTs).
21
+ */
22
+ /** A saved component as `GET /api/v1/components` returns it. */
23
+ export interface EditorComponent {
24
+ id: string;
25
+ name: string;
26
+ type: string;
27
+ moduleType: string | null;
28
+ definition: unknown;
29
+ }
30
+ export interface ComponentLibrary {
31
+ /** Every loaded component, all types. */
32
+ components: EditorComponent[];
33
+ byId: (componentId: string) => EditorComponent | null;
34
+ /** Display name for a linked instance's pill, or null when unknown. */
35
+ nameOf: (componentId: string) => string | null;
36
+ /** Picker options for one component type. */
37
+ optionsFor: (type: 'module' | 'section' | 'variantContainer') => ComponentOption[];
38
+ /**
39
+ * The canonical lookup materialisation reads (`componentDetachSource`), used by
40
+ * detach, by save-as-component's nested-link flattening, and by anything else
41
+ * that has to answer "what does this link render".
42
+ */
43
+ lookup: ComponentPlacementLookup;
44
+ /** Module-component projection for the canvas preview (kywi-cms#46). */
45
+ resolveModule: (componentId: string) => {
46
+ props: Record<string, unknown>;
47
+ style: Record<string, string>;
48
+ moduleType: string;
49
+ } | null;
50
+ /**
51
+ * What a module node RENDERS: its own props/style for an ordinary node, and for
52
+ * a linked instance the definition read through the canonical placement rule
53
+ * (`resolveModulePlacement` — definition alone for a clean instance, definition
54
+ * then node for a legacy override one).
55
+ *
56
+ * The props rail needs exactly this (kywi-cms#147 T4): a clean instance carries
57
+ * no props of its own, so fields fed from `node.props` would show an empty form
58
+ * for a module full of content, and the first keystroke would look like it
59
+ * cleared everything. Same projection as the canvas preview and the public
60
+ * renderer, so what the rail shows is what the visitor sees.
61
+ */
62
+ renderedModule: (node: Pick<ModuleNode, 'props' | 'style' | 'componentId'>) => {
63
+ props: Record<string, unknown>;
64
+ style: Record<string, string>;
65
+ };
66
+ /**
67
+ * Which module type's registry entry describes a node's editable FIELDS, or null
68
+ * when nothing honest can be shown (kywi-cms#147 T4 review, I2).
69
+ *
70
+ * For an ordinary node that is its own `type`. For a linked instance it is the
71
+ * COMPONENT's `moduleType`, because that is what the placement renders as
72
+ * (`materializeModuleNode` retypes the node) — and because a component placed
73
+ * from the palette picker is a `component` placeholder node, whose registry entry
74
+ * declares "Component Slug" and "Component ID" props. Those are link plumbing,
75
+ * not content: seeded from the resolved definition they read empty, and typing
76
+ * into "Component ID" writes a prop the fork deliberately strips.
77
+ *
78
+ * Null for a linked placeholder whose component does not resolve — there is no
79
+ * module type, so there are no fields, and inventing the placeholder's own two is
80
+ * how the rail came to show a form nobody could use.
81
+ */
82
+ fieldModuleType: (node: Pick<ModuleNode, 'type' | 'componentId'>) => string | null;
83
+ /** Adopt a component the shell just created, so its name is available at once. */
84
+ add: (component: EditorComponent) => void;
85
+ /**
86
+ * Adopt a definition the shell just wrote (the save fork's `PUT`), so everything
87
+ * reading the library — the rail's field values, the canvas preview, the copy
88
+ * refresh, and the next fork's staleness check — sees the new content rather than
89
+ * the one the page loaded with (kywi-cms#147 T4 review, C1).
90
+ */
91
+ update: (componentId: string, definition: unknown) => void;
92
+ }
93
+ export declare function useComponentLibrary(): ComponentLibrary;
94
+ //# sourceMappingURL=use-component-library.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-component-library.d.ts","sourceRoot":"","sources":["../../../src/admin/layout-editor/use-component-library.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAA;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAGvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAElE;;;;;;;;;;;;;;;;;GAiBG;AAEH,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,UAAU,EAAE,eAAe,EAAE,CAAA;IAC7B,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,eAAe,GAAG,IAAI,CAAA;IACrD,uEAAuE;IACvE,MAAM,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IAC9C,6CAA6C;IAC7C,UAAU,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,kBAAkB,KAAK,eAAe,EAAE,CAAA;IAClF;;;;OAIG;IACH,MAAM,EAAE,wBAAwB,CAAA;IAChC,wEAAwE;IACxE,aAAa,EAAE,CACb,WAAW,EAAE,MAAM,KAChB;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACjG;;;;;;;;;;;OAWG;IACH,cAAc,EAAE,CACd,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,GAAG,aAAa,CAAC,KACtD;QAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;IACtE;;;;;;;;;;;;;;;OAeG;IACH,eAAe,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,MAAM,GAAG,IAAI,CAAA;IAClF,kFAAkF;IAClF,GAAG,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAA;IACzC;;;;;OAKG;IACH,MAAM,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,KAAK,IAAI,CAAA;CAC3D;AAED,wBAAgB,mBAAmB,IAAI,gBAAgB,CAkFtD"}