@issuegraph/editor 0.25.0 → 0.26.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.
- package/README.md +6 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/overlay/render.d.ts.map +1 -1
- package/dist/overlay/render.js +18 -2
- package/dist/overlay/render.js.map +1 -1
- package/dist/reevaluate/styles.d.ts +7 -1
- package/dist/reevaluate/styles.d.ts.map +1 -1
- package/dist/reevaluate/styles.js +32 -11
- package/dist/reevaluate/styles.js.map +1 -1
- package/dist/scale/render.d.ts +5 -1
- package/dist/scale/render.d.ts.map +1 -1
- package/dist/scale/render.js +19 -2
- package/dist/scale/render.js.map +1 -1
- package/dist/workspace/host.d.ts +33 -2
- package/dist/workspace/host.d.ts.map +1 -1
- package/dist/workspace/host.js +64 -14
- package/dist/workspace/host.js.map +1 -1
- package/dist/workspace/inspector.d.ts +9 -0
- package/dist/workspace/inspector.d.ts.map +1 -1
- package/dist/workspace/inspector.js +16 -0
- package/dist/workspace/inspector.js.map +1 -1
- package/dist/workspace/mount.d.ts +17 -3
- package/dist/workspace/mount.d.ts.map +1 -1
- package/dist/workspace/mount.js +150 -30
- package/dist/workspace/mount.js.map +1 -1
- package/dist/workspace/narrow.d.ts +38 -0
- package/dist/workspace/narrow.d.ts.map +1 -0
- package/dist/workspace/narrow.js +48 -0
- package/dist/workspace/narrow.js.map +1 -0
- package/dist/workspace/related.d.ts +65 -0
- package/dist/workspace/related.d.ts.map +1 -0
- package/dist/workspace/related.js +105 -0
- package/dist/workspace/related.js.map +1 -0
- package/dist/workspace/render.d.ts +102 -19
- package/dist/workspace/render.d.ts.map +1 -1
- package/dist/workspace/render.js +211 -29
- package/dist/workspace/render.js.map +1 -1
- package/dist/workspace/selection.d.ts +44 -3
- package/dist/workspace/selection.d.ts.map +1 -1
- package/dist/workspace/selection.js +58 -0
- package/dist/workspace/selection.js.map +1 -1
- package/dist/workspace/styles.d.ts +1 -1
- package/dist/workspace/styles.d.ts.map +1 -1
- package/dist/workspace/styles.js +265 -8
- package/dist/workspace/styles.js.map +1 -1
- package/package.json +3 -3
|
@@ -32,14 +32,15 @@
|
|
|
32
32
|
* clean — which is the audit failing silently on exactly the rows where an
|
|
33
33
|
* encoding error is hardest to see.
|
|
34
34
|
*
|
|
35
|
-
* ## The zone frames, and the one place
|
|
35
|
+
* ## The zone frames, and the one place markup is joined here
|
|
36
36
|
*
|
|
37
37
|
* Two of the four zones hand back a STRING rather than a spec — the ladder's
|
|
38
38
|
* chrome and the audit header — so the frames are assembled by concatenation,
|
|
39
39
|
* as `renderScaleLadder` already assembles its own canvas and chrome. What
|
|
40
|
-
* makes that safe is not care:
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* makes that safe is not care: a frame's own opening tag carries the caller's
|
|
41
|
+
* `surfaceId` in its id, so {@link zone} has `renderMarkup` write it, and only
|
|
42
|
+
* already-rendered markup is joined inside. Everything with a dynamic value in
|
|
43
|
+
* it goes through `renderMarkup`.
|
|
43
44
|
*
|
|
44
45
|
* ## Dark only
|
|
45
46
|
*
|
|
@@ -51,6 +52,7 @@
|
|
|
51
52
|
import { type Theme, type ViewerDocument } from '@issuegraph/viewer';
|
|
52
53
|
import type { EdgeId, InvalidCode, MutationId, OrderChange, OrderStatus, ProjectedEdge } from '@issuegraph/store';
|
|
53
54
|
import type { AuditInput } from '../audit/findings.ts';
|
|
55
|
+
import { type EdgeField } from '@issuegraph/core';
|
|
54
56
|
import { type AuditWords } from '../audit/panel.ts';
|
|
55
57
|
import { type EncodingRefusedBlockOptions } from '../audit/refused.ts';
|
|
56
58
|
import { type CreateDraft } from '../create/draft.ts';
|
|
@@ -59,10 +61,11 @@ import type { ChangeWords } from '../reevaluate/words.ts';
|
|
|
59
61
|
import { type AuditOverlay } from '../audit/surface.ts';
|
|
60
62
|
import { type ScaleState } from '../scale/commands.ts';
|
|
61
63
|
import { type InspectorView } from './inspector.ts';
|
|
64
|
+
import { type CanvasMode, type NarrowView } from './narrow.ts';
|
|
62
65
|
import { type RailWindow, type RailWindowOptions } from './rail.ts';
|
|
63
66
|
import { type ConflictDiff } from './recovery.ts';
|
|
64
67
|
import { type WorkspaceSelection } from './selection.ts';
|
|
65
|
-
/** The four fixed positions.
|
|
68
|
+
/** The four fixed positions. */
|
|
66
69
|
export declare const ZONES: readonly ["header", "rail", "canvas", "inspector"];
|
|
67
70
|
export type Zone = (typeof ZONES)[number];
|
|
68
71
|
export interface WorkspaceWords {
|
|
@@ -139,6 +142,13 @@ export interface WorkspaceWords {
|
|
|
139
142
|
readonly inspector: string;
|
|
140
143
|
/** Shown in the inspector when nothing is selected. */
|
|
141
144
|
readonly nothingSelected: string;
|
|
145
|
+
/**
|
|
146
|
+
* The inspector's heading with two or more issues selected: *"3 issues
|
|
147
|
+
* selected"*. A function for the reason `filteredDenominator` is one: the
|
|
148
|
+
* count sits inside the sentence and its grammar moves with it, so the host
|
|
149
|
+
* writes the sentence.
|
|
150
|
+
*/
|
|
151
|
+
readonly issuesSelected: (count: number) => string;
|
|
142
152
|
/**
|
|
143
153
|
* The control that returns to nothing selected.
|
|
144
154
|
*
|
|
@@ -406,6 +416,16 @@ export interface WorkspaceWords {
|
|
|
406
416
|
* are safely the same.
|
|
407
417
|
*/
|
|
408
418
|
readonly rail?: RailWords | undefined;
|
|
419
|
+
/**
|
|
420
|
+
* The layout under `640`: its three tabs, and the Related groups list's
|
|
421
|
+
* sentence for nothing selected.
|
|
422
|
+
*
|
|
423
|
+
* REQUIRED, unlike `canvas` and `rail`. The tabs are the only way between the
|
|
424
|
+
* three views at that width, and every render draws them, so there is no
|
|
425
|
+
* absent state that would still work: a tab with no name is a control a
|
|
426
|
+
* screen reader announces as nothing.
|
|
427
|
+
*/
|
|
428
|
+
readonly narrow: NarrowWords;
|
|
409
429
|
}
|
|
410
430
|
/**
|
|
411
431
|
* Frame 17a's canvas toolbar reads `focus: #512 · 1 hop · 6 of 312 shown`, and
|
|
@@ -498,6 +518,35 @@ export interface RailWords {
|
|
|
498
518
|
*/
|
|
499
519
|
readonly hide: string;
|
|
500
520
|
}
|
|
521
|
+
/**
|
|
522
|
+
* The words of the layout under `640`, where one of Order, Related groups and
|
|
523
|
+
* Sub-issues shows at a time.
|
|
524
|
+
*/
|
|
525
|
+
export interface NarrowWords {
|
|
526
|
+
/** The tab that shows the order. */
|
|
527
|
+
readonly order: string;
|
|
528
|
+
/** The tab that lists the selection's relationships. */
|
|
529
|
+
readonly related: string;
|
|
530
|
+
/** The tab that shows the sub-issue tree. */
|
|
531
|
+
readonly subIssues: string;
|
|
532
|
+
/**
|
|
533
|
+
* Names the control that closes the Inspector's sheet under `640`. Nothing
|
|
534
|
+
* in this version draws that sheet, so nothing reads this yet.
|
|
535
|
+
*/
|
|
536
|
+
readonly closeSheet: string;
|
|
537
|
+
/** What the Related groups list says while nothing is selected. */
|
|
538
|
+
readonly noSelection: string;
|
|
539
|
+
/** Labels the Related groups search field. */
|
|
540
|
+
readonly searchRelated: string;
|
|
541
|
+
/**
|
|
542
|
+
* Says how many matches the Related groups list left out past its 60-row
|
|
543
|
+
* cut: *"12 more — narrow the search"*. A function for the reason
|
|
544
|
+
* `filteredDenominator` is one: the count sits inside the sentence.
|
|
545
|
+
*/
|
|
546
|
+
readonly omitted: (count: number) => string;
|
|
547
|
+
/** What the Related groups list says when a search matched nothing. */
|
|
548
|
+
readonly noMatch: string;
|
|
549
|
+
}
|
|
501
550
|
export interface RecoveryWords {
|
|
502
551
|
/** Names the state on a failed card. */
|
|
503
552
|
readonly failed: string;
|
|
@@ -889,22 +938,45 @@ export interface WorkspaceOptions {
|
|
|
889
938
|
*/
|
|
890
939
|
readonly diffOpen?: MutationId | null | undefined;
|
|
891
940
|
/**
|
|
892
|
-
* A value unique to this surface, used to bind
|
|
893
|
-
* isolated list the canvas
|
|
894
|
-
*
|
|
895
|
-
*
|
|
896
|
-
*
|
|
897
|
-
* id invented in here would be emitted twice by a
|
|
898
|
-
* workspaces, leaving the second
|
|
899
|
-
* `scale/render.ts`'s `searchSpec`
|
|
900
|
-
*
|
|
901
|
-
*
|
|
902
|
-
*
|
|
903
|
-
*
|
|
904
|
-
*
|
|
905
|
-
*
|
|
941
|
+
* A value unique to this surface, used to bind controls in one zone to what
|
|
942
|
+
* they open in another: §17a's rail footer to the isolated list the canvas
|
|
943
|
+
* draws, and each narrow tab to the zone it shows.
|
|
944
|
+
*
|
|
945
|
+
* SUPPLIED BY WHOEVER KNOWS THE PAGE. A control names its target with
|
|
946
|
+
* `aria-controls`, and an id invented in here would be emitted twice by a
|
|
947
|
+
* host rendering two workspaces, leaving the second surface's controls
|
|
948
|
+
* pointing at the first surface's elements. `scale/render.ts`'s `searchSpec`
|
|
949
|
+
* records the same hazard for its own label. `mountWorkspace` mints a value
|
|
950
|
+
* per mount, so a PAGE THAT DRAWS MORE THAN ONE WORKSPACE WITHOUT A MOUNT
|
|
951
|
+
* PASSES ONE PER WORKSPACE.
|
|
952
|
+
*
|
|
953
|
+
* ABSENT, THE RAIL FOOTER DRAWS NO ASSOCIATION, and that is the honest
|
|
954
|
+
* default rather than a degraded one: markup served without a mount is not
|
|
955
|
+
* operable anyway — the same argument `CanvasWords.editMode` is optional
|
|
956
|
+
* under. A toggle nobody can press needs no `aria-controls`.
|
|
957
|
+
*
|
|
958
|
+
* THE ZONE FRAMES ARE THE ONE EXCEPTION, and they take the fixed ids
|
|
959
|
+
* `ig-zone-<zone>` when this is absent. The tabs are drawn on every render
|
|
960
|
+
* and a tab must name the panel it shows, so a tab with no `aria-controls`
|
|
961
|
+
* would be a broken tab rather than an absent one. The cost is the hazard
|
|
962
|
+
* above, for a page that draws two unmounted workspaces with no value here.
|
|
906
963
|
*/
|
|
907
964
|
readonly surfaceId?: string | undefined;
|
|
965
|
+
/**
|
|
966
|
+
* Which zone the layout under `640` shows. See `HostState.narrowView`.
|
|
967
|
+
* Absent is `'order'`.
|
|
968
|
+
*/
|
|
969
|
+
readonly narrowView?: NarrowView | undefined;
|
|
970
|
+
/**
|
|
971
|
+
* What the canvas zone draws. The tree itself is drawn by `mountWorkspace`;
|
|
972
|
+
* this only tells the tabs which one is selected. Absent is
|
|
973
|
+
* `'neighbourhood'`.
|
|
974
|
+
*/
|
|
975
|
+
readonly canvas?: CanvasMode | undefined;
|
|
976
|
+
/** The Related groups list's open group. See `HostState.relatedGroup`. */
|
|
977
|
+
readonly relatedGroup?: EdgeField | null | undefined;
|
|
978
|
+
/** The Related groups list's search text. See `HostState.relatedQuery`. */
|
|
979
|
+
readonly relatedQuery?: string | undefined;
|
|
908
980
|
}
|
|
909
981
|
export interface WorkspaceView {
|
|
910
982
|
readonly selection: WorkspaceSelection;
|
|
@@ -929,6 +1001,17 @@ export interface WorkspaceResult {
|
|
|
929
1001
|
readonly styles: string;
|
|
930
1002
|
readonly diagnostics: readonly string[];
|
|
931
1003
|
}
|
|
1004
|
+
/**
|
|
1005
|
+
* The search's status line, right under the field: that a search matched
|
|
1006
|
+
* nothing, or how many matches the 60-row cut left out, and empty otherwise.
|
|
1007
|
+
*
|
|
1008
|
+
* DRAWN WHENEVER THE SEARCH IS, EMPTY OR NOT. A live region that is created
|
|
1009
|
+
* already holding its text is not reliably announced; it has to exist first
|
|
1010
|
+
* and then change. So it is always in the markup beside the field, and
|
|
1011
|
+
* `mountWorkspace` carries the element across redraws (`RELATED_STATUS`), as
|
|
1012
|
+
* it carries §17c's change line, so typing changes its text and nothing else.
|
|
1013
|
+
*/
|
|
1014
|
+
export declare const RELATED_STATUS_CLASS = "ig-related-status";
|
|
932
1015
|
/** Render one document at one reader position, as the whole workspace. */
|
|
933
1016
|
export declare function renderWorkspace(input: ViewerDocument, options: WorkspaceOptions): WorkspaceResult;
|
|
934
1017
|
//# sourceMappingURL=render.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/workspace/render.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/workspace/render.ts"],"names":[],"mappings":"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"}
|
package/dist/workspace/render.js
CHANGED
|
@@ -32,14 +32,15 @@
|
|
|
32
32
|
* clean — which is the audit failing silently on exactly the rows where an
|
|
33
33
|
* encoding error is hardest to see.
|
|
34
34
|
*
|
|
35
|
-
* ## The zone frames, and the one place
|
|
35
|
+
* ## The zone frames, and the one place markup is joined here
|
|
36
36
|
*
|
|
37
37
|
* Two of the four zones hand back a STRING rather than a spec — the ladder's
|
|
38
38
|
* chrome and the audit header — so the frames are assembled by concatenation,
|
|
39
39
|
* as `renderScaleLadder` already assembles its own canvas and chrome. What
|
|
40
|
-
* makes that safe is not care:
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* makes that safe is not care: a frame's own opening tag carries the caller's
|
|
41
|
+
* `surfaceId` in its id, so {@link zone} has `renderMarkup` write it, and only
|
|
42
|
+
* already-rendered markup is joined inside. Everything with a dynamic value in
|
|
43
|
+
* it goes through `renderMarkup`.
|
|
43
44
|
*
|
|
44
45
|
* ## Dark only
|
|
45
46
|
*
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
* forked token set here and no second palette: the theme is the viewer's, and
|
|
49
50
|
* `styles.ts` writes structure against its custom properties.
|
|
50
51
|
*/
|
|
51
|
-
import { KEY_ATTRIBUTE, element, glyphAndLabel, hiddenGlyph, identity, labelFrom, normalizeDocument, renderMarkup, provenanceClause, renderViewer, resolveTheme, themeCss, treatmentFor, viewerStylesheet, } from '@issuegraph/viewer';
|
|
52
|
+
import { KEY_ATTRIBUTE, element, glyphAndLabel, hiddenGlyph, identity, labelFrom, normalizeDocument, renderMarkup, provenanceClause, recedingOf, renderViewer, resolveTheme, themeCss, treatmentFor, viewerStylesheet, } from '@issuegraph/viewer';
|
|
52
53
|
import { edgeIdentity } from '@issuegraph/core';
|
|
53
54
|
import { renderAuditPanel } from "../audit/panel.js";
|
|
54
55
|
import { renderEncodingRefusedBlock } from "../audit/refused.js";
|
|
@@ -65,21 +66,61 @@ import { INITIAL_SCALE_STATE } from "../scale/commands.js";
|
|
|
65
66
|
import { renderScaleLadder } from "../scale/render.js";
|
|
66
67
|
import { scaleLadderStylesheet } from "../scale/styles.js";
|
|
67
68
|
import { inspectorView, } from "./inspector.js";
|
|
69
|
+
import { NARROW_TABS, narrowTabOf } from "./narrow.js";
|
|
68
70
|
import { railWindow } from "./rail.js";
|
|
71
|
+
import { relatedListView } from "./related.js";
|
|
69
72
|
import { diffIsEmpty, diffWithin } from "./recovery.js";
|
|
70
|
-
import { INITIAL_SELECTION, selectedEdgeId,
|
|
73
|
+
import { INITIAL_SELECTION, selectedEdgeId, selectedKeys, } from "./selection.js";
|
|
71
74
|
import { workspaceStylesheet } from "./styles.js";
|
|
72
|
-
/** The four fixed positions.
|
|
75
|
+
/** The four fixed positions. */
|
|
73
76
|
export const ZONES = Object.freeze(['header', 'rail', 'canvas', 'inspector']);
|
|
77
|
+
const ZONE_CLOSE = '</section>';
|
|
74
78
|
/**
|
|
75
|
-
* A zone frame
|
|
79
|
+
* A zone frame, around already-rendered markup from `renderMarkup` or from a
|
|
80
|
+
* sibling leaf's renderer.
|
|
76
81
|
*
|
|
77
|
-
*
|
|
78
|
-
* `
|
|
79
|
-
*
|
|
82
|
+
* THE OPENING TAG IS `renderMarkup`'S, because the id carries the caller's
|
|
83
|
+
* `surfaceId` and only that function escapes an attribute in this package. It
|
|
84
|
+
* renders the frame empty and the inner markup goes where its closing tag was.
|
|
80
85
|
*/
|
|
81
|
-
function zone(name, inner) {
|
|
82
|
-
|
|
86
|
+
function zone(name, id, inner) {
|
|
87
|
+
const frame = renderMarkup(element('section', { class: 'ig-zone', 'data-zone': name, id }, []));
|
|
88
|
+
return `${frame.slice(0, -ZONE_CLOSE.length)}${inner}${ZONE_CLOSE}`;
|
|
89
|
+
}
|
|
90
|
+
/** Each zone frame's id, unique on the page when the caller supplied a `surfaceId`. */
|
|
91
|
+
function zoneIds(surfaceId) {
|
|
92
|
+
const suffix = surfaceId === undefined ? '' : `-${surfaceId}`;
|
|
93
|
+
return {
|
|
94
|
+
header: `ig-zone-header${suffix}`,
|
|
95
|
+
rail: `ig-zone-rail${suffix}`,
|
|
96
|
+
canvas: `ig-zone-canvas${suffix}`,
|
|
97
|
+
inspector: `ig-zone-inspector${suffix}`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/** The zone each narrow tab shows, and the word that names it. */
|
|
101
|
+
const NARROW_TAB_PARTS = Object.freeze({
|
|
102
|
+
order: { zone: 'rail', word: 'order' },
|
|
103
|
+
related: { zone: 'canvas', word: 'related' },
|
|
104
|
+
'sub-issues': { zone: 'canvas', word: 'subIssues' },
|
|
105
|
+
});
|
|
106
|
+
/**
|
|
107
|
+
* The tabs of the layout under `640`.
|
|
108
|
+
*
|
|
109
|
+
* ALWAYS DRAWN, AND HIDDEN BY THE SHEET AT THE WIDER LAYOUTS, for the reason the
|
|
110
|
+
* canvas strip is: this function does not know how wide it is. Every tab is a
|
|
111
|
+
* tab stop rather than one roving stop, so each is reachable the way every other
|
|
112
|
+
* control on this surface is.
|
|
113
|
+
*/
|
|
114
|
+
function narrowTabsSpec(selected, words, ids) {
|
|
115
|
+
return element('div', { class: 'ig-narrow-tabs', role: 'tablist' }, NARROW_TABS.map((tab) => element('button', {
|
|
116
|
+
type: 'button',
|
|
117
|
+
class: 'ig-narrow-tab',
|
|
118
|
+
role: 'tab',
|
|
119
|
+
'data-ig-command': 'narrow-tab',
|
|
120
|
+
'data-ig-value': tab,
|
|
121
|
+
'aria-selected': tab === selected ? 'true' : 'false',
|
|
122
|
+
'aria-controls': ids[NARROW_TAB_PARTS[tab].zone],
|
|
123
|
+
}, [words[NARROW_TAB_PARTS[tab].word]])));
|
|
83
124
|
}
|
|
84
125
|
/**
|
|
85
126
|
* §17f's canvas caption — what this canvas is drawing, and out of how much.
|
|
@@ -627,6 +668,97 @@ function relationshipSpec(relationship, subject, selected, words, refused) {
|
|
|
627
668
|
flipControl(relationship, selected, words),
|
|
628
669
|
]);
|
|
629
670
|
}
|
|
671
|
+
/**
|
|
672
|
+
* The Related groups list's rows: the Inspector's own head in the Inspector's
|
|
673
|
+
* own row box, so a relationship reads the same words, direction and hue here.
|
|
674
|
+
* Only the head: removing, retyping and flipping stay the Inspector's.
|
|
675
|
+
*/
|
|
676
|
+
function relatedRowsSpec(rows, subject) {
|
|
677
|
+
return element('ul', { class: 'ig-related-rows' }, rows.map((row) => element('li', { class: 'ig-relationship', 'data-edge': row.field }, [relationshipHead(row, subject)])));
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* The Related groups search. The input sits inside its label, so the two are
|
|
681
|
+
* associated without an `id`, for the reason `scale/render.ts`'s `searchSpec`
|
|
682
|
+
* gives. Named by the host's own search label.
|
|
683
|
+
*/
|
|
684
|
+
function relatedSearchSpec(query, words) {
|
|
685
|
+
return element('label', { class: 'ig-related-search' }, [
|
|
686
|
+
words.searchRelated,
|
|
687
|
+
element('input', {
|
|
688
|
+
type: 'search',
|
|
689
|
+
'data-ig-command': 'related-query',
|
|
690
|
+
value: query,
|
|
691
|
+
autocomplete: 'off',
|
|
692
|
+
}),
|
|
693
|
+
]);
|
|
694
|
+
}
|
|
695
|
+
/** One kind's group control, worded as the Inspector words that kind, then its count. */
|
|
696
|
+
function relatedGroupSpec(field, count, open) {
|
|
697
|
+
const treatment = treatmentFor(field);
|
|
698
|
+
return element('button', {
|
|
699
|
+
type: 'button',
|
|
700
|
+
class: 'ig-related-group',
|
|
701
|
+
'data-ig-command': 'related-group',
|
|
702
|
+
'data-ig-value': field,
|
|
703
|
+
'aria-expanded': open ? 'true' : 'false',
|
|
704
|
+
}, [...glyphAndLabel(treatment.glyph, labelFrom(treatment, true)), ' ', element('span', {}, [String(count)])]);
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* The search's status line, right under the field: that a search matched
|
|
708
|
+
* nothing, or how many matches the 60-row cut left out, and empty otherwise.
|
|
709
|
+
*
|
|
710
|
+
* DRAWN WHENEVER THE SEARCH IS, EMPTY OR NOT. A live region that is created
|
|
711
|
+
* already holding its text is not reliably announced; it has to exist first
|
|
712
|
+
* and then change. So it is always in the markup beside the field, and
|
|
713
|
+
* `mountWorkspace` carries the element across redraws (`RELATED_STATUS`), as
|
|
714
|
+
* it carries §17c's change line, so typing changes its text and nothing else.
|
|
715
|
+
*/
|
|
716
|
+
export const RELATED_STATUS_CLASS = 'ig-related-status';
|
|
717
|
+
function relatedStatusSpec(view, words) {
|
|
718
|
+
const said = view.noMatch ? words.noMatch : view.omitted > 0 ? words.omitted(view.omitted) : null;
|
|
719
|
+
return element('p', { class: RELATED_STATUS_CLASS, role: 'status' }, said === null ? [] : [said]);
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* The Related groups list, drawn in the canvas zone under `640`.
|
|
723
|
+
*
|
|
724
|
+
* EVERY DECISION IS `relatedListView`'S — which rows, which groups, whether a
|
|
725
|
+
* search is drawn and how many rows were cut. This only gives each part its
|
|
726
|
+
* element, so the 60-row cap is enforced in one place.
|
|
727
|
+
*
|
|
728
|
+
* An open group draws its search and its rows inside its own item, under its
|
|
729
|
+
* control. A search over every relationship sits above the groups, and while it
|
|
730
|
+
* holds a query its matches stand where the groups were.
|
|
731
|
+
*/
|
|
732
|
+
function relatedListSpec(view, subject, query, words) {
|
|
733
|
+
return element('div', {
|
|
734
|
+
class: 'ig-related',
|
|
735
|
+
'data-ig-omitted': view.kind === 'grouped' && view.omitted > 0 ? view.omitted : undefined,
|
|
736
|
+
}, relatedListParts(view, subject, query, words));
|
|
737
|
+
}
|
|
738
|
+
function relatedListParts(view, subject, query, words) {
|
|
739
|
+
switch (view.kind) {
|
|
740
|
+
case 'no-selection':
|
|
741
|
+
return [element('p', { class: 'ig-related-empty' }, [words.narrow.noSelection])];
|
|
742
|
+
case 'no-relationships':
|
|
743
|
+
return [element('p', { class: 'ig-related-empty' }, [words.noRelationships])];
|
|
744
|
+
case 'flat':
|
|
745
|
+
return [relatedRowsSpec(view.rows, subject)];
|
|
746
|
+
case 'grouped': {
|
|
747
|
+
const search = view.search === 'none' ? null : relatedSearchSpec(query, words.narrow);
|
|
748
|
+
const status = view.search === 'none' ? null : relatedStatusSpec(view, words.narrow);
|
|
749
|
+
const open = view.groups.some((group) => group.open);
|
|
750
|
+
const groups = element('ul', { class: 'ig-related-groups' }, view.groups.map((group) => element('li', {}, [
|
|
751
|
+
relatedGroupSpec(group.field, group.count, group.open),
|
|
752
|
+
group.open ? search : null,
|
|
753
|
+
group.open ? status : null,
|
|
754
|
+
group.open ? relatedRowsSpec(view.rows, subject) : null,
|
|
755
|
+
])));
|
|
756
|
+
if (open)
|
|
757
|
+
return [groups];
|
|
758
|
+
return [search, status, view.groups.length > 0 ? groups : relatedRowsSpec(view.rows, subject)];
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
630
762
|
/**
|
|
631
763
|
* A refused relationship, drawn where the reader was building it.
|
|
632
764
|
*
|
|
@@ -998,6 +1130,14 @@ function headerMarkup(host, auditHeader, words) {
|
|
|
998
1130
|
];
|
|
999
1131
|
return `<div class="ig-workspace-header">${parts.join('')}</div>`;
|
|
1000
1132
|
}
|
|
1133
|
+
/**
|
|
1134
|
+
* The selection as the viewer's `selected` takes it: one key as a string, a
|
|
1135
|
+
* set as its keys in addition order, and nothing for an edge or none.
|
|
1136
|
+
*/
|
|
1137
|
+
function viewerSelected(selection) {
|
|
1138
|
+
const keys = selectedKeys(selection);
|
|
1139
|
+
return keys.length > 1 ? keys : (keys[0] ?? null);
|
|
1140
|
+
}
|
|
1001
1141
|
function panelScope(view) {
|
|
1002
1142
|
const { subject } = view;
|
|
1003
1143
|
switch (subject.kind) {
|
|
@@ -1008,6 +1148,10 @@ function panelScope(view) {
|
|
|
1008
1148
|
kind: 'issue',
|
|
1009
1149
|
keys: new Set([subject.issue.key, ...(subject.whyRank?.unitPartners ?? [])]),
|
|
1010
1150
|
};
|
|
1151
|
+
// A SET STATES NOTHING. It offers no edit, so no refusal or recovery is
|
|
1152
|
+
// about an edit made from it; each one stays on its own issue's panel.
|
|
1153
|
+
case 'issues':
|
|
1154
|
+
return { kind: 'none' };
|
|
1011
1155
|
case 'edge':
|
|
1012
1156
|
return { kind: 'edge', edgeId: subject.relationship.edgeId };
|
|
1013
1157
|
}
|
|
@@ -1347,6 +1491,20 @@ function inspectorSpec(view, context) {
|
|
|
1347
1491
|
: whyRankSpec(subject.whyRank, words, subject.whyRank.holds.map((hold) => holdRow(hold, context.known, (subjectKey) => context.leadOf.get(subjectKey) === context.leadOf.get(subject.issue.key)))),
|
|
1348
1492
|
])
|
|
1349
1493
|
: null,
|
|
1494
|
+
// A SET SAYS HOW MANY AND LISTS THEM, in the order they were added, as
|
|
1495
|
+
// text: no link, no command and no key attribute, so the list is
|
|
1496
|
+
// agreement with the rail and the canvas, not a second place to act. The
|
|
1497
|
+
// batch offers are a later change.
|
|
1498
|
+
subject.kind === 'issues'
|
|
1499
|
+
? element('div', { class: 'ig-inspector-issues' }, [
|
|
1500
|
+
element('h3', { class: 'ig-inspector-title' }, [words.issuesSelected(subject.issues.length)]),
|
|
1501
|
+
element('ul', { class: 'ig-inspector-set' }, subject.issues.map((issue) => element('li', { class: 'ig-inspector-set-item' }, [
|
|
1502
|
+
element('span', { class: 'ig-title' }, [issue.title]),
|
|
1503
|
+
' ',
|
|
1504
|
+
element('span', { class: 'ig-id' }, [issue.key]),
|
|
1505
|
+
]))),
|
|
1506
|
+
])
|
|
1507
|
+
: null,
|
|
1350
1508
|
// ONE DERIVATION, READ TWICE. The step is asked once here and both
|
|
1351
1509
|
// placements below read the answer, so the header and the body cannot
|
|
1352
1510
|
// disagree about WHICH step is live. What each draws for a given arm is
|
|
@@ -1355,7 +1513,10 @@ function inspectorSpec(view, context) {
|
|
|
1355
1513
|
// unrepresentable, and a value read at two sites does not. The pin that
|
|
1356
1514
|
// stands where the return ordering used to is the one asserting no `add`
|
|
1357
1515
|
// control exists anywhere in the panel at the kind step.
|
|
1358
|
-
|
|
1516
|
+
// NO RELATIONSHIP REGION FOR A SET: it lists none and offers no `+ add`,
|
|
1517
|
+
// and "no relationships" under a list of issues would read as a fact
|
|
1518
|
+
// about them.
|
|
1519
|
+
subject.kind === 'issues' ? null : element('div', { class: 'ig-inspector-relationships', 'data-filtered': view.filtered ? 'true' : 'false' }, [
|
|
1359
1520
|
// §17a PUTS `+ add` ON THE HEADING'S OWN ROW, and the reason is the
|
|
1360
1521
|
// list between them: it is unbounded, so a control after it drifts
|
|
1361
1522
|
// down the panel as a subject gains relationships and is below the
|
|
@@ -1685,9 +1846,14 @@ export function renderWorkspace(input, options) {
|
|
|
1685
1846
|
// back on `scene.footer`, it is composed after the trailing spacer below.
|
|
1686
1847
|
// See `SceneOptions.detachFooter`.
|
|
1687
1848
|
detachFooter: true,
|
|
1688
|
-
// The rail is where a selected ISSUE reads as current
|
|
1689
|
-
//
|
|
1690
|
-
selected:
|
|
1849
|
+
// The rail is where a selected ISSUE reads as current, and every member of
|
|
1850
|
+
// a set does. An edge selection resolves to no key.
|
|
1851
|
+
selected: viewerSelected(selection),
|
|
1852
|
+
// WORKED OUT OVER THE WHOLE DOCUMENT, NOT THE WINDOW. `rail.document` holds
|
|
1853
|
+
// only the window's issues and edges, so a selection outside it would
|
|
1854
|
+
// recede nothing here while the canvas recedes around it. An edge
|
|
1855
|
+
// selection recedes the rail too, and so does a set, member by member.
|
|
1856
|
+
receding: recedingOf(document, { key: viewerSelected(selection), edge: selectedEdgeId(selection) }),
|
|
1691
1857
|
// §16f. Passed WHOLE rather than windowed: the window moves, and a reader
|
|
1692
1858
|
// who opened a row, scrolled past it and came back should find it open.
|
|
1693
1859
|
// A key the window does not draw costs one `includes` miss and nothing else.
|
|
@@ -1752,7 +1918,7 @@ export function renderWorkspace(input, options) {
|
|
|
1752
1918
|
// selected issue as ordinary while the rail marked it current, so the
|
|
1753
1919
|
// single selection this surface advertises disagreed with itself between
|
|
1754
1920
|
// two zones on every render.
|
|
1755
|
-
selected:
|
|
1921
|
+
selected: viewerSelected(selection),
|
|
1756
1922
|
// AND ITS OTHER HALF. The union has two payloads, and reading only the
|
|
1757
1923
|
// issue one left the canvas the single zone that could not see an edge
|
|
1758
1924
|
// selection: the inspector filtered to the edge while the canvas drew it
|
|
@@ -1810,9 +1976,14 @@ export function renderWorkspace(input, options) {
|
|
|
1810
1976
|
// Suppressing the markup with an option would put the key out of reach of
|
|
1811
1977
|
// both.
|
|
1812
1978
|
const canvasLegend = canvas.ladder.tier === 'direct' ? 'drawn' : 'absent';
|
|
1979
|
+
// THE TAB IS READ OFF THE VIEW AND THE MODE, never handed in, so the selected
|
|
1980
|
+
// tab cannot disagree with what the canvas zone draws. See `narrowTabOf`.
|
|
1981
|
+
const tab = narrowTabOf(options.narrowView ?? 'order', options.canvas ?? 'neighbourhood');
|
|
1813
1982
|
const narrowState = ` data-canvas="${canvasOpen ? 'open' : 'strip'}"` +
|
|
1814
1983
|
` data-canvas-legend="${canvasLegend}"` +
|
|
1815
|
-
` data-inspector="${lifted ? 'lifted' : 'dismissed'}"
|
|
1984
|
+
` data-inspector="${lifted ? 'lifted' : 'dismissed'}"` +
|
|
1985
|
+
` data-tab="${tab}"`;
|
|
1986
|
+
const ids = zoneIds(options.surfaceId);
|
|
1816
1987
|
// §17a'S RAIL FOOTER, FROM THE LADDER THE CANVAS ALREADY DERIVED. `isolated`
|
|
1817
1988
|
// is a property of the whole document rather than of the tier the canvas
|
|
1818
1989
|
// settled on, so the rail and the canvas cannot disagree about it: there is
|
|
@@ -1825,6 +1996,14 @@ export function renderWorkspace(input, options) {
|
|
|
1825
1996
|
// scope is a reading hazard worth one name, not one comment per use.
|
|
1826
1997
|
const railFooterSpec = railFooter(canvas.ladder.isolated, options.words.rail, isolatedListId);
|
|
1827
1998
|
const inspector = inspectorView(document, selection);
|
|
1999
|
+
// The Related groups list, drawn only while its tab is the one selected: the
|
|
2000
|
+
// other two tabs show nothing of it, and the wider layouts hide it.
|
|
2001
|
+
const relatedList = tab !== 'related'
|
|
2002
|
+
? ''
|
|
2003
|
+
: renderMarkup(relatedListSpec(relatedListView(document, selection, {
|
|
2004
|
+
group: options.relatedGroup ?? null,
|
|
2005
|
+
query: options.relatedQuery ?? '',
|
|
2006
|
+
}), inspector.subject.kind === 'issue' ? inspector.subject.issue.key : null, options.relatedQuery ?? '', options.words));
|
|
1828
2007
|
// §17c'S LOOP, OVER THE RAIL THE READER IS ACTUALLY LOOKING AT.
|
|
1829
2008
|
// `reevaluateView` is handed the WINDOWED scene, so a chip whose row is
|
|
1830
2009
|
// scrolled out of the window resolves to no row and draws nowhere — which is
|
|
@@ -1931,7 +2110,7 @@ export function renderWorkspace(input, options) {
|
|
|
1931
2110
|
//
|
|
1932
2111
|
// §17k'S TWO READER DECISIONS RIDE THE SAME ROOT, and for the same reason
|
|
1933
2112
|
// `data-order` does: the stylesheet is the only party that knows which of
|
|
1934
|
-
// the
|
|
2113
|
+
// the four layouts is drawn, so the surface publishes what the reader
|
|
1935
2114
|
// asked for and each container block reads the one it has a use for.
|
|
1936
2115
|
// Neither attribute means anything at the width where its zone is a zone.
|
|
1937
2116
|
//
|
|
@@ -1943,7 +2122,7 @@ export function renderWorkspace(input, options) {
|
|
|
1943
2122
|
changeWords === undefined
|
|
1944
2123
|
? `<div class="ig-workspace"${narrowState}>`
|
|
1945
2124
|
: `<div class="ig-workspace" data-order="${orderStatus}"${narrowState}>`,
|
|
1946
|
-
zone('header', [
|
|
2125
|
+
zone('header', ids.header, [
|
|
1947
2126
|
headerMarkup(document.host, overlay === null ? '' : renderAuditHeader(overlay, { open: auditOpen }), options.words),
|
|
1948
2127
|
// §17c'S SUMMARY LIVES IN THE HEADER, NOT AT THE TOP OF THE RAIL, and
|
|
1949
2128
|
// the frame draws them adjacent so this is a real departure worth the
|
|
@@ -1969,8 +2148,12 @@ export function renderWorkspace(input, options) {
|
|
|
1969
2148
|
changeWords === undefined
|
|
1970
2149
|
? ''
|
|
1971
2150
|
: renderMarkup(summarySpec(change.summary, changeWords, { held: change.held })),
|
|
2151
|
+
// THE TABS ARE THE HEADER'S LAST CHILD, because the header is the one
|
|
2152
|
+
// zone nothing replaces after this render: the mount swaps the canvas
|
|
2153
|
+
// zone's children for the tree, and a tab inside it would vanish there.
|
|
2154
|
+
renderMarkup(narrowTabsSpec(tab, options.words.narrow, ids)),
|
|
1972
2155
|
].join('')),
|
|
1973
|
-
zone('rail', [
|
|
2156
|
+
zone('rail', ids.rail, [
|
|
1974
2157
|
railSpacer(rail.before, 'before'),
|
|
1975
2158
|
renderMarkup(markRailRows(railRender.scene.root)),
|
|
1976
2159
|
railSpacer(rail.after, 'after'),
|
|
@@ -1982,14 +2165,13 @@ export function renderWorkspace(input, options) {
|
|
|
1982
2165
|
railRender.scene.footer === null ? '' : renderMarkup(markRailRows(railRender.scene.footer)),
|
|
1983
2166
|
railFooterSpec === null ? '' : renderMarkup(railFooterSpec),
|
|
1984
2167
|
].join('')),
|
|
1985
|
-
zone('canvas',
|
|
2168
|
+
zone('canvas', ids.canvas,
|
|
1986
2169
|
// THE CAPTION LEADS THE ZONE, above the graph, exactly as frame 17a
|
|
1987
2170
|
// draws it — and it is assembled HERE rather than inside the ladder.
|
|
1988
2171
|
// `renderScaleLadder` is also used standalone, where `chrome: false` is
|
|
1989
2172
|
// the deliberate answer, and the words this row needs are the
|
|
1990
2173
|
// workspace's. Both halves are already-rendered markup, which is the
|
|
1991
|
-
// rule `zone` exists under: it
|
|
1992
|
-
// package and takes no caller value.
|
|
2174
|
+
// rule `zone` exists under: it frames markup that was already escaped.
|
|
1993
2175
|
//
|
|
1994
2176
|
// THE STRIP CONTROL LEADS THE ZONE, above the caption, because below
|
|
1995
2177
|
// `1120` it is the ONLY thing in the zone the reader can reach: the
|
|
@@ -2006,9 +2188,10 @@ export function renderWorkspace(input, options) {
|
|
|
2006
2188
|
[strip, toolbar]
|
|
2007
2189
|
.map((spec) => (spec === null ? '' : renderMarkup(spec)))
|
|
2008
2190
|
.join('') +
|
|
2191
|
+
relatedList +
|
|
2009
2192
|
canvas.markup +
|
|
2010
2193
|
auditPanel),
|
|
2011
|
-
zone('inspector',
|
|
2194
|
+
zone('inspector', ids.inspector,
|
|
2012
2195
|
// §17d'S AUDIT IS THE SELECTION'S SIBLING, AND THEY SHARE ONE SCROLL
|
|
2013
2196
|
// TRACK. Sibling rather than child so each surface keeps its own padding
|
|
2014
2197
|
// and reads as a peer of the selection rather than part of it — their
|
|
@@ -2040,9 +2223,8 @@ export function renderWorkspace(input, options) {
|
|
|
2040
2223
|
// track is what avoids needing panes at all.
|
|
2041
2224
|
//
|
|
2042
2225
|
// BOTH SIDES ARE ALREADY-RENDERED MARKUP, which is the rule `zone` exists
|
|
2043
|
-
// under:
|
|
2044
|
-
//
|
|
2045
|
-
// `renderMarkup`.
|
|
2226
|
+
// under: everything with a dynamic value in it went through
|
|
2227
|
+
// `renderMarkup`, the frame's own id included.
|
|
2046
2228
|
//
|
|
2047
2229
|
// `known` IS THE DRAWN DOCUMENT'S KEYS, the same set `holdRow` withholds
|
|
2048
2230
|
// its subject control on, and NOT the audit's: a host audits what it
|