@ndla/ui 56.0.185-alpha.0 → 56.0.187-alpha.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/dist/panda.buildinfo.json +20 -27
- package/dist/styles.css +61 -140
- package/es/Article/ArticleByline.mjs +2 -1
- package/es/Article/ArticleByline.mjs.map +1 -1
- package/es/AudioPlayer/AudioElement.mjs +12 -0
- package/es/AudioPlayer/AudioElement.mjs.map +1 -0
- package/es/AudioPlayer/AudioPlayer.mjs +7 -2
- package/es/AudioPlayer/AudioPlayer.mjs.map +1 -1
- package/es/AudioPlayer/AudioProgress.mjs +54 -0
- package/es/AudioPlayer/AudioProgress.mjs.map +1 -0
- package/es/AudioPlayer/CompactAudioPlayer.mjs +111 -0
- package/es/AudioPlayer/CompactAudioPlayer.mjs.map +1 -0
- package/es/AudioPlayer/Controls.mjs +25 -110
- package/es/AudioPlayer/Controls.mjs.map +1 -1
- package/es/AudioPlayer/PlayButton.mjs +24 -0
- package/es/AudioPlayer/PlayButton.mjs.map +1 -0
- package/es/AudioPlayer/SpeechControl.mjs +5 -16
- package/es/AudioPlayer/SpeechControl.mjs.map +1 -1
- package/es/AudioPlayer/VolumeSlider.mjs +31 -0
- package/es/AudioPlayer/VolumeSlider.mjs.map +1 -0
- package/es/AudioPlayer/audioUtils.mjs +17 -0
- package/es/AudioPlayer/audioUtils.mjs.map +1 -0
- package/es/AudioPlayer/useAudioControls.mjs +55 -0
- package/es/AudioPlayer/useAudioControls.mjs.map +1 -0
- package/es/Breadcrumb/BreadcrumbItem.mjs +1 -2
- package/es/Breadcrumb/BreadcrumbItem.mjs.map +1 -1
- package/es/Embed/AudioEmbed.mjs +3 -7
- package/es/Embed/AudioEmbed.mjs.map +1 -1
- package/es/Embed/ExternalEmbed.mjs +13 -16
- package/es/Embed/ExternalEmbed.mjs.map +1 -1
- package/es/Embed/IframeEmbed.mjs +4 -5
- package/es/Embed/IframeEmbed.mjs.map +1 -1
- package/es/FactBox/FactBox.mjs +14 -38
- package/es/FactBox/FactBox.mjs.map +1 -1
- package/es/Gloss/Gloss.mjs +1 -2
- package/es/Gloss/Gloss.mjs.map +1 -1
- package/es/Grid/Grid.mjs +1 -2
- package/es/Grid/Grid.mjs.map +1 -1
- package/es/LinkBlock/LinkBlock.mjs +9 -2
- package/es/LinkBlock/LinkBlock.mjs.map +1 -1
- package/es/Pitch/Pitch.mjs +1 -2
- package/es/Pitch/Pitch.mjs.map +1 -1
- package/es/index.mjs +2 -1
- package/lib/Article/ArticleByline.js +2 -1
- package/lib/Article/ArticleByline.js.map +1 -1
- package/lib/AudioPlayer/AudioElement.d.ts +14 -0
- package/lib/AudioPlayer/AudioElement.js +13 -0
- package/lib/AudioPlayer/AudioElement.js.map +1 -0
- package/lib/AudioPlayer/AudioPlayer.d.ts +5 -4
- package/lib/AudioPlayer/AudioPlayer.js +7 -2
- package/lib/AudioPlayer/AudioPlayer.js.map +1 -1
- package/lib/AudioPlayer/AudioProgress.d.ts +16 -0
- package/lib/AudioPlayer/AudioProgress.js +55 -0
- package/lib/AudioPlayer/AudioProgress.js.map +1 -0
- package/lib/AudioPlayer/CompactAudioPlayer.d.ts +13 -0
- package/lib/AudioPlayer/CompactAudioPlayer.js +112 -0
- package/lib/AudioPlayer/CompactAudioPlayer.js.map +1 -0
- package/lib/AudioPlayer/Controls.d.ts +1 -0
- package/lib/AudioPlayer/Controls.js +25 -110
- package/lib/AudioPlayer/Controls.js.map +1 -1
- package/lib/AudioPlayer/PlayButton.d.ts +13 -0
- package/lib/AudioPlayer/PlayButton.js +25 -0
- package/lib/AudioPlayer/PlayButton.js.map +1 -0
- package/lib/AudioPlayer/SpeechControl.d.ts +1 -2
- package/lib/AudioPlayer/SpeechControl.js +5 -16
- package/lib/AudioPlayer/SpeechControl.js.map +1 -1
- package/lib/AudioPlayer/VolumeSlider.d.ts +14 -0
- package/lib/AudioPlayer/VolumeSlider.js +32 -0
- package/lib/AudioPlayer/VolumeSlider.js.map +1 -0
- package/lib/AudioPlayer/audioUtils.d.ts +8 -0
- package/lib/AudioPlayer/audioUtils.js +17 -0
- package/lib/AudioPlayer/audioUtils.js.map +1 -0
- package/lib/AudioPlayer/useAudioControls.d.ts +24 -0
- package/lib/AudioPlayer/useAudioControls.js +56 -0
- package/lib/AudioPlayer/useAudioControls.js.map +1 -0
- package/lib/Breadcrumb/BreadcrumbItem.js +1 -2
- package/lib/Breadcrumb/BreadcrumbItem.js.map +1 -1
- package/lib/Embed/AudioEmbed.js +3 -7
- package/lib/Embed/AudioEmbed.js.map +1 -1
- package/lib/Embed/ExternalEmbed.js +13 -16
- package/lib/Embed/ExternalEmbed.js.map +1 -1
- package/lib/Embed/IframeEmbed.js +4 -5
- package/lib/Embed/IframeEmbed.js.map +1 -1
- package/lib/FactBox/FactBox.js +13 -37
- package/lib/FactBox/FactBox.js.map +1 -1
- package/lib/Gloss/Gloss.js +1 -2
- package/lib/Gloss/Gloss.js.map +1 -1
- package/lib/Grid/Grid.js +1 -2
- package/lib/Grid/Grid.js.map +1 -1
- package/lib/LinkBlock/LinkBlock.js +9 -2
- package/lib/LinkBlock/LinkBlock.js.map +1 -1
- package/lib/Pitch/Pitch.js +1 -2
- package/lib/Pitch/Pitch.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/package.json +10 -10
- package/src/Article/ArticleByline.tsx +5 -1
- package/src/AudioPlayer/AudioElement.tsx +20 -0
- package/src/AudioPlayer/{AudiPlayer.stories.tsx → AudioPlayer.stories.tsx} +10 -1
- package/src/AudioPlayer/AudioPlayer.tsx +12 -5
- package/src/AudioPlayer/AudioProgress.tsx +92 -0
- package/src/AudioPlayer/CompactAudioPlayer.tsx +124 -0
- package/src/AudioPlayer/Controls.tsx +36 -149
- package/src/AudioPlayer/PlayButton.tsx +24 -0
- package/src/AudioPlayer/SpeechControl.tsx +6 -19
- package/src/AudioPlayer/VolumeSlider.tsx +56 -0
- package/src/AudioPlayer/audioUtils.ts +15 -0
- package/src/AudioPlayer/useAudioControls.ts +80 -0
- package/src/Embed/AudioEmbed.tsx +3 -4
- package/src/FactBox/FactBox.tsx +13 -43
- package/src/Gloss/Gloss.tsx +1 -1
- package/src/LinkBlock/LinkBlock.tsx +5 -2
- package/src/index.ts +2 -0
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
type Props = {
|
|
9
9
|
src: string;
|
|
10
10
|
title: string;
|
|
11
|
-
type?: "gloss" | "audio";
|
|
12
11
|
};
|
|
13
|
-
export declare const SpeechControl: ({ src, title
|
|
12
|
+
export declare const SpeechControl: ({ src, title }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
14
13
|
export {};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require("../_virtual/_rolldown/runtime.js");
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
let react_i18next = require("react-i18next");
|
|
2
|
+
const require_PlayButton = require("./PlayButton.js");
|
|
3
|
+
const require_useAudioControls = require("./useAudioControls.js");
|
|
5
4
|
let _ndla_icons = require("@ndla/icons");
|
|
6
5
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
6
|
//#region src/AudioPlayer/SpeechControl.tsx
|
|
@@ -12,16 +11,8 @@ let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
12
11
|
* LICENSE file in the root directory of this source tree.
|
|
13
12
|
*
|
|
14
13
|
*/
|
|
15
|
-
const SpeechControl = ({ src, title
|
|
16
|
-
const {
|
|
17
|
-
const audioRef = (0, react.useRef)(null);
|
|
18
|
-
const togglePlay = () => {
|
|
19
|
-
if (audioRef.current) {
|
|
20
|
-
const audioElement = audioRef.current;
|
|
21
|
-
if (audioElement.paused) audioElement.play();
|
|
22
|
-
else audioElement.pause();
|
|
23
|
-
}
|
|
24
|
-
};
|
|
14
|
+
const SpeechControl = ({ src, title }) => {
|
|
15
|
+
const { audioRef, togglePlay } = require_useAudioControls.useAudioControls();
|
|
25
16
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
26
17
|
"data-embed-type": "speech",
|
|
27
18
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
|
|
@@ -29,10 +20,8 @@ const SpeechControl = ({ src, title, type = "audio" }) => {
|
|
|
29
20
|
src,
|
|
30
21
|
title,
|
|
31
22
|
preload: "metadata"
|
|
32
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
23
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_PlayButton.PlayButton, {
|
|
33
24
|
variant: "tertiary",
|
|
34
|
-
"aria-label": t(`${type}.play`),
|
|
35
|
-
title: t(`${type}.play`),
|
|
36
25
|
onClick: togglePlay,
|
|
37
26
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ndla_icons.VolumeUpFill, {})
|
|
38
27
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpeechControl.js","names":["
|
|
1
|
+
{"version":3,"file":"SpeechControl.js","names":["useAudioControls","PlayButton","VolumeUpFill"],"sources":["../../src/AudioPlayer/SpeechControl.tsx"],"sourcesContent":["/**\n * Copyright (c) 2021-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { VolumeUpFill } from \"@ndla/icons\";\nimport { PlayButton } from \"./PlayButton\";\nimport { useAudioControls } from \"./useAudioControls\";\n\ntype Props = {\n src: string;\n title: string;\n};\n\nexport const SpeechControl = ({ src, title }: Props) => {\n const { audioRef, togglePlay } = useAudioControls();\n\n return (\n <div data-embed-type=\"speech\">\n {/* oxlint-disable-next-line jsx-a11y/media-has-caption */}\n <audio ref={audioRef} src={src} title={title} preload=\"metadata\" />\n <PlayButton variant=\"tertiary\" onClick={togglePlay}>\n <VolumeUpFill />\n </PlayButton>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAiBA,MAAa,iBAAiB,EAAE,KAAK,YAAmB;CACtD,MAAM,EAAE,UAAU,eAAeA,yBAAAA,kBAAkB;AAEnD,QACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EAAK,mBAAgB;YAArB,CAEE,iBAAA,GAAA,kBAAA,KAAC,SAAD;GAAO,KAAK;GAAe;GAAY;GAAO,SAAQ;GAAa,CAAA,EACnE,iBAAA,GAAA,kBAAA,KAACC,mBAAAA,YAAD;GAAY,SAAQ;GAAW,SAAS;aACtC,iBAAA,GAAA,kBAAA,KAACC,YAAAA,cAAD,EAAgB,CAAA;GACL,CAAA,CACT"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { SliderValueChangeDetails } from "@ark-ui/react";
|
|
9
|
+
interface Props {
|
|
10
|
+
value: number;
|
|
11
|
+
onValueChange: (value: SliderValueChangeDetails) => void;
|
|
12
|
+
}
|
|
13
|
+
export declare const VolumeSlider: ({ value, onValueChange }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.js");
|
|
2
|
+
let _ndla_primitives = require("@ndla/primitives");
|
|
3
|
+
let _ndla_styled_system_jsx = require("@ndla/styled-system/jsx");
|
|
4
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
|
+
let i18next = require("i18next");
|
|
6
|
+
//#region src/AudioPlayer/VolumeSlider.tsx
|
|
7
|
+
const StyledSliderControl = (0, _ndla_styled_system_jsx.styled)(_ndla_primitives.SliderControl, { base: {
|
|
8
|
+
height: "surface.3xsmall",
|
|
9
|
+
minWidth: "small"
|
|
10
|
+
} });
|
|
11
|
+
const VolumeSlider = ({ value, onValueChange }) => {
|
|
12
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_ndla_primitives.SliderRoot, {
|
|
13
|
+
orientation: "vertical",
|
|
14
|
+
value: [value],
|
|
15
|
+
min: 0,
|
|
16
|
+
max: 100,
|
|
17
|
+
defaultValue: [100],
|
|
18
|
+
step: 1,
|
|
19
|
+
onValueChange,
|
|
20
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ndla_primitives.SliderLabel, {
|
|
21
|
+
srOnly: true,
|
|
22
|
+
children: (0, i18next.t)("audio.controls.adjustVolume")
|
|
23
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(StyledSliderControl, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ndla_primitives.SliderTrack, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ndla_primitives.SliderRange, {}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ndla_primitives.SliderThumb, {
|
|
24
|
+
index: 0,
|
|
25
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ndla_primitives.SliderHiddenInput, {})
|
|
26
|
+
})] })]
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
exports.VolumeSlider = VolumeSlider;
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=VolumeSlider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VolumeSlider.js","names":["SliderControl","SliderRoot","SliderLabel","SliderTrack","SliderRange","SliderThumb","SliderHiddenInput"],"sources":["../../src/AudioPlayer/VolumeSlider.tsx"],"sourcesContent":["/**\n * Copyright (c) 2026-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport type { SliderValueChangeDetails } from \"@ark-ui/react\";\nimport {\n SliderControl,\n SliderRoot,\n SliderLabel,\n SliderTrack,\n SliderRange,\n SliderHiddenInput,\n SliderThumb,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { t } from \"i18next\";\n\nconst StyledSliderControl = styled(SliderControl, {\n base: {\n height: \"surface.3xsmall\",\n minWidth: \"small\",\n },\n});\n\ninterface Props {\n value: number;\n onValueChange: (value: SliderValueChangeDetails) => void;\n}\n\nexport const VolumeSlider = ({ value, onValueChange }: Props) => {\n return (\n <SliderRoot\n orientation=\"vertical\"\n value={[value]}\n min={0}\n max={100}\n defaultValue={[100]}\n step={1}\n onValueChange={onValueChange}\n >\n <SliderLabel srOnly>{t(\"audio.controls.adjustVolume\")}</SliderLabel>\n <StyledSliderControl>\n <SliderTrack>\n <SliderRange />\n </SliderTrack>\n <SliderThumb index={0}>\n <SliderHiddenInput />\n </SliderThumb>\n </StyledSliderControl>\n </SliderRoot>\n );\n};\n"],"mappings":";;;;;;AAqBA,MAAM,uBAAA,GAAA,wBAAA,QAA6BA,iBAAAA,eAAe,EAChD,MAAM;CACJ,QAAQ;CACR,UAAU;CACX,EACF,CAAC;AAOF,MAAa,gBAAgB,EAAE,OAAO,oBAA2B;AAC/D,QACE,iBAAA,GAAA,kBAAA,MAACC,iBAAAA,YAAD;EACE,aAAY;EACZ,OAAO,CAAC,MAAM;EACd,KAAK;EACL,KAAK;EACL,cAAc,CAAC,IAAI;EACnB,MAAM;EACS;YAPjB,CASE,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,aAAD;GAAa,QAAA;4BAAU,8BAA8B;GAAe,CAAA,EACpE,iBAAA,GAAA,kBAAA,MAAC,qBAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,aAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,aAAD,EAAe,CAAA,EACH,CAAA,EACd,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,aAAD;GAAa,OAAO;aAClB,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,mBAAD,EAAqB,CAAA;GACT,CAAA,CACM,EAAA,CAAA,CACX"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/AudioPlayer/audioUtils.ts
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) 2026-present, NDLA.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
const formatTime = (seconds) => {
|
|
10
|
+
const minutes = Math.floor(seconds / 60);
|
|
11
|
+
const currentSeconds = seconds % 60;
|
|
12
|
+
return `${minutes}:${currentSeconds < 10 ? `0${currentSeconds}` : currentSeconds}`;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
exports.formatTime = formatTime;
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=audioUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audioUtils.js","names":[],"sources":["../../src/AudioPlayer/audioUtils.ts"],"sourcesContent":["/**\n * Copyright (c) 2026-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nexport const formatTime = (seconds: number) => {\n const minutes = Math.floor(seconds / 60);\n const currentSeconds = seconds % 60;\n\n const formattedSeconds = currentSeconds < 10 ? `0${currentSeconds}` : currentSeconds;\n return `${minutes}:${formattedSeconds}`;\n};\n"],"mappings":";;;;;;;;AAQA,MAAa,cAAc,YAAoB;CAC7C,MAAM,UAAU,KAAK,MAAM,UAAU,GAAG;CACxC,MAAM,iBAAiB,UAAU;AAGjC,QAAO,GAAG,QAAQ,GADO,iBAAiB,KAAK,IAAI,mBAAmB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import type { SliderValueChangeDetails } from "@ark-ui/react";
|
|
9
|
+
import { type ReactEventHandler } from "react";
|
|
10
|
+
export declare const useAudioControls: () => {
|
|
11
|
+
togglePlay: () => void;
|
|
12
|
+
onPlaybackRateChange: (rate: number) => void;
|
|
13
|
+
onSeekSeconds: (seconds: number) => void;
|
|
14
|
+
handleVolumeSliderChange: (details: SliderValueChangeDetails) => void;
|
|
15
|
+
handleSliderChange: (details: SliderValueChangeDetails) => void;
|
|
16
|
+
onEnded: () => void;
|
|
17
|
+
onHandleTime: ReactEventHandler<HTMLAudioElement>;
|
|
18
|
+
speedValue: number;
|
|
19
|
+
volumeValue: number;
|
|
20
|
+
currentTime: number;
|
|
21
|
+
duration: number;
|
|
22
|
+
playing: boolean;
|
|
23
|
+
audioRef: import("react").RefObject<HTMLAudioElement | null>;
|
|
24
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.js");
|
|
2
|
+
let react = require("react");
|
|
3
|
+
//#region src/AudioPlayer/useAudioControls.ts
|
|
4
|
+
const useAudioControls = () => {
|
|
5
|
+
const [speedValue, setSpeedValue] = (0, react.useState)(1);
|
|
6
|
+
const [volumeValue, setVolumeValue] = (0, react.useState)(100);
|
|
7
|
+
const [currentTime, setCurrentTime] = (0, react.useState)(0);
|
|
8
|
+
const [duration, setDuration] = (0, react.useState)(0);
|
|
9
|
+
const [playing, setPlaying] = (0, react.useState)(false);
|
|
10
|
+
const audioRef = (0, react.useRef)(null);
|
|
11
|
+
const togglePlay = (0, react.useCallback)(() => {
|
|
12
|
+
if (!audioRef.current) return;
|
|
13
|
+
if (audioRef.current.paused) audioRef.current.play();
|
|
14
|
+
else audioRef.current.pause();
|
|
15
|
+
setPlaying((p) => !p);
|
|
16
|
+
}, []);
|
|
17
|
+
const onPlaybackRateChange = (0, react.useCallback)((rate) => {
|
|
18
|
+
setSpeedValue(rate);
|
|
19
|
+
if (audioRef.current) audioRef.current.playbackRate = rate;
|
|
20
|
+
}, []);
|
|
21
|
+
const onSeekSeconds = (0, react.useCallback)((seconds) => {
|
|
22
|
+
if (audioRef.current) audioRef.current.currentTime += seconds;
|
|
23
|
+
}, []);
|
|
24
|
+
const handleSliderChange = (0, react.useCallback)((details) => {
|
|
25
|
+
const newValue = details.value[0];
|
|
26
|
+
if (audioRef.current && newValue != null && !isNaN(newValue)) audioRef.current.currentTime = details.value[0];
|
|
27
|
+
}, []);
|
|
28
|
+
return {
|
|
29
|
+
togglePlay,
|
|
30
|
+
onPlaybackRateChange,
|
|
31
|
+
onSeekSeconds,
|
|
32
|
+
handleVolumeSliderChange: (0, react.useCallback)((details) => {
|
|
33
|
+
if (audioRef.current) {
|
|
34
|
+
audioRef.current.volume = details.value[0] / 100;
|
|
35
|
+
setVolumeValue(details.value[0]);
|
|
36
|
+
}
|
|
37
|
+
}, []),
|
|
38
|
+
handleSliderChange,
|
|
39
|
+
onEnded: (0, react.useCallback)(() => setPlaying(false), []),
|
|
40
|
+
onHandleTime: (0, react.useCallback)((meta) => {
|
|
41
|
+
const target = meta.currentTarget;
|
|
42
|
+
setCurrentTime(Math.round(target.currentTime));
|
|
43
|
+
setDuration(Math.round(target.duration));
|
|
44
|
+
}, []),
|
|
45
|
+
speedValue,
|
|
46
|
+
volumeValue,
|
|
47
|
+
currentTime,
|
|
48
|
+
duration,
|
|
49
|
+
playing,
|
|
50
|
+
audioRef
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
exports.useAudioControls = useAudioControls;
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=useAudioControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAudioControls.js","names":[],"sources":["../../src/AudioPlayer/useAudioControls.ts"],"sourcesContent":["/**\n * Copyright (c) 2026-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport type { SliderValueChangeDetails } from \"@ark-ui/react\";\nimport { useCallback, useRef, useState, type ReactEventHandler } from \"react\";\n\nexport const useAudioControls = () => {\n const [speedValue, setSpeedValue] = useState(1);\n const [volumeValue, setVolumeValue] = useState(100);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [playing, setPlaying] = useState(false);\n const audioRef = useRef<HTMLAudioElement>(null);\n\n const togglePlay = useCallback(() => {\n if (!audioRef.current) return;\n if (audioRef.current.paused) {\n audioRef.current.play();\n } else {\n audioRef.current.pause();\n }\n setPlaying((p) => !p);\n }, []);\n\n const onPlaybackRateChange = useCallback((rate: number) => {\n setSpeedValue(rate);\n if (audioRef.current) {\n audioRef.current.playbackRate = rate;\n }\n }, []);\n\n const onSeekSeconds = useCallback((seconds: number) => {\n if (audioRef.current) {\n audioRef.current.currentTime += seconds;\n }\n }, []);\n\n const handleSliderChange = useCallback((details: SliderValueChangeDetails) => {\n const newValue = details.value[0];\n if (audioRef.current && newValue != null && !isNaN(newValue)) {\n audioRef.current.currentTime = details.value[0];\n }\n }, []);\n\n const handleVolumeSliderChange = useCallback((details: SliderValueChangeDetails) => {\n if (audioRef.current) {\n audioRef.current.volume = details.value[0] / 100;\n setVolumeValue(details.value[0]);\n }\n }, []);\n\n const onEnded = useCallback(() => setPlaying(false), []);\n\n const onHandleTime: ReactEventHandler<HTMLAudioElement> = useCallback((meta) => {\n const target = meta.currentTarget;\n setCurrentTime(Math.round(target.currentTime));\n setDuration(Math.round(target.duration));\n }, []);\n\n return {\n togglePlay,\n onPlaybackRateChange,\n onSeekSeconds,\n handleVolumeSliderChange,\n handleSliderChange,\n onEnded,\n onHandleTime,\n speedValue,\n volumeValue,\n currentTime,\n duration,\n playing,\n audioRef,\n };\n};\n"],"mappings":";;;AAWA,MAAa,yBAAyB;CACpC,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,UAA0B,EAAE;CAC/C,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,UAA2B,IAAI;CACnD,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,UAA2B,EAAE;CACjD,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,UAAwB,EAAE;CAC3C,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,UAAuB,MAAM;CAC7C,MAAM,YAAA,GAAA,MAAA,QAAoC,KAAK;CAE/C,MAAM,cAAA,GAAA,MAAA,mBAA+B;AACnC,MAAI,CAAC,SAAS,QAAS;AACvB,MAAI,SAAS,QAAQ,OACnB,UAAS,QAAQ,MAAM;MAEvB,UAAS,QAAQ,OAAO;AAE1B,cAAY,MAAM,CAAC,EAAE;IACpB,EAAE,CAAC;CAEN,MAAM,wBAAA,GAAA,MAAA,cAAoC,SAAiB;AACzD,gBAAc,KAAK;AACnB,MAAI,SAAS,QACX,UAAS,QAAQ,eAAe;IAEjC,EAAE,CAAC;CAEN,MAAM,iBAAA,GAAA,MAAA,cAA6B,YAAoB;AACrD,MAAI,SAAS,QACX,UAAS,QAAQ,eAAe;IAEjC,EAAE,CAAC;CAEN,MAAM,sBAAA,GAAA,MAAA,cAAkC,YAAsC;EAC5E,MAAM,WAAW,QAAQ,MAAM;AAC/B,MAAI,SAAS,WAAW,YAAY,QAAQ,CAAC,MAAM,SAAS,CAC1D,UAAS,QAAQ,cAAc,QAAQ,MAAM;IAE9C,EAAE,CAAC;AAiBN,QAAO;EACL;EACA;EACA;EACA,2BAAA,GAAA,MAAA,cAnB4C,YAAsC;AAClF,OAAI,SAAS,SAAS;AACpB,aAAS,QAAQ,SAAS,QAAQ,MAAM,KAAK;AAC7C,mBAAe,QAAQ,MAAM,GAAG;;KAEjC,EAAE,CAAC;EAeJ;EACA,UAAA,GAAA,MAAA,mBAdgC,WAAW,MAAM,EAAE,EAAE,CAAC;EAetD,eAAA,GAAA,MAAA,cAbqE,SAAS;GAC9E,MAAM,SAAS,KAAK;AACpB,kBAAe,KAAK,MAAM,OAAO,YAAY,CAAC;AAC9C,eAAY,KAAK,MAAM,OAAO,SAAS,CAAC;KACvC,EAAE,CAAC;EAUJ;EACA;EACA;EACA;EACA;EACA;EACD"}
|
|
@@ -19,9 +19,8 @@ const StyledListItem = (0, _ndla_styled_system_jsx.styled)("li", { base: {
|
|
|
19
19
|
"& a": { _visited: { color: "inherit" } }
|
|
20
20
|
} });
|
|
21
21
|
const BreadcrumbItem = ({ renderItem, renderSeparator, item, totalCount }) => {
|
|
22
|
-
const isLast = item.index === totalCount - 1;
|
|
23
22
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(StyledListItem, {
|
|
24
|
-
"aria-current":
|
|
23
|
+
"aria-current": item.index === totalCount - 1 ? "page" : void 0,
|
|
25
24
|
children: [renderItem(item, totalCount), renderSeparator(item, totalCount)]
|
|
26
25
|
});
|
|
27
26
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BreadcrumbItem.js","names":[],"sources":["../../src/Breadcrumb/BreadcrumbItem.tsx"],"sourcesContent":["/**\n * Copyright (c) 2016-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { type ReactNode } from \"react\";\n\nexport interface SimpleBreadcrumbItem {\n to: string | Partial<Location>;\n name: ReactNode;\n}\n\nexport interface IndexedBreadcrumbItem extends SimpleBreadcrumbItem {\n index: number;\n}\n\nexport interface BreadcrumbRenderProps {\n item: IndexedBreadcrumbItem;\n totalCount: number;\n}\n\nconst StyledListItem = styled(\"li\", {\n base: {\n display: \"flex\",\n color: \"inherit\",\n gap: \"3xsmall\",\n alignItems: \"flex-end\",\n tabletDown: {\n display: \"block\",\n },\n \"& a\": {\n _visited: {\n color: \"inherit\",\n },\n },\n },\n});\n\ninterface Props {\n item: IndexedBreadcrumbItem;\n autoCollapse?: boolean;\n totalCount: number;\n renderItem: (item: IndexedBreadcrumbItem, totalCount: number) => ReactNode;\n renderSeparator: (item: IndexedBreadcrumbItem, totalCount: number) => ReactNode;\n}\n\nexport const BreadcrumbItem = ({ renderItem, renderSeparator, item, totalCount }: Props) => {\n const isLast = item.index === totalCount - 1;\n return (\n <StyledListItem aria-current={isLast ? \"page\" : undefined}>\n {renderItem(item, totalCount)}\n {renderSeparator(item, totalCount)}\n </StyledListItem>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAyBA,MAAM,kBAAA,GAAA,wBAAA,QAAwB,MAAM,EAClC,MAAM;CACJ,SAAS;CACT,OAAO;CACP,KAAK;CACL,YAAY;CACZ,YAAY,EACV,SAAS,SACV;CACD,OAAO,EACL,UAAU,EACR,OAAO,WACR,EACF;CACF,EACF,CAAC;AAUF,MAAa,kBAAkB,EAAE,YAAY,iBAAiB,MAAM,iBAAwB;
|
|
1
|
+
{"version":3,"file":"BreadcrumbItem.js","names":[],"sources":["../../src/Breadcrumb/BreadcrumbItem.tsx"],"sourcesContent":["/**\n * Copyright (c) 2016-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { type ReactNode } from \"react\";\n\nexport interface SimpleBreadcrumbItem {\n to: string | Partial<Location>;\n name: ReactNode;\n}\n\nexport interface IndexedBreadcrumbItem extends SimpleBreadcrumbItem {\n index: number;\n}\n\nexport interface BreadcrumbRenderProps {\n item: IndexedBreadcrumbItem;\n totalCount: number;\n}\n\nconst StyledListItem = styled(\"li\", {\n base: {\n display: \"flex\",\n color: \"inherit\",\n gap: \"3xsmall\",\n alignItems: \"flex-end\",\n tabletDown: {\n display: \"block\",\n },\n \"& a\": {\n _visited: {\n color: \"inherit\",\n },\n },\n },\n});\n\ninterface Props {\n item: IndexedBreadcrumbItem;\n autoCollapse?: boolean;\n totalCount: number;\n renderItem: (item: IndexedBreadcrumbItem, totalCount: number) => ReactNode;\n renderSeparator: (item: IndexedBreadcrumbItem, totalCount: number) => ReactNode;\n}\n\nexport const BreadcrumbItem = ({ renderItem, renderSeparator, item, totalCount }: Props) => {\n const isLast = item.index === totalCount - 1;\n return (\n <StyledListItem aria-current={isLast ? \"page\" : undefined}>\n {renderItem(item, totalCount)}\n {renderSeparator(item, totalCount)}\n </StyledListItem>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAyBA,MAAM,kBAAA,GAAA,wBAAA,QAAwB,MAAM,EAClC,MAAM;CACJ,SAAS;CACT,OAAO;CACP,KAAK;CACL,YAAY;CACZ,YAAY,EACV,SAAS,SACV;CACD,OAAO,EACL,UAAU,EACR,OAAO,WACR,EACF;CACF,EACF,CAAC;AAUF,MAAa,kBAAkB,EAAE,YAAY,iBAAiB,MAAM,iBAAwB;AAE1F,QACE,iBAAA,GAAA,kBAAA,MAAC,gBAAD;EAAgB,gBAFH,KAAK,UAAU,aAAa,IAEF,SAAS,KAAA;YAAhD,CACG,WAAW,MAAM,WAAW,EAC5B,gBAAgB,MAAM,WAAW,CACnB"}
|
package/lib/Embed/AudioEmbed.js
CHANGED
|
@@ -19,11 +19,7 @@ const AudioEmbed = ({ embed, lang }) => {
|
|
|
19
19
|
const type = embed.embedData.type === "standard" ? "audio" : "podcast";
|
|
20
20
|
if (embed.status === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_EmbedErrorPlaceholder.EmbedErrorPlaceholder, { type });
|
|
21
21
|
const { data, embedData } = embed;
|
|
22
|
-
|
|
23
|
-
speech: true,
|
|
24
|
-
src: data.audioFile.url,
|
|
25
|
-
title: data.title.title
|
|
26
|
-
});
|
|
22
|
+
const variant = embedData.type === "podcast" ? "standard" : embedData.type;
|
|
27
23
|
const subtitle = data.series ? {
|
|
28
24
|
title: data.series.title.title,
|
|
29
25
|
url: `/podkast/${data.series.id}`
|
|
@@ -33,12 +29,12 @@ const AudioEmbed = ({ embed, lang }) => {
|
|
|
33
29
|
url: coverPhoto.url,
|
|
34
30
|
alt: coverPhoto.altText
|
|
35
31
|
};
|
|
36
|
-
const licenseProps = require_licenseAttributes.licenseAttributes(data.copyright.license.license, lang, embedData.url);
|
|
37
32
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(StyledFigure, {
|
|
38
33
|
lang,
|
|
39
34
|
"data-embed-type": type,
|
|
40
|
-
...
|
|
35
|
+
...require_licenseAttributes.licenseAttributes(data.copyright.license.license, lang, embedData.url),
|
|
41
36
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_AudioPlayer.AudioPlayer, {
|
|
37
|
+
variant,
|
|
42
38
|
description: data.podcastMeta?.introduction ?? "",
|
|
43
39
|
img,
|
|
44
40
|
src: data.audioFile.url,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioEmbed.js","names":["Figure","EmbedErrorPlaceholder","
|
|
1
|
+
{"version":3,"file":"AudioEmbed.js","names":["Figure","EmbedErrorPlaceholder","licenseAttributes","AudioPlayer","EmbedByline"],"sources":["../../src/Embed/AudioEmbed.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { Figure } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { AudioMetaData } from \"@ndla/types-embed\";\nimport { AudioPlayer, type AudioPlayerVariant } from \"../AudioPlayer/AudioPlayer\";\nimport { EmbedByline } from \"../LicenseByline/EmbedByline\";\nimport { licenseAttributes } from \"../utils/licenseAttributes\";\nimport { EmbedErrorPlaceholder } from \"./EmbedErrorPlaceholder\";\nimport type { Author } from \"./ImageEmbed\";\n\nconst StyledFigure = styled(Figure, {\n base: {\n clear: \"both\",\n },\n});\n\ninterface Props {\n embed: AudioMetaData;\n lang?: string;\n}\n\nexport const getFirstNonEmptyLicenseCredits = (authors: {\n creators: Author[];\n rightsholders: Author[];\n processors: Author[];\n}) => Object.values(authors).find((i) => i.length > 0) ?? [];\n\nexport const AudioEmbed = ({ embed, lang }: Props) => {\n const type = embed.embedData.type === \"standard\" ? \"audio\" : \"podcast\";\n if (embed.status === \"error\") {\n return <EmbedErrorPlaceholder type={type} />;\n }\n\n const { data, embedData } = embed;\n\n const variant = embedData.type === \"podcast\" ? \"standard\" : (embedData.type as AudioPlayerVariant);\n\n const subtitle = data.series ? { title: data.series.title.title, url: `/podkast/${data.series.id}` } : undefined;\n\n const coverPhoto = data.podcastMeta?.coverPhoto;\n\n const img = coverPhoto && { url: coverPhoto.url, alt: coverPhoto.altText };\n\n const licenseProps = licenseAttributes(data.copyright.license.license, lang, embedData.url);\n\n return (\n <StyledFigure lang={lang} data-embed-type={type} {...licenseProps}>\n <AudioPlayer\n variant={variant}\n description={data.podcastMeta?.introduction ?? \"\"}\n img={img}\n src={data.audioFile.url}\n textVersion={\n data.manuscript?.manuscript.length ? (\n <div dangerouslySetInnerHTML={{ __html: data.manuscript.manuscript }} />\n ) : undefined\n }\n title={data.title.title}\n subtitle={subtitle}\n />\n <EmbedByline\n error={false}\n type={data.audioType === \"standard\" ? \"audio\" : \"podcast\"}\n copyright={embed.data.copyright}\n />\n </StyledFigure>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,MAAM,gBAAA,GAAA,wBAAA,QAAsBA,iBAAAA,QAAQ,EAClC,MAAM,EACJ,OAAO,QACR,EACF,CAAC;AAaF,MAAa,cAAc,EAAE,OAAO,WAAkB;CACpD,MAAM,OAAO,MAAM,UAAU,SAAS,aAAa,UAAU;AAC7D,KAAI,MAAM,WAAW,QACnB,QAAO,iBAAA,GAAA,kBAAA,KAACC,8BAAAA,uBAAD,EAA6B,MAAQ,CAAA;CAG9C,MAAM,EAAE,MAAM,cAAc;CAE5B,MAAM,UAAU,UAAU,SAAS,YAAY,aAAc,UAAU;CAEvE,MAAM,WAAW,KAAK,SAAS;EAAE,OAAO,KAAK,OAAO,MAAM;EAAO,KAAK,YAAY,KAAK,OAAO;EAAM,GAAG,KAAA;CAEvG,MAAM,aAAa,KAAK,aAAa;CAErC,MAAM,MAAM,cAAc;EAAE,KAAK,WAAW;EAAK,KAAK,WAAW;EAAS;AAI1E,QACE,iBAAA,GAAA,kBAAA,MAAC,cAAD;EAAoB;EAAM,mBAAiB;EAAM,GAH9BC,0BAAAA,kBAAkB,KAAK,UAAU,QAAQ,SAAS,MAAM,UAAU,IAAI;YAGzF,CACE,iBAAA,GAAA,kBAAA,KAACC,oBAAAA,aAAD;GACW;GACT,aAAa,KAAK,aAAa,gBAAgB;GAC1C;GACL,KAAK,KAAK,UAAU;GACpB,aACE,KAAK,YAAY,WAAW,SAC1B,iBAAA,GAAA,kBAAA,KAAC,OAAD,EAAK,yBAAyB,EAAE,QAAQ,KAAK,WAAW,YAAY,EAAI,CAAA,GACtE,KAAA;GAEN,OAAO,KAAK,MAAM;GACR;GACV,CAAA,EACF,iBAAA,GAAA,kBAAA,KAACC,oBAAAA,aAAD;GACE,OAAO;GACP,MAAM,KAAK,cAAc,aAAa,UAAU;GAChD,WAAW,MAAM,KAAK;GACtB,CAAA,CACW"}
|
|
@@ -32,22 +32,19 @@ const ExternalEmbed = ({ embed }) => {
|
|
|
32
32
|
}, []);
|
|
33
33
|
if (embed.status === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_EmbedErrorPlaceholder.EmbedErrorPlaceholder, { type: "external" });
|
|
34
34
|
const { embedData, data } = embed;
|
|
35
|
-
if (embedData.type === "fullscreen") {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
})
|
|
49
|
-
});
|
|
50
|
-
}
|
|
35
|
+
if (embedData.type === "fullscreen") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ndla_primitives.Figure, {
|
|
36
|
+
"data-embed-type": "external",
|
|
37
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ResourceBox.ResourceBox, {
|
|
38
|
+
image: {
|
|
39
|
+
src: data.iframeImage?.image.imageUrl,
|
|
40
|
+
alt: embedData.alt !== void 0 ? embedData.alt : data.iframeImage?.alttext?.alttext ?? ""
|
|
41
|
+
},
|
|
42
|
+
title: embedData.title ?? "",
|
|
43
|
+
url: embedData.url,
|
|
44
|
+
caption: embedData.caption ?? "",
|
|
45
|
+
buttonText: t("license.other.itemImage.ariaLabel")
|
|
46
|
+
})
|
|
47
|
+
});
|
|
51
48
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StyledFigure, {
|
|
52
49
|
"data-embed-type": "external",
|
|
53
50
|
ref: figRef,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExternalEmbed.js","names":["Figure","EmbedErrorPlaceholder","ResourceBox"],"sources":["../../src/Embed/ExternalEmbed.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { Figure } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { OembedMetaData } from \"@ndla/types-embed\";\nimport { useEffect, useRef } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ResourceBox } from \"../ResourceBox/ResourceBox\";\nimport { EmbedErrorPlaceholder } from \"./EmbedErrorPlaceholder\";\n\ninterface Props {\n embed: OembedMetaData;\n}\n\nconst StyledFigure = styled(Figure, {\n base: {\n \"& iframe\": {\n height: \"auto\",\n width: \"100%\",\n },\n },\n});\n\nexport const ExternalEmbed = ({ embed }: Props) => {\n const { t } = useTranslation();\n const figRef = useRef<HTMLElement>(null);\n\n useEffect(() => {\n const iframe = figRef.current?.querySelector(\"iframe\");\n if (iframe) {\n const [width, height] = [Number.parseInt(iframe.width), Number.parseInt(iframe.height)];\n iframe.style.aspectRatio = `${width ? width : 16}/${height ? height : 9}`;\n iframe.width = \"\";\n iframe.height = \"\";\n }\n }, []);\n\n if (embed.status === \"error\") {\n return <EmbedErrorPlaceholder type=\"external\" />;\n }\n\n const { embedData, data } = embed;\n\n if (embedData.type === \"fullscreen\") {\n const image = {\n src: data.iframeImage?.image.imageUrl,\n alt: embedData.alt !== undefined ? embedData.alt : (data.iframeImage?.alttext?.alttext ?? \"\"),\n };\n return (\n <Figure data-embed-type=\"external\">\n <ResourceBox\n image={image}\n title={embedData.title ?? \"\"}\n url={embedData.url}\n caption={embedData.caption ?? \"\"}\n buttonText={t(\"license.other.itemImage.ariaLabel\")}\n />\n </Figure>\n );\n }\n\n return (\n <StyledFigure\n data-embed-type=\"external\"\n ref={figRef}\n dangerouslySetInnerHTML={{ __html: data?.oembed?.html ?? \"\" }}\n />\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,MAAM,gBAAA,GAAA,wBAAA,QAAsBA,iBAAAA,QAAQ,EAClC,MAAM,EACJ,YAAY;CACV,QAAQ;CACR,OAAO;CACR,EACF,EACF,CAAC;AAEF,MAAa,iBAAiB,EAAE,YAAmB;CACjD,MAAM,EAAE,OAAA,GAAA,cAAA,iBAAsB;CAC9B,MAAM,UAAA,GAAA,MAAA,QAA6B,KAAK;AAExC,EAAA,GAAA,MAAA,iBAAgB;EACd,MAAM,SAAS,OAAO,SAAS,cAAc,SAAS;AACtD,MAAI,QAAQ;GACV,MAAM,CAAC,OAAO,UAAU,CAAC,OAAO,SAAS,OAAO,MAAM,EAAE,OAAO,SAAS,OAAO,OAAO,CAAC;AACvF,UAAO,MAAM,cAAc,GAAG,QAAQ,QAAQ,GAAG,GAAG,SAAS,SAAS;AACtE,UAAO,QAAQ;AACf,UAAO,SAAS;;IAEjB,EAAE,CAAC;AAEN,KAAI,MAAM,WAAW,QACnB,QAAO,iBAAA,GAAA,kBAAA,KAACC,8BAAAA,uBAAD,EAAuB,MAAK,YAAa,CAAA;CAGlD,MAAM,EAAE,WAAW,SAAS;AAE5B,KAAI,UAAU,SAAS,
|
|
1
|
+
{"version":3,"file":"ExternalEmbed.js","names":["Figure","EmbedErrorPlaceholder","ResourceBox"],"sources":["../../src/Embed/ExternalEmbed.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { Figure } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { OembedMetaData } from \"@ndla/types-embed\";\nimport { useEffect, useRef } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ResourceBox } from \"../ResourceBox/ResourceBox\";\nimport { EmbedErrorPlaceholder } from \"./EmbedErrorPlaceholder\";\n\ninterface Props {\n embed: OembedMetaData;\n}\n\nconst StyledFigure = styled(Figure, {\n base: {\n \"& iframe\": {\n height: \"auto\",\n width: \"100%\",\n },\n },\n});\n\nexport const ExternalEmbed = ({ embed }: Props) => {\n const { t } = useTranslation();\n const figRef = useRef<HTMLElement>(null);\n\n useEffect(() => {\n const iframe = figRef.current?.querySelector(\"iframe\");\n if (iframe) {\n const [width, height] = [Number.parseInt(iframe.width), Number.parseInt(iframe.height)];\n iframe.style.aspectRatio = `${width ? width : 16}/${height ? height : 9}`;\n iframe.width = \"\";\n iframe.height = \"\";\n }\n }, []);\n\n if (embed.status === \"error\") {\n return <EmbedErrorPlaceholder type=\"external\" />;\n }\n\n const { embedData, data } = embed;\n\n if (embedData.type === \"fullscreen\") {\n const image = {\n src: data.iframeImage?.image.imageUrl,\n alt: embedData.alt !== undefined ? embedData.alt : (data.iframeImage?.alttext?.alttext ?? \"\"),\n };\n return (\n <Figure data-embed-type=\"external\">\n <ResourceBox\n image={image}\n title={embedData.title ?? \"\"}\n url={embedData.url}\n caption={embedData.caption ?? \"\"}\n buttonText={t(\"license.other.itemImage.ariaLabel\")}\n />\n </Figure>\n );\n }\n\n return (\n <StyledFigure\n data-embed-type=\"external\"\n ref={figRef}\n dangerouslySetInnerHTML={{ __html: data?.oembed?.html ?? \"\" }}\n />\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,MAAM,gBAAA,GAAA,wBAAA,QAAsBA,iBAAAA,QAAQ,EAClC,MAAM,EACJ,YAAY;CACV,QAAQ;CACR,OAAO;CACR,EACF,EACF,CAAC;AAEF,MAAa,iBAAiB,EAAE,YAAmB;CACjD,MAAM,EAAE,OAAA,GAAA,cAAA,iBAAsB;CAC9B,MAAM,UAAA,GAAA,MAAA,QAA6B,KAAK;AAExC,EAAA,GAAA,MAAA,iBAAgB;EACd,MAAM,SAAS,OAAO,SAAS,cAAc,SAAS;AACtD,MAAI,QAAQ;GACV,MAAM,CAAC,OAAO,UAAU,CAAC,OAAO,SAAS,OAAO,MAAM,EAAE,OAAO,SAAS,OAAO,OAAO,CAAC;AACvF,UAAO,MAAM,cAAc,GAAG,QAAQ,QAAQ,GAAG,GAAG,SAAS,SAAS;AACtE,UAAO,QAAQ;AACf,UAAO,SAAS;;IAEjB,EAAE,CAAC;AAEN,KAAI,MAAM,WAAW,QACnB,QAAO,iBAAA,GAAA,kBAAA,KAACC,8BAAAA,uBAAD,EAAuB,MAAK,YAAa,CAAA;CAGlD,MAAM,EAAE,WAAW,SAAS;AAE5B,KAAI,UAAU,SAAS,aAKrB,QACE,iBAAA,GAAA,kBAAA,KAACD,iBAAAA,QAAD;EAAQ,mBAAgB;YACtB,iBAAA,GAAA,kBAAA,KAACE,oBAAAA,aAAD;GACE,OAPQ;IACZ,KAAK,KAAK,aAAa,MAAM;IAC7B,KAAK,UAAU,QAAQ,KAAA,IAAY,UAAU,MAAO,KAAK,aAAa,SAAS,WAAW;IAC3F;GAKK,OAAO,UAAU,SAAS;GAC1B,KAAK,UAAU;GACf,SAAS,UAAU,WAAW;GAC9B,YAAY,EAAE,oCAAoC;GAClD,CAAA;EACK,CAAA;AAIb,QACE,iBAAA,GAAA,kBAAA,KAAC,cAAD;EACE,mBAAgB;EAChB,KAAK;EACL,yBAAyB,EAAE,QAAQ,MAAM,QAAQ,QAAQ,IAAI;EAC7D,CAAA"}
|
package/lib/Embed/IframeEmbed.js
CHANGED
|
@@ -36,14 +36,13 @@ const IframeEmbed = ({ embed }) => {
|
|
|
36
36
|
if (embedData.type === "fullscreen") {
|
|
37
37
|
const iframeImage = embed.status === "success" ? data.iframeImage : void 0;
|
|
38
38
|
const alt = embedData.alt !== void 0 ? embedData.alt : iframeImage?.alttext.alttext;
|
|
39
|
-
const image = {
|
|
40
|
-
src: iframeImage?.image.imageUrl,
|
|
41
|
-
alt: alt ?? ""
|
|
42
|
-
};
|
|
43
39
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StyledFigure, {
|
|
44
40
|
"data-embed-type": "iframe",
|
|
45
41
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ResourceBox.ResourceBox, {
|
|
46
|
-
image
|
|
42
|
+
image: {
|
|
43
|
+
src: iframeImage?.image.imageUrl,
|
|
44
|
+
alt: alt ?? ""
|
|
45
|
+
},
|
|
47
46
|
title: embedData.title ?? "",
|
|
48
47
|
url: embedData.url,
|
|
49
48
|
caption: embedData.caption ?? "",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframeEmbed.js","names":["Figure","EmbedErrorPlaceholder","ResourceBox"],"sources":["../../src/Embed/IframeEmbed.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { Figure } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { IframeMetaData } from \"@ndla/types-embed\";\nimport { useEffect, useRef } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ResourceBox } from \"../ResourceBox/ResourceBox\";\nimport { EmbedErrorPlaceholder } from \"./EmbedErrorPlaceholder\";\n\ninterface Props {\n embed: IframeMetaData;\n}\n\nconst StyledIframe = styled(\"iframe\", {\n base: {\n width: \"100%\",\n border: 0,\n },\n});\n\nconst StyledFigure = styled(Figure, {\n base: {\n clear: \"both\",\n },\n});\n\nexport const IframeEmbed = ({ embed }: Props) => {\n const { t } = useTranslation();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (iframe) {\n const [width, height] = [Number.parseInt(iframe.width), Number.parseInt(iframe.height)];\n iframe.style.aspectRatio = `${width ? width : 16}/${height ? height : 9}`;\n iframe.width = \"\";\n iframe.height = \"\";\n }\n }, []);\n\n if (embed.status === \"error\") {\n return <EmbedErrorPlaceholder type=\"external\" />;\n }\n\n const { embedData, data } = embed;\n\n if (embedData.type === \"fullscreen\") {\n const iframeImage = embed.status === \"success\" ? data.iframeImage : undefined;\n const alt = embedData.alt !== undefined ? embedData.alt : iframeImage?.alttext.alttext;\n const image = { src: iframeImage?.image.imageUrl, alt: alt ?? \"\" };\n return (\n <StyledFigure data-embed-type=\"iframe\">\n <ResourceBox\n image={image}\n title={embedData.title ?? \"\"}\n url={embedData.url}\n caption={embedData.caption ?? \"\"}\n buttonText={t(\"license.other.itemImage.ariaLabel\")}\n />\n </StyledFigure>\n );\n }\n\n const { width, height, url } = embedData;\n\n const strippedWidth = typeof width === \"number\" ? width : width?.replace(/\\s*px/, \"\");\n const strippedHeight = typeof height === \"number\" ? height : height?.replace(/\\s*px/, \"\");\n const title = `${t(\"embed.type.external\")}: ${embedData.title?.trim() ? embedData.title : url}`;\n\n return (\n <StyledFigure data-embed-type=\"iframe\">\n <StyledIframe\n ref={iframeRef}\n title={title}\n aria-label={title}\n src={url}\n width={strippedWidth}\n height={strippedHeight}\n allow=\"autoplay; encrypted-media; fullscreen\"\n loading=\"lazy\"\n />\n </StyledFigure>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,MAAM,gBAAA,GAAA,wBAAA,QAAsB,UAAU,EACpC,MAAM;CACJ,OAAO;CACP,QAAQ;CACT,EACF,CAAC;AAEF,MAAM,gBAAA,GAAA,wBAAA,QAAsBA,iBAAAA,QAAQ,EAClC,MAAM,EACJ,OAAO,QACR,EACF,CAAC;AAEF,MAAa,eAAe,EAAE,YAAmB;CAC/C,MAAM,EAAE,OAAA,GAAA,cAAA,iBAAsB;CAC9B,MAAM,aAAA,GAAA,MAAA,QAAsC,KAAK;AAEjD,EAAA,GAAA,MAAA,iBAAgB;EACd,MAAM,SAAS,UAAU;AACzB,MAAI,QAAQ;GACV,MAAM,CAAC,OAAO,UAAU,CAAC,OAAO,SAAS,OAAO,MAAM,EAAE,OAAO,SAAS,OAAO,OAAO,CAAC;AACvF,UAAO,MAAM,cAAc,GAAG,QAAQ,QAAQ,GAAG,GAAG,SAAS,SAAS;AACtE,UAAO,QAAQ;AACf,UAAO,SAAS;;IAEjB,EAAE,CAAC;AAEN,KAAI,MAAM,WAAW,QACnB,QAAO,iBAAA,GAAA,kBAAA,KAACC,8BAAAA,uBAAD,EAAuB,MAAK,YAAa,CAAA;CAGlD,MAAM,EAAE,WAAW,SAAS;AAE5B,KAAI,UAAU,SAAS,cAAc;EACnC,MAAM,cAAc,MAAM,WAAW,YAAY,KAAK,cAAc,KAAA;EACpE,MAAM,MAAM,UAAU,QAAQ,KAAA,IAAY,UAAU,MAAM,aAAa,QAAQ;
|
|
1
|
+
{"version":3,"file":"IframeEmbed.js","names":["Figure","EmbedErrorPlaceholder","ResourceBox"],"sources":["../../src/Embed/IframeEmbed.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { Figure } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { IframeMetaData } from \"@ndla/types-embed\";\nimport { useEffect, useRef } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { ResourceBox } from \"../ResourceBox/ResourceBox\";\nimport { EmbedErrorPlaceholder } from \"./EmbedErrorPlaceholder\";\n\ninterface Props {\n embed: IframeMetaData;\n}\n\nconst StyledIframe = styled(\"iframe\", {\n base: {\n width: \"100%\",\n border: 0,\n },\n});\n\nconst StyledFigure = styled(Figure, {\n base: {\n clear: \"both\",\n },\n});\n\nexport const IframeEmbed = ({ embed }: Props) => {\n const { t } = useTranslation();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (iframe) {\n const [width, height] = [Number.parseInt(iframe.width), Number.parseInt(iframe.height)];\n iframe.style.aspectRatio = `${width ? width : 16}/${height ? height : 9}`;\n iframe.width = \"\";\n iframe.height = \"\";\n }\n }, []);\n\n if (embed.status === \"error\") {\n return <EmbedErrorPlaceholder type=\"external\" />;\n }\n\n const { embedData, data } = embed;\n\n if (embedData.type === \"fullscreen\") {\n const iframeImage = embed.status === \"success\" ? data.iframeImage : undefined;\n const alt = embedData.alt !== undefined ? embedData.alt : iframeImage?.alttext.alttext;\n const image = { src: iframeImage?.image.imageUrl, alt: alt ?? \"\" };\n return (\n <StyledFigure data-embed-type=\"iframe\">\n <ResourceBox\n image={image}\n title={embedData.title ?? \"\"}\n url={embedData.url}\n caption={embedData.caption ?? \"\"}\n buttonText={t(\"license.other.itemImage.ariaLabel\")}\n />\n </StyledFigure>\n );\n }\n\n const { width, height, url } = embedData;\n\n const strippedWidth = typeof width === \"number\" ? width : width?.replace(/\\s*px/, \"\");\n const strippedHeight = typeof height === \"number\" ? height : height?.replace(/\\s*px/, \"\");\n const title = `${t(\"embed.type.external\")}: ${embedData.title?.trim() ? embedData.title : url}`;\n\n return (\n <StyledFigure data-embed-type=\"iframe\">\n <StyledIframe\n ref={iframeRef}\n title={title}\n aria-label={title}\n src={url}\n width={strippedWidth}\n height={strippedHeight}\n allow=\"autoplay; encrypted-media; fullscreen\"\n loading=\"lazy\"\n />\n </StyledFigure>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,MAAM,gBAAA,GAAA,wBAAA,QAAsB,UAAU,EACpC,MAAM;CACJ,OAAO;CACP,QAAQ;CACT,EACF,CAAC;AAEF,MAAM,gBAAA,GAAA,wBAAA,QAAsBA,iBAAAA,QAAQ,EAClC,MAAM,EACJ,OAAO,QACR,EACF,CAAC;AAEF,MAAa,eAAe,EAAE,YAAmB;CAC/C,MAAM,EAAE,OAAA,GAAA,cAAA,iBAAsB;CAC9B,MAAM,aAAA,GAAA,MAAA,QAAsC,KAAK;AAEjD,EAAA,GAAA,MAAA,iBAAgB;EACd,MAAM,SAAS,UAAU;AACzB,MAAI,QAAQ;GACV,MAAM,CAAC,OAAO,UAAU,CAAC,OAAO,SAAS,OAAO,MAAM,EAAE,OAAO,SAAS,OAAO,OAAO,CAAC;AACvF,UAAO,MAAM,cAAc,GAAG,QAAQ,QAAQ,GAAG,GAAG,SAAS,SAAS;AACtE,UAAO,QAAQ;AACf,UAAO,SAAS;;IAEjB,EAAE,CAAC;AAEN,KAAI,MAAM,WAAW,QACnB,QAAO,iBAAA,GAAA,kBAAA,KAACC,8BAAAA,uBAAD,EAAuB,MAAK,YAAa,CAAA;CAGlD,MAAM,EAAE,WAAW,SAAS;AAE5B,KAAI,UAAU,SAAS,cAAc;EACnC,MAAM,cAAc,MAAM,WAAW,YAAY,KAAK,cAAc,KAAA;EACpE,MAAM,MAAM,UAAU,QAAQ,KAAA,IAAY,UAAU,MAAM,aAAa,QAAQ;AAE/E,SACE,iBAAA,GAAA,kBAAA,KAAC,cAAD;GAAc,mBAAgB;aAC5B,iBAAA,GAAA,kBAAA,KAACC,oBAAAA,aAAD;IACE,OAJQ;KAAE,KAAK,aAAa,MAAM;KAAU,KAAK,OAAO;KAAI;IAK5D,OAAO,UAAU,SAAS;IAC1B,KAAK,UAAU;IACf,SAAS,UAAU,WAAW;IAC9B,YAAY,EAAE,oCAAoC;IAClD,CAAA;GACW,CAAA;;CAInB,MAAM,EAAE,OAAO,QAAQ,QAAQ;CAE/B,MAAM,gBAAgB,OAAO,UAAU,WAAW,QAAQ,OAAO,QAAQ,SAAS,GAAG;CACrF,MAAM,iBAAiB,OAAO,WAAW,WAAW,SAAS,QAAQ,QAAQ,SAAS,GAAG;CACzF,MAAM,QAAQ,GAAG,EAAE,sBAAsB,CAAC,IAAI,UAAU,OAAO,MAAM,GAAG,UAAU,QAAQ;AAE1F,QACE,iBAAA,GAAA,kBAAA,KAAC,cAAD;EAAc,mBAAgB;YAC5B,iBAAA,GAAA,kBAAA,KAAC,cAAD;GACE,KAAK;GACE;GACP,cAAY;GACZ,KAAK;GACL,OAAO;GACP,QAAQ;GACR,OAAM;GACN,SAAQ;GACR,CAAA;EACW,CAAA"}
|
package/lib/FactBox/FactBox.js
CHANGED
|
@@ -4,7 +4,6 @@ let _ndla_styled_system_jsx = require("@ndla/styled-system/jsx");
|
|
|
4
4
|
let react = require("react");
|
|
5
5
|
react = require_runtime.__toESM(react);
|
|
6
6
|
let react_i18next = require("react-i18next");
|
|
7
|
-
let _ndla_icons = require("@ndla/icons");
|
|
8
7
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
8
|
//#region src/FactBox/FactBox.tsx
|
|
10
9
|
/**
|
|
@@ -29,52 +28,29 @@ const StyledAside = (0, _ndla_styled_system_jsx.styled)("aside", {
|
|
|
29
28
|
borderRadius: "xsmall",
|
|
30
29
|
clear: "both",
|
|
31
30
|
_open: { gridTemplateRows: "1fr" },
|
|
32
|
-
|
|
31
|
+
_print: {
|
|
32
|
+
gridTemplateRows: "1fr",
|
|
33
33
|
overflow: "visible",
|
|
34
34
|
maxHeight: "500vh"
|
|
35
|
-
}
|
|
35
|
+
},
|
|
36
36
|
"& > div": { minHeight: "surface.3xsmall" }
|
|
37
37
|
},
|
|
38
|
-
variants: { overflowHidden: { true: { "& > div": {
|
|
38
|
+
variants: { overflowHidden: { true: { "& > div": {
|
|
39
|
+
overflow: "hidden",
|
|
40
|
+
_print: { overflow: "visible" }
|
|
41
|
+
} } } }
|
|
39
42
|
});
|
|
40
43
|
const StyledContent = (0, _ndla_styled_system_jsx.styled)("div", { base: {
|
|
41
44
|
position: "relative",
|
|
42
45
|
width: "100%",
|
|
43
46
|
"& :first-child": { marginBlockStart: "0" },
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
textAlign: "center",
|
|
47
|
-
position: "absolute",
|
|
48
|
-
inset: "0",
|
|
49
|
-
transitionProperty: "opacity",
|
|
50
|
-
transitionDuration: "slow",
|
|
51
|
-
transitionTimingFunction: "ease-in-out",
|
|
52
|
-
gradientFrom: "surface.default/20",
|
|
53
|
-
gradientTo: "surface.default/95",
|
|
54
|
-
backgroundGradient: "to-b",
|
|
55
|
-
opacity: "1",
|
|
56
|
-
zIndex: "base",
|
|
57
|
-
pointerEvents: "none"
|
|
58
|
-
},
|
|
59
|
-
_print: {
|
|
60
|
-
overflow: "visible",
|
|
61
|
-
_after: { display: "none" }
|
|
62
|
-
},
|
|
63
|
-
_open: {
|
|
64
|
-
paddingBlockEnd: "xsmall",
|
|
65
|
-
_after: { opacity: "0" }
|
|
66
|
-
}
|
|
47
|
+
_print: { overflow: "visible" },
|
|
48
|
+
_open: { paddingBlockEnd: "xsmall" }
|
|
67
49
|
} });
|
|
68
|
-
const
|
|
50
|
+
const StyledButton = (0, _ndla_styled_system_jsx.styled)(_ndla_primitives.Button, { base: {
|
|
69
51
|
position: "absolute",
|
|
70
52
|
bottom: "-medium",
|
|
71
53
|
zIndex: "base",
|
|
72
|
-
"& svg": {
|
|
73
|
-
transitionProperty: "transform",
|
|
74
|
-
transitionTimingFunction: "ease-in-out",
|
|
75
|
-
transitionDuration: "fast"
|
|
76
|
-
},
|
|
77
|
-
_open: { "& svg": { transform: "rotate(180deg)" } },
|
|
78
54
|
_print: { display: "none" }
|
|
79
55
|
} });
|
|
80
56
|
const FactBox = (0, react.forwardRef)(({ children, open, onOpenChange, defaultOpen = false, ...rest }, ref) => {
|
|
@@ -105,14 +81,14 @@ const FactBox = (0, react.forwardRef)(({ children, open, onOpenChange, defaultOp
|
|
|
105
81
|
onTransitionEnd: (e) => {
|
|
106
82
|
if (e.target === e.currentTarget && state === "open") setOverflowHidden(false);
|
|
107
83
|
},
|
|
108
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
84
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StyledButton, {
|
|
109
85
|
"data-state": state,
|
|
110
86
|
onClick,
|
|
111
87
|
contentEditable: false,
|
|
112
88
|
"aria-expanded": state === "open",
|
|
89
|
+
variant: "secondary",
|
|
113
90
|
"aria-controls": contentId,
|
|
114
|
-
|
|
115
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ndla_icons.ArrowDownShortLine, {})
|
|
91
|
+
children: t(`factbox.${state === "open" ? "showLess" : "showMore"}`)
|
|
116
92
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StyledContent, {
|
|
117
93
|
id: contentId,
|
|
118
94
|
"data-state": state,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FactBox.js","names":["
|
|
1
|
+
{"version":3,"file":"FactBox.js","names":["Button","React"],"sources":["../../src/FactBox/FactBox.tsx"],"sourcesContent":["/**\n * Copyright (c) 2016-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { Button } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport React, {\n type ComponentProps,\n type ReactNode,\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useState,\n} from \"react\";\nimport { useTranslation } from \"react-i18next\";\n\ninterface Props extends ComponentProps<\"aside\"> {\n children?: ReactNode;\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nconst StyledAside = styled(\"aside\", {\n base: {\n position: \"relative\",\n padding: \"medium\",\n display: \"grid\",\n gridTemplateRows: \"0fr\",\n transitionProperty: \"grid-template-rows\",\n transitionDuration: \"slow\",\n transitionTimingFunction: \"ease-in-out\",\n justifyItems: \"center\",\n border: \"1px solid\",\n borderColor: \"stroke.default\",\n borderRadius: \"xsmall\",\n clear: \"both\",\n _open: {\n gridTemplateRows: \"1fr\",\n },\n _print: {\n gridTemplateRows: \"1fr\",\n overflow: \"visible\",\n maxHeight: \"500vh\",\n },\n \"& > div\": {\n minHeight: \"surface.3xsmall\",\n },\n },\n variants: {\n overflowHidden: {\n true: {\n \"& > div\": {\n overflow: \"hidden\",\n _print: {\n overflow: \"visible\",\n },\n },\n },\n },\n },\n});\n\nconst StyledContent = styled(\"div\", {\n base: {\n position: \"relative\",\n width: \"100%\",\n // Reset the top margin of the very first child.\n \"& :first-child\": {\n marginBlockStart: \"0\",\n },\n _print: {\n overflow: \"visible\",\n },\n _open: {\n paddingBlockEnd: \"xsmall\",\n },\n },\n});\n\nconst StyledButton = styled(Button, {\n base: {\n position: \"absolute\",\n bottom: \"-medium\",\n zIndex: \"base\",\n _print: {\n display: \"none\",\n },\n },\n});\n\n// TODO: Consider moving the open trigger depending on whether the content is open or closed.\n\nexport const FactBox = forwardRef<HTMLElement, Props>(\n ({ children, open, onOpenChange, defaultOpen = false, ...rest }, ref) => {\n const { t } = useTranslation();\n const [state, setState] = useState<\"open\" | \"closed\">(defaultOpen ? \"open\" : \"closed\");\n const [overflowHidden, setOverflowHidden] = useState(!defaultOpen);\n const contentId = useId();\n // Inert has existed since early 2023. It allows us to disable tabindex inside the content if it is closed, allowing us to be accessible for users with newish browsers. React 18 removes this because it doesn't recognize the attribute. This is a workaround for that.\n // When running in React 18, we need to use an empty string instead of true.\n // TODO: Remove this hack once we upgrade to React 19 as a peer dep.\n const inertAttribute = useMemo(() => {\n return state === \"closed\" ? { inert: typeof React.use === \"function\" ? true : \"\" } : {};\n }, [state]) as { inert?: boolean };\n\n useEffect(() => {\n if (open !== undefined) {\n setState(open ? \"open\" : \"closed\");\n }\n }, [open]);\n\n const onClick = useCallback(() => {\n const newState = state === \"open\" ? \"closed\" : \"open\";\n setState(newState);\n onOpenChange?.(newState === \"open\");\n }, [state, onOpenChange]);\n\n return (\n <StyledAside\n data-state={state}\n data-embed-type=\"factbox\"\n {...rest}\n ref={ref}\n overflowHidden={overflowHidden}\n onTransitionStart={(e) => {\n if (e.target === e.currentTarget && state === \"closed\") {\n setOverflowHidden(true);\n }\n }}\n onTransitionEnd={(e) => {\n if (e.target === e.currentTarget && state === \"open\") {\n setOverflowHidden(false);\n }\n }}\n >\n <StyledButton\n data-state={state}\n onClick={onClick}\n contentEditable={false}\n aria-expanded={state === \"open\"}\n variant=\"secondary\"\n aria-controls={contentId}\n >\n {t(`factbox.${state === \"open\" ? \"showLess\" : \"showMore\"}`)}\n </StyledButton>\n <StyledContent id={contentId} data-state={state} aria-hidden={state === \"closed\"} {...inertAttribute}>\n {children}\n </StyledContent>\n </StyledAside>\n );\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;AA6BA,MAAM,eAAA,GAAA,wBAAA,QAAqB,SAAS;CAClC,MAAM;EACJ,UAAU;EACV,SAAS;EACT,SAAS;EACT,kBAAkB;EAClB,oBAAoB;EACpB,oBAAoB;EACpB,0BAA0B;EAC1B,cAAc;EACd,QAAQ;EACR,aAAa;EACb,cAAc;EACd,OAAO;EACP,OAAO,EACL,kBAAkB,OACnB;EACD,QAAQ;GACN,kBAAkB;GAClB,UAAU;GACV,WAAW;GACZ;EACD,WAAW,EACT,WAAW,mBACZ;EACF;CACD,UAAU,EACR,gBAAgB,EACd,MAAM,EACJ,WAAW;EACT,UAAU;EACV,QAAQ,EACN,UAAU,WACX;EACF,EACF,EACF,EACF;CACF,CAAC;AAEF,MAAM,iBAAA,GAAA,wBAAA,QAAuB,OAAO,EAClC,MAAM;CACJ,UAAU;CACV,OAAO;CAEP,kBAAkB,EAChB,kBAAkB,KACnB;CACD,QAAQ,EACN,UAAU,WACX;CACD,OAAO,EACL,iBAAiB,UAClB;CACF,EACF,CAAC;AAEF,MAAM,gBAAA,GAAA,wBAAA,QAAsBA,iBAAAA,QAAQ,EAClC,MAAM;CACJ,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ,EACN,SAAS,QACV;CACF,EACF,CAAC;AAIF,MAAa,WAAA,GAAA,MAAA,aACV,EAAE,UAAU,MAAM,cAAc,cAAc,OAAO,GAAG,QAAQ,QAAQ;CACvE,MAAM,EAAE,OAAA,GAAA,cAAA,iBAAsB;CAC9B,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,UAAwC,cAAc,SAAS,SAAS;CACtF,MAAM,CAAC,gBAAgB,sBAAA,GAAA,MAAA,UAA8B,CAAC,YAAY;CAClE,MAAM,aAAA,GAAA,MAAA,QAAmB;CAIzB,MAAM,kBAAA,GAAA,MAAA,eAA+B;AACnC,SAAO,UAAU,WAAW,EAAE,OAAO,OAAOC,MAAAA,QAAM,QAAQ,aAAa,OAAO,IAAI,GAAG,EAAE;IACtF,CAAC,MAAM,CAAC;AAEX,EAAA,GAAA,MAAA,iBAAgB;AACd,MAAI,SAAS,KAAA,EACX,UAAS,OAAO,SAAS,SAAS;IAEnC,CAAC,KAAK,CAAC;CAEV,MAAM,WAAA,GAAA,MAAA,mBAA4B;EAChC,MAAM,WAAW,UAAU,SAAS,WAAW;AAC/C,WAAS,SAAS;AAClB,iBAAe,aAAa,OAAO;IAClC,CAAC,OAAO,aAAa,CAAC;AAEzB,QACE,iBAAA,GAAA,kBAAA,MAAC,aAAD;EACE,cAAY;EACZ,mBAAgB;EAChB,GAAI;EACC;EACW;EAChB,oBAAoB,MAAM;AACxB,OAAI,EAAE,WAAW,EAAE,iBAAiB,UAAU,SAC5C,mBAAkB,KAAK;;EAG3B,kBAAkB,MAAM;AACtB,OAAI,EAAE,WAAW,EAAE,iBAAiB,UAAU,OAC5C,mBAAkB,MAAM;;YAb9B,CAiBE,iBAAA,GAAA,kBAAA,KAAC,cAAD;GACE,cAAY;GACH;GACT,iBAAiB;GACjB,iBAAe,UAAU;GACzB,SAAQ;GACR,iBAAe;aAEd,EAAE,WAAW,UAAU,SAAS,aAAa,aAAa;GAC9C,CAAA,EACf,iBAAA,GAAA,kBAAA,KAAC,eAAD;GAAe,IAAI;GAAW,cAAY;GAAO,eAAa,UAAU;GAAU,GAAI;GACnF;GACa,CAAA,CACJ;;EAGnB"}
|
package/lib/Gloss/Gloss.js
CHANGED
|
@@ -112,8 +112,7 @@ const Gloss = ({ title, glossData, audio, exampleIds, exampleLangs, variant }) =
|
|
|
112
112
|
})
|
|
113
113
|
] }), !!audio?.src && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpeechControl.SpeechControl, {
|
|
114
114
|
src: audio.src,
|
|
115
|
-
title: audio.title
|
|
116
|
-
type: "gloss"
|
|
115
|
+
title: audio.title
|
|
117
116
|
})] }),
|
|
118
117
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(StyledContainer, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ndla_primitives.Text, {
|
|
119
118
|
textStyle: "label.medium",
|