@formicoidea/labre-framework-cynefin 0.40.0 → 0.42.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 +384 -0
- package/dist/commands.js +5 -1
- package/dist/cynefin/consts.d.ts +55 -12
- package/dist/cynefin/consts.js +281 -34
- package/dist/cynefin/element-renderer.d.ts +16 -0
- package/dist/cynefin/element-renderer.js +60 -23
- package/dist/cynefin/element-view.d.ts +11 -2
- package/dist/cynefin/element-view.js +17 -2
- package/dist/cynefin/labels.d.ts +25 -0
- package/dist/cynefin/labels.js +40 -0
- package/dist/cynefin/toolbar/config.d.ts +2 -0
- package/dist/cynefin/toolbar/config.js +22 -3
- package/dist/estuarine/consts.d.ts +29 -4
- package/dist/estuarine/consts.js +44 -4
- package/dist/estuarine/element-renderer.js +14 -8
- package/dist/estuarine/element-view.d.ts +10 -2
- package/dist/estuarine/element-view.js +17 -2
- package/dist/estuarine/labels.d.ts +39 -0
- package/dist/estuarine/labels.js +49 -0
- package/dist/estuarine/toolbar/config.d.ts +2 -0
- package/dist/estuarine/toolbar/config.js +28 -4
- package/dist/templates/index.d.ts +39 -0
- package/dist/templates/index.js +123 -16
- package/dist/toolbar/palette.d.ts +31 -0
- package/dist/toolbar/palette.js +105 -0
- package/dist/toolbar/senior-button.d.ts +2 -0
- package/dist/toolbar/senior-button.js +6 -2
- package/dist/translations.js +52 -1
- package/dist/view.js +7 -0
- package/package.json +2 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { backgroundTextHitBox } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { refScale } from '../utils.js';
|
|
3
|
+
import { DOMAINS, HEADING_SIZE, REF_H, REF_W } from './consts.js';
|
|
4
|
+
/**
|
|
5
|
+
* What a domain heading SAYS: the user's own word, else the vocabulary.
|
|
6
|
+
*
|
|
7
|
+
* The very precedence `backgroundLabelText` applies to a declared background —
|
|
8
|
+
* user text wins over the catalogue, the catalogue over the shipped English —
|
|
9
|
+
* spelled out here because this diagram has no declaration to apply it for it.
|
|
10
|
+
* An empty string is a real answer (the user erased the word), which is why the
|
|
11
|
+
* test is against `undefined` and not against falsiness.
|
|
12
|
+
*/
|
|
13
|
+
export function cynefinHeadingText(model, block, translate) {
|
|
14
|
+
const own = model[block.prop];
|
|
15
|
+
return own === undefined || own === null
|
|
16
|
+
? translate(block.heading)
|
|
17
|
+
: String(own);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Clickable boxes of the four domain headings, in ELEMENT-LOCAL coordinates.
|
|
21
|
+
*
|
|
22
|
+
* Built from the same reference positions and the same uniform letterbox fit
|
|
23
|
+
* the renderer draws them with, so the target tracks the word at any size, and
|
|
24
|
+
* empty while the headings are hidden — a label that is not painted may not be
|
|
25
|
+
* aimed at either.
|
|
26
|
+
*/
|
|
27
|
+
export function cynefinLabelHits(model, w, h, translate) {
|
|
28
|
+
if (!model.showTitles)
|
|
29
|
+
return [];
|
|
30
|
+
const { s, ox, oy } = refScale(w, h, REF_W, REF_H);
|
|
31
|
+
return DOMAINS.map(block => {
|
|
32
|
+
const text = cynefinHeadingText(model, block, translate);
|
|
33
|
+
return {
|
|
34
|
+
id: block.prop,
|
|
35
|
+
prop: block.prop,
|
|
36
|
+
text,
|
|
37
|
+
...backgroundTextHitBox(text, HEADING_SIZE * s, ox + block.x * s, oy + block.hy * s),
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type ChromeWording, type ToolbarContext } from '@formicoidea/labre-core/shared/services';
|
|
2
2
|
import { type TemplateResult } from 'lit';
|
|
3
|
+
/** Every wording above, for `translations.ts`'s manifest contribution. */
|
|
4
|
+
export declare const CYNEFIN_TOOLBAR_WORDINGS: readonly ChromeWording[];
|
|
3
5
|
export declare const cynefinToolbarConfig: {
|
|
4
6
|
readonly actions: [{
|
|
5
7
|
id: string;
|
|
@@ -52,6 +52,25 @@ const LiminalIcon = html `<svg
|
|
|
52
52
|
>
|
|
53
53
|
<path d="M5 17 C9 6 15 6 19 7" />
|
|
54
54
|
</svg>`;
|
|
55
|
+
/** The three toolbar tooltips this file used to hard-code as English literals. */
|
|
56
|
+
const TITLES_TOGGLE = [
|
|
57
|
+
'com.labre.cynefin-estuarine.cynefin.toolbar.titles',
|
|
58
|
+
'Show / hide titles',
|
|
59
|
+
];
|
|
60
|
+
const DESCRIPTIONS_TOGGLE = [
|
|
61
|
+
'com.labre.cynefin-estuarine.cynefin.toolbar.descriptions',
|
|
62
|
+
'Show / hide explanatory text',
|
|
63
|
+
];
|
|
64
|
+
const LIMINAL_LINE_TOGGLE = [
|
|
65
|
+
'com.labre.cynefin-estuarine.cynefin.toolbar.liminal-line',
|
|
66
|
+
'Show / hide liminal line',
|
|
67
|
+
];
|
|
68
|
+
/** Every wording above, for `translations.ts`'s manifest contribution. */
|
|
69
|
+
export const CYNEFIN_TOOLBAR_WORDINGS = [
|
|
70
|
+
TITLES_TOGGLE,
|
|
71
|
+
DESCRIPTIONS_TOGGLE,
|
|
72
|
+
LIMINAL_LINE_TOGGLE,
|
|
73
|
+
];
|
|
55
74
|
function booleanToggle(id, tooltip, icon, prop) {
|
|
56
75
|
return {
|
|
57
76
|
id,
|
|
@@ -81,9 +100,9 @@ function booleanToggle(id, tooltip, icon, prop) {
|
|
|
81
100
|
export const cynefinToolbarConfig = {
|
|
82
101
|
actions: [
|
|
83
102
|
booleanToggle('a.toggle-resize', BOARD_RESIZE_TOGGLE, ResizeIcon, 'resizeEnabled'),
|
|
84
|
-
booleanToggle('b.toggle-titles',
|
|
85
|
-
booleanToggle('c.toggle-descriptions',
|
|
86
|
-
booleanToggle('d.toggle-liminal',
|
|
103
|
+
booleanToggle('b.toggle-titles', TITLES_TOGGLE, TitlesIcon, 'showTitles'),
|
|
104
|
+
booleanToggle('c.toggle-descriptions', DESCRIPTIONS_TOGGLE, DescIcon, 'showDescriptions'),
|
|
105
|
+
booleanToggle('d.toggle-liminal', LIMINAL_LINE_TOGGLE, LiminalIcon, 'showLiminalLine'),
|
|
87
106
|
],
|
|
88
107
|
when: ctx => ctx.getSurfaceModelsByType(CynefinElementModel).length > 0,
|
|
89
108
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ChromeWording } from '@formicoidea/labre-core/shared/services';
|
|
1
2
|
/**
|
|
2
3
|
* Visual constants for the Estuarine framework map, reproduced from the official
|
|
3
4
|
* SVG (viewBox 0 0 690 801). All geometry is authored in that fixed reference
|
|
@@ -7,6 +8,12 @@
|
|
|
7
8
|
* letterboxed (see `EstuarineFit` in `./element-renderer.ts`). The e axis is
|
|
8
9
|
* vertical & double-headed (energy), the t axis horizontal & single-headed
|
|
9
10
|
* (time only flows one way).
|
|
11
|
+
*
|
|
12
|
+
* The three curve legends below (`LABELS`) carry a `wording`, resolved by
|
|
13
|
+
* `element-renderer.ts` through the `CanvasRenderer` it is handed at paint
|
|
14
|
+
* time — see `cynefin/consts.ts` for the identical mechanism next door. The
|
|
15
|
+
* italic `e` / `t` axis LETTERS (`AXIS_LABELS`) are notation, not words, and
|
|
16
|
+
* are deliberately NOT keyed (PO decision).
|
|
10
17
|
*/
|
|
11
18
|
export declare const REF_W = 690;
|
|
12
19
|
export declare const REF_H = 801;
|
|
@@ -50,24 +57,42 @@ export declare const COUNTERFACTUAL_WIDTH = 5.5;
|
|
|
50
57
|
/** Volatile: red boundary descending along the left, bulging right. */
|
|
51
58
|
export declare const VOLATILE_PATH = "M 58 446 C 61 447, 70 451, 76 454 C 82 457, 88 462, 94 466 C 100 470, 107 476, 112 481 C 117 486, 122 492, 126 498 C 130 504, 135 509, 139 515 C 143 521, 145 526, 148 532 C 151 538, 153 544, 155 550 C 157 556, 159 562, 160 568 C 161 574, 162 580, 163 586 C 164 592, 164 598, 164 604 C 164 610, 166 616, 166 622 C 166 628, 166 634, 165 640 C 164 646, 164 652, 163 658 C 162 664, 162 670, 161 676 C 160 682, 160 688, 159 694 C 158 700, 155 706, 154 712 C 153 718, 152 724, 151 730 C 150 736, 148 746, 147 749";
|
|
52
59
|
export declare const VOLATILE_WIDTH = 5;
|
|
53
|
-
/**
|
|
60
|
+
/** Every {@link LABELS} wording, for `translations.ts`'s manifest. */
|
|
61
|
+
export declare const ESTUARINE_CANVAS_WORDINGS: readonly ChromeWording[];
|
|
62
|
+
/**
|
|
63
|
+
* Uppercase legends: anchored centre, alphabetic baseline, with letter-spacing.
|
|
64
|
+
*
|
|
65
|
+
* `prop` names the model key a double-click renames the legend into (issue
|
|
66
|
+
* #355), and `visibleProp` the toggle that shows it — the legend is painted
|
|
67
|
+
* with its curve and hidden with it, so it is aimable exactly when it is drawn.
|
|
68
|
+
*
|
|
69
|
+
* The three legends and nothing else: the italic `e` / `t` axis letters are
|
|
70
|
+
* notation, not words (PO decision, and the reason they carry no i18n key
|
|
71
|
+
* either), so they are not renamable.
|
|
72
|
+
*/
|
|
54
73
|
export declare const LABELS: {
|
|
55
74
|
readonly counterfactual: {
|
|
56
|
-
readonly
|
|
75
|
+
readonly wording: ChromeWording;
|
|
76
|
+
readonly prop: "counterfactualLabel";
|
|
77
|
+
readonly visibleProp: "showCounterfactual";
|
|
57
78
|
readonly x: 422;
|
|
58
79
|
readonly y: 25;
|
|
59
80
|
readonly size: 20;
|
|
60
81
|
readonly color: "#1a1a1a";
|
|
61
82
|
};
|
|
62
83
|
readonly liminal: {
|
|
63
|
-
readonly
|
|
84
|
+
readonly wording: ChromeWording;
|
|
85
|
+
readonly prop: "liminalLabel";
|
|
86
|
+
readonly visibleProp: "showLiminal";
|
|
64
87
|
readonly x: 316;
|
|
65
88
|
readonly y: 192;
|
|
66
89
|
readonly size: 18;
|
|
67
90
|
readonly color: "#2e7d32";
|
|
68
91
|
};
|
|
69
92
|
readonly volatile: {
|
|
70
|
-
readonly
|
|
93
|
+
readonly wording: ChromeWording;
|
|
94
|
+
readonly prop: "volatileLabel";
|
|
95
|
+
readonly visibleProp: "showVolatile";
|
|
71
96
|
readonly x: 219;
|
|
72
97
|
readonly y: 783;
|
|
73
98
|
readonly size: 20;
|
package/dist/estuarine/consts.js
CHANGED
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
* letterboxed (see `EstuarineFit` in `./element-renderer.ts`). The e axis is
|
|
8
8
|
* vertical & double-headed (energy), the t axis horizontal & single-headed
|
|
9
9
|
* (time only flows one way).
|
|
10
|
+
*
|
|
11
|
+
* The three curve legends below (`LABELS`) carry a `wording`, resolved by
|
|
12
|
+
* `element-renderer.ts` through the `CanvasRenderer` it is handed at paint
|
|
13
|
+
* time — see `cynefin/consts.ts` for the identical mechanism next door. The
|
|
14
|
+
* italic `e` / `t` axis LETTERS (`AXIS_LABELS`) are notation, not words, and
|
|
15
|
+
* are deliberately NOT keyed (PO decision).
|
|
10
16
|
*/
|
|
11
17
|
export const REF_W = 690;
|
|
12
18
|
export const REF_H = 801;
|
|
@@ -54,24 +60,58 @@ export const COUNTERFACTUAL_WIDTH = 5.5;
|
|
|
54
60
|
/** Volatile: red boundary descending along the left, bulging right. */
|
|
55
61
|
export const VOLATILE_PATH = 'M 58 446 C 61 447, 70 451, 76 454 C 82 457, 88 462, 94 466 C 100 470, 107 476, 112 481 C 117 486, 122 492, 126 498 C 130 504, 135 509, 139 515 C 143 521, 145 526, 148 532 C 151 538, 153 544, 155 550 C 157 556, 159 562, 160 568 C 161 574, 162 580, 163 586 C 164 592, 164 598, 164 604 C 164 610, 166 616, 166 622 C 166 628, 166 634, 165 640 C 164 646, 164 652, 163 658 C 162 664, 162 670, 161 676 C 160 682, 160 688, 159 694 C 158 700, 155 706, 154 712 C 153 718, 152 724, 151 730 C 150 736, 148 746, 147 749';
|
|
56
62
|
export const VOLATILE_WIDTH = 5;
|
|
57
|
-
|
|
63
|
+
const LABEL_COUNTERFACTUAL = [
|
|
64
|
+
'com.labre.cynefin-estuarine.estuarine.legend.counter-factual',
|
|
65
|
+
'COUNTER FACTUAL',
|
|
66
|
+
];
|
|
67
|
+
const LABEL_LIMINAL = [
|
|
68
|
+
'com.labre.cynefin-estuarine.estuarine.legend.liminal',
|
|
69
|
+
'LIMINAL',
|
|
70
|
+
];
|
|
71
|
+
const LABEL_VOLATILE = [
|
|
72
|
+
'com.labre.cynefin-estuarine.estuarine.legend.volatile',
|
|
73
|
+
'VOLATILE',
|
|
74
|
+
];
|
|
75
|
+
/** Every {@link LABELS} wording, for `translations.ts`'s manifest. */
|
|
76
|
+
export const ESTUARINE_CANVAS_WORDINGS = [
|
|
77
|
+
LABEL_COUNTERFACTUAL,
|
|
78
|
+
LABEL_LIMINAL,
|
|
79
|
+
LABEL_VOLATILE,
|
|
80
|
+
];
|
|
81
|
+
/**
|
|
82
|
+
* Uppercase legends: anchored centre, alphabetic baseline, with letter-spacing.
|
|
83
|
+
*
|
|
84
|
+
* `prop` names the model key a double-click renames the legend into (issue
|
|
85
|
+
* #355), and `visibleProp` the toggle that shows it — the legend is painted
|
|
86
|
+
* with its curve and hidden with it, so it is aimable exactly when it is drawn.
|
|
87
|
+
*
|
|
88
|
+
* The three legends and nothing else: the italic `e` / `t` axis letters are
|
|
89
|
+
* notation, not words (PO decision, and the reason they carry no i18n key
|
|
90
|
+
* either), so they are not renamable.
|
|
91
|
+
*/
|
|
58
92
|
export const LABELS = {
|
|
59
93
|
counterfactual: {
|
|
60
|
-
|
|
94
|
+
wording: LABEL_COUNTERFACTUAL,
|
|
95
|
+
prop: 'counterfactualLabel',
|
|
96
|
+
visibleProp: 'showCounterfactual',
|
|
61
97
|
x: 422,
|
|
62
98
|
y: 25,
|
|
63
99
|
size: 20,
|
|
64
100
|
color: COLORS.label,
|
|
65
101
|
},
|
|
66
102
|
liminal: {
|
|
67
|
-
|
|
103
|
+
wording: LABEL_LIMINAL,
|
|
104
|
+
prop: 'liminalLabel',
|
|
105
|
+
visibleProp: 'showLiminal',
|
|
68
106
|
x: 316,
|
|
69
107
|
y: 192,
|
|
70
108
|
size: 18,
|
|
71
109
|
color: COLORS.liminalLabel,
|
|
72
110
|
},
|
|
73
111
|
volatile: {
|
|
74
|
-
|
|
112
|
+
wording: LABEL_VOLATILE,
|
|
113
|
+
prop: 'volatileLabel',
|
|
114
|
+
visibleProp: 'showVolatile',
|
|
75
115
|
x: 219,
|
|
76
116
|
y: 783,
|
|
77
117
|
size: 20,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { ElementRendererExtension, } from '@formicoidea/labre-core/blocks/surface';
|
|
1
|
+
import { ElementRendererExtension, taggedPath2D, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { translateKey, } from '@formicoidea/labre-core/shared/services';
|
|
2
3
|
import { FONT_FAMILY } from '../utils.js';
|
|
3
4
|
import { ARROWHEADS, AXIS_LABELS, AXIS_WIDTH, COLORS, COUNTERFACTUAL_PATH, COUNTERFACTUAL_WIDTH, E_AXIS, LABEL_LETTER_SPACING, LABELS, LIMINAL_PATH, LIMINAL_WIDTH, REF_H, REF_W, T_AXIS, VOLATILE_PATH, VOLATILE_WIDTH, } from './consts.js';
|
|
5
|
+
import { estuarineLegendText } from './labels.js';
|
|
4
6
|
/**
|
|
5
7
|
* The three reference curves are drawn as a permanent GHOST (PO arbitration,
|
|
6
8
|
* 26/08/2026): dashed, translucent, never solid again.
|
|
@@ -39,21 +41,21 @@ export function estuarineCurves() {
|
|
|
39
41
|
return (_curves ??= [
|
|
40
42
|
{
|
|
41
43
|
key: 'liminal',
|
|
42
|
-
path:
|
|
44
|
+
path: taggedPath2D(LIMINAL_PATH),
|
|
43
45
|
color: COLORS.liminal,
|
|
44
46
|
width: LIMINAL_WIDTH,
|
|
45
47
|
visibleProp: 'showLiminal',
|
|
46
48
|
},
|
|
47
49
|
{
|
|
48
50
|
key: 'volatile',
|
|
49
|
-
path:
|
|
51
|
+
path: taggedPath2D(VOLATILE_PATH),
|
|
50
52
|
color: COLORS.volatile,
|
|
51
53
|
width: VOLATILE_WIDTH,
|
|
52
54
|
visibleProp: 'showVolatile',
|
|
53
55
|
},
|
|
54
56
|
{
|
|
55
57
|
key: 'counterfactual',
|
|
56
|
-
path:
|
|
58
|
+
path: taggedPath2D(COUNTERFACTUAL_PATH),
|
|
57
59
|
color: COLORS.counterfactual,
|
|
58
60
|
width: COUNTERFACTUAL_WIDTH,
|
|
59
61
|
visibleProp: 'showCounterfactual',
|
|
@@ -99,7 +101,8 @@ export function applyEstuarineTransform(ctx, w, h) {
|
|
|
99
101
|
* the three curves, which are boundaries across the plane and must cover
|
|
100
102
|
* whatever plane the user has made.
|
|
101
103
|
*/
|
|
102
|
-
export const estuarine = (model, ctx, matrix) => {
|
|
104
|
+
export const estuarine = (model, ctx, matrix, renderer) => {
|
|
105
|
+
const tr = (wording) => renderer ? translateKey(renderer.std, ...wording) : wording[1];
|
|
103
106
|
const [, , w, h] = model.deserializedXYWH;
|
|
104
107
|
const cx = w / 2;
|
|
105
108
|
const cy = h / 2;
|
|
@@ -144,7 +147,8 @@ export const estuarine = (model, ctx, matrix) => {
|
|
|
144
147
|
// Uppercase legend (centre-anchored, alphabetic baseline, letter-spaced).
|
|
145
148
|
// Anchored proportionally, typed isotropically — never inside the stretch.
|
|
146
149
|
const hasSpacing = 'letterSpacing' in ctx;
|
|
147
|
-
const legend = (
|
|
150
|
+
const legend = (key) => {
|
|
151
|
+
const l = LABELS[key];
|
|
148
152
|
ctx.fillStyle = l.color;
|
|
149
153
|
ctx.font = `600 ${l.size * fit.strokeScale}px ${FONT_FAMILY}`;
|
|
150
154
|
ctx.textAlign = 'center';
|
|
@@ -152,7 +156,9 @@ export const estuarine = (model, ctx, matrix) => {
|
|
|
152
156
|
if (hasSpacing) {
|
|
153
157
|
ctx.letterSpacing = `${LABEL_LETTER_SPACING * fit.strokeScale}px`;
|
|
154
158
|
}
|
|
155
|
-
|
|
159
|
+
// The user's own word when they have renamed this legend, the catalogue's
|
|
160
|
+
// otherwise — the same precedence a declared background applies.
|
|
161
|
+
ctx.fillText(estuarineLegendText(model, key, tr), ax(l.x), ay(l.y));
|
|
156
162
|
if (hasSpacing)
|
|
157
163
|
ctx.letterSpacing = '0px';
|
|
158
164
|
};
|
|
@@ -171,7 +177,7 @@ export const estuarine = (model, ctx, matrix) => {
|
|
|
171
177
|
ctx.setLineDash([...GHOST_DASH]);
|
|
172
178
|
ctx.stroke(curve.path);
|
|
173
179
|
ctx.restore();
|
|
174
|
-
legend(
|
|
180
|
+
legend(curve.key);
|
|
175
181
|
}
|
|
176
182
|
// ── Italic e / t axis letters ───────────────────────────────────────
|
|
177
183
|
if (model.showAxisLabels) {
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import type { EditableBackgroundLabel } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { FrameworkBackgroundView } from '@formicoidea/labre-core/blocks/surface';
|
|
1
3
|
import type { EstuarineElementModel } from '@formicoidea/labre-core/model';
|
|
2
|
-
import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
3
4
|
/**
|
|
4
5
|
* View for the Estuarine background. Registering it ensures `gfx.view.get(model)`
|
|
5
6
|
* returns a view (required so move / select interactions work).
|
|
7
|
+
*
|
|
8
|
+
* Extends {@link FrameworkBackgroundView} rather than
|
|
9
|
+
* `DeclaredBackgroundView`: the map is a reproduction of the official SVG with
|
|
10
|
+
* a stretch of its own and no `FrameworkBackgroundDef` behind it, so it says
|
|
11
|
+
* where its three legends are through the very fit the renderer anchors them
|
|
12
|
+
* with. The gesture itself is the shared one (issue #355).
|
|
6
13
|
*/
|
|
7
|
-
export declare class EstuarineView extends
|
|
14
|
+
export declare class EstuarineView extends FrameworkBackgroundView<EstuarineElementModel> {
|
|
8
15
|
static type: string;
|
|
16
|
+
protected labelAt(lx: number, ly: number, w: number, h: number): EditableBackgroundLabel | null;
|
|
9
17
|
}
|
|
10
18
|
/**
|
|
11
19
|
* Resize gating: the resize handles are hidden unless `model.resizeEnabled` is
|
|
@@ -1,10 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FrameworkBackgroundView, hitTestBackgroundLabel, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { translateKey, } from '@formicoidea/labre-core/shared/services';
|
|
3
|
+
import { GfxViewInteractionExtension } from '@formicoidea/labre-core/std/gfx';
|
|
4
|
+
import { estuarineFit } from './element-renderer.js';
|
|
5
|
+
import { estuarineLabelHits } from './labels.js';
|
|
2
6
|
/**
|
|
3
7
|
* View for the Estuarine background. Registering it ensures `gfx.view.get(model)`
|
|
4
8
|
* returns a view (required so move / select interactions work).
|
|
9
|
+
*
|
|
10
|
+
* Extends {@link FrameworkBackgroundView} rather than
|
|
11
|
+
* `DeclaredBackgroundView`: the map is a reproduction of the official SVG with
|
|
12
|
+
* a stretch of its own and no `FrameworkBackgroundDef` behind it, so it says
|
|
13
|
+
* where its three legends are through the very fit the renderer anchors them
|
|
14
|
+
* with. The gesture itself is the shared one (issue #355).
|
|
5
15
|
*/
|
|
6
|
-
export class EstuarineView extends
|
|
16
|
+
export class EstuarineView extends FrameworkBackgroundView {
|
|
7
17
|
static { this.type = 'estuarine'; }
|
|
18
|
+
labelAt(lx, ly, w, h) {
|
|
19
|
+
const translate = (wording) => translateKey(this.gfx.std, ...wording);
|
|
20
|
+
const hit = hitTestBackgroundLabel(estuarineLabelHits(this.model, estuarineFit(w, h), translate), lx, ly);
|
|
21
|
+
return hit ? { prop: hit.prop, text: hit.text } : null;
|
|
22
|
+
}
|
|
8
23
|
}
|
|
9
24
|
/**
|
|
10
25
|
* Resize gating: the resize handles are hidden unless `model.resizeEnabled` is
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { BackgroundLabelHit } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import type { EstuarineElementModel } from '@formicoidea/labre-core/model';
|
|
3
|
+
import type { ChromeWording } from '@formicoidea/labre-core/shared/services';
|
|
4
|
+
import { LABELS } from './consts.js';
|
|
5
|
+
/** Resolves a wording against the host's catalogue, or falls back to English. */
|
|
6
|
+
export type EstuarineWordingResolver = (wording: ChromeWording) => string;
|
|
7
|
+
/** The three curve legends, in the order the renderer paints them. */
|
|
8
|
+
export type EstuarineLegendKey = keyof typeof LABELS;
|
|
9
|
+
/**
|
|
10
|
+
* Only the factors the legends need out of `EstuarineFit`.
|
|
11
|
+
*
|
|
12
|
+
* Taken as a parameter rather than imported: the fit is computed in
|
|
13
|
+
* `./element-renderer.ts`, which reads this module to know what a legend says,
|
|
14
|
+
* and a module cycle to save two fields would be a poor trade.
|
|
15
|
+
*/
|
|
16
|
+
export interface EstuarineLegendFit {
|
|
17
|
+
sx: number;
|
|
18
|
+
sy: number;
|
|
19
|
+
/** The one undeformed factor — type is never stretched. */
|
|
20
|
+
strokeScale: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* What a legend SAYS: the user's own word, else the vocabulary.
|
|
24
|
+
*
|
|
25
|
+
* The very precedence `backgroundLabelText` applies to a declared background —
|
|
26
|
+
* user text wins over the catalogue, the catalogue over the shipped English —
|
|
27
|
+
* spelled out here because this map has no declaration to apply it for it. An
|
|
28
|
+
* empty string is a real answer (the user erased the word), which is why the
|
|
29
|
+
* test is against `undefined` and not against falsiness.
|
|
30
|
+
*/
|
|
31
|
+
export declare function estuarineLegendText(model: EstuarineElementModel, key: EstuarineLegendKey, translate: EstuarineWordingResolver): string;
|
|
32
|
+
/**
|
|
33
|
+
* Clickable boxes of the visible legends, in ELEMENT-LOCAL coordinates.
|
|
34
|
+
*
|
|
35
|
+
* Anchored through the same fit the renderer anchors them with: proportionally
|
|
36
|
+
* in both directions, typed isotropically. A legend whose curve is switched off
|
|
37
|
+
* is not painted and is therefore not aimable either.
|
|
38
|
+
*/
|
|
39
|
+
export declare function estuarineLabelHits(model: EstuarineElementModel, fit: EstuarineLegendFit, translate: EstuarineWordingResolver): BackgroundLabelHit[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { backgroundTextHitBox } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { LABEL_LETTER_SPACING, LABELS } from './consts.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a legend SAYS: the user's own word, else the vocabulary.
|
|
5
|
+
*
|
|
6
|
+
* The very precedence `backgroundLabelText` applies to a declared background —
|
|
7
|
+
* user text wins over the catalogue, the catalogue over the shipped English —
|
|
8
|
+
* spelled out here because this map has no declaration to apply it for it. An
|
|
9
|
+
* empty string is a real answer (the user erased the word), which is why the
|
|
10
|
+
* test is against `undefined` and not against falsiness.
|
|
11
|
+
*/
|
|
12
|
+
export function estuarineLegendText(model, key, translate) {
|
|
13
|
+
const label = LABELS[key];
|
|
14
|
+
const own = model[label.prop];
|
|
15
|
+
return own === undefined || own === null
|
|
16
|
+
? translate(label.wording)
|
|
17
|
+
: String(own);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Clickable boxes of the visible legends, in ELEMENT-LOCAL coordinates.
|
|
21
|
+
*
|
|
22
|
+
* Anchored through the same fit the renderer anchors them with: proportionally
|
|
23
|
+
* in both directions, typed isotropically. A legend whose curve is switched off
|
|
24
|
+
* is not painted and is therefore not aimable either.
|
|
25
|
+
*/
|
|
26
|
+
export function estuarineLabelHits(model, fit, translate) {
|
|
27
|
+
const props = model;
|
|
28
|
+
const hits = [];
|
|
29
|
+
for (const key of Object.keys(LABELS)) {
|
|
30
|
+
const label = LABELS[key];
|
|
31
|
+
if (!props[label.visibleProp])
|
|
32
|
+
continue;
|
|
33
|
+
const text = estuarineLegendText(model, key, translate);
|
|
34
|
+
const box = backgroundTextHitBox(text, label.size * fit.strokeScale, label.x * fit.sx, label.y * fit.sy, 'center');
|
|
35
|
+
// A legend is letter-spaced, so it is wider than the shared estimate: half
|
|
36
|
+
// of the extra width on each side, since the word is centred on its anchor.
|
|
37
|
+
const spread = (Math.max(text.length - 1, 0) * LABEL_LETTER_SPACING * fit.strokeScale) /
|
|
38
|
+
2;
|
|
39
|
+
hits.push({
|
|
40
|
+
id: key,
|
|
41
|
+
prop: label.prop,
|
|
42
|
+
text,
|
|
43
|
+
...box,
|
|
44
|
+
minX: box.minX - spread,
|
|
45
|
+
maxX: box.maxX + spread,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return hits;
|
|
49
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type ChromeWording, type ToolbarContext } from '@formicoidea/labre-core/shared/services';
|
|
2
2
|
import { type TemplateResult } from 'lit';
|
|
3
|
+
/** Every wording above, for `translations.ts`'s manifest contribution. */
|
|
4
|
+
export declare const ESTUARINE_TOOLBAR_WORDINGS: readonly ChromeWording[];
|
|
3
5
|
export declare const estuarineToolbarConfig: {
|
|
4
6
|
readonly actions: [{
|
|
5
7
|
id: string;
|
|
@@ -64,6 +64,30 @@ const AxisIcon = html `<svg
|
|
|
64
64
|
<path d="M6 3v18M6 12h15" />
|
|
65
65
|
<path d="M3 6l3-3 3 3M18 9l3 3-3 3" />
|
|
66
66
|
</svg>`;
|
|
67
|
+
/** The four toolbar tooltips this file used to hard-code as English literals. */
|
|
68
|
+
const LIMINAL_TOGGLE = [
|
|
69
|
+
'com.labre.cynefin-estuarine.estuarine.toolbar.liminal',
|
|
70
|
+
'Show / hide the Liminal line',
|
|
71
|
+
];
|
|
72
|
+
const VOLATILE_TOGGLE = [
|
|
73
|
+
'com.labre.cynefin-estuarine.estuarine.toolbar.volatile',
|
|
74
|
+
'Show / hide the Volatile line',
|
|
75
|
+
];
|
|
76
|
+
const COUNTERFACTUAL_TOGGLE = [
|
|
77
|
+
'com.labre.cynefin-estuarine.estuarine.toolbar.counterfactual',
|
|
78
|
+
'Show / hide the Counter-factual line',
|
|
79
|
+
];
|
|
80
|
+
const AXIS_LABELS_TOGGLE = [
|
|
81
|
+
'com.labre.cynefin-estuarine.estuarine.toolbar.axis-labels',
|
|
82
|
+
'Show / hide axis labels (e / t)',
|
|
83
|
+
];
|
|
84
|
+
/** Every wording above, for `translations.ts`'s manifest contribution. */
|
|
85
|
+
export const ESTUARINE_TOOLBAR_WORDINGS = [
|
|
86
|
+
LIMINAL_TOGGLE,
|
|
87
|
+
VOLATILE_TOGGLE,
|
|
88
|
+
COUNTERFACTUAL_TOGGLE,
|
|
89
|
+
AXIS_LABELS_TOGGLE,
|
|
90
|
+
];
|
|
67
91
|
function booleanToggle(id, tooltip, icon, prop) {
|
|
68
92
|
return {
|
|
69
93
|
id,
|
|
@@ -93,10 +117,10 @@ function booleanToggle(id, tooltip, icon, prop) {
|
|
|
93
117
|
export const estuarineToolbarConfig = {
|
|
94
118
|
actions: [
|
|
95
119
|
booleanToggle('a.toggle-resize', BOARD_RESIZE_TOGGLE, ResizeIcon, 'resizeEnabled'),
|
|
96
|
-
booleanToggle('b.toggle-liminal',
|
|
97
|
-
booleanToggle('c.toggle-volatile',
|
|
98
|
-
booleanToggle('d.toggle-counterfactual',
|
|
99
|
-
booleanToggle('e.toggle-axis-labels',
|
|
120
|
+
booleanToggle('b.toggle-liminal', LIMINAL_TOGGLE, LiminalIcon, 'showLiminal'),
|
|
121
|
+
booleanToggle('c.toggle-volatile', VOLATILE_TOGGLE, VolatileIcon, 'showVolatile'),
|
|
122
|
+
booleanToggle('d.toggle-counterfactual', COUNTERFACTUAL_TOGGLE, CounterfactualIcon, 'showCounterfactual'),
|
|
123
|
+
booleanToggle('e.toggle-axis-labels', AXIS_LABELS_TOGGLE, AxisIcon, 'showAxisLabels'),
|
|
100
124
|
],
|
|
101
125
|
when: ctx => ctx.getSurfaceModelsByType(EstuarineElementModel).length > 0,
|
|
102
126
|
};
|
|
@@ -1,3 +1,42 @@
|
|
|
1
1
|
import { type TemplateCategory } from '@formicoidea/labre-core/gfx/template';
|
|
2
|
+
import { type ChromeWording } from '@formicoidea/labre-core/shared/services';
|
|
3
|
+
/**
|
|
4
|
+
* The seeds the two hand-composed templates below write into the document:
|
|
5
|
+
* the "Decision sorting" board's four domain stickies, and the "Constraint
|
|
6
|
+
* map" board's three hexagon captions. Exported so `translations.ts` derives
|
|
7
|
+
* the manifest entries from the SAME constants rather than restating them.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CYNEFIN_SEED_PROBE_LEARN: ChromeWording;
|
|
10
|
+
export declare const CYNEFIN_SEED_EXPERT_ANALYSIS: ChromeWording;
|
|
11
|
+
export declare const CYNEFIN_SEED_ACT_NOW: ChromeWording;
|
|
12
|
+
export declare const CYNEFIN_SEED_KNOWN_ISSUE: ChromeWording;
|
|
13
|
+
export declare const ESTUARINE_SEED_POLICY: ChromeWording;
|
|
14
|
+
export declare const ESTUARINE_SEED_HABIT: ChromeWording;
|
|
15
|
+
export declare const ESTUARINE_SEED_BUDGET: ChromeWording;
|
|
16
|
+
/** All seven, for `translations.ts`'s manifest contribution. */
|
|
17
|
+
export declare const CYNEFIN_ESTUARINE_TEMPLATE_SEEDS: readonly ChromeWording[];
|
|
18
|
+
/**
|
|
19
|
+
* The two Templates-panel tab names — new keys, since Cynefin and Estuarine
|
|
20
|
+
* share one senior-button key (`com.labre.framework.cynefin-estuarine`) that
|
|
21
|
+
* names neither individually (see `TemplateCategory.nameKey`). Both are proper
|
|
22
|
+
* nouns; the PO's French proposal for each is the identical word.
|
|
23
|
+
*/
|
|
24
|
+
export declare const CYNEFIN_TEMPLATE_CATEGORY_NAME: ChromeWording;
|
|
25
|
+
export declare const ESTUARINE_TEMPLATE_CATEGORY_NAME: ChromeWording;
|
|
26
|
+
/**
|
|
27
|
+
* The two Templates-panel tab names (chrome, not seeds — a widget-resolved
|
|
28
|
+
* label, never written into a document), for `translations.ts`'s manifest.
|
|
29
|
+
*/
|
|
30
|
+
export declare const CYNEFIN_ESTUARINE_TEMPLATE_CATEGORY_WORDINGS: readonly ChromeWording[];
|
|
31
|
+
/**
|
|
32
|
+
* The two hand-composed templates' own tile names (`Template.nameKey`):
|
|
33
|
+
* chrome, resolved by the panel widget every time it opens, never written
|
|
34
|
+
* into a document — distinct from {@link CYNEFIN_ESTUARINE_TEMPLATE_SEEDS}
|
|
35
|
+
* above, which the templates WRITE.
|
|
36
|
+
*/
|
|
37
|
+
export declare const CYNEFIN_TEMPLATE_NAME_DECISION_SORTING: ChromeWording;
|
|
38
|
+
export declare const ESTUARINE_TEMPLATE_NAME_CONSTRAINT_MAP: ChromeWording;
|
|
39
|
+
/** Both tile names, for `translations.ts`'s manifest. */
|
|
40
|
+
export declare const CYNEFIN_ESTUARINE_TEMPLATE_NAME_WORDINGS: readonly ChromeWording[];
|
|
2
41
|
export declare const cynefinTemplateCategory: TemplateCategory;
|
|
3
42
|
export declare const estuarineTemplateCategory: TemplateCategory;
|