@issuegraph/viewer 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.
- package/LICENSE +201 -0
- package/README.md +156 -0
- package/dist/clusters.d.ts +34 -0
- package/dist/clusters.d.ts.map +1 -0
- package/dist/clusters.js +195 -0
- package/dist/clusters.js.map +1 -0
- package/dist/document.d.ts +190 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +308 -0
- package/dist/document.js.map +1 -0
- package/dist/element.d.ts +95 -0
- package/dist/element.d.ts.map +1 -0
- package/dist/element.js +174 -0
- package/dist/element.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +122 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +297 -0
- package/dist/layout.js.map +1 -0
- package/dist/mount.d.ts +64 -0
- package/dist/mount.d.ts.map +1 -0
- package/dist/mount.js +402 -0
- package/dist/mount.js.map +1 -0
- package/dist/navigation.d.ts +56 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +121 -0
- package/dist/navigation.js.map +1 -0
- package/dist/parts.d.ts +89 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +214 -0
- package/dist/parts.js.map +1 -0
- package/dist/projections/graph.d.ts +30 -0
- package/dist/projections/graph.d.ts.map +1 -0
- package/dist/projections/graph.js +644 -0
- package/dist/projections/graph.js.map +1 -0
- package/dist/projections/linear.d.ts +35 -0
- package/dist/projections/linear.d.ts.map +1 -0
- package/dist/projections/linear.js +157 -0
- package/dist/projections/linear.js.map +1 -0
- package/dist/projections/tree.d.ts +17 -0
- package/dist/projections/tree.d.ts.map +1 -0
- package/dist/projections/tree.js +209 -0
- package/dist/projections/tree.js.map +1 -0
- package/dist/render.d.ts +35 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +45 -0
- package/dist/render.js.map +1 -0
- package/dist/scene.d.ts +94 -0
- package/dist/scene.d.ts.map +1 -0
- package/dist/scene.js +48 -0
- package/dist/scene.js.map +1 -0
- package/dist/styles.d.ts +17 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +389 -0
- package/dist/styles.js.map +1 -0
- package/dist/theme.d.ts +71 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +169 -0
- package/dist/theme.js.map +1 -0
- package/dist/vocabulary.d.ts +107 -0
- package/dist/vocabulary.d.ts.map +1 -0
- package/dist/vocabulary.js +98 -0
- package/dist/vocabulary.js.map +1 -0
- package/package.json +56 -0
package/dist/theme.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The theme: every value the viewer draws with, in one place, emitted as CSS
|
|
3
|
+
* custom properties.
|
|
4
|
+
*
|
|
5
|
+
* THE SHIPPED PALETTE IS THE DEFAULT THEME, NOT THE STYLING. It is dark, and
|
|
6
|
+
* light mode is deliberately absent rather than forgotten — a host that wants
|
|
7
|
+
* one supplies it through these same properties, which is exactly what makes
|
|
8
|
+
* this a theme rather than a look. The forcing function is that the package has
|
|
9
|
+
* to render two of them from one set of components; if a value cannot be
|
|
10
|
+
* overridden here, it is a bug in this file and not a styling choice elsewhere.
|
|
11
|
+
*
|
|
12
|
+
* GEOMETRY IS SINGLE-SOURCED AS NUMBERS. Layout maths needs real numbers (an
|
|
13
|
+
* SVG endpoint is a coordinate, not a `var()`), and CSS needs custom
|
|
14
|
+
* properties. Declaring both by hand would be two sources that drift, so the
|
|
15
|
+
* numbers are canonical and {@link themeCss} renders the properties FROM them.
|
|
16
|
+
* Retheming geometry therefore moves the drawing and the stylesheet together.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Every colour the viewer uses, by token name. Declared as a tuple so the
|
|
20
|
+
* token list and the theme type cannot disagree: a colour added here is a
|
|
21
|
+
* compile error in every theme that does not supply it.
|
|
22
|
+
*/
|
|
23
|
+
export const COLOR_TOKENS = Object.freeze([
|
|
24
|
+
'--ig-bg',
|
|
25
|
+
'--ig-surface',
|
|
26
|
+
'--ig-surface-2',
|
|
27
|
+
'--ig-line',
|
|
28
|
+
'--ig-text',
|
|
29
|
+
'--ig-text-body',
|
|
30
|
+
'--ig-text-muted',
|
|
31
|
+
'--ig-accent',
|
|
32
|
+
'--ig-focus',
|
|
33
|
+
'--ig-station-ready',
|
|
34
|
+
'--ig-station-pending',
|
|
35
|
+
'--ig-station-held',
|
|
36
|
+
'--ig-edge-blocked-by',
|
|
37
|
+
'--ig-edge-serialize-with',
|
|
38
|
+
'--ig-edge-together-with',
|
|
39
|
+
'--ig-edge-duplicate-of',
|
|
40
|
+
'--ig-edge-decomposed-from',
|
|
41
|
+
]);
|
|
42
|
+
/** Type tokens. `lineHeight` is unitless; the rest carry their own units. */
|
|
43
|
+
export const TYPE_TOKENS = Object.freeze([
|
|
44
|
+
'--ig-font-ui',
|
|
45
|
+
'--ig-font-mono',
|
|
46
|
+
'--ig-font-size',
|
|
47
|
+
'--ig-font-size-small',
|
|
48
|
+
'--ig-line-height',
|
|
49
|
+
]);
|
|
50
|
+
/** Geometry tokens. Every value is a number of CSS pixels. */
|
|
51
|
+
export const METRIC_TOKENS = Object.freeze([
|
|
52
|
+
'--ig-space',
|
|
53
|
+
'--ig-space-tight',
|
|
54
|
+
'--ig-radius',
|
|
55
|
+
'--ig-row-height',
|
|
56
|
+
'--ig-station-size',
|
|
57
|
+
'--ig-station-halo',
|
|
58
|
+
'--ig-stroke',
|
|
59
|
+
'--ig-stroke-connector',
|
|
60
|
+
'--ig-terminal-length',
|
|
61
|
+
'--ig-terminal-width',
|
|
62
|
+
'--ig-gutter-width',
|
|
63
|
+
'--ig-spine-width',
|
|
64
|
+
'--ig-char-width',
|
|
65
|
+
'--ig-focus-ring',
|
|
66
|
+
]);
|
|
67
|
+
/** Every custom property the stylesheet may reference. */
|
|
68
|
+
export const THEME_TOKENS = Object.freeze([
|
|
69
|
+
...COLOR_TOKENS,
|
|
70
|
+
...TYPE_TOKENS,
|
|
71
|
+
...METRIC_TOKENS,
|
|
72
|
+
]);
|
|
73
|
+
/**
|
|
74
|
+
* The default theme.
|
|
75
|
+
*
|
|
76
|
+
* Contrast is a claim this palette makes and `theme.test.ts` measures: every
|
|
77
|
+
* text colour clears WCAG AA's 4.5:1 against all three surfaces, and every edge
|
|
78
|
+
* hue clears the 3:1 non-text bar that applies to a line or a badge outline.
|
|
79
|
+
* `--ig-text-muted` is the tight one — it carries sentence-length copy at small
|
|
80
|
+
* sizes, which is why it is the value the tests pin most precisely.
|
|
81
|
+
*/
|
|
82
|
+
export const defaultTheme = Object.freeze({
|
|
83
|
+
colors: Object.freeze({
|
|
84
|
+
'--ig-bg': '#0B0D0F',
|
|
85
|
+
'--ig-surface': '#11181C',
|
|
86
|
+
'--ig-surface-2': '#0E1519',
|
|
87
|
+
'--ig-line': '#232D34',
|
|
88
|
+
'--ig-text': '#E8EDF0',
|
|
89
|
+
'--ig-text-body': '#AEB9C0',
|
|
90
|
+
'--ig-text-muted': '#75848E',
|
|
91
|
+
'--ig-accent': '#17BCEE',
|
|
92
|
+
'--ig-focus': '#17BCEE',
|
|
93
|
+
'--ig-station-ready': '#17BCEE',
|
|
94
|
+
'--ig-station-pending': '#AEB9C0',
|
|
95
|
+
'--ig-station-held': '#75848E',
|
|
96
|
+
'--ig-edge-blocked-by': '#EF6B6B',
|
|
97
|
+
'--ig-edge-serialize-with': '#E2B912',
|
|
98
|
+
'--ig-edge-together-with': '#17BCEE',
|
|
99
|
+
'--ig-edge-duplicate-of': '#B037F1',
|
|
100
|
+
'--ig-edge-decomposed-from': '#E7317A',
|
|
101
|
+
}),
|
|
102
|
+
type: Object.freeze({
|
|
103
|
+
'--ig-font-ui': "Geist, ui-sans-serif, system-ui, sans-serif",
|
|
104
|
+
// Tabular numerals are what let a rank column line up; a proportional
|
|
105
|
+
// fallback would make the spine's numbers wander.
|
|
106
|
+
'--ig-font-mono': "'JetBrains Mono', ui-monospace, SFMono-Regular, monospace",
|
|
107
|
+
'--ig-font-size': '13px',
|
|
108
|
+
'--ig-font-size-small': '11px',
|
|
109
|
+
'--ig-line-height': '1.45',
|
|
110
|
+
}),
|
|
111
|
+
metrics: Object.freeze({
|
|
112
|
+
'--ig-space': 12,
|
|
113
|
+
'--ig-space-tight': 6,
|
|
114
|
+
'--ig-radius': 6,
|
|
115
|
+
'--ig-row-height': 44,
|
|
116
|
+
'--ig-station-size': 12,
|
|
117
|
+
// A halo wide enough that a crossing edge reads as passing behind the
|
|
118
|
+
// station rather than through it.
|
|
119
|
+
'--ig-station-halo': 4,
|
|
120
|
+
'--ig-stroke': 1.5,
|
|
121
|
+
// The `together-with` hairline connector, which is deliberately finer than
|
|
122
|
+
// an ordinary edge so the enclosure stays the primary read.
|
|
123
|
+
'--ig-stroke-connector': 1.6,
|
|
124
|
+
// The terminal marker's own box. It is theme data rather than a constant
|
|
125
|
+
// in the drawing code because it is a SIZE, and R5 admits no exceptions:
|
|
126
|
+
// a host scaling the type up needs the arrowheads to follow.
|
|
127
|
+
'--ig-terminal-length': 9,
|
|
128
|
+
'--ig-terminal-width': 8,
|
|
129
|
+
'--ig-gutter-width': 208,
|
|
130
|
+
'--ig-spine-width': 360,
|
|
131
|
+
// The advance width of one character at `--ig-font-size` in the mono face.
|
|
132
|
+
// Layout measures text with it, so a host changing the type scale changes
|
|
133
|
+
// this too and the boxes stay around their contents.
|
|
134
|
+
'--ig-char-width': 7.8,
|
|
135
|
+
'--ig-focus-ring': 2,
|
|
136
|
+
}),
|
|
137
|
+
});
|
|
138
|
+
/**
|
|
139
|
+
* Merge an override onto a base theme, per token.
|
|
140
|
+
*
|
|
141
|
+
* A partial override is the shape a second theme actually takes — changing a
|
|
142
|
+
* palette rarely means restating the geometry — and requiring a whole `Theme`
|
|
143
|
+
* would make the cheap case impossible to express.
|
|
144
|
+
*/
|
|
145
|
+
export function extendTheme(base, override) {
|
|
146
|
+
return Object.freeze({
|
|
147
|
+
colors: Object.freeze({ ...base.colors, ...override.colors }),
|
|
148
|
+
type: Object.freeze({ ...base.type, ...override.type }),
|
|
149
|
+
metrics: Object.freeze({ ...base.metrics, ...override.metrics }),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Render a theme as one CSS rule of custom properties.
|
|
154
|
+
*
|
|
155
|
+
* Values are emitted verbatim for colours and type — a theme's author owns
|
|
156
|
+
* their spelling — and metrics gain a `px` unit here, which is the single place
|
|
157
|
+
* the numbers become CSS.
|
|
158
|
+
*/
|
|
159
|
+
export function themeCss(theme, selector = ':root') {
|
|
160
|
+
const lines = [];
|
|
161
|
+
for (const token of COLOR_TOKENS)
|
|
162
|
+
lines.push(` ${token}: ${theme.colors[token]};`);
|
|
163
|
+
for (const token of TYPE_TOKENS)
|
|
164
|
+
lines.push(` ${token}: ${theme.type[token]};`);
|
|
165
|
+
for (const token of METRIC_TOKENS)
|
|
166
|
+
lines.push(` ${token}: ${String(theme.metrics[token])}px;`);
|
|
167
|
+
return `${selector} {\n${lines.join('\n')}\n}\n`;
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The edge grammar, as data.
|
|
3
|
+
*
|
|
4
|
+
* Each relationship is separable on FOUR redundant channels — dash pattern,
|
|
5
|
+
* terminal marker, glyph and hue — and the colour-blind-safety claim is that
|
|
6
|
+
* removing hue entirely still leaves all five distinguishable. That is a
|
|
7
|
+
* property of this table, so it is asserted against this table rather than
|
|
8
|
+
* asserted about the rendering.
|
|
9
|
+
*
|
|
10
|
+
* It is declared as a total mapping over `EDGE_FIELDS` rather than a list of
|
|
11
|
+
* cases, so a sixth relationship added to the format fails the BUILD here
|
|
12
|
+
* instead of rendering as an untreated line nobody notices.
|
|
13
|
+
*/
|
|
14
|
+
import { type EdgeField } from '@issuegraph/core';
|
|
15
|
+
/** How the line is stroked. `enclosure` draws a surrounding shape, not a line. */
|
|
16
|
+
export type EdgeDash = 'solid' | 'double' | 'dotted' | 'dashed' | 'enclosure';
|
|
17
|
+
/** What sits at the pointed end. `none` is symmetric; `enclosure` has no end. */
|
|
18
|
+
export type EdgeTerminal = 'arrow' | 'none' | 'enclosure' | 'hollow-circle' | 'tee';
|
|
19
|
+
/** What the relationship does to the order. */
|
|
20
|
+
export type OrderingEffect = 'strict-directed' | 'exclusive-unordered' | 'shares-rank' | 'never-worked' | 'provenance-only';
|
|
21
|
+
export interface EdgeTreatment {
|
|
22
|
+
readonly dash: EdgeDash;
|
|
23
|
+
readonly terminal: EdgeTerminal;
|
|
24
|
+
/** The single character that names the relationship without colour. */
|
|
25
|
+
readonly glyph: string;
|
|
26
|
+
/** The custom property carrying this edge's hue. Never a literal colour. */
|
|
27
|
+
readonly hueToken: string;
|
|
28
|
+
/** Announced to a screen reader, and used as the badge's accessible name. */
|
|
29
|
+
readonly label: string;
|
|
30
|
+
readonly ordering: OrderingEffect;
|
|
31
|
+
/**
|
|
32
|
+
* Whether the edge reads the same both ways. A symmetric edge is drawn once
|
|
33
|
+
* and never as two arrows, because `A serialize-with B` and its reverse state
|
|
34
|
+
* one fact.
|
|
35
|
+
*/
|
|
36
|
+
readonly symmetric: boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* `satisfies` rather than an annotation, so the object literal keeps its narrow
|
|
40
|
+
* types AND the compiler proves every `EdgeField` has an entry. Adding a field
|
|
41
|
+
* to `@issuegraph/core` without adding it here is TS2739 at build time.
|
|
42
|
+
*/
|
|
43
|
+
export declare const EDGE_TREATMENTS: Readonly<{
|
|
44
|
+
readonly 'blocked-by': {
|
|
45
|
+
readonly dash: "solid";
|
|
46
|
+
readonly terminal: "arrow";
|
|
47
|
+
readonly glyph: "⊘";
|
|
48
|
+
readonly hueToken: "--ig-edge-blocked-by";
|
|
49
|
+
readonly label: "blocked by";
|
|
50
|
+
readonly ordering: "strict-directed";
|
|
51
|
+
readonly symmetric: false;
|
|
52
|
+
};
|
|
53
|
+
readonly 'serialize-with': {
|
|
54
|
+
readonly dash: "double";
|
|
55
|
+
readonly terminal: "none";
|
|
56
|
+
readonly glyph: "⇄";
|
|
57
|
+
readonly hueToken: "--ig-edge-serialize-with";
|
|
58
|
+
readonly label: "serialized with";
|
|
59
|
+
readonly ordering: "exclusive-unordered";
|
|
60
|
+
readonly symmetric: true;
|
|
61
|
+
};
|
|
62
|
+
readonly 'together-with': {
|
|
63
|
+
readonly dash: "enclosure";
|
|
64
|
+
readonly terminal: "enclosure";
|
|
65
|
+
readonly glyph: "⧉";
|
|
66
|
+
readonly hueToken: "--ig-edge-together-with";
|
|
67
|
+
readonly label: "together with";
|
|
68
|
+
readonly ordering: "shares-rank";
|
|
69
|
+
readonly symmetric: true;
|
|
70
|
+
};
|
|
71
|
+
readonly 'duplicate-of': {
|
|
72
|
+
readonly dash: "dotted";
|
|
73
|
+
readonly terminal: "hollow-circle";
|
|
74
|
+
readonly glyph: "≡";
|
|
75
|
+
readonly hueToken: "--ig-edge-duplicate-of";
|
|
76
|
+
readonly label: "duplicate of";
|
|
77
|
+
readonly ordering: "never-worked";
|
|
78
|
+
readonly symmetric: false;
|
|
79
|
+
};
|
|
80
|
+
readonly 'decomposed-from': {
|
|
81
|
+
readonly dash: "dashed";
|
|
82
|
+
readonly terminal: "tee";
|
|
83
|
+
readonly glyph: "⑃";
|
|
84
|
+
readonly hueToken: "--ig-edge-decomposed-from";
|
|
85
|
+
readonly label: "decomposed from";
|
|
86
|
+
readonly ordering: "provenance-only";
|
|
87
|
+
readonly symmetric: false;
|
|
88
|
+
};
|
|
89
|
+
}>;
|
|
90
|
+
/** The treatment for a relationship. Total over the format's fields. */
|
|
91
|
+
export declare function treatmentFor(field: EdgeField): EdgeTreatment;
|
|
92
|
+
/**
|
|
93
|
+
* The dash patterns, as SVG `stroke-dasharray` values keyed by dash name.
|
|
94
|
+
*
|
|
95
|
+
* `solid` and `double` carry none: a solid line has no pattern, and a double
|
|
96
|
+
* line is two solid strokes side by side rather than one stroked differently.
|
|
97
|
+
* Returning `null` for them says that out loud; returning `'none'` would read
|
|
98
|
+
* as "solid" and quietly collapse two of the four channels into one.
|
|
99
|
+
*
|
|
100
|
+
* This is the single source for the pattern channel — the stylesheet sets no
|
|
101
|
+
* `stroke-dasharray` for an edge, so a pattern cannot be changed in one place
|
|
102
|
+
* and left stale in the other.
|
|
103
|
+
*/
|
|
104
|
+
export declare function dashArrayFor(dash: EdgeDash): string | null;
|
|
105
|
+
/** Every relationship the format declares, in the order `@issuegraph/core` lists them. */
|
|
106
|
+
export declare const EDGE_ORDER: readonly EdgeField[];
|
|
107
|
+
//# sourceMappingURL=vocabulary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vocabulary.d.ts","sourceRoot":"","sources":["../src/vocabulary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE/D,kFAAkF;AAClF,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE9E,iFAAiF;AACjF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,WAAW,GAAG,eAAe,GAAG,KAAK,CAAC;AAEpF,+CAA+C;AAC/C,MAAM,MAAM,cAAc,GACtB,iBAAiB,GACjB,qBAAqB,GACrB,aAAa,GACb,cAAc,GACd,iBAAiB,CAAC;AAEtB,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8C0B,CAAC;AAEvD,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,aAAa,CAE5D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAY1D;AAED,0FAA0F;AAC1F,eAAO,MAAM,UAAU,EAAE,SAAS,SAAS,EAAgB,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The edge grammar, as data.
|
|
3
|
+
*
|
|
4
|
+
* Each relationship is separable on FOUR redundant channels — dash pattern,
|
|
5
|
+
* terminal marker, glyph and hue — and the colour-blind-safety claim is that
|
|
6
|
+
* removing hue entirely still leaves all five distinguishable. That is a
|
|
7
|
+
* property of this table, so it is asserted against this table rather than
|
|
8
|
+
* asserted about the rendering.
|
|
9
|
+
*
|
|
10
|
+
* It is declared as a total mapping over `EDGE_FIELDS` rather than a list of
|
|
11
|
+
* cases, so a sixth relationship added to the format fails the BUILD here
|
|
12
|
+
* instead of rendering as an untreated line nobody notices.
|
|
13
|
+
*/
|
|
14
|
+
import { EDGE_FIELDS } from '@issuegraph/core';
|
|
15
|
+
/**
|
|
16
|
+
* `satisfies` rather than an annotation, so the object literal keeps its narrow
|
|
17
|
+
* types AND the compiler proves every `EdgeField` has an entry. Adding a field
|
|
18
|
+
* to `@issuegraph/core` without adding it here is TS2739 at build time.
|
|
19
|
+
*/
|
|
20
|
+
export const EDGE_TREATMENTS = Object.freeze({
|
|
21
|
+
'blocked-by': {
|
|
22
|
+
dash: 'solid',
|
|
23
|
+
terminal: 'arrow',
|
|
24
|
+
glyph: '⊘',
|
|
25
|
+
hueToken: '--ig-edge-blocked-by',
|
|
26
|
+
label: 'blocked by',
|
|
27
|
+
ordering: 'strict-directed',
|
|
28
|
+
symmetric: false,
|
|
29
|
+
},
|
|
30
|
+
'serialize-with': {
|
|
31
|
+
dash: 'double',
|
|
32
|
+
terminal: 'none',
|
|
33
|
+
glyph: '⇄',
|
|
34
|
+
hueToken: '--ig-edge-serialize-with',
|
|
35
|
+
label: 'serialized with',
|
|
36
|
+
ordering: 'exclusive-unordered',
|
|
37
|
+
symmetric: true,
|
|
38
|
+
},
|
|
39
|
+
'together-with': {
|
|
40
|
+
dash: 'enclosure',
|
|
41
|
+
terminal: 'enclosure',
|
|
42
|
+
glyph: '⧉',
|
|
43
|
+
hueToken: '--ig-edge-together-with',
|
|
44
|
+
label: 'together with',
|
|
45
|
+
ordering: 'shares-rank',
|
|
46
|
+
symmetric: true,
|
|
47
|
+
},
|
|
48
|
+
'duplicate-of': {
|
|
49
|
+
dash: 'dotted',
|
|
50
|
+
terminal: 'hollow-circle',
|
|
51
|
+
glyph: '≡',
|
|
52
|
+
hueToken: '--ig-edge-duplicate-of',
|
|
53
|
+
label: 'duplicate of',
|
|
54
|
+
ordering: 'never-worked',
|
|
55
|
+
symmetric: false,
|
|
56
|
+
},
|
|
57
|
+
'decomposed-from': {
|
|
58
|
+
dash: 'dashed',
|
|
59
|
+
terminal: 'tee',
|
|
60
|
+
glyph: '⑃',
|
|
61
|
+
hueToken: '--ig-edge-decomposed-from',
|
|
62
|
+
label: 'decomposed from',
|
|
63
|
+
ordering: 'provenance-only',
|
|
64
|
+
symmetric: false,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
/** The treatment for a relationship. Total over the format's fields. */
|
|
68
|
+
export function treatmentFor(field) {
|
|
69
|
+
return EDGE_TREATMENTS[field];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The dash patterns, as SVG `stroke-dasharray` values keyed by dash name.
|
|
73
|
+
*
|
|
74
|
+
* `solid` and `double` carry none: a solid line has no pattern, and a double
|
|
75
|
+
* line is two solid strokes side by side rather than one stroked differently.
|
|
76
|
+
* Returning `null` for them says that out loud; returning `'none'` would read
|
|
77
|
+
* as "solid" and quietly collapse two of the four channels into one.
|
|
78
|
+
*
|
|
79
|
+
* This is the single source for the pattern channel — the stylesheet sets no
|
|
80
|
+
* `stroke-dasharray` for an edge, so a pattern cannot be changed in one place
|
|
81
|
+
* and left stale in the other.
|
|
82
|
+
*/
|
|
83
|
+
export function dashArrayFor(dash) {
|
|
84
|
+
switch (dash) {
|
|
85
|
+
case 'solid':
|
|
86
|
+
case 'double':
|
|
87
|
+
return null;
|
|
88
|
+
case 'dotted':
|
|
89
|
+
return '1 3';
|
|
90
|
+
case 'dashed':
|
|
91
|
+
return '6 4';
|
|
92
|
+
case 'enclosure':
|
|
93
|
+
return '3 3';
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Every relationship the format declares, in the order `@issuegraph/core` lists them. */
|
|
97
|
+
export const EDGE_ORDER = EDGE_FIELDS;
|
|
98
|
+
//# sourceMappingURL=vocabulary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vocabulary.js","sourceRoot":"","sources":["../src/vocabulary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,WAAW,EAAkB,MAAM,kBAAkB,CAAC;AAkC/D;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3C,YAAY,EAAE;QACZ,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,sBAAsB;QAChC,KAAK,EAAE,YAAY;QACnB,QAAQ,EAAE,iBAAiB;QAC3B,SAAS,EAAE,KAAK;KACjB;IACD,gBAAgB,EAAE;QAChB,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,0BAA0B;QACpC,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,qBAAqB;QAC/B,SAAS,EAAE,IAAI;KAChB;IACD,eAAe,EAAE;QACf,IAAI,EAAE,WAAW;QACjB,QAAQ,EAAE,WAAW;QACrB,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,yBAAyB;QACnC,KAAK,EAAE,eAAe;QACtB,QAAQ,EAAE,aAAa;QACvB,SAAS,EAAE,IAAI;KAChB;IACD,cAAc,EAAE;QACd,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,eAAe;QACzB,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,wBAAwB;QAClC,KAAK,EAAE,cAAc;QACrB,QAAQ,EAAE,cAAc;QACxB,SAAS,EAAE,KAAK;KACjB;IACD,iBAAiB,EAAE;QACjB,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,2BAA2B;QACrC,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,iBAAiB;QAC3B,SAAS,EAAE,KAAK;KACjB;CACkD,CAAC,CAAC;AAEvD,wEAAwE;AACxE,MAAM,UAAU,YAAY,CAAC,KAAgB;IAC3C,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,IAAI,CAAC;QACd,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC;QACf,KAAK,WAAW;YACd,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,MAAM,UAAU,GAAyB,WAAW,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@issuegraph/viewer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Render an Issuegraph document as a work order — the ordered spine with readiness stations, the five edge treatments, and three projections. Rendering only: no fetching, no mutation, no auth, and every value themeable through CSS custom properties.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"issuegraph",
|
|
7
|
+
"dependency-graph",
|
|
8
|
+
"backlog",
|
|
9
|
+
"scheduling",
|
|
10
|
+
"visualization",
|
|
11
|
+
"viewer"
|
|
12
|
+
],
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"author": "Autonomy LLC",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public",
|
|
30
|
+
"provenance": true
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/autnmy/issuegraph.git",
|
|
35
|
+
"directory": "packages/viewer"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/autnmy/issuegraph#readme",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/autnmy/issuegraph/issues"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@issuegraph/core": "^0.1.1"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^22.18.0",
|
|
49
|
+
"typescript": "^6.0.3"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsc -p tsconfig.json",
|
|
53
|
+
"typecheck": "tsc -p tsconfig.test.json",
|
|
54
|
+
"test": "node --test \"src/**/*.test.ts\""
|
|
55
|
+
}
|
|
56
|
+
}
|