@formicoidea/labre-framework-wardley 0.35.0 → 0.37.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/dist/export.js CHANGED
@@ -336,6 +336,10 @@ function labelAnchors(node, label) {
336
336
  *
337
337
  * A pipeline HANDLE never claims a label: it sits on the body's top edge, right
338
338
  * under the name the body owns, and would win every pipeline's name from it.
339
+ * A Porter's-forces glyph never claims one either, and for a sharper reason: it
340
+ * HAS no name — its one letter is the shape's own inner text — so any label it
341
+ * matched would be some neighbouring artefact's, taken out of that artefact's
342
+ * mouth and then thrown away, since a force is not written to the file at all.
339
343
  */
340
344
  function matchLabels(nodes, labels) {
341
345
  const pairs = [];
@@ -343,8 +347,15 @@ function matchLabels(nodes, labels) {
343
347
  // A handle sits on the pipeline body's top edge, directly under the name
344
348
  // the BODY owns, and would win it from the body every time. A roleless node
345
349
  // is a glyph's own wiring (a market's three inner dots) and names nothing.
346
- if (node.kind === 'handle' || node.role === undefined)
350
+ // An AREA claims none either, and it is the one that would do real damage:
351
+ // a zone is drawn around the components it groups, so its box sits next to
352
+ // every label on the map and would win one from the artefact it belongs to.
353
+ if (node.kind === 'handle' ||
354
+ node.kind === 'porter' ||
355
+ node.kind === 'area' ||
356
+ node.role === undefined) {
347
357
  return;
358
+ }
348
359
  const nodeBox = boxOf(node);
349
360
  labels.forEach((label, labelIndex) => {
350
361
  const labelBox = boxOf(label);
@@ -380,7 +391,17 @@ export function textOf(element) {
380
391
  * method is the `(build)` / `(buy)` / `(outsource)` decorator on a component
381
392
  * line — so a Labre method node is written as a component and the export warns
382
393
  * that the method itself could not be said. `pipeline` and `handle` are absent
383
- * because a pipeline is written from its BODY, in its own section.
394
+ * because a pipeline is written from its BODY, in its own section — and
395
+ * `porter` because OWM has no word for an external competition force at all —
396
+ * and `area` for the same silence, since the format has no word for a zone of
397
+ * the map either. The node loop skips both before this table is consulted, so a
398
+ * kind's absence here is never the reason it is left out.
399
+ *
400
+ * The climate annotations DO have a word, and OWM's own spelling of the second
401
+ * one is `deaccelerator` — not a typo on this side but the keyword the
402
+ * reference parser claims, so writing `decelerator` would produce a line no
403
+ * other Wardley tool reads. Both are written like a component line, `keyword
404
+ * name [visibility, evolution]`, which is exactly what they are in that format.
384
405
  */
385
406
  const OWM_KEYWORD_OF_KIND = {
386
407
  component: 'component',
@@ -388,6 +409,8 @@ const OWM_KEYWORD_OF_KIND = {
388
409
  market: 'market',
389
410
  ecosystem: 'ecosystem',
390
411
  method: 'component',
412
+ accelerator: 'accelerator',
413
+ decelerator: 'deaccelerator',
391
414
  };
392
415
  /** What one element carried from the file it came out of, if anything. */
393
416
  function carriedOf(element) {
@@ -506,11 +529,30 @@ export function exportWardleyOwmWithWarnings(board, options = {}) {
506
529
  const nodeLines = [];
507
530
  const pipelineLines = [];
508
531
  const methodNodes = [];
532
+ const porterNodes = [];
533
+ const areaNodes = [];
509
534
  for (const node of board.nodes) {
510
535
  if (node.role === undefined)
511
536
  continue; // a glyph's own wiring, not an artefact
512
537
  if (node.kind === 'handle')
513
538
  continue;
539
+ // Skipped BEFORE `nameOf`, and that is the whole reason it is a branch of
540
+ // its own rather than a missing entry in `OWM_KEYWORD_OF_KIND`: a force
541
+ // carries no name, so asking for one would christen it "Component 3" and
542
+ // count it among the artefacts that lost theirs — a warning about a loss
543
+ // that never happened, on a line the file does not contain.
544
+ if (node.kind === 'porter') {
545
+ porterNodes.push(node.id);
546
+ continue;
547
+ }
548
+ // Same branch, same reason: an area's name is its own inner text rather
549
+ // than a label beside it, so `nameOf` would find none and christen the zone
550
+ // "Component 4" — counting a nameless artefact among the ones that lost
551
+ // their name, on a line the file does not contain either way.
552
+ if (node.kind === 'area') {
553
+ areaNodes.push(node.id);
554
+ continue;
555
+ }
514
556
  if (twins.has(node.id))
515
557
  continue; // written by its `evolve` line
516
558
  const name = nameOf(node);
@@ -597,6 +639,12 @@ export function exportWardleyOwmWithWarnings(board, options = {}) {
597
639
  if (methodNodes.length > 0) {
598
640
  warnings.push(`${methodNodes.length} component${methodNodes.length === 1 ? ' carries' : 's carry'} a method (build / buy / outsource). OWM writes a method as a decorator this export cannot tell apart, so ${methodNodes.length === 1 ? 'it was' : 'they were'} written as plain components.`);
599
641
  }
642
+ if (porterNodes.length > 0) {
643
+ warnings.push(`${porterNodes.length} Porter's forces glyph${porterNodes.length === 1 ? '' : 's'} could not be written: OWM has no word for an external competition force, so ${porterNodes.length === 1 ? 'it was' : 'they were'} left out.`);
644
+ }
645
+ if (areaNodes.length > 0) {
646
+ warnings.push(`${areaNodes.length} area${areaNodes.length === 1 ? '' : 's'} could not be written: OWM has no word for a zone of the map, so ${areaNodes.length === 1 ? 'it was' : 'they were'} left out.`);
647
+ }
600
648
  if (looseLinks.length > 0) {
601
649
  warnings.push(`${looseLinks.length} link${looseLinks.length === 1 ? ' has an end' : 's have ends'} that is loose or attached to something that is not a Wardley artefact. A link names two components, so ${looseLinks.length === 1 ? 'it was' : 'they were'} left out.`);
602
650
  }
package/dist/import.d.ts CHANGED
@@ -44,10 +44,11 @@ import { OWM_SCOPE, WARDLEY_OWM_FORMAT_ID } from './export.js';
44
44
  * ## Three states, and the middle one is where the file survives
45
45
  *
46
46
  * **Mapped** is what the pack draws: `component`, `anchor`, `market`,
47
- * `ecosystem`, `pipeline`, `note`, `evolve`, `title`, and the `->` links.
47
+ * `ecosystem`, `accelerator`, `deaccelerator`, `pipeline`, `note`, `evolve`,
48
+ * `title`, and the `->` links.
48
49
  * **Carried** is every other statement — `style`, `annotation`, `attitudes`
49
50
  * (`pioneers` / `settlers` / `townplanners`), `submap`, `url`, `size`,
50
- * `accelerator`, the axis-label overrides, the flow links (`+>`, `+<`, `+<>`,
51
+ * the axis-label overrides, the flow links (`+>`, `+<`, `+<>`,
51
52
  * `+'…'>`), a link carrying a `;` context, and every `//` comment — kept
52
53
  * verbatim in `interchange.owm.children['@document']` on the map's background
53
54
  * element (D6) and written back, in order, at the end of the next export.
@@ -67,6 +68,7 @@ import { OWM_SCOPE, WARDLEY_OWM_FORMAT_ID } from './export.js';
67
68
  * | what | state | after a round trip |
68
69
  * | ---------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------- |
69
70
  * | `component` / `anchor` / `market` / `ecosystem` and their coordinates | mapped | drawn, and written back from the drawing, to two decimals |
71
+ * | `accelerator` / `deaccelerator` and their coordinates | mapped | drawn as the climate arrow, and written back under OWM's own spelling (`deaccelerator` for a decelerator) |
70
72
  * | the NAME, which in this format is the identity | mapped | given back verbatim, quoted exactly as it needs to be — the fixed point |
71
73
  * | `pipeline Name [m1, m2]` | mapped | drawn as the body + handle composite; `[m1, m2]` written back from the body's two edges |
72
74
  * | `note Text [v, e]` | mapped | a free text on the map, written back from its centre |
@@ -74,7 +76,7 @@ import { OWM_SCOPE, WARDLEY_OWM_FORMAT_ID } from './export.js';
74
76
  * | `A->B` links | mapped | a `wardley:dependency` connector, consumer → what it needs, never inverted |
75
77
  * | `title` | mapped | consumed as the board's own name; written back from the board's name (see the two rows below) |
76
78
  * | a mapped line's TAIL — `label [x, y]`, `(build)`, `inertia`, comments | carried | invisible on the canvas, re-appended to the very line it came off |
77
- * | `style`, `annotation(s)`, `attitudes`, `submap`, `url`, `size`, `accelerator`, the axis-label overrides | carried | invisible on the canvas, re-emitted verbatim at the end of the file |
79
+ * | `style`, `annotation(s)`, `attitudes`, `submap`, `url`, `size`, the axis-label overrides | carried | invisible on the canvas, re-emitted verbatim at the end of the file |
78
80
  * | flow links (`+>`, `+<`, `+<>`, `+'…'>`) and a link with a `;` context | carried | not drawn — a flow is not a dependency — and re-emitted verbatim |
79
81
  * | a `pipeline` with a `{ … }` body | carried | the block is kept whole and written back whole; the pack draws no pipeline children |
80
82
  * | `//` comments | carried | re-emitted verbatim, at the end |
package/dist/import.js CHANGED
@@ -1,7 +1,8 @@
1
- import { ConnectorMode, FontFamily, PointStyle, ShapeStyle, StrokeStyle, TextAlign, } from '@formicoidea/labre-core/model';
1
+ import { ConnectorMode, FontFamily, FontWeight, PointStyle, ShapeStyle, StrokeStyle, TextAlign, } from '@formicoidea/labre-core/model';
2
2
  import { WARDLEY_BACKGROUND } from './background.js';
3
3
  import { OWM_DEFAULT_MAP_HEIGHT, OWM_DEFAULT_MAP_WIDTH, OWM_LABEL_HEIGHT, OWM_LABEL_WIDTH, OWM_SCOPE, OWM_TAIL_ATTR, OWM_KEYWORDS, OWM_TITLE_ATTR, owmDefaultPlot, owmPointOf, WARDLEY_OWM_FORMAT_ID, } from './export.js';
4
4
  import { HANDLE_SIZE, LABEL_GAP, LABEL_FONT_SIZE, LINK_GREY, LINK_STROKE_WIDTH, MARKET_DOT_RING, MARKET_DOT_SIZE, MARKET_DOT_STROKE_WIDTH, MARKET_LINK_COLOR, MARKET_LINK_WIDTH, MARKET_SIZE, ECOSYSTEM_SIZE, NODE_FILL, NODE_SIZE, NODE_STROKE, NODE_STROKE_WIDTH, PIPELINE_FILL, PIPELINE_HEIGHT, WARDLEY_RED, } from './node/consts.js';
5
+ import { WARDLEY_NODE_SIZE, wardleyNodeProps } from './presets.js';
5
6
  import { WARDLEY_ROLE } from './roles.js';
6
7
  /**
7
8
  * An OnlineWardleyMaps (OWM) DSL document, read as a Wardley map — the inverse
@@ -47,10 +48,11 @@ import { WARDLEY_ROLE } from './roles.js';
47
48
  * ## Three states, and the middle one is where the file survives
48
49
  *
49
50
  * **Mapped** is what the pack draws: `component`, `anchor`, `market`,
50
- * `ecosystem`, `pipeline`, `note`, `evolve`, `title`, and the `->` links.
51
+ * `ecosystem`, `accelerator`, `deaccelerator`, `pipeline`, `note`, `evolve`,
52
+ * `title`, and the `->` links.
51
53
  * **Carried** is every other statement — `style`, `annotation`, `attitudes`
52
54
  * (`pioneers` / `settlers` / `townplanners`), `submap`, `url`, `size`,
53
- * `accelerator`, the axis-label overrides, the flow links (`+>`, `+<`, `+<>`,
55
+ * the axis-label overrides, the flow links (`+>`, `+<`, `+<>`,
54
56
  * `+'…'>`), a link carrying a `;` context, and every `//` comment — kept
55
57
  * verbatim in `interchange.owm.children['@document']` on the map's background
56
58
  * element (D6) and written back, in order, at the end of the next export.
@@ -70,6 +72,7 @@ import { WARDLEY_ROLE } from './roles.js';
70
72
  * | what | state | after a round trip |
71
73
  * | ---------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------- |
72
74
  * | `component` / `anchor` / `market` / `ecosystem` and their coordinates | mapped | drawn, and written back from the drawing, to two decimals |
75
+ * | `accelerator` / `deaccelerator` and their coordinates | mapped | drawn as the climate arrow, and written back under OWM's own spelling (`deaccelerator` for a decelerator) |
73
76
  * | the NAME, which in this format is the identity | mapped | given back verbatim, quoted exactly as it needs to be — the fixed point |
74
77
  * | `pipeline Name [m1, m2]` | mapped | drawn as the body + handle composite; `[m1, m2]` written back from the body's two edges |
75
78
  * | `note Text [v, e]` | mapped | a free text on the map, written back from its centre |
@@ -77,7 +80,7 @@ import { WARDLEY_ROLE } from './roles.js';
77
80
  * | `A->B` links | mapped | a `wardley:dependency` connector, consumer → what it needs, never inverted |
78
81
  * | `title` | mapped | consumed as the board's own name; written back from the board's name (see the two rows below) |
79
82
  * | a mapped line's TAIL — `label [x, y]`, `(build)`, `inertia`, comments | carried | invisible on the canvas, re-appended to the very line it came off |
80
- * | `style`, `annotation(s)`, `attitudes`, `submap`, `url`, `size`, `accelerator`, the axis-label overrides | carried | invisible on the canvas, re-emitted verbatim at the end of the file |
83
+ * | `style`, `annotation(s)`, `attitudes`, `submap`, `url`, `size`, the axis-label overrides | carried | invisible on the canvas, re-emitted verbatim at the end of the file |
81
84
  * | flow links (`+>`, `+<`, `+<>`, `+'…'>`) and a link with a `;` context | carried | not drawn — a flow is not a dependency — and re-emitted verbatim |
82
85
  * | a `pipeline` with a `{ … }` body | carried | the block is kept whole and written back whole; the pack draws no pipeline children |
83
86
  * | `//` comments | carried | re-emitted verbatim, at the end |
@@ -217,12 +220,21 @@ const MATURITY = String.raw `[0-9]*\.[0-9]+`;
217
220
  const BEFORE_MATURITY = new RegExp(String.raw `^(.*?)(\s+${MATURITY})(\s.*)?$`);
218
221
  const LEADING_MATURITY = new RegExp(String.raw `^\s*(${MATURITY})`);
219
222
  /* ── The statements a document is made of ─────────────────────────────── */
220
- /** The keywords that declare a positioned artefact, and the kind each is. */
223
+ /**
224
+ * The keywords that declare a positioned artefact, and the kind each is.
225
+ *
226
+ * `deaccelerator` is OWM's own spelling of a decelerator — the keyword the
227
+ * reference parser claims — so the KEY is the format's word and the VALUE is
228
+ * this canvas's kind. It is the one row where the two differ, and the reason
229
+ * this is a table rather than an identity.
230
+ */
221
231
  const NODE_KEYWORDS = {
222
232
  component: 'component',
223
233
  anchor: 'anchor',
224
234
  market: 'market',
225
235
  ecosystem: 'ecosystem',
236
+ accelerator: 'accelerator',
237
+ deaccelerator: 'decelerator',
226
238
  };
227
239
  /* ── The reader ───────────────────────────────────────────────────────── */
228
240
  /**
@@ -724,7 +736,12 @@ function payload(parts) {
724
736
  return { [WARDLEY_OWM_FORMAT_ID]: carried };
725
737
  }
726
738
  /** A name, as the free text element this canvas writes one as. */
727
- function label(text, x, y, textAlign, color = NODE_STROKE) {
739
+ function label(text, x, y, textAlign, color = NODE_STROKE,
740
+ // Regular by default, because that is what a value-chain name is. The one
741
+ // caller that passes anything else is the climate arrow below, and it does so
742
+ // for the reason `createWardleyAccelerator` does: an imported map and a drawn
743
+ // one must be the same document, down to the weight of the words.
744
+ fontWeight = FontWeight.Regular) {
728
745
  return {
729
746
  type: 'text',
730
747
  text,
@@ -734,12 +751,40 @@ function label(text, x, y, textAlign, color = NODE_STROKE) {
734
751
  color,
735
752
  fontFamily: FontFamily.Inter,
736
753
  fontSize: LABEL_FONT_SIZE,
754
+ fontWeight,
737
755
  textAlign,
738
756
  xywh: `[${x},${y},${OWM_LABEL_WIDTH},${OWM_LABEL_HEIGHT}]`,
739
757
  };
740
758
  }
741
759
  /** The circle (or composite) one positioned statement draws, plus its name. */
742
760
  function artefact(keyword, name, cx, cy, tail, mintHandle) {
761
+ // The two climate annotations are the only statements this reader draws as
762
+ // something other than a circle: a fat polygon, at the canonical size the
763
+ // palette gives one, with its name on the side its shaft is on. The presets
764
+ // own both facts, so a map that arrives from a file and one drawn by hand are
765
+ // the same element.
766
+ const kind = NODE_KEYWORDS[keyword];
767
+ if (kind === 'accelerator' || kind === 'decelerator') {
768
+ const { w, h } = WARDLEY_NODE_SIZE[kind];
769
+ const arrow = {
770
+ ...wardleyNodeProps(kind, {
771
+ xywh: `[${cx - w / 2},${cy - h / 2},${w},${h}]`,
772
+ }),
773
+ interchange: payload({ id: name, tail }),
774
+ };
775
+ const rightwards = kind === 'accelerator';
776
+ return [
777
+ arrow,
778
+ label(name, rightwards
779
+ ? cx + w / 2 + LABEL_GAP
780
+ : cx - w / 2 - LABEL_GAP - OWM_LABEL_WIDTH, cy - OWM_LABEL_HEIGHT / 2, rightwards ? TextAlign.Left : TextAlign.Right, NODE_STROKE,
781
+ // SemiBold, exactly as the sub-menu draws one. The recette of #212
782
+ // caught the two paths disagreeing: a climate arrow is an annotation
783
+ // laid over a map already full of names, and where it came from is not
784
+ // something the reader should be able to see.
785
+ FontWeight.SemiBold),
786
+ ];
787
+ }
743
788
  const diameter = keyword === 'anchor'
744
789
  ? OWM_ANCHOR_SIZE
745
790
  : keyword === 'market'
@@ -749,8 +794,8 @@ function artefact(keyword, name, cx, cy, tail, mintHandle) {
749
794
  : NODE_SIZE;
750
795
  const circle = {
751
796
  type: 'wardleyNode',
752
- kind: NODE_KEYWORDS[keyword],
753
- role: WARDLEY_ROLE[NODE_KEYWORDS[keyword]],
797
+ kind,
798
+ role: WARDLEY_ROLE[kind],
754
799
  shapeType: 'ellipse',
755
800
  filled: true,
756
801
  fillColor: NODE_FILL,
package/dist/index.d.ts CHANGED
@@ -2,12 +2,13 @@ export { WARDLEY_ROLE, WARDLEY_ROLES, type WardleyRole, type WardleyRoleId, } fr
2
2
  export { WARDLEY_AUDIT_CRITERIA } from './audit-criteria.js';
3
3
  export { wardleyCommandIcons, wardleyCommands } from './commands.js';
4
4
  export { wardleyTranslationEntries } from './translations.js';
5
- export { WARDLEY_NATURE, WARDLEY_NATURE_TAG_ID, WARDLEY_TAG_DEFS, } from './natures.js';
5
+ export { WARDLEY_COMPETITION, WARDLEY_COMPETITION_TAG_ID, WARDLEY_NATURE, WARDLEY_NATURE_TAG_ID, WARDLEY_TAG_DEFS, } from './natures.js';
6
+ export { competitionOfPorterLetter, porterLetterOfCompetition, type WardleyPorterLetter, } from './porter-competition.js';
6
7
  export { WARDLEY_PROFILES } from './profiles.js';
7
8
  export { WARDLEY_NUDGES } from './nudges.js';
8
9
  export { WARDLEY_NAMING_CONVENTIONS, WARDLEY_READING } from './reading.js';
9
10
  export { WARDLEY_RULES } from './rules.js';
10
- export { type WardleyArtefactKind, wardleyCanonicalBox, wardleyCenteredBox, wardleyHandleBox, wardleyHandleProps, wardleyMarketDotBoxes, wardleyMarketDotProps, wardleyMarketLinkPairs, wardleyMarketLinkProps, WARDLEY_NODE_LABEL, WARDLEY_NODE_SIZE, wardleyMorphClears, wardleyMorphProps, wardleyNodeProps, } from './presets.js';
11
+ export { WARDLEY_AREA_SIZE, wardleyAreaBox, wardleyAreaProps, type WardleyAreaShape, type WardleyArtefactKind, wardleyCanonicalBox, wardleyCenteredBox, wardleyHandleBox, wardleyHandleProps, wardleyMarketDotBoxes, wardleyMarketDotProps, wardleyMarketLinkPairs, wardleyMarketLinkProps, WARDLEY_NODE_LABEL, WARDLEY_NODE_SIZE, type WardleyLabelledKind, WARDLEY_MORPHABLE_KINDS, wardleyMorphClears, wardleyMorphProps, wardleyNodeProps, type WardleyPorterArrow, wardleyPorterArrowProps, wardleyPorterArrows, wardleyPorterLetterProps, } from './presets.js';
11
12
  export { WARDLEY_MORPH_FAMILIES, WARDLEY_MORPH_SPEC, type WardleyMorphKind, wardleyMorphComposite, wardleyMorphedLabel, wardleyNodeOfComponent, } from './morph.js';
12
13
  /**
13
14
  * The map's own frame, declared. Public because a host that lays elements out
package/dist/index.js CHANGED
@@ -2,7 +2,12 @@ export { WARDLEY_ROLE, WARDLEY_ROLES, } from './roles.js';
2
2
  export { WARDLEY_AUDIT_CRITERIA } from './audit-criteria.js';
3
3
  export { wardleyCommandIcons, wardleyCommands } from './commands.js';
4
4
  export { wardleyTranslationEntries } from './translations.js';
5
- export { WARDLEY_NATURE, WARDLEY_NATURE_TAG_ID, WARDLEY_TAG_DEFS, } from './natures.js';
5
+ export { WARDLEY_COMPETITION, WARDLEY_COMPETITION_TAG_ID, WARDLEY_NATURE, WARDLEY_NATURE_TAG_ID, WARDLEY_TAG_DEFS, } from './natures.js';
6
+ // The letter and the tag, related in both directions. Exported for the reason
7
+ // the presets are: a host laying out or reading a map without an editor —
8
+ // labre-mcp does — must be able to say which force a glyph marks without
9
+ // re-deriving the mapping from the three labels.
10
+ export { competitionOfPorterLetter, porterLetterOfCompetition, } from './porter-competition.js';
6
11
  export { WARDLEY_PROFILES } from './profiles.js';
7
12
  export { WARDLEY_NUDGES } from './nudges.js';
8
13
  export { WARDLEY_NAMING_CONVENTIONS, WARDLEY_READING } from './reading.js';
@@ -11,7 +16,7 @@ export { WARDLEY_RULES } from './rules.js';
11
16
  // morph — by the toolbar that says one artefact differently, so the two can
12
17
  // never disagree about what a market looks like. The sizes are the notation
13
18
  // itself, which is why a host laying out a map without an editor needs them.
14
- export { wardleyCanonicalBox, wardleyCenteredBox, wardleyHandleBox, wardleyHandleProps, wardleyMarketDotBoxes, wardleyMarketDotProps, wardleyMarketLinkPairs, wardleyMarketLinkProps, WARDLEY_NODE_LABEL, WARDLEY_NODE_SIZE, wardleyMorphClears, wardleyMorphProps, wardleyNodeProps, } from './presets.js';
19
+ export { WARDLEY_AREA_SIZE, wardleyAreaBox, wardleyAreaProps, wardleyCanonicalBox, wardleyCenteredBox, wardleyHandleBox, wardleyHandleProps, wardleyMarketDotBoxes, wardleyMarketDotProps, wardleyMarketLinkPairs, wardleyMarketLinkProps, WARDLEY_NODE_LABEL, WARDLEY_NODE_SIZE, WARDLEY_MORPHABLE_KINDS, wardleyMorphClears, wardleyMorphProps, wardleyNodeProps, wardleyPorterArrowProps, wardleyPorterArrows, wardleyPorterLetterProps, } from './presets.js';
15
20
  // What an artefact may BECOME: the declared family, the spec the generic morph
16
21
  // module is registered with, the resolution from a selected group to the node
17
22
  // inside it, and the two rules a composite morph owes its own parts. Data a
package/dist/legend.d.ts CHANGED
@@ -1,11 +1,37 @@
1
1
  import { type WardleyBackgroundElementModel } from '@formicoidea/labre-core/model';
2
2
  import type { BlockStdScope } from '@formicoidea/labre-core/std';
3
+ /** A box in the panel, relative to the panel's top-left, plus its words. */
4
+ interface PorterPanelBox {
5
+ xywh: [number, number, number, number];
6
+ label: string;
7
+ }
8
+ interface PorterPanelLayout {
9
+ w: number;
10
+ h: number;
11
+ title: [number, number, number, number];
12
+ /** The glyph's centre. */
13
+ center: [number, number];
14
+ radius: number;
15
+ boxes: PorterPanelBox[];
16
+ caption: [number, number, number, number];
17
+ }
18
+ /**
19
+ * The panel's geometry for a given width — the PO's reference drawing, as
20
+ * numbers.
21
+ *
22
+ * A pure function so the layout can be asserted without a surface, and so the
23
+ * one thing that must hold — that none of the four boxes overlaps the glyph
24
+ * they surround — is checkable rather than eyeballed.
25
+ */
26
+ export declare function porterPanelLayout(w: number): PorterPanelLayout;
3
27
  /**
4
28
  * Build a "Legend" group from real, editable elements (white rect frame +
5
29
  * "Legend" text + one row of [real component glyph + description text] per
6
30
  * Wardley component TYPE present inside the background's perimeter + a
7
- * gradient-meaning block when the background is a gradient variant). A snapshot
31
+ * gradient-meaning block when the background is a gradient variant + the
32
+ * five-forces panel when a Porter's-forces glyph is on the map). A snapshot
8
33
  * is created on each call; everything is grouped so it can be moved / resized /
9
34
  * edited and is dropped bottom-left of the background.
10
35
  */
11
36
  export declare function createWardleyLegend(std: BlockStdScope, bg: WardleyBackgroundElementModel): void;
37
+ export {};