explico 0.4.0 → 0.6.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/CHANGELOG.md +382 -1
- package/README.md +103 -8
- package/dist/compiler/astro.d.ts +9 -1
- package/dist/compiler/astro.js +182 -3
- package/dist/compiler/cli.d.ts +13 -0
- package/dist/compiler/cli.js +28 -4
- package/dist/compiler/collections.d.ts +3 -2
- package/dist/compiler/collections.js +28 -1
- package/dist/compiler/course-config.d.ts +88 -1
- package/dist/compiler/course-config.js +35 -1
- package/dist/compiler/exports/standalone-html.d.ts +34 -0
- package/dist/compiler/exports/standalone-html.js +803 -0
- package/dist/compiler/manifest.d.ts +98 -6
- package/dist/compiler/manifest.js +154 -17
- package/dist/compiler/resolution-report.d.ts +4 -0
- package/dist/reference/base-abbreviations.d.mts +30 -0
- package/dist/reference/base-abbreviations.mjs +60 -0
- package/dist/reference/base-operators.d.mts +15 -0
- package/dist/reference/base-operators.mjs +40 -0
- package/dist/reference/base-roman-labels.d.mts +35 -0
- package/dist/reference/base-roman-labels.mjs +43 -0
- package/dist/reference/consistency.d.ts +8 -2
- package/dist/reference/consistency.js +50 -3
- package/dist/reference/diagrams-validate.d.ts +21 -0
- package/dist/reference/diagrams-validate.js +13 -0
- package/dist/reference/equations.d.mts +10 -15
- package/dist/reference/equations.mjs +67 -14
- package/dist/reference/gate-abbreviations.d.ts +17 -0
- package/dist/reference/gate-abbreviations.js +64 -0
- package/dist/reference/gate-heading-length.d.ts +12 -0
- package/dist/reference/gate-heading-length.js +79 -0
- package/dist/reference/gate-math.d.ts +32 -5
- package/dist/reference/gate-math.js +6 -2
- package/dist/reference/gate-prose-notation.d.ts +60 -0
- package/dist/reference/gate-prose-notation.js +125 -0
- package/dist/reference/keyed-float-validate.d.ts +5 -5
- package/dist/reference/keyed-jsx-floats.d.mts +7 -12
- package/dist/reference/keyed-jsx-floats.mjs +50 -25
- package/dist/reference/knowledge-checks-validate.d.ts +35 -0
- package/dist/reference/knowledge-checks-validate.js +78 -0
- package/dist/reference/knowledge-checks.d.mts +25 -0
- package/dist/reference/knowledge-checks.mjs +45 -0
- package/dist/reference/lab-math-scope.d.ts +9 -1
- package/dist/reference/lab-math-scope.js +32 -4
- package/dist/reference/math-glyphs.d.mts +42 -0
- package/dist/reference/math-glyphs.mjs +548 -40
- package/dist/reference/mdx-attributes.d.mts +13 -0
- package/dist/reference/mdx-attributes.mjs +38 -0
- package/dist/reference/mixed-content.d.ts +17 -0
- package/dist/reference/mixed-content.js +29 -0
- package/dist/reference/page-notation.d.ts +52 -0
- package/dist/reference/page-notation.js +171 -0
- package/dist/reference/raw-floats-validate.d.ts +18 -0
- package/dist/reference/raw-floats-validate.js +53 -0
- package/dist/reference/raw-floats.d.mts +18 -0
- package/dist/reference/raw-floats.mjs +129 -0
- package/dist/reference/rehype-heading-anchors.d.mts +1 -1
- package/dist/reference/rehype-heading-anchors.mjs +107 -1
- package/dist/reference/rehype-table-header-labels.d.mts +26 -0
- package/dist/reference/rehype-table-header-labels.mjs +152 -0
- package/dist/reference/remark-abbreviations.d.mts +7 -0
- package/dist/reference/remark-abbreviations.mjs +174 -0
- package/dist/reference/remark-citation.d.mts +5 -1
- package/dist/reference/remark-citation.mjs +0 -0
- package/dist/reference/remark-memo.d.mts +16 -0
- package/dist/reference/remark-memo.mjs +339 -0
- package/dist/reference/remark-notation.d.mts +57 -9
- package/dist/reference/remark-notation.mjs +354 -42
- package/dist/reference/remark-short-note.d.mts +4 -0
- package/dist/reference/remark-short-note.mjs +237 -0
- package/dist/reference/types.d.ts +16 -1
- package/dist/reference/units-vocab.js +4 -0
- package/docs/VERSIONING.md +53 -4
- package/docs/authoring/README.md +10 -0
- package/docs/authoring/agents.md +17 -2
- package/docs/authoring/components.md +138 -0
- package/docs/authoring/migrating.md +275 -7
- package/docs/authoring/notation.md +615 -1
- package/docs/authoring/structure-rules.md +69 -0
- package/docs/authoring/structure.md +120 -8
- package/docs/authoring/visualizations.md +36 -3
- package/package.json +5 -2
- package/src/compiler/astro.ts +208 -3
- package/src/compiler/cli.ts +29 -2
- package/src/compiler/collections.ts +45 -4
- package/src/compiler/course-config.ts +132 -0
- package/src/compiler/exports/standalone-html.ts +963 -0
- package/src/compiler/manifest.ts +281 -22
- package/src/components/HoverPanel.astro +45 -4
- package/src/components/abbreviation/AbbreviationGlossary.astro +70 -0
- package/src/components/abbreviation/AbbreviationLayer.astro +127 -0
- package/src/components/assessments/AssessmentRunner.tsx +52 -17
- package/src/components/assessments/AssessmentSet.astro +98 -14
- package/src/components/assessments/RenderedContent.tsx +55 -0
- package/src/components/assessments/assessment-randomization.ts +16 -0
- package/src/components/diagram/Diagram.astro +409 -103
- package/src/components/disclosure/hover-preview.ts +202 -0
- package/src/components/disclosure/persisted-disclosure.ts +66 -0
- package/src/components/examples/CompactExamples.astro +2 -0
- package/src/components/figure/Figure.astro +279 -10
- package/src/components/memo/Memo.astro +453 -0
- package/src/components/memo/ShortNote.astro +223 -0
- package/src/components/notation/NotationFormula.astro +18 -1
- package/src/components/notation/NotationLayer.astro +260 -83
- package/src/components/notation/render-notation-math.ts +39 -2
- package/src/components/notation/safe-math-to-react.ts +50 -0
- package/src/components/reference/FloatRefLayer.astro +233 -15
- package/src/components/starlight/CollapsibleSections.astro +461 -0
- package/src/components/starlight/DiagramEnhancer.astro +385 -0
- package/src/components/starlight/HeadingAnchorEnhancer.astro +5 -17
- package/src/components/starlight/KeyedFloatEnhancer.astro +81 -3
- package/src/components/starlight/LayoutHeader.astro +50 -0
- package/src/components/starlight/LayoutSocialIcons.astro +41 -2
- package/src/components/starlight/LessonExportActions.astro +436 -0
- package/src/components/starlight/LessonFooter.astro +30 -3
- package/src/components/starlight/section-parts.ts +31 -0
- package/src/components/table/Table.astro +293 -7
- package/src/components/table/TableOverflowExpander.astro +489 -0
- package/src/content-config.ts +36 -1
- package/src/reference/base-abbreviations.mjs +60 -0
- package/src/reference/base-operators.mjs +40 -0
- package/src/reference/base-roman-labels.mjs +43 -0
- package/src/reference/consistency.ts +73 -2
- package/src/reference/diagrams-validate.ts +40 -0
- package/src/reference/equations.mjs +67 -14
- package/src/reference/gate-abbreviations.ts +128 -0
- package/src/reference/gate-heading-length.ts +131 -0
- package/src/reference/gate-math.ts +32 -7
- package/src/reference/gate-prose-notation.ts +224 -0
- package/src/reference/keyed-float-validate.ts +5 -5
- package/src/reference/keyed-jsx-floats.mjs +50 -25
- package/src/reference/knowledge-checks-validate.ts +130 -0
- package/src/reference/knowledge-checks.mjs +45 -0
- package/src/reference/lab-math-scope.ts +45 -3
- package/src/reference/math-glyphs.mjs +548 -40
- package/src/reference/mdx-attributes.mjs +38 -0
- package/src/reference/mixed-content.ts +69 -0
- package/src/reference/page-notation.ts +252 -0
- package/src/reference/raw-floats-validate.ts +103 -0
- package/src/reference/raw-floats.mjs +129 -0
- package/src/reference/rehype-heading-anchors.mjs +107 -1
- package/src/reference/rehype-table-header-labels.mjs +152 -0
- package/src/reference/remark-abbreviations.mjs +174 -0
- package/src/reference/remark-citation.mjs +0 -0
- package/src/reference/remark-memo.mjs +339 -0
- package/src/reference/remark-notation.mjs +354 -42
- package/src/reference/remark-short-note.mjs +237 -0
- package/src/reference/types.ts +16 -0
- package/src/reference/units-vocab.ts +4 -0
- package/src/styles/global.css +996 -50
|
@@ -26,6 +26,10 @@ import { renderNotationFormula } from '../notation/render-notation-math';
|
|
|
26
26
|
import type { SafeMathNode as SafeMathNodeType } from '../notation/render-notation-math';
|
|
27
27
|
import SafeMathNode from '../notation/SafeMathNode.astro';
|
|
28
28
|
import type { GlyphScopeEntry } from '../../reference/gloss';
|
|
29
|
+
import {
|
|
30
|
+
notationKeysInMathNodes,
|
|
31
|
+
registerPageNotationDependencies,
|
|
32
|
+
} from '../../reference/page-notation';
|
|
29
33
|
|
|
30
34
|
export interface DiagramNode {
|
|
31
35
|
readonly id: string;
|
|
@@ -53,12 +57,19 @@ export interface Props {
|
|
|
53
57
|
/** Glyph scope `formula` resolves against — omit if no node uses `formula`. */
|
|
54
58
|
scope?: readonly GlyphScopeEntry[];
|
|
55
59
|
direction?: 'TB' | 'LR';
|
|
60
|
+
/** Computed by `remark-notation.mjs` for a top-level lesson diagram. */
|
|
61
|
+
number?: string;
|
|
62
|
+
/** Computed by `remark-notation.mjs` for a top-level lesson diagram. */
|
|
63
|
+
anchorId?: string;
|
|
64
|
+
/** Author-chosen state for a reader with nothing saved yet. Default: `true`. */
|
|
65
|
+
defaultOpen?: boolean;
|
|
66
|
+
/** Persist the reader's open/closed choice across visits. Default: `true`. */
|
|
67
|
+
rememberState?: boolean;
|
|
56
68
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* hand-written sentence usually reads better for a screen-reader user.
|
|
69
|
+
* Emit a build warning when the laid-out SVG is wider than this many pixels.
|
|
70
|
+
* Set `false` only when horizontal overflow is deliberate. Default: `800`.
|
|
60
71
|
*/
|
|
61
|
-
|
|
72
|
+
warnAboveWidth?: number | false;
|
|
62
73
|
}
|
|
63
74
|
|
|
64
75
|
const {
|
|
@@ -68,7 +79,11 @@ const {
|
|
|
68
79
|
edges,
|
|
69
80
|
scope = [],
|
|
70
81
|
direction = 'TB',
|
|
71
|
-
|
|
82
|
+
number,
|
|
83
|
+
anchorId,
|
|
84
|
+
defaultOpen = true,
|
|
85
|
+
rememberState = true,
|
|
86
|
+
warnAboveWidth = 800,
|
|
72
87
|
} = Astro.props;
|
|
73
88
|
|
|
74
89
|
const idPattern = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
@@ -78,6 +93,17 @@ if (!idPattern.test(id)) {
|
|
|
78
93
|
if (nodes.length === 0) {
|
|
79
94
|
throw new Error(`Diagram "${id}" has no nodes.`);
|
|
80
95
|
}
|
|
96
|
+
if ((number && !anchorId) || (!number && anchorId)) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Diagram "${id}" must receive both computed \`number\` and \`anchorId\`, or neither.`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
if (
|
|
102
|
+
warnAboveWidth !== false &&
|
|
103
|
+
(!Number.isFinite(warnAboveWidth) || warnAboveWidth <= 0)
|
|
104
|
+
) {
|
|
105
|
+
throw new Error(`Diagram "${id}" requires a positive \`warnAboveWidth\`.`);
|
|
106
|
+
}
|
|
81
107
|
|
|
82
108
|
interface RenderedNode extends DiagramNode {
|
|
83
109
|
readonly mathNodes?: readonly SafeMathNodeType[];
|
|
@@ -114,6 +140,15 @@ const rendered: RenderedNode[] = nodes.map((node) => {
|
|
|
114
140
|
return { ...node, mathNodes };
|
|
115
141
|
});
|
|
116
142
|
|
|
143
|
+
for (const node of rendered) {
|
|
144
|
+
if (!node.mathNodes) continue;
|
|
145
|
+
registerPageNotationDependencies(
|
|
146
|
+
Astro.locals,
|
|
147
|
+
notationKeysInMathNodes(node.mathNodes),
|
|
148
|
+
`Diagram "${id}" node "${node.id}" formula "${node.formula}"`,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
117
152
|
const sized = rendered.map((node) => ({
|
|
118
153
|
node,
|
|
119
154
|
box:
|
|
@@ -134,11 +169,18 @@ const layout = layoutDiagram(
|
|
|
134
169
|
const nodeById = new Map(rendered.map((node) => [node.id, node]));
|
|
135
170
|
const laidOutById = new Map(layout.nodes.map((node) => [node.id, node]));
|
|
136
171
|
const markerId = `diagram-arrow-${id}`;
|
|
172
|
+
const legacyAnchorId = `diagram-${id}`;
|
|
173
|
+
const renderedAnchorId = anchorId ?? legacyAnchorId;
|
|
174
|
+
const viewportId = `${legacyAnchorId}-viewport`;
|
|
137
175
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
176
|
+
if (warnAboveWidth !== false && layout.width > warnAboveWidth) {
|
|
177
|
+
console.warn(
|
|
178
|
+
`[explico/Diagram] "${id}" lays out at ${layout.width}px wide, above the ` +
|
|
179
|
+
`${warnAboveWidth}px authoring threshold. It will scroll and can be expanded ` +
|
|
180
|
+
`by readers, but consider recreating the graph with direction="TB", shorter ` +
|
|
181
|
+
`labels, or explicit node sizes. Set warnAboveWidth={false} only when the ` +
|
|
182
|
+
`horizontal overflow is intentional.`,
|
|
183
|
+
);
|
|
142
184
|
}
|
|
143
185
|
|
|
144
186
|
function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
@@ -148,100 +190,334 @@ function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
|
148
190
|
}
|
|
149
191
|
---
|
|
150
192
|
|
|
151
|
-
<figure
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
193
|
+
<figure
|
|
194
|
+
class="diagram"
|
|
195
|
+
id={renderedAnchorId}
|
|
196
|
+
aria-labelledby={`${id}-caption`}
|
|
197
|
+
data-dia-number={number}
|
|
198
|
+
data-dia-key={number ? id : undefined}
|
|
199
|
+
data-diagram-width={layout.width}
|
|
200
|
+
data-diagram-expandable
|
|
201
|
+
>
|
|
202
|
+
<div class="diagram__titlebar">
|
|
203
|
+
<details
|
|
204
|
+
class="diagram__details"
|
|
205
|
+
data-diagram-details
|
|
206
|
+
data-remember-state={String(rememberState)}
|
|
207
|
+
data-state={defaultOpen ? 'open' : 'closed'}
|
|
208
|
+
open={defaultOpen}
|
|
209
|
+
>
|
|
210
|
+
<summary class="diagram__summary" id={`${id}-caption`}>
|
|
211
|
+
{number && <span class="diagram__number">Diagram {number}</span>}
|
|
212
|
+
<span class="diagram__caption-text">{label}</span>
|
|
213
|
+
</summary>
|
|
214
|
+
<div class="diagram__body" data-diagram-body>
|
|
215
|
+
<div
|
|
216
|
+
class="diagram-stage"
|
|
217
|
+
id={renderedAnchorId === legacyAnchorId ? undefined : legacyAnchorId}
|
|
218
|
+
>
|
|
219
|
+
<div
|
|
220
|
+
id={viewportId}
|
|
221
|
+
class="diagram-scroll"
|
|
222
|
+
tabindex="0"
|
|
223
|
+
role="group"
|
|
224
|
+
aria-labelledby={`${id}-caption`}
|
|
225
|
+
>
|
|
226
|
+
<div
|
|
227
|
+
class="diagram-canvas"
|
|
228
|
+
style={`--diagram-print-ratio: ${layout.width} / ${layout.height}; width: ${layout.width}px; height: ${layout.height}px;`}
|
|
229
|
+
>
|
|
230
|
+
<svg
|
|
231
|
+
viewBox={`0 0 ${layout.width} ${layout.height}`}
|
|
232
|
+
width="100%"
|
|
233
|
+
height="100%"
|
|
234
|
+
>
|
|
235
|
+
<defs>
|
|
236
|
+
<marker
|
|
237
|
+
id={markerId}
|
|
238
|
+
viewBox="0 0 10 10"
|
|
239
|
+
refX="9"
|
|
240
|
+
refY="5"
|
|
241
|
+
markerWidth="7"
|
|
242
|
+
markerHeight="7"
|
|
243
|
+
orient="auto-start-reverse"
|
|
244
|
+
>
|
|
245
|
+
<path
|
|
246
|
+
d="M 0 0 L 10 5 L 0 10 z"
|
|
247
|
+
class="diagram-arrowhead"
|
|
248
|
+
/>
|
|
249
|
+
</marker>
|
|
250
|
+
</defs>
|
|
251
|
+
|
|
252
|
+
{
|
|
253
|
+
layout.edges.map((edge) => (
|
|
254
|
+
<path
|
|
255
|
+
d={pathFrom(edge.points)}
|
|
256
|
+
class="diagram-edge"
|
|
257
|
+
marker-end={`url(#${markerId})`}
|
|
258
|
+
/>
|
|
259
|
+
))
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
{
|
|
263
|
+
layout.nodes.map((position) => {
|
|
264
|
+
const node = nodeById.get(position.id)!;
|
|
265
|
+
return (
|
|
266
|
+
<g
|
|
267
|
+
transform={`translate(${position.x}, ${position.y})`}
|
|
268
|
+
class="diagram-node"
|
|
269
|
+
>
|
|
270
|
+
<rect
|
|
271
|
+
width={position.width}
|
|
272
|
+
height={position.height}
|
|
273
|
+
rx="8"
|
|
274
|
+
ry="8"
|
|
275
|
+
/>
|
|
276
|
+
<foreignObject
|
|
277
|
+
width={position.width}
|
|
278
|
+
height={position.height}
|
|
279
|
+
>
|
|
280
|
+
<div
|
|
281
|
+
xmlns="http://www.w3.org/1999/xhtml"
|
|
282
|
+
class="diagram-node-content"
|
|
283
|
+
>
|
|
284
|
+
{
|
|
285
|
+
node.text && (
|
|
286
|
+
<span class="diagram-node-text">{node.text}</span>
|
|
287
|
+
)
|
|
288
|
+
}
|
|
289
|
+
{
|
|
290
|
+
node.mathNodes && (
|
|
291
|
+
<span class="diagram-node-formula notation-math">
|
|
292
|
+
{node.mathNodes.map((mathNode) => (
|
|
293
|
+
<SafeMathNode node={mathNode} />
|
|
294
|
+
))}
|
|
295
|
+
</span>
|
|
296
|
+
)
|
|
297
|
+
}
|
|
298
|
+
</div>
|
|
299
|
+
</foreignObject>
|
|
300
|
+
</g>
|
|
301
|
+
);
|
|
302
|
+
})
|
|
303
|
+
}
|
|
304
|
+
</svg>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
</div>
|
|
309
|
+
</details>
|
|
310
|
+
|
|
311
|
+
<a
|
|
312
|
+
class="diagram__title-anchor"
|
|
313
|
+
href={`#${renderedAnchorId}`}
|
|
314
|
+
aria-label={`${number ? `Diagram ${number}: ` : ''}${label}`}
|
|
315
|
+
>
|
|
316
|
+
<svg
|
|
317
|
+
aria-hidden="true"
|
|
318
|
+
width="16"
|
|
319
|
+
height="16"
|
|
320
|
+
viewBox="0 0 24 24"
|
|
321
|
+
fill="currentColor"
|
|
322
|
+
><path
|
|
323
|
+
d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 1 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 0 0-1.42-1.42m8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 1 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3.88-3.89a4.49 4.49 0 0 0 0-6.33M8.83 15.17a1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.92-4.92a1 1 0 1 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42"
|
|
324
|
+
></path></svg
|
|
168
325
|
>
|
|
169
|
-
|
|
170
|
-
</marker>
|
|
171
|
-
</defs>
|
|
172
|
-
|
|
173
|
-
{
|
|
174
|
-
layout.edges.map((edge) => (
|
|
175
|
-
<path
|
|
176
|
-
d={pathFrom(edge.points)}
|
|
177
|
-
class="diagram-edge"
|
|
178
|
-
marker-end={`url(#${markerId})`}
|
|
179
|
-
/>
|
|
180
|
-
))
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
{
|
|
184
|
-
layout.nodes.map((position) => {
|
|
185
|
-
const node = nodeById.get(position.id)!;
|
|
186
|
-
return (
|
|
187
|
-
<g transform={`translate(${position.x}, ${position.y})`} class="diagram-node">
|
|
188
|
-
<rect width={position.width} height={position.height} rx="8" ry="8" />
|
|
189
|
-
<foreignObject width={position.width} height={position.height}>
|
|
190
|
-
<div xmlns="http://www.w3.org/1999/xhtml" class="diagram-node-content">
|
|
191
|
-
{node.text && <span class="diagram-node-text">{node.text}</span>}
|
|
192
|
-
{node.mathNodes && (
|
|
193
|
-
<span class="diagram-node-formula notation-math">
|
|
194
|
-
{node.mathNodes.map((mathNode) => (
|
|
195
|
-
<SafeMathNode node={mathNode} />
|
|
196
|
-
))}
|
|
197
|
-
</span>
|
|
198
|
-
)}
|
|
199
|
-
</div>
|
|
200
|
-
</foreignObject>
|
|
201
|
-
</g>
|
|
202
|
-
);
|
|
203
|
-
})
|
|
204
|
-
}
|
|
205
|
-
</svg>
|
|
206
|
-
</div>
|
|
326
|
+
</a>
|
|
207
327
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
</p>
|
|
229
|
-
)}
|
|
230
|
-
</Fragment>
|
|
231
|
-
)
|
|
232
|
-
}
|
|
233
|
-
</details>
|
|
328
|
+
<div class="diagram-toolbar" data-diagram-toolbar hidden>
|
|
329
|
+
<button
|
|
330
|
+
type="button"
|
|
331
|
+
class="diagram-expand-button"
|
|
332
|
+
data-diagram-expand
|
|
333
|
+
aria-controls={viewportId}
|
|
334
|
+
aria-expanded="false"
|
|
335
|
+
title="Expand diagram horizontally"
|
|
336
|
+
>
|
|
337
|
+
<svg aria-hidden="true" viewBox="0 0 24 24">
|
|
338
|
+
<path class="diagram-expand-icon" d="M3 12h18M8 7l-5 5 5 5M16 7l5 5-5 5" />
|
|
339
|
+
<path
|
|
340
|
+
class="diagram-shrink-icon"
|
|
341
|
+
d="M3 12h7M7 9l3 3-3 3M21 12h-7M17 9l-3 3 3 3"
|
|
342
|
+
/>
|
|
343
|
+
</svg>
|
|
344
|
+
<span class="sr-only">Expand {label}</span>
|
|
345
|
+
</button>
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
234
348
|
</figure>
|
|
235
349
|
|
|
236
350
|
<style>
|
|
237
351
|
@layer starlight.components {
|
|
238
352
|
.diagram {
|
|
353
|
+
position: relative;
|
|
239
354
|
margin: 1.5rem 0;
|
|
355
|
+
max-width: 100%;
|
|
356
|
+
contain: inline-size;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.diagram__titlebar {
|
|
360
|
+
position: relative;
|
|
240
361
|
}
|
|
241
362
|
|
|
242
|
-
.
|
|
243
|
-
|
|
363
|
+
.diagram__details {
|
|
364
|
+
border-inline-start: 0;
|
|
365
|
+
padding-inline-start: 0;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.diagram__summary {
|
|
369
|
+
position: relative;
|
|
370
|
+
min-height: 1.75rem;
|
|
371
|
+
padding-inline-end: 4rem;
|
|
244
372
|
font-weight: 600;
|
|
373
|
+
cursor: pointer;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.diagram__summary::before {
|
|
377
|
+
position: absolute;
|
|
378
|
+
top: 50%;
|
|
379
|
+
left: -1.35em;
|
|
380
|
+
margin: 0;
|
|
381
|
+
transform: translateY(-50%);
|
|
382
|
+
opacity: 0;
|
|
383
|
+
transition:
|
|
384
|
+
opacity 150ms ease 700ms,
|
|
385
|
+
transform 150ms ease;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.diagram__details[data-state='open'] > .diagram__summary::before {
|
|
389
|
+
transform: translateY(-50%) rotateZ(90deg);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.diagram__details[data-state='closed'] > .diagram__summary::before {
|
|
393
|
+
opacity: 1;
|
|
394
|
+
transition: none;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.diagram__summary:hover::before,
|
|
398
|
+
.diagram__summary:focus-visible::before {
|
|
399
|
+
opacity: 1;
|
|
400
|
+
transition: opacity 100ms ease;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.diagram__body {
|
|
404
|
+
overflow: hidden;
|
|
405
|
+
transition: max-height 220ms ease;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.diagram__number {
|
|
409
|
+
color: var(--sl-color-text-accent);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.diagram__caption-text::before {
|
|
413
|
+
content: ' — ';
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.diagram__summary > .diagram__caption-text:first-child::before {
|
|
417
|
+
content: none;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.diagram__title-anchor {
|
|
421
|
+
position: absolute;
|
|
422
|
+
top: 0.1rem;
|
|
423
|
+
inset-inline-end: 0;
|
|
424
|
+
display: inline-flex;
|
|
425
|
+
width: 1.5rem;
|
|
426
|
+
height: 1.5rem;
|
|
427
|
+
align-items: center;
|
|
428
|
+
justify-content: center;
|
|
429
|
+
color: var(--sl-color-gray-3);
|
|
430
|
+
text-decoration: none;
|
|
431
|
+
opacity: 1;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.diagram[data-diagram-overflow='true'] .diagram__title-anchor {
|
|
435
|
+
inset-inline-end: 2rem;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.diagram__title-anchor svg {
|
|
439
|
+
width: 0.9rem;
|
|
440
|
+
height: 0.9rem;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.diagram__title-anchor:hover,
|
|
444
|
+
.diagram__title-anchor:focus-visible {
|
|
445
|
+
color: var(--sl-color-text-accent);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.diagram__title-anchor:focus-visible {
|
|
449
|
+
outline: 2px solid var(--sl-color-accent);
|
|
450
|
+
outline-offset: 0.1rem;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
@media (hover: hover) {
|
|
454
|
+
.diagram__title-anchor {
|
|
455
|
+
opacity: 0;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.diagram__details:has(> .diagram__summary:hover) ~ .diagram__title-anchor,
|
|
459
|
+
.diagram__details:has(> .diagram__summary:focus-visible)
|
|
460
|
+
~ .diagram__title-anchor,
|
|
461
|
+
.diagram__title-anchor:hover,
|
|
462
|
+
.diagram__title-anchor:focus-visible {
|
|
463
|
+
opacity: 1;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.diagram-stage {
|
|
468
|
+
min-width: 0;
|
|
469
|
+
max-width: 100%;
|
|
470
|
+
overflow: hidden;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.diagram-toolbar {
|
|
474
|
+
position: absolute;
|
|
475
|
+
z-index: 2;
|
|
476
|
+
top: -0.25rem;
|
|
477
|
+
inset-inline-end: 0;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.diagram-toolbar[hidden] {
|
|
481
|
+
display: none;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.diagram-expand-button {
|
|
485
|
+
display: inline-flex;
|
|
486
|
+
width: 1.75rem;
|
|
487
|
+
height: 1.75rem;
|
|
488
|
+
margin: 0;
|
|
489
|
+
align-items: center;
|
|
490
|
+
justify-content: center;
|
|
491
|
+
color: var(--sl-color-gray-2);
|
|
492
|
+
border: 0;
|
|
493
|
+
border-radius: 0.25rem;
|
|
494
|
+
background: transparent;
|
|
495
|
+
cursor: pointer;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.diagram-expand-button svg {
|
|
499
|
+
width: 1.1rem;
|
|
500
|
+
height: 1.1rem;
|
|
501
|
+
fill: none;
|
|
502
|
+
stroke: currentColor;
|
|
503
|
+
stroke-width: 1.8;
|
|
504
|
+
stroke-linecap: round;
|
|
505
|
+
stroke-linejoin: round;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.diagram-expand-button[aria-expanded='false'] .diagram-shrink-icon,
|
|
509
|
+
.diagram-expand-button[aria-expanded='true'] .diagram-expand-icon {
|
|
510
|
+
display: none;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.diagram-expand-button:hover {
|
|
514
|
+
color: var(--sl-color-text);
|
|
515
|
+
background: var(--sl-color-accent-low);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.diagram-expand-button:focus-visible {
|
|
519
|
+
outline: 2px solid var(--sl-color-accent);
|
|
520
|
+
outline-offset: 1px;
|
|
245
521
|
}
|
|
246
522
|
|
|
247
523
|
/* A wide graph scrolls inside its own box rather than shrinking to
|
|
@@ -250,6 +526,10 @@ function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
|
250
526
|
that: a scrollable region a keyboard user cannot reach is unreachable
|
|
251
527
|
content, not just an awkward one. */
|
|
252
528
|
.diagram-scroll {
|
|
529
|
+
width: 100%;
|
|
530
|
+
min-width: 0;
|
|
531
|
+
max-width: 100%;
|
|
532
|
+
flex: 1 1 auto;
|
|
253
533
|
overflow-x: auto;
|
|
254
534
|
padding-block: 0.15rem;
|
|
255
535
|
}
|
|
@@ -259,11 +539,27 @@ function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
|
259
539
|
outline-offset: 2px;
|
|
260
540
|
}
|
|
261
541
|
|
|
262
|
-
.diagram svg {
|
|
542
|
+
.diagram-canvas > svg {
|
|
263
543
|
display: block;
|
|
544
|
+
/* Starlight globally constrains SVGs to the content width. That is safe
|
|
545
|
+
for an all-SVG illustration, but this diagram embeds HTML/KaTeX in
|
|
546
|
+
`foreignObject` nodes. WebKit on iOS can scale the SVG geometry while
|
|
547
|
+
leaving that HTML at its unscaled size, which puts formulas outside
|
|
548
|
+
their boxes. Keep the build-time dimensions and let the keyboard-
|
|
549
|
+
reachable wrapper above provide the intended horizontal scroll. */
|
|
550
|
+
max-width: none;
|
|
264
551
|
overflow: visible;
|
|
265
552
|
}
|
|
266
553
|
|
|
554
|
+
.diagram-canvas {
|
|
555
|
+
flex: none;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.diagram.dia-ref-highlight {
|
|
559
|
+
outline: 3px solid var(--sl-color-accent);
|
|
560
|
+
outline-offset: 0.25rem;
|
|
561
|
+
}
|
|
562
|
+
|
|
267
563
|
.diagram-node rect {
|
|
268
564
|
fill: var(--sl-color-gray-7);
|
|
269
565
|
stroke: var(--sl-color-gray-5);
|
|
@@ -299,19 +595,29 @@ function pathFrom(points: readonly { x: number; y: number }[]): string {
|
|
|
299
595
|
fill: var(--sl-color-gray-4);
|
|
300
596
|
}
|
|
301
597
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
598
|
+
@media print {
|
|
599
|
+
.diagram-toolbar,
|
|
600
|
+
.diagram__title-anchor,
|
|
601
|
+
.diagram__summary::before {
|
|
602
|
+
display: none;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
.diagram__number {
|
|
606
|
+
color: inherit;
|
|
607
|
+
}
|
|
307
608
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
609
|
+
.diagram__body {
|
|
610
|
+
display: block !important;
|
|
611
|
+
max-height: none !important;
|
|
612
|
+
overflow: visible !important;
|
|
613
|
+
}
|
|
311
614
|
}
|
|
312
615
|
|
|
313
|
-
|
|
314
|
-
|
|
616
|
+
@media (prefers-reduced-motion: reduce) {
|
|
617
|
+
.diagram__summary::before,
|
|
618
|
+
.diagram__body {
|
|
619
|
+
transition: none;
|
|
620
|
+
}
|
|
315
621
|
}
|
|
316
622
|
}
|
|
317
623
|
</style>
|