@pie-element/passage 8.0.2-next.20261007003844 → 8.0.2

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.
@@ -1,31 +1,31 @@
1
1
  import { p as e } from "./speech-worker-CP5P4gRS-G4rtBs8u.js";
2
- import { C as t, Et as n, F as r, M as i, P as a, a as o, b as s, et as c, h as l, o as u, s as d, t as f, x as p } from "./dist-DOHfKGBZ.js";
3
- import m from "react";
4
- import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
2
+ import { C as t, Dt as n, F as r, I as i, M as a, N as o, a as s, b as c, h as l, o as u, s as d, t as f, tt as p, x as m } from "./dist-iIKWVMz9.js";
3
+ import h from "react";
4
+ import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
5
5
  //#region src/delivery/stimulus-tabs.tsx
6
- var v = /* @__PURE__ */ e(n(), 1), { translator: y } = p;
7
- function b(e) {
6
+ var y = /* @__PURE__ */ e(n(), 1), { translator: b } = m;
7
+ function x(e) {
8
8
  return typeof e == "function" || typeof e == "object" && !!e && typeof e.$$typeof == "symbol";
9
9
  }
10
- function x(e, t) {
11
- return !e || b(e) ? e : b(e.default) ? e.default : t && b(e[t]) ? e[t] : t && b(e[t]?.default) ? e[t].default : e;
10
+ function S(e, t) {
11
+ return !e || x(e) ? e : x(e.default) ? e.default : t && x(e[t]) ? e[t] : t && x(e[t]?.default) ? e[t].default : e;
12
12
  }
13
- var S = x(l, "UiLayout") || x(O.UiLayout, "UiLayout"), C = x(u, "Purpose") || x(O.Purpose, "Purpose"), w = x(d, "PreviewPrompt") || x(O.PreviewPrompt, "PreviewPrompt"), T = x(s, "Collapsible") || x(O.Collapsible, "Collapsible"), E = f, D = E.default, O = D && typeof D == "object" ? D : E, k = 2, A = .4, j = 170, M = () => {
13
+ var C = S(l, "UiLayout") || S(k.UiLayout, "UiLayout"), w = S(u, "Purpose") || S(k.Purpose, "Purpose"), T = S(d, "PreviewPrompt") || S(k.PreviewPrompt, "PreviewPrompt"), E = S(c, "Collapsible") || S(k.Collapsible, "Collapsible"), D = f, O = D.default, k = O && typeof O == "object" ? O : D, A = 2, j = .4, M = 170, N = () => {
14
14
  if (typeof window > "u") return 1;
15
15
  let e = window.outerWidth / window.innerWidth;
16
- return Math.max(A, Math.min(1, k / (Number.isFinite(e) && e > 0 ? e : 1)));
17
- }, N = c("div")({
16
+ return Math.max(j, Math.min(1, A / (Number.isFinite(e) && e > 0 ? e : 1)));
17
+ }, P = p("div")({
18
18
  flexGrow: 1,
19
- backgroundColor: i.background(),
20
- color: i.text(),
19
+ backgroundColor: o.background(),
20
+ color: o.text(),
21
21
  "&:not(.MathJax) table": { borderCollapse: "collapse" },
22
22
  "&:not(.MathJax) table td, &:not(.MathJax) table th": {
23
23
  padding: ".6em 1em",
24
24
  textAlign: "left"
25
25
  }
26
- }), P = c("div")(({ theme: e }) => ({
27
- backgroundColor: i.background(),
28
- color: i.text(),
26
+ }), F = p("div")(({ theme: e }) => ({
27
+ backgroundColor: o.background(),
28
+ color: o.text(),
29
29
  padding: e.spacing(2),
30
30
  "& blockquote": {
31
31
  background: "#f9f9f9",
@@ -33,13 +33,13 @@ var S = x(l, "UiLayout") || x(O.UiLayout, "UiLayout"), C = x(u, "Purpose") || x(
33
33
  margin: "1.5em 10px",
34
34
  padding: ".5em 10px"
35
35
  }
36
- })), F = c("div")({ fontSize: "1.75rem" }), I = c("div")({ fontSize: "1.5rem" }), L = c("div")({ fontSize: "1.25rem" }), R = c(a)(({ theme: e }) => ({
37
- background: i.background(),
36
+ })), I = p("div")({ fontSize: "1.75rem" }), L = p("div")({ fontSize: "1.5rem" }), R = p("div")({ fontSize: "1.25rem" }), z = p(r)(({ theme: e }) => ({
37
+ background: o.background(),
38
38
  fontSize: "inherit",
39
39
  fontFamily: "Roboto, sans-serif",
40
- color: i.text(),
40
+ color: o.text(),
41
41
  borderRadius: `${e.spacing(2)} ${e.spacing(2)} 0 0`,
42
- border: `1px solid ${i.borderGray()}`,
42
+ border: `1px solid ${o.borderGray()}`,
43
43
  borderBottomWidth: 0,
44
44
  minHeight: "56px",
45
45
  padding: "8px 10px",
@@ -59,24 +59,24 @@ var S = x(l, "UiLayout") || x(O.UiLayout, "UiLayout"), C = x(u, "Purpose") || x(
59
59
  opacity: .7
60
60
  },
61
61
  "&.Mui-selected": {
62
- color: i.text(),
62
+ color: o.text(),
63
63
  ".passage-label": { opacity: 1 },
64
- ".passage-label-underline": { backgroundColor: i.tertiary() }
64
+ ".passage-label-underline": { backgroundColor: o.tertiary() }
65
65
  },
66
- "&:hover": { ".passage-label-underline": { backgroundColor: i.tertiaryLight() } },
66
+ "&:hover": { ".passage-label-underline": { backgroundColor: o.tertiaryLight() } },
67
67
  "& .MuiTouchRipple-root": { opacity: .7 }
68
- })), z = c("div")(() => ({
68
+ })), B = p("div")(() => ({
69
69
  height: "2px",
70
70
  width: "100%",
71
71
  marginTop: "6px",
72
- background: i.background()
73
- })), B = class extends m.Component {
72
+ background: o.background()
73
+ })), V = class extends h.Component {
74
74
  state = {
75
75
  activeTab: 0,
76
- zoomCompensation: M(),
76
+ zoomCompensation: N(),
77
77
  containerWidth: 0
78
78
  };
79
- containerRef = m.createRef();
79
+ containerRef = h.createRef();
80
80
  idPrefix = t("passage");
81
81
  tabButtonId = (e) => `${this.idPrefix}-button-${e}`;
82
82
  tabPanelId = (e) => `${this.idPrefix}-tabpanel-${e}`;
@@ -87,7 +87,7 @@ var S = x(l, "UiLayout") || x(O.UiLayout, "UiLayout"), C = x(u, "Purpose") || x(
87
87
  typeof window > "u" || (window.removeEventListener("resize", this.updateZoomCompensation), this.resizeObserver &&= (this.resizeObserver.disconnect(), null));
88
88
  }
89
89
  updateZoomCompensation = () => {
90
- this.setState({ zoomCompensation: M() });
90
+ this.setState({ zoomCompensation: N() });
91
91
  };
92
92
  updateContainerWidth = () => {
93
93
  let e = this.containerRef.current;
@@ -126,7 +126,7 @@ var S = x(l, "UiLayout") || x(O.UiLayout, "UiLayout"), C = x(u, "Purpose") || x(
126
126
  };
127
127
  parsedText = (e = "") => {
128
128
  let t = document.createElement("div");
129
- t.innerHTML = e.replace(/(<br\/>\n)/g, "<br/>");
129
+ t.innerHTML = a(e.replace(/(<br\/>\n)/g, "<br/>"));
130
130
  let n = t.querySelector("audio");
131
131
  if (n) {
132
132
  let e = document.createElement("source");
@@ -136,23 +136,23 @@ var S = x(l, "UiLayout") || x(O.UiLayout, "UiLayout"), C = x(u, "Purpose") || x(
136
136
  };
137
137
  renderInstructions(e, t = !1) {
138
138
  if (!e) return;
139
- let n = /* @__PURE__ */ g(w, {
139
+ let n = /* @__PURE__ */ _(T, {
140
140
  tagName: "div",
141
141
  className: "prompt",
142
142
  defaultClassName: "teacher-instructions",
143
143
  prompt: e
144
144
  });
145
- return t ? n : /* @__PURE__ */ g(T, {
145
+ return t ? n : /* @__PURE__ */ _(E, {
146
146
  labels: {
147
- hidden: y.t("common:showTeacherInstructions", { lng: this.props.model?.language }),
148
- visible: y.t("common:hideTeacherInstructions", { lng: this.props.model?.language })
147
+ hidden: b.t("common:showTeacherInstructions", { lng: this.props.model?.language }),
148
+ visible: b.t("common:hideTeacherInstructions", { lng: this.props.model?.language })
149
149
  },
150
150
  children: n
151
151
  });
152
152
  }
153
153
  renderTab(e, t, n = !0) {
154
- let { baseHeadingLevel: r } = this.props, i = r ? Math.min(6, Math.max(1, r)) : void 0, a = r ? `h${i}` : "h2", s = r ? Math.min(6, Math.max(1, i + 1)) : void 0;
155
- return /* @__PURE__ */ _(P, {
154
+ let { baseHeadingLevel: r } = this.props, i = r ? Math.min(6, Math.max(1, r)) : void 0, o = r ? `h${i}` : "h2", c = r ? Math.min(6, Math.max(1, i + 1)) : void 0;
155
+ return /* @__PURE__ */ v(F, {
156
156
  id: this.tabPanelId(e.id),
157
157
  className: `tabpanel-${e.id}`,
158
158
  ...n && {
@@ -161,41 +161,41 @@ var S = x(l, "UiLayout") || x(O.UiLayout, "UiLayout"), C = x(u, "Purpose") || x(
161
161
  },
162
162
  children: [
163
163
  this.renderInstructions(e.teacherInstructions, t),
164
- e.title && /* @__PURE__ */ g(C, {
164
+ e.title && /* @__PURE__ */ _(w, {
165
165
  purpose: "passage-title",
166
- children: /* @__PURE__ */ g(a, { children: /* @__PURE__ */ g(F, { dangerouslySetInnerHTML: { __html: this.parsedText(e.title) } }) })
166
+ children: /* @__PURE__ */ _(o, { children: /* @__PURE__ */ _(I, { dangerouslySetInnerHTML: { __html: this.parsedText(e.title) } }) })
167
167
  }),
168
- e.subtitle && /* @__PURE__ */ g(C, {
168
+ e.subtitle && /* @__PURE__ */ _(w, {
169
169
  purpose: "passage-subtitle",
170
- children: /* @__PURE__ */ g(I, { dangerouslySetInnerHTML: { __html: this.parsedText(e.subtitle) } })
170
+ children: /* @__PURE__ */ _(L, { dangerouslySetInnerHTML: { __html: this.parsedText(e.subtitle) } })
171
171
  }),
172
- e.author && /* @__PURE__ */ g(C, {
172
+ e.author && /* @__PURE__ */ _(w, {
173
173
  purpose: "passage-author",
174
- children: /* @__PURE__ */ g(L, {
174
+ children: /* @__PURE__ */ _(R, {
175
175
  className: "author",
176
176
  dangerouslySetInnerHTML: { __html: this.parsedText(e.author) }
177
177
  })
178
178
  }),
179
- e.text && /* @__PURE__ */ g(C, {
179
+ e.text && /* @__PURE__ */ _(w, {
180
180
  purpose: "passage-text",
181
- children: /* @__PURE__ */ g("div", {
181
+ children: /* @__PURE__ */ _("div", {
182
182
  className: "text",
183
- dangerouslySetInnerHTML: { __html: r ? o(e.text, s) : e.text }
183
+ dangerouslySetInnerHTML: { __html: a(r ? s(e.text, c) : e.text) }
184
184
  }, e.id)
185
185
  })
186
186
  ]
187
187
  }, e.id);
188
188
  }
189
189
  render() {
190
- let { model: e, tabs: t, disabledTabs: n } = this.props, { activeTab: a, zoomCompensation: o, containerWidth: s } = this.state;
190
+ let { model: e, tabs: t, disabledTabs: n } = this.props, { activeTab: r, zoomCompensation: a, containerWidth: s } = this.state;
191
191
  if (!t?.length) return;
192
- let { extraCSSRules: c } = e || {}, l = (t || []).find((e) => e.id === a), u = s > 0 ? s / t.length : null, d = s > 0 && s <= t.length * j;
193
- return /* @__PURE__ */ g(S, {
192
+ let { extraCSSRules: c } = e || {}, l = (t || []).find((e) => e.id === r), u = s > 0 ? s / t.length : null, d = s > 0 && s <= t.length * M;
193
+ return /* @__PURE__ */ _(C, {
194
194
  extraCSSRules: c,
195
- children: /* @__PURE__ */ g(N, {
195
+ children: /* @__PURE__ */ _(P, {
196
196
  className: "passages",
197
197
  ref: this.containerRef,
198
- children: n || t.length === 1 ? t.map((e) => this.renderTab(e, n, !1)) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(r, {
198
+ children: n || t.length === 1 ? t.map((e) => this.renderTab(e, n, !1)) : /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(i, {
199
199
  sx: {
200
200
  position: "static",
201
201
  "@media (min-width: 841px)": {
@@ -204,38 +204,38 @@ var S = x(l, "UiLayout") || x(O.UiLayout, "UiLayout"), C = x(u, "Purpose") || x(
204
204
  zIndex: 1
205
205
  },
206
206
  background: "var(--pie-passage-header-background, rgba(255,255,255,0))",
207
- color: i.text(),
207
+ color: o.text(),
208
208
  fontFamily: "Roboto, sans-serif",
209
- zoom: o,
209
+ zoom: a,
210
210
  "& .MuiTabs-list": {
211
- backgroundColor: `var(--pie-passage-header-background, ${i.backgroundDark()})`,
212
- borderBottom: `1px solid ${i.borderGray()}`
211
+ backgroundColor: `var(--pie-passage-header-background, ${o.backgroundDark()})`,
212
+ borderBottom: `1px solid ${o.borderGray()}`
213
213
  },
214
214
  "& .MuiTabs-indicator": {
215
- backgroundColor: i.white(),
215
+ backgroundColor: o.white(),
216
216
  marginBottom: "-1px"
217
217
  }
218
218
  },
219
- value: a,
219
+ value: r,
220
220
  onChange: this.handleChange,
221
- children: t.map((e, t) => /* @__PURE__ */ g(R, {
221
+ children: t.map((e, t) => /* @__PURE__ */ _(z, {
222
222
  id: this.tabButtonId(e.id),
223
223
  className: `button-${e.id}`,
224
224
  sx: u ? { maxWidth: `${u}px` } : void 0,
225
- label: /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(C, {
225
+ label: /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _(w, {
226
226
  purpose: "passage-label",
227
- children: d ? /* @__PURE__ */ g("span", {
227
+ children: d ? /* @__PURE__ */ _("span", {
228
228
  className: "passage-label",
229
229
  children: `Passage ${t + 1}`
230
- }) : /* @__PURE__ */ g("span", {
230
+ }) : /* @__PURE__ */ _("span", {
231
231
  className: "passage-label",
232
232
  dangerouslySetInnerHTML: { __html: this.parsedText(e.label) }
233
233
  })
234
- }), /* @__PURE__ */ g(z, { className: "passage-label-underline" })] }),
234
+ }), /* @__PURE__ */ _(B, { className: "passage-label-underline" })] }),
235
235
  value: e.id,
236
- tabIndex: a === e.id ? 0 : -1,
236
+ tabIndex: r === e.id ? 0 : -1,
237
237
  "aria-controls": this.tabPanelId(e.id),
238
- "aria-selected": a === e.id,
238
+ "aria-selected": r === e.id,
239
239
  onKeyDown: (t) => this.handleKeyDown(t, e.id)
240
240
  }, e.id))
241
241
  }), l ? this.renderTab(l, n) : null] })
@@ -243,21 +243,21 @@ var S = x(l, "UiLayout") || x(O.UiLayout, "UiLayout"), C = x(u, "Purpose") || x(
243
243
  });
244
244
  }
245
245
  };
246
- B.propTypes = {
247
- tabs: v.default.arrayOf(v.default.shape({
248
- id: v.default.number.isRequired,
249
- label: v.default.string.isRequired,
250
- title: v.default.string.isRequired,
251
- subtitle: v.default.string,
252
- author: v.default.string,
253
- text: v.default.string.isRequired,
254
- teacherInstructions: v.default.string
246
+ V.propTypes = {
247
+ tabs: y.default.arrayOf(y.default.shape({
248
+ id: y.default.number.isRequired,
249
+ label: y.default.string.isRequired,
250
+ title: y.default.string.isRequired,
251
+ subtitle: y.default.string,
252
+ author: y.default.string,
253
+ text: y.default.string.isRequired,
254
+ teacherInstructions: y.default.string
255
255
  }).isRequired).isRequired,
256
- disabledTabs: v.default.bool,
257
- model: v.default.object,
258
- baseHeadingLevel: v.default.number
256
+ disabledTabs: y.default.bool,
257
+ model: y.default.object,
258
+ baseHeadingLevel: y.default.number
259
259
  };
260
260
  //#endregion
261
- export { B as t };
261
+ export { V as t };
262
262
 
263
- //# sourceMappingURL=stimulus-tabs-b-310g7S.js.map
263
+ //# sourceMappingURL=stimulus-tabs-CV5wwqR_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stimulus-tabs-CV5wwqR_.js","names":[],"sources":["../../src/delivery/stimulus-tabs.tsx"],"sourcesContent":["// @ts-nocheck\n\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport Tabs from '@mui/material/Tabs';\nimport Tab from '@mui/material/Tab';\nimport { styled } from '@mui/material/styles';\nimport { Collapsible as CollapsibleImport, color, createUniqueId, PreviewPrompt as PreviewPromptImport, Purpose as PurposeImport, UiLayout as UiLayoutImport, transformDataHeadings } from '@pie-lib/render-ui';\nimport Translator from '@pie-lib/translator';\n\nconst { translator } = Translator;\n\nfunction isRenderableReactInteropType(value: any) {\n return (\n typeof value === 'function' ||\n (typeof value === 'object' && value !== null && typeof value.$$typeof === 'symbol')\n );\n}\n\nfunction unwrapReactInteropSymbol(maybeSymbol: any, namedExport?: string) {\n if (!maybeSymbol) return maybeSymbol;\n if (isRenderableReactInteropType(maybeSymbol)) return maybeSymbol;\n if (isRenderableReactInteropType(maybeSymbol.default)) return maybeSymbol.default;\n if (namedExport && isRenderableReactInteropType(maybeSymbol[namedExport])) {\n return maybeSymbol[namedExport];\n }\n if (namedExport && isRenderableReactInteropType(maybeSymbol[namedExport]?.default)) {\n return maybeSymbol[namedExport].default;\n }\n return maybeSymbol;\n}\nconst UiLayout = unwrapReactInteropSymbol(UiLayoutImport, 'UiLayout') || unwrapReactInteropSymbol(renderUi.UiLayout, 'UiLayout');\nconst Purpose = unwrapReactInteropSymbol(PurposeImport, 'Purpose') || unwrapReactInteropSymbol(renderUi.Purpose, 'Purpose');\nconst PreviewPrompt = unwrapReactInteropSymbol(PreviewPromptImport, 'PreviewPrompt') || unwrapReactInteropSymbol(renderUi.PreviewPrompt, 'PreviewPrompt');\nconst Collapsible = unwrapReactInteropSymbol(CollapsibleImport, 'Collapsible') || unwrapReactInteropSymbol(renderUi.Collapsible, 'Collapsible');\nimport * as RenderUiNamespace from '@pie-lib/render-ui';\nimport { sanitizeModelHtml } from '@pie-element/shared-utils';\nconst renderUiNamespaceAny = RenderUiNamespace as any;\nconst renderUiDefaultMaybe = renderUiNamespaceAny['default'];\nconst renderUi =\n renderUiDefaultMaybe && typeof renderUiDefaultMaybe === 'object'\n ? renderUiDefaultMaybe\n : renderUiNamespaceAny;\n// Must match the breakpoint Quiz Engine passes to the PIE section player for\n// switching from the side-by-side passage/question layout to the tabbed layout.\n// Below (and at) this width the passage tabs scroll with the passage content\n// instead of being locked to the top of the panel, so that they do not lock up\n// space needed for the passage text (WCAG 1.4.10 Reflow, 400% zoom / 320px).\nconst STICKY_TABS_BREAKPOINT = 840;\n\n/**\n * Zoom compensation for the passage selection tabs.\n *\n * The tabs scale naturally with browser zoom up to 200%. Beyond 200%,\n * we shrink their CSS size proportionally so their physical on-screen size\n * freezes at the 200% appearance, leaving more room for passage content\n * in high-zoom / small-window situations.\n * The factor is min(1, 2 / zoom): exactly 1 at zoom <= 200% (component\n * behavior unchanged), shrinking proportionally above that. A lower clamp\n * of 0.4 guards against inflated ratios (docked devtools, browser side\n * panels, window chrome) ever making the tabs unusably small.\n */\nconst MAX_TABS_ZOOM = 2;\nconst MIN_ZOOM_COMPENSATION = 0.4;\n\n// Per-tab horizontal-space floor in CSS pixels. When the passage container is\n// narrow enough that each tab would have at most this much room\n// (containerWidth <= tabs.length * NUMERIC_LABEL_MIN_WIDTH_PER_TAB), tab labels\n// fall back to \"Passage 1\", \"Passage 2\", ... so navigation stays usable instead\n// of being dominated by aggressively truncated titles.\nconst NUMERIC_LABEL_MIN_WIDTH_PER_TAB = 170;\n\nconst computeZoomCompensation = () => {\n if (typeof window === 'undefined') return 1;\n const ratio = window.outerWidth / window.innerWidth;\n const zoom = Number.isFinite(ratio) && ratio > 0 ? ratio : 1;\n return Math.max(MIN_ZOOM_COMPENSATION, Math.min(1, MAX_TABS_ZOOM / zoom));\n};\n\nconst PassagesContainer: any = styled('div')({\n flexGrow: 1,\n backgroundColor: color.background(),\n color: color.text(),\n '&:not(.MathJax) table': {\n borderCollapse: 'collapse',\n },\n '&:not(.MathJax) table td, &:not(.MathJax) table th': {\n padding: '.6em 1em',\n textAlign: 'left',\n },\n});\n\nconst Passage: any = styled('div')(({ theme }) => ({\n backgroundColor: color.background(),\n color: color.text(),\n padding: theme.spacing(2),\n '& blockquote': {\n background: '#f9f9f9',\n borderLeft: '5px solid #ccc',\n margin: '1.5em 10px',\n padding: '.5em 10px',\n },\n}));\n\nconst PassageTitle: any = styled('div')({\n fontSize: '1.75rem',\n});\n\nconst PassageSubtitle: any = styled('div')({\n fontSize: '1.5rem',\n});\n\nconst PassageAuthor: any = styled('div')({\n fontSize: '1.25rem',\n});\n\nconst TabStyled: any = styled(Tab)(({ theme }) => ({\n /*\n * The tab carries the colour of the panel it opens, which is what makes it read as a\n * tab rather than a button, and it has to be the themed panel colour: MUI's palette\n * does not follow `--pie-*`, so `common.white` here left the tab white on every color\n * scheme while the passage body beneath it went dark. The comment this replaces gated\n * the change on PD-2801, which is about OT's `color-contrast` class -- the mechanism\n * pie-theme superseded, and blocked since 2023.\n */\n background: color.background(),\n fontSize: 'inherit',\n fontFamily: 'Roboto, sans-serif',\n color: color.text(),\n borderRadius: `${theme.spacing(2)} ${theme.spacing(2)} 0 0`,\n /*\n * `--pie-border-gray` is stepped to the 3:1 non-text minimum in every scheme. The\n * literal it replaces measured about 1.2:1 against the dark schemes' surfaces, so the\n * tab outline -- the only thing separating an unselected tab from the strip -- was\n * invisible there.\n */\n border: `1px solid ${color.borderGray()}`,\n borderBottomWidth: 0,\n minHeight: '56px',\n padding: '8px 10px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: `0 ${theme.spacing(1)}`,\n textTransform: 'none',\n\n '.passage-label': {\n display: '-webkit-box',\n WebkitLineClamp: 2,\n WebkitBoxOrient: 'vertical',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'normal',\n margin: 'auto 0',\n opacity: 0.7,\n },\n\n '&.Mui-selected': {\n color: color.text(),\n '.passage-label': {\n opacity: 1,\n },\n '.passage-label-underline': {\n backgroundColor: color.tertiary(),\n },\n },\n\n '&:hover': {\n '.passage-label-underline': {\n backgroundColor: color.tertiaryLight(),\n },\n },\n\n '& .MuiTouchRipple-root': {\n opacity: 0.7,\n },\n}));\n\n/*\n * The selection indicator, one per tab. Unselected it has to disappear into the tab, so it\n * paints the tab's own background rather than a fixed white; selected it becomes\n * `--pie-tertiary`, which every scheme sets.\n */\nconst Underline: any = styled('div')(() => ({\n height: '2px',\n width: '100%',\n marginTop: '6px',\n background: color.background(),\n}));\n\nclass StimulusTabs extends React.Component {\n state = {\n activeTab: 0,\n zoomCompensation: computeZoomCompensation(),\n containerWidth: 0,\n };\n\n containerRef = React.createRef();\n\n // Tab ids are model indexes, so DOM ids take a per-instance prefix and each passage's\n // aria-controls / aria-labelledby pairs resolve inside that passage. `button-N` and\n // `tabpanel-N` stay as class hooks.\n idPrefix = createUniqueId('passage');\n\n tabButtonId: any = (tabId) => `${this.idPrefix}-button-${tabId}`;\n\n tabPanelId: any = (tabId) => `${this.idPrefix}-tabpanel-${tabId}`;\n\n componentDidMount() {\n if (typeof window === 'undefined') return;\n window.addEventListener('resize', this.updateZoomCompensation);\n\n if (this.containerRef.current && typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(this.updateContainerWidth);\n this.resizeObserver.observe(this.containerRef.current);\n }\n\n this.updateContainerWidth();\n }\n\n componentWillUnmount() {\n if (typeof window === 'undefined') return;\n window.removeEventListener('resize', this.updateZoomCompensation);\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n }\n\n updateZoomCompensation: any = () => {\n this.setState({ zoomCompensation: computeZoomCompensation() });\n };\n\n updateContainerWidth: any = () => {\n const node = this.containerRef.current;\n if (!node) return;\n const width = node.clientWidth;\n if (width !== this.state.containerWidth) {\n this.setState({ containerWidth: width });\n }\n };\n\n handleChange: any = (event, activeTab) => {\n this.setState(() => ({ activeTab }));\n\n setTimeout(() => {\n const tabChangeEvent = new CustomEvent('pie-ui-passage-tabChanged', {\n detail: { tab: activeTab },\n });\n\n window.dispatchEvent(tabChangeEvent);\n });\n };\n\n handleKeyDown: any = (event, currentTabId) => {\n const { key } = event;\n const { tabs } = this.props;\n\n let newTabIndex = -1;\n const currentIndex = tabs.findIndex((tab) => tab.id === currentTabId);\n\n switch (key) {\n case 'ArrowRight':\n // Move to the next tab\n newTabIndex = (currentIndex + 1) % tabs.length;\n break;\n case 'ArrowLeft':\n // Move to the previous tab\n newTabIndex = (currentIndex - 1 + tabs.length) % tabs.length;\n break;\n // Commented out ArrowDown and ArrowUp for future vertical tab navigation\n // case 'ArrowDown':\n // // Move to the next tab (for vertical alignment)\n // newTabIndex = (currentIndex + 1) % tabs.length;\n // break;\n // case 'ArrowUp':\n // // Move to the previous tab (for vertical alignment)\n // newTabIndex = (currentIndex - 1 + tabs.length) % tabs.length;\n // break;\n case 'Home':\n // Move to the first tab\n newTabIndex = 0;\n break;\n case 'End':\n // Move to the last tab\n newTabIndex = tabs.length - 1;\n break;\n case 'Enter':\n case ' ':\n // Activate the current tab\n newTabIndex = currentIndex;\n break;\n default:\n break;\n }\n\n if (newTabIndex !== -1) {\n event.preventDefault();\n event.stopPropagation();\n this.handleChange(event, tabs[newTabIndex].id);\n this.containerRef.current?.querySelector(`[id=\"${this.tabButtonId(tabs[newTabIndex].id)}\"]`)?.focus();\n }\n };\n\n parsedText: any = (text = '') => {\n // fix imported audio content for Safari PD-1391\n const div = document.createElement('div');\n div.innerHTML = sanitizeModelHtml(text.replace(/(<br\\/>\\n)/g, '<br/>'));\n\n const audio = div.querySelector('audio');\n\n if (audio) {\n const source = document.createElement('source');\n\n source.setAttribute('type', 'audio/mp3');\n source.setAttribute('src', audio.getAttribute('src'));\n\n audio.removeAttribute('src');\n audio.appendChild(source);\n }\n\n return div.innerHTML;\n };\n\n renderInstructions(teacherInstructions, disabledTabs = false) {\n if (!teacherInstructions) {\n return;\n }\n\n const teacherInstructionsDiv = (\n <PreviewPrompt\n tagName=\"div\"\n className=\"prompt\"\n defaultClassName=\"teacher-instructions\"\n prompt={teacherInstructions}\n />\n );\n\n if (disabledTabs) {\n return teacherInstructionsDiv;\n }\n\n return (\n <Collapsible\n labels={{\n hidden: translator.t('common:showTeacherInstructions', { lng: this.props.model?.language }),\n visible: translator.t('common:hideTeacherInstructions', { lng: this.props.model?.language }),\n }}\n >\n {teacherInstructionsDiv}\n </Collapsible>\n );\n }\n\n // Outside a tab list (one passage, or print) no tab names the panel, so it renders without the\n // tabpanel role and its title heading carries the structure.\n renderTab(tab, disabledTabs, tabbed = true) {\n const { baseHeadingLevel } = this.props;\n const clampedLevel = baseHeadingLevel ? Math.min(6, Math.max(1, baseHeadingLevel)) : undefined;\n const TitleTag = baseHeadingLevel ? `h${clampedLevel}` : 'h2'; // default to h2 if no base level is provided - this was the previous behavior\n const textLevel = baseHeadingLevel ? Math.min(6, Math.max(1, clampedLevel + 1)) : undefined; // promote text headings one level above title\n\n return (\n <Passage\n key={tab.id}\n id={this.tabPanelId(tab.id)}\n className={`tabpanel-${tab.id}`}\n {...(tabbed && { role: 'tabpanel', 'aria-labelledby': this.tabButtonId(tab.id) })}\n >\n {this.renderInstructions(tab.teacherInstructions, disabledTabs)}\n\n {tab.title && (\n <Purpose purpose=\"passage-title\">\n <TitleTag>\n <PassageTitle dangerouslySetInnerHTML={{ __html: this.parsedText(tab.title) }} />\n </TitleTag>\n </Purpose>\n )}\n\n {tab.subtitle && (\n <Purpose purpose=\"passage-subtitle\">\n <PassageSubtitle dangerouslySetInnerHTML={{ __html: this.parsedText(tab.subtitle) }} />\n </Purpose>\n )}\n\n {tab.author && (\n <Purpose purpose=\"passage-author\">\n <PassageAuthor className=\"author\" dangerouslySetInnerHTML={{ __html: this.parsedText(tab.author) }} />\n </Purpose>\n )}\n\n {tab.text && (\n <Purpose purpose=\"passage-text\">\n <div key={tab.id} className=\"text\" dangerouslySetInnerHTML={{ __html: sanitizeModelHtml(baseHeadingLevel ? transformDataHeadings(tab.text, textLevel) : tab.text) }} />\n </Purpose>\n )}\n </Passage>\n );\n }\n\n render() {\n const { model, tabs, disabledTabs } = this.props;\n const { activeTab, zoomCompensation, containerWidth } = this.state;\n\n if (!tabs?.length) {\n return;\n }\n\n const { extraCSSRules } = model || {};\n const selectedTab = (tabs || []).find((tab) => tab.id === activeTab);\n\n // cap each tab at 1/n of the passage container width so a single long\n // title can't push other tabs off-screen. Existing two-line wrap + ellipsis\n // on .passage-label still trims anything that doesn't fit.\n const tabMaxWidth = containerWidth > 0 ? containerWidth / tabs.length : null;\n // When per-tab horizontal space drops to NUMERIC_LABEL_MIN_WIDTH_PER_TAB or\n // less, titles become unreadably truncated; swap to \"Passage N\" so users\n // can still navigate. Container width is read once layout has settled\n // (>0), so initial render uses real labels.\n const useNumericLabels =\n containerWidth > 0 && containerWidth <= tabs.length * NUMERIC_LABEL_MIN_WIDTH_PER_TAB;\n\n return (\n <UiLayout extraCSSRules={extraCSSRules}>\n <PassagesContainer className=\"passages\" ref={this.containerRef}>\n {disabledTabs || tabs.length === 1 ? (\n tabs.map((tab) => this.renderTab(tab, disabledTabs, false))\n ) : (\n <>\n <Tabs\n sx={{\n // Below the breakpoint (e.g. WCAG 400% zoom, ~320px viewport)\n // the tabs are in normal flow and scroll with the passage text,\n // so they don't lock up space needed to display the passage.\n position: 'static',\n // Above the breakpoint there is adequate screen space, so the\n // tabs stay locked to the top of the panel while the passage\n // text scrolls beneath them.\n [`@media (min-width: ${STICKY_TABS_BREAKPOINT + 1}px)`]: {\n position: 'sticky',\n top: 0,\n zIndex: 1,\n },\n background: 'var(--pie-passage-header-background, rgba(255,255,255,0))',\n color: color.text(),\n fontFamily: 'Roboto, sans-serif',\n // Freeze the tabs' physical size at their 200%-zoom appearance\n // when browser zoom exceeds 200%. The factor is 1 at zoom <= 200%,\n // so behavior below that threshold is unchanged. Using `zoom`\n // (rather than transform: scale) shrinks the layout box itself,\n // so the reclaimed space flows to the passage content below.\n zoom: zoomCompensation,\n '& .MuiTabs-list': {\n /*\n * The strip behind the tabs. A host that has opted into\n * `--pie-passage-header-background` keeps its own colour on every\n * scheme -- Knowledge Checks' pale green-blue is deliberate and is not\n * a scheme's business to override. With no host colour the fallback has\n * to be a theme token rather than a white literal, or the strip stays\n * white over a dark passage body.\n */\n backgroundColor: `var(--pie-passage-header-background, ${color.backgroundDark()})`,\n borderBottom: `1px solid ${color.borderGray()}`,\n },\n '& .MuiTabs-indicator': {\n backgroundColor: color.white(),\n marginBottom: '-1px',\n },\n }}\n value={activeTab}\n onChange={this.handleChange}\n >\n {tabs.map((tab, index) => (\n <TabStyled\n key={tab.id}\n id={this.tabButtonId(tab.id)}\n className={`button-${tab.id}`}\n sx={tabMaxWidth ? { maxWidth: `${tabMaxWidth}px` } : undefined}\n label={\n <>\n <Purpose purpose=\"passage-label\">\n {useNumericLabels ? (\n <span className=\"passage-label\">{`Passage ${index + 1}`}</span>\n ) : (\n <span\n className=\"passage-label\"\n dangerouslySetInnerHTML={{ __html: this.parsedText(tab.label) }}\n />\n )}\n </Purpose>\n <Underline className=\"passage-label-underline\" />\n </>\n }\n value={tab.id}\n tabIndex={activeTab === tab.id ? 0 : -1}\n aria-controls={this.tabPanelId(tab.id)}\n aria-selected={activeTab === tab.id}\n onKeyDown={(event) => this.handleKeyDown(event, tab.id)}\n />\n ))}\n </Tabs>\n {selectedTab ? this.renderTab(selectedTab, disabledTabs) : null}\n </>\n )}\n </PassagesContainer>\n </UiLayout>\n );\n }\n}\n\nStimulusTabs.propTypes = {\n tabs: PropTypes.arrayOf(\n PropTypes.shape({\n id: PropTypes.number.isRequired,\n label: PropTypes.string.isRequired,\n title: PropTypes.string.isRequired,\n subtitle: PropTypes.string,\n author: PropTypes.string,\n text: PropTypes.string.isRequired,\n teacherInstructions: PropTypes.string,\n }).isRequired,\n ).isRequired,\n disabledTabs: PropTypes.bool,\n model: PropTypes.object,\n baseHeadingLevel: PropTypes.number,\n};\n\nexport default StimulusTabs;\n"],"mappings":"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"}
@@ -7,19 +7,20 @@ import * as a from "@pie-lib/render-ui";
7
7
  import { Collapsible as o, PreviewPrompt as s, Purpose as c, UiLayout as l, color as u, createUniqueId as d, transformDataHeadings as f } from "@pie-lib/render-ui";
8
8
  import p from "@pie-lib/translator";
9
9
  import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
10
+ import { sanitizeModelHtml as _ } from "@pie-element/shared-utils";
10
11
  //#region src/delivery/stimulus-tabs.tsx
11
- var { translator: _ } = p;
12
- function v(e) {
12
+ var { translator: v } = p;
13
+ function y(e) {
13
14
  return typeof e == "function" || typeof e == "object" && !!e && typeof e.$$typeof == "symbol";
14
15
  }
15
- function y(e, t) {
16
- return !e || v(e) ? e : v(e.default) ? e.default : t && v(e[t]) ? e[t] : t && v(e[t]?.default) ? e[t].default : e;
16
+ function b(e, t) {
17
+ return !e || y(e) ? e : y(e.default) ? e.default : t && y(e[t]) ? e[t] : t && y(e[t]?.default) ? e[t].default : e;
17
18
  }
18
- var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(E.Purpose, "Purpose"), S = y(s, "PreviewPrompt") || y(E.PreviewPrompt, "PreviewPrompt"), C = y(o, "Collapsible") || y(E.Collapsible, "Collapsible"), w = a, T = w.default, E = T && typeof T == "object" ? T : w, D = 2, O = .4, k = 170, A = () => {
19
+ var x = b(l, "UiLayout") || b(D.UiLayout, "UiLayout"), S = b(c, "Purpose") || b(D.Purpose, "Purpose"), C = b(s, "PreviewPrompt") || b(D.PreviewPrompt, "PreviewPrompt"), w = b(o, "Collapsible") || b(D.Collapsible, "Collapsible"), T = a, E = T.default, D = E && typeof E == "object" ? E : T, O = 2, k = .4, A = 170, j = () => {
19
20
  if (typeof window > "u") return 1;
20
21
  let e = window.outerWidth / window.innerWidth;
21
- return Math.max(O, Math.min(1, D / (Number.isFinite(e) && e > 0 ? e : 1)));
22
- }, j = i("div")({
22
+ return Math.max(k, Math.min(1, O / (Number.isFinite(e) && e > 0 ? e : 1)));
23
+ }, M = i("div")({
23
24
  flexGrow: 1,
24
25
  backgroundColor: u.background(),
25
26
  color: u.text(),
@@ -28,7 +29,7 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
28
29
  padding: ".6em 1em",
29
30
  textAlign: "left"
30
31
  }
31
- }), M = i("div")(({ theme: e }) => ({
32
+ }), N = i("div")(({ theme: e }) => ({
32
33
  backgroundColor: u.background(),
33
34
  color: u.text(),
34
35
  padding: e.spacing(2),
@@ -38,7 +39,7 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
38
39
  margin: "1.5em 10px",
39
40
  padding: ".5em 10px"
40
41
  }
41
- })), N = i("div")({ fontSize: "1.75rem" }), P = i("div")({ fontSize: "1.5rem" }), F = i("div")({ fontSize: "1.25rem" }), I = i(r)(({ theme: e }) => ({
42
+ })), P = i("div")({ fontSize: "1.75rem" }), F = i("div")({ fontSize: "1.5rem" }), I = i("div")({ fontSize: "1.25rem" }), L = i(r)(({ theme: e }) => ({
42
43
  background: u.background(),
43
44
  fontSize: "inherit",
44
45
  fontFamily: "Roboto, sans-serif",
@@ -70,15 +71,15 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
70
71
  },
71
72
  "&:hover": { ".passage-label-underline": { backgroundColor: u.tertiaryLight() } },
72
73
  "& .MuiTouchRipple-root": { opacity: .7 }
73
- })), L = i("div")(() => ({
74
+ })), R = i("div")(() => ({
74
75
  height: "2px",
75
76
  width: "100%",
76
77
  marginTop: "6px",
77
78
  background: u.background()
78
- })), R = class extends e.Component {
79
+ })), z = class extends e.Component {
79
80
  state = {
80
81
  activeTab: 0,
81
- zoomCompensation: A(),
82
+ zoomCompensation: j(),
82
83
  containerWidth: 0
83
84
  };
84
85
  containerRef = e.createRef();
@@ -92,7 +93,7 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
92
93
  typeof window > "u" || (window.removeEventListener("resize", this.updateZoomCompensation), this.resizeObserver &&= (this.resizeObserver.disconnect(), null));
93
94
  }
94
95
  updateZoomCompensation = () => {
95
- this.setState({ zoomCompensation: A() });
96
+ this.setState({ zoomCompensation: j() });
96
97
  };
97
98
  updateContainerWidth = () => {
98
99
  let e = this.containerRef.current;
@@ -131,7 +132,7 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
131
132
  };
132
133
  parsedText = (e = "") => {
133
134
  let t = document.createElement("div");
134
- t.innerHTML = e.replace(/(<br\/>\n)/g, "<br/>");
135
+ t.innerHTML = _(e.replace(/(<br\/>\n)/g, "<br/>"));
135
136
  let n = t.querySelector("audio");
136
137
  if (n) {
137
138
  let e = document.createElement("source");
@@ -141,23 +142,23 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
141
142
  };
142
143
  renderInstructions(e, t = !1) {
143
144
  if (!e) return;
144
- let n = /* @__PURE__ */ h(S, {
145
+ let n = /* @__PURE__ */ h(C, {
145
146
  tagName: "div",
146
147
  className: "prompt",
147
148
  defaultClassName: "teacher-instructions",
148
149
  prompt: e
149
150
  });
150
- return t ? n : /* @__PURE__ */ h(C, {
151
+ return t ? n : /* @__PURE__ */ h(w, {
151
152
  labels: {
152
- hidden: _.t("common:showTeacherInstructions", { lng: this.props.model?.language }),
153
- visible: _.t("common:hideTeacherInstructions", { lng: this.props.model?.language })
153
+ hidden: v.t("common:showTeacherInstructions", { lng: this.props.model?.language }),
154
+ visible: v.t("common:hideTeacherInstructions", { lng: this.props.model?.language })
154
155
  },
155
156
  children: n
156
157
  });
157
158
  }
158
159
  renderTab(e, t, n = !0) {
159
160
  let { baseHeadingLevel: r } = this.props, i = r ? Math.min(6, Math.max(1, r)) : void 0, a = r ? `h${i}` : "h2", o = r ? Math.min(6, Math.max(1, i + 1)) : void 0;
160
- return /* @__PURE__ */ g(M, {
161
+ return /* @__PURE__ */ g(N, {
161
162
  id: this.tabPanelId(e.id),
162
163
  className: `tabpanel-${e.id}`,
163
164
  ...n && {
@@ -166,26 +167,26 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
166
167
  },
167
168
  children: [
168
169
  this.renderInstructions(e.teacherInstructions, t),
169
- e.title && /* @__PURE__ */ h(x, {
170
+ e.title && /* @__PURE__ */ h(S, {
170
171
  purpose: "passage-title",
171
- children: /* @__PURE__ */ h(a, { children: /* @__PURE__ */ h(N, { dangerouslySetInnerHTML: { __html: this.parsedText(e.title) } }) })
172
+ children: /* @__PURE__ */ h(a, { children: /* @__PURE__ */ h(P, { dangerouslySetInnerHTML: { __html: this.parsedText(e.title) } }) })
172
173
  }),
173
- e.subtitle && /* @__PURE__ */ h(x, {
174
+ e.subtitle && /* @__PURE__ */ h(S, {
174
175
  purpose: "passage-subtitle",
175
- children: /* @__PURE__ */ h(P, { dangerouslySetInnerHTML: { __html: this.parsedText(e.subtitle) } })
176
+ children: /* @__PURE__ */ h(F, { dangerouslySetInnerHTML: { __html: this.parsedText(e.subtitle) } })
176
177
  }),
177
- e.author && /* @__PURE__ */ h(x, {
178
+ e.author && /* @__PURE__ */ h(S, {
178
179
  purpose: "passage-author",
179
- children: /* @__PURE__ */ h(F, {
180
+ children: /* @__PURE__ */ h(I, {
180
181
  className: "author",
181
182
  dangerouslySetInnerHTML: { __html: this.parsedText(e.author) }
182
183
  })
183
184
  }),
184
- e.text && /* @__PURE__ */ h(x, {
185
+ e.text && /* @__PURE__ */ h(S, {
185
186
  purpose: "passage-text",
186
187
  children: /* @__PURE__ */ h("div", {
187
188
  className: "text",
188
- dangerouslySetInnerHTML: { __html: r ? f(e.text, o) : e.text }
189
+ dangerouslySetInnerHTML: { __html: _(r ? f(e.text, o) : e.text) }
189
190
  }, e.id)
190
191
  })
191
192
  ]
@@ -194,10 +195,10 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
194
195
  render() {
195
196
  let { model: e, tabs: t, disabledTabs: r } = this.props, { activeTab: i, zoomCompensation: a, containerWidth: o } = this.state;
196
197
  if (!t?.length) return;
197
- let { extraCSSRules: s } = e || {}, c = (t || []).find((e) => e.id === i), l = o > 0 ? o / t.length : null, d = o > 0 && o <= t.length * k;
198
- return /* @__PURE__ */ h(b, {
198
+ let { extraCSSRules: s } = e || {}, c = (t || []).find((e) => e.id === i), l = o > 0 ? o / t.length : null, d = o > 0 && o <= t.length * A;
199
+ return /* @__PURE__ */ h(x, {
199
200
  extraCSSRules: s,
200
- children: /* @__PURE__ */ h(j, {
201
+ children: /* @__PURE__ */ h(M, {
201
202
  className: "passages",
202
203
  ref: this.containerRef,
203
204
  children: r || t.length === 1 ? t.map((e) => this.renderTab(e, r, !1)) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(n, {
@@ -223,11 +224,11 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
223
224
  },
224
225
  value: i,
225
226
  onChange: this.handleChange,
226
- children: t.map((e, t) => /* @__PURE__ */ h(I, {
227
+ children: t.map((e, t) => /* @__PURE__ */ h(L, {
227
228
  id: this.tabButtonId(e.id),
228
229
  className: `button-${e.id}`,
229
230
  sx: l ? { maxWidth: `${l}px` } : void 0,
230
- label: /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(x, {
231
+ label: /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(S, {
231
232
  purpose: "passage-label",
232
233
  children: d ? /* @__PURE__ */ h("span", {
233
234
  className: "passage-label",
@@ -236,7 +237,7 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
236
237
  className: "passage-label",
237
238
  dangerouslySetInnerHTML: { __html: this.parsedText(e.label) }
238
239
  })
239
- }), /* @__PURE__ */ h(L, { className: "passage-label-underline" })] }),
240
+ }), /* @__PURE__ */ h(R, { className: "passage-label-underline" })] }),
240
241
  value: e.id,
241
242
  tabIndex: i === e.id ? 0 : -1,
242
243
  "aria-controls": this.tabPanelId(e.id),
@@ -248,7 +249,7 @@ var b = y(l, "UiLayout") || y(E.UiLayout, "UiLayout"), x = y(c, "Purpose") || y(
248
249
  });
249
250
  }
250
251
  };
251
- R.propTypes = {
252
+ z.propTypes = {
252
253
  tabs: t.arrayOf(t.shape({
253
254
  id: t.number.isRequired,
254
255
  label: t.string.isRequired,
@@ -263,4 +264,4 @@ R.propTypes = {
263
264
  baseHeadingLevel: t.number
264
265
  };
265
266
  //#endregion
266
- export { R as default };
267
+ export { z as default };