@septkit/ui 0.0.49 → 0.0.51

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 (28) hide show
  1. package/dist/dialecte/composables/use-active-document.js +27 -17
  2. package/dist/dialecte/composables/use-live-data.js +13 -13
  3. package/dist/dialecte/create-document-store.js +3 -3
  4. package/dist/external/.pnpm/{@dialecte_core@0.4.7 → @dialecte_core@0.4.9}/node_modules/@dialecte/core/dist/helpers.js +16 -19
  5. package/dist/external/.pnpm/{@dialecte_core@0.4.7 → @dialecte_core@0.4.9}/node_modules/@dialecte/core/dist/index.js +1 -1
  6. package/dist/external/.pnpm/{@dialecte_core@0.4.7/node_modules/@dialecte/core/dist/project-DxIu-3AU.js → @dialecte_core@0.4.9/node_modules/@dialecte/core/dist/project-D-KS3OPN.js} +1 -1
  7. package/dist/external/.pnpm/{@dialecte_core@0.4.7 → @dialecte_core@0.4.9}/node_modules/@dialecte/core/dist/utils-C5_11hqg.js +1 -1
  8. package/dist/external/.pnpm/{@dialecte_scl@0.3.8/node_modules/@dialecte/scl/dist/hooks-DJJN-WU2.js → @dialecte_scl@0.3.12/node_modules/@dialecte/scl/dist/hooks-Cm_UYBBt.js} +48 -5277
  9. package/dist/external/.pnpm/@dialecte_scl@0.3.12/node_modules/@dialecte/scl/dist/v2019C1/index.js +22 -0
  10. package/dist/index.d.ts +48 -10
  11. package/dist/merge/build-view-model.js +101 -74
  12. package/dist/merge/decision-toggle.vue_vue_type_script_setup_true_lang.js +2 -2
  13. package/dist/merge/element-detail.vue_vue_type_script_setup_true_lang.js +154 -45
  14. package/dist/merge/merge-correlate.js +46 -0
  15. package/dist/merge/merge-decision.js +6 -0
  16. package/dist/merge/merge-highlight.js +44 -0
  17. package/dist/merge/merge-preflight.js +5 -0
  18. package/dist/merge/merge-preflight.vue_vue_type_script_setup_true_lang.js +41 -0
  19. package/dist/merge/merge-progress.vue_vue_type_script_setup_true_lang.js +12 -20
  20. package/dist/merge/merge-review.vue_vue_type_script_setup_true_lang.js +230 -181
  21. package/dist/merge/merge-summary.vue_vue_type_script_setup_true_lang.js +47 -25
  22. package/dist/merge/merge-tree.vue_vue_type_script_setup_true_lang.js +73 -62
  23. package/dist/merge/merge.service.js +36 -23
  24. package/dist/merge/use-document-progress.js +8 -9
  25. package/dist/merge/use-merge-session.js +122 -108
  26. package/dist/ui.css +1 -1
  27. package/package.json +3 -3
  28. package/dist/external/.pnpm/@dialecte_scl@0.3.8/node_modules/@dialecte/scl/dist/v2019C1/index.js +0 -3
@@ -0,0 +1,22 @@
1
+ import "../../../../../../@dialecte_core@0.4.9/node_modules/@dialecte/core/dist/index.js";
2
+ import { i as e } from "../hooks-Cm_UYBBt.js";
3
+ //#region node_modules/.pnpm/@dialecte+scl@0.3.12/node_modules/@dialecte/scl/dist/v2019C1/index.js
4
+ var t = {
5
+ "cross-type-template-uuid": {
6
+ title: "Placeholder templateUuid reused across element types",
7
+ description: "One templateUuid is carried by elements of several different types, so it cannot identify a single template element — it is an authoring placeholder, not real lineage.",
8
+ fallback: "Template lineage is ignored for these elements; each instance is recognised by its name within its parent instead, so the merge still proceeds."
9
+ },
10
+ "duplicate-instance-uuid": {
11
+ title: "Duplicate instance uuid",
12
+ description: "The same uuid is used by more than one element. Every instance uuid in an SCL must be unique, so uuid-based identity is ambiguous for the affected elements.",
13
+ fallback: "The affected elements are matched by name and position rather than uuid, so the merge still proceeds — resolve the duplication to restore reliable identity."
14
+ },
15
+ "template-uuid-type-mismatch": {
16
+ title: "templateUuid resolves to a different element type",
17
+ description: "A templateUuid points in-file to an element of a different type than the one carrying it. An instance cannot derive from a template of another type, so the lineage is inconsistent.",
18
+ fallback: "The mismatched lineage is ignored and the element is recognised by name, so the merge still proceeds."
19
+ }
20
+ };
21
+ //#endregion
22
+ export { t as TEMPLATE_UUID_WARNING_INFO, e as presentationScope };
package/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ import { Reactive } from 'vue';
21
21
  import { Ref } from 'vue';
