@oicl/openbridge-webcomponents 2.0.0-next.101 → 2.0.0-next.103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +580 -143
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +629 -407
  4. package/dist/bars-graphs/donut-chart/donut-chart.d.ts +18 -16
  5. package/dist/bars-graphs/donut-chart/donut-chart.d.ts.map +1 -1
  6. package/dist/bars-graphs/donut-chart/donut-chart.js.map +1 -1
  7. package/dist/bars-graphs/pie-chart/pie-chart.d.ts +14 -12
  8. package/dist/bars-graphs/pie-chart/pie-chart.d.ts.map +1 -1
  9. package/dist/bars-graphs/pie-chart/pie-chart.js.map +1 -1
  10. package/dist/bars-graphs/polar-chart/polar-chart.d.ts +19 -16
  11. package/dist/bars-graphs/polar-chart/polar-chart.d.ts.map +1 -1
  12. package/dist/bars-graphs/polar-chart/polar-chart.js.map +1 -1
  13. package/dist/bars-graphs/radial-bar-chart/radial-bar-chart.d.ts +8 -8
  14. package/dist/bars-graphs/radial-bar-chart/radial-bar-chart.d.ts.map +1 -1
  15. package/dist/bars-graphs/radial-bar-chart/radial-bar-chart.js.map +1 -1
  16. package/dist/building-blocks/chart-line/chart-line-base.d.ts +8 -25
  17. package/dist/building-blocks/chart-line/chart-line-base.d.ts.map +1 -1
  18. package/dist/building-blocks/chart-line/chart-line-base.js.map +1 -1
  19. package/dist/building-blocks/instrument-radial/instrument-radial.d.ts +22 -2
  20. package/dist/building-blocks/instrument-radial/instrument-radial.d.ts.map +1 -1
  21. package/dist/building-blocks/instrument-radial/instrument-radial.js +61 -37
  22. package/dist/building-blocks/instrument-radial/instrument-radial.js.map +1 -1
  23. package/dist/integration-systems/integration-bar/integration-bar.d.ts +20 -24
  24. package/dist/integration-systems/integration-bar/integration-bar.d.ts.map +1 -1
  25. package/dist/integration-systems/integration-bar/integration-bar.js.map +1 -1
  26. package/dist/integration-systems/integration-button/integration-button.d.ts +15 -13
  27. package/dist/integration-systems/integration-button/integration-button.d.ts.map +1 -1
  28. package/dist/integration-systems/integration-button/integration-button.js.map +1 -1
  29. package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.d.ts +14 -0
  30. package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.d.ts.map +1 -1
  31. package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.js +30 -11
  32. package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.js.map +1 -1
  33. package/dist/navigation-instruments/compass/compass.d.ts +68 -31
  34. package/dist/navigation-instruments/compass/compass.d.ts.map +1 -1
  35. package/dist/navigation-instruments/compass/compass.js +36 -16
  36. package/dist/navigation-instruments/compass/compass.js.map +1 -1
  37. package/dist/navigation-instruments/compass-flat/compass-flat.d.ts +8 -9
  38. package/dist/navigation-instruments/compass-flat/compass-flat.d.ts.map +1 -1
  39. package/dist/navigation-instruments/compass-flat/compass-flat.js.map +1 -1
  40. package/dist/navigation-instruments/compass-sector/compass-sector.d.ts.map +1 -1
  41. package/dist/navigation-instruments/compass-sector/compass-sector.js.map +1 -1
  42. package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js +34 -2
  43. package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js.map +1 -1
  44. package/dist/navigation-instruments/gauge-radial/gauge-radial.d.ts +15 -0
  45. package/dist/navigation-instruments/gauge-radial/gauge-radial.d.ts.map +1 -1
  46. package/dist/navigation-instruments/gauge-radial/gauge-radial.js +35 -1
  47. package/dist/navigation-instruments/gauge-radial/gauge-radial.js.map +1 -1
  48. package/dist/navigation-instruments/gauge-trend/gauge-trend.d.ts +0 -5
  49. package/dist/navigation-instruments/gauge-trend/gauge-trend.d.ts.map +1 -1
  50. package/dist/navigation-instruments/gauge-trend/gauge-trend.js.map +1 -1
  51. package/dist/navigation-instruments/graph-mini/graph-mini.d.ts +1 -1
  52. package/dist/navigation-instruments/graph-mini/graph-mini.d.ts.map +1 -1
  53. package/dist/navigation-instruments/graph-mini/graph-mini.js.map +1 -1
  54. package/dist/navigation-instruments/heading/heading.d.ts +19 -1
  55. package/dist/navigation-instruments/heading/heading.d.ts.map +1 -1
  56. package/dist/navigation-instruments/heading/heading.js +34 -16
  57. package/dist/navigation-instruments/heading/heading.js.map +1 -1
  58. package/dist/navigation-instruments/indicator-graph/indicator-graph.d.ts +1 -1
  59. package/dist/navigation-instruments/indicator-graph/indicator-graph.d.ts.map +1 -1
  60. package/dist/navigation-instruments/indicator-graph/indicator-graph.js.map +1 -1
  61. package/dist/navigation-instruments/rudder/rudder.d.ts +15 -2
  62. package/dist/navigation-instruments/rudder/rudder.d.ts.map +1 -1
  63. package/dist/navigation-instruments/rudder/rudder.js +36 -26
  64. package/dist/navigation-instruments/rudder/rudder.js.map +1 -1
  65. package/dist/navigation-instruments/speed-gauge/speed-gauge.d.ts +15 -1
  66. package/dist/navigation-instruments/speed-gauge/speed-gauge.d.ts.map +1 -1
  67. package/dist/navigation-instruments/speed-gauge/speed-gauge.js +31 -3
  68. package/dist/navigation-instruments/speed-gauge/speed-gauge.js.map +1 -1
  69. package/dist/navigation-instruments/watch/watch.d.ts +45 -17
  70. package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
  71. package/dist/navigation-instruments/watch/watch.js +53 -38
  72. package/dist/navigation-instruments/watch/watch.js.map +1 -1
  73. package/dist/svghelpers/radial-frame.d.ts +122 -0
  74. package/dist/svghelpers/radial-frame.d.ts.map +1 -0
  75. package/dist/svghelpers/radial-frame.js +259 -0
  76. package/dist/svghelpers/radial-frame.js.map +1 -0
  77. package/package.json +1 -1
