@issuegraph/editor 0.1.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 (143) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +238 -0
  3. package/dist/audit/findings.d.ts +225 -0
  4. package/dist/audit/findings.d.ts.map +1 -0
  5. package/dist/audit/findings.js +348 -0
  6. package/dist/audit/findings.js.map +1 -0
  7. package/dist/audit/styles.d.ts +37 -0
  8. package/dist/audit/styles.d.ts.map +1 -0
  9. package/dist/audit/styles.js +72 -0
  10. package/dist/audit/styles.js.map +1 -0
  11. package/dist/audit/surface.d.ts +155 -0
  12. package/dist/audit/surface.d.ts.map +1 -0
  13. package/dist/audit/surface.js +202 -0
  14. package/dist/audit/surface.js.map +1 -0
  15. package/dist/create/draft.d.ts +119 -0
  16. package/dist/create/draft.d.ts.map +1 -0
  17. package/dist/create/draft.js +114 -0
  18. package/dist/create/draft.js.map +1 -0
  19. package/dist/create/keys.d.ts +225 -0
  20. package/dist/create/keys.d.ts.map +1 -0
  21. package/dist/create/keys.js +228 -0
  22. package/dist/create/keys.js.map +1 -0
  23. package/dist/create/placement.d.ts +69 -0
  24. package/dist/create/placement.d.ts.map +1 -0
  25. package/dist/create/placement.js +76 -0
  26. package/dist/create/placement.js.map +1 -0
  27. package/dist/firstpass/batch.d.ts +190 -0
  28. package/dist/firstpass/batch.d.ts.map +1 -0
  29. package/dist/firstpass/batch.js +143 -0
  30. package/dist/firstpass/batch.js.map +1 -0
  31. package/dist/firstpass/candidates.d.ts +128 -0
  32. package/dist/firstpass/candidates.d.ts.map +1 -0
  33. package/dist/firstpass/candidates.js +39 -0
  34. package/dist/firstpass/candidates.js.map +1 -0
  35. package/dist/firstpass/keys.d.ts +90 -0
  36. package/dist/firstpass/keys.d.ts.map +1 -0
  37. package/dist/firstpass/keys.js +112 -0
  38. package/dist/firstpass/keys.js.map +1 -0
  39. package/dist/firstpass/queue.d.ts +183 -0
  40. package/dist/firstpass/queue.d.ts.map +1 -0
  41. package/dist/firstpass/queue.js +159 -0
  42. package/dist/firstpass/queue.js.map +1 -0
  43. package/dist/firstpass/render.d.ts +100 -0
  44. package/dist/firstpass/render.d.ts.map +1 -0
  45. package/dist/firstpass/render.js +216 -0
  46. package/dist/firstpass/render.js.map +1 -0
  47. package/dist/firstpass/styles.d.ts +36 -0
  48. package/dist/firstpass/styles.d.ts.map +1 -0
  49. package/dist/firstpass/styles.js +148 -0
  50. package/dist/firstpass/styles.js.map +1 -0
  51. package/dist/firstpass/view.d.ts +82 -0
  52. package/dist/firstpass/view.d.ts.map +1 -0
  53. package/dist/firstpass/view.js +60 -0
  54. package/dist/firstpass/view.js.map +1 -0
  55. package/dist/firstpass/words.d.ts +105 -0
  56. package/dist/firstpass/words.d.ts.map +1 -0
  57. package/dist/firstpass/words.js +28 -0
  58. package/dist/firstpass/words.js.map +1 -0
  59. package/dist/index.d.ts +150 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +147 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/overlay/grammar.d.ts +259 -0
  64. package/dist/overlay/grammar.d.ts.map +1 -0
  65. package/dist/overlay/grammar.js +223 -0
  66. package/dist/overlay/grammar.js.map +1 -0
  67. package/dist/overlay/render.d.ts +125 -0
  68. package/dist/overlay/render.d.ts.map +1 -0
  69. package/dist/overlay/render.js +439 -0
  70. package/dist/overlay/render.js.map +1 -0
  71. package/dist/overlay/styles.d.ts +41 -0
  72. package/dist/overlay/styles.d.ts.map +1 -0
  73. package/dist/overlay/styles.js +124 -0
  74. package/dist/overlay/styles.js.map +1 -0
  75. package/dist/picker/render.d.ts +80 -0
  76. package/dist/picker/render.d.ts.map +1 -0
  77. package/dist/picker/render.js +112 -0
  78. package/dist/picker/render.js.map +1 -0
  79. package/dist/picker/styles.d.ts +26 -0
  80. package/dist/picker/styles.d.ts.map +1 -0
  81. package/dist/picker/styles.js +116 -0
  82. package/dist/picker/styles.js.map +1 -0
  83. package/dist/picker/view.d.ts +135 -0
  84. package/dist/picker/view.d.ts.map +1 -0
  85. package/dist/picker/view.js +117 -0
  86. package/dist/picker/view.js.map +1 -0
  87. package/dist/picker/words.d.ts +53 -0
  88. package/dist/picker/words.d.ts.map +1 -0
  89. package/dist/picker/words.js +28 -0
  90. package/dist/picker/words.js.map +1 -0
  91. package/dist/reevaluate/render.d.ts +77 -0
  92. package/dist/reevaluate/render.d.ts.map +1 -0
  93. package/dist/reevaluate/render.js +211 -0
  94. package/dist/reevaluate/render.js.map +1 -0
  95. package/dist/reevaluate/styles.d.ts +24 -0
  96. package/dist/reevaluate/styles.d.ts.map +1 -0
  97. package/dist/reevaluate/styles.js +182 -0
  98. package/dist/reevaluate/styles.js.map +1 -0
  99. package/dist/reevaluate/view.d.ts +102 -0
  100. package/dist/reevaluate/view.d.ts.map +1 -0
  101. package/dist/reevaluate/view.js +111 -0
  102. package/dist/reevaluate/view.js.map +1 -0
  103. package/dist/reevaluate/words.d.ts +54 -0
  104. package/dist/reevaluate/words.d.ts.map +1 -0
  105. package/dist/reevaluate/words.js +29 -0
  106. package/dist/reevaluate/words.js.map +1 -0
  107. package/dist/scale/commands.d.ts +60 -0
  108. package/dist/scale/commands.d.ts.map +1 -0
  109. package/dist/scale/commands.js +49 -0
  110. package/dist/scale/commands.js.map +1 -0
  111. package/dist/scale/ladder.d.ts +141 -0
  112. package/dist/scale/ladder.d.ts.map +1 -0
  113. package/dist/scale/ladder.js +243 -0
  114. package/dist/scale/ladder.js.map +1 -0
  115. package/dist/scale/render.d.ts +85 -0
  116. package/dist/scale/render.d.ts.map +1 -0
  117. package/dist/scale/render.js +194 -0
  118. package/dist/scale/render.js.map +1 -0
  119. package/dist/scale/styles.d.ts +21 -0
  120. package/dist/scale/styles.d.ts.map +1 -0
  121. package/dist/scale/styles.js +105 -0
  122. package/dist/scale/styles.js.map +1 -0
  123. package/dist/workspace/inspector.d.ts +117 -0
  124. package/dist/workspace/inspector.d.ts.map +1 -0
  125. package/dist/workspace/inspector.js +140 -0
  126. package/dist/workspace/inspector.js.map +1 -0
  127. package/dist/workspace/rail.d.ts +122 -0
  128. package/dist/workspace/rail.d.ts.map +1 -0
  129. package/dist/workspace/rail.js +216 -0
  130. package/dist/workspace/rail.js.map +1 -0
  131. package/dist/workspace/render.d.ts +139 -0
  132. package/dist/workspace/render.d.ts.map +1 -0
  133. package/dist/workspace/render.js +366 -0
  134. package/dist/workspace/render.js.map +1 -0
  135. package/dist/workspace/selection.d.ts +92 -0
  136. package/dist/workspace/selection.d.ts.map +1 -0
  137. package/dist/workspace/selection.js +83 -0
  138. package/dist/workspace/selection.js.map +1 -0
  139. package/dist/workspace/styles.d.ts +39 -0
  140. package/dist/workspace/styles.d.ts.map +1 -0
  141. package/dist/workspace/styles.js +313 -0
  142. package/dist/workspace/styles.js.map +1 -0
  143. package/package.json +58 -0
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The picker's words. Supplied by the host, never by this package.
3
+ *
4
+ * Same contract, and the same reasoning, as
5
+ * {@link ../reevaluate/words.ts ChangeWords}: the store deliberately stops at
6
+ * data rather than prose, and a default vocabulary here would take that choice
7
+ * back one layer down. It is sharper for this surface than for the summary,
8
+ * because what is being worded is a RELATIONSHIP — "is blocked by" carries a
9
+ * word order as well as a language, and a package that shipped the phrase would
10
+ * ship an English clause its consumers could not translate or reverse.
11
+ *
12
+ * SO IT IS REQUIRED, NOT DEFAULTED, exactly as `StoreConfig.derive` is: a
13
+ * default would be a second implementation of something this layer is not
14
+ * entitled to decide.
15
+ *
16
+ * ## One vocabulary, read in two places
17
+ *
18
+ * {@link PickerWords.kinds} words both a picker OPTION ("is blocked by", chosen
19
+ * from a list of five) and the DIRECTION STATEMENT it produces ("#530 is
20
+ * blocked by #602"). One entry has to read in both positions, which is the same
21
+ * constraint `ChangeWords.facets` carries for the summary and its chips.
22
+ *
23
+ * A host wanting two registers — a short label in the list, a full clause in
24
+ * the statement — renders {@link ../picker/view.ts PickerView} itself. Nothing
25
+ * in the default render is load-bearing for that.
26
+ */
27
+ import type { EdgeKind } from '@issuegraph/store';
28
+ export interface PickerWords {
29
+ /**
30
+ * One relational phrase per kind.
31
+ *
32
+ * `Record<EdgeKind, string>` rather than a partial map: a kind with no phrase
33
+ * would render as a bare reference pair, which reads as a DIFFERENT
34
+ * relationship rather than as a missing label — and mistaking one
35
+ * relationship for another is the encoding error this surface exists to
36
+ * prevent. A kind added to the format fails a host's build here, which is
37
+ * where it can be fixed.
38
+ */
39
+ readonly kinds: Readonly<Record<EdgeKind, string>>;
40
+ /** Names the picker for a screen reader and for a visible heading. */
41
+ readonly heading: string;
42
+ /** The control that reverses a directed relationship. */
43
+ readonly flip: string;
44
+ /**
45
+ * Marks the option the edge already carries.
46
+ *
47
+ * A word rather than a colour: "which one is it now" is the question the
48
+ * picker is opened to answer, and a purely visual answer is unavailable to a
49
+ * screen reader and to a host with a monochrome theme.
50
+ */
51
+ readonly current: string;
52
+ }
53
+ //# sourceMappingURL=words.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"words.d.ts","sourceRoot":"","sources":["../../src/picker/words.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;OASG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The picker's words. Supplied by the host, never by this package.
3
+ *
4
+ * Same contract, and the same reasoning, as
5
+ * {@link ../reevaluate/words.ts ChangeWords}: the store deliberately stops at
6
+ * data rather than prose, and a default vocabulary here would take that choice
7
+ * back one layer down. It is sharper for this surface than for the summary,
8
+ * because what is being worded is a RELATIONSHIP — "is blocked by" carries a
9
+ * word order as well as a language, and a package that shipped the phrase would
10
+ * ship an English clause its consumers could not translate or reverse.
11
+ *
12
+ * SO IT IS REQUIRED, NOT DEFAULTED, exactly as `StoreConfig.derive` is: a
13
+ * default would be a second implementation of something this layer is not
14
+ * entitled to decide.
15
+ *
16
+ * ## One vocabulary, read in two places
17
+ *
18
+ * {@link PickerWords.kinds} words both a picker OPTION ("is blocked by", chosen
19
+ * from a list of five) and the DIRECTION STATEMENT it produces ("#530 is
20
+ * blocked by #602"). One entry has to read in both positions, which is the same
21
+ * constraint `ChangeWords.facets` carries for the summary and its chips.
22
+ *
23
+ * A host wanting two registers — a short label in the list, a full clause in
24
+ * the statement — renders {@link ../picker/view.ts PickerView} itself. Nothing
25
+ * in the default render is load-bearing for that.
26
+ */
27
+ export {};
28
+ //# sourceMappingURL=words.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"words.js","sourceRoot":"","sources":["../../src/picker/words.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The re-evaluate surface, as markup: the rail, a summary of what the last edit
3
+ * did to it, and a delta chip for each row that changed.
4
+ *
5
+ * ## It draws nothing inside a row
6
+ *
7
+ * The rail is `@issuegraph/viewer`'s linear projection, composed here as a SPEC
8
+ * rather than as a string — `renderViewer` hands back `scene.root`, so the
9
+ * viewer's tree nests inside this one and every byte still comes out of
10
+ * `renderMarkup`. Nothing is concatenated by hand, and no attribute value in
11
+ * this package is ever escaped by anything but the one renderer.
12
+ *
13
+ * That is what makes the design's rule structural instead of asserted:
14
+ * **unaffected rows are left completely alone** because this package never
15
+ * touches a row. The rejected alternative — splice chips into the rail's markup
16
+ * string — would have re-introduced exactly the hand-built escaping surface the
17
+ * spec grammar exists to remove.
18
+ *
19
+ * ## The chips are a KEYED LIST, and this package does not position them
20
+ *
21
+ * Said plainly because the earlier wording did not: `data-ig-key` has no
22
+ * browser behaviour of its own. The chips render as a list beside the rail, and
23
+ * putting one ON its row needs that row's geometry — which only a mount has,
24
+ * and this package has no mount. Naming it an overlay while shipping a
25
+ * normal-flow list claimed a positioning this markup cannot do.
26
+ *
27
+ * So the list is built to stand on its own instead: every chip NAMES the row it
28
+ * describes, which is what lets a reader account for the rows that got no chip.
29
+ * The key is published for the mount that will position them, and that mount
30
+ * lands with the change that assembles the workspace — the same boundary the
31
+ * scale ladder already draws when it defers listener wiring and focus
32
+ * restoration to whoever owns the mount.
33
+ *
34
+ * ## Two rejected alternatives from the design, recorded so they stay rejected
35
+ *
36
+ * A before/after side-by-side makes the owner redo the comparison the machine
37
+ * already did, and doubles the surface at 300 rows. An animated re-sort is
38
+ * pretty once and unusable in a loop, because rows moving under the cursor mean
39
+ * the next edit targets the wrong thing. Neither is reachable from here.
40
+ *
41
+ * ## Nothing dismisses itself
42
+ *
43
+ * There is no timer, and there is no view state. `Store.dismissChange()` is
44
+ * already the only thing besides the next edit that clears the summary, so this
45
+ * renders a control publishing `data-ig-command="dismiss-change"` and lets the
46
+ * store stay the single source of truth. A second copy of "has this been
47
+ * dismissed" held out here is the drift the command grammar exists to avoid.
48
+ */
49
+ import { type Theme, type ViewerDocument } from '@issuegraph/viewer';
50
+ import type { OrderChange, OrderStatus } from '@issuegraph/store';
51
+ import type { ChangeWords } from './words.ts';
52
+ import { type ReevaluateView } from './view.ts';
53
+ export interface ReevaluateOptions {
54
+ /**
55
+ * The words. Required — see {@link ChangeWords} for why this package will not
56
+ * invent them.
57
+ */
58
+ readonly words: ChangeWords;
59
+ /** The store's `lastChange`. Absent means no edit has landed to report. */
60
+ readonly change?: OrderChange | null | undefined;
61
+ /** The store's `order.status`. `held` greys and labels the rail. */
62
+ readonly status?: OrderStatus | undefined;
63
+ readonly theme?: Theme | undefined;
64
+ /** The selector the theme's custom properties are written onto. */
65
+ readonly themeSelector?: string | undefined;
66
+ }
67
+ export interface ReevaluateResult {
68
+ readonly view: ReevaluateView;
69
+ /** The whole surface: the summary, the chips, and the rail inside one root. */
70
+ readonly markup: string;
71
+ /** The viewer's stylesheet, the theme, and this surface's own. Install all. */
72
+ readonly styles: string;
73
+ readonly diagnostics: readonly string[];
74
+ }
75
+ /** Render the order, and what the last edit did to it. */
76
+ export declare function renderReevaluate(input: ViewerDocument, options: ReevaluateOptions): ReevaluateResult;
77
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/reevaluate/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,EAEL,KAAK,KAAK,EACV,KAAK,cAAc,EAMpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAa,MAAM,mBAAmB,CAAC;AAE7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAuC,KAAK,cAAc,EAAkB,MAAM,WAAW,CAAC;AAGrG,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IACjD,oEAAoE;IACpE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IACnC,mEAAmE;IACnE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7C;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAqJD,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,iBAAiB,GACzB,gBAAgB,CA8ClB"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * The re-evaluate surface, as markup: the rail, a summary of what the last edit
3
+ * did to it, and a delta chip for each row that changed.
4
+ *
5
+ * ## It draws nothing inside a row
6
+ *
7
+ * The rail is `@issuegraph/viewer`'s linear projection, composed here as a SPEC
8
+ * rather than as a string — `renderViewer` hands back `scene.root`, so the
9
+ * viewer's tree nests inside this one and every byte still comes out of
10
+ * `renderMarkup`. Nothing is concatenated by hand, and no attribute value in
11
+ * this package is ever escaped by anything but the one renderer.
12
+ *
13
+ * That is what makes the design's rule structural instead of asserted:
14
+ * **unaffected rows are left completely alone** because this package never
15
+ * touches a row. The rejected alternative — splice chips into the rail's markup
16
+ * string — would have re-introduced exactly the hand-built escaping surface the
17
+ * spec grammar exists to remove.
18
+ *
19
+ * ## The chips are a KEYED LIST, and this package does not position them
20
+ *
21
+ * Said plainly because the earlier wording did not: `data-ig-key` has no
22
+ * browser behaviour of its own. The chips render as a list beside the rail, and
23
+ * putting one ON its row needs that row's geometry — which only a mount has,
24
+ * and this package has no mount. Naming it an overlay while shipping a
25
+ * normal-flow list claimed a positioning this markup cannot do.
26
+ *
27
+ * So the list is built to stand on its own instead: every chip NAMES the row it
28
+ * describes, which is what lets a reader account for the rows that got no chip.
29
+ * The key is published for the mount that will position them, and that mount
30
+ * lands with the change that assembles the workspace — the same boundary the
31
+ * scale ladder already draws when it defers listener wiring and focus
32
+ * restoration to whoever owns the mount.
33
+ *
34
+ * ## Two rejected alternatives from the design, recorded so they stay rejected
35
+ *
36
+ * A before/after side-by-side makes the owner redo the comparison the machine
37
+ * already did, and doubles the surface at 300 rows. An animated re-sort is
38
+ * pretty once and unusable in a loop, because rows moving under the cursor mean
39
+ * the next edit targets the wrong thing. Neither is reachable from here.
40
+ *
41
+ * ## Nothing dismisses itself
42
+ *
43
+ * There is no timer, and there is no view state. `Store.dismissChange()` is
44
+ * already the only thing besides the next edit that clears the summary, so this
45
+ * renders a control publishing `data-ig-command="dismiss-change"` and lets the
46
+ * store stay the single source of truth. A second copy of "has this been
47
+ * dismissed" held out here is the drift the command grammar exists to avoid.
48
+ */
49
+ import { KEY_ATTRIBUTE, element, renderMarkup, renderViewer, resolveTheme, } from '@issuegraph/viewer';
50
+ import { reevaluateView } from "./view.js";
51
+ import { reevaluateStylesheet } from "./styles.js";
52
+ function countWord(count, word) {
53
+ return [
54
+ element('span', { class: 'ig-change-count' }, [String(count)]),
55
+ element('span', { class: 'ig-change-word' }, [word]),
56
+ ];
57
+ }
58
+ function summarySpec(summary, words) {
59
+ return element('div', {
60
+ class: 'ig-change-summary',
61
+ // Omitted rather than falsified while there is nothing to report: an
62
+ // element() attribute whose value is `undefined` is not written at all,
63
+ // and `data-unchanged="false"` would claim an edit landed and moved
64
+ // nothing when no edit has landed.
65
+ 'data-unchanged': summary === null ? undefined : summary.unchanged ? 'true' : 'false',
66
+ 'data-op': summary?.op,
67
+ 'data-mutation': summary?.mutationId,
68
+ }, [
69
+ // THE LIVE REGION IS ALWAYS MOUNTED, AND EMPTY UNTIL THERE IS SOMETHING
70
+ // TO SAY. A `role="status"` node that is CREATED already carrying its
71
+ // text is not reliably announced — the region has to exist first and
72
+ // then have its contents change — so rendering it only alongside a
73
+ // summary would silently lose the FIRST summary after a load, which is
74
+ // the one a reader is most likely to be waiting for.
75
+ //
76
+ // It is also why the region is this wrapper rather than the content
77
+ // inside it: an edit that moved something renders a list and one that
78
+ // moved nothing renders a paragraph, so a role on either would come and
79
+ // go with the shape. And the dismiss button stays OUTSIDE, or its label
80
+ // would be re-announced with every summary.
81
+ //
82
+ // It is a role, not a timer. Nothing about it expires and the region
83
+ // stays put until the next edit or an explicit dismissal.
84
+ element('div', { class: 'ig-change-line', role: 'status' }, summary === null
85
+ ? []
86
+ : [
87
+ // THE ZERO CASE RENDERS, in the summary's own place. An edit that
88
+ // landed and moved nothing is the finding an owner auditing an
89
+ // encoding most needs, and drawing nothing for it is the defect
90
+ // this branch prevents.
91
+ summary.unchanged
92
+ ? element('p', { class: 'ig-change-unchanged' }, [words.unchanged])
93
+ : element('ul', { class: 'ig-change-parts' }, summary.parts.map((part) => element('li', { class: 'ig-change-part', 'data-facet': part.facet }, [
94
+ ...countWord(part.count, words.facets[part.facet]),
95
+ ]))),
96
+ ]),
97
+ // ITS OWN CLASS, not the ladder's `.ig-chip`. That class is defined only
98
+ // in `scale/styles.ts`, so borrowing it would leave this control unstyled
99
+ // for a host that installs this surface and not that one. Folding the two
100
+ // chip looks into one rule is the assembling change's call, not this
101
+ // leaf's — it is the change that first has both on screen at once.
102
+ //
103
+ // Absent with no summary: a control that clears nothing is a control that
104
+ // does nothing, and the region above is what has to persist, not this.
105
+ summary === null
106
+ ? null
107
+ : element('button', { type: 'button', class: 'ig-change-dismiss', 'data-ig-command': 'dismiss-change' }, [words.dismiss]),
108
+ ]);
109
+ }
110
+ /**
111
+ * What one issue's delta says, as spans.
112
+ *
113
+ * IT NAMES A DIRECTION AND A DISTANCE, NEVER A RANK. `RankMovement.from` and
114
+ * `.to` are the deriver's 0-BASED positions, while the rail beside them renders
115
+ * the viewer's 1-BASED ranks — so printing either as a number would put two
116
+ * different bases side by side and read as an off-by-one. `by` is a distance,
117
+ * which is basis-independent and safe to print. A host that knows the basis and
118
+ * wants the endpoints reads them off `view.chips[].deltas`, which carries every
119
+ * `RankDelta` untouched.
120
+ */
121
+ function memberSpec(delta, words, named) {
122
+ return element('span', { class: 'ig-delta-member', 'data-ref': delta.ref }, [
123
+ // NAMED ONLY WHEN THE NAME ADDS SOMETHING. On a chip whose single member IS
124
+ // the row, the row key above has already said it and repeating it is noise.
125
+ // Everywhere else the ref is load-bearing: two members reading
126
+ // `lead 1 down 1 down` says the row moved twice rather than that a unit of
127
+ // two each moved down one, and a lone member that is NOT the lead is a
128
+ // change to an issue the row key does not name at all.
129
+ named ? element('span', { class: 'ig-delta-ref' }, [delta.ref]) : null,
130
+ delta.movement === undefined
131
+ ? null
132
+ : element('span', {
133
+ class: 'ig-delta-move',
134
+ 'data-direction': delta.movement.direction,
135
+ 'data-by': delta.movement.by,
136
+ }, [...countWord(delta.movement.by, words.direction[delta.movement.direction])]),
137
+ delta.readiness === undefined
138
+ ? null
139
+ : element('span', { class: 'ig-delta-readiness', 'data-readiness': delta.readiness }, [
140
+ words.facets[delta.readiness],
141
+ ]),
142
+ delta.presence === undefined
143
+ ? null
144
+ : element('span', { class: 'ig-delta-presence', 'data-presence': delta.presence }, [
145
+ words.facets[delta.presence],
146
+ ]),
147
+ ]);
148
+ }
149
+ /**
150
+ * One ROW's chip — which can speak for more than one issue.
151
+ *
152
+ * A `together-with` unit is one row and several refs, so its members are nested
153
+ * inside a single chip rather than given one each. Each keeps its own
154
+ * `data-ref`, so a host can still tell which member moved.
155
+ *
156
+ * IT NAMES ITS ROW IN TEXT, not only in `KEY_ATTRIBUTE`. Unpositioned, a chip
157
+ * that carried its key only as an attribute said nothing a reader could see
158
+ * about WHICH row moved — and the rows that did not move are accounted for
159
+ * precisely by not being named here. The key is data, not language, so naming
160
+ * it costs the host no word.
161
+ */
162
+ function chipSpec(chip, words) {
163
+ // One member whose ref IS the row: the key names it, so naming it again would
164
+ // be the only text on the chip that says nothing. Any other shape — several
165
+ // members, or a lone member the row is not named after — needs each fact
166
+ // attributed, or the chip reads as one row's facts repeated.
167
+ const named = chip.deltas.length > 1 || chip.deltas[0]?.ref !== chip.key;
168
+ return element('li', { class: 'ig-delta-chip', [KEY_ATTRIBUTE]: chip.key }, [
169
+ element('span', { class: 'ig-delta-key' }, [chip.key]),
170
+ ...chip.deltas.map((delta) => memberSpec(delta, words, named)),
171
+ ]);
172
+ }
173
+ /** Render the order, and what the last edit did to it. */
174
+ export function renderReevaluate(input, options) {
175
+ const status = options.status ?? 'settled';
176
+ const theme = resolveTheme(options.theme);
177
+ const rail = renderViewer(input, {
178
+ projection: 'linear',
179
+ theme,
180
+ ...(options.themeSelector === undefined ? {} : { themeSelector: options.themeSelector }),
181
+ });
182
+ const view = reevaluateView(options.change, rail.scene, status);
183
+ const root = element('section', {
184
+ class: 'ig-reevaluate',
185
+ // The rail's own state, on the surface that owns the label for it. The
186
+ // viewer draws the order it was handed; whether that order is the current
187
+ // one is a fact only the store knows.
188
+ 'data-order': status,
189
+ }, [
190
+ // "Write landed, order computing" shows the PREVIOUS order, held still,
191
+ // greyed one step and EXPLICITLY LABELLED. A stale-but-labelled order
192
+ // beats a half-computed one, and the rail never shows a rank it is not
193
+ // sure of — which is why nothing here re-ranks anything: the ranks drawn
194
+ // are the ones the caller vouched for, and a chip's movement is drawn as
195
+ // a chip rather than as a rank.
196
+ view.held ? element('p', { class: 'ig-order-computing' }, [options.words.computing]) : null,
197
+ summarySpec(view.summary, options.words),
198
+ view.chips.length === 0
199
+ ? null
200
+ : element('ul', { class: 'ig-delta-list' }, view.chips.map((chip) => chipSpec(chip, options.words))),
201
+ // The viewer's own tree, nested rather than concatenated.
202
+ rail.scene.root,
203
+ ]);
204
+ return {
205
+ view,
206
+ markup: renderMarkup(root),
207
+ styles: `${rail.styles}\n${reevaluateStylesheet}`,
208
+ diagnostics: [...view.diagnostics, ...rail.diagnostics],
209
+ };
210
+ }
211
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/reevaluate/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The re-evaluate surface's structural stylesheet.
3
+ *
4
+ * Same contract as the viewer's and the ladder's: layout, weight and state,
5
+ * never a value. Every colour, length and font is a `var(--ig-…)` the host's
6
+ * theme resolves, so a second theme keeps working here too, and
7
+ * `styles.test.ts` scans these bytes for a literal or an unresolvable token.
8
+ *
9
+ * IT ADDS SELECTORS RATHER THAN REDEFINING THEM, with one deliberate exception
10
+ * that is worth naming: the greyed rail. `.ig-reevaluate[data-order='held']
11
+ * .ig-viewer` reaches a layer-1 class — but only from INSIDE this surface's own
12
+ * root, and only for a state layer 1 does not model. The viewer draws the order
13
+ * it is handed; whether that order is the current one is a fact only the store
14
+ * knows, so the label and the greying belong to whoever knows it. Nothing here
15
+ * changes how the rail looks outside this surface.
16
+ *
17
+ * There is no transition and no animation, anywhere in this file. The design
18
+ * rejected the animated re-sort because rows moving under the cursor mean the
19
+ * next edit targets the wrong thing, and it rejected the toast because the only
20
+ * evidence the edit worked disappears before it is read. A stylesheet is a
21
+ * place both could creep back in.
22
+ */
23
+ export declare const reevaluateStylesheet = "\n.ig-reevaluate {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size);\n line-height: var(--ig-line-height);\n color: var(--ig-text-body);\n}\n\n/* Greyed one step, and never hidden: a stale order that is labelled is still\n the most useful thing on the screen.\n\n A FILTER, NOT A COLOUR, and that is the whole point of this rule. color on\n the rail greys almost nothing: the viewer's own stylesheet sets color\n directly on .ig-title, .ig-id and .ig-hold, and carries the stations\n and badges in background and border-color, none of which inherit at all.\n A specified value beats an inherited one, so the stale order would have kept\n its normal palette while this rule looked like it was doing something.\n\n The enumeration is the trap here, not the oversight: listing the descendants\n to override is the \"a static rule names one spelling of a capability\"\n class this repository has already paid for several times over, and it would\n go stale the first time layer 1 colours something new. filter applies to\n an element AND its whole subtree whatever properties that subtree sets, so\n a descendant added later is covered by construction. styles.test.ts pins\n both halves: that layer 1 really does colour its own descendants, and that\n this rule is not a bare color. */\n.ig-reevaluate[data-order='held'] .ig-viewer {\n filter: grayscale(1);\n}\n\n.ig-order-computing {\n margin: 0;\n color: var(--ig-text-muted);\n font-size: var(--ig-font-size-small);\n}\n\n.ig-change-summary {\n display: flex;\n gap: var(--ig-space);\n align-items: baseline;\n flex-wrap: wrap;\n}\n\n.ig-change-line {\n display: flex;\n align-items: baseline;\n}\n\n.ig-change-parts {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-wrap: wrap;\n /* The blast radius reads as ONE line. The gap is the separator, so no\n punctuation glyph is baked into the markup \u2014 that would be a second\n language choice on top of the words themselves. */\n gap: var(--ig-space);\n}\n\n.ig-change-part {\n display: flex;\n gap: var(--ig-space-tight);\n align-items: baseline;\n}\n\n.ig-change-count {\n font-family: var(--ig-font-mono);\n color: var(--ig-text);\n}\n\n.ig-change-word {\n color: var(--ig-text-body);\n}\n\n.ig-change-unchanged {\n margin: 0;\n color: var(--ig-text-body);\n}\n\n.ig-change-dismiss {\n align-self: flex-start;\n background: var(--ig-surface-2);\n color: var(--ig-text-body);\n border: var(--ig-stroke) solid var(--ig-line);\n border-radius: var(--ig-radius);\n padding: var(--ig-space-tight) var(--ig-space);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size-small);\n cursor: pointer;\n}\n\n.ig-change-dismiss:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-delta-list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n.ig-delta-chip {\n display: flex;\n gap: var(--ig-space-tight);\n align-items: baseline;\n border: var(--ig-stroke) solid var(--ig-line);\n border-radius: var(--ig-radius);\n padding: var(--ig-space-tight);\n background: var(--ig-surface-2);\n}\n\n.ig-delta-member {\n display: flex;\n gap: var(--ig-space-tight);\n align-items: baseline;\n}\n\n.ig-delta-key,\n.ig-delta-ref {\n font-family: var(--ig-font-mono);\n color: var(--ig-text-muted);\n}\n\n/* The count and its word are adjacent spans with no text between them, so\n without this they render as 2up. Same reason .ig-change-part has one. */\n.ig-delta-move {\n display: flex;\n gap: var(--ig-space-tight);\n align-items: baseline;\n}\n\n.ig-delta-move[data-direction='up'] .ig-change-count {\n color: var(--ig-station-ready);\n}\n\n.ig-delta-move[data-direction='down'] .ig-change-count {\n color: var(--ig-text-muted);\n}\n\n.ig-delta-readiness[data-readiness='promoted'] {\n color: var(--ig-station-ready);\n}\n\n.ig-delta-readiness[data-readiness='newly-held'] {\n color: var(--ig-station-held);\n}\n\n.ig-delta-presence {\n color: var(--ig-text-muted);\n}\n";
24
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/reevaluate/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,eAAO,MAAM,oBAAoB,2oIA8JhC,CAAC"}
@@ -0,0 +1,182 @@
1
+ /**
2
+ * The re-evaluate surface's structural stylesheet.
3
+ *
4
+ * Same contract as the viewer's and the ladder's: layout, weight and state,
5
+ * never a value. Every colour, length and font is a `var(--ig-…)` the host's
6
+ * theme resolves, so a second theme keeps working here too, and
7
+ * `styles.test.ts` scans these bytes for a literal or an unresolvable token.
8
+ *
9
+ * IT ADDS SELECTORS RATHER THAN REDEFINING THEM, with one deliberate exception
10
+ * that is worth naming: the greyed rail. `.ig-reevaluate[data-order='held']
11
+ * .ig-viewer` reaches a layer-1 class — but only from INSIDE this surface's own
12
+ * root, and only for a state layer 1 does not model. The viewer draws the order
13
+ * it is handed; whether that order is the current one is a fact only the store
14
+ * knows, so the label and the greying belong to whoever knows it. Nothing here
15
+ * changes how the rail looks outside this surface.
16
+ *
17
+ * There is no transition and no animation, anywhere in this file. The design
18
+ * rejected the animated re-sort because rows moving under the cursor mean the
19
+ * next edit targets the wrong thing, and it rejected the toast because the only
20
+ * evidence the edit worked disappears before it is read. A stylesheet is a
21
+ * place both could creep back in.
22
+ */
23
+ export const reevaluateStylesheet = `
24
+ .ig-reevaluate {
25
+ display: flex;
26
+ flex-direction: column;
27
+ gap: var(--ig-space);
28
+ font-family: var(--ig-font-ui);
29
+ font-size: var(--ig-font-size);
30
+ line-height: var(--ig-line-height);
31
+ color: var(--ig-text-body);
32
+ }
33
+
34
+ /* Greyed one step, and never hidden: a stale order that is labelled is still
35
+ the most useful thing on the screen.
36
+
37
+ A FILTER, NOT A COLOUR, and that is the whole point of this rule. color on
38
+ the rail greys almost nothing: the viewer's own stylesheet sets color
39
+ directly on .ig-title, .ig-id and .ig-hold, and carries the stations
40
+ and badges in background and border-color, none of which inherit at all.
41
+ A specified value beats an inherited one, so the stale order would have kept
42
+ its normal palette while this rule looked like it was doing something.
43
+
44
+ The enumeration is the trap here, not the oversight: listing the descendants
45
+ to override is the "a static rule names one spelling of a capability"
46
+ class this repository has already paid for several times over, and it would
47
+ go stale the first time layer 1 colours something new. filter applies to
48
+ an element AND its whole subtree whatever properties that subtree sets, so
49
+ a descendant added later is covered by construction. styles.test.ts pins
50
+ both halves: that layer 1 really does colour its own descendants, and that
51
+ this rule is not a bare color. */
52
+ .ig-reevaluate[data-order='held'] .ig-viewer {
53
+ filter: grayscale(1);
54
+ }
55
+
56
+ .ig-order-computing {
57
+ margin: 0;
58
+ color: var(--ig-text-muted);
59
+ font-size: var(--ig-font-size-small);
60
+ }
61
+
62
+ .ig-change-summary {
63
+ display: flex;
64
+ gap: var(--ig-space);
65
+ align-items: baseline;
66
+ flex-wrap: wrap;
67
+ }
68
+
69
+ .ig-change-line {
70
+ display: flex;
71
+ align-items: baseline;
72
+ }
73
+
74
+ .ig-change-parts {
75
+ list-style: none;
76
+ margin: 0;
77
+ padding: 0;
78
+ display: flex;
79
+ flex-wrap: wrap;
80
+ /* The blast radius reads as ONE line. The gap is the separator, so no
81
+ punctuation glyph is baked into the markup — that would be a second
82
+ language choice on top of the words themselves. */
83
+ gap: var(--ig-space);
84
+ }
85
+
86
+ .ig-change-part {
87
+ display: flex;
88
+ gap: var(--ig-space-tight);
89
+ align-items: baseline;
90
+ }
91
+
92
+ .ig-change-count {
93
+ font-family: var(--ig-font-mono);
94
+ color: var(--ig-text);
95
+ }
96
+
97
+ .ig-change-word {
98
+ color: var(--ig-text-body);
99
+ }
100
+
101
+ .ig-change-unchanged {
102
+ margin: 0;
103
+ color: var(--ig-text-body);
104
+ }
105
+
106
+ .ig-change-dismiss {
107
+ align-self: flex-start;
108
+ background: var(--ig-surface-2);
109
+ color: var(--ig-text-body);
110
+ border: var(--ig-stroke) solid var(--ig-line);
111
+ border-radius: var(--ig-radius);
112
+ padding: var(--ig-space-tight) var(--ig-space);
113
+ font-family: var(--ig-font-ui);
114
+ font-size: var(--ig-font-size-small);
115
+ cursor: pointer;
116
+ }
117
+
118
+ .ig-change-dismiss:focus-visible {
119
+ outline: var(--ig-focus-ring) solid var(--ig-focus);
120
+ outline-offset: var(--ig-space-tight);
121
+ }
122
+
123
+ .ig-delta-list {
124
+ list-style: none;
125
+ margin: 0;
126
+ padding: 0;
127
+ display: flex;
128
+ flex-direction: column;
129
+ gap: var(--ig-space-tight);
130
+ }
131
+
132
+ .ig-delta-chip {
133
+ display: flex;
134
+ gap: var(--ig-space-tight);
135
+ align-items: baseline;
136
+ border: var(--ig-stroke) solid var(--ig-line);
137
+ border-radius: var(--ig-radius);
138
+ padding: var(--ig-space-tight);
139
+ background: var(--ig-surface-2);
140
+ }
141
+
142
+ .ig-delta-member {
143
+ display: flex;
144
+ gap: var(--ig-space-tight);
145
+ align-items: baseline;
146
+ }
147
+
148
+ .ig-delta-key,
149
+ .ig-delta-ref {
150
+ font-family: var(--ig-font-mono);
151
+ color: var(--ig-text-muted);
152
+ }
153
+
154
+ /* The count and its word are adjacent spans with no text between them, so
155
+ without this they render as 2up. Same reason .ig-change-part has one. */
156
+ .ig-delta-move {
157
+ display: flex;
158
+ gap: var(--ig-space-tight);
159
+ align-items: baseline;
160
+ }
161
+
162
+ .ig-delta-move[data-direction='up'] .ig-change-count {
163
+ color: var(--ig-station-ready);
164
+ }
165
+
166
+ .ig-delta-move[data-direction='down'] .ig-change-count {
167
+ color: var(--ig-text-muted);
168
+ }
169
+
170
+ .ig-delta-readiness[data-readiness='promoted'] {
171
+ color: var(--ig-station-ready);
172
+ }
173
+
174
+ .ig-delta-readiness[data-readiness='newly-held'] {
175
+ color: var(--ig-station-held);
176
+ }
177
+
178
+ .ig-delta-presence {
179
+ color: var(--ig-text-muted);
180
+ }
181
+ `;
182
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/reevaluate/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8JnC,CAAC"}