22
22
  import { Scl } from '@dialecte/scl/v2019C1';
23
23
  import { ShallowRef } from 'vue';
24
+ import { TemplateUuidWarning } from '@dialecte/scl/v2019C1';
24
25
 
25
26
  declare const __VLS_component: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, HTMLButtonElement>;
26
27
 
@@ -100,6 +101,8 @@ declare type __VLS_Props_11 = {
100
101
  detail: ElementDetailVM | undefined;
101
102
  /** Consumer-supplied fixed prefix/suffix per attribute; the user edits only the core. */
102
103
  affixMask?: AffixMaskResolver;
104
+ /** The selected group is skipped: lock editing and show the skip (current) value. */
105
+ disabled?: boolean;
103
106
  };
104
107
 
105
108
  declare type __VLS_Props_12 = MergeSessionParams & {
@@ -405,7 +408,7 @@ export declare const Button: __VLS_WithTemplateSlots<typeof __VLS_component, __V
405
408
  export declare const CATEGORY_ELEMENTS: Record<string, string[]>;
406
409
 
407
410
  /** How an element or attribute changed between the template and the instance. */
408
- export declare type ChangeStatus = 'added' | 'removed' | 'modified' | 'unchanged';
411
+ export declare type ChangeStatus = 'added' | 'removed' | 'modified' | 'unchanged' | 'target-only';
409
412
 
410
413
  declare function closeDropdown(): void;
411
414
 
@@ -462,10 +465,15 @@ export declare const DecisionToggle: DefineComponent<__VLS_PublicProps_2, {}, {}
462
465
  export declare type DetailAttribute = {
463
466
  name: string;
464
467
  status: ChangeStatus;
465
- /** The current/instance value — the `-` line, present when modified/removed. */
468
+ /** The current/instance value — the `-` line, present when modified/removed. (Skip target.) */
466
469
  before?: string;
467
- /** The final value that will be written — the `+` line, present when added/modified. */
470
+ /** The incoming/proposed value — the `+` line, present when added/modified. (Accept target.) */
468
471
  after?: string;
472
+ /**
473
+ * The live value that will actually be written — the user's edit, or accept/skip choice.
474
+ * Defaults to `after` (accept) when unset; a skip sets it to `before`. The input binds to this.
475
+ */
476
+ written?: string;
469
477
  /** When set, the attribute is user-editable and its value renders as an input. */
470
478
  editable?: EditableMode;
471
479
  /** The engine auto-resolved a placement collision on this field (value = the resolved one). */
@@ -656,8 +664,23 @@ export declare type MergeNodeMeta = {
656
664
  role: 'primary' | 'companion' | 'plain';
657
665
  /** The decision group this node belongs to (primary + companions share it). */
658
666
  groupId?: string;
667
+ /**
668
+ * The topmost changed node of a change region (no changed same-group ancestor above it).
669
+ * Only region heads carry a status marker, so one badge shows per change instead of
670
+ * scattering across correlated companions but not their uuid-less siblings.
671
+ */
672
+ regionHead?: boolean;
659
673
  /** For a satellite companion that lives elsewhere: its real document path (shown as subtitle). */
660
674
  path?: string;
675
+ /**
676
+ * Present on an instance ROOT (Application/Function): its linkage to the loaded template
677
+ * and its member cluster. Drives the "linked / up to date" badge and the select-to-highlight
678
+ * of the whole instance (subtree + folded satellites).
679
+ */
680
+ instance?: {
681
+ linked: boolean;
682
+ upToDate: boolean;
683
+ };
661
684
  };
662
685
 
663
686
  export declare const MergeReview: DefineComponent<__VLS_Props_12, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
@@ -737,14 +760,21 @@ export declare type UnifiedDiff = {
737
760
  };
738
761
 
739
762
  /**
740
- * Reactively hydrate the shell's active document — race-safe across realms.
763
+ * Reactively resolve the shell's active document — race-safe across realms.
741
764
  *
742
765
  * The active-document id (shell `localStorage` `storage` event) and the
743
766
  * project's document registry (BroadcastChannel) are not ordered across realms,
744
767
  * so in an iframe extension the id can arrive before the document is registered
745
768
  * / its records are readable. `project.getDocumentStatus(id)` reconciles this
746
- * realm's store against persisted state first, so hydration never races ahead
747
- * of the document. Results from a superseded switch are ignored.
769
+ * realm's store against persisted state first, so the exposed document never
770
+ * races ahead of the document. Results from a superseded switch are ignored.
771
+ *
772
+ * The resolved document is returned as a nullable `document` ref (single source
773
+ * of truth); `isReady` is derived from it. When the active id changes, the
774
+ * previous document is dropped *before* the new one's readiness is probed, so a
775
+ * stale document is never exposed for the new id. Consumers should gate on
776
+ * `isReady`/`document` and can pass optional `hydrate`/`clear` callbacks to also
777
+ * mirror the value into a module-level document store.
748
778
  *
749
779
  * Cleanup runs automatically when used inside a component/effect scope; the
750
780
  * returned `stop` lets scope-less callers (e.g. an extension bootstrap) tear it
@@ -753,10 +783,11 @@ export declare type UnifiedDiff = {
753
783
  export declare function useActiveDocument<GenericDocument>(params: {
754
784
  project: ActiveDocumentProject<GenericDocument>;
755
785
  activeDocumentId: ActiveDocumentObservable<string>;
756
- hydrate: (doc: GenericDocument) => void;
757
- clear: () => void;
786
+ hydrate?: (doc: GenericDocument) => void;
787
+ clear?: () => void;
758
788
  }): {
759
- isReady: Ref<boolean>;
789
+ document: Ref<GenericDocument | undefined>;
790
+ isReady: ComputedRef<boolean>;
760
791
  activeDocumentId: Ref<string | undefined>;
761
792
  stop: () => void;
762
793
  };
@@ -790,9 +821,15 @@ export declare function useDialog(): DialogController;
790
821
  * a `commit` message for this documentId — posted by any Document instance,
791
822
  * in this tab or another — re-runs the fetcher. Document state itself is plain,
792
823
  * non-reactive data in core; do not watch it.
824
+ *
825
+ * The document may be absent (`undefined`): the composable then holds `initial`,
826
+ * subscribes to nothing, and starts fetching once a document appears — mirroring
827
+ * {@link useProjectLiveData}. This lets a caller pass a document that is null
828
+ * before hydration or during a teardown/switch without pre-guarding a value
829
+ * that would otherwise throw.
793
830
  */
794
831
  export declare function useLiveData<T>(params: {
795
- document: LiveDataDocument | ComputedRef<LiveDataDocument>;
832
+ document: MaybeRefOrGetter<LiveDataDocument | undefined>;
796
833
  fetcher: () => Promise<T>;
797
834
  initial: T;
798
835
  }): {
@@ -815,6 +852,7 @@ export declare function useMergeSession(params: MergeSessionParams): {
815
852
  previewXml: ShallowRef<string | undefined, string | undefined>;
816
853
  previewBeforeXml: ShallowRef<string | undefined, string | undefined>;
817
854
  previewLoading: ShallowRef<boolean, boolean>;
855
+ warnings: ShallowRef<TemplateUuidWarning[], TemplateUuidWarning[]>;
818
856
  load: () => Promise<void>;
819
857
  setDecision: (groupId: string, action: "accept" | "skip") => void;
820
858
  setValue: (groupId: string, attr: string, value: string) => void;
@@ -1,89 +1,104 @@
1
1
  import { extractTitle as e, getAttributes as t } from "./merge.service.js";
2
2
  //#region lib/merge/build-view-model.ts
3
- async function n(e) {
4
- let { report: n, createdBySourceUuid: r, sourceQuery: i } = e, a = /* @__PURE__ */ new Map();
5
- for (let e of n.groups) {
6
- a.set(e.primary, {
7
- role: "primary",
8
- groupId: e.id
9
- });
10
- for (let t of e.companions) a.set(t, {
11
- role: "companion",
12
- groupId: e.id
3
+ function n(e) {
4
+ return e.instances.flatMap((e) => e.groups);
5
+ }
6
+ function r(e) {
7
+ let { report: t, correlation: r } = e, i = /* @__PURE__ */ new Map();
8
+ for (let e of n(t)) i.set(e.primary, {
9
+ role: "primary",
10
+ groupId: e.id
11
+ });
12
+ let a = /* @__PURE__ */ new Map();
13
+ function o(e) {
14
+ let t = r.get(e);
15
+ if (!t) return;
16
+ let n = i.get(e);
17
+ a.set(t, {
18
+ change: e.change,
19
+ role: n?.role ?? "plain",
20
+ groupId: n?.groupId,
21
+ node: e
13
22
  });
14
23
  }
15
- let o = /* @__PURE__ */ new Map();
16
- async function s(e) {
17
- if (e.instanceRef) return e.instanceRef.id;
18
- if (e.sourceRef) {
19
- let n = await t(i, e.sourceRef);
20
- return n.uuid ? r.get(n.uuid)?.id : void 0;
21
- }
24
+ function s(e) {
25
+ o(e);
26
+ for (let t of e.children) s(t);
22
27
  }
23
- async function c(e) {
24
- let t = await s(e);
25
- if (t) {
26
- let n = a.get(e);
27
- o.set(t, {
28
+ function c(e, t) {
29
+ if (e.change !== "unchanged") {
30
+ let n = r.get(e);
31
+ n && a.set(n, {
28
32
  change: e.change,
29
- role: n?.role ?? "plain",
30
- groupId: n?.groupId,
33
+ role: "companion",
34
+ groupId: t,
31
35
  node: e
32
36
  });
33
37
  }
38
+ for (let n of e.children) c(n, t);
34
39
  }
35
- async function l(e) {
36
- await c(e);
37
- for (let t of e.children) await l(t);
38
- }
39
- for (let e of n.roots) await l(e);
40
- for (let e of n.groups) for (let t of e.companions) await c(t);
41
- return o;
40
+ for (let e of t.instances) s(e.tree);
41
+ for (let e of n(t)) for (let t of e.companions) c(t, e.id);
42
+ return a;
42
43
  }
43
- async function r(t) {
44
+ async function i(t) {
44
45
  let { tree: n, changeByStagedId: r, query: i } = t, a = {
45
46
  items: [],
46
47
  meta: {},
47
48
  index: {},
48
49
  expanded: []
49
50
  };
50
- async function o(t, n) {
51
- let s = r.get(t.id), c = s?.change ?? (n.added ? "added" : "unchanged"), l = s?.groupId ?? (c === "unchanged" ? void 0 : n.groupId), u = s?.role ?? "plain", d = {
51
+ async function o(t, n, s) {
52
+ let c = r.get(t.id), l = c?.change ?? (n.added ? "added" : "unchanged"), u = c?.groupId ?? (l === "unchanged" ? void 0 : n.groupId), d = c?.role ?? "plain", f = {
52
53
  tagName: t.tagName,
53
54
  id: t.id
54
- }, f = {
55
- added: s ? s.change === "added" : n.added,
56
- groupId: l ?? n.groupId
57
- }, p = [];
58
- for (let e of t.tree ?? []) p.push(await o(e, f));
59
- let m = c !== "unchanged" || p.some((e) => e.changed);
55
+ }, p = l !== "unchanged" && (!s || s.change === "unchanged" || s.groupId !== u || s.change !== l), m = {
56
+ added: c ? c.change === "added" : n.added,
57
+ groupId: u ?? n.groupId
58
+ }, h = [];
59
+ for (let e of t.tree ?? []) h.push(await o(e, m, {
60
+ change: l,
61
+ groupId: u
62
+ }));
63
+ let g = l !== "unchanged" || h.some((e) => e.changed);
60
64
  return a.meta[t.id] = {
61
- change: c,
62
- role: u,
63
- groupId: l
65
+ change: l,
66
+ role: d,
67
+ groupId: u,
68
+ regionHead: p
64
69
  }, a.index[t.id] = {
65
- previewRef: d,
66
- change: c,
67
- role: u,
68
- groupId: l,
69
- node: s?.node
70
- }, m && a.expanded.push(t.id), {
70
+ previewRef: f,
71
+ change: l,
72
+ role: d,
73
+ groupId: u,
74
+ node: c?.node
75
+ }, g && a.expanded.push(t.id), {
71
76
  node: {
72
77
  tag: t.tagName,
73
78
  id: t.id,
74
- name: await e(i, d),
79
+ name: await e(i, f),
75
80
  selectable: !0,
76
- children: p.length ? p.map((e) => e.node) : void 0
81
+ children: h.length ? h.map((e) => e.node) : void 0
77
82
  },
78
- changed: m
83
+ changed: g
79
84
  };
80
85
  }
81
- return a.items.push((await o(n, {
86
+ a.items.push((await o(n, {
82
87
  added: !1,
83
88
  groupId: void 0
84
- })).node), a;
89
+ }, void 0)).node);
90
+ let s = /* @__PURE__ */ new Map();
91
+ for (let [e, t] of r) s.set(t.node, e);
92
+ for (let e of t.instances) {
93
+ let t = s.get(e.tree);
94
+ !t || !a.meta[t] || (a.meta[t].instance = {
95
+ linked: e.linked,
96
+ upToDate: e.upToDate
97
+ });
98
+ }
99
+ return a;
85
100
  }
86
- async function i(e, n, r) {
101
+ async function a(e, n, r) {
87
102
  let i = new Map((n?.editableAttributes ?? []).map((e) => [e.attr, e])), a = [];
88
103
  if (e.change === "added" && e.sourceRef) {
89
104
  let n = await t(r.sourceQuery, e.sourceRef);
@@ -138,51 +153,63 @@ async function i(e, n, r) {
138
153
  }
139
154
  return {
140
155
  tag: e.tagName,
141
- title: await o(e, r),
156
+ title: await s(e, r),
142
157
  change: e.change,
143
158
  attributes: a
144
159
  };
145
160
  }
146
- async function a(e, t, n, r) {
147
- let i = {
161
+ async function o(e, t, r, i) {
162
+ let a = {
148
163
  added: [],
149
164
  updated: [],
150
165
  skipped: [],
166
+ preserved: [],
167
+ removed: [],
151
168
  renamed: []
152
169
  };
153
- for (let a of e.groups) {
154
- let e = await o(a.primary, r), s = a.primary.tagName, c = a.companions.length;
155
- if (t(a.id) === "skip") {
156
- i.skipped.push({
170
+ for (let o of n(e)) {
171
+ let e = await s(o.primary, i), n = o.primary.tagName, c = o.companions.length;
172
+ if (o.primary.change === "target-only") {
173
+ t(o.id) === "skip" ? a.preserved.push({
174
+ title: e,
175
+ tag: n
176
+ }) : a.removed.push({
177
+ title: e,
178
+ tag: n
179
+ });
180
+ continue;
181
+ }
182
+ if (t(o.id) === "skip") {
183
+ a.skipped.push({
157
184
  title: e,
158
- tag: s
185
+ tag: n
159
186
  });
160
187
  continue;
161
188
  }
162
- for (let t of a.editableAttributes ?? []) t.conflict && t.suggestedValue && n(a.id, t.attr) == null && i.renamed.push({
189
+ for (let t of o.editableAttributes ?? []) t.conflict && t.suggestedValue && r(o.id, t.attr) == null && a.renamed.push({
163
190
  title: e,
164
191
  field: t.attr,
165
192
  to: t.suggestedValue
166
193
  });
167
- let l = a.editableAttributes?.find((e) => e.attr === "name" && e.conflict), u = n(a.id, "name") ?? l?.suggestedValue ?? e;
168
- if (a.primary.change === "added") i.added.push({
194
+ let l = o.editableAttributes?.find((e) => e.attr === "name" && e.conflict), u = r(o.id, "name") ?? l?.suggestedValue ?? e;
195
+ if (o.primary.change === "added") a.added.push({
169
196
  title: u,
170
- tag: s,
197
+ tag: n,
171
198
  detail: c ? `+${c} companion${c > 1 ? "s" : ""}` : void 0
172
199
  });
173
- else if (a.primary.change === "modified") {
174
- let e = a.primary.attributeChanges?.length ?? 0;
175
- i.updated.push({
200
+ else if (o.primary.change === "modified") {
201
+ let e = o.primary.attributeChanges?.length ?? 0;
202
+ a.updated.push({
176
203
  title: u,
177
- tag: s,
204
+ tag: n,
178
205
  detail: e ? `${e} attribute change${e > 1 ? "s" : ""}` : void 0
179
206
  });
180
207
  }
181
208
  }
182
- return i;
209
+ return a;
183
210
  }
184
- async function o(t, n) {
211
+ async function s(t, n) {
185
212
  return t.instanceRef ? e(n.targetQuery, t.instanceRef) : t.sourceRef ? e(n.sourceQuery, t.sourceRef) : t.tagName;
186
213
  }
187
214
  //#endregion
188
- export { n as buildChangeIndex, i as buildDetail, r as buildStructuralTree, a as buildSummary };
215
+ export { n as allGroups, r as buildChangeIndex, a as buildDetail, i as buildStructuralTree, o as buildSummary };
@@ -23,13 +23,13 @@ var c = {
23
23
  })[d.size ?? "undefined"]);
24
24
  return (e, s) => (o(), t("div", c, [n("button", {
25
25
  type: "button",
26
- class: a(["btn join-item", [f.value, i.value === "accept" ? "btn-success" : "btn-ghost"]]),
26
+ class: a(["btn join-item font-semibold", [f.value, i.value === "accept" ? "btn-success text-success-content" : "btn-ghost"]]),
27
27
  disabled: r.disabled,
28
28
  "aria-pressed": i.value === "accept",
29
29
  onClick: s[0] ||= (e) => i.value = "accept"
30
30
  }, " Accept ", 10, l), n("button", {
31
31
  type: "button",
32
- class: a(["btn join-item", [f.value, i.value === "skip" ? "btn-warning" : "btn-ghost"]]),
32
+ class: a(["btn join-item font-semibold", [f.value, i.value === "skip" ? "btn-warning text-black" : "btn-ghost"]]),
33
33
  disabled: r.disabled,
34
34
  "aria-pressed": i.value === "skip",
35
35
  onClick: s[1] ||= (e) => i.value = "skip"
@@ -1,76 +1,185 @@
1
- import { composeAffix as e, splitAffix as t } from "./affix.js";
2
- import { Fragment as n, computed as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, defineComponent as s, normalizeClass as c, openBlock as l, renderList as u, toDisplayString as d } from "vue";
1
+ import e from "../external/.pnpm/@lucide_vue@1.23.0_vue@3.5.39_typescript@5.8.3_/node_modules/@lucide/vue/dist/esm/icons/pencil.js";
2
+ import { composeAffix as t, splitAffix as n } from "./affix.js";
3
+ import { Fragment as r, computed as i, createCommentVNode as a, createElementBlock as o, createElementVNode as s, createTextVNode as c, createVNode as l, defineComponent as u, nextTick as d, normalizeClass as f, openBlock as p, reactive as m, renderList as h, toDisplayString as g, unref as ee } from "vue";
3
4
  //#region lib/merge/element-detail.vue?vue&type=script&setup=true&lang.ts
4
- var f = {
5
+ var te = {
5
6
  key: 0,
6
7
  class: "flex h-full flex-col gap-3 overflow-auto p-3 text-sm"
7
- }, p = { class: "flex items-center gap-2" }, m = { class: "font-medium" }, h = { class: "badge badge-sm opacity-70" }, g = {
8
+ }, ne = { class: "flex items-center gap-2" }, _ = { class: "font-medium" }, v = { class: "badge badge-sm opacity-70" }, y = {
8
9
  key: 0,
9
- class: "flex flex-col gap-2 font-mono text-xs"
10
- }, _ = { class: "whitespace-nowrap shrink-0 opacity-70" }, v = { class: "flex w-full items-center" }, y = {
10
+ class: "flex flex-col gap-2 text-xs"
11
+ }, b = { class: "flex items-center gap-2" }, x = ["title"], S = ["aria-label"], C = ["aria-checked", "onClick"], w = ["title"], re = ["aria-checked", "onClick"], ie = ["title"], T = ["aria-checked", "onClick"], E = {
11
12
  key: 0,
12
13
  class: "shrink-0 select-none opacity-60"
13
- }, b = ["value", "onInput"], x = {
14
+ }, D = [
15
+ "value",
16
+ "readonly",
17
+ "onInput"
18
+ ], O = {
14
19
  key: 1,
15
20
  class: "shrink-0 select-none opacity-60"
16
- }, S = {
17
- key: 0,
21
+ }, k = {
22
+ key: 2,
18
23
  class: "badge badge-warning badge-xs shrink-0",
19
24
  title: "Auto-resolved to avoid a naming collision — edit to override"
20
- }, C = {
25
+ }, A = {
26
+ key: 0,
27
+ class: "mt-1.5 flex items-center gap-2"
28
+ }, j = { class: "flex w-full items-center font-mono" }, M = {
29
+ key: 0,
30
+ class: "shrink-0 select-none opacity-60"
31
+ }, N = ["value", "onInput"], P = {
32
+ key: 1,
33
+ class: "shrink-0 select-none opacity-60"
34
+ }, F = {
21
35
  key: 1,
22
36
  class: "text-xs opacity-60"
23
- }, w = {
37
+ }, I = {
24
38
  key: 1,
25
39
  class: "grid h-full place-items-center p-4 text-sm opacity-60"
26
- }, T = /*@__PURE__*/ s({
40
+ }, L = /*@__PURE__*/ u({
27
41
  __name: "element-detail",
28
42
  props: {
29
43
  detail: {},
30
- affixMask: { type: Function }
44
+ affixMask: { type: Function },
45
+ disabled: { type: Boolean }
31
46
  },
32
47
  emits: ["edit"],
33
- setup(s, { emit: T }) {
34
- let E = s, D = T, O = r(() => ({
48
+ setup(u, { emit: L }) {
49
+ let R = {
50
+ accept: {
51
+ border: "border-success",
52
+ label: "bg-success text-success-content",
53
+ value: "bg-success/15 text-success"
54
+ },
55
+ skip: {
56
+ border: "border-warning",
57
+ label: "bg-warning text-black",
58
+ value: "bg-warning/20 text-black"
59
+ },
60
+ other: {
61
+ border: "border-info",
62
+ label: "bg-info text-info-content",
63
+ value: "bg-info/15 text-info"
64
+ }
65
+ }, z = u, B = L, V = m(/* @__PURE__ */ new Set()), H = /* @__PURE__ */ new Map(), U = i(() => ({
35
66
  added: "badge-success",
36
67
  removed: "badge-error",
37
68
  modified: "badge-warning",
38
- unchanged: "badge-ghost"
39
- })[E.detail?.change ?? "unchanged"]), k = r(() => E.detail?.attributes.filter((e) => e.editable));
40
- function A(e) {
41
- if (!(!E.detail || !E.affixMask)) return E.affixMask({
42
- tag: E.detail.tag,
69
+ unchanged: "badge-ghost",
70
+ "target-only": "badge-info"
71
+ })[z.detail?.change ?? "unchanged"]), W = i(() => [...z.detail?.attributes ?? []].filter((e) => e.editable).sort((e, t) => Number(J(t)) - Number(J(e))));
72
+ function G(e) {
73
+ if (!(!z.detail || !z.affixMask)) return z.affixMask({
74
+ tag: z.detail.tag,
43
75
  attr: e.name
44
76
  });
45
77
  }
46
- function j(e) {
47
- return t(e.after ?? "", A(e));
78
+ function K(e) {
79
+ return z.disabled ? e.before ?? e.after ?? "" : e.written ?? e.after ?? "";
80
+ }
81
+ function q(e) {
82
+ return n(K(e), G(e));
83
+ }
84
+ function J(e) {
85
+ return e.status === "modified";
86
+ }
87
+ function Y(e) {
88
+ return e && e.length > 0 ? e : "∅";
89
+ }
90
+ function X(e) {
91
+ if (V.has(e.name)) return "other";
92
+ let t = K(e);
93
+ return t === (e.after ?? "") ? "accept" : t === (e.before ?? "") ? "skip" : "other";
94
+ }
95
+ function Z(e, t) {
96
+ if (t === "other") {
97
+ V.add(e.name), d(() => H.get(e.name)?.focus());
98
+ return;
99
+ }
100
+ V.delete(e.name), B("edit", e.name, t === "accept" ? e.after ?? "" : e.before ?? "");
101
+ }
102
+ function Q(e, t) {
103
+ t instanceof HTMLInputElement ? H.set(e.name, t) : H.delete(e.name);
48
104
  }
49
- function M(t, n) {
105
+ function $(e, n) {
50
106
  let r = n.target.value;
51
- D("edit", t.name, e(r, A(t)));
107
+ B("edit", e.name, t(r, G(e)));
52
108
  }
53
- return (e, t) => s.detail ? (l(), a("div", f, [o("header", p, [
54
- o("span", m, d(s.detail.title), 1),
55
- o("span", h, d(s.detail.tag), 1),
56
- o("span", { class: c(["badge badge-sm", O.value]) }, d(s.detail.change), 3)
57
- ]), k.value?.length ? (l(), a("div", g, [(l(!0), a(n, null, u(k.value, (e) => (l(), a("label", {
58
- key: e.name,
59
- class: "flex items-center gap-2"
60
- }, [
61
- o("span", _, d(e.name) + ":", 1),
62
- o("span", v, [
63
- j(e).prefix ? (l(), a("span", y, d(j(e).prefix), 1)) : i("", !0),
64
- o("input", {
65
- class: c(["input input-xs input-bordered w-full font-mono", { "input-warning": e.conflict }]),
66
- value: j(e).core,
67
- onInput: (t) => M(e, t)
68
- }, null, 42, b),
69
- j(e).suffix ? (l(), a("span", x, d(j(e).suffix), 1)) : i("", !0)
70
- ]),
71
- e.conflict ? (l(), a("span", S, " conflict ")) : i("", !0)
72
- ]))), 128))])) : (l(), a("div", C, "No editable fields. See the diff below."))])) : (l(), a("div", w, " Select an element to see its changes. "));
109
+ return (t, n) => u.detail ? (p(), o("div", te, [s("header", ne, [
110
+ s("span", _, g(u.detail.title), 1),
111
+ s("span", v, g(u.detail.tag), 1),
112
+ s("span", { class: f(["badge badge-sm", U.value]) }, g(u.detail.change), 3)
113
+ ]), W.value.length ? (p(), o("div", y, [(p(!0), o(r, null, h(W.value, (t) => (p(), o("div", {
114
+ key: t.name,
115
+ class: f(["rounded-md border px-2 py-1.5", J(t) ? "border-warning/40 bg-warning/5" : "border-base-200"])
116
+ }, [s("div", b, [
117
+ s("span", {
118
+ class: "w-24 shrink-0 truncate opacity-70",
119
+ title: t.name
120
+ }, g(t.name), 9, x),
121
+ J(t) ? (p(), o("div", {
122
+ key: 0,
123
+ class: f(["flex flex-1 flex-wrap items-center gap-1.5", u.disabled && "pointer-events-none opacity-60"]),
124
+ role: "radiogroup",
125
+ "aria-label": `Decision for ${t.name}`
126
+ }, [
127
+ s("button", {
128
+ type: "button",
129
+ class: f(["inline-flex items-stretch overflow-hidden rounded-md border-2 text-xs transition", X(t) === "accept" ? R.accept.border : "border-transparent opacity-55 hover:opacity-100"]),
130
+ role: "radio",
131
+ "aria-checked": X(t) === "accept",
132
+ onClick: (e) => Z(t, "accept")
133
+ }, [s("span", { class: f(["px-2 py-0.5 font-semibold", R.accept.label]) }, " Accept ", 2), s("span", {
134
+ class: f(["max-w-[12ch] truncate px-2 py-0.5 font-mono", R.accept.value]),
135
+ title: Y(t.after)
136
+ }, g(Y(t.after)), 11, w)], 10, C),
137
+ s("button", {
138
+ type: "button",
139
+ class: f(["inline-flex items-stretch overflow-hidden rounded-md border-2 text-xs transition", X(t) === "skip" ? R.skip.border : "border-transparent opacity-55 hover:opacity-100"]),
140
+ role: "radio",
141
+ "aria-checked": X(t) === "skip",
142
+ onClick: (e) => Z(t, "skip")
143
+ }, [s("span", { class: f(["px-2 py-0.5 font-semibold", R.skip.label]) }, " Skip ", 2), s("span", {
144
+ class: f(["max-w-[12ch] truncate px-2 py-0.5 font-mono", R.skip.value]),
145
+ title: Y(t.before)
146
+ }, g(Y(t.before)), 11, ie)], 10, re),
147
+ s("button", {
148
+ type: "button",
149
+ class: f(["inline-flex items-stretch overflow-hidden rounded-md border-2 text-xs transition", X(t) === "other" ? R.other.border : "border-transparent opacity-55 hover:opacity-100"]),
150
+ role: "radio",
151
+ "aria-checked": X(t) === "other",
152
+ onClick: (e) => Z(t, "other")
153
+ }, [s("span", { class: f(["flex items-center gap-1 px-2 py-0.5 font-semibold", R.other.label]) }, [l(ee(e), { class: "size-3" }), n[0] ||= c(" Other ", -1)], 2)], 10, T)
154
+ ], 10, S)) : (p(), o("span", {
155
+ key: 1,
156
+ class: f(["flex w-full items-center font-mono", u.disabled && "pointer-events-none opacity-60"])
157
+ }, [
158
+ q(t).prefix ? (p(), o("span", E, g(q(t).prefix), 1)) : a("", !0),
159
+ s("input", {
160
+ ref_for: !0,
161
+ ref: (e) => Q(t, e),
162
+ class: f(["input input-xs input-bordered w-full font-mono", { "input-warning": t.conflict }]),
163
+ value: q(t).core,
164
+ readonly: u.disabled,
165
+ onInput: (e) => $(t, e)
166
+ }, null, 42, D),
167
+ q(t).suffix ? (p(), o("span", O, g(q(t).suffix), 1)) : a("", !0)
168
+ ], 2)),
169
+ t.conflict ? (p(), o("span", k, " conflict ")) : a("", !0)
170
+ ]), J(t) && X(t) === "other" ? (p(), o("div", A, [n[1] ||= s("span", { class: "w-24 shrink-0" }, null, -1), s("span", j, [
171
+ q(t).prefix ? (p(), o("span", M, g(q(t).prefix), 1)) : a("", !0),
172
+ s("input", {
173
+ ref_for: !0,
174
+ ref: (e) => Q(t, e),
175
+ class: f(["input input-xs input-bordered w-full font-mono", { "input-warning": t.conflict }]),
176
+ value: q(t).core,
177
+ placeholder: "custom value",
178
+ onInput: (e) => $(t, e)
179
+ }, null, 42, N),
180
+ q(t).suffix ? (p(), o("span", P, g(q(t).suffix), 1)) : a("", !0)
181
+ ])])) : a("", !0)], 2))), 128))])) : (p(), o("div", F, "No editable fields. See the diff below."))])) : (p(), o("div", I, " Select an element to see its changes. "));
73
182
  }
74
183
  });
75
184
  //#endregion
76
- export { T as default };
185
+ export { L as default };