@ponchia/ui 0.5.0 → 0.6.3
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/CHANGELOG.md +386 -4
- package/MIGRATIONS.json +14 -0
- package/README.md +29 -6
- package/annotations/index.d.ts +398 -276
- package/annotations/index.d.ts.map +1 -0
- package/annotations/index.js +350 -77
- package/behaviors/carousel.d.ts +28 -0
- package/behaviors/carousel.d.ts.map +1 -0
- package/behaviors/carousel.js +20 -16
- package/behaviors/combobox.d.ts +40 -0
- package/behaviors/combobox.d.ts.map +1 -0
- package/behaviors/combobox.js +111 -29
- package/behaviors/command.d.ts +41 -0
- package/behaviors/command.d.ts.map +1 -0
- package/behaviors/command.js +27 -15
- package/behaviors/connectors.d.ts +17 -0
- package/behaviors/connectors.d.ts.map +1 -0
- package/behaviors/connectors.js +7 -5
- package/behaviors/crosshair.d.ts +42 -0
- package/behaviors/crosshair.d.ts.map +1 -0
- package/behaviors/crosshair.js +23 -6
- package/behaviors/dialog.d.ts +20 -0
- package/behaviors/dialog.d.ts.map +1 -0
- package/behaviors/dialog.js +6 -2
- package/behaviors/disclosure.d.ts +10 -0
- package/behaviors/disclosure.d.ts.map +1 -0
- package/behaviors/disclosure.js +6 -2
- package/behaviors/dismissible.d.ts +10 -0
- package/behaviors/dismissible.d.ts.map +1 -0
- package/behaviors/dismissible.js +6 -2
- package/behaviors/forms.d.ts +27 -0
- package/behaviors/forms.d.ts.map +1 -0
- package/behaviors/forms.js +54 -13
- package/behaviors/glyph.d.ts +14 -0
- package/behaviors/glyph.d.ts.map +1 -0
- package/behaviors/glyph.js +28 -5
- package/behaviors/index.d.ts +31 -237
- package/behaviors/index.d.ts.map +1 -0
- package/behaviors/index.js +17 -0
- package/behaviors/inert.d.ts +20 -0
- package/behaviors/inert.d.ts.map +1 -0
- package/behaviors/inert.js +46 -0
- package/behaviors/internal.d.ts +25 -0
- package/behaviors/internal.d.ts.map +1 -0
- package/behaviors/internal.js +77 -1
- package/behaviors/legend.d.ts +35 -0
- package/behaviors/legend.d.ts.map +1 -0
- package/behaviors/legend.js +32 -2
- package/behaviors/menu.d.ts +16 -0
- package/behaviors/menu.d.ts.map +1 -0
- package/behaviors/menu.js +6 -2
- package/behaviors/modal.d.ts +41 -0
- package/behaviors/modal.d.ts.map +1 -0
- package/behaviors/modal.js +124 -0
- package/behaviors/popover.d.ts +28 -0
- package/behaviors/popover.d.ts.map +1 -0
- package/behaviors/popover.js +78 -7
- package/behaviors/spotlight.d.ts +17 -0
- package/behaviors/spotlight.d.ts.map +1 -0
- package/behaviors/spotlight.js +7 -5
- package/behaviors/table.d.ts +36 -0
- package/behaviors/table.d.ts.map +1 -0
- package/behaviors/table.js +84 -17
- package/behaviors/tabs.d.ts +20 -0
- package/behaviors/tabs.d.ts.map +1 -0
- package/behaviors/tabs.js +17 -14
- package/behaviors/theme.d.ts +54 -0
- package/behaviors/theme.d.ts.map +1 -0
- package/behaviors/theme.js +22 -3
- package/behaviors/toast.d.ts +49 -0
- package/behaviors/toast.d.ts.map +1 -0
- package/behaviors/toast.js +47 -3
- package/classes/classes.json +2527 -0
- package/classes/index.d.ts +134 -15
- package/classes/index.js +280 -80
- package/classes/vscode.css-custom-data.json +12 -0
- package/connectors/index.d.ts +201 -69
- package/connectors/index.d.ts.map +1 -0
- package/connectors/index.js +142 -25
- package/css/app.css +69 -13
- package/css/base.css +15 -10
- package/css/bullet.css +108 -0
- package/css/code.css +98 -0
- package/css/connectors.css +17 -0
- package/css/content.css +22 -3
- package/css/crosshair.css +7 -7
- package/css/dataviz.css +5 -1
- package/css/diff.css +153 -0
- package/css/disclosure.css +53 -7
- package/css/dots.css +94 -7
- package/css/feedback.css +97 -7
- package/css/forms.css +113 -4
- package/css/legend.css +16 -9
- package/css/marks.css +38 -8
- package/css/motion.css +98 -53
- package/css/navigation.css +7 -0
- package/css/overlay.css +90 -3
- package/css/primitives.css +158 -13
- package/css/report.css +73 -56
- package/css/sidenote.css +67 -0
- package/css/site.css +16 -2
- package/css/sources.css +43 -1
- package/css/spark.css +62 -0
- package/css/spotlight.css +1 -1
- package/css/table.css +9 -2
- package/css/term.css +110 -0
- package/css/textref.css +63 -0
- package/css/toc.css +91 -0
- package/css/tokens.css +49 -1
- package/css/tree.css +134 -0
- package/css/workbench.css +1 -1
- package/dist/bronto.css +1 -1
- package/dist/css/analytical.css +1 -1
- package/dist/css/app.css +1 -1
- package/dist/css/base.css +1 -1
- package/dist/css/bullet.css +1 -0
- package/dist/css/code.css +1 -0
- package/dist/css/connectors.css +1 -1
- package/dist/css/content.css +1 -1
- package/dist/css/crosshair.css +1 -1
- package/dist/css/diff.css +1 -0
- package/dist/css/disclosure.css +1 -1
- package/dist/css/dots.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/forms.css +1 -1
- package/dist/css/legend.css +1 -1
- package/dist/css/marks.css +1 -1
- package/dist/css/motion.css +1 -1
- package/dist/css/navigation.css +1 -1
- package/dist/css/overlay.css +1 -1
- package/dist/css/primitives.css +1 -1
- package/dist/css/report.css +1 -1
- package/dist/css/sidenote.css +1 -0
- package/dist/css/site.css +1 -1
- package/dist/css/sources.css +1 -1
- package/dist/css/spark.css +1 -0
- package/dist/css/spotlight.css +1 -1
- package/dist/css/table.css +1 -1
- package/dist/css/term.css +1 -0
- package/dist/css/textref.css +1 -0
- package/dist/css/toc.css +1 -0
- package/dist/css/tokens.css +1 -1
- package/dist/css/tree.css +1 -0
- package/dist/css/workbench.css +1 -1
- package/docs/adr/0003-theme-model.md +1 -1
- package/docs/annotations.md +133 -14
- package/docs/architecture.md +49 -6
- package/docs/bullet.md +78 -0
- package/docs/code.md +76 -0
- package/docs/contrast.md +116 -92
- package/docs/d2.md +196 -0
- package/docs/diff.md +146 -0
- package/docs/legends.md +23 -3
- package/docs/marks.md +9 -2
- package/docs/mermaid.md +169 -0
- package/docs/reference.md +201 -26
- package/docs/reporting.md +416 -57
- package/docs/sidenote.md +64 -0
- package/docs/sources.md +27 -0
- package/docs/spark.md +78 -0
- package/docs/stability.md +10 -2
- package/docs/term.md +81 -0
- package/docs/textref.md +78 -0
- package/docs/theming.md +44 -5
- package/docs/toc.md +83 -0
- package/docs/tree.md +74 -0
- package/docs/usage.md +354 -16
- package/docs/vega.md +244 -0
- package/docs/workbench.md +7 -1
- package/glyphs/glyphs.js +13 -5
- package/llms.txt +285 -14
- package/package.json +95 -17
- package/qwik/index.d.ts +44 -59
- package/qwik/index.d.ts.map +1 -0
- package/qwik/index.js +65 -3
- package/react/index.d.ts +41 -61
- package/react/index.d.ts.map +1 -0
- package/react/index.js +63 -3
- package/solid/index.d.ts +68 -61
- package/solid/index.d.ts.map +1 -0
- package/solid/index.js +66 -3
- package/tokens/d2.d.ts +38 -0
- package/tokens/d2.js +71 -0
- package/tokens/d2.json +43 -0
- package/tokens/index.d.ts +5 -5
- package/tokens/index.js +15 -1
- package/tokens/index.json +9 -0
- package/tokens/mermaid.d.ts +23 -0
- package/tokens/mermaid.js +181 -0
- package/tokens/mermaid.json +163 -0
- package/tokens/resolved.json +45 -1
- package/tokens/skins.js +3 -2
- package/tokens/tokens.dtcg.json +26 -0
- package/tokens/vega.d.ts +34 -0
- package/tokens/vega.js +155 -0
- package/tokens/vega.json +179 -0
package/annotations/index.js
CHANGED
|
@@ -1,53 +1,229 @@
|
|
|
1
1
|
// Shared SVG geometry primitives live in the connectors kernel; annotations
|
|
2
2
|
// (figure callouts) build on them so a line/curve/arrow/dot is drawn one way.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @ponchia/ui — SVG annotation geometry helpers.
|
|
6
|
+
*
|
|
7
|
+
* The public types below are JSDoc `@typedef`s; the shipped `index.d.ts` is
|
|
8
|
+
* generated from them (and these signatures) by `tsc --emitDeclarationOnly`.
|
|
9
|
+
*
|
|
10
|
+
* @typedef {{ x: number, y: number }} AnnotationPoint
|
|
11
|
+
* @typedef {{ dx: number, dy: number }} AnnotationOffset
|
|
12
|
+
* @typedef {'callout' | 'elbow' | 'curve'} AnnotationConnectorType
|
|
13
|
+
* @typedef {'start' | 'middle' | 'end'} AnnotationAlign
|
|
14
|
+
* @typedef {'top' | 'middle' | 'bottom'} AnnotationValign
|
|
15
|
+
* @typedef {'horizontal' | 'vertical'} AxisOrientation
|
|
16
|
+
* @typedef {'up' | 'down' | 'left' | 'right'} TimelineDirection
|
|
17
|
+
*
|
|
18
|
+
* @typedef {object} CircleSubject
|
|
19
|
+
* @property {'circle'} type
|
|
20
|
+
* @property {number} radius
|
|
21
|
+
* @property {number} [radiusPadding]
|
|
22
|
+
*
|
|
23
|
+
* @typedef {object} RectSubject
|
|
24
|
+
* @property {'rect'} type
|
|
25
|
+
* @property {number} width
|
|
26
|
+
* @property {number} height
|
|
27
|
+
* @property {number} [x]
|
|
28
|
+
* @property {number} [y]
|
|
29
|
+
* @property {number} [padding]
|
|
30
|
+
*
|
|
31
|
+
* @typedef {CircleSubject | RectSubject} ConnectorSubject
|
|
32
|
+
*
|
|
33
|
+
* @typedef {AnnotationOffset & { subject?: ConnectorSubject, mid?: number }} ConnectorOptions
|
|
34
|
+
*
|
|
35
|
+
* @typedef {object} CircleSubjectOptions
|
|
36
|
+
* @property {number} radius
|
|
37
|
+
*
|
|
38
|
+
* @typedef {object} RectSubjectOptions
|
|
39
|
+
* @property {number} width
|
|
40
|
+
* @property {number} height
|
|
41
|
+
* @property {number} [x]
|
|
42
|
+
* @property {number} [y]
|
|
43
|
+
* @property {number} [padding]
|
|
44
|
+
*
|
|
45
|
+
* @typedef {object} ThresholdOptions
|
|
46
|
+
* @property {number} [x1]
|
|
47
|
+
* @property {number} [y1]
|
|
48
|
+
* @property {number} x2
|
|
49
|
+
* @property {number} y2
|
|
50
|
+
*
|
|
51
|
+
* @typedef {object} AxisThresholdOptions
|
|
52
|
+
* @property {AxisOrientation} [orientation]
|
|
53
|
+
* @property {number} [value]
|
|
54
|
+
* @property {number} [start]
|
|
55
|
+
* @property {number} end
|
|
56
|
+
*
|
|
57
|
+
* @typedef {object} BracketSubjectOptions
|
|
58
|
+
* @property {number} x1
|
|
59
|
+
* @property {number} y1
|
|
60
|
+
* @property {number} x2
|
|
61
|
+
* @property {number} y2
|
|
62
|
+
* @property {number} [depth]
|
|
63
|
+
*
|
|
64
|
+
* @typedef {object} BandSubjectOptions
|
|
65
|
+
* @property {number} [x]
|
|
66
|
+
* @property {number} [y]
|
|
67
|
+
* @property {number} width
|
|
68
|
+
* @property {number} height
|
|
69
|
+
* @property {number} [padding]
|
|
70
|
+
*
|
|
71
|
+
* @typedef {object} SlopeSubjectOptions
|
|
72
|
+
* @property {number} x1
|
|
73
|
+
* @property {number} y1
|
|
74
|
+
* @property {number} x2
|
|
75
|
+
* @property {number} y2
|
|
76
|
+
*
|
|
77
|
+
* @typedef {object} ComparisonBraceOptions
|
|
78
|
+
* @property {number} x1
|
|
79
|
+
* @property {number} y1
|
|
80
|
+
* @property {number} x2
|
|
81
|
+
* @property {number} y2
|
|
82
|
+
* @property {number} [depth]
|
|
83
|
+
*
|
|
84
|
+
* @typedef {object} OutlierClusterOptions
|
|
85
|
+
* @property {AnnotationPoint[]} points
|
|
86
|
+
* @property {number} [radius]
|
|
87
|
+
*
|
|
88
|
+
* @typedef {object} TimelineEventOptions
|
|
89
|
+
* @property {number} [size]
|
|
90
|
+
* @property {TimelineDirection} [direction]
|
|
91
|
+
*
|
|
92
|
+
* @typedef {object} EvidenceMarkerOptions
|
|
93
|
+
* @property {number} [x]
|
|
94
|
+
* @property {number} [y]
|
|
95
|
+
* @property {number} [width]
|
|
96
|
+
* @property {number} [height]
|
|
97
|
+
* @property {number} [padding]
|
|
98
|
+
*
|
|
99
|
+
* @typedef {AnnotationPoint & { radius?: number }} ConnectorEndDotOptions
|
|
100
|
+
*
|
|
101
|
+
* @typedef {object} ConnectorEndArrowOptions
|
|
102
|
+
* @property {number} [x1]
|
|
103
|
+
* @property {number} [y1]
|
|
104
|
+
* @property {number} x2
|
|
105
|
+
* @property {number} y2
|
|
106
|
+
* @property {number} [size]
|
|
107
|
+
* @property {number} [spread] Half-angle of the arrowhead in radians (default
|
|
108
|
+
* 0.32 ≈ a crisp 37° included angle). Larger = blunter.
|
|
109
|
+
*
|
|
110
|
+
* @typedef {object} NoteTransformOptions
|
|
111
|
+
* @property {number} [dx]
|
|
112
|
+
* @property {number} [dy]
|
|
113
|
+
* @property {number} [x]
|
|
114
|
+
* @property {number} [y]
|
|
115
|
+
* @property {AnnotationAlign} [align]
|
|
116
|
+
* @property {AnnotationValign} [valign]
|
|
117
|
+
* @property {number} [width]
|
|
118
|
+
* @property {number} [height]
|
|
119
|
+
*
|
|
120
|
+
* @typedef {object} AnnotationBounds
|
|
121
|
+
* @property {number} [x]
|
|
122
|
+
* @property {number} [y]
|
|
123
|
+
* @property {number} width
|
|
124
|
+
* @property {number} height
|
|
125
|
+
*
|
|
126
|
+
* @typedef {object} NotePlacementOptions
|
|
127
|
+
* @property {number} [x]
|
|
128
|
+
* @property {number} [y]
|
|
129
|
+
* @property {number} width
|
|
130
|
+
* @property {number} height
|
|
131
|
+
* @property {AnnotationBounds} bounds
|
|
132
|
+
* @property {number} [padding]
|
|
133
|
+
* @property {number} [gap]
|
|
134
|
+
* @property {'right' | 'left' | 'top' | 'bottom'} [preferred]
|
|
135
|
+
* @property {number} [inset] Extra margin (user units) the note must keep from
|
|
136
|
+
* the bounds edge, on top of `padding`. Reserve the note's title stroke-halo
|
|
137
|
+
* (~3) or a leader stub so a placement that "fits" doesn't clip. Default 0.
|
|
138
|
+
*
|
|
139
|
+
* @typedef {object} NotePlacement
|
|
140
|
+
* @property {number} dx
|
|
141
|
+
* @property {number} dy
|
|
142
|
+
* @property {AnnotationAlign} align
|
|
143
|
+
* @property {AnnotationValign} valign
|
|
144
|
+
* @property {string} transform
|
|
145
|
+
*
|
|
146
|
+
* @typedef {(
|
|
147
|
+
* | CircleSubject
|
|
148
|
+
* | RectSubject
|
|
149
|
+
* | ({ type: 'threshold' } & ThresholdOptions)
|
|
150
|
+
* | ({ type: 'bracket' } & BracketSubjectOptions)
|
|
151
|
+
* | ({ type: 'band' } & BandSubjectOptions)
|
|
152
|
+
* | ({ type: 'slope' } & SlopeSubjectOptions)
|
|
153
|
+
* | ({ type: 'compare' } & ComparisonBraceOptions)
|
|
154
|
+
* | ({ type: 'cluster' } & OutlierClusterOptions)
|
|
155
|
+
* | ({ type: 'axis' } & AxisThresholdOptions)
|
|
156
|
+
* | ({ type: 'timeline' } & TimelineEventOptions)
|
|
157
|
+
* | ({ type: 'evidence' } & EvidenceMarkerOptions)
|
|
158
|
+
* )} AnnotationPartsSubject
|
|
159
|
+
*
|
|
160
|
+
* @typedef {object} AnnotationPartsOptions
|
|
161
|
+
* @property {AnnotationConnectorType} [type]
|
|
162
|
+
* @property {number} [x]
|
|
163
|
+
* @property {number} [y]
|
|
164
|
+
* @property {number} [dx]
|
|
165
|
+
* @property {number} [dy]
|
|
166
|
+
* @property {AnnotationPartsSubject} [subject]
|
|
167
|
+
*
|
|
168
|
+
* @typedef {object} AnnotationParts
|
|
169
|
+
* @property {string} transform
|
|
170
|
+
* @property {string} subject
|
|
171
|
+
* @property {string} connector
|
|
172
|
+
* @property {string} note
|
|
173
|
+
*
|
|
174
|
+
* @typedef {object} DeclutterLabelItem
|
|
175
|
+
* @property {number} pos Desired centre coordinate along the axis.
|
|
176
|
+
* @property {number} size The label's extent along the axis.
|
|
177
|
+
*
|
|
178
|
+
* @typedef {object} DeclutterLabelsOptions
|
|
179
|
+
* @property {number} [gap] Minimum gap kept between adjacent labels. Default 0.
|
|
180
|
+
* @property {number} [min] Lower bound of the axis. Default -Infinity.
|
|
181
|
+
* @property {number} [max] Upper bound of the axis. Default Infinity.
|
|
182
|
+
*
|
|
183
|
+
* @typedef {object} DirectLabelItem
|
|
184
|
+
* @property {AnnotationPoint} anchor The true data point the label refers to (figure coordinates).
|
|
185
|
+
* @property {number} size The label's extent along the layout axis.
|
|
186
|
+
* @property {string | number} [key] Optional identifier, echoed back on the matching output (input order).
|
|
187
|
+
*
|
|
188
|
+
* @typedef {object} DirectLabelsOptions
|
|
189
|
+
* @property {'x' | 'y'} [axis] Axis the labels declutter along. 'y' = a vertical column. Default 'y'.
|
|
190
|
+
* @property {number} [cross] Fixed coordinate on the other axis where the label column/row sits. Default 0.
|
|
191
|
+
* @property {number} [gap] Minimum gap kept between adjacent labels. Default 0.
|
|
192
|
+
* @property {number} [min] Lower bound of the layout axis. Default -Infinity.
|
|
193
|
+
* @property {number} [max] Upper bound of the layout axis. Default Infinity.
|
|
194
|
+
* @property {'straight' | 'elbow' | 'curve'} [shape] Leader-line shape. Default 'straight'.
|
|
195
|
+
*
|
|
196
|
+
* @typedef {object} DirectLabel
|
|
197
|
+
* @property {number} x Placed label point — the leader's label-side end.
|
|
198
|
+
* @property {number} y
|
|
199
|
+
* @property {AnnotationPoint} anchor The echoed input anchor.
|
|
200
|
+
* @property {string | number} [key] The echoed input key, if any.
|
|
201
|
+
* @property {string} d SVG path for the leader (anchor → label point); '' if they coincide.
|
|
202
|
+
*/
|
|
203
|
+
|
|
3
204
|
import {
|
|
4
205
|
straightPath,
|
|
5
206
|
curvePath,
|
|
6
207
|
connectorPath,
|
|
208
|
+
elbowPath,
|
|
7
209
|
arrowHead,
|
|
8
210
|
dotMark,
|
|
9
211
|
angleBetween,
|
|
212
|
+
// Shared scalar/geometry kernel — single source of truth (was copy-pasted,
|
|
213
|
+
// and the local clamp had silently diverged from the connectors one).
|
|
214
|
+
roundNumber,
|
|
215
|
+
finite,
|
|
216
|
+
dimension,
|
|
217
|
+
fmt,
|
|
218
|
+
point,
|
|
219
|
+
clamp,
|
|
220
|
+
rectPath,
|
|
10
221
|
} from '../connectors/index.js';
|
|
11
222
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
function finite(name, value, fallback) {
|
|
15
|
-
const v = value ?? fallback;
|
|
16
|
-
if (!Number.isFinite(v)) throw new TypeError(`${name} must be a finite number`);
|
|
17
|
-
return v;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function dimension(name, value, fallback) {
|
|
21
|
-
const v = finite(name, value, fallback);
|
|
22
|
-
if (v < 0) throw new RangeError(`${name} must be greater than or equal to 0`);
|
|
23
|
-
return v;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function fmt(value) {
|
|
27
|
-
const rounded = Math.round((Object.is(value, -0) ? 0 : value) * PRECISION) / PRECISION;
|
|
28
|
-
return String(Object.is(rounded, -0) ? 0 : rounded);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function roundedNumber(value) {
|
|
32
|
-
const rounded = Math.round((Object.is(value, -0) ? 0 : value) * PRECISION) / PRECISION;
|
|
33
|
-
return Object.is(rounded, -0) ? 0 : rounded;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function point(x, y) {
|
|
37
|
-
return `${fmt(x)},${fmt(y)}`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function clamp(value, min, max) {
|
|
41
|
-
if (max < min) return min;
|
|
42
|
-
return Math.min(max, Math.max(min, value));
|
|
43
|
-
}
|
|
44
|
-
|
|
223
|
+
// A circle subject is just a filled dot at (x, y) — delegate to the kernel's
|
|
224
|
+
// dotMark so the arc geometry/precision can't diverge. (code-quality audit Q5.)
|
|
45
225
|
function circlePathAt(x, y, radius) {
|
|
46
|
-
|
|
47
|
-
if (r === 0) return '';
|
|
48
|
-
return `M${point(x, y - r)}A${fmt(r)},${fmt(r)} 0 1 1 ${point(x, y + r)}A${fmt(r)},${fmt(
|
|
49
|
-
r,
|
|
50
|
-
)} 0 1 1 ${point(x, y - r)}Z`;
|
|
226
|
+
return dotMark({ x, y }, radius);
|
|
51
227
|
}
|
|
52
228
|
|
|
53
229
|
function samePoint(a, b) {
|
|
@@ -106,10 +282,18 @@ function linePath(start, end) {
|
|
|
106
282
|
return `M${point(start.x, start.y)}L${point(end.x, end.y)}`;
|
|
107
283
|
}
|
|
108
284
|
|
|
285
|
+
/**
|
|
286
|
+
* @param {Partial<AnnotationPoint>} [point]
|
|
287
|
+
* @returns {string}
|
|
288
|
+
*/
|
|
109
289
|
export function annotationTransform({ x = 0, y = 0 } = {}) {
|
|
110
290
|
return `translate(${fmt(finite('x', x))}, ${fmt(finite('y', y))})`;
|
|
111
291
|
}
|
|
112
292
|
|
|
293
|
+
/**
|
|
294
|
+
* @param {NoteTransformOptions} [options]
|
|
295
|
+
* @returns {string}
|
|
296
|
+
*/
|
|
113
297
|
export function noteTransform({
|
|
114
298
|
dx,
|
|
115
299
|
dy,
|
|
@@ -172,6 +356,10 @@ function noteRect(x, y, width, height, placement) {
|
|
|
172
356
|
};
|
|
173
357
|
}
|
|
174
358
|
|
|
359
|
+
/**
|
|
360
|
+
* @param {NotePlacementOptions} options
|
|
361
|
+
* @returns {NotePlacement}
|
|
362
|
+
*/
|
|
175
363
|
export function notePlacement({
|
|
176
364
|
x = 0,
|
|
177
365
|
y = 0,
|
|
@@ -181,6 +369,7 @@ export function notePlacement({
|
|
|
181
369
|
padding = 8,
|
|
182
370
|
gap = 32,
|
|
183
371
|
preferred = 'right',
|
|
372
|
+
inset = 0,
|
|
184
373
|
} = {}) {
|
|
185
374
|
const anchorX = finite('x', x);
|
|
186
375
|
const anchorY = finite('y', y);
|
|
@@ -188,22 +377,25 @@ export function notePlacement({
|
|
|
188
377
|
const h = dimension('height', height);
|
|
189
378
|
const p = dimension('padding', padding);
|
|
190
379
|
const g = dimension('gap', gap);
|
|
380
|
+
const ins = dimension('inset', inset, 0);
|
|
191
381
|
const bx = finite('bounds.x', bounds?.x, 0);
|
|
192
382
|
const by = finite('bounds.y', bounds?.y, 0);
|
|
193
383
|
const bw = dimension('bounds.width', bounds?.width);
|
|
194
384
|
const bh = dimension('bounds.height', bounds?.height);
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
const
|
|
385
|
+
// `inset` reserves an extra margin (e.g. the title stroke-halo) inside the
|
|
386
|
+
// padded bounds, so a placement that "just fits" doesn't clip the halo/leader.
|
|
387
|
+
const minX = bx + p + ins;
|
|
388
|
+
const minY = by + p + ins;
|
|
389
|
+
const maxX = bx + bw - p - ins;
|
|
390
|
+
const maxY = by + bh - p - ins;
|
|
199
391
|
|
|
200
392
|
for (const side of placementOrder(preferred)) {
|
|
201
393
|
const placement = candidatePlacement(side, g);
|
|
202
394
|
const rect = noteRect(anchorX, anchorY, w, h, placement);
|
|
203
395
|
if (rect.left >= minX && rect.top >= minY && rect.right <= maxX && rect.bottom <= maxY) {
|
|
204
396
|
return {
|
|
205
|
-
dx:
|
|
206
|
-
dy:
|
|
397
|
+
dx: roundNumber(placement.dx),
|
|
398
|
+
dy: roundNumber(placement.dy),
|
|
207
399
|
align: placement.align,
|
|
208
400
|
valign: placement.valign,
|
|
209
401
|
transform: noteTransform({ ...placement, width: w, height: h }),
|
|
@@ -215,8 +407,8 @@ export function notePlacement({
|
|
|
215
407
|
const rect = noteRect(anchorX, anchorY, w, h, fallback);
|
|
216
408
|
const left = clamp(rect.left, minX, maxX - w);
|
|
217
409
|
const top = clamp(rect.top, minY, maxY - h);
|
|
218
|
-
const dx =
|
|
219
|
-
const dy =
|
|
410
|
+
const dx = roundNumber(left - anchorX);
|
|
411
|
+
const dy = roundNumber(top - anchorY);
|
|
220
412
|
return {
|
|
221
413
|
dx,
|
|
222
414
|
dy,
|
|
@@ -226,10 +418,18 @@ export function notePlacement({
|
|
|
226
418
|
};
|
|
227
419
|
}
|
|
228
420
|
|
|
421
|
+
/**
|
|
422
|
+
* @param {CircleSubjectOptions} options
|
|
423
|
+
* @returns {string}
|
|
424
|
+
*/
|
|
229
425
|
export function circleSubjectPath({ radius } = {}) {
|
|
230
426
|
return circlePathAt(0, 0, radius);
|
|
231
427
|
}
|
|
232
428
|
|
|
429
|
+
/**
|
|
430
|
+
* @param {RectSubjectOptions} options
|
|
431
|
+
* @returns {string}
|
|
432
|
+
*/
|
|
233
433
|
export function rectSubjectPath({ width, height, x, y, padding = 0 } = {}) {
|
|
234
434
|
const w = dimension('width', width);
|
|
235
435
|
const h = dimension('height', height);
|
|
@@ -239,15 +439,23 @@ export function rectSubjectPath({ width, height, x, y, padding = 0 } = {}) {
|
|
|
239
439
|
const top = finite('y', y, -h / 2) - p;
|
|
240
440
|
const right = left + w + p * 2;
|
|
241
441
|
const bottom = top + h + p * 2;
|
|
242
|
-
return
|
|
442
|
+
return rectPath(left, top, right, bottom);
|
|
243
443
|
}
|
|
244
444
|
|
|
445
|
+
/**
|
|
446
|
+
* @param {ThresholdOptions} options
|
|
447
|
+
* @returns {string}
|
|
448
|
+
*/
|
|
245
449
|
export function thresholdPath({ x1 = 0, y1 = 0, x2, y2 } = {}) {
|
|
246
450
|
const start = { x: finite('x1', x1), y: finite('y1', y1) };
|
|
247
451
|
const end = { x: finite('x2', x2), y: finite('y2', y2) };
|
|
248
452
|
return linePath(start, end);
|
|
249
453
|
}
|
|
250
454
|
|
|
455
|
+
/**
|
|
456
|
+
* @param {AxisThresholdOptions} options
|
|
457
|
+
* @returns {string}
|
|
458
|
+
*/
|
|
251
459
|
export function axisThresholdPath({ orientation = 'horizontal', value = 0, start = 0, end } = {}) {
|
|
252
460
|
const v = finite('value', value);
|
|
253
461
|
const s = finite('start', start);
|
|
@@ -257,6 +465,10 @@ export function axisThresholdPath({ orientation = 'horizontal', value = 0, start
|
|
|
257
465
|
throw new TypeError('orientation must be "horizontal" or "vertical"');
|
|
258
466
|
}
|
|
259
467
|
|
|
468
|
+
/**
|
|
469
|
+
* @param {BracketSubjectOptions} options
|
|
470
|
+
* @returns {string}
|
|
471
|
+
*/
|
|
260
472
|
export function bracketSubjectPath({ x1, y1, x2, y2, depth = 12 } = {}) {
|
|
261
473
|
const start = { x: finite('x1', x1), y: finite('y1', y1) };
|
|
262
474
|
const end = { x: finite('x2', x2), y: finite('y2', y2) };
|
|
@@ -268,14 +480,26 @@ export function bracketSubjectPath({ x1, y1, x2, y2, depth = 12 } = {}) {
|
|
|
268
480
|
return `M${point(start.x, start.y)}H${fmt(start.x + d)}V${fmt(end.y)}H${fmt(end.x)}`;
|
|
269
481
|
}
|
|
270
482
|
|
|
483
|
+
/**
|
|
484
|
+
* @param {BandSubjectOptions} options
|
|
485
|
+
* @returns {string}
|
|
486
|
+
*/
|
|
271
487
|
export function bandSubjectPath({ x = 0, y = 0, width, height, padding = 0 } = {}) {
|
|
272
488
|
return rectSubjectPath({ x, y, width, height, padding });
|
|
273
489
|
}
|
|
274
490
|
|
|
491
|
+
/**
|
|
492
|
+
* @param {SlopeSubjectOptions} options
|
|
493
|
+
* @returns {string}
|
|
494
|
+
*/
|
|
275
495
|
export function slopeSubjectPath({ x1, y1, x2, y2 } = {}) {
|
|
276
496
|
return thresholdPath({ x1, y1, x2, y2 });
|
|
277
497
|
}
|
|
278
498
|
|
|
499
|
+
/**
|
|
500
|
+
* @param {ComparisonBraceOptions} options
|
|
501
|
+
* @returns {string}
|
|
502
|
+
*/
|
|
279
503
|
export function comparisonBracePath({ x1, y1, x2, y2, depth = 14 } = {}) {
|
|
280
504
|
const start = { x: finite('x1', x1), y: finite('y1', y1) };
|
|
281
505
|
const end = { x: finite('x2', x2), y: finite('y2', y2) };
|
|
@@ -313,6 +537,10 @@ export function comparisonBracePath({ x1, y1, x2, y2, depth = 14 } = {}) {
|
|
|
313
537
|
)} ${point(x, end.y)}`;
|
|
314
538
|
}
|
|
315
539
|
|
|
540
|
+
/**
|
|
541
|
+
* @param {OutlierClusterOptions} options
|
|
542
|
+
* @returns {string}
|
|
543
|
+
*/
|
|
316
544
|
export function outlierClusterPath({ points, radius = 6 } = {}) {
|
|
317
545
|
if (!Array.isArray(points)) throw new TypeError('points must be an array');
|
|
318
546
|
return points
|
|
@@ -323,6 +551,10 @@ export function outlierClusterPath({ points, radius = 6 } = {}) {
|
|
|
323
551
|
.join('');
|
|
324
552
|
}
|
|
325
553
|
|
|
554
|
+
/**
|
|
555
|
+
* @param {TimelineEventOptions} [options]
|
|
556
|
+
* @returns {string}
|
|
557
|
+
*/
|
|
326
558
|
export function timelineEventPath({ size = 10, direction = 'down' } = {}) {
|
|
327
559
|
const s = dimension('size', size);
|
|
328
560
|
if (s === 0) return '';
|
|
@@ -333,6 +565,10 @@ export function timelineEventPath({ size = 10, direction = 'down' } = {}) {
|
|
|
333
565
|
throw new TypeError('direction must be "up", "down", "left" or "right"');
|
|
334
566
|
}
|
|
335
567
|
|
|
568
|
+
/**
|
|
569
|
+
* @param {EvidenceMarkerOptions} [options]
|
|
570
|
+
* @returns {string}
|
|
571
|
+
*/
|
|
336
572
|
export function evidenceMarkerPath({ x = 0, y = 0, width = 36, height = 36, padding = 0 } = {}) {
|
|
337
573
|
const w = dimension('width', width);
|
|
338
574
|
const h = dimension('height', height);
|
|
@@ -344,21 +580,33 @@ export function evidenceMarkerPath({ x = 0, y = 0, width = 36, height = 36, padd
|
|
|
344
580
|
const top = cy - h / 2 - p;
|
|
345
581
|
const right = left + w + p * 2;
|
|
346
582
|
const bottom = top + h + p * 2;
|
|
347
|
-
return
|
|
583
|
+
return rectPath(left, top, right, bottom);
|
|
348
584
|
}
|
|
349
585
|
|
|
586
|
+
/**
|
|
587
|
+
* @param {ConnectorEndDotOptions} options
|
|
588
|
+
* @returns {string}
|
|
589
|
+
*/
|
|
350
590
|
export function connectorEndDot({ x, y, radius = 3 } = {}) {
|
|
351
591
|
return dotMark({ x: finite('x', x), y: finite('y', y) }, radius);
|
|
352
592
|
}
|
|
353
593
|
|
|
354
|
-
|
|
594
|
+
/**
|
|
595
|
+
* @param {ConnectorEndArrowOptions} options
|
|
596
|
+
* @returns {string}
|
|
597
|
+
*/
|
|
598
|
+
export function connectorEndArrow({ x1 = 0, y1 = 0, x2, y2, size = 8, spread = 0.32 } = {}) {
|
|
355
599
|
const start = { x: finite('x1', x1), y: finite('y1', y1) };
|
|
356
600
|
const end = { x: finite('x2', x2), y: finite('y2', y2) };
|
|
357
601
|
const s = dimension('size', size);
|
|
358
602
|
if (s === 0 || (end.x === start.x && end.y === start.y)) return '';
|
|
359
|
-
return arrowHead(end, angleBetween(start, end), s);
|
|
603
|
+
return arrowHead(end, angleBetween(start, end), s, spread);
|
|
360
604
|
}
|
|
361
605
|
|
|
606
|
+
/**
|
|
607
|
+
* @param {ConnectorOptions} opts
|
|
608
|
+
* @returns {string}
|
|
609
|
+
*/
|
|
362
610
|
export function connectorLine(opts = {}) {
|
|
363
611
|
const { dx, dy } = validateOffset(opts);
|
|
364
612
|
if (dx === 0 && dy === 0) return '';
|
|
@@ -370,25 +618,29 @@ export function connectorLine(opts = {}) {
|
|
|
370
618
|
return straightPath(start, end);
|
|
371
619
|
}
|
|
372
620
|
|
|
621
|
+
/**
|
|
622
|
+
* @param {ConnectorOptions} opts
|
|
623
|
+
* @returns {string}
|
|
624
|
+
*/
|
|
373
625
|
export function connectorElbow(opts = {}) {
|
|
374
626
|
const { dx, dy } = validateOffset(opts);
|
|
375
627
|
if (dx === 0 && dy === 0) return '';
|
|
376
628
|
const start = connectorStart(dx, dy, opts.subject);
|
|
377
629
|
if (!start) return '';
|
|
378
630
|
const end = { x: dx, y: dy };
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
: { x: end.x, y: start.y + Math.sign(vy) * Math.abs(vx) };
|
|
387
|
-
|
|
388
|
-
if (samePoint(start, elbow) || samePoint(elbow, end)) return linePath(start, end);
|
|
389
|
-
return `M${point(start.x, start.y)}L${point(elbow.x, elbow.y)}L${point(end.x, end.y)}`;
|
|
631
|
+
if (samePoint(start, end)) return '';
|
|
632
|
+
// A true right-angle dogleg (H/V/H), turning on the dominant axis at `mid`
|
|
633
|
+
// (0..1, default 0.5). Delegated to the connectors geometry kernel so an
|
|
634
|
+
// annotation leader and a node connector draw the same elbow. (The former
|
|
635
|
+
// inline form turned by min(|dx|,|dy|), i.e. a 45° chamfer that read as a
|
|
636
|
+
// diagonal stub, not an elbow — which the `stroke-linejoin` bevel assumes.)
|
|
637
|
+
return elbowPath(start, end, { mid: opts.mid });
|
|
390
638
|
}
|
|
391
639
|
|
|
640
|
+
/**
|
|
641
|
+
* @param {ConnectorOptions} opts
|
|
642
|
+
* @returns {string}
|
|
643
|
+
*/
|
|
392
644
|
export function connectorCurve(opts = {}) {
|
|
393
645
|
const { dx, dy } = validateOffset(opts);
|
|
394
646
|
if (dx === 0 && dy === 0) return '';
|
|
@@ -400,6 +652,26 @@ export function connectorCurve(opts = {}) {
|
|
|
400
652
|
return curvePath(start, end, { curvature: 0.35 });
|
|
401
653
|
}
|
|
402
654
|
|
|
655
|
+
// subject.type → its path builder. A flat dispatch table (replaces an 11-arm
|
|
656
|
+
// if/else) keyed by the SubjectType union; an unknown type throws below. (Q10.)
|
|
657
|
+
const SUBJECT_BUILDERS = {
|
|
658
|
+
circle: circleSubjectPath,
|
|
659
|
+
rect: rectSubjectPath,
|
|
660
|
+
threshold: thresholdPath,
|
|
661
|
+
bracket: bracketSubjectPath,
|
|
662
|
+
band: bandSubjectPath,
|
|
663
|
+
slope: slopeSubjectPath,
|
|
664
|
+
compare: comparisonBracePath,
|
|
665
|
+
cluster: outlierClusterPath,
|
|
666
|
+
axis: axisThresholdPath,
|
|
667
|
+
timeline: timelineEventPath,
|
|
668
|
+
evidence: evidenceMarkerPath,
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* @param {AnnotationPartsOptions} [opts]
|
|
673
|
+
* @returns {AnnotationParts}
|
|
674
|
+
*/
|
|
403
675
|
export function annotationParts(opts = {}) {
|
|
404
676
|
const type = opts.type ?? 'callout';
|
|
405
677
|
const transform = annotationTransform({ x: opts.x ?? 0, y: opts.y ?? 0 });
|
|
@@ -416,18 +688,11 @@ export function annotationParts(opts = {}) {
|
|
|
416
688
|
const note = noteTransform({ dx, dy });
|
|
417
689
|
let subject = '';
|
|
418
690
|
|
|
419
|
-
if (opts.subject
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
else if (opts.subject?.type === 'slope') subject = slopeSubjectPath(opts.subject);
|
|
425
|
-
else if (opts.subject?.type === 'compare') subject = comparisonBracePath(opts.subject);
|
|
426
|
-
else if (opts.subject?.type === 'cluster') subject = outlierClusterPath(opts.subject);
|
|
427
|
-
else if (opts.subject?.type === 'axis') subject = axisThresholdPath(opts.subject);
|
|
428
|
-
else if (opts.subject?.type === 'timeline') subject = timelineEventPath(opts.subject);
|
|
429
|
-
else if (opts.subject?.type === 'evidence') subject = evidenceMarkerPath(opts.subject);
|
|
430
|
-
else if (opts.subject != null) throw new TypeError('unsupported subject.type');
|
|
691
|
+
if (opts.subject != null) {
|
|
692
|
+
const build = SUBJECT_BUILDERS[opts.subject.type];
|
|
693
|
+
if (!build) throw new TypeError('unsupported subject.type');
|
|
694
|
+
subject = build(opts.subject);
|
|
695
|
+
}
|
|
431
696
|
|
|
432
697
|
return { transform, subject, connector, note };
|
|
433
698
|
}
|
|
@@ -442,6 +707,10 @@ export function annotationParts(opts = {}) {
|
|
|
442
707
|
* `items`: `[{ pos, size }]` — `pos` is the desired centre coordinate along the
|
|
443
708
|
* axis, `size` the label's extent along it. Returns the adjusted centre per
|
|
444
709
|
* input item, in the original order.
|
|
710
|
+
*
|
|
711
|
+
* @param {DeclutterLabelItem[]} items
|
|
712
|
+
* @param {DeclutterLabelsOptions} [opts]
|
|
713
|
+
* @returns {number[]}
|
|
445
714
|
*/
|
|
446
715
|
export function declutterLabels(items, opts = {}) {
|
|
447
716
|
if (!Array.isArray(items)) throw new TypeError('items must be an array');
|
|
@@ -470,7 +739,7 @@ export function declutterLabels(items, opts = {}) {
|
|
|
470
739
|
}
|
|
471
740
|
|
|
472
741
|
const out = new Array(nodes.length);
|
|
473
|
-
for (const n of nodes) out[n.index] =
|
|
742
|
+
for (const n of nodes) out[n.index] = roundNumber(n.pos);
|
|
474
743
|
return out;
|
|
475
744
|
}
|
|
476
745
|
|
|
@@ -488,6 +757,10 @@ export function declutterLabels(items, opts = {}) {
|
|
|
488
757
|
* in input order, the placed label point `{x, y}`, the echoed `anchor` and
|
|
489
758
|
* `key`, and the leader path `d` (anchor → label; `''` if they coincide) ready
|
|
490
759
|
* for a `<path class="ui-annotation__connector">`.
|
|
760
|
+
*
|
|
761
|
+
* @param {DirectLabelItem[]} items
|
|
762
|
+
* @param {DirectLabelsOptions} [opts]
|
|
763
|
+
* @returns {DirectLabel[]}
|
|
491
764
|
*/
|
|
492
765
|
export function directLabels(items, opts = {}) {
|
|
493
766
|
if (!Array.isArray(items)) throw new TypeError('items must be an array');
|
|
@@ -512,9 +785,9 @@ export function directLabels(items, opts = {}) {
|
|
|
512
785
|
? ''
|
|
513
786
|
: connectorPath({ from: a.anchor, to: labelPoint, shape });
|
|
514
787
|
return {
|
|
515
|
-
x:
|
|
516
|
-
y:
|
|
517
|
-
anchor: { x:
|
|
788
|
+
x: roundNumber(labelPoint.x),
|
|
789
|
+
y: roundNumber(labelPoint.y),
|
|
790
|
+
anchor: { x: roundNumber(a.anchor.x), y: roundNumber(a.anchor.y) },
|
|
518
791
|
key: a.key,
|
|
519
792
|
d,
|
|
520
793
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image carousel / gallery, built on CSS scroll-snap so touch + trackpad
|
|
3
|
+
* swipe (and momentum) are the browser's, not hand-rolled. This wires the
|
|
4
|
+
* parts scroll-snap can't do alone: prev/next buttons, keyboard nav, a
|
|
5
|
+
* thumbnail strip, the position counter, and ARIA — keeping a JS index in
|
|
6
|
+
* sync with the scroll position both ways.
|
|
7
|
+
*
|
|
8
|
+
* Markup: `[data-bronto-carousel]` containing a `.ui-carousel__viewport`
|
|
9
|
+
* of `.ui-carousel__slide` children; optionally
|
|
10
|
+
* `[data-bronto-carousel-prev]` / `[data-bronto-carousel-next]` controls,
|
|
11
|
+
* a `.ui-carousel__thumbs` list of `.ui-carousel__thumb` buttons, and a
|
|
12
|
+
* `.ui-carousel__status` counter slot. Add `data-bronto-carousel-loop` to
|
|
13
|
+
* wrap at the ends, `data-bronto-carousel-label` to name the region.
|
|
14
|
+
*
|
|
15
|
+
* A full-screen **lightbox** is the same markup inside a native
|
|
16
|
+
* `<dialog class="ui-lightbox">` opened by {@link initDialog}: the
|
|
17
|
+
* `<dialog>` provides the top layer, focus-trap, Escape and focus-return,
|
|
18
|
+
* so this behavior never touches focus management.
|
|
19
|
+
*
|
|
20
|
+
* Emits `bronto:change` ({ detail: { index } }) on every index change
|
|
21
|
+
* (button, key, thumbnail, or swipe). SSR-safe, idempotent per carousel;
|
|
22
|
+
* returns a cleanup function.
|
|
23
|
+
*
|
|
24
|
+
* @param {import('./internal.js').DelegateOpts} [opts]
|
|
25
|
+
* @returns {import('./internal.js').Cleanup}
|
|
26
|
+
*/
|
|
27
|
+
export function initCarousel({ root }?: import("./internal.js").DelegateOpts): import("./internal.js").Cleanup;
|
|
28
|
+
//# sourceMappingURL=carousel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"carousel.d.ts","sourceRoot":"","sources":["carousel.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAuK3C"}
|