@@ -0,0 +1,122 @@
1
+ import { WatchArea } from '../navigation-instruments/watch/watch.js';
2
+ import { ZoomToFitArcFrame } from './arc-frame.js';
3
+ /** Approximate digit advance at 12px font-instrument-label. */
4
+ export declare const DIGIT_WIDTH_PX = 7;
5
+ /** Compass NSWE label width assumed by label.ts (`labelWidth = 16`). */
6
+ export declare const NSWE_LABEL_WIDTH_PX = 16;
7
+ /**
8
+ * North-arrow glyph allowance for outside-decor reserves (px). The arrow
9
+ * renders regardless of `showLabels`, so consumers charge this portion
10
+ * whenever the arrow sits outside the ring.
11
+ */
12
+ export declare const NORTH_ARROW_WIDTH_PX = 16;
13
+ /**
14
+ * Labels are dropped (not clipped) when their reserve would exceed this share
15
+ * of the box. 0.45 makes a 4-digit gauge hide labels below a ~182px container
16
+ * — near the canvas charts' fixed MIN_HEIGHT_WITH_LABELS = 192px threshold —
17
+ * while 2-digit labels survive down to ~120px. Designers may later prefer a
18
+ * fixed pixel threshold instead (see charthelpers/constants.ts).
19
+ */
20
+ export declare const LABEL_RESERVE_MAX_FRACTION = 0.45;
21
+ /**
22
+ * Pixel drop of "Max-min" end labels (`endLabelsMaxMin`) below the ±90° line:
23
+ * anchored at `12px/scale` with `dominant-baseline: central` (tickmark.ts),
24
+ * so the glyph bottom reaches ~12 + 6 + descender ≈ 20px — plus 1px pad.
25
+ */
26
+ export declare const END_MAXMIN_LABEL_DROP_PX = 21;
27
+ /**
28
+ * Pixel drop of regular side labels at the ±90° ends: glyph centered on the
29
+ * line (half-height ~6px + descender), plus pad.
30
+ */
31
+ export declare const SIDE_LABEL_DROP_PX = 13;
32
+ /** Per-edge viewBox crops in percent (0–100), matching obc-watch `clip*`. */
33
+ export interface RadialClips {
34
+ top: number;
35
+ bottom: number;
36
+ left: number;
37
+ right: number;
38
+ }
39
+ export interface RadialFrameOptions {
40
+ /** Legacy padding: the frame never shrinks below `(176 + basePadding) * 2`. */
41
+ basePadding: number;
42
+ /** Max label pixel width at 12px font; 0/undefined = no outside labels. */
43
+ labelWidthPx?: number;
44
+ /** Un-zoomed viewBox crops; ignored when `zoomToFitArc` is set. */
45
+ clips?: RadialClips;
46
+ /**
47
+ * Pixel extent the outside labels need past the ±90° horizontal line
48
+ * toward a top/bottom crop edge (see END_MAXMIN_LABEL_DROP_PX /
49
+ * SIDE_LABEL_DROP_PX). When a `clips.top`/`clips.bottom` crop would cut
50
+ * into that drop, the clip is lowered so the labels stay inside the box.
51
+ * Absent/0 keeps the requested clips untouched (legacy geometry).
52
+ */
53
+ labelDropPx?: number;
54
+ /** Host client box in px; absent or zero ⇒ scale-1 fallback (first paint). */
55
+ containerPx?: {
56
+ width: number;
57
+ height: number;
58
+ };
59
+ /** Outer-ring diameter in px; pins scale for equal circumference (mode b). */
60
+ faceDiameter?: number;
61
+ zoomToFitArc?: boolean;
62
+ /** Visible arc segments; required for the zoom path. */
63
+ areas?: WatchArea[];
64
+ /** Innermost visible radius (depends on WatchCircleType); zoom path only. */
65
+ innerRadius?: number;
66
+ }
67
+ export interface RadialFrame extends ZoomToFitArcFrame {
68
+ /** Px per SVG unit implied by container or faceDiameter (1 when unknown). */
69
+ scale: number;
70
+ /** SVG units added beyond the base geometry for labels (0 when none/hidden). */
71
+ labelReserve: number;
72
+ /** True when the label reserve exceeded the cap; callers strip tick texts. */
73
+ labelsHidden: boolean;
74
+ /**
75
+ * True when `labelDropPx` lowered a top/bottom clip: the box's aspect no
76
+ * longer matches the requested clip fractions, so hosts with an
77
+ * aspect-ratio derived from those fractions must follow the frame instead.
78
+ */
79
+ clipsAdjusted: boolean;
80
+ /** Fixed host size in px; defined only when `faceDiameter` is set. */
81
+ hostWidthPx?: number;
82
+ /** Fixed host size in px; defined only when `faceDiameter` is set. */
83
+ hostHeightPx?: number;
84
+ }
85
+ /**
86
+ * Measure the host's available box in px. Radial instrument hosts render
87
+ * inline by default, so clientWidth/Height are often 0 — fall back to the
88
+ * parent box, like obc-watch's getScale() has always done (issue #1032).
89
+ */
90
+ export declare function measureContainerPx(host: HTMLElement): {
91
+ width: number;
92
+ height: number;
93
+ };
94
+ /**
95
+ * Apply/remove the fixed intrinsic host size a `faceDiameter` frame pins.
96
+ * The hosts render inline by default, so a pinned size also needs
97
+ * `display: block` for width/height to apply. Returns whether the size is
98
+ * currently pinned; pass that back as `wasPinned` on the next call so an
99
+ * unpinned host's own inline styles are never clobbered.
100
+ */
101
+ export declare function applyPinnedHostSize(host: HTMLElement, frame: RadialFrame | undefined, wasPinned: boolean): boolean;
102
+ /**
103
+ * Additionally observe an internal element that always generates a box (the
104
+ * shadow `<svg>` or `.container`). Several radial hosts render inline (no
105
+ * `:host {display}` rule), and ResizeObserver never fires for inline boxes —
106
+ * the host reports a permanent 0×0 size, so a controller observing only the
107
+ * host misses every resize. That freezes the container-dependent frame and
108
+ * the `--scale` font counter-scaling at their first-paint values.
109
+ */
110
+ export declare function observeInnerBox(controller: {
111
+ observe(target: Element): void;
112
+ }, renderRoot: ParentNode): void;
113
+ /**
114
+ * Estimate the widest label's pixel width at the 12px instrument label font.
115
+ */
116
+ export declare function estimateLabelWidthPx(texts: readonly (string | undefined)[]): number;
117
+ /**
118
+ * Compute the viewBox frame for a radial instrument, reserving width-aware
119
+ * room for outside tick labels. See the module documentation for the model.
120
+ */
121
+ export declare function computeRadialFrame(opts: RadialFrameOptions): RadialFrame;
122
+ //# sourceMappingURL=radial-frame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radial-frame.d.ts","sourceRoot":"","sources":["../../src/svghelpers/radial-frame.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0CAA0C,CAAC;AACxE,OAAO,EAA2B,KAAK,iBAAiB,EAAC,MAAM,gBAAgB,CAAC;AA6DhF,+DAA+D;AAC/D,eAAO,MAAM,cAAc,IAAI,CAAC;AAChC,wEAAwE;AACxE,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAC/C;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C;;;GAGG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,WAAW,CAAC,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAC;IAC9C,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wDAAwD;IACxD,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IACpB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAY,SAAQ,iBAAiB;IACpD,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,YAAY,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAWA;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,WAAW,GAAG,SAAS,EAC9B,SAAS,EAAE,OAAO,GACjB,OAAO,CAaT;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE;IAAC,OAAO,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAA;CAAC,EAC5C,UAAU,EAAE,UAAU,GACrB,IAAI,CAKN;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GACrC,MAAM,CAQR;AAoJD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,GAAG,WAAW,CA4DxE"}
@@ -0,0 +1,259 @@
1
+ import { computeZoomToFitArcFrame } from "./arc-frame.js";
2
+ const OUTER_RING_RADIUS = 368 / 2;
3
+ const RADIAL_VIEWBOX_BASE = 176;
4
+ const LABEL_RADIAL_PAD_UNITS = 3;
5
+ const LABEL_ANCHOR_OFFSET_PX = 9;
6
+ const LABEL_EDGE_PAD_PX = 4;
7
+ const DIGIT_WIDTH_PX = 7;
8
+ const NSWE_LABEL_WIDTH_PX = 16;
9
+ const NORTH_ARROW_WIDTH_PX = 16;
10
+ const LABEL_RESERVE_MAX_FRACTION = 0.45;
11
+ const END_MAXMIN_LABEL_DROP_PX = 21;
12
+ const SIDE_LABEL_DROP_PX = 13;
13
+ function measureContainerPx(host) {
14
+ let width = host.clientWidth;
15
+ let height = host.clientHeight;
16
+ if (width === 0 || height === 0) {
17
+ const box = host.parentElement?.getBoundingClientRect();
18
+ if (box) {
19
+ width = box.width;
20
+ height = box.height;
21
+ }
22
+ }
23
+ return { width, height };
24
+ }
25
+ function applyPinnedHostSize(host, frame, wasPinned) {
26
+ if (frame?.hostWidthPx !== void 0 && frame.hostHeightPx !== void 0) {
27
+ host.style.width = `${frame.hostWidthPx}px`;
28
+ host.style.height = `${frame.hostHeightPx}px`;
29
+ host.style.display = "block";
30
+ return true;
31
+ }
32
+ if (wasPinned) {
33
+ host.style.removeProperty("width");
34
+ host.style.removeProperty("height");
35
+ host.style.removeProperty("display");
36
+ }
37
+ return false;
38
+ }
39
+ function observeInnerBox(controller, renderRoot) {
40
+ const box = renderRoot.querySelector("svg, .container");
41
+ if (box) {
42
+ controller.observe(box);
43
+ }
44
+ }
45
+ function estimateLabelWidthPx(texts) {
46
+ let maxChars = 0;
47
+ for (const t of texts) {
48
+ if (t !== void 0 && t.length > maxChars) {
49
+ maxChars = t.length;
50
+ }
51
+ }
52
+ return maxChars * DIGIT_WIDTH_PX;
53
+ }
54
+ function clipFractions(clips) {
55
+ if (!clips) {
56
+ return { fx: 1, fy: 1 };
57
+ }
58
+ const fx = 1 - (clips.left + clips.right) / 100;
59
+ const fy = 1 - (clips.top + clips.bottom) / 100;
60
+ return { fx: fx > 0 ? fx : 1, fy: fy > 0 ? fy : 1 };
61
+ }
62
+ function buildViewBox(side, clips) {
63
+ const { fx, fy } = clipFractions(clips);
64
+ const width = side * fx;
65
+ const height = side * fy;
66
+ const x = -side / 2 + side * (clips?.left ?? 0) / 100;
67
+ const y = -side / 2 + side * (clips?.top ?? 0) / 100;
68
+ return {
69
+ x,
70
+ y,
71
+ width,
72
+ height,
73
+ viewBox: `${x} ${y} ${width} ${height}`,
74
+ radiusOffset: 0
75
+ };
76
+ }
77
+ function pinnedScale(opts) {
78
+ if (opts.faceDiameter === void 0) {
79
+ return void 0;
80
+ }
81
+ const scale = opts.faceDiameter / (2 * OUTER_RING_RADIUS);
82
+ return Number.isFinite(scale) && scale > 0 ? scale : void 0;
83
+ }
84
+ function effectiveContainer(opts, fx, fy) {
85
+ const w = opts.containerPx?.width ?? 0;
86
+ const h = opts.containerPx?.height ?? 0;
87
+ if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {
88
+ return void 0;
89
+ }
90
+ return Math.min(w / fx, h / fy);
91
+ }
92
+ function containerScale(opts, frame) {
93
+ const w = opts.containerPx?.width ?? 0;
94
+ const h = opts.containerPx?.height ?? 0;
95
+ if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {
96
+ return void 0;
97
+ }
98
+ const scale = Math.min(w / frame.width, h / frame.height);
99
+ return Number.isFinite(scale) && scale > 0 ? scale : void 0;
100
+ }
101
+ function withHostPx(frame, pinned, scale, labelReserve, labelsHidden, clipsAdjusted = false) {
102
+ const result = {
103
+ ...frame,
104
+ scale,
105
+ labelReserve,
106
+ labelsHidden,
107
+ clipsAdjusted
108
+ };
109
+ if (pinned) {
110
+ result.hostWidthPx = frame.width * scale;
111
+ result.hostHeightPx = frame.height * scale;
112
+ }
113
+ return result;
114
+ }
115
+ function solveSide(opts, labelCostPx, clips) {
116
+ const baseSide = (RADIAL_VIEWBOX_BASE + opts.basePadding) * 2;
117
+ const { fx, fy } = clipFractions(clips);
118
+ const labelSideAt = (scale) => 2 * (OUTER_RING_RADIUS + LABEL_RADIAL_PAD_UNITS + labelCostPx / scale);
119
+ let side = baseSide;
120
+ let labelsHidden = false;
121
+ if (labelCostPx > 0) {
122
+ const pinned = pinnedScale(opts);
123
+ if (pinned !== void 0) {
124
+ const grown = Math.max(baseSide, labelSideAt(pinned));
125
+ labelsHidden = 2 * (labelCostPx / pinned) / grown > LABEL_RESERVE_MAX_FRACTION;
126
+ side = labelsHidden ? baseSide : grown;
127
+ } else {
128
+ const container = effectiveContainer(opts, fx, fy);
129
+ if (container === void 0) {
130
+ side = Math.max(baseSide, labelSideAt(1));
131
+ } else if (2 * labelCostPx / container > LABEL_RESERVE_MAX_FRACTION) {
132
+ labelsHidden = true;
133
+ } else {
134
+ side = Math.max(
135
+ baseSide,
136
+ 2 * (OUTER_RING_RADIUS + LABEL_RADIAL_PAD_UNITS) / (1 - 2 * labelCostPx / container)
137
+ );
138
+ }
139
+ }
140
+ }
141
+ return { side, labelsHidden };
142
+ }
143
+ function adjustClipsForLabelDrop(clips, side, scale, labelDropPx) {
144
+ const requiredUnits = labelDropPx / scale;
145
+ const requiredClipPct = Math.max(0, (0.5 - requiredUnits / side) * 100);
146
+ const bottom = clips.bottom > requiredClipPct ? requiredClipPct : clips.bottom;
147
+ const top = clips.top > requiredClipPct ? requiredClipPct : clips.top;
148
+ if (bottom === clips.bottom && top === clips.top) {
149
+ return clips;
150
+ }
151
+ return { ...clips, top, bottom };
152
+ }
153
+ function computeRadialFrame(opts) {
154
+ const labelWidthPx = opts.labelWidthPx ?? 0;
155
+ const labelCostPx = labelWidthPx > 0 ? LABEL_ANCHOR_OFFSET_PX + labelWidthPx + LABEL_EDGE_PAD_PX : 0;
156
+ if (opts.zoomToFitArc && opts.areas && opts.areas.length > 0) {
157
+ return computeZoomedFrame(opts, labelCostPx);
158
+ }
159
+ const baseSide = (RADIAL_VIEWBOX_BASE + opts.basePadding) * 2;
160
+ let clips = opts.clips;
161
+ let { side, labelsHidden } = solveSide(opts, labelCostPx, clips);
162
+ const labelDropPx = opts.labelDropPx ?? 0;
163
+ if (labelDropPx > 0 && labelCostPx > 0 && !labelsHidden && clips) {
164
+ for (let i = 0; i < 2; i++) {
165
+ const scale2 = pinnedScale(opts) ?? containerScale(opts, buildViewBox(side, clips)) ?? 1;
166
+ const adjusted = adjustClipsForLabelDrop(
167
+ clips,
168
+ side,
169
+ scale2,
170
+ labelDropPx
171
+ );
172
+ if (adjusted === clips) {
173
+ break;
174
+ }
175
+ clips = adjusted;
176
+ const solved = solveSide(opts, labelCostPx, clips);
177
+ side = solved.side;
178
+ labelsHidden = solved.labelsHidden;
179
+ }
180
+ if (labelsHidden) {
181
+ clips = opts.clips;
182
+ const solved = solveSide(opts, labelCostPx, clips);
183
+ side = solved.side;
184
+ labelsHidden = solved.labelsHidden;
185
+ }
186
+ }
187
+ const frame = buildViewBox(side, clips);
188
+ const pinned = pinnedScale(opts);
189
+ const scale = pinned ?? containerScale(opts, frame) ?? 1;
190
+ return withHostPx(
191
+ frame,
192
+ pinned !== void 0,
193
+ scale,
194
+ (side - baseSide) / 2,
195
+ labelsHidden,
196
+ clips !== opts.clips
197
+ );
198
+ }
199
+ function computeZoomedFrame(opts, labelCostPx) {
200
+ let reserve = 0;
201
+ let labelsHidden = false;
202
+ let frame = zoomFrameAt(opts, opts.basePadding);
203
+ if (labelCostPx > 0) {
204
+ for (let i = 0; i < 2; i++) {
205
+ const passScale = zoomedScale(opts, frame);
206
+ const reserveUnits = labelCostPx / passScale;
207
+ if (2 * reserveUnits / Math.max(frame.width, frame.height) > LABEL_RESERVE_MAX_FRACTION) {
208
+ labelsHidden = true;
209
+ reserve = 0;
210
+ frame = zoomFrameAt(opts, opts.basePadding);
211
+ break;
212
+ }
213
+ reserve = reserveUnits;
214
+ frame = zoomFrameAt(opts, opts.basePadding + reserve);
215
+ }
216
+ }
217
+ const pinned = pinnedZoomedScale(opts, frame);
218
+ const scale = pinned ?? containerScale(opts, frame) ?? 1;
219
+ return withHostPx(
220
+ frame,
221
+ pinned !== void 0,
222
+ scale,
223
+ labelsHidden ? 0 : reserve,
224
+ labelsHidden
225
+ );
226
+ }
227
+ function zoomFrameAt(opts, extension) {
228
+ return computeZoomToFitArcFrame({
229
+ areas: opts.areas,
230
+ outerRadius: OUTER_RING_RADIUS,
231
+ innerRadius: opts.innerRadius ?? OUTER_RING_RADIUS,
232
+ extension,
233
+ targetSize: (RADIAL_VIEWBOX_BASE + extension) * 2
234
+ });
235
+ }
236
+ function pinnedZoomedScale(opts, frame) {
237
+ if (opts.faceDiameter === void 0) {
238
+ return void 0;
239
+ }
240
+ const scale = opts.faceDiameter / (2 * (OUTER_RING_RADIUS + frame.radiusOffset));
241
+ return Number.isFinite(scale) && scale > 0 ? scale : void 0;
242
+ }
243
+ function zoomedScale(opts, frame) {
244
+ return pinnedZoomedScale(opts, frame) ?? containerScale(opts, frame) ?? 1;
245
+ }
246
+ export {
247
+ DIGIT_WIDTH_PX,
248
+ END_MAXMIN_LABEL_DROP_PX,
249
+ LABEL_RESERVE_MAX_FRACTION,
250
+ NORTH_ARROW_WIDTH_PX,
251
+ NSWE_LABEL_WIDTH_PX,
252
+ SIDE_LABEL_DROP_PX,
253
+ applyPinnedHostSize,
254
+ computeRadialFrame,
255
+ estimateLabelWidthPx,
256
+ measureContainerPx,
257
+ observeInnerBox
258
+ };
259
+ //# sourceMappingURL=radial-frame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radial-frame.js","sources":["../../src/svghelpers/radial-frame.ts"],"sourcesContent":["import type {WatchArea} from '../navigation-instruments/watch/watch.js';\nimport {computeZoomToFitArcFrame, type ZoomToFitArcFrame} from './arc-frame.js';\n\n/**\n * Shared frame computation for circular/radial watch-based instruments.\n *\n * Every radial instrument (watch, instrument-radial/gauge-radial, speed-gauge,\n * azimuth-thruster, compass, heading, rudder, pitch/roll, …) needs the same\n * three outputs to render: an SVG viewBox for `<obc-watch>` and its overlay,\n * a zoom radius offset, and — since issue #1021 — enough reserved room around\n * the outer ring that tick labels are not clipped when the instrument shrinks\n * inside a flex container.\n *\n * `computeRadialFrame()` is the single source of truth for that geometry.\n * Consumers call it once per render and pass the resulting frame to\n * `<obc-watch .arcFrame=...>` (which uses it verbatim) and to their own\n * overlay `<svg viewBox=...>`, guaranteeing the two layers stay aligned.\n *\n * ## Label reserve (issue #1021)\n *\n * Tick labels render at `font-size: calc(12px / scale)` so they keep a\n * constant on-screen size while the ring scales. Their footprint in SVG units\n * is therefore `px / scale`, where `scale = containerPx / viewBoxSide` — the\n * smaller the instrument, the more SVG units a label needs. The frame solves\n * the resulting equation in closed form:\n *\n * ```\n * side/2 >= (OUTER_RING_RADIUS + LABEL_RADIAL_PAD_UNITS) + P/scale\n * scale = containerPx / side\n * => side = 2 * (OUTER_RING_RADIUS + LABEL_RADIAL_PAD_UNITS) / (1 - 2P/containerPx)\n * ```\n *\n * where `P` is the label's pixel cost beyond the ring (anchor offsets + text\n * width + edge padding). The viewBox never shrinks below the legacy\n * `(176 + basePadding) * 2` box, so instruments without labels — or with\n * labels that already fit — render byte-identical to the pre-#1021 output.\n *\n * When the reserve would exceed `LABEL_RESERVE_MAX_FRACTION` of the box, the\n * frame reports `labelsHidden: true` and falls back to the base box; callers\n * must then strip tick label texts (graceful degradation instead of clipping,\n * mirroring the canvas charts).\n *\n * ## Equal circumference (`faceDiameter`)\n *\n * When `faceDiameter` (px) is given, the outer-ring diameter is pinned:\n * `scale = faceDiameter / 368`. The frame then reports `hostWidthPx` /\n * `hostHeightPx` so the host element can adopt a fixed intrinsic size, and\n * instruments sharing a `faceDiameter` value have identical ring\n * circumference regardless of label width or arc extent — the SVG counterpart\n * of `obc-donut-chart`'s fixed-height ⇒ fixed-circumference contract.\n */\n\n// Keep in sync with watch.ts OUTER_RING_RADIUS (importing it would be circular).\nconst OUTER_RING_RADIUS = 368 / 2;\n/** Legacy viewBox base: `side = (RADIAL_VIEWBOX_BASE + padding) * 2`. */\nconst RADIAL_VIEWBOX_BASE = 176;\n/** Non-scaled part of the tickmark text radius pad (`3/scale + 3` in tickmark.ts). */\nconst LABEL_RADIAL_PAD_UNITS = 3;\n/** Scaled label anchor offsets in px: `3/scale` textRadius pad + `6/scale` xOffset. */\nconst LABEL_ANCHOR_OFFSET_PX = 9;\n/** Breathing room between the label's far edge and the viewBox edge, in px. */\nconst LABEL_EDGE_PAD_PX = 4;\n/** Approximate digit advance at 12px font-instrument-label. */\nexport const DIGIT_WIDTH_PX = 7;\n/** Compass NSWE label width assumed by label.ts (`labelWidth = 16`). */\nexport const NSWE_LABEL_WIDTH_PX = 16;\n/**\n * North-arrow glyph allowance for outside-decor reserves (px). The arrow\n * renders regardless of `showLabels`, so consumers charge this portion\n * whenever the arrow sits outside the ring.\n */\nexport const NORTH_ARROW_WIDTH_PX = 16;\n/**\n * Labels are dropped (not clipped) when their reserve would exceed this share\n * of the box. 0.45 makes a 4-digit gauge hide labels below a ~182px container\n * — near the canvas charts' fixed MIN_HEIGHT_WITH_LABELS = 192px threshold —\n * while 2-digit labels survive down to ~120px. Designers may later prefer a\n * fixed pixel threshold instead (see charthelpers/constants.ts).\n */\nexport const LABEL_RESERVE_MAX_FRACTION = 0.45;\n/**\n * Pixel drop of \"Max-min\" end labels (`endLabelsMaxMin`) below the ±90° line:\n * anchored at `12px/scale` with `dominant-baseline: central` (tickmark.ts),\n * so the glyph bottom reaches ~12 + 6 + descender ≈ 20px — plus 1px pad.\n */\nexport const END_MAXMIN_LABEL_DROP_PX = 21;\n/**\n * Pixel drop of regular side labels at the ±90° ends: glyph centered on the\n * line (half-height ~6px + descender), plus pad.\n */\nexport const SIDE_LABEL_DROP_PX = 13;\n\n/** Per-edge viewBox crops in percent (0–100), matching obc-watch `clip*`. */\nexport interface RadialClips {\n top: number;\n bottom: number;\n left: number;\n right: number;\n}\n\nexport interface RadialFrameOptions {\n /** Legacy padding: the frame never shrinks below `(176 + basePadding) * 2`. */\n basePadding: number;\n /** Max label pixel width at 12px font; 0/undefined = no outside labels. */\n labelWidthPx?: number;\n /** Un-zoomed viewBox crops; ignored when `zoomToFitArc` is set. */\n clips?: RadialClips;\n /**\n * Pixel extent the outside labels need past the ±90° horizontal line\n * toward a top/bottom crop edge (see END_MAXMIN_LABEL_DROP_PX /\n * SIDE_LABEL_DROP_PX). When a `clips.top`/`clips.bottom` crop would cut\n * into that drop, the clip is lowered so the labels stay inside the box.\n * Absent/0 keeps the requested clips untouched (legacy geometry).\n */\n labelDropPx?: number;\n /** Host client box in px; absent or zero ⇒ scale-1 fallback (first paint). */\n containerPx?: {width: number; height: number};\n /** Outer-ring diameter in px; pins scale for equal circumference (mode b). */\n faceDiameter?: number;\n zoomToFitArc?: boolean;\n /** Visible arc segments; required for the zoom path. */\n areas?: WatchArea[];\n /** Innermost visible radius (depends on WatchCircleType); zoom path only. */\n innerRadius?: number;\n}\n\nexport interface RadialFrame extends ZoomToFitArcFrame {\n /** Px per SVG unit implied by container or faceDiameter (1 when unknown). */\n scale: number;\n /** SVG units added beyond the base geometry for labels (0 when none/hidden). */\n labelReserve: number;\n /** True when the label reserve exceeded the cap; callers strip tick texts. */\n labelsHidden: boolean;\n /**\n * True when `labelDropPx` lowered a top/bottom clip: the box's aspect no\n * longer matches the requested clip fractions, so hosts with an\n * aspect-ratio derived from those fractions must follow the frame instead.\n */\n clipsAdjusted: boolean;\n /** Fixed host size in px; defined only when `faceDiameter` is set. */\n hostWidthPx?: number;\n /** Fixed host size in px; defined only when `faceDiameter` is set. */\n hostHeightPx?: number;\n}\n\n/**\n * Measure the host's available box in px. Radial instrument hosts render\n * inline by default, so clientWidth/Height are often 0 — fall back to the\n * parent box, like obc-watch's getScale() has always done (issue #1032).\n */\nexport function measureContainerPx(host: HTMLElement): {\n width: number;\n height: number;\n} {\n let width = host.clientWidth;\n let height = host.clientHeight;\n if (width === 0 || height === 0) {\n const box = host.parentElement?.getBoundingClientRect();\n if (box) {\n width = box.width;\n height = box.height;\n }\n }\n return {width, height};\n}\n\n/**\n * Apply/remove the fixed intrinsic host size a `faceDiameter` frame pins.\n * The hosts render inline by default, so a pinned size also needs\n * `display: block` for width/height to apply. Returns whether the size is\n * currently pinned; pass that back as `wasPinned` on the next call so an\n * unpinned host's own inline styles are never clobbered.\n */\nexport function applyPinnedHostSize(\n host: HTMLElement,\n frame: RadialFrame | undefined,\n wasPinned: boolean\n): boolean {\n if (frame?.hostWidthPx !== undefined && frame.hostHeightPx !== undefined) {\n host.style.width = `${frame.hostWidthPx}px`;\n host.style.height = `${frame.hostHeightPx}px`;\n host.style.display = 'block';\n return true;\n }\n if (wasPinned) {\n host.style.removeProperty('width');\n host.style.removeProperty('height');\n host.style.removeProperty('display');\n }\n return false;\n}\n\n/**\n * Additionally observe an internal element that always generates a box (the\n * shadow `<svg>` or `.container`). Several radial hosts render inline (no\n * `:host {display}` rule), and ResizeObserver never fires for inline boxes —\n * the host reports a permanent 0×0 size, so a controller observing only the\n * host misses every resize. That freezes the container-dependent frame and\n * the `--scale` font counter-scaling at their first-paint values.\n */\nexport function observeInnerBox(\n controller: {observe(target: Element): void},\n renderRoot: ParentNode\n): void {\n const box = renderRoot.querySelector('svg, .container');\n if (box) {\n controller.observe(box);\n }\n}\n\n/**\n * Estimate the widest label's pixel width at the 12px instrument label font.\n */\nexport function estimateLabelWidthPx(\n texts: readonly (string | undefined)[]\n): number {\n let maxChars = 0;\n for (const t of texts) {\n if (t !== undefined && t.length > maxChars) {\n maxChars = t.length;\n }\n }\n return maxChars * DIGIT_WIDTH_PX;\n}\n\nfunction clipFractions(clips?: RadialClips): {fx: number; fy: number} {\n if (!clips) {\n return {fx: 1, fy: 1};\n }\n const fx = 1 - (clips.left + clips.right) / 100;\n const fy = 1 - (clips.top + clips.bottom) / 100;\n return {fx: fx > 0 ? fx : 1, fy: fy > 0 ? fy : 1};\n}\n\nfunction buildViewBox(side: number, clips?: RadialClips): ZoomToFitArcFrame {\n const {fx, fy} = clipFractions(clips);\n const width = side * fx;\n const height = side * fy;\n const x = -side / 2 + (side * (clips?.left ?? 0)) / 100;\n const y = -side / 2 + (side * (clips?.top ?? 0)) / 100;\n return {\n x,\n y,\n width,\n height,\n viewBox: `${x} ${y} ${width} ${height}`,\n radiusOffset: 0,\n };\n}\n\nfunction pinnedScale(opts: RadialFrameOptions): number | undefined {\n if (opts.faceDiameter === undefined) {\n return undefined;\n }\n const scale = opts.faceDiameter / (2 * OUTER_RING_RADIUS);\n return Number.isFinite(scale) && scale > 0 ? scale : undefined;\n}\n\n/** Container px available for the full (un-clipped) square, or undefined. */\nfunction effectiveContainer(\n opts: RadialFrameOptions,\n fx: number,\n fy: number\n): number | undefined {\n const w = opts.containerPx?.width ?? 0;\n const h = opts.containerPx?.height ?? 0;\n if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {\n return undefined;\n }\n return Math.min(w / fx, h / fy);\n}\n\nfunction containerScale(\n opts: RadialFrameOptions,\n frame: {width: number; height: number}\n): number | undefined {\n const w = opts.containerPx?.width ?? 0;\n const h = opts.containerPx?.height ?? 0;\n if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {\n return undefined;\n }\n const scale = Math.min(w / frame.width, h / frame.height);\n return Number.isFinite(scale) && scale > 0 ? scale : undefined;\n}\n\nfunction withHostPx(\n frame: ZoomToFitArcFrame,\n pinned: boolean,\n scale: number,\n labelReserve: number,\n labelsHidden: boolean,\n clipsAdjusted = false\n): RadialFrame {\n const result: RadialFrame = {\n ...frame,\n scale,\n labelReserve,\n labelsHidden,\n clipsAdjusted,\n };\n if (pinned) {\n result.hostWidthPx = frame.width * scale;\n result.hostHeightPx = frame.height * scale;\n }\n return result;\n}\n\n/**\n * Solve the un-zoomed box side and label visibility for a given clip window.\n */\nfunction solveSide(\n opts: RadialFrameOptions,\n labelCostPx: number,\n clips: RadialClips | undefined\n): {side: number; labelsHidden: boolean} {\n const baseSide = (RADIAL_VIEWBOX_BASE + opts.basePadding) * 2;\n const {fx, fy} = clipFractions(clips);\n const labelSideAt = (scale: number): number =>\n 2 * (OUTER_RING_RADIUS + LABEL_RADIAL_PAD_UNITS + labelCostPx / scale);\n\n let side = baseSide;\n let labelsHidden = false;\n\n if (labelCostPx > 0) {\n const pinned = pinnedScale(opts);\n if (pinned !== undefined) {\n const grown = Math.max(baseSide, labelSideAt(pinned));\n labelsHidden =\n (2 * (labelCostPx / pinned)) / grown > LABEL_RESERVE_MAX_FRACTION;\n side = labelsHidden ? baseSide : grown;\n } else {\n const container = effectiveContainer(opts, fx, fy);\n if (container === undefined) {\n side = Math.max(baseSide, labelSideAt(1));\n } else if ((2 * labelCostPx) / container > LABEL_RESERVE_MAX_FRACTION) {\n labelsHidden = true;\n } else {\n side = Math.max(\n baseSide,\n (2 * (OUTER_RING_RADIUS + LABEL_RADIAL_PAD_UNITS)) /\n (1 - (2 * labelCostPx) / container)\n );\n }\n }\n }\n\n return {side, labelsHidden};\n}\n\n/**\n * Lower a top/bottom clip so the crop edge keeps `labelDropPx / scale` SVG\n * units past the ±90° horizontal line (where the arc end labels hang).\n * Returns the input object unchanged when the requested clips already fit.\n */\nfunction adjustClipsForLabelDrop(\n clips: RadialClips,\n side: number,\n scale: number,\n labelDropPx: number\n): RadialClips {\n const requiredUnits = labelDropPx / scale;\n const requiredClipPct = Math.max(0, (0.5 - requiredUnits / side) * 100);\n const bottom =\n clips.bottom > requiredClipPct ? requiredClipPct : clips.bottom;\n const top = clips.top > requiredClipPct ? requiredClipPct : clips.top;\n if (bottom === clips.bottom && top === clips.top) {\n return clips;\n }\n return {...clips, top, bottom};\n}\n\n/**\n * Compute the viewBox frame for a radial instrument, reserving width-aware\n * room for outside tick labels. See the module documentation for the model.\n */\nexport function computeRadialFrame(opts: RadialFrameOptions): RadialFrame {\n const labelWidthPx = opts.labelWidthPx ?? 0;\n const labelCostPx =\n labelWidthPx > 0\n ? LABEL_ANCHOR_OFFSET_PX + labelWidthPx + LABEL_EDGE_PAD_PX\n : 0;\n\n if (opts.zoomToFitArc && opts.areas && opts.areas.length > 0) {\n return computeZoomedFrame(opts, labelCostPx);\n }\n\n const baseSide = (RADIAL_VIEWBOX_BASE + opts.basePadding) * 2;\n let clips = opts.clips;\n let {side, labelsHidden} = solveSide(opts, labelCostPx, clips);\n\n // Label drop past the ±90° line: lower a top/bottom crop that would cut\n // into it. The clip change alters the container fit (fy grows), so run a\n // second pass; visually exact after two.\n const labelDropPx = opts.labelDropPx ?? 0;\n if (labelDropPx > 0 && labelCostPx > 0 && !labelsHidden && clips) {\n for (let i = 0; i < 2; i++) {\n const scale =\n pinnedScale(opts) ??\n containerScale(opts, buildViewBox(side, clips)) ??\n 1;\n const adjusted = adjustClipsForLabelDrop(\n clips!,\n side,\n scale,\n labelDropPx\n );\n if (adjusted === clips) {\n break;\n }\n clips = adjusted;\n const solved = solveSide(opts, labelCostPx, clips);\n side = solved.side;\n labelsHidden = solved.labelsHidden;\n }\n if (labelsHidden) {\n // The taller window pushed the reserve past the cap: labels are\n // stripped, so the drop is moot — restore the requested clips.\n clips = opts.clips;\n const solved = solveSide(opts, labelCostPx, clips);\n side = solved.side;\n labelsHidden = solved.labelsHidden;\n }\n }\n\n const frame = buildViewBox(side, clips);\n const pinned = pinnedScale(opts);\n const scale = pinned ?? containerScale(opts, frame) ?? 1;\n return withHostPx(\n frame,\n pinned !== undefined,\n scale,\n (side - baseSide) / 2,\n labelsHidden,\n clips !== opts.clips\n );\n}\n\nfunction computeZoomedFrame(\n opts: RadialFrameOptions,\n labelCostPx: number\n): RadialFrame {\n let reserve = 0;\n let labelsHidden = false;\n let frame: ZoomToFitArcFrame = zoomFrameAt(opts, opts.basePadding);\n\n if (labelCostPx > 0) {\n // Fixed-point on the extension: the reserve depends on the scale, and the\n // scale on the frame size. Converges monotonically; two passes suffice.\n for (let i = 0; i < 2; i++) {\n const passScale = zoomedScale(opts, frame);\n const reserveUnits = labelCostPx / passScale;\n if (\n (2 * reserveUnits) / Math.max(frame.width, frame.height) >\n LABEL_RESERVE_MAX_FRACTION\n ) {\n labelsHidden = true;\n reserve = 0;\n frame = zoomFrameAt(opts, opts.basePadding);\n break;\n }\n reserve = reserveUnits;\n frame = zoomFrameAt(opts, opts.basePadding + reserve);\n }\n }\n\n const pinned = pinnedZoomedScale(opts, frame);\n const scale = pinned ?? containerScale(opts, frame) ?? 1;\n return withHostPx(\n frame,\n pinned !== undefined,\n scale,\n labelsHidden ? 0 : reserve,\n labelsHidden\n );\n}\n\nfunction zoomFrameAt(\n opts: RadialFrameOptions,\n extension: number\n): ZoomToFitArcFrame {\n return computeZoomToFitArcFrame({\n areas: opts.areas!,\n outerRadius: OUTER_RING_RADIUS,\n innerRadius: opts.innerRadius ?? OUTER_RING_RADIUS,\n extension,\n targetSize: (RADIAL_VIEWBOX_BASE + extension) * 2,\n });\n}\n\n/** Pin scale for a zoomed frame, or undefined when `faceDiameter` is unusable. */\nfunction pinnedZoomedScale(\n opts: RadialFrameOptions,\n frame: ZoomToFitArcFrame\n): number | undefined {\n if (opts.faceDiameter === undefined) {\n return undefined;\n }\n const scale =\n opts.faceDiameter / (2 * (OUTER_RING_RADIUS + frame.radiusOffset));\n return Number.isFinite(scale) && scale > 0 ? scale : undefined;\n}\n\nfunction zoomedScale(\n opts: RadialFrameOptions,\n frame: ZoomToFitArcFrame\n): number {\n return pinnedZoomedScale(opts, frame) ?? containerScale(opts, frame) ?? 1;\n}\n"],"names":["scale"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oicl/openbridge-webcomponents",
3
- "version": "2.0.0-next.101",
3
+ "version": "2.0.0-next.103",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",