explico 0.8.0 → 0.11.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 +1239 -1
- package/README.md +60 -15
- package/dist/compiler/astro.d.ts +6 -1
- package/dist/compiler/cli.d.ts +46 -2
- package/dist/compiler/cli.js +70 -4
- package/dist/compiler/collections.d.ts +35 -2
- package/dist/compiler/collections.js +68 -5
- package/dist/compiler/course-config.d.ts +3 -194
- package/dist/compiler/course-config.js +78 -5
- package/dist/compiler/exports/standalone-html.d.ts +6 -1
- package/dist/compiler/knowledge-version.js +1 -1
- package/dist/compiler/lesson-derivation.d.ts +27 -10
- package/dist/compiler/lesson-derivation.js +23 -8
- package/dist/compiler/logging.d.ts +4 -1
- package/dist/compiler/logging.js +4 -1
- package/dist/compiler/manifest.d.ts +204 -31
- package/dist/compiler/manifest.js +270 -55
- package/dist/compiler/resolution-report.d.ts +6 -1
- package/dist/course-config-Dsnri9Tk.d.ts +464 -0
- package/dist/reference/base-accents.d.mts +26 -0
- package/dist/reference/base-accents.mjs +31 -0
- package/dist/reference/base-roman-labels.d.mts +2 -2
- package/dist/reference/base-roman-labels.mjs +2 -2
- package/dist/reference/consistency.d.ts +14 -2
- package/dist/reference/consistency.js +108 -4
- package/dist/reference/delimiter-size.d.ts +3 -2
- package/dist/reference/diagrams-validate.d.ts +7 -2
- package/dist/reference/diagrams-validate.js +9 -1
- package/dist/reference/equations-validate.d.ts +8 -5
- package/dist/reference/equations-validate.js +1 -0
- package/dist/reference/equations.d.mts +60 -31
- package/dist/reference/equations.mjs +83 -43
- package/dist/reference/examples-validate.d.ts +31 -0
- package/dist/reference/examples-validate.js +48 -0
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/figures-validate.js +4 -1
- package/dist/reference/folds-validate.d.ts +33 -0
- package/dist/reference/folds-validate.js +32 -0
- package/dist/reference/gate-abbreviations.d.ts +3 -1
- package/dist/reference/gate-abbreviations.js +1 -0
- package/dist/reference/gate-course-rules.d.ts +32 -0
- package/dist/reference/gate-course-rules.js +85 -0
- package/dist/reference/gate-heading-length.d.ts +5 -2
- package/dist/reference/gate-heading-length.js +45 -21
- package/dist/reference/gate-heading-structure.d.ts +41 -0
- package/dist/reference/gate-heading-structure.js +113 -0
- package/dist/reference/gate-math-punctuation.d.ts +71 -0
- package/dist/reference/gate-math-punctuation.js +251 -0
- package/dist/reference/gate-math.d.ts +22 -6
- package/dist/reference/gate-math.js +42 -8
- package/dist/reference/gate-part-pages.d.ts +50 -0
- package/dist/reference/gate-part-pages.js +118 -0
- package/dist/reference/gate-prose-notation.d.ts +21 -11
- package/dist/reference/gate-prose-notation.js +25 -7
- package/dist/reference/katex-delimiters.mjs +20 -7
- package/dist/reference/keyed-float-validate.d.ts +27 -10
- package/dist/reference/keyed-float-validate.js +15 -1
- package/dist/reference/keyed-jsx-floats.d.mts +11 -5
- package/dist/reference/keyed-jsx-floats.mjs +73 -20
- package/dist/reference/knowledge-checks-validate.d.ts +1 -1
- package/dist/reference/knowledge-checks.d.mts +3 -1
- package/dist/reference/knowledge-checks.mjs +9 -4
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-slot.d.ts +34 -0
- package/dist/reference/lab-math-slot.js +6 -0
- package/dist/reference/math-glyphs.d.mts +80 -4
- package/dist/reference/math-glyphs.mjs +572 -37
- package/dist/reference/page-notation.d.ts +6 -1
- package/dist/reference/raw-floats-validate.js +1 -1
- package/dist/reference/raw-floats.mjs +1 -1
- package/dist/reference/rehype-heading-anchors.d.mts +14 -0
- package/dist/reference/rehype-heading-anchors.mjs +116 -17
- package/dist/reference/rehype-table-header-labels.d.mts +6 -1
- package/dist/reference/rehype-table-header-labels.mjs +21 -3
- package/dist/reference/remark-asides.d.mts +3 -0
- package/dist/reference/remark-asides.mjs +180 -0
- package/dist/reference/remark-memo.d.mts +3 -1
- package/dist/reference/remark-memo.mjs +42 -11
- package/dist/reference/remark-notation.d.mts +60 -10
- package/dist/reference/remark-notation.mjs +387 -36
- package/dist/reference/render-lab-math.d.ts +4 -26
- package/dist/reference/render-lab-math.js +4 -4
- package/dist/reference/sections-validate.d.ts +27 -0
- package/dist/reference/sections-validate.js +41 -0
- package/dist/reference/sections.d.mts +97 -0
- package/dist/reference/sections.mjs +306 -0
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/types.d.ts +17 -1
- package/dist/reference/unit-words.d.ts +37 -0
- package/dist/reference/unit-words.js +170 -0
- package/dist/rules/catalog.d.ts +176 -0
- package/dist/rules/catalog.js +983 -0
- package/dist/rules/course-rules.d.ts +115 -0
- package/dist/rules/course-rules.js +292 -0
- package/dist/rules/course-rules.schema.json +138 -0
- package/dist/rules/in-effect.d.ts +53 -0
- package/dist/rules/in-effect.js +142 -0
- package/dist/rules/rules.schema.json +1072 -0
- package/dist/rules/settings.d.ts +3 -0
- package/dist/rules/settings.js +290 -0
- package/dist/rules/waivers.d.ts +53 -0
- package/dist/rules/waivers.js +132 -0
- package/dist/session/PreferenceStore.d.ts +5 -0
- package/dist/session/PreferenceStore.js +9 -0
- package/docs/VERSIONING.md +2 -2
- package/docs/authoring/README.md +232 -40
- package/docs/authoring/agents.md +55 -9
- package/docs/authoring/components.md +178 -22
- package/docs/authoring/migrating.md +1096 -2
- package/docs/authoring/notation.md +576 -322
- package/docs/authoring/prose.md +551 -0
- package/docs/authoring/retired.md +35 -0
- package/docs/authoring/structure-rules.md +422 -40
- package/docs/authoring/structure.md +445 -62
- package/docs/authoring/versioning.md +20 -28
- package/docs/authoring/visualizations.md +142 -20
- package/package.json +2 -2
- package/src/compiler/cli.ts +116 -6
- package/src/compiler/collections.ts +111 -7
- package/src/compiler/course-config.ts +273 -34
- package/src/compiler/knowledge-version.ts +1 -1
- package/src/compiler/lesson-derivation.ts +54 -15
- package/src/compiler/logging.ts +8 -2
- package/src/compiler/manifest.ts +573 -104
- package/src/components/BlockHeading.astro +113 -0
- package/src/components/CourseContents.astro +221 -0
- package/src/components/CurriculumMap.astro +5 -6
- package/src/components/FloatIndex.astro +200 -0
- package/src/components/HoverPanel.astro +431 -79
- package/src/components/PartBridge.astro +27 -0
- package/src/components/PartOverview.astro +401 -0
- package/src/components/PartScope.astro +27 -0
- package/src/components/abbreviation/AbbreviationLayer.astro +49 -51
- package/src/components/assessments/AssessmentRunner.tsx +8 -5
- package/src/components/assessments/AssessmentSet.astro +23 -26
- package/src/components/block-heading.ts +146 -0
- package/src/components/card-arrow.ts +243 -0
- package/src/components/card-drag.ts +631 -0
- package/src/components/card-jump.ts +45 -0
- package/src/components/card-manager.ts +1589 -0
- package/src/components/card-memory.ts +177 -0
- package/src/components/card-placement.ts +504 -0
- package/src/components/card-side.ts +336 -0
- package/src/components/card-travel.ts +197 -0
- package/src/components/citation/CitationLayer.astro +77 -76
- package/src/components/diagram/Diagram.astro +161 -316
- package/src/components/disclosure/course-disclosure.ts +24 -0
- package/src/components/disclosure/hover-preview.ts +122 -42
- package/src/components/disclosure/persisted-disclosure.ts +3 -3
- package/src/components/disclosure/print-as-shown.ts +252 -0
- package/src/components/examples/CompactExample.astro +3 -1
- package/src/components/examples/CompactExamples.astro +101 -94
- package/src/components/figure/Figure.astro +174 -274
- package/src/components/figure/FloatCaption.astro +87 -0
- package/src/components/figure/figure-state.ts +58 -0
- package/src/components/figure/figure-tools.ts +87 -0
- package/src/components/float-name.ts +101 -0
- package/src/components/fold/Fold.astro +125 -0
- package/src/components/fold/fold-id.ts +40 -0
- package/src/components/memo/Memo.astro +162 -231
- package/src/components/memo/ShortNote.astro +6 -6
- package/src/components/notation/NotationFormula.astro +5 -1
- package/src/components/notation/NotationGlossary.astro +3 -4
- package/src/components/notation/NotationLayer.astro +169 -162
- package/src/components/notation/NotationMath.astro +10 -1
- package/src/components/reference/FloatRefLayer.astro +485 -423
- package/src/components/starlight/AboutPanel.astro +5 -4
- package/src/components/starlight/CollapsibleSections.astro +207 -93
- package/src/components/starlight/DiagramEnhancer.astro +15 -138
- package/src/components/starlight/HeadingAnchorEnhancer.astro +193 -1
- package/src/components/starlight/KeyedFloatEnhancer.astro +100 -9
- package/src/components/starlight/LayoutHeader.astro +298 -19
- package/src/components/starlight/LayoutPageSidebar.astro +99 -12
- package/src/components/starlight/LayoutPageTitle.astro +120 -0
- package/src/components/starlight/LayoutSidebar.astro +229 -11
- package/src/components/starlight/LessonExportActions.astro +53 -72
- package/src/components/starlight/LessonFooter.astro +26 -4
- package/src/components/starlight/section-parts.ts +15 -2
- package/src/components/starlight/section-summary.ts +181 -0
- package/src/components/table/Table.astro +95 -76
- package/src/components/table/TableOverflowExpander.astro +65 -28
- package/src/content-config.ts +40 -4
- package/src/reference/base-accents.mjs +31 -0
- package/src/reference/base-roman-labels.mjs +2 -2
- package/src/reference/consistency.ts +176 -5
- package/src/reference/delimiter-size.ts +3 -2
- package/src/reference/diagrams-validate.ts +17 -1
- package/src/reference/equations-validate.ts +10 -5
- package/src/reference/equations.mjs +83 -43
- package/src/reference/examples-validate.ts +97 -0
- package/src/reference/figures-validate.ts +6 -1
- package/src/reference/folds-validate.ts +65 -0
- package/src/reference/gate-abbreviations.ts +1 -0
- package/src/reference/gate-course-rules.ts +134 -0
- package/src/reference/gate-heading-length.ts +66 -35
- package/src/reference/gate-heading-structure.ts +193 -0
- package/src/reference/gate-math-punctuation.ts +381 -0
- package/src/reference/gate-math.ts +69 -10
- package/src/reference/gate-part-pages.ts +217 -0
- package/src/reference/gate-prose-notation.ts +59 -12
- package/src/reference/katex-delimiters.mjs +20 -7
- package/src/reference/keyed-float-validate.ts +45 -11
- package/src/reference/keyed-jsx-floats.mjs +73 -20
- package/src/reference/knowledge-checks-validate.ts +1 -1
- package/src/reference/knowledge-checks.mjs +9 -4
- package/src/reference/lab-math-slot.ts +36 -0
- package/src/reference/math-glyphs.mjs +572 -37
- package/src/reference/raw-floats-validate.ts +1 -1
- package/src/reference/raw-floats.mjs +1 -1
- package/src/reference/rehype-heading-anchors.mjs +116 -17
- package/src/reference/rehype-table-header-labels.mjs +21 -3
- package/src/reference/remark-asides.mjs +180 -0
- package/src/reference/remark-memo.mjs +42 -11
- package/src/reference/remark-notation.mjs +387 -36
- package/src/reference/render-lab-math.ts +16 -31
- package/src/reference/sections-validate.ts +81 -0
- package/src/reference/sections.mjs +306 -0
- package/src/reference/tables-validate.ts +2 -1
- package/src/reference/types.ts +17 -0
- package/src/reference/unit-words.ts +233 -0
- package/src/rules/catalog.ts +1298 -0
- package/src/rules/course-rules.ts +456 -0
- package/src/rules/in-effect.ts +235 -0
- package/src/rules/settings.ts +448 -0
- package/src/rules/waivers.ts +249 -0
- package/src/session/PreferenceStore.ts +15 -0
- package/src/styles/global.css +1471 -163
- package/src/styles/surfaces.css +182 -0
- package/src/components/hover-panel.ts +0 -339
- package/src/components/popup-stack.ts +0 -345
|
@@ -179,11 +179,12 @@ const knowledgeLine = knowledge.date
|
|
|
179
179
|
max-height: min(70vh, 34rem);
|
|
180
180
|
overflow-y: auto;
|
|
181
181
|
padding: 1rem;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
border
|
|
182
|
+
/* Course logistics: the meta tier's surface, border and radius
|
|
183
|
+
(`surfaces.css`), plus the overlay shadow every floating card has. */
|
|
184
|
+
border: var(--ex-edge-border);
|
|
185
|
+
border-radius: var(--ex-radius-meta);
|
|
185
186
|
color: var(--sl-color-text);
|
|
186
|
-
background: var(--
|
|
187
|
+
background: var(--ex-surface-tint-neutral);
|
|
187
188
|
box-shadow: var(--sl-shadow-lg);
|
|
188
189
|
font-size: var(--sl-text-xs);
|
|
189
190
|
line-height: 1.5;
|
|
@@ -32,10 +32,15 @@
|
|
|
32
32
|
* together, matching how `rehype-heading-anchors` emits them) into
|
|
33
33
|
* `<summary>` breaks axe's `no-focusable-content` check — a `<summary>` must
|
|
34
34
|
* have no focusable descendants, full stop, no matter how its click handling
|
|
35
|
-
* is patched up.
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* is patched up. So the anchor stays a sibling of `<summary>` rather than a
|
|
36
|
+
* child — the same reason a float's caption line keeps its links outside any
|
|
37
|
+
* `<summary>` — reusing the existing `.sl-heading-wrapper` div as that
|
|
38
|
+
* sibling-holding container.
|
|
39
|
+
*
|
|
40
|
+
* A `<Memo>` and a `<Fold>` are folded here too: each bar is an `<h6>` in a
|
|
41
|
+
* heading wrapper of its own (`Memo.astro`, `Fold.astro`), with its default
|
|
42
|
+
* and its `rememberState` on the wrapper (`data-default-open`,
|
|
43
|
+
* `data-remember-state="false"` to keep the default on every visit).
|
|
39
44
|
*
|
|
40
45
|
* Headings are processed deepest-rank first (h6 before h2, etc.) so that by
|
|
41
46
|
* the time a shallower heading's `sectionParts()` walk runs, any nested
|
|
@@ -69,6 +74,34 @@
|
|
|
69
74
|
* feel; the peek here needs to be the real, in-place content, sized and
|
|
70
75
|
* positioned relative to its own section, animatable into a real expand.
|
|
71
76
|
*
|
|
77
|
+
* **A closed section must look closed on every screen.** The chevron alone
|
|
78
|
+
* isn't enough: on wide screens it sits in the gutter left of the title, and
|
|
79
|
+
* on a phone there is no gutter — it used to render off-screen, leaving a
|
|
80
|
+
* collapsed section indistinguishable from a plain heading. So `<summary>`
|
|
81
|
+
* also carries two `aria-hidden` spans after the heading:
|
|
82
|
+
* `.sl-section-hint` — "(tap to expand)" / "(click to expand)", narrow or
|
|
83
|
+
* touch screens only, where `global.css` also moves the chevron into the
|
|
84
|
+
* title line — and `.sl-section-stub`, a "Hidden here: 2 paragraphs, 1
|
|
85
|
+
* equation" line (`./section-summary.ts`) on every screen. Both show only
|
|
86
|
+
* while the section isn't `open`, and both are part of the tap target. The
|
|
87
|
+
* heading brings its outline number along (`data-sec-number`, printed by
|
|
88
|
+
* `global.css`): a narrow screen hides it on an open section but shows it on a
|
|
89
|
+
* closed one, which is where it says what is folded away.
|
|
90
|
+
*
|
|
91
|
+
* **Print follows the screen** (`../disclosure/print-as-shown.ts`): an open
|
|
92
|
+
* section prints in full, a closed one as its title plus a "(content
|
|
93
|
+
* collapsed — full text: …)" note with the section's permalink.
|
|
94
|
+
*
|
|
95
|
+
* **Carded sections** (docs/plans/titles-and-containers.md Part 2): a
|
|
96
|
+
* wrapper with `data-card="accent"|"meta"` — a `[card]` / `[card=meta]`
|
|
97
|
+
* heading marker, or a knowledge check (`AssessmentSet.astro`) — has its whole
|
|
98
|
+
* section, heading and body, moved into one `div.ex-section-card` carrying
|
|
99
|
+
* that tier's class from `surfaces.css`. Same boundary, same deepest-first
|
|
100
|
+
* order: a card nested in a section reads as one sibling holding its heading,
|
|
101
|
+
* so the parent's walk still sees it. A section that is both collapsible and
|
|
102
|
+
* carded is collapsed first, then its titlebar — which by then holds the
|
|
103
|
+
* whole section — goes into the card.
|
|
104
|
+
*
|
|
72
105
|
* Wired only on lesson pages (see `LessonFooter.astro`), same gating as
|
|
73
106
|
* `HeadingAnchorEnhancer.astro`/`KeyedFloatEnhancer.astro` — and placed
|
|
74
107
|
* *before* `HeadingAnchorEnhancer` in that file so this component's own
|
|
@@ -80,10 +113,14 @@
|
|
|
80
113
|
|
|
81
114
|
<script>
|
|
82
115
|
import { HEADINGS, sectionParts } from './section-parts';
|
|
116
|
+
import { collectHiddenContent, hiddenContentParts } from './section-summary';
|
|
83
117
|
import {
|
|
84
118
|
wirePersistedDetails,
|
|
85
119
|
savePersistedOpenState,
|
|
86
120
|
} from '../disclosure/persisted-disclosure';
|
|
121
|
+
import { installPrintAsShownFallback } from '../disclosure/print-as-shown';
|
|
122
|
+
import { CARD_CONSTANTS } from '../card-manager';
|
|
123
|
+
import { startTrip, type Trip } from '../card-travel';
|
|
87
124
|
|
|
88
125
|
(() => {
|
|
89
126
|
const root = document.querySelector('.sl-markdown-content');
|
|
@@ -91,6 +128,20 @@
|
|
|
91
128
|
|
|
92
129
|
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
93
130
|
|
|
131
|
+
// Every section peek the pointer is travelling from, fed by one listener.
|
|
132
|
+
const peekTrips = new Set<Trip>();
|
|
133
|
+
document.addEventListener(
|
|
134
|
+
'pointermove',
|
|
135
|
+
(event) => {
|
|
136
|
+
if (event.pointerType === 'touch') return;
|
|
137
|
+
for (const trip of [...peekTrips]) {
|
|
138
|
+
trip.move({ x: event.clientX, y: event.clientY });
|
|
139
|
+
if (!trip.active) peekTrips.delete(trip);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
{ passive: true },
|
|
143
|
+
);
|
|
144
|
+
|
|
94
145
|
type State = 'closed' | 'peeking' | 'open';
|
|
95
146
|
|
|
96
147
|
// A collapsed section's peek caps at 10em, measured in the body's own
|
|
@@ -176,20 +227,40 @@
|
|
|
176
227
|
});
|
|
177
228
|
};
|
|
178
229
|
|
|
179
|
-
|
|
230
|
+
const CARD_TIERS = new Set(['accent', 'meta']);
|
|
231
|
+
|
|
232
|
+
const cardSection = (heading: HTMLElement, tier: string) => {
|
|
233
|
+
const parts = sectionParts(heading);
|
|
234
|
+
const card = document.createElement('div');
|
|
235
|
+
card.className = `ex-section-card ex-tier-${tier}`;
|
|
236
|
+
parts[0].before(card);
|
|
237
|
+
card.append(...parts);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const sectionHeadings = Array.from(
|
|
180
241
|
root.querySelectorAll<HTMLElement>(HEADINGS),
|
|
181
242
|
)
|
|
182
|
-
.filter(
|
|
183
|
-
(heading)
|
|
243
|
+
.filter((heading) => {
|
|
244
|
+
const wrapper = heading.closest<HTMLElement>('.sl-heading-wrapper');
|
|
245
|
+
return (
|
|
184
246
|
!!heading.id &&
|
|
185
|
-
|
|
186
|
-
.
|
|
187
|
-
|
|
247
|
+
(wrapper?.dataset.collapsible === 'true' ||
|
|
248
|
+
CARD_TIERS.has(wrapper?.dataset.card ?? ''))
|
|
249
|
+
);
|
|
250
|
+
})
|
|
188
251
|
// Deepest rank first — see the module comment above.
|
|
189
|
-
.sort((a, b) => Number(b.tagName[1]) - Number(a.tagName[1]))
|
|
252
|
+
.sort((a, b) => Number(b.tagName[1]) - Number(a.tagName[1]));
|
|
253
|
+
|
|
254
|
+
for (const heading of sectionHeadings) {
|
|
255
|
+
const wrapper = heading.closest<HTMLElement>('.sl-heading-wrapper')!;
|
|
256
|
+
if (wrapper.dataset.collapsible === 'true') makeCollapsible(heading, wrapper);
|
|
257
|
+
const tier = wrapper.dataset.card ?? '';
|
|
258
|
+
if (CARD_TIERS.has(tier)) cardSection(heading, tier);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function makeCollapsible(heading: HTMLElement, wrapper: HTMLElement) {
|
|
190
262
|
const parts = sectionParts(heading);
|
|
191
263
|
const bodyParts = parts.slice(1);
|
|
192
|
-
const wrapper = heading.closest<HTMLElement>('.sl-heading-wrapper')!;
|
|
193
264
|
|
|
194
265
|
const details = document.createElement('details');
|
|
195
266
|
details.className = 'sl-section-collapsible';
|
|
@@ -208,6 +279,43 @@
|
|
|
208
279
|
':scope > .sl-anchor-link',
|
|
209
280
|
);
|
|
210
281
|
summary.append(heading);
|
|
282
|
+
|
|
283
|
+
// What a *closed* section shows beyond its title (styles in
|
|
284
|
+
// `global.css`; see the module comment): a "(tap to expand)" hint on
|
|
285
|
+
// narrow/touch screens and a "Hidden here: …" line on every screen.
|
|
286
|
+
// Both are `aria-hidden` — the native `<details>` already announces
|
|
287
|
+
// "collapsed", and the heading alone stays the summary's name.
|
|
288
|
+
const hint = document.createElement('span');
|
|
289
|
+
hint.className = 'sl-section-hint';
|
|
290
|
+
hint.setAttribute('aria-hidden', 'true');
|
|
291
|
+
summary.append(hint);
|
|
292
|
+
// A `<Fold>` whose bar names its floats (`data-bar-names-floats`)
|
|
293
|
+
// counts them here rather than naming them twice.
|
|
294
|
+
const { counts, named } = collectHiddenContent(body, HEADINGS, {
|
|
295
|
+
nameFloats: wrapper.dataset.barNamesFloats === undefined,
|
|
296
|
+
});
|
|
297
|
+
const hiddenParts = hiddenContentParts(counts, named);
|
|
298
|
+
if (hiddenParts) {
|
|
299
|
+
// Outer span collapses as a grid row; the inner one clips the text.
|
|
300
|
+
const stub = document.createElement('span');
|
|
301
|
+
stub.className = 'sl-section-stub';
|
|
302
|
+
stub.setAttribute('aria-hidden', 'true');
|
|
303
|
+
const stubText = document.createElement('span');
|
|
304
|
+
stubText.append('Hidden here: ');
|
|
305
|
+
hiddenParts.forEach((part, index) => {
|
|
306
|
+
if (index > 0) stubText.append(', ');
|
|
307
|
+
if (typeof part === 'string') {
|
|
308
|
+
stubText.append(part);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const number = document.createElement('b');
|
|
312
|
+
number.textContent = part.number;
|
|
313
|
+
stubText.append(number, ` ${part.short}`);
|
|
314
|
+
});
|
|
315
|
+
stub.append(stubText);
|
|
316
|
+
summary.append(stub);
|
|
317
|
+
}
|
|
318
|
+
|
|
211
319
|
details.append(summary, body);
|
|
212
320
|
|
|
213
321
|
// The anchor link stays put as `details`'s sibling inside `wrapper`
|
|
@@ -223,10 +331,17 @@
|
|
|
223
331
|
// mis-computing a nested `<table>`'s intrinsic (auto-layout) width
|
|
224
332
|
// when a `<details>` is built pre-opened and inserted already-open,
|
|
225
333
|
// versus being opened only after attachment.
|
|
334
|
+
// `data-remember-state="false"` (a `<Memo rememberState={false}>`)
|
|
335
|
+
// keeps the default on every visit; everything else remembers.
|
|
226
336
|
const defaultOpen = wrapper.dataset.defaultOpen !== 'false';
|
|
227
|
-
|
|
228
|
-
details.dataset.state = (details.open ? 'open' : 'closed') satisfies State;
|
|
337
|
+
const remember = wrapper.dataset.rememberState !== 'false';
|
|
229
338
|
const persistKey = `section:${heading.id}`;
|
|
339
|
+
if (remember) wirePersistedDetails(details, persistKey, defaultOpen);
|
|
340
|
+
else details.open = defaultOpen;
|
|
341
|
+
details.dataset.state = (details.open ? 'open' : 'closed') satisfies State;
|
|
342
|
+
const save = (open: boolean) => {
|
|
343
|
+
if (remember) savePersistedOpenState(persistKey, open);
|
|
344
|
+
};
|
|
230
345
|
|
|
231
346
|
// A real (non-peek) commit: the only place a choice gets persisted —
|
|
232
347
|
// via `savePersistedOpenState`, called *synchronously* with the
|
|
@@ -247,7 +362,7 @@
|
|
|
247
362
|
const goingOpen = next === 'open';
|
|
248
363
|
if (goingOpen) details.open = true; // render before animating/measuring
|
|
249
364
|
details.dataset.state = next satisfies State;
|
|
250
|
-
|
|
365
|
+
save(goingOpen);
|
|
251
366
|
growTo(body, goingOpen ? body.scrollHeight : 0, () => {
|
|
252
367
|
details.open = goingOpen;
|
|
253
368
|
if (goingOpen) body.style.maxHeight = '';
|
|
@@ -269,7 +384,7 @@
|
|
|
269
384
|
details.dataset.state = 'open' satisfies State; // …then re-enter flow at that same height
|
|
270
385
|
void body.offsetHeight; // reflow again before animating the grow
|
|
271
386
|
body.style.transition = '';
|
|
272
|
-
|
|
387
|
+
save(true);
|
|
273
388
|
growTo(body, body.scrollHeight, () => {
|
|
274
389
|
details.open = true;
|
|
275
390
|
body.style.maxHeight = '';
|
|
@@ -291,33 +406,60 @@
|
|
|
291
406
|
});
|
|
292
407
|
};
|
|
293
408
|
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
//
|
|
305
|
-
//
|
|
306
|
-
|
|
409
|
+
// The peek closes when the reader leaves both the title and the peeked
|
|
410
|
+
// body — not the moment the pointer steps off them, but on the
|
|
411
|
+
// explanation cards' terms (rules C2 and C12 of
|
|
412
|
+
// docs/plans/hover-card-consistency.md, `../card-travel.ts`): heading
|
|
413
|
+
// back toward the body keeps it, anything else closes it after the
|
|
414
|
+
// cards' grace. `:focus-visible`, not `:focus-within` — the same
|
|
415
|
+
// reasoning as `hover-preview.ts`: clicking `summary` to commit a peek
|
|
416
|
+
// (or to collapse an open section) leaves it focused as an ordinary
|
|
417
|
+
// side effect of the click, and that focus lingers (`:focus-within`
|
|
418
|
+
// stays true) long after the pointer has moved elsewhere — which, before
|
|
419
|
+
// this used `:focus-visible` instead, meant a peek entered right after
|
|
420
|
+
// such a click could never close on mouse-leave at all.
|
|
421
|
+
// `:focus-visible` is only true for keyboard/keyboard-equivalent focus,
|
|
422
|
+
// so a mouse click doesn't count, but a reader who actually tabbed here
|
|
423
|
+
// still keeps their peek open.
|
|
424
|
+
let graceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
425
|
+
let ownTrip: Trip | null = null;
|
|
426
|
+
const exitUnlessWanted = () => {
|
|
427
|
+
if (!details.matches(':hover') && !summary.matches(':focus-visible')) {
|
|
428
|
+
exitPeek();
|
|
429
|
+
}
|
|
430
|
+
};
|
|
307
431
|
const cancelLeave = () => {
|
|
308
|
-
if (
|
|
309
|
-
|
|
310
|
-
|
|
432
|
+
if (ownTrip) {
|
|
433
|
+
ownTrip.end();
|
|
434
|
+
peekTrips.delete(ownTrip);
|
|
435
|
+
ownTrip = null;
|
|
311
436
|
}
|
|
437
|
+
if (graceTimer !== null) clearTimeout(graceTimer);
|
|
438
|
+
graceTimer = null;
|
|
312
439
|
};
|
|
313
440
|
const scheduleLeave = () => {
|
|
314
441
|
cancelLeave();
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
442
|
+
graceTimer = setTimeout(() => {
|
|
443
|
+
graceTimer = null;
|
|
444
|
+
exitUnlessWanted();
|
|
445
|
+
}, CARD_CONSTANTS.travelGraceMs);
|
|
446
|
+
};
|
|
447
|
+
const travelFrom = (apex: { x: number; y: number }) => {
|
|
448
|
+
cancelLeave();
|
|
449
|
+
const trip = startTrip(apex, {
|
|
450
|
+
graceMs: CARD_CONSTANTS.travelGraceMs,
|
|
451
|
+
restMs: CARD_CONSTANTS.travelRestMs,
|
|
452
|
+
tripMaxMs: CARD_CONSTANTS.travelTripMaxMs,
|
|
453
|
+
cardBox: () => body.getBoundingClientRect(),
|
|
454
|
+
triggerBox: () => summary.getBoundingClientRect(),
|
|
455
|
+
onExit: () => {
|
|
456
|
+
if (ownTrip === trip) cancelLeave();
|
|
457
|
+
exitUnlessWanted();
|
|
458
|
+
},
|
|
320
459
|
});
|
|
460
|
+
if (!trip.active) return;
|
|
461
|
+
ownTrip = trip;
|
|
462
|
+
peekTrips.add(trip);
|
|
321
463
|
};
|
|
322
464
|
|
|
323
465
|
summary.addEventListener('pointerenter', (event) => {
|
|
@@ -326,9 +468,16 @@
|
|
|
326
468
|
enterPeek();
|
|
327
469
|
});
|
|
328
470
|
summary.addEventListener('focus', enterPeek);
|
|
471
|
+
details.addEventListener('pointerenter', (event) => {
|
|
472
|
+
if (event.pointerType !== 'touch') cancelLeave();
|
|
473
|
+
});
|
|
329
474
|
details.addEventListener('pointerleave', (event) => {
|
|
330
475
|
if (event.pointerType === 'touch') return;
|
|
331
|
-
|
|
476
|
+
if (details.dataset.state === 'peeking') {
|
|
477
|
+
travelFrom({ x: event.clientX, y: event.clientY });
|
|
478
|
+
} else {
|
|
479
|
+
scheduleLeave();
|
|
480
|
+
}
|
|
332
481
|
});
|
|
333
482
|
details.addEventListener('focusout', scheduleLeave);
|
|
334
483
|
|
|
@@ -342,6 +491,20 @@
|
|
|
342
491
|
else if (details.dataset.state === 'open') commitOpenOrClosed('closed');
|
|
343
492
|
else commitOpenOrClosed('open');
|
|
344
493
|
});
|
|
494
|
+
|
|
495
|
+
// The browser opens a closed `<details>` by itself to show a match of
|
|
496
|
+
// find-in-page or a fragment inside it. Every open this state machine
|
|
497
|
+
// makes sets `data-state` in the same task, so an open that finds it
|
|
498
|
+
// still `closed` is the browser's: follow it, as a real expand.
|
|
499
|
+
details.addEventListener('toggle', () => {
|
|
500
|
+
if (!details.open || details.dataset.state !== 'closed') return;
|
|
501
|
+
if (details.hasAttribute('data-explico-temporary-open')) return;
|
|
502
|
+
supersede.get(body)?.();
|
|
503
|
+
supersede.delete(body);
|
|
504
|
+
details.dataset.state = 'open' satisfies State;
|
|
505
|
+
body.style.removeProperty('max-height');
|
|
506
|
+
save(true);
|
|
507
|
+
});
|
|
345
508
|
}
|
|
346
509
|
|
|
347
510
|
// A closed native `<details>` doesn't just hide its non-`<summary>`
|
|
@@ -402,60 +565,11 @@
|
|
|
402
565
|
expandAncestors(currentHashId(), false);
|
|
403
566
|
});
|
|
404
567
|
|
|
405
|
-
// Print
|
|
406
|
-
//
|
|
407
|
-
//
|
|
408
|
-
//
|
|
409
|
-
//
|
|
410
|
-
|
|
411
|
-
// force every section's real `open`/`data-state` for print in JS and
|
|
412
|
-
// restore afterward. `beforeprint`/`afterprint` cover an actual print
|
|
413
|
-
// dialog; `matchMedia('print')`'s `change` event additionally covers
|
|
414
|
-
// tools (headless browsers, some print-preview UIs) that flip the media
|
|
415
|
-
// type without firing those events.
|
|
416
|
-
let savedState: { open: boolean; state: string }[] | null = null;
|
|
417
|
-
|
|
418
|
-
const expandAllForPrint = () => {
|
|
419
|
-
if (document.querySelector('[data-explico-print-controller]')) return;
|
|
420
|
-
if (savedState) return; // already expanded for a print in progress
|
|
421
|
-
const all = Array.from(
|
|
422
|
-
document.querySelectorAll<HTMLDetailsElement>(
|
|
423
|
-
'.sl-section-collapsible',
|
|
424
|
-
),
|
|
425
|
-
);
|
|
426
|
-
savedState = all.map((d) => ({
|
|
427
|
-
open: d.open,
|
|
428
|
-
state: d.dataset.state ?? 'closed',
|
|
429
|
-
}));
|
|
430
|
-
for (const d of all) {
|
|
431
|
-
d.open = true;
|
|
432
|
-
d.dataset.state = 'open' satisfies State;
|
|
433
|
-
(d.querySelector<HTMLElement>(':scope > .sl-section-body') ??
|
|
434
|
-
undefined)?.style.removeProperty('max-height');
|
|
435
|
-
}
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
const restoreAfterPrint = () => {
|
|
439
|
-
if (!savedState) return;
|
|
440
|
-
const all = document.querySelectorAll<HTMLDetailsElement>(
|
|
441
|
-
'.sl-section-collapsible',
|
|
442
|
-
);
|
|
443
|
-
all.forEach((d, i) => {
|
|
444
|
-
const saved = savedState?.[i];
|
|
445
|
-
if (!saved) return;
|
|
446
|
-
d.open = saved.open;
|
|
447
|
-
d.dataset.state = saved.state;
|
|
448
|
-
d.querySelector<HTMLElement>(':scope > .sl-section-body')?.style
|
|
449
|
-
.removeProperty('max-height');
|
|
450
|
-
});
|
|
451
|
-
savedState = null;
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
window.addEventListener('beforeprint', expandAllForPrint);
|
|
455
|
-
window.addEventListener('afterprint', restoreAfterPrint);
|
|
456
|
-
window.matchMedia('print').addEventListener('change', (event) => {
|
|
457
|
-
if (event.matches) expandAllForPrint();
|
|
458
|
-
else restoreAfterPrint();
|
|
459
|
-
});
|
|
568
|
+
// Print follows the screen: a section the reader left open prints in
|
|
569
|
+
// full, a closed (or merely peeking) one prints its title plus a
|
|
570
|
+
// "(content collapsed …)" note. `LessonExportActions.astro` does this
|
|
571
|
+
// when the course has the print controller; this covers the browser's
|
|
572
|
+
// own print on a course without it.
|
|
573
|
+
installPrintAsShownFallback();
|
|
460
574
|
})();
|
|
461
575
|
</script>
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Progressive behavior for `<Diagram>`:
|
|
4
4
|
*
|
|
5
|
-
* -
|
|
6
|
-
*
|
|
5
|
+
* - the widen button ↔ at the end of the diagram's caption line (a
|
|
6
|
+
* `.float-tool`, like a table's), shown only while the canvas overflows;
|
|
7
7
|
* - an in-page expanded surface that moves the real figure (never a clone) to
|
|
8
8
|
* `<body>`, overlays its placeholder, and follows that placeholder while the
|
|
9
9
|
* page scrolls — the same spatial model as `TableOverflowExpander.astro`.
|
|
@@ -16,15 +16,9 @@
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
<script>
|
|
19
|
-
import {
|
|
20
|
-
savePersistedOpenState,
|
|
21
|
-
wirePersistedDetails,
|
|
22
|
-
} from '../disclosure/persisted-disclosure';
|
|
23
|
-
import { claimActiveSurface, releaseActiveSurface } from '../hover-panel';
|
|
19
|
+
import { closeTransientCards } from '../card-manager';
|
|
24
20
|
|
|
25
|
-
const GROUP = 'diagram-overflow';
|
|
26
21
|
const EDGE_PX = 16;
|
|
27
|
-
const ANIMATION_MS = 220;
|
|
28
22
|
|
|
29
23
|
interface Expansion {
|
|
30
24
|
readonly figure: HTMLElement;
|
|
@@ -56,8 +50,8 @@
|
|
|
56
50
|
|
|
57
51
|
function captionFor(figure: HTMLElement): string {
|
|
58
52
|
return (
|
|
59
|
-
figure.querySelector<HTMLElement>('
|
|
60
|
-
|
|
53
|
+
figure.querySelector<HTMLElement>(':scope > figcaption[data-float-name]')?.dataset
|
|
54
|
+
.floatName ?? 'this diagram'
|
|
61
55
|
);
|
|
62
56
|
}
|
|
63
57
|
|
|
@@ -74,8 +68,6 @@
|
|
|
74
68
|
: `Expand ${captionFor(figure)} horizontally`,
|
|
75
69
|
);
|
|
76
70
|
button.title = expanded ? 'Shrink diagram' : 'Expand diagram horizontally';
|
|
77
|
-
const srText = button.querySelector<HTMLElement>('.sr-only');
|
|
78
|
-
if (srText) srText.textContent = expanded ? 'Shrink diagram' : 'Expand diagram';
|
|
79
71
|
}
|
|
80
72
|
|
|
81
73
|
function updateScrollFocusability(scroll: HTMLElement, figure: HTMLElement): void {
|
|
@@ -90,15 +82,12 @@
|
|
|
90
82
|
|
|
91
83
|
function evaluateOverflow(
|
|
92
84
|
figure: HTMLElement,
|
|
93
|
-
details: HTMLDetailsElement,
|
|
94
|
-
toolbar: HTMLElement,
|
|
95
85
|
button: HTMLButtonElement,
|
|
96
86
|
scroll: HTMLElement,
|
|
97
87
|
): void {
|
|
98
88
|
if (active?.figure === figure) return;
|
|
99
|
-
const overflows =
|
|
89
|
+
const overflows = scroll.scrollWidth > scroll.clientWidth + 1;
|
|
100
90
|
figure.dataset.diagramOverflow = String(overflows);
|
|
101
|
-
toolbar.hidden = !overflows;
|
|
102
91
|
button.hidden = !overflows;
|
|
103
92
|
updateScrollFocusability(scroll, figure);
|
|
104
93
|
}
|
|
@@ -130,8 +119,8 @@
|
|
|
130
119
|
// restored.
|
|
131
120
|
if (active && active.figure !== figure) return;
|
|
132
121
|
|
|
133
|
-
|
|
134
|
-
|
|
122
|
+
// A hovered card would linger over the expanded diagram; pinned ones stay.
|
|
123
|
+
closeTransientCards();
|
|
135
124
|
|
|
136
125
|
const neededWidth = scroll.scrollWidth;
|
|
137
126
|
const rect = figure.getBoundingClientRect();
|
|
@@ -183,13 +172,13 @@
|
|
|
183
172
|
80,
|
|
184
173
|
);
|
|
185
174
|
figure.style.maxHeight = `${maxHeight}px`;
|
|
186
|
-
const
|
|
175
|
+
const captionHeight =
|
|
187
176
|
figure
|
|
188
|
-
.querySelector<HTMLElement>('
|
|
177
|
+
.querySelector<HTMLElement>(':scope > figcaption')
|
|
189
178
|
?.getBoundingClientRect().height ?? 0;
|
|
190
179
|
figure.style.setProperty(
|
|
191
180
|
'--diagram-expanded-body-height',
|
|
192
|
-
`${Math.max(maxHeight -
|
|
181
|
+
`${Math.max(maxHeight - captionHeight, 40)}px`,
|
|
193
182
|
);
|
|
194
183
|
updateScrollFocusability(scroll, figure);
|
|
195
184
|
};
|
|
@@ -212,126 +201,22 @@
|
|
|
212
201
|
window.addEventListener('resize', reposition, { passive: true });
|
|
213
202
|
}
|
|
214
203
|
|
|
215
|
-
function wireDisclosure(
|
|
216
|
-
figure: HTMLElement,
|
|
217
|
-
details: HTMLDetailsElement,
|
|
218
|
-
body: HTMLElement,
|
|
219
|
-
evaluate: () => void,
|
|
220
|
-
): void {
|
|
221
|
-
const summary = details.querySelector<HTMLElement>(':scope > summary');
|
|
222
|
-
if (!summary) return;
|
|
223
|
-
const defaultOpen = details.open;
|
|
224
|
-
const remember = details.dataset.rememberState === 'true';
|
|
225
|
-
if (remember) {
|
|
226
|
-
wirePersistedDetails(details, `diagram:${figure.id}`, defaultOpen);
|
|
227
|
-
}
|
|
228
|
-
details.dataset.state = details.open ? 'open' : 'closed';
|
|
229
|
-
|
|
230
|
-
// An external/bookmarked deep link reveals the complete diagram. Later
|
|
231
|
-
// in-page jumps retain the reader's persisted minimized state.
|
|
232
|
-
if (location.hash === `#${figure.id}`) {
|
|
233
|
-
details.open = true;
|
|
234
|
-
details.dataset.state = 'open';
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
238
|
-
let finishTimer: number | null = null;
|
|
239
|
-
let transitionEnd: ((event: TransitionEvent) => void) | null = null;
|
|
240
|
-
|
|
241
|
-
const cancelAnimation = () => {
|
|
242
|
-
if (finishTimer !== null) window.clearTimeout(finishTimer);
|
|
243
|
-
finishTimer = null;
|
|
244
|
-
if (transitionEnd) body.removeEventListener('transitionend', transitionEnd);
|
|
245
|
-
transitionEnd = null;
|
|
246
|
-
body.style.removeProperty('transition');
|
|
247
|
-
body.style.removeProperty('overflow');
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
const setOpen = (open: boolean) => {
|
|
251
|
-
cancelAnimation();
|
|
252
|
-
const current = body.getBoundingClientRect().height;
|
|
253
|
-
if (open) details.open = true;
|
|
254
|
-
details.dataset.state = open ? 'open' : 'closed';
|
|
255
|
-
if (remember) savePersistedOpenState(`diagram:${figure.id}`, open);
|
|
256
|
-
|
|
257
|
-
if (reduceMotion.matches) {
|
|
258
|
-
details.open = open;
|
|
259
|
-
body.style.maxHeight = open ? '' : '0px';
|
|
260
|
-
if (active?.figure === figure) {
|
|
261
|
-
active.placeholder.style.height = `${figure.getBoundingClientRect().height}px`;
|
|
262
|
-
}
|
|
263
|
-
evaluate();
|
|
264
|
-
active?.reposition();
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
body.style.transition = 'none';
|
|
269
|
-
body.style.maxHeight = `${current}px`;
|
|
270
|
-
body.style.overflow = 'hidden';
|
|
271
|
-
void body.offsetHeight;
|
|
272
|
-
body.style.removeProperty('transition');
|
|
273
|
-
|
|
274
|
-
const expandedLimit = Number.parseFloat(
|
|
275
|
-
getComputedStyle(figure).getPropertyValue(
|
|
276
|
-
'--diagram-expanded-body-height',
|
|
277
|
-
),
|
|
278
|
-
);
|
|
279
|
-
const target = open
|
|
280
|
-
? Math.min(
|
|
281
|
-
body.scrollHeight,
|
|
282
|
-
Number.isFinite(expandedLimit) ? expandedLimit : Number.POSITIVE_INFINITY,
|
|
283
|
-
)
|
|
284
|
-
: 0;
|
|
285
|
-
const finish = () => {
|
|
286
|
-
cancelAnimation();
|
|
287
|
-
details.open = open;
|
|
288
|
-
body.style.maxHeight = open ? '' : '0px';
|
|
289
|
-
if (active?.figure === figure) {
|
|
290
|
-
active.placeholder.style.height = `${figure.getBoundingClientRect().height}px`;
|
|
291
|
-
}
|
|
292
|
-
evaluate();
|
|
293
|
-
active?.reposition();
|
|
294
|
-
};
|
|
295
|
-
transitionEnd = (event) => {
|
|
296
|
-
if (event.target === body && event.propertyName === 'max-height') finish();
|
|
297
|
-
};
|
|
298
|
-
body.addEventListener('transitionend', transitionEnd);
|
|
299
|
-
finishTimer = window.setTimeout(finish, ANIMATION_MS + 60);
|
|
300
|
-
requestAnimationFrame(() => {
|
|
301
|
-
body.style.maxHeight = `${target}px`;
|
|
302
|
-
});
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
summary.addEventListener('click', (event) => {
|
|
306
|
-
event.preventDefault();
|
|
307
|
-
setOpen(details.dataset.state !== 'open');
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
|
|
311
204
|
function setup(): void {
|
|
312
205
|
for (const figure of document.querySelectorAll<HTMLElement>(
|
|
313
206
|
'.diagram[data-diagram-expandable]',
|
|
314
207
|
)) {
|
|
315
208
|
if (figure.dataset.diagramExpandReady === 'true') continue;
|
|
316
|
-
const details = figure.querySelector<HTMLDetailsElement>(
|
|
317
|
-
'[data-diagram-details]',
|
|
318
|
-
);
|
|
319
|
-
const body = figure.querySelector<HTMLElement>('[data-diagram-body]');
|
|
320
|
-
const toolbar = figure.querySelector<HTMLElement>('[data-diagram-toolbar]');
|
|
321
209
|
const button = figure.querySelector<HTMLButtonElement>('[data-diagram-expand]');
|
|
322
210
|
const scroll = figure.querySelector<HTMLElement>('.diagram-scroll');
|
|
323
|
-
if (!
|
|
211
|
+
if (!button || !scroll) continue;
|
|
324
212
|
figure.dataset.diagramExpandReady = 'true';
|
|
325
213
|
|
|
326
|
-
const evaluate = () =>
|
|
327
|
-
evaluateOverflow(figure, details, toolbar, button, scroll);
|
|
214
|
+
const evaluate = () => evaluateOverflow(figure, button, scroll);
|
|
328
215
|
button.addEventListener('click', () => {
|
|
329
216
|
if (active?.figure === figure) collapseExpansion();
|
|
330
217
|
else expand(figure, button, scroll, evaluate);
|
|
331
218
|
});
|
|
332
219
|
new ResizeObserver(evaluate).observe(scroll);
|
|
333
|
-
details.addEventListener('toggle', evaluate);
|
|
334
|
-
wireDisclosure(figure, details, body, evaluate);
|
|
335
220
|
updateExpandButton(figure, button, false);
|
|
336
221
|
evaluate();
|
|
337
222
|
}
|
|
@@ -359,16 +244,8 @@
|
|
|
359
244
|
box-shadow: var(--sl-shadow-lg);
|
|
360
245
|
}
|
|
361
246
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
max-height: inherit;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
.diagram-is-expanded .diagram__details {
|
|
368
|
-
display: flex;
|
|
369
|
-
flex-direction: column;
|
|
370
|
-
}
|
|
371
|
-
|
|
247
|
+
/* The caption line stays below the graph; the body takes the height the
|
|
248
|
+
caption leaves (`--diagram-expanded-body-height`) and scrolls. */
|
|
372
249
|
.diagram-is-expanded .diagram__body {
|
|
373
250
|
min-height: 0;
|
|
374
251
|
max-height: var(--diagram-expanded-body-height);
|