@ndla/ui 56.0.189-alpha.0 → 56.0.191-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 +4 -0
- package/dist/styles.css +16 -0
- package/es/AudioPlayer/AudioProgress.mjs +4 -1
- package/es/AudioPlayer/AudioProgress.mjs.map +1 -1
- package/es/AudioPlayer/useAudioControls.mjs.map +1 -1
- package/es/Embed/AudioEmbed.mjs.map +1 -1
- package/es/Embed/BrightcoveEmbed.mjs.map +1 -1
- package/es/Embed/ExternalEmbed.mjs.map +1 -1
- package/es/Embed/IframeEmbed.mjs.map +1 -1
- package/es/FactBox/FactBox.mjs +1 -0
- package/es/FactBox/FactBox.mjs.map +1 -1
- package/es/Gloss/Gloss.mjs.map +1 -1
- package/es/LicenseByline/EmbedByline.mjs +3 -2
- package/es/LicenseByline/EmbedByline.mjs.map +1 -1
- package/es/Pitch/Pitch.mjs.map +1 -1
- package/es/utils/licenseAttributes.mjs.map +1 -1
- package/lib/Article/BadgesContainer.js.map +1 -1
- package/lib/AudioPlayer/AudioProgress.js +4 -1
- package/lib/AudioPlayer/AudioProgress.js.map +1 -1
- package/lib/AudioPlayer/useAudioControls.js.map +1 -1
- package/lib/Embed/AudioEmbed.js.map +1 -1
- package/lib/Embed/BrightcoveEmbed.js.map +1 -1
- package/lib/Embed/ConceptInlineTriggerButton.js.map +1 -1
- package/lib/Embed/ExternalEmbed.js.map +1 -1
- package/lib/Embed/IframeEmbed.js.map +1 -1
- package/lib/FactBox/FactBox.js +1 -0
- package/lib/FactBox/FactBox.js.map +1 -1
- package/lib/Gloss/Gloss.js.map +1 -1
- package/lib/LicenseByline/EmbedByline.js +2 -1
- package/lib/LicenseByline/EmbedByline.js.map +1 -1
- package/lib/Pitch/Pitch.js.map +1 -1
- package/lib/utils/licenseAttributes.js.map +1 -1
- package/package.json +5 -5
- package/src/AudioPlayer/AudioProgress.tsx +3 -0
- package/src/Embed/BrightcoveEmbed.tsx +1 -0
- package/src/Embed/ConceptEmbed.stories.tsx +32 -0
- package/src/Embed/ImageEmbed.stories.tsx +2 -2
- package/src/FactBox/FactBox.tsx +1 -0
- package/src/Grid/Grid.stories.tsx +32 -25
- package/src/LicenseByline/EmbedByline.tsx +3 -2
|
@@ -83,6 +83,9 @@
|
|
|
83
83
|
"marginInlineStart]___[value:3xsmall",
|
|
84
84
|
"marginBlockStart]___[value:-4xsmall",
|
|
85
85
|
"transitionProperty]___[value:background, border-radius, width, height",
|
|
86
|
+
"width]___[value:4xsmall",
|
|
87
|
+
"height]___[value:4xsmall",
|
|
88
|
+
"borderRadius]___[value:sharp",
|
|
86
89
|
"background]___[value:unset",
|
|
87
90
|
"marginBlockEnd]___[value:-xsmall",
|
|
88
91
|
"paddingBlockEnd]___[value:0",
|
|
@@ -256,6 +259,7 @@
|
|
|
256
259
|
"transitionTimingFunction]___[value:ease-out]___[cond:& svg",
|
|
257
260
|
"alignSelf]___[value:flex-end",
|
|
258
261
|
"fill]___[value:icon.subtle",
|
|
262
|
+
"paddingBottom]___[value:xxlarge",
|
|
259
263
|
"gridTemplateRows]___[value:0fr",
|
|
260
264
|
"transitionProperty]___[value:grid-template-rows",
|
|
261
265
|
"transitionDuration]___[value:slow",
|
package/dist/styles.css
CHANGED
|
@@ -314,6 +314,10 @@
|
|
|
314
314
|
padding-inline: var(--spacing-xsmall);
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
+
.bdr_sharp {
|
|
318
|
+
border-radius: var(--radii-sharp);
|
|
319
|
+
}
|
|
320
|
+
|
|
317
321
|
.px_medium {
|
|
318
322
|
padding-inline: var(--spacing-medium);
|
|
319
323
|
}
|
|
@@ -759,6 +763,14 @@
|
|
|
759
763
|
max-width: var(--sizes-surface-xlarge);
|
|
760
764
|
}
|
|
761
765
|
|
|
766
|
+
.w_4xsmall {
|
|
767
|
+
width: var(--sizes-4xsmall);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
.h_4xsmall {
|
|
771
|
+
height: var(--sizes-4xsmall);
|
|
772
|
+
}
|
|
773
|
+
|
|
762
774
|
.min-w_4xlarge {
|
|
763
775
|
min-width: var(--sizes-4xlarge);
|
|
764
776
|
}
|
|
@@ -843,6 +855,10 @@
|
|
|
843
855
|
height: var(--sizes-medium);
|
|
844
856
|
}
|
|
845
857
|
|
|
858
|
+
.pb_xxlarge {
|
|
859
|
+
padding-bottom: var(--spacing-xxlarge);
|
|
860
|
+
}
|
|
861
|
+
|
|
846
862
|
.bottom_-medium {
|
|
847
863
|
bottom: calc(var(--spacing-medium) * -1);
|
|
848
864
|
}
|
|
@@ -8,7 +8,10 @@ const StyledSliderThumb = styled(SliderThumb, { variants: { variant: {
|
|
|
8
8
|
standard: {},
|
|
9
9
|
simple: {
|
|
10
10
|
marginBlockStart: "-4xsmall",
|
|
11
|
-
transitionProperty: "background, border-radius, width, height"
|
|
11
|
+
transitionProperty: "background, border-radius, width, height",
|
|
12
|
+
width: "4xsmall",
|
|
13
|
+
height: "4xsmall",
|
|
14
|
+
borderRadius: "sharp"
|
|
12
15
|
}
|
|
13
16
|
} } });
|
|
14
17
|
const StyledSliderTrack = styled(SliderTrack, { variants: { variant: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioProgress.mjs","names":[],"sources":["../../src/AudioPlayer/AudioProgress.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 SliderRoot,\n SliderLabel,\n SliderControl,\n SliderTrack,\n SliderRange,\n SliderThumb,\n SliderHiddenInput,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { useTranslation } from \"react-i18next\";\nimport { formatTime } from \"./audioUtils\";\n\ninterface Props {\n currentTime: number;\n duration: number;\n onValueChange: (details: SliderValueChangeDetails) => void;\n variant?: \"simple\" | \"standard\";\n}\n\nconst StyledSliderThumb = styled(SliderThumb, {\n variants: {\n variant: {\n standard: {},\n simple: {\n marginBlockStart: \"-4xsmall\",\n transitionProperty: \"background, border-radius, width, height\",\n },\n },\n },\n});\n\nconst StyledSliderTrack = styled(SliderTrack, {\n variants: {\n variant: {\n standard: {},\n simple: {\n marginBlockStart: \"-4xsmall\",\n background: \"unset\",\n },\n },\n },\n});\n\nconst StyledSliderRoot = styled(SliderRoot, {\n variants: {\n variant: {\n standard: {},\n simple: {\n position: \"relative\",\n marginBlockEnd: \"-xsmall\",\n },\n },\n },\n});\n\nexport const AudioProgress = ({ currentTime, duration, onValueChange, variant }: Props) => {\n const { t } = useTranslation();\n return (\n <StyledSliderRoot\n value={[currentTime]}\n defaultValue={[0]}\n step={1}\n max={duration}\n onValueChange={onValueChange}\n variant={variant}\n getAriaValueText={(value) =>\n t(\"audio.valueText\", {\n start: formatTime(Math.round(value.value)),\n end: formatTime(Math.round(duration)),\n })\n }\n >\n <SliderLabel srOnly>{t(\"audio.progressBar\")}</SliderLabel>\n <SliderControl>\n <StyledSliderTrack variant={variant}>\n <SliderRange />\n </StyledSliderTrack>\n <StyledSliderThumb index={0} variant={variant}>\n <SliderHiddenInput />\n </StyledSliderThumb>\n </SliderControl>\n </StyledSliderRoot>\n );\n};\n"],"mappings":";;;;;;AA6BA,MAAM,oBAAoB,OAAO,aAAa,EAC5C,UAAU,EACR,SAAS;CACP,UAAU,EAAE;CACZ,QAAQ;EACN,kBAAkB;EAClB,oBAAoB;
|
|
1
|
+
{"version":3,"file":"AudioProgress.mjs","names":[],"sources":["../../src/AudioPlayer/AudioProgress.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 SliderRoot,\n SliderLabel,\n SliderControl,\n SliderTrack,\n SliderRange,\n SliderThumb,\n SliderHiddenInput,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { useTranslation } from \"react-i18next\";\nimport { formatTime } from \"./audioUtils\";\n\ninterface Props {\n currentTime: number;\n duration: number;\n onValueChange: (details: SliderValueChangeDetails) => void;\n variant?: \"simple\" | \"standard\";\n}\n\nconst StyledSliderThumb = styled(SliderThumb, {\n variants: {\n variant: {\n standard: {},\n simple: {\n marginBlockStart: \"-4xsmall\",\n transitionProperty: \"background, border-radius, width, height\",\n width: \"4xsmall\",\n height: \"4xsmall\",\n borderRadius: \"sharp\",\n },\n },\n },\n});\n\nconst StyledSliderTrack = styled(SliderTrack, {\n variants: {\n variant: {\n standard: {},\n simple: {\n marginBlockStart: \"-4xsmall\",\n background: \"unset\",\n },\n },\n },\n});\n\nconst StyledSliderRoot = styled(SliderRoot, {\n variants: {\n variant: {\n standard: {},\n simple: {\n position: \"relative\",\n marginBlockEnd: \"-xsmall\",\n },\n },\n },\n});\n\nexport const AudioProgress = ({ currentTime, duration, onValueChange, variant }: Props) => {\n const { t } = useTranslation();\n return (\n <StyledSliderRoot\n value={[currentTime]}\n defaultValue={[0]}\n step={1}\n max={duration}\n onValueChange={onValueChange}\n variant={variant}\n getAriaValueText={(value) =>\n t(\"audio.valueText\", {\n start: formatTime(Math.round(value.value)),\n end: formatTime(Math.round(duration)),\n })\n }\n >\n <SliderLabel srOnly>{t(\"audio.progressBar\")}</SliderLabel>\n <SliderControl>\n <StyledSliderTrack variant={variant}>\n <SliderRange />\n </StyledSliderTrack>\n <StyledSliderThumb index={0} variant={variant}>\n <SliderHiddenInput />\n </StyledSliderThumb>\n </SliderControl>\n </StyledSliderRoot>\n );\n};\n"],"mappings":";;;;;;AA6BA,MAAM,oBAAoB,OAAO,aAAa,EAC5C,UAAU,EACR,SAAS;CACP,UAAU,EAAE;CACZ,QAAQ;EACN,kBAAkB;EAClB,oBAAoB;EACpB,OAAO;EACP,QAAQ;EACR,cAAc;EACf;CACF,EACF,EACF,CAAC;AAEF,MAAM,oBAAoB,OAAO,aAAa,EAC5C,UAAU,EACR,SAAS;CACP,UAAU,EAAE;CACZ,QAAQ;EACN,kBAAkB;EAClB,YAAY;EACb;CACF,EACF,EACF,CAAC;AAEF,MAAM,mBAAmB,OAAO,YAAY,EAC1C,UAAU,EACR,SAAS;CACP,UAAU,EAAE;CACZ,QAAQ;EACN,UAAU;EACV,gBAAgB;EACjB;CACF,EACF,EACF,CAAC;AAEF,MAAa,iBAAiB,EAAE,aAAa,UAAU,eAAe,cAAqB;CACzF,MAAM,EAAE,MAAM,gBAAgB;AAC9B,QACE,qBAAC,kBAAD;EACE,OAAO,CAAC,YAAY;EACpB,cAAc,CAAC,EAAE;EACjB,MAAM;EACN,KAAK;EACU;EACN;EACT,mBAAmB,UACjB,EAAE,mBAAmB;GACnB,OAAO,WAAW,KAAK,MAAM,MAAM,MAAM,CAAC;GAC1C,KAAK,WAAW,KAAK,MAAM,SAAS,CAAC;GACtC,CAAC;YAXN,CAcE,oBAAC,aAAD;GAAa,QAAA;aAAQ,EAAE,oBAAoB;GAAe,CAAA,EAC1D,qBAAC,eAAD,EAAA,UAAA,CACE,oBAAC,mBAAD;GAA4B;aAC1B,oBAAC,aAAD,EAAe,CAAA;GACG,CAAA,EACpB,oBAAC,mBAAD;GAAmB,OAAO;GAAY;aACpC,oBAAC,mBAAD,EAAqB,CAAA;GACH,CAAA,CACN,EAAA,CAAA,CACC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAudioControls.mjs","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,iBAAiB,SAAS,EAAE;CAC/C,MAAM,CAAC,aAAa,kBAAkB,SAAS,IAAI;CACnD,MAAM,CAAC,aAAa,kBAAkB,SAAS,EAAE;CACjD,MAAM,CAAC,UAAU,eAAe,SAAS,EAAE;CAC3C,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAC7C,MAAM,WAAW,OAAyB,KAAK;CAE/C,MAAM,aAAa,kBAAkB;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,uBAAuB,aAAa,SAAiB;AACzD,gBAAc,KAAK;AACnB,MAAI,SAAS,QACX,UAAS,QAAQ,eAAe;IAEjC,EAAE,CAAC;CAEN,MAAM,gBAAgB,aAAa,YAAoB;AACrD,MAAI,SAAS,QACX,UAAS,QAAQ,eAAe;IAEjC,EAAE,CAAC;CAEN,MAAM,qBAAqB,aAAa,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,0BAnB+B,aAAa,YAAsC;AAClF,OAAI,SAAS,SAAS;AACpB,aAAS,QAAQ,SAAS,QAAQ,MAAM,KAAK;AAC7C,mBAAe,QAAQ,MAAM,GAAG;;KAEjC,EAAE,
|
|
1
|
+
{"version":3,"file":"useAudioControls.mjs","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,iBAAiB,SAAS,EAAE;CAC/C,MAAM,CAAC,aAAa,kBAAkB,SAAS,IAAI;CACnD,MAAM,CAAC,aAAa,kBAAkB,SAAS,EAAE;CACjD,MAAM,CAAC,UAAU,eAAe,SAAS,EAAE;CAC3C,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAC7C,MAAM,WAAW,OAAyB,KAAK;CAE/C,MAAM,aAAa,kBAAkB;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,uBAAuB,aAAa,SAAiB;AACzD,gBAAc,KAAK;AACnB,MAAI,SAAS,QACX,UAAS,QAAQ,eAAe;IAEjC,EAAE,CAAC;CAEN,MAAM,gBAAgB,aAAa,YAAoB;AACrD,MAAI,SAAS,QACX,UAAS,QAAQ,eAAe;IAEjC,EAAE,CAAC;CAEN,MAAM,qBAAqB,aAAa,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,0BAnB+B,aAAa,YAAsC;AAClF,OAAI,SAAS,SAAS;AACpB,aAAS,QAAQ,SAAS,QAAQ,MAAM,KAAK;AAC7C,mBAAe,QAAQ,MAAM,GAAG;;KAEjC,EAAE,CAcqB;EACxB;EACA,SAdc,kBAAkB,WAAW,MAAM,EAAE,EAAE,CAc9C;EACP,cAbwD,aAAa,SAAS;GAC9E,MAAM,SAAS,KAAK;AACpB,kBAAe,KAAK,MAAM,OAAO,YAAY,CAAC;AAC9C,eAAY,KAAK,MAAM,OAAO,SAAS,CAAC;KACvC,EAAE,CASS;EACZ;EACA;EACA;EACA;EACA;EACA;EACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioEmbed.mjs","names":[],"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 {variant === \"standard\" && (\n <EmbedByline\n error={false}\n type={data.audioType === \"standard\" ? \"audio\" : \"podcast\"}\n copyright={embed.data.copyright}\n />\n )}\n </StyledFigure>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,MAAM,eAAe,OAAO,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,oBAAC,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,qBAAC,cAAD;EAAoB;EAAM,mBAAiB;EAAM,GAH9B,kBAAkB,KAAK,UAAU,QAAQ,SAAS,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"AudioEmbed.mjs","names":[],"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 {variant === \"standard\" && (\n <EmbedByline\n error={false}\n type={data.audioType === \"standard\" ? \"audio\" : \"podcast\"}\n copyright={embed.data.copyright}\n />\n )}\n </StyledFigure>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,MAAM,eAAe,OAAO,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,oBAAC,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,qBAAC,cAAD;EAAoB;EAAM,mBAAiB;EAAM,GAH9B,kBAAkB,KAAK,UAAU,QAAQ,SAAS,MAAM,UAAU,IAGpB;YAAjE,CACE,oBAAC,aAAD;GACW;GACT,aAAa,KAAK,aAAa,gBAAgB;GAC1C;GACL,KAAK,KAAK,UAAU;GACpB,aACE,KAAK,YAAY,WAAW,SAC1B,oBAAC,OAAD,EAAK,yBAAyB,EAAE,QAAQ,KAAK,WAAW,YAAY,EAAI,CAAA,GACtE,KAAA;GAEN,OAAO,KAAK,MAAM;GACR;GACV,CAAA,EACD,YAAY,cACX,oBAAC,aAAD;GACE,OAAO;GACP,MAAM,KAAK,cAAc,aAAa,UAAU;GAChD,WAAW,MAAM,KAAK;GACtB,CAAA,CAES"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrightcoveEmbed.mjs","names":[],"sources":["../../src/Embed/BrightcoveEmbed.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 { Button, Figure } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { BrightcoveEmbedData, BrightcoveMetaData, BrightcoveVideoSource } from \"@ndla/types-embed\";\nimport parse from \"html-react-parser\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { EmbedByline } from \"../LicenseByline/EmbedByline\";\nimport { licenseAttributes } from \"../utils/licenseAttributes\";\nimport { EmbedErrorPlaceholder } from \"./EmbedErrorPlaceholder\";\nimport type { RenderContext } from \"./types\";\n\ninterface Props {\n embed: BrightcoveMetaData;\n renderContext?: RenderContext;\n lang?: string;\n}\n\nconst LinkedVideoButton = styled(Button, {\n base: {\n marginBlockStart: \"3xsmall\",\n },\n});\n\nconst BrightcoveIframe = styled(\"iframe\", {\n base: {\n border: 0,\n height: \"auto\",\n width: \"100%\",\n },\n});\n\nexport const makeIframeString = (url: string, width: string | number, height: string | number, title = \"\") => {\n const strippedWidth = typeof width === \"number\" ? width : width.replace(/\\s*px/, \"\");\n const strippedHeight = typeof height === \"number\" ? height : height.replace(/\\s*px/, \"\");\n const urlOrTitle = title || url;\n return `<iframe title=\"${urlOrTitle}\" aria-label=\"${urlOrTitle}\" src=\"${url}\" width=\"${strippedWidth}\" height=\"${strippedHeight}\" allowfullscreen scrolling=\"no\" style=\"border: none;\" loading=\"lazy\"></iframe>`;\n};\n\nexport const isNumeric = (value: any) => !Number.isNaN(value - Number.parseFloat(value));\n\nconst getIframeProps = (data: BrightcoveEmbedData, sources: BrightcoveVideoSource[]) => {\n const { account, videoid, player = \"default\" } = data;\n\n const source = sources.filter((s) => s.width && s.height).toSorted((a, b) => a!.height! - b.height!)[0];\n\n return {\n src: `https://players.brightcove.net/${account}/${player}_default/index.html?videoId=${videoid}`,\n height: source?.height ?? \"480\",\n width: source?.width ?? \"640\",\n };\n};\nexport const BrightcoveEmbed = ({ embed, renderContext = \"article\", lang }: Props) => {\n const [showOriginalVideo, setShowOriginalVideo] = useState(true);\n const { t } = useTranslation();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const { embedData } = embed;\n const fallbackTitle = `${t(\"embed.type.video\")}: ${embedData.videoid}`;\n const parsedDescription = useMemo(() => {\n if (embed.embedData.caption || renderContext === \"article\") {\n return embed.embedData.caption ? parse(embed.embedData.caption) : undefined;\n } else if (embed.status === \"success\" && embed.data.description) {\n return parse(embed.data.description);\n }\n }, [embed, renderContext]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (iframe) {\n const [width, height] = [parseInt(iframe.width), parseInt(iframe.height)];\n iframe.style.aspectRatio = `${width}/${height}`;\n iframe.width = \"\";\n iframe.height = \"\";\n }\n }, []);\n if (embed.status === \"error\") {\n return (\n <EmbedErrorPlaceholder type=\"video\">\n <BrightcoveIframe\n ref={iframeRef}\n title={embedData.alt || fallbackTitle}\n aria-label={embedData.alt || fallbackTitle}\n {...getIframeProps(embedData, [])}\n allow=\"fullscreen; encrypted-media\"\n />\n </EmbedErrorPlaceholder>\n );\n }\n const { data } = embed;\n\n const linkedVideoId = isNumeric(data.link?.text) ? data.link?.text : undefined;\n\n const originalVideoProps = getIframeProps(embedData, data.sources);\n const alternativeVideoProps = linkedVideoId\n ? getIframeProps({ ...embedData, videoid: linkedVideoId }, data.sources)\n : undefined;\n\n const licenseProps = licenseAttributes(data?.copyright?.license.license, lang, embedData.pageUrl);\n\n const title = data.name?.trim() ? `${t(\"embed.type.video\")}: ${data.name}` : fallbackTitle;\n\n return (\n <Figure data-embed-type=\"brightcove\" {...licenseProps}>\n <div className=\"brightcove-video\">\n <BrightcoveIframe\n ref={iframeRef}\n className=\"original\"\n title={title}\n aria-label={title}\n {...(alternativeVideoProps && !showOriginalVideo ? alternativeVideoProps : originalVideoProps)}\n allow=\"fullscreen; encrypted-media\"\n />\n </div>\n <EmbedByline type=\"video\" copyright={data.copyright!} description={parsedDescription}>\n <div>\n {!!linkedVideoId && (\n <LinkedVideoButton size=\"small\" variant=\"secondary\" onClick={() => setShowOriginalVideo((p) => !p)}>\n {t(`figure.button.${!showOriginalVideo ? \"original\" : \"alternative\"}`)}\n </LinkedVideoButton>\n )}\n </div>\n </EmbedByline>\n </Figure>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,MAAM,oBAAoB,OAAO,QAAQ,EACvC,MAAM,EACJ,kBAAkB,WACnB,EACF,CAAC;AAEF,MAAM,mBAAmB,OAAO,UAAU,EACxC,MAAM;CACJ,QAAQ;CACR,QAAQ;CACR,OAAO;CACR,EACF,CAAC;AASF,MAAa,aAAa,UAAe,CAAC,OAAO,MAAM,QAAQ,OAAO,WAAW,MAAM,CAAC;AAExF,MAAM,kBAAkB,MAA2B,YAAqC;
|
|
1
|
+
{"version":3,"file":"BrightcoveEmbed.mjs","names":[],"sources":["../../src/Embed/BrightcoveEmbed.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 { Button, Figure } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { BrightcoveEmbedData, BrightcoveMetaData, BrightcoveVideoSource } from \"@ndla/types-embed\";\nimport parse from \"html-react-parser\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { EmbedByline } from \"../LicenseByline/EmbedByline\";\nimport { licenseAttributes } from \"../utils/licenseAttributes\";\nimport { EmbedErrorPlaceholder } from \"./EmbedErrorPlaceholder\";\nimport type { RenderContext } from \"./types\";\n\ninterface Props {\n embed: BrightcoveMetaData;\n renderContext?: RenderContext;\n lang?: string;\n}\n\nconst LinkedVideoButton = styled(Button, {\n base: {\n marginBlockStart: \"3xsmall\",\n },\n});\n\nconst BrightcoveIframe = styled(\"iframe\", {\n base: {\n border: 0,\n height: \"auto\",\n width: \"100%\",\n },\n});\n\nexport const makeIframeString = (url: string, width: string | number, height: string | number, title = \"\") => {\n const strippedWidth = typeof width === \"number\" ? width : width.replace(/\\s*px/, \"\");\n const strippedHeight = typeof height === \"number\" ? height : height.replace(/\\s*px/, \"\");\n const urlOrTitle = title || url;\n return `<iframe title=\"${urlOrTitle}\" aria-label=\"${urlOrTitle}\" src=\"${url}\" width=\"${strippedWidth}\" height=\"${strippedHeight}\" allowfullscreen scrolling=\"no\" style=\"border: none;\" loading=\"lazy\"></iframe>`;\n};\n\nexport const isNumeric = (value: any) => !Number.isNaN(value - Number.parseFloat(value));\n\nconst getIframeProps = (data: BrightcoveEmbedData, sources: BrightcoveVideoSource[]) => {\n // oxlint-disable-next-line typescript/no-useless-default-assignment\n const { account, videoid, player = \"default\" } = data;\n\n const source = sources.filter((s) => s.width && s.height).toSorted((a, b) => a!.height! - b.height!)[0];\n\n return {\n src: `https://players.brightcove.net/${account}/${player}_default/index.html?videoId=${videoid}`,\n height: source?.height ?? \"480\",\n width: source?.width ?? \"640\",\n };\n};\nexport const BrightcoveEmbed = ({ embed, renderContext = \"article\", lang }: Props) => {\n const [showOriginalVideo, setShowOriginalVideo] = useState(true);\n const { t } = useTranslation();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const { embedData } = embed;\n const fallbackTitle = `${t(\"embed.type.video\")}: ${embedData.videoid}`;\n const parsedDescription = useMemo(() => {\n if (embed.embedData.caption || renderContext === \"article\") {\n return embed.embedData.caption ? parse(embed.embedData.caption) : undefined;\n } else if (embed.status === \"success\" && embed.data.description) {\n return parse(embed.data.description);\n }\n }, [embed, renderContext]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (iframe) {\n const [width, height] = [parseInt(iframe.width), parseInt(iframe.height)];\n iframe.style.aspectRatio = `${width}/${height}`;\n iframe.width = \"\";\n iframe.height = \"\";\n }\n }, []);\n if (embed.status === \"error\") {\n return (\n <EmbedErrorPlaceholder type=\"video\">\n <BrightcoveIframe\n ref={iframeRef}\n title={embedData.alt || fallbackTitle}\n aria-label={embedData.alt || fallbackTitle}\n {...getIframeProps(embedData, [])}\n allow=\"fullscreen; encrypted-media\"\n />\n </EmbedErrorPlaceholder>\n );\n }\n const { data } = embed;\n\n const linkedVideoId = isNumeric(data.link?.text) ? data.link?.text : undefined;\n\n const originalVideoProps = getIframeProps(embedData, data.sources);\n const alternativeVideoProps = linkedVideoId\n ? getIframeProps({ ...embedData, videoid: linkedVideoId }, data.sources)\n : undefined;\n\n const licenseProps = licenseAttributes(data?.copyright?.license.license, lang, embedData.pageUrl);\n\n const title = data.name?.trim() ? `${t(\"embed.type.video\")}: ${data.name}` : fallbackTitle;\n\n return (\n <Figure data-embed-type=\"brightcove\" {...licenseProps}>\n <div className=\"brightcove-video\">\n <BrightcoveIframe\n ref={iframeRef}\n className=\"original\"\n title={title}\n aria-label={title}\n {...(alternativeVideoProps && !showOriginalVideo ? alternativeVideoProps : originalVideoProps)}\n allow=\"fullscreen; encrypted-media\"\n />\n </div>\n <EmbedByline type=\"video\" copyright={data.copyright!} description={parsedDescription}>\n <div>\n {!!linkedVideoId && (\n <LinkedVideoButton size=\"small\" variant=\"secondary\" onClick={() => setShowOriginalVideo((p) => !p)}>\n {t(`figure.button.${!showOriginalVideo ? \"original\" : \"alternative\"}`)}\n </LinkedVideoButton>\n )}\n </div>\n </EmbedByline>\n </Figure>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExternalEmbed.mjs","names":[],"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,eAAe,OAAO,QAAQ,EAClC,MAAM,EACJ,YAAY;CACV,QAAQ;CACR,OAAO;CACR,EACF,EACF,CAAC;AAEF,MAAa,iBAAiB,EAAE,YAAmB;CACjD,MAAM,EAAE,MAAM,gBAAgB;CAC9B,MAAM,SAAS,OAAoB,KAAK;AAExC,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,oBAAC,uBAAD,EAAuB,MAAK,YAAa,CAAA;CAGlD,MAAM,EAAE,WAAW,SAAS;AAE5B,KAAI,UAAU,SAAS,aAKrB,QACE,oBAAC,QAAD;EAAQ,mBAAgB;YACtB,oBAAC,aAAD;GACE,
|
|
1
|
+
{"version":3,"file":"ExternalEmbed.mjs","names":[],"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,eAAe,OAAO,QAAQ,EAClC,MAAM,EACJ,YAAY;CACV,QAAQ;CACR,OAAO;CACR,EACF,EACF,CAAC;AAEF,MAAa,iBAAiB,EAAE,YAAmB;CACjD,MAAM,EAAE,MAAM,gBAAgB;CAC9B,MAAM,SAAS,OAAoB,KAAK;AAExC,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,oBAAC,uBAAD,EAAuB,MAAK,YAAa,CAAA;CAGlD,MAAM,EAAE,WAAW,SAAS;AAE5B,KAAI,UAAU,SAAS,aAKrB,QACE,oBAAC,QAAD;EAAQ,mBAAgB;YACtB,oBAAC,aAAD;GACE,OAAO;IANX,KAAK,KAAK,aAAa,MAAM;IAC7B,KAAK,UAAU,QAAQ,KAAA,IAAY,UAAU,MAAO,KAAK,aAAa,SAAS,WAAW;IAK1E;GACZ,OAAO,UAAU,SAAS;GAC1B,KAAK,UAAU;GACf,SAAS,UAAU,WAAW;GAC9B,YAAY,EAAE,oCAAoC;GAClD,CAAA;EACK,CAAA;AAIb,QACE,oBAAC,cAAD;EACE,mBAAgB;EAChB,KAAK;EACL,yBAAyB,EAAE,QAAQ,MAAM,QAAQ,QAAQ,IAAI;EAC7D,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframeEmbed.mjs","names":[],"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,eAAe,OAAO,UAAU,EACpC,MAAM;CACJ,OAAO;CACP,QAAQ;CACT,EACF,CAAC;AAEF,MAAM,eAAe,OAAO,QAAQ,EAClC,MAAM,EACJ,OAAO,QACR,EACF,CAAC;AAEF,MAAa,eAAe,EAAE,YAAmB;CAC/C,MAAM,EAAE,MAAM,gBAAgB;CAC9B,MAAM,YAAY,OAA0B,KAAK;AAEjD,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,oBAAC,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,oBAAC,cAAD;GAAc,mBAAgB;aAC5B,oBAAC,aAAD;IACE,
|
|
1
|
+
{"version":3,"file":"IframeEmbed.mjs","names":[],"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,eAAe,OAAO,UAAU,EACpC,MAAM;CACJ,OAAO;CACP,QAAQ;CACT,EACF,CAAC;AAEF,MAAM,eAAe,OAAO,QAAQ,EAClC,MAAM,EACJ,OAAO,QACR,EACF,CAAC;AAEF,MAAa,eAAe,EAAE,YAAmB;CAC/C,MAAM,EAAE,MAAM,gBAAgB;CAC9B,MAAM,YAAY,OAA0B,KAAK;AAEjD,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,oBAAC,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,oBAAC,cAAD;GAAc,mBAAgB;aAC5B,oBAAC,aAAD;IACE,OAAO;KAJG,KAAK,aAAa,MAAM;KAAU,KAAK,OAAO;KAI5C;IACZ,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,oBAAC,cAAD;EAAc,mBAAgB;YAC5B,oBAAC,cAAD;GACE,KAAK;GACE;GACP,cAAY;GACZ,KAAK;GACL,OAAO;GACP,QAAQ;GACR,OAAM;GACN,SAAQ;GACR,CAAA;EACW,CAAA"}
|
package/es/FactBox/FactBox.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FactBox.mjs","names":[],"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,cAAc,OAAO,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,gBAAgB,OAAO,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,eAAe,OAAO,QAAQ,EAClC,MAAM;CACJ,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ,EACN,SAAS,QACV;CACF,EACF,CAAC;AAIF,MAAa,UAAU,YACpB,EAAE,UAAU,MAAM,cAAc,cAAc,OAAO,GAAG,QAAQ,QAAQ;CACvE,MAAM,EAAE,MAAM,gBAAgB;CAC9B,MAAM,CAAC,OAAO,YAAY,SAA4B,cAAc,SAAS,SAAS;CACtF,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,CAAC,YAAY;CAClE,MAAM,YAAY,OAAO;CAIzB,MAAM,iBAAiB,cAAc;AACnC,SAAO,UAAU,WAAW,EAAE,OAAO,OAAO,MAAM,QAAQ,aAAa,OAAO,IAAI,GAAG,EAAE;IACtF,CAAC,MAAM,CAAC;AAEX,iBAAgB;AACd,MAAI,SAAS,KAAA,EACX,UAAS,OAAO,SAAS,SAAS;IAEnC,CAAC,KAAK,CAAC;CAEV,MAAM,UAAU,kBAAkB;EAChC,MAAM,WAAW,UAAU,SAAS,WAAW;AAC/C,WAAS,SAAS;AAClB,iBAAe,aAAa,OAAO;IAClC,CAAC,OAAO,aAAa,CAAC;AAEzB,QACE,qBAAC,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,oBAAC,cAAD;GACE,cAAY;GACH;GACT,iBAAiB;GACjB,iBAAe,UAAU;GACzB,SAAQ;GACR,iBAAe;aAEd,EAAE,WAAW,UAAU,SAAS,aAAa,aAAa;GAC9C,CAAA,EACf,oBAAC,eAAD;GAAe,IAAI;GAAW,cAAY;GAAO,eAAa,UAAU;GAAU,GAAI;GACnF;GACa,CAAA,CACJ;;EAGnB"}
|
|
1
|
+
{"version":3,"file":"FactBox.mjs","names":[],"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 paddingBottom: \"xxlarge\",\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,cAAc,OAAO,SAAS;CAClC,MAAM;EACJ,UAAU;EACV,SAAS;EACT,eAAe;EACf,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,gBAAgB,OAAO,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,eAAe,OAAO,QAAQ,EAClC,MAAM;CACJ,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ,EACN,SAAS,QACV;CACF,EACF,CAAC;AAIF,MAAa,UAAU,YACpB,EAAE,UAAU,MAAM,cAAc,cAAc,OAAO,GAAG,QAAQ,QAAQ;CACvE,MAAM,EAAE,MAAM,gBAAgB;CAC9B,MAAM,CAAC,OAAO,YAAY,SAA4B,cAAc,SAAS,SAAS;CACtF,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,CAAC,YAAY;CAClE,MAAM,YAAY,OAAO;CAIzB,MAAM,iBAAiB,cAAc;AACnC,SAAO,UAAU,WAAW,EAAE,OAAO,OAAO,MAAM,QAAQ,aAAa,OAAO,IAAI,GAAG,EAAE;IACtF,CAAC,MAAM,CAAC;AAEX,iBAAgB;AACd,MAAI,SAAS,KAAA,EACX,UAAS,OAAO,SAAS,SAAS;IAEnC,CAAC,KAAK,CAAC;CAEV,MAAM,UAAU,kBAAkB;EAChC,MAAM,WAAW,UAAU,SAAS,WAAW;AAC/C,WAAS,SAAS;AAClB,iBAAe,aAAa,OAAO;IAClC,CAAC,OAAO,aAAa,CAAC;AAEzB,QACE,qBAAC,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,oBAAC,cAAD;GACE,cAAY;GACH;GACT,iBAAiB;GACjB,iBAAe,UAAU;GACzB,SAAQ;GACR,iBAAe;aAEd,EAAE,WAAW,UAAU,SAAS,aAAa,aAAa;GAC9C,CAAA,EACf,oBAAC,eAAD;GAAe,IAAI;GAAW,cAAY;GAAO,eAAa,UAAU;GAAU,GAAI;GACnF;GACa,CAAA,CACJ;;EAGnB"}
|
package/es/Gloss/Gloss.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Gloss.mjs","names":["AccordionItemTrigger"],"sources":["../../src/Gloss/Gloss.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 { AccordionItemTrigger } from \"@ark-ui/react\";\nimport { ArrowDownShortLine } from \"@ndla/icons\";\nimport {\n AccordionItem,\n AccordionItemContent,\n AccordionItemIndicator,\n AccordionRoot,\n IconButton,\n Text,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { StyledVariantProps } from \"@ndla/styled-system/types\";\nimport type { ConceptTitleDTO, GlossDataDTO, GlossExampleDTO } from \"@ndla/types-backend/concept-api\";\nimport parse from \"html-react-parser\";\nimport { useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { SpeechControl } from \"../AudioPlayer/SpeechControl\";\nimport { GlossExample } from \"./GlossExample\";\n\n// TODO: Figure out padding between bordered and simple variant.\n// The design says that the content above the accordion content should have enough padding to align with the accordion content.\n// When a gloss is bordered there's way too much padding.\n\nconst getFilteredExamples = (\n glossData: GlossDataDTO | undefined,\n exampleIds: string | undefined,\n exampleLangs: string | undefined,\n): GlossExampleDTO[][] => {\n if (exampleIds !== undefined || exampleLangs !== undefined) {\n const exampleIdsList = exampleIds?.toString()?.split(\",\") ?? [];\n const exampleLangsList = exampleLangs?.split(\",\") ?? [];\n\n const filteredExamples =\n glossData?.examples?.map((examples, i) => {\n if (exampleIdsList.includes(i.toString())) {\n return examples.filter((e) => exampleLangsList.includes(e.language));\n }\n return [];\n }) ?? [];\n const examplesWithoutEmpty = filteredExamples.filter((el) => !!el.length);\n return examplesWithoutEmpty;\n }\n return glossData?.examples ?? [];\n};\n\nconst Container = styled(\"div\", {\n base: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n },\n});\n\nconst TextWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n gap: \"small\",\n },\n});\n\nconst StyledAccordionItemContent = styled(AccordionItemContent, {\n base: {\n paddingInline: \"0\",\n },\n});\n\nconst StyledContainer = styled(Container, {\n base: {\n marginBlockStart: \"3xsmall\",\n },\n});\n\nconst StyledAccordionItem = styled(AccordionItem, {\n base: {\n paddingBlock: \"small\",\n paddingInline: \"medium\",\n },\n defaultVariants: {\n variant: \"simple\",\n },\n variants: {\n variant: {\n simple: {},\n bordered: {\n border: \"1px solid\",\n borderColor: \"stroke.subtle\",\n borderRadius: \"xsmall\",\n },\n },\n },\n});\n\ntype GlossVariantProps = StyledVariantProps<typeof StyledAccordionItem>;\n\nexport interface Props {\n title: ConceptTitleDTO;\n glossData?: GlossDataDTO;\n audio?: {\n title: string;\n src?: string;\n };\n exampleIds?: string;\n exampleLangs?: string;\n}\n\nexport const Gloss = ({ title, glossData, audio, exampleIds, exampleLangs, variant }: Props & GlossVariantProps) => {\n const { t } = useTranslation();\n\n const parsedTitle = useMemo(() => parse(title.htmlTitle), [title.htmlTitle]);\n\n const filteredExamples = useMemo(\n () => getFilteredExamples(glossData, exampleIds, exampleLangs),\n [exampleIds, exampleLangs, glossData],\n );\n\n if (!glossData) return null;\n\n return (\n <AccordionRoot multiple variant=\"clean\">\n <StyledAccordionItem value=\"gloss\" variant={variant}>\n <Container>\n <TextWrapper>\n <Text textStyle=\"label.medium\" fontWeight=\"bold\" asChild consumeCss lang={glossData.originalLanguage}>\n <span>{glossData.gloss}</span>\n </Text>\n {!!glossData.transcriptions.traditional && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n key={t(\"gloss.transcriptions.traditional\")}\n aria-label={t(\"gloss.transcriptions.traditional\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.traditional}\n </span>\n </Text>\n )}\n {!!glossData.transcriptions.pinyin && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n data-pinyin=\"\"\n key={t(\"gloss.transcriptions.pinyin\")}\n aria-label={t(\"gloss.transcriptions.pinyin\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.pinyin}\n </span>\n </Text>\n )}\n {!!glossData.wordClass && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span aria-label={t(\"gloss.wordClass\")}>\n {glossData.wordClass.map((wc) => t(`wordClass.${wc}`).toLowerCase()).join(\" / \")}\n </span>\n </Text>\n )}\n </TextWrapper>\n {!!audio?.src && <SpeechControl src={audio.src} title={audio.title} />}\n </Container>\n <StyledContainer>\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span lang={title.language}>{parsedTitle}</span>\n </Text>\n {!!filteredExamples.length && (\n <AccordionItemTrigger asChild>\n <IconButton variant=\"tertiary\" aria-label={t(\"gloss.showExamples\")} title={t(\"gloss.showExamples\")}>\n <AccordionItemIndicator asChild>\n <ArrowDownShortLine size=\"medium\" />\n </AccordionItemIndicator>\n </IconButton>\n </AccordionItemTrigger>\n )}\n </StyledContainer>\n <StyledAccordionItemContent>\n {filteredExamples.map((examples, index) => (\n <GlossExample\n key={`gloss-example-${index}`}\n examples={examples}\n originalLanguage={glossData.originalLanguage}\n />\n ))}\n </StyledAccordionItemContent>\n </StyledAccordionItem>\n </AccordionRoot>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AA+BA,MAAM,uBACJ,WACA,YACA,iBACwB;AACxB,KAAI,eAAe,KAAA,KAAa,iBAAiB,KAAA,GAAW;EAC1D,MAAM,iBAAiB,YAAY,UAAU,EAAE,MAAM,IAAI,IAAI,EAAE;EAC/D,MAAM,mBAAmB,cAAc,MAAM,IAAI,IAAI,EAAE;AAUvD,UAPE,WAAW,UAAU,KAAK,UAAU,MAAM;AACxC,OAAI,eAAe,SAAS,EAAE,UAAU,CAAC,CACvC,QAAO,SAAS,QAAQ,MAAM,iBAAiB,SAAS,EAAE,SAAS,CAAC;AAEtE,UAAO,EAAE;IACT,IAAI,EAAE,EACoC,QAAQ,OAAO,CAAC,CAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"Gloss.mjs","names":["AccordionItemTrigger"],"sources":["../../src/Gloss/Gloss.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 { AccordionItemTrigger } from \"@ark-ui/react\";\nimport { ArrowDownShortLine } from \"@ndla/icons\";\nimport {\n AccordionItem,\n AccordionItemContent,\n AccordionItemIndicator,\n AccordionRoot,\n IconButton,\n Text,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { StyledVariantProps } from \"@ndla/styled-system/types\";\nimport type { ConceptTitleDTO, GlossDataDTO, GlossExampleDTO } from \"@ndla/types-backend/concept-api\";\nimport parse from \"html-react-parser\";\nimport { useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { SpeechControl } from \"../AudioPlayer/SpeechControl\";\nimport { GlossExample } from \"./GlossExample\";\n\n// TODO: Figure out padding between bordered and simple variant.\n// The design says that the content above the accordion content should have enough padding to align with the accordion content.\n// When a gloss is bordered there's way too much padding.\n\nconst getFilteredExamples = (\n glossData: GlossDataDTO | undefined,\n exampleIds: string | undefined,\n exampleLangs: string | undefined,\n): GlossExampleDTO[][] => {\n if (exampleIds !== undefined || exampleLangs !== undefined) {\n const exampleIdsList = exampleIds?.toString()?.split(\",\") ?? [];\n const exampleLangsList = exampleLangs?.split(\",\") ?? [];\n\n const filteredExamples =\n glossData?.examples?.map((examples, i) => {\n if (exampleIdsList.includes(i.toString())) {\n return examples.filter((e) => exampleLangsList.includes(e.language));\n }\n return [];\n }) ?? [];\n const examplesWithoutEmpty = filteredExamples.filter((el) => !!el.length);\n return examplesWithoutEmpty;\n }\n return glossData?.examples ?? [];\n};\n\nconst Container = styled(\"div\", {\n base: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n },\n});\n\nconst TextWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n gap: \"small\",\n },\n});\n\nconst StyledAccordionItemContent = styled(AccordionItemContent, {\n base: {\n paddingInline: \"0\",\n },\n});\n\nconst StyledContainer = styled(Container, {\n base: {\n marginBlockStart: \"3xsmall\",\n },\n});\n\nconst StyledAccordionItem = styled(AccordionItem, {\n base: {\n paddingBlock: \"small\",\n paddingInline: \"medium\",\n },\n defaultVariants: {\n variant: \"simple\",\n },\n variants: {\n variant: {\n simple: {},\n bordered: {\n border: \"1px solid\",\n borderColor: \"stroke.subtle\",\n borderRadius: \"xsmall\",\n },\n },\n },\n});\n\ntype GlossVariantProps = StyledVariantProps<typeof StyledAccordionItem>;\n\nexport interface Props {\n title: ConceptTitleDTO;\n glossData?: GlossDataDTO;\n audio?: {\n title: string;\n src?: string;\n };\n exampleIds?: string;\n exampleLangs?: string;\n}\n\nexport const Gloss = ({ title, glossData, audio, exampleIds, exampleLangs, variant }: Props & GlossVariantProps) => {\n const { t } = useTranslation();\n\n const parsedTitle = useMemo(() => parse(title.htmlTitle), [title.htmlTitle]);\n\n const filteredExamples = useMemo(\n () => getFilteredExamples(glossData, exampleIds, exampleLangs),\n [exampleIds, exampleLangs, glossData],\n );\n\n if (!glossData) return null;\n\n return (\n <AccordionRoot multiple variant=\"clean\">\n <StyledAccordionItem value=\"gloss\" variant={variant}>\n <Container>\n <TextWrapper>\n <Text textStyle=\"label.medium\" fontWeight=\"bold\" asChild consumeCss lang={glossData.originalLanguage}>\n <span>{glossData.gloss}</span>\n </Text>\n {!!glossData.transcriptions.traditional && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n key={t(\"gloss.transcriptions.traditional\")}\n aria-label={t(\"gloss.transcriptions.traditional\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.traditional}\n </span>\n </Text>\n )}\n {!!glossData.transcriptions.pinyin && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n data-pinyin=\"\"\n key={t(\"gloss.transcriptions.pinyin\")}\n aria-label={t(\"gloss.transcriptions.pinyin\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.pinyin}\n </span>\n </Text>\n )}\n {!!glossData.wordClass && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span aria-label={t(\"gloss.wordClass\")}>\n {glossData.wordClass.map((wc) => t(`wordClass.${wc}`).toLowerCase()).join(\" / \")}\n </span>\n </Text>\n )}\n </TextWrapper>\n {!!audio?.src && <SpeechControl src={audio.src} title={audio.title} />}\n </Container>\n <StyledContainer>\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span lang={title.language}>{parsedTitle}</span>\n </Text>\n {!!filteredExamples.length && (\n <AccordionItemTrigger asChild>\n <IconButton variant=\"tertiary\" aria-label={t(\"gloss.showExamples\")} title={t(\"gloss.showExamples\")}>\n <AccordionItemIndicator asChild>\n <ArrowDownShortLine size=\"medium\" />\n </AccordionItemIndicator>\n </IconButton>\n </AccordionItemTrigger>\n )}\n </StyledContainer>\n <StyledAccordionItemContent>\n {filteredExamples.map((examples, index) => (\n <GlossExample\n key={`gloss-example-${index}`}\n examples={examples}\n originalLanguage={glossData.originalLanguage}\n />\n ))}\n </StyledAccordionItemContent>\n </StyledAccordionItem>\n </AccordionRoot>\n );\n};\n"],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { styled } from "@ndla/styled-system/jsx";
|
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
import { AlertLine } from "@ndla/icons";
|
|
7
|
-
import { getLicenseByAbbreviation } from "@ndla/licenses";
|
|
7
|
+
import { getLicenseByAbbreviation, rights } from "@ndla/licenses";
|
|
8
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/LicenseByline/EmbedByline.tsx
|
|
10
10
|
/**
|
|
@@ -110,6 +110,7 @@ const LicenseDescription = ({ children, isOpen, setIsOpen }) => {
|
|
|
110
110
|
const LicenseContainerContent = ({ children, copyright, type }) => {
|
|
111
111
|
const { t, i18n } = useTranslation();
|
|
112
112
|
const license = copyright ? getLicenseByAbbreviation(copyright.license?.license ?? "", i18n.language) : void 0;
|
|
113
|
+
const shouldShowLicense = !!license && !license.rights.includes(rights.NA);
|
|
113
114
|
const captionAuthors = [
|
|
114
115
|
copyright?.creators,
|
|
115
116
|
copyright?.rightsholders,
|
|
@@ -120,7 +121,7 @@ const LicenseContainerContent = ({ children, copyright, type }) => {
|
|
|
120
121
|
children,
|
|
121
122
|
` ${t(`embed.type.${type}`)}${captionAuthors.length ? ": " : ""}`,
|
|
122
123
|
/* @__PURE__ */ jsx("span", { children: captionAuthors.map((author) => author.name).join(", ") }),
|
|
123
|
-
|
|
124
|
+
shouldShowLicense ? /* @__PURE__ */ jsxs(Fragment$1, { children: [" / ", /* @__PURE__ */ jsx(LicenseLink, {
|
|
124
125
|
license,
|
|
125
126
|
hideLink: !isOpen && !!children
|
|
126
127
|
})] }) : null
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmbedByline.mjs","names":[],"sources":["../../src/LicenseByline/EmbedByline.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 { AlertLine } from \"@ndla/icons\";\nimport { getLicenseByAbbreviation } from \"@ndla/licenses\";\nimport { Button, Text } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { CopyrightDTO as ArticleCopyright } from \"@ndla/types-backend/article-api\";\nimport type { CopyrightDTO as AudioCopyright } from \"@ndla/types-backend/audio-api\";\nimport type { DraftCopyrightDTO as ConceptCopyright } from \"@ndla/types-backend/concept-api\";\nimport type { CopyrightDTO as ImageCopyright } from \"@ndla/types-backend/image-api\";\nimport type { BrightcoveCopyright } from \"@ndla/types-embed\";\nimport { type Dispatch, type ReactNode, type SetStateAction, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { LicenseLink } from \"./LicenseLink\";\n\ninterface BaseProps {\n description?: ReactNode;\n children?: ReactNode;\n visibleAlt?: string;\n error?: true | false;\n hideDescription?: boolean;\n hideCopyright?: boolean;\n}\n\nexport interface EmbedBylineErrorProps extends BaseProps {\n type: EmbedBylineTypeProps[\"type\"] | \"h5p\" | \"external\" | \"code\";\n error: true;\n}\n\ninterface ImageProps extends BaseProps {\n type: \"image\";\n copyright: ImageCopyright | undefined;\n}\n\ninterface BrightcoveProps extends BaseProps {\n type: \"video\";\n copyright: BrightcoveCopyright | undefined;\n}\n\ninterface AudioProps extends BaseProps {\n type: \"audio\";\n copyright: AudioCopyright | undefined;\n}\n\ninterface PodcastProps extends BaseProps {\n type: \"podcast\";\n copyright: AudioCopyright | undefined;\n}\n\ninterface ConceptProps extends BaseProps {\n type: \"concept\" | \"gloss\";\n copyright: ConceptCopyright | undefined;\n}\n\ninterface CopyrightProps extends BaseProps {\n type: \"copyright\";\n copyright: ArticleCopyright | undefined;\n}\n\nexport type EmbedBylineTypeProps =\n | ImageProps\n | BrightcoveProps\n | AudioProps\n | PodcastProps\n | ConceptProps\n | CopyrightProps;\n\ntype Props = EmbedBylineTypeProps | EmbedBylineErrorProps;\n\nconst BylineWrapper = styled(\"figcaption\", {\n base: {\n display: \"flex\",\n flexDirection: \"column\",\n paddingBlock: \"xsmall\",\n textStyle: \"label.medium\",\n color: \"text.subtle\",\n },\n});\n\nconst ErrorBylineWrapper = styled(BylineWrapper, {\n base: {\n border: \"1px solid\",\n borderColor: \"stroke.error\",\n borderRadius: \"xsmall\",\n background: \"surface.dangerSubtle\",\n paddingInline: \"medium\",\n paddingBlock: \"medium\",\n },\n});\n\nconst StyledText = styled(Text, {\n base: {\n fontStyle: \"italic\",\n },\n});\n\nconst ContentWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n gap: \"xsmall\",\n alignItems: \"center\",\n textStyle: \"label.medium\",\n },\n});\n\nconst BaseDescription = styled(\"div\", {\n base: {\n display: \"inline-flex\",\n whiteSpace: \"pre-wrap\",\n },\n});\n\nexport const EmbedByline = ({ type, description, children, visibleAlt, hideCopyright, ...props }: Props) => {\n const { t } = useTranslation();\n\n if (props.error) {\n const typeString = type === \"h5p\" ? \"H5P\" : t(`embed.type.${type}`).toLowerCase();\n return (\n <ErrorBylineWrapper>\n <ContentWrapper>\n <AlertLine />\n <BaseDescription>\n <span>{t(\"embed.embedError\", { type: typeString })}</span>\n </BaseDescription>\n </ContentWrapper>\n </ErrorBylineWrapper>\n );\n }\n\n const { copyright } = props;\n const hideByline = hideCopyright && !description;\n\n return (\n <>\n {!hideByline && (\n <BylineWrapper>\n <div>\n {!!hideCopyright && description}\n {!hideCopyright && (\n <LicenseContainerContent type={type} copyright={copyright}>\n {description}\n </LicenseContainerContent>\n )}\n {children}\n </div>\n </BylineWrapper>\n )}\n {visibleAlt ? (\n <StyledText color=\"text.subtle\" textStyle=\"label.medium\" asChild consumeCss>\n <span>{`Alt: ${visibleAlt}`}</span>\n </StyledText>\n ) : null}\n </>\n );\n};\n\ninterface LicenseContainerProps {\n children?: ReactNode;\n copyright: EmbedBylineTypeProps[\"copyright\"];\n type: Props[\"type\"];\n}\n\nconst StyledDescription = styled(BaseDescription, {\n base: {\n mobileWideDown: {\n display: \"grid\",\n gridTemplateColumns: \"1fr auto\",\n alignItems: \"center\",\n overflow: \"hidden\",\n _open: {\n display: \"inline\",\n },\n },\n },\n});\n\nconst TextContent = styled(\"span\", {\n base: {\n mobileWideDown: {\n whiteSpace: \"nowrap\",\n maxHeight: \"large\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n transitionProperty: \"max-height\",\n transitionDuration: \"slow\",\n transitionTimingFunction: \"ease-in\",\n marginInlineEnd: \"4xsmall\",\n _open: {\n whiteSpace: \"pre-wrap\",\n maxHeight: \"none\",\n },\n },\n },\n});\n\nconst StyledButton = styled(Button, {\n base: {\n mobileWide: {\n display: \"none\",\n },\n _print: {\n display: \"none\",\n },\n },\n});\n\ninterface LicenseDescriptionProps {\n children?: ReactNode;\n isOpen: boolean;\n setIsOpen: Dispatch<SetStateAction<boolean>>;\n}\n\nconst LicenseDescription = ({ children, isOpen, setIsOpen }: LicenseDescriptionProps) => {\n const open = isOpen ? { \"data-open\": \"\" } : {};\n const { t } = useTranslation();\n\n const handleToggle = () => {\n setIsOpen(!isOpen);\n };\n\n return (\n <ContentWrapper>\n <StyledDescription {...open}>\n <TextContent {...open}>{children}</TextContent>\n <StyledButton variant=\"link\" size=\"small\" onClick={handleToggle}>\n {isOpen ? `${t(\"audio.readLessDescriptionLabel\")}` : `${t(\"audio.readMoreDescriptionLabel\")}`}\n </StyledButton>\n </StyledDescription>\n </ContentWrapper>\n );\n};\n\nexport const LicenseContainerContent = ({ children, copyright, type }: LicenseContainerProps) => {\n const { t, i18n } = useTranslation();\n const license = copyright ? getLicenseByAbbreviation(copyright.license?.license ?? \"\", i18n.language) : undefined;\n const captionAuthors =\n [copyright?.creators, copyright?.rightsholders, copyright?.processors].find((authors) => authors?.length) ?? [];\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const content = (\n <>\n {children}\n {` ${t(`embed.type.${type}`)}${captionAuthors.length ? \": \" : \"\"}`}\n <span>{captionAuthors.map((author) => author.name).join(\", \")}</span>\n {license ? (\n <>\n {\" / \"}\n {<LicenseLink license={license} hideLink={!isOpen && !!children} />}\n </>\n ) : null}\n </>\n );\n\n if (children) {\n return (\n <LicenseDescription isOpen={isOpen} setIsOpen={setIsOpen}>\n {content}\n </LicenseDescription>\n );\n }\n\n return (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span>{content}</span>\n </Text>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EmbedByline.mjs","names":[],"sources":["../../src/LicenseByline/EmbedByline.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 { AlertLine } from \"@ndla/icons\";\nimport { getLicenseByAbbreviation, rights } from \"@ndla/licenses\";\nimport { Button, Text } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { CopyrightDTO as ArticleCopyright } from \"@ndla/types-backend/article-api\";\nimport type { CopyrightDTO as AudioCopyright } from \"@ndla/types-backend/audio-api\";\nimport type { DraftCopyrightDTO as ConceptCopyright } from \"@ndla/types-backend/concept-api\";\nimport type { CopyrightDTO as ImageCopyright } from \"@ndla/types-backend/image-api\";\nimport type { BrightcoveCopyright } from \"@ndla/types-embed\";\nimport { type Dispatch, type ReactNode, type SetStateAction, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { LicenseLink } from \"./LicenseLink\";\n\ninterface BaseProps {\n description?: ReactNode;\n children?: ReactNode;\n visibleAlt?: string;\n error?: true | false;\n hideDescription?: boolean;\n hideCopyright?: boolean;\n}\n\nexport interface EmbedBylineErrorProps extends BaseProps {\n type: EmbedBylineTypeProps[\"type\"] | \"h5p\" | \"external\" | \"code\";\n error: true;\n}\n\ninterface ImageProps extends BaseProps {\n type: \"image\";\n copyright: ImageCopyright | undefined;\n}\n\ninterface BrightcoveProps extends BaseProps {\n type: \"video\";\n copyright: BrightcoveCopyright | undefined;\n}\n\ninterface AudioProps extends BaseProps {\n type: \"audio\";\n copyright: AudioCopyright | undefined;\n}\n\ninterface PodcastProps extends BaseProps {\n type: \"podcast\";\n copyright: AudioCopyright | undefined;\n}\n\ninterface ConceptProps extends BaseProps {\n type: \"concept\" | \"gloss\";\n copyright: ConceptCopyright | undefined;\n}\n\ninterface CopyrightProps extends BaseProps {\n type: \"copyright\";\n copyright: ArticleCopyright | undefined;\n}\n\nexport type EmbedBylineTypeProps =\n | ImageProps\n | BrightcoveProps\n | AudioProps\n | PodcastProps\n | ConceptProps\n | CopyrightProps;\n\ntype Props = EmbedBylineTypeProps | EmbedBylineErrorProps;\n\nconst BylineWrapper = styled(\"figcaption\", {\n base: {\n display: \"flex\",\n flexDirection: \"column\",\n paddingBlock: \"xsmall\",\n textStyle: \"label.medium\",\n color: \"text.subtle\",\n },\n});\n\nconst ErrorBylineWrapper = styled(BylineWrapper, {\n base: {\n border: \"1px solid\",\n borderColor: \"stroke.error\",\n borderRadius: \"xsmall\",\n background: \"surface.dangerSubtle\",\n paddingInline: \"medium\",\n paddingBlock: \"medium\",\n },\n});\n\nconst StyledText = styled(Text, {\n base: {\n fontStyle: \"italic\",\n },\n});\n\nconst ContentWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n gap: \"xsmall\",\n alignItems: \"center\",\n textStyle: \"label.medium\",\n },\n});\n\nconst BaseDescription = styled(\"div\", {\n base: {\n display: \"inline-flex\",\n whiteSpace: \"pre-wrap\",\n },\n});\n\nexport const EmbedByline = ({ type, description, children, visibleAlt, hideCopyright, ...props }: Props) => {\n const { t } = useTranslation();\n\n if (props.error) {\n const typeString = type === \"h5p\" ? \"H5P\" : t(`embed.type.${type}`).toLowerCase();\n return (\n <ErrorBylineWrapper>\n <ContentWrapper>\n <AlertLine />\n <BaseDescription>\n <span>{t(\"embed.embedError\", { type: typeString })}</span>\n </BaseDescription>\n </ContentWrapper>\n </ErrorBylineWrapper>\n );\n }\n\n const { copyright } = props;\n const hideByline = hideCopyright && !description;\n\n return (\n <>\n {!hideByline && (\n <BylineWrapper>\n <div>\n {!!hideCopyright && description}\n {!hideCopyright && (\n <LicenseContainerContent type={type} copyright={copyright}>\n {description}\n </LicenseContainerContent>\n )}\n {children}\n </div>\n </BylineWrapper>\n )}\n {visibleAlt ? (\n <StyledText color=\"text.subtle\" textStyle=\"label.medium\" asChild consumeCss>\n <span>{`Alt: ${visibleAlt}`}</span>\n </StyledText>\n ) : null}\n </>\n );\n};\n\ninterface LicenseContainerProps {\n children?: ReactNode;\n copyright: EmbedBylineTypeProps[\"copyright\"];\n type: Props[\"type\"];\n}\n\nconst StyledDescription = styled(BaseDescription, {\n base: {\n mobileWideDown: {\n display: \"grid\",\n gridTemplateColumns: \"1fr auto\",\n alignItems: \"center\",\n overflow: \"hidden\",\n _open: {\n display: \"inline\",\n },\n },\n },\n});\n\nconst TextContent = styled(\"span\", {\n base: {\n mobileWideDown: {\n whiteSpace: \"nowrap\",\n maxHeight: \"large\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n transitionProperty: \"max-height\",\n transitionDuration: \"slow\",\n transitionTimingFunction: \"ease-in\",\n marginInlineEnd: \"4xsmall\",\n _open: {\n whiteSpace: \"pre-wrap\",\n maxHeight: \"none\",\n },\n },\n },\n});\n\nconst StyledButton = styled(Button, {\n base: {\n mobileWide: {\n display: \"none\",\n },\n _print: {\n display: \"none\",\n },\n },\n});\n\ninterface LicenseDescriptionProps {\n children?: ReactNode;\n isOpen: boolean;\n setIsOpen: Dispatch<SetStateAction<boolean>>;\n}\n\nconst LicenseDescription = ({ children, isOpen, setIsOpen }: LicenseDescriptionProps) => {\n const open = isOpen ? { \"data-open\": \"\" } : {};\n const { t } = useTranslation();\n\n const handleToggle = () => {\n setIsOpen(!isOpen);\n };\n\n return (\n <ContentWrapper>\n <StyledDescription {...open}>\n <TextContent {...open}>{children}</TextContent>\n <StyledButton variant=\"link\" size=\"small\" onClick={handleToggle}>\n {isOpen ? `${t(\"audio.readLessDescriptionLabel\")}` : `${t(\"audio.readMoreDescriptionLabel\")}`}\n </StyledButton>\n </StyledDescription>\n </ContentWrapper>\n );\n};\n\nexport const LicenseContainerContent = ({ children, copyright, type }: LicenseContainerProps) => {\n const { t, i18n } = useTranslation();\n const license = copyright ? getLicenseByAbbreviation(copyright.license?.license ?? \"\", i18n.language) : undefined;\n const shouldShowLicense = !!license && !license.rights.includes(rights.NA);\n const captionAuthors =\n [copyright?.creators, copyright?.rightsholders, copyright?.processors].find((authors) => authors?.length) ?? [];\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const content = (\n <>\n {children}\n {` ${t(`embed.type.${type}`)}${captionAuthors.length ? \": \" : \"\"}`}\n <span>{captionAuthors.map((author) => author.name).join(\", \")}</span>\n {shouldShowLicense ? (\n <>\n {\" / \"}\n {<LicenseLink license={license} hideLink={!isOpen && !!children} />}\n </>\n ) : null}\n </>\n );\n\n if (children) {\n return (\n <LicenseDescription isOpen={isOpen} setIsOpen={setIsOpen}>\n {content}\n </LicenseDescription>\n );\n }\n\n return (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span>{content}</span>\n </Text>\n );\n};\n"],"mappings":"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"}
|
package/es/Pitch/Pitch.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pitch.mjs","names":[],"sources":["../../src/Pitch/Pitch.tsx"],"sourcesContent":["/**\n * Copyright (c) 2024-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 { CardHeading, CardImage, CardRoot, Text } from \"@ndla/primitives\";\nimport { SafeLink } from \"@ndla/safelink\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { linkOverlay } from \"@ndla/styled-system/patterns\";\nimport parse from \"html-react-parser\";\nimport { getPossiblyRelativeUrl } from \"../utils/relativeUrl\";\n\nexport interface Props {\n title: string;\n url: string;\n description?: string;\n metaImage: {\n url: string;\n alt: string;\n };\n path?: string;\n}\n\nconst StyledCardHeading = styled(CardHeading, {\n base: {\n paddingBlockStart: \"medium\",\n },\n});\n\nconst StyledText = styled(Text, {\n base: {\n paddingBlockEnd: \"medium\",\n },\n});\n\nconst StyledCardRoot = styled(CardRoot, {\n base: {\n outline: \"0px\",\n boxShadow: \"none\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"small\",\n },\n});\n\nconst StyledCardImage = styled(CardImage, {\n base: {\n aspectRatio: \"16/9\",\n height: \"unset\",\n },\n});\n\nexport const Pitch = ({ title, url, metaImage, path, description }: Props) => {\n const href = getPossiblyRelativeUrl(url, path);\n\n return (\n <StyledCardRoot nonInteractive data-embed-type=\"pitch\" asChild consumeCss>\n <div>\n <StyledCardHeading textStyle=\"heading.small\" asChild consumeCss>\n <SafeLink to={href} unstyled css={linkOverlay.raw()}>\n {parse(title)}\n </SafeLink>\n </StyledCardHeading>\n {!!description && (\n <StyledText textStyle=\"body.xlarge\" asChild consumeCss>\n <div>{parse(description)}</div>\n </StyledText>\n )}\n <StyledCardImage\n variant=\"rounded\"\n src={metaImage.url}\n alt={metaImage.alt}\n sizes=\"480px\"\n fallbackWidth={300}\n width={550}\n height={310}\n />\n </div>\n </StyledCardRoot>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AA0BA,MAAM,oBAAoB,OAAO,aAAa,EAC5C,MAAM,EACJ,mBAAmB,UACpB,EACF,CAAC;AAEF,MAAM,aAAa,OAAO,MAAM,EAC9B,MAAM,EACJ,iBAAiB,UAClB,EACF,CAAC;AAEF,MAAM,iBAAiB,OAAO,UAAU,EACtC,MAAM;CACJ,SAAS;CACT,WAAW;CACX,SAAS;CACT,eAAe;CACf,KAAK;CACN,EACF,CAAC;AAEF,MAAM,kBAAkB,OAAO,WAAW,EACxC,MAAM;CACJ,aAAa;CACb,QAAQ;CACT,EACF,CAAC;AAEF,MAAa,SAAS,EAAE,OAAO,KAAK,WAAW,MAAM,kBAAyB;AAG5E,QACE,oBAAC,gBAAD;EAAgB,gBAAA;EAAe,mBAAgB;EAAQ,SAAA;EAAQ,YAAA;YAC7D,qBAAC,OAAD,EAAA,UAAA;GACE,oBAAC,mBAAD;IAAmB,WAAU;IAAgB,SAAA;IAAQ,YAAA;cACnD,oBAAC,UAAD;KAAU,IANL,uBAAuB,KAAK,
|
|
1
|
+
{"version":3,"file":"Pitch.mjs","names":[],"sources":["../../src/Pitch/Pitch.tsx"],"sourcesContent":["/**\n * Copyright (c) 2024-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 { CardHeading, CardImage, CardRoot, Text } from \"@ndla/primitives\";\nimport { SafeLink } from \"@ndla/safelink\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { linkOverlay } from \"@ndla/styled-system/patterns\";\nimport parse from \"html-react-parser\";\nimport { getPossiblyRelativeUrl } from \"../utils/relativeUrl\";\n\nexport interface Props {\n title: string;\n url: string;\n description?: string;\n metaImage: {\n url: string;\n alt: string;\n };\n path?: string;\n}\n\nconst StyledCardHeading = styled(CardHeading, {\n base: {\n paddingBlockStart: \"medium\",\n },\n});\n\nconst StyledText = styled(Text, {\n base: {\n paddingBlockEnd: \"medium\",\n },\n});\n\nconst StyledCardRoot = styled(CardRoot, {\n base: {\n outline: \"0px\",\n boxShadow: \"none\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"small\",\n },\n});\n\nconst StyledCardImage = styled(CardImage, {\n base: {\n aspectRatio: \"16/9\",\n height: \"unset\",\n },\n});\n\nexport const Pitch = ({ title, url, metaImage, path, description }: Props) => {\n const href = getPossiblyRelativeUrl(url, path);\n\n return (\n <StyledCardRoot nonInteractive data-embed-type=\"pitch\" asChild consumeCss>\n <div>\n <StyledCardHeading textStyle=\"heading.small\" asChild consumeCss>\n <SafeLink to={href} unstyled css={linkOverlay.raw()}>\n {parse(title)}\n </SafeLink>\n </StyledCardHeading>\n {!!description && (\n <StyledText textStyle=\"body.xlarge\" asChild consumeCss>\n <div>{parse(description)}</div>\n </StyledText>\n )}\n <StyledCardImage\n variant=\"rounded\"\n src={metaImage.url}\n alt={metaImage.alt}\n sizes=\"480px\"\n fallbackWidth={300}\n width={550}\n height={310}\n />\n </div>\n </StyledCardRoot>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AA0BA,MAAM,oBAAoB,OAAO,aAAa,EAC5C,MAAM,EACJ,mBAAmB,UACpB,EACF,CAAC;AAEF,MAAM,aAAa,OAAO,MAAM,EAC9B,MAAM,EACJ,iBAAiB,UAClB,EACF,CAAC;AAEF,MAAM,iBAAiB,OAAO,UAAU,EACtC,MAAM;CACJ,SAAS;CACT,WAAW;CACX,SAAS;CACT,eAAe;CACf,KAAK;CACN,EACF,CAAC;AAEF,MAAM,kBAAkB,OAAO,WAAW,EACxC,MAAM;CACJ,aAAa;CACb,QAAQ;CACT,EACF,CAAC;AAEF,MAAa,SAAS,EAAE,OAAO,KAAK,WAAW,MAAM,kBAAyB;AAG5E,QACE,oBAAC,gBAAD;EAAgB,gBAAA;EAAe,mBAAgB;EAAQ,SAAA;EAAQ,YAAA;YAC7D,qBAAC,OAAD,EAAA,UAAA;GACE,oBAAC,mBAAD;IAAmB,WAAU;IAAgB,SAAA;IAAQ,YAAA;cACnD,oBAAC,UAAD;KAAU,IANL,uBAAuB,KAAK,KAMf;KAAE,UAAA;KAAS,KAAK,YAAY,KAAK;eAChD,MAAM,MAAM;KACJ,CAAA;IACO,CAAA;GACnB,CAAC,CAAC,eACD,oBAAC,YAAD;IAAY,WAAU;IAAc,SAAA;IAAQ,YAAA;cAC1C,oBAAC,OAAD,EAAA,UAAM,MAAM,YAAY,EAAO,CAAA;IACpB,CAAA;GAEf,oBAAC,iBAAD;IACE,SAAQ;IACR,KAAK,UAAU;IACf,KAAK,UAAU;IACf,OAAM;IACN,eAAe;IACf,OAAO;IACP,QAAQ;IACR,CAAA;GACE,EAAA,CAAA;EACS,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"licenseAttributes.mjs","names":[],"sources":["../../src/utils/licenseAttributes.ts"],"sourcesContent":["/**\n * Copyright (c) 2024-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 { getLicenseByAbbreviation, isCreativeCommonsLicense } from \"@ndla/licenses\";\n\nexport const licenseAttributes = (license: string | undefined, lang: string | undefined, url: string | undefined) => {\n const licenseAbbr = getLicenseByAbbreviation(license ? license : \"\", lang);\n\n const licenseProps = isCreativeCommonsLicense(licenseAbbr.rights)\n ? {\n \"xmlns:cc\": \"https://creativecommons.org/ns#\",\n \"xmlns:dct\": \"http://purl.org/dc/terms/\",\n about: url ?? undefined,\n }\n : {};\n\n return licenseProps;\n};\n"],"mappings":";;;;;;;;;AAUA,MAAa,qBAAqB,SAA6B,MAA0B,QAA4B;AAWnH,QARqB,yBAFD,yBAAyB,UAAU,UAAU,IAAI,
|
|
1
|
+
{"version":3,"file":"licenseAttributes.mjs","names":[],"sources":["../../src/utils/licenseAttributes.ts"],"sourcesContent":["/**\n * Copyright (c) 2024-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 { getLicenseByAbbreviation, isCreativeCommonsLicense } from \"@ndla/licenses\";\n\nexport const licenseAttributes = (license: string | undefined, lang: string | undefined, url: string | undefined) => {\n const licenseAbbr = getLicenseByAbbreviation(license ? license : \"\", lang);\n\n const licenseProps = isCreativeCommonsLicense(licenseAbbr.rights)\n ? {\n \"xmlns:cc\": \"https://creativecommons.org/ns#\",\n \"xmlns:dct\": \"http://purl.org/dc/terms/\",\n about: url ?? undefined,\n }\n : {};\n\n return licenseProps;\n};\n"],"mappings":";;;;;;;;;AAUA,MAAa,qBAAqB,SAA6B,MAA0B,QAA4B;AAWnH,QARqB,yBAFD,yBAAyB,UAAU,UAAU,IAAI,KAEZ,CAAC,OAAO,GAC7D;EACE,YAAY;EACZ,aAAa;EACb,OAAO,OAAO,KAAA;EACf,GACD,EAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BadgesContainer.js","names":[],"sources":["../../src/Article/BadgesContainer.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025-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\";\n\nexport const BadgesContainer = styled(\"div\", {\n base: {\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n flexWrap: \"wrap\",\n gap: \"xxsmall\",\n },\n});\n"],"mappings":";;;;;;;;;AAUA,MAAa,mBAAA,
|
|
1
|
+
{"version":3,"file":"BadgesContainer.js","names":[],"sources":["../../src/Article/BadgesContainer.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025-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\";\n\nexport const BadgesContainer = styled(\"div\", {\n base: {\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n flexWrap: \"wrap\",\n gap: \"xxsmall\",\n },\n});\n"],"mappings":";;;;;;;;;AAUA,MAAa,mBAAA,qCAAA,CAAA,QAAyB,OAAO,EAC3C,MAAM;CACJ,SAAS;CACT,eAAe;CACf,YAAY;CACZ,UAAU;CACV,KAAK;CACN,EACF,CAAC"}
|
|
@@ -9,7 +9,10 @@ const StyledSliderThumb = (0, _ndla_styled_system_jsx.styled)(_ndla_primitives.S
|
|
|
9
9
|
standard: {},
|
|
10
10
|
simple: {
|
|
11
11
|
marginBlockStart: "-4xsmall",
|
|
12
|
-
transitionProperty: "background, border-radius, width, height"
|
|
12
|
+
transitionProperty: "background, border-radius, width, height",
|
|
13
|
+
width: "4xsmall",
|
|
14
|
+
height: "4xsmall",
|
|
15
|
+
borderRadius: "sharp"
|
|
13
16
|
}
|
|
14
17
|
} } });
|
|
15
18
|
const StyledSliderTrack = (0, _ndla_styled_system_jsx.styled)(_ndla_primitives.SliderTrack, { variants: { variant: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioProgress.js","names":["SliderThumb","SliderTrack","SliderRoot","formatTime","SliderLabel","SliderControl","SliderRange","SliderHiddenInput"],"sources":["../../src/AudioPlayer/AudioProgress.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 SliderRoot,\n SliderLabel,\n SliderControl,\n SliderTrack,\n SliderRange,\n SliderThumb,\n SliderHiddenInput,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { useTranslation } from \"react-i18next\";\nimport { formatTime } from \"./audioUtils\";\n\ninterface Props {\n currentTime: number;\n duration: number;\n onValueChange: (details: SliderValueChangeDetails) => void;\n variant?: \"simple\" | \"standard\";\n}\n\nconst StyledSliderThumb = styled(SliderThumb, {\n variants: {\n variant: {\n standard: {},\n simple: {\n marginBlockStart: \"-4xsmall\",\n transitionProperty: \"background, border-radius, width, height\",\n },\n },\n },\n});\n\nconst StyledSliderTrack = styled(SliderTrack, {\n variants: {\n variant: {\n standard: {},\n simple: {\n marginBlockStart: \"-4xsmall\",\n background: \"unset\",\n },\n },\n },\n});\n\nconst StyledSliderRoot = styled(SliderRoot, {\n variants: {\n variant: {\n standard: {},\n simple: {\n position: \"relative\",\n marginBlockEnd: \"-xsmall\",\n },\n },\n },\n});\n\nexport const AudioProgress = ({ currentTime, duration, onValueChange, variant }: Props) => {\n const { t } = useTranslation();\n return (\n <StyledSliderRoot\n value={[currentTime]}\n defaultValue={[0]}\n step={1}\n max={duration}\n onValueChange={onValueChange}\n variant={variant}\n getAriaValueText={(value) =>\n t(\"audio.valueText\", {\n start: formatTime(Math.round(value.value)),\n end: formatTime(Math.round(duration)),\n })\n }\n >\n <SliderLabel srOnly>{t(\"audio.progressBar\")}</SliderLabel>\n <SliderControl>\n <StyledSliderTrack variant={variant}>\n <SliderRange />\n </StyledSliderTrack>\n <StyledSliderThumb index={0} variant={variant}>\n <SliderHiddenInput />\n </StyledSliderThumb>\n </SliderControl>\n </StyledSliderRoot>\n );\n};\n"],"mappings":";;;;;;;AA6BA,MAAM,qBAAA,GAAA,wBAAA,QAA2BA,iBAAAA,aAAa,EAC5C,UAAU,EACR,SAAS;CACP,UAAU,EAAE;CACZ,QAAQ;EACN,kBAAkB;EAClB,oBAAoB;
|
|
1
|
+
{"version":3,"file":"AudioProgress.js","names":["SliderThumb","SliderTrack","SliderRoot","formatTime","SliderLabel","SliderControl","SliderRange","SliderHiddenInput"],"sources":["../../src/AudioPlayer/AudioProgress.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 SliderRoot,\n SliderLabel,\n SliderControl,\n SliderTrack,\n SliderRange,\n SliderThumb,\n SliderHiddenInput,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { useTranslation } from \"react-i18next\";\nimport { formatTime } from \"./audioUtils\";\n\ninterface Props {\n currentTime: number;\n duration: number;\n onValueChange: (details: SliderValueChangeDetails) => void;\n variant?: \"simple\" | \"standard\";\n}\n\nconst StyledSliderThumb = styled(SliderThumb, {\n variants: {\n variant: {\n standard: {},\n simple: {\n marginBlockStart: \"-4xsmall\",\n transitionProperty: \"background, border-radius, width, height\",\n width: \"4xsmall\",\n height: \"4xsmall\",\n borderRadius: \"sharp\",\n },\n },\n },\n});\n\nconst StyledSliderTrack = styled(SliderTrack, {\n variants: {\n variant: {\n standard: {},\n simple: {\n marginBlockStart: \"-4xsmall\",\n background: \"unset\",\n },\n },\n },\n});\n\nconst StyledSliderRoot = styled(SliderRoot, {\n variants: {\n variant: {\n standard: {},\n simple: {\n position: \"relative\",\n marginBlockEnd: \"-xsmall\",\n },\n },\n },\n});\n\nexport const AudioProgress = ({ currentTime, duration, onValueChange, variant }: Props) => {\n const { t } = useTranslation();\n return (\n <StyledSliderRoot\n value={[currentTime]}\n defaultValue={[0]}\n step={1}\n max={duration}\n onValueChange={onValueChange}\n variant={variant}\n getAriaValueText={(value) =>\n t(\"audio.valueText\", {\n start: formatTime(Math.round(value.value)),\n end: formatTime(Math.round(duration)),\n })\n }\n >\n <SliderLabel srOnly>{t(\"audio.progressBar\")}</SliderLabel>\n <SliderControl>\n <StyledSliderTrack variant={variant}>\n <SliderRange />\n </StyledSliderTrack>\n <StyledSliderThumb index={0} variant={variant}>\n <SliderHiddenInput />\n </StyledSliderThumb>\n </SliderControl>\n </StyledSliderRoot>\n );\n};\n"],"mappings":";;;;;;;AA6BA,MAAM,qBAAA,GAAA,wBAAA,QAA2BA,iBAAAA,aAAa,EAC5C,UAAU,EACR,SAAS;CACP,UAAU,EAAE;CACZ,QAAQ;EACN,kBAAkB;EAClB,oBAAoB;EACpB,OAAO;EACP,QAAQ;EACR,cAAc;EACf;CACF,EACF,EACF,CAAC;AAEF,MAAM,qBAAA,GAAA,wBAAA,QAA2BC,iBAAAA,aAAa,EAC5C,UAAU,EACR,SAAS;CACP,UAAU,EAAE;CACZ,QAAQ;EACN,kBAAkB;EAClB,YAAY;EACb;CACF,EACF,EACF,CAAC;AAEF,MAAM,oBAAA,GAAA,wBAAA,QAA0BC,iBAAAA,YAAY,EAC1C,UAAU,EACR,SAAS;CACP,UAAU,EAAE;CACZ,QAAQ;EACN,UAAU;EACV,gBAAgB;EACjB;CACF,EACF,EACF,CAAC;AAEF,MAAa,iBAAiB,EAAE,aAAa,UAAU,eAAe,cAAqB;CACzF,MAAM,EAAE,OAAA,GAAA,cAAA,iBAAsB;AAC9B,QACE,iBAAA,GAAA,kBAAA,MAAC,kBAAD;EACE,OAAO,CAAC,YAAY;EACpB,cAAc,CAAC,EAAE;EACjB,MAAM;EACN,KAAK;EACU;EACN;EACT,mBAAmB,UACjB,EAAE,mBAAmB;GACnB,OAAOC,mBAAAA,WAAW,KAAK,MAAM,MAAM,MAAM,CAAC;GAC1C,KAAKA,mBAAAA,WAAW,KAAK,MAAM,SAAS,CAAC;GACtC,CAAC;YAXN,CAcE,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,aAAD;GAAa,QAAA;aAAQ,EAAE,oBAAoB;GAAe,CAAA,EAC1D,iBAAA,GAAA,kBAAA,MAACC,iBAAAA,eAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAC,mBAAD;GAA4B;aAC1B,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,aAAD,EAAe,CAAA;GACG,CAAA,EACpB,iBAAA,GAAA,kBAAA,KAAC,mBAAD;GAAmB,OAAO;GAAY;aACpC,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,mBAAD,EAAqB,CAAA;GACH,CAAA,CACN,EAAA,CAAA,CACC"}
|
|
@@ -1 +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,
|
|
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,CAcqB;EACxB;EACA,UAAA,GAAA,MAAA,mBAdgC,WAAW,MAAM,EAAE,EAAE,CAc9C;EACP,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,CASS;EACZ;EACA;EACA;EACA;EACA;EACA;EACD"}
|
|
@@ -1 +1 @@
|
|
|
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 {variant === \"standard\" && (\n <EmbedByline\n error={false}\n type={data.audioType === \"standard\" ? \"audio\" : \"podcast\"}\n copyright={embed.data.copyright}\n />\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,
|
|
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 {variant === \"standard\" && (\n <EmbedByline\n error={false}\n type={data.audioType === \"standard\" ? \"audio\" : \"podcast\"}\n copyright={embed.data.copyright}\n />\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,IAGpB;YAAjE,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,EACD,YAAY,cACX,iBAAA,GAAA,kBAAA,KAACC,oBAAAA,aAAD;GACE,OAAO;GACP,MAAM,KAAK,cAAc,aAAa,UAAU;GAChD,WAAW,MAAM,KAAK;GACtB,CAAA,CAES"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrightcoveEmbed.js","names":["Button","EmbedErrorPlaceholder","licenseAttributes","Figure","EmbedByline"],"sources":["../../src/Embed/BrightcoveEmbed.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 { Button, Figure } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { BrightcoveEmbedData, BrightcoveMetaData, BrightcoveVideoSource } from \"@ndla/types-embed\";\nimport parse from \"html-react-parser\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { EmbedByline } from \"../LicenseByline/EmbedByline\";\nimport { licenseAttributes } from \"../utils/licenseAttributes\";\nimport { EmbedErrorPlaceholder } from \"./EmbedErrorPlaceholder\";\nimport type { RenderContext } from \"./types\";\n\ninterface Props {\n embed: BrightcoveMetaData;\n renderContext?: RenderContext;\n lang?: string;\n}\n\nconst LinkedVideoButton = styled(Button, {\n base: {\n marginBlockStart: \"3xsmall\",\n },\n});\n\nconst BrightcoveIframe = styled(\"iframe\", {\n base: {\n border: 0,\n height: \"auto\",\n width: \"100%\",\n },\n});\n\nexport const makeIframeString = (url: string, width: string | number, height: string | number, title = \"\") => {\n const strippedWidth = typeof width === \"number\" ? width : width.replace(/\\s*px/, \"\");\n const strippedHeight = typeof height === \"number\" ? height : height.replace(/\\s*px/, \"\");\n const urlOrTitle = title || url;\n return `<iframe title=\"${urlOrTitle}\" aria-label=\"${urlOrTitle}\" src=\"${url}\" width=\"${strippedWidth}\" height=\"${strippedHeight}\" allowfullscreen scrolling=\"no\" style=\"border: none;\" loading=\"lazy\"></iframe>`;\n};\n\nexport const isNumeric = (value: any) => !Number.isNaN(value - Number.parseFloat(value));\n\nconst getIframeProps = (data: BrightcoveEmbedData, sources: BrightcoveVideoSource[]) => {\n const { account, videoid, player = \"default\" } = data;\n\n const source = sources.filter((s) => s.width && s.height).toSorted((a, b) => a!.height! - b.height!)[0];\n\n return {\n src: `https://players.brightcove.net/${account}/${player}_default/index.html?videoId=${videoid}`,\n height: source?.height ?? \"480\",\n width: source?.width ?? \"640\",\n };\n};\nexport const BrightcoveEmbed = ({ embed, renderContext = \"article\", lang }: Props) => {\n const [showOriginalVideo, setShowOriginalVideo] = useState(true);\n const { t } = useTranslation();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const { embedData } = embed;\n const fallbackTitle = `${t(\"embed.type.video\")}: ${embedData.videoid}`;\n const parsedDescription = useMemo(() => {\n if (embed.embedData.caption || renderContext === \"article\") {\n return embed.embedData.caption ? parse(embed.embedData.caption) : undefined;\n } else if (embed.status === \"success\" && embed.data.description) {\n return parse(embed.data.description);\n }\n }, [embed, renderContext]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (iframe) {\n const [width, height] = [parseInt(iframe.width), parseInt(iframe.height)];\n iframe.style.aspectRatio = `${width}/${height}`;\n iframe.width = \"\";\n iframe.height = \"\";\n }\n }, []);\n if (embed.status === \"error\") {\n return (\n <EmbedErrorPlaceholder type=\"video\">\n <BrightcoveIframe\n ref={iframeRef}\n title={embedData.alt || fallbackTitle}\n aria-label={embedData.alt || fallbackTitle}\n {...getIframeProps(embedData, [])}\n allow=\"fullscreen; encrypted-media\"\n />\n </EmbedErrorPlaceholder>\n );\n }\n const { data } = embed;\n\n const linkedVideoId = isNumeric(data.link?.text) ? data.link?.text : undefined;\n\n const originalVideoProps = getIframeProps(embedData, data.sources);\n const alternativeVideoProps = linkedVideoId\n ? getIframeProps({ ...embedData, videoid: linkedVideoId }, data.sources)\n : undefined;\n\n const licenseProps = licenseAttributes(data?.copyright?.license.license, lang, embedData.pageUrl);\n\n const title = data.name?.trim() ? `${t(\"embed.type.video\")}: ${data.name}` : fallbackTitle;\n\n return (\n <Figure data-embed-type=\"brightcove\" {...licenseProps}>\n <div className=\"brightcove-video\">\n <BrightcoveIframe\n ref={iframeRef}\n className=\"original\"\n title={title}\n aria-label={title}\n {...(alternativeVideoProps && !showOriginalVideo ? alternativeVideoProps : originalVideoProps)}\n allow=\"fullscreen; encrypted-media\"\n />\n </div>\n <EmbedByline type=\"video\" copyright={data.copyright!} description={parsedDescription}>\n <div>\n {!!linkedVideoId && (\n <LinkedVideoButton size=\"small\" variant=\"secondary\" onClick={() => setShowOriginalVideo((p) => !p)}>\n {t(`figure.button.${!showOriginalVideo ? \"original\" : \"alternative\"}`)}\n </LinkedVideoButton>\n )}\n </div>\n </EmbedByline>\n </Figure>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAyBA,MAAM,qBAAA,GAAA,wBAAA,QAA2BA,iBAAAA,QAAQ,EACvC,MAAM,EACJ,kBAAkB,WACnB,EACF,CAAC;AAEF,MAAM,oBAAA,GAAA,wBAAA,QAA0B,UAAU,EACxC,MAAM;CACJ,QAAQ;CACR,QAAQ;CACR,OAAO;CACR,EACF,CAAC;AASF,MAAa,aAAa,UAAe,CAAC,OAAO,MAAM,QAAQ,OAAO,WAAW,MAAM,CAAC;AAExF,MAAM,kBAAkB,MAA2B,YAAqC;
|
|
1
|
+
{"version":3,"file":"BrightcoveEmbed.js","names":["Button","EmbedErrorPlaceholder","licenseAttributes","Figure","EmbedByline"],"sources":["../../src/Embed/BrightcoveEmbed.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 { Button, Figure } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { BrightcoveEmbedData, BrightcoveMetaData, BrightcoveVideoSource } from \"@ndla/types-embed\";\nimport parse from \"html-react-parser\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { EmbedByline } from \"../LicenseByline/EmbedByline\";\nimport { licenseAttributes } from \"../utils/licenseAttributes\";\nimport { EmbedErrorPlaceholder } from \"./EmbedErrorPlaceholder\";\nimport type { RenderContext } from \"./types\";\n\ninterface Props {\n embed: BrightcoveMetaData;\n renderContext?: RenderContext;\n lang?: string;\n}\n\nconst LinkedVideoButton = styled(Button, {\n base: {\n marginBlockStart: \"3xsmall\",\n },\n});\n\nconst BrightcoveIframe = styled(\"iframe\", {\n base: {\n border: 0,\n height: \"auto\",\n width: \"100%\",\n },\n});\n\nexport const makeIframeString = (url: string, width: string | number, height: string | number, title = \"\") => {\n const strippedWidth = typeof width === \"number\" ? width : width.replace(/\\s*px/, \"\");\n const strippedHeight = typeof height === \"number\" ? height : height.replace(/\\s*px/, \"\");\n const urlOrTitle = title || url;\n return `<iframe title=\"${urlOrTitle}\" aria-label=\"${urlOrTitle}\" src=\"${url}\" width=\"${strippedWidth}\" height=\"${strippedHeight}\" allowfullscreen scrolling=\"no\" style=\"border: none;\" loading=\"lazy\"></iframe>`;\n};\n\nexport const isNumeric = (value: any) => !Number.isNaN(value - Number.parseFloat(value));\n\nconst getIframeProps = (data: BrightcoveEmbedData, sources: BrightcoveVideoSource[]) => {\n // oxlint-disable-next-line typescript/no-useless-default-assignment\n const { account, videoid, player = \"default\" } = data;\n\n const source = sources.filter((s) => s.width && s.height).toSorted((a, b) => a!.height! - b.height!)[0];\n\n return {\n src: `https://players.brightcove.net/${account}/${player}_default/index.html?videoId=${videoid}`,\n height: source?.height ?? \"480\",\n width: source?.width ?? \"640\",\n };\n};\nexport const BrightcoveEmbed = ({ embed, renderContext = \"article\", lang }: Props) => {\n const [showOriginalVideo, setShowOriginalVideo] = useState(true);\n const { t } = useTranslation();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const { embedData } = embed;\n const fallbackTitle = `${t(\"embed.type.video\")}: ${embedData.videoid}`;\n const parsedDescription = useMemo(() => {\n if (embed.embedData.caption || renderContext === \"article\") {\n return embed.embedData.caption ? parse(embed.embedData.caption) : undefined;\n } else if (embed.status === \"success\" && embed.data.description) {\n return parse(embed.data.description);\n }\n }, [embed, renderContext]);\n\n useEffect(() => {\n const iframe = iframeRef.current;\n if (iframe) {\n const [width, height] = [parseInt(iframe.width), parseInt(iframe.height)];\n iframe.style.aspectRatio = `${width}/${height}`;\n iframe.width = \"\";\n iframe.height = \"\";\n }\n }, []);\n if (embed.status === \"error\") {\n return (\n <EmbedErrorPlaceholder type=\"video\">\n <BrightcoveIframe\n ref={iframeRef}\n title={embedData.alt || fallbackTitle}\n aria-label={embedData.alt || fallbackTitle}\n {...getIframeProps(embedData, [])}\n allow=\"fullscreen; encrypted-media\"\n />\n </EmbedErrorPlaceholder>\n );\n }\n const { data } = embed;\n\n const linkedVideoId = isNumeric(data.link?.text) ? data.link?.text : undefined;\n\n const originalVideoProps = getIframeProps(embedData, data.sources);\n const alternativeVideoProps = linkedVideoId\n ? getIframeProps({ ...embedData, videoid: linkedVideoId }, data.sources)\n : undefined;\n\n const licenseProps = licenseAttributes(data?.copyright?.license.license, lang, embedData.pageUrl);\n\n const title = data.name?.trim() ? `${t(\"embed.type.video\")}: ${data.name}` : fallbackTitle;\n\n return (\n <Figure data-embed-type=\"brightcove\" {...licenseProps}>\n <div className=\"brightcove-video\">\n <BrightcoveIframe\n ref={iframeRef}\n className=\"original\"\n title={title}\n aria-label={title}\n {...(alternativeVideoProps && !showOriginalVideo ? alternativeVideoProps : originalVideoProps)}\n allow=\"fullscreen; encrypted-media\"\n />\n </div>\n <EmbedByline type=\"video\" copyright={data.copyright!} description={parsedDescription}>\n <div>\n {!!linkedVideoId && (\n <LinkedVideoButton size=\"small\" variant=\"secondary\" onClick={() => setShowOriginalVideo((p) => !p)}>\n {t(`figure.button.${!showOriginalVideo ? \"original\" : \"alternative\"}`)}\n </LinkedVideoButton>\n )}\n </div>\n </EmbedByline>\n </Figure>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConceptInlineTriggerButton.js","names":["InlineTriggerButton"],"sources":["../../src/Embed/ConceptInlineTriggerButton.tsx"],"sourcesContent":["/**\n * Copyright (c) 2024-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 { InlineTriggerButton } from \"./InlineTriggerButton\";\n\nexport const ConceptInlineTriggerButton = styled(InlineTriggerButton, {\n base: {\n position: \"relative\",\n overflow: \"visible\",\n borderBottom: \"1px solid\",\n borderStyle: \"dashed\",\n borderColor: \"stroke.hover\",\n paddingBlockStart: \"5xsmall\",\n width: \"fit-content\",\n cursor: \"pointer\",\n _hover: {\n borderColor: \"text.link\",\n background: \"surface.actionSubtle.hover\",\n },\n _active: {\n borderColor: \"text.link\",\n background: \"surface.actionSubtle.active\",\n },\n // The global focus ring forces the border-radius to be xsmall, causing the dashed border to be cut off. This is a workaround.\n _focusVisible: {\n outline: \"none\",\n borderRadius: \"0\",\n _after: {\n content: '\"\"',\n position: \"absolute\",\n inset: \"0\",\n outline: \"3px\",\n borderRadius: \"xsmall\",\n outlineColor: \"stroke.default\",\n outlineOffset: \"3px\",\n outlineStyle: \"solid\",\n },\n },\n },\n});\n"],"mappings":";;;;;;;;;;AAWA,MAAa,8BAAA,
|
|
1
|
+
{"version":3,"file":"ConceptInlineTriggerButton.js","names":["InlineTriggerButton"],"sources":["../../src/Embed/ConceptInlineTriggerButton.tsx"],"sourcesContent":["/**\n * Copyright (c) 2024-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 { InlineTriggerButton } from \"./InlineTriggerButton\";\n\nexport const ConceptInlineTriggerButton = styled(InlineTriggerButton, {\n base: {\n position: \"relative\",\n overflow: \"visible\",\n borderBottom: \"1px solid\",\n borderStyle: \"dashed\",\n borderColor: \"stroke.hover\",\n paddingBlockStart: \"5xsmall\",\n width: \"fit-content\",\n cursor: \"pointer\",\n _hover: {\n borderColor: \"text.link\",\n background: \"surface.actionSubtle.hover\",\n },\n _active: {\n borderColor: \"text.link\",\n background: \"surface.actionSubtle.active\",\n },\n // The global focus ring forces the border-radius to be xsmall, causing the dashed border to be cut off. This is a workaround.\n _focusVisible: {\n outline: \"none\",\n borderRadius: \"0\",\n _after: {\n content: '\"\"',\n position: \"absolute\",\n inset: \"0\",\n outline: \"3px\",\n borderRadius: \"xsmall\",\n outlineColor: \"stroke.default\",\n outlineOffset: \"3px\",\n outlineStyle: \"solid\",\n },\n },\n },\n});\n"],"mappings":";;;;;;;;;;AAWA,MAAa,8BAAA,qCAAA,CAAA,QAAoCA,4BAAAA,qBAAqB,EACpE,MAAM;CACJ,UAAU;CACV,UAAU;CACV,cAAc;CACd,aAAa;CACb,aAAa;CACb,mBAAmB;CACnB,OAAO;CACP,QAAQ;CACR,QAAQ;EACN,aAAa;EACb,YAAY;EACb;CACD,SAAS;EACP,aAAa;EACb,YAAY;EACb;CAED,eAAe;EACb,SAAS;EACT,cAAc;EACd,QAAQ;GACN,SAAS;GACT,UAAU;GACV,OAAO;GACP,SAAS;GACT,cAAc;GACd,cAAc;GACd,eAAe;GACf,cAAc;GACf;EACF;CACF,EACF,CAAC"}
|
|
@@ -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,aAKrB,QACE,iBAAA,GAAA,kBAAA,KAACD,iBAAAA,QAAD;EAAQ,mBAAgB;YACtB,iBAAA,GAAA,kBAAA,KAACE,oBAAAA,aAAD;GACE,
|
|
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,OAAO;IANX,KAAK,KAAK,aAAa,MAAM;IAC7B,KAAK,UAAU,QAAQ,KAAA,IAAY,UAAU,MAAO,KAAK,aAAa,SAAS,WAAW;IAK1E;GACZ,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"}
|
|
@@ -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;AAE/E,SACE,iBAAA,GAAA,kBAAA,KAAC,cAAD;GAAc,mBAAgB;aAC5B,iBAAA,GAAA,kBAAA,KAACC,oBAAAA,aAAD;IACE,
|
|
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,OAAO;KAJG,KAAK,aAAa,MAAM;KAAU,KAAK,OAAO;KAI5C;IACZ,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
|
@@ -1 +1 @@
|
|
|
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"}
|
|
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 paddingBottom: \"xxlarge\",\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,eAAe;EACf,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.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Gloss.js","names":["AccordionItemContent","AccordionItem","AccordionRoot","Text","SpeechControl","AccordionItemTrigger","IconButton","AccordionItemIndicator","ArrowDownShortLine","GlossExample"],"sources":["../../src/Gloss/Gloss.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 { AccordionItemTrigger } from \"@ark-ui/react\";\nimport { ArrowDownShortLine } from \"@ndla/icons\";\nimport {\n AccordionItem,\n AccordionItemContent,\n AccordionItemIndicator,\n AccordionRoot,\n IconButton,\n Text,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { StyledVariantProps } from \"@ndla/styled-system/types\";\nimport type { ConceptTitleDTO, GlossDataDTO, GlossExampleDTO } from \"@ndla/types-backend/concept-api\";\nimport parse from \"html-react-parser\";\nimport { useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { SpeechControl } from \"../AudioPlayer/SpeechControl\";\nimport { GlossExample } from \"./GlossExample\";\n\n// TODO: Figure out padding between bordered and simple variant.\n// The design says that the content above the accordion content should have enough padding to align with the accordion content.\n// When a gloss is bordered there's way too much padding.\n\nconst getFilteredExamples = (\n glossData: GlossDataDTO | undefined,\n exampleIds: string | undefined,\n exampleLangs: string | undefined,\n): GlossExampleDTO[][] => {\n if (exampleIds !== undefined || exampleLangs !== undefined) {\n const exampleIdsList = exampleIds?.toString()?.split(\",\") ?? [];\n const exampleLangsList = exampleLangs?.split(\",\") ?? [];\n\n const filteredExamples =\n glossData?.examples?.map((examples, i) => {\n if (exampleIdsList.includes(i.toString())) {\n return examples.filter((e) => exampleLangsList.includes(e.language));\n }\n return [];\n }) ?? [];\n const examplesWithoutEmpty = filteredExamples.filter((el) => !!el.length);\n return examplesWithoutEmpty;\n }\n return glossData?.examples ?? [];\n};\n\nconst Container = styled(\"div\", {\n base: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n },\n});\n\nconst TextWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n gap: \"small\",\n },\n});\n\nconst StyledAccordionItemContent = styled(AccordionItemContent, {\n base: {\n paddingInline: \"0\",\n },\n});\n\nconst StyledContainer = styled(Container, {\n base: {\n marginBlockStart: \"3xsmall\",\n },\n});\n\nconst StyledAccordionItem = styled(AccordionItem, {\n base: {\n paddingBlock: \"small\",\n paddingInline: \"medium\",\n },\n defaultVariants: {\n variant: \"simple\",\n },\n variants: {\n variant: {\n simple: {},\n bordered: {\n border: \"1px solid\",\n borderColor: \"stroke.subtle\",\n borderRadius: \"xsmall\",\n },\n },\n },\n});\n\ntype GlossVariantProps = StyledVariantProps<typeof StyledAccordionItem>;\n\nexport interface Props {\n title: ConceptTitleDTO;\n glossData?: GlossDataDTO;\n audio?: {\n title: string;\n src?: string;\n };\n exampleIds?: string;\n exampleLangs?: string;\n}\n\nexport const Gloss = ({ title, glossData, audio, exampleIds, exampleLangs, variant }: Props & GlossVariantProps) => {\n const { t } = useTranslation();\n\n const parsedTitle = useMemo(() => parse(title.htmlTitle), [title.htmlTitle]);\n\n const filteredExamples = useMemo(\n () => getFilteredExamples(glossData, exampleIds, exampleLangs),\n [exampleIds, exampleLangs, glossData],\n );\n\n if (!glossData) return null;\n\n return (\n <AccordionRoot multiple variant=\"clean\">\n <StyledAccordionItem value=\"gloss\" variant={variant}>\n <Container>\n <TextWrapper>\n <Text textStyle=\"label.medium\" fontWeight=\"bold\" asChild consumeCss lang={glossData.originalLanguage}>\n <span>{glossData.gloss}</span>\n </Text>\n {!!glossData.transcriptions.traditional && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n key={t(\"gloss.transcriptions.traditional\")}\n aria-label={t(\"gloss.transcriptions.traditional\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.traditional}\n </span>\n </Text>\n )}\n {!!glossData.transcriptions.pinyin && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n data-pinyin=\"\"\n key={t(\"gloss.transcriptions.pinyin\")}\n aria-label={t(\"gloss.transcriptions.pinyin\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.pinyin}\n </span>\n </Text>\n )}\n {!!glossData.wordClass && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span aria-label={t(\"gloss.wordClass\")}>\n {glossData.wordClass.map((wc) => t(`wordClass.${wc}`).toLowerCase()).join(\" / \")}\n </span>\n </Text>\n )}\n </TextWrapper>\n {!!audio?.src && <SpeechControl src={audio.src} title={audio.title} />}\n </Container>\n <StyledContainer>\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span lang={title.language}>{parsedTitle}</span>\n </Text>\n {!!filteredExamples.length && (\n <AccordionItemTrigger asChild>\n <IconButton variant=\"tertiary\" aria-label={t(\"gloss.showExamples\")} title={t(\"gloss.showExamples\")}>\n <AccordionItemIndicator asChild>\n <ArrowDownShortLine size=\"medium\" />\n </AccordionItemIndicator>\n </IconButton>\n </AccordionItemTrigger>\n )}\n </StyledContainer>\n <StyledAccordionItemContent>\n {filteredExamples.map((examples, index) => (\n <GlossExample\n key={`gloss-example-${index}`}\n examples={examples}\n originalLanguage={glossData.originalLanguage}\n />\n ))}\n </StyledAccordionItemContent>\n </StyledAccordionItem>\n </AccordionRoot>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA+BA,MAAM,uBACJ,WACA,YACA,iBACwB;AACxB,KAAI,eAAe,KAAA,KAAa,iBAAiB,KAAA,GAAW;EAC1D,MAAM,iBAAiB,YAAY,UAAU,EAAE,MAAM,IAAI,IAAI,EAAE;EAC/D,MAAM,mBAAmB,cAAc,MAAM,IAAI,IAAI,EAAE;AAUvD,UAPE,WAAW,UAAU,KAAK,UAAU,MAAM;AACxC,OAAI,eAAe,SAAS,EAAE,UAAU,CAAC,CACvC,QAAO,SAAS,QAAQ,MAAM,iBAAiB,SAAS,EAAE,SAAS,CAAC;AAEtE,UAAO,EAAE;IACT,IAAI,EAAE,EACoC,QAAQ,OAAO,CAAC,CAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"Gloss.js","names":["AccordionItemContent","AccordionItem","AccordionRoot","Text","SpeechControl","AccordionItemTrigger","IconButton","AccordionItemIndicator","ArrowDownShortLine","GlossExample"],"sources":["../../src/Gloss/Gloss.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 { AccordionItemTrigger } from \"@ark-ui/react\";\nimport { ArrowDownShortLine } from \"@ndla/icons\";\nimport {\n AccordionItem,\n AccordionItemContent,\n AccordionItemIndicator,\n AccordionRoot,\n IconButton,\n Text,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { StyledVariantProps } from \"@ndla/styled-system/types\";\nimport type { ConceptTitleDTO, GlossDataDTO, GlossExampleDTO } from \"@ndla/types-backend/concept-api\";\nimport parse from \"html-react-parser\";\nimport { useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { SpeechControl } from \"../AudioPlayer/SpeechControl\";\nimport { GlossExample } from \"./GlossExample\";\n\n// TODO: Figure out padding between bordered and simple variant.\n// The design says that the content above the accordion content should have enough padding to align with the accordion content.\n// When a gloss is bordered there's way too much padding.\n\nconst getFilteredExamples = (\n glossData: GlossDataDTO | undefined,\n exampleIds: string | undefined,\n exampleLangs: string | undefined,\n): GlossExampleDTO[][] => {\n if (exampleIds !== undefined || exampleLangs !== undefined) {\n const exampleIdsList = exampleIds?.toString()?.split(\",\") ?? [];\n const exampleLangsList = exampleLangs?.split(\",\") ?? [];\n\n const filteredExamples =\n glossData?.examples?.map((examples, i) => {\n if (exampleIdsList.includes(i.toString())) {\n return examples.filter((e) => exampleLangsList.includes(e.language));\n }\n return [];\n }) ?? [];\n const examplesWithoutEmpty = filteredExamples.filter((el) => !!el.length);\n return examplesWithoutEmpty;\n }\n return glossData?.examples ?? [];\n};\n\nconst Container = styled(\"div\", {\n base: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n },\n});\n\nconst TextWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n gap: \"small\",\n },\n});\n\nconst StyledAccordionItemContent = styled(AccordionItemContent, {\n base: {\n paddingInline: \"0\",\n },\n});\n\nconst StyledContainer = styled(Container, {\n base: {\n marginBlockStart: \"3xsmall\",\n },\n});\n\nconst StyledAccordionItem = styled(AccordionItem, {\n base: {\n paddingBlock: \"small\",\n paddingInline: \"medium\",\n },\n defaultVariants: {\n variant: \"simple\",\n },\n variants: {\n variant: {\n simple: {},\n bordered: {\n border: \"1px solid\",\n borderColor: \"stroke.subtle\",\n borderRadius: \"xsmall\",\n },\n },\n },\n});\n\ntype GlossVariantProps = StyledVariantProps<typeof StyledAccordionItem>;\n\nexport interface Props {\n title: ConceptTitleDTO;\n glossData?: GlossDataDTO;\n audio?: {\n title: string;\n src?: string;\n };\n exampleIds?: string;\n exampleLangs?: string;\n}\n\nexport const Gloss = ({ title, glossData, audio, exampleIds, exampleLangs, variant }: Props & GlossVariantProps) => {\n const { t } = useTranslation();\n\n const parsedTitle = useMemo(() => parse(title.htmlTitle), [title.htmlTitle]);\n\n const filteredExamples = useMemo(\n () => getFilteredExamples(glossData, exampleIds, exampleLangs),\n [exampleIds, exampleLangs, glossData],\n );\n\n if (!glossData) return null;\n\n return (\n <AccordionRoot multiple variant=\"clean\">\n <StyledAccordionItem value=\"gloss\" variant={variant}>\n <Container>\n <TextWrapper>\n <Text textStyle=\"label.medium\" fontWeight=\"bold\" asChild consumeCss lang={glossData.originalLanguage}>\n <span>{glossData.gloss}</span>\n </Text>\n {!!glossData.transcriptions.traditional && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n key={t(\"gloss.transcriptions.traditional\")}\n aria-label={t(\"gloss.transcriptions.traditional\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.traditional}\n </span>\n </Text>\n )}\n {!!glossData.transcriptions.pinyin && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n data-pinyin=\"\"\n key={t(\"gloss.transcriptions.pinyin\")}\n aria-label={t(\"gloss.transcriptions.pinyin\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.pinyin}\n </span>\n </Text>\n )}\n {!!glossData.wordClass && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span aria-label={t(\"gloss.wordClass\")}>\n {glossData.wordClass.map((wc) => t(`wordClass.${wc}`).toLowerCase()).join(\" / \")}\n </span>\n </Text>\n )}\n </TextWrapper>\n {!!audio?.src && <SpeechControl src={audio.src} title={audio.title} />}\n </Container>\n <StyledContainer>\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span lang={title.language}>{parsedTitle}</span>\n </Text>\n {!!filteredExamples.length && (\n <AccordionItemTrigger asChild>\n <IconButton variant=\"tertiary\" aria-label={t(\"gloss.showExamples\")} title={t(\"gloss.showExamples\")}>\n <AccordionItemIndicator asChild>\n <ArrowDownShortLine size=\"medium\" />\n </AccordionItemIndicator>\n </IconButton>\n </AccordionItemTrigger>\n )}\n </StyledContainer>\n <StyledAccordionItemContent>\n {filteredExamples.map((examples, index) => (\n <GlossExample\n key={`gloss-example-${index}`}\n examples={examples}\n originalLanguage={glossData.originalLanguage}\n />\n ))}\n </StyledAccordionItemContent>\n </StyledAccordionItem>\n </AccordionRoot>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA+BA,MAAM,uBACJ,WACA,YACA,iBACwB;AACxB,KAAI,eAAe,KAAA,KAAa,iBAAiB,KAAA,GAAW;EAC1D,MAAM,iBAAiB,YAAY,UAAU,EAAE,MAAM,IAAI,IAAI,EAAE;EAC/D,MAAM,mBAAmB,cAAc,MAAM,IAAI,IAAI,EAAE;AAUvD,UAPE,WAAW,UAAU,KAAK,UAAU,MAAM;AACxC,OAAI,eAAe,SAAS,EAAE,UAAU,CAAC,CACvC,QAAO,SAAS,QAAQ,MAAM,iBAAiB,SAAS,EAAE,SAAS,CAAC;AAEtE,UAAO,EAAE;IACT,IAAI,EAAE,EACoC,QAAQ,OAAO,CAAC,CAAC,GAAG,OACvC;;AAE7B,QAAO,WAAW,YAAY,EAAE;;AAGlC,MAAM,aAAA,GAAA,wBAAA,QAAmB,OAAO,EAC9B,MAAM;CACJ,SAAS;CACT,YAAY;CACZ,gBAAgB;CACjB,EACF,CAAC;AAEF,MAAM,eAAA,GAAA,wBAAA,QAAqB,OAAO,EAChC,MAAM;CACJ,SAAS;CACT,KAAK;CACN,EACF,CAAC;AAEF,MAAM,8BAAA,GAAA,wBAAA,QAAoCA,iBAAAA,sBAAsB,EAC9D,MAAM,EACJ,eAAe,KAChB,EACF,CAAC;AAEF,MAAM,mBAAA,GAAA,wBAAA,QAAyB,WAAW,EACxC,MAAM,EACJ,kBAAkB,WACnB,EACF,CAAC;AAEF,MAAM,uBAAA,GAAA,wBAAA,QAA6BC,iBAAAA,eAAe;CAChD,MAAM;EACJ,cAAc;EACd,eAAe;EAChB;CACD,iBAAiB,EACf,SAAS,UACV;CACD,UAAU,EACR,SAAS;EACP,QAAQ,EAAE;EACV,UAAU;GACR,QAAQ;GACR,aAAa;GACb,cAAc;GACf;EACF,EACF;CACF,CAAC;AAeF,MAAa,SAAS,EAAE,OAAO,WAAW,OAAO,YAAY,cAAc,cAAyC;CAClH,MAAM,EAAE,OAAA,GAAA,cAAA,iBAAsB;CAE9B,MAAM,eAAA,GAAA,MAAA,gBAAA,GAAA,kBAAA,SAAkC,MAAM,UAAU,EAAE,CAAC,MAAM,UAAU,CAAC;CAE5E,MAAM,oBAAA,GAAA,MAAA,eACE,oBAAoB,WAAW,YAAY,aAAa,EAC9D;EAAC;EAAY;EAAc;EAAU,CACtC;AAED,KAAI,CAAC,UAAW,QAAO;AAEvB,QACE,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,eAAD;EAAe,UAAA;EAAS,SAAQ;YAC9B,iBAAA,GAAA,kBAAA,MAAC,qBAAD;GAAqB,OAAM;GAAiB;aAA5C;IACE,iBAAA,GAAA,kBAAA,MAAC,WAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,MAAC,aAAD,EAAA,UAAA;KACE,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,MAAD;MAAM,WAAU;MAAe,YAAW;MAAO,SAAA;MAAQ,YAAA;MAAW,MAAM,UAAU;gBAClF,iBAAA,GAAA,kBAAA,KAAC,QAAD,EAAA,UAAO,UAAU,OAAa,CAAA;MACzB,CAAA;KACN,CAAC,CAAC,UAAU,eAAe,eAC1B,iBAAA,GAAA,kBAAA,KAACA,iBAAAA,MAAD;MAAM,WAAU;MAAe,SAAA;MAAQ,YAAA;gBACrC,iBAAA,GAAA,kBAAA,KAAC,QAAD;OAEE,cAAY,EAAE,mCAAmC;OACjD,MAAM,UAAU;iBAEf,UAAU,eAAe;OACrB,EALA,EAAE,mCAAmC,CAKrC;MACF,CAAA;KAER,CAAC,CAAC,UAAU,eAAe,UAC1B,iBAAA,GAAA,kBAAA,KAACA,iBAAAA,MAAD;MAAM,WAAU;MAAe,SAAA;MAAQ,YAAA;gBACrC,iBAAA,GAAA,kBAAA,KAAC,QAAD;OACE,eAAY;OAEZ,cAAY,EAAE,8BAA8B;OAC5C,MAAM,UAAU;iBAEf,UAAU,eAAe;OACrB,EALA,EAAE,8BAA8B,CAKhC;MACF,CAAA;KAER,CAAC,CAAC,UAAU,aACX,iBAAA,GAAA,kBAAA,KAACA,iBAAAA,MAAD;MAAM,WAAU;MAAe,SAAA;MAAQ,YAAA;gBACrC,iBAAA,GAAA,kBAAA,KAAC,QAAD;OAAM,cAAY,EAAE,kBAAkB;iBACnC,UAAU,UAAU,KAAK,OAAO,EAAE,aAAa,KAAK,CAAC,aAAa,CAAC,CAAC,KAAK,MAAM;OAC3E,CAAA;MACF,CAAA;KAEG,EAAA,CAAA,EACb,CAAC,CAAC,OAAO,OAAO,iBAAA,GAAA,kBAAA,KAACC,sBAAAA,eAAD;KAAe,KAAK,MAAM;KAAK,OAAO,MAAM;KAAS,CAAA,CAC5D,EAAA,CAAA;IACZ,iBAAA,GAAA,kBAAA,MAAC,iBAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAACD,iBAAAA,MAAD;KAAM,WAAU;KAAe,SAAA;KAAQ,YAAA;eACrC,iBAAA,GAAA,kBAAA,KAAC,QAAD;MAAM,MAAM,MAAM;gBAAW;MAAmB,CAAA;KAC3C,CAAA,EACN,CAAC,CAAC,iBAAiB,UAClB,iBAAA,GAAA,kBAAA,KAACE,cAAAA,sBAAD;KAAsB,SAAA;eACpB,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,YAAD;MAAY,SAAQ;MAAW,cAAY,EAAE,qBAAqB;MAAE,OAAO,EAAE,qBAAqB;gBAChG,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,wBAAD;OAAwB,SAAA;iBACtB,iBAAA,GAAA,kBAAA,KAACC,YAAAA,oBAAD,EAAoB,MAAK,UAAW,CAAA;OACb,CAAA;MACd,CAAA;KACQ,CAAA,CAET,EAAA,CAAA;IAClB,iBAAA,GAAA,kBAAA,KAAC,4BAAD,EAAA,UACG,iBAAiB,KAAK,UAAU,UAC/B,iBAAA,GAAA,kBAAA,KAACC,qBAAAA,cAAD;KAEY;KACV,kBAAkB,UAAU;KAC5B,EAHK,iBAAiB,QAGtB,CACF,EACyB,CAAA;IACT;;EACR,CAAA"}
|
|
@@ -111,6 +111,7 @@ const LicenseDescription = ({ children, isOpen, setIsOpen }) => {
|
|
|
111
111
|
const LicenseContainerContent = ({ children, copyright, type }) => {
|
|
112
112
|
const { t, i18n } = (0, react_i18next.useTranslation)();
|
|
113
113
|
const license = copyright ? (0, _ndla_licenses.getLicenseByAbbreviation)(copyright.license?.license ?? "", i18n.language) : void 0;
|
|
114
|
+
const shouldShowLicense = !!license && !license.rights.includes(_ndla_licenses.rights.NA);
|
|
114
115
|
const captionAuthors = [
|
|
115
116
|
copyright?.creators,
|
|
116
117
|
copyright?.rightsholders,
|
|
@@ -121,7 +122,7 @@ const LicenseContainerContent = ({ children, copyright, type }) => {
|
|
|
121
122
|
children,
|
|
122
123
|
` ${t(`embed.type.${type}`)}${captionAuthors.length ? ": " : ""}`,
|
|
123
124
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: captionAuthors.map((author) => author.name).join(", ") }),
|
|
124
|
-
|
|
125
|
+
shouldShowLicense ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" / ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_LicenseLink.LicenseLink, {
|
|
125
126
|
license,
|
|
126
127
|
hideLink: !isOpen && !!children
|
|
127
128
|
})] }) : null
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmbedByline.js","names":["Text","AlertLine","Button","LicenseLink"],"sources":["../../src/LicenseByline/EmbedByline.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 { AlertLine } from \"@ndla/icons\";\nimport { getLicenseByAbbreviation } from \"@ndla/licenses\";\nimport { Button, Text } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { CopyrightDTO as ArticleCopyright } from \"@ndla/types-backend/article-api\";\nimport type { CopyrightDTO as AudioCopyright } from \"@ndla/types-backend/audio-api\";\nimport type { DraftCopyrightDTO as ConceptCopyright } from \"@ndla/types-backend/concept-api\";\nimport type { CopyrightDTO as ImageCopyright } from \"@ndla/types-backend/image-api\";\nimport type { BrightcoveCopyright } from \"@ndla/types-embed\";\nimport { type Dispatch, type ReactNode, type SetStateAction, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { LicenseLink } from \"./LicenseLink\";\n\ninterface BaseProps {\n description?: ReactNode;\n children?: ReactNode;\n visibleAlt?: string;\n error?: true | false;\n hideDescription?: boolean;\n hideCopyright?: boolean;\n}\n\nexport interface EmbedBylineErrorProps extends BaseProps {\n type: EmbedBylineTypeProps[\"type\"] | \"h5p\" | \"external\" | \"code\";\n error: true;\n}\n\ninterface ImageProps extends BaseProps {\n type: \"image\";\n copyright: ImageCopyright | undefined;\n}\n\ninterface BrightcoveProps extends BaseProps {\n type: \"video\";\n copyright: BrightcoveCopyright | undefined;\n}\n\ninterface AudioProps extends BaseProps {\n type: \"audio\";\n copyright: AudioCopyright | undefined;\n}\n\ninterface PodcastProps extends BaseProps {\n type: \"podcast\";\n copyright: AudioCopyright | undefined;\n}\n\ninterface ConceptProps extends BaseProps {\n type: \"concept\" | \"gloss\";\n copyright: ConceptCopyright | undefined;\n}\n\ninterface CopyrightProps extends BaseProps {\n type: \"copyright\";\n copyright: ArticleCopyright | undefined;\n}\n\nexport type EmbedBylineTypeProps =\n | ImageProps\n | BrightcoveProps\n | AudioProps\n | PodcastProps\n | ConceptProps\n | CopyrightProps;\n\ntype Props = EmbedBylineTypeProps | EmbedBylineErrorProps;\n\nconst BylineWrapper = styled(\"figcaption\", {\n base: {\n display: \"flex\",\n flexDirection: \"column\",\n paddingBlock: \"xsmall\",\n textStyle: \"label.medium\",\n color: \"text.subtle\",\n },\n});\n\nconst ErrorBylineWrapper = styled(BylineWrapper, {\n base: {\n border: \"1px solid\",\n borderColor: \"stroke.error\",\n borderRadius: \"xsmall\",\n background: \"surface.dangerSubtle\",\n paddingInline: \"medium\",\n paddingBlock: \"medium\",\n },\n});\n\nconst StyledText = styled(Text, {\n base: {\n fontStyle: \"italic\",\n },\n});\n\nconst ContentWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n gap: \"xsmall\",\n alignItems: \"center\",\n textStyle: \"label.medium\",\n },\n});\n\nconst BaseDescription = styled(\"div\", {\n base: {\n display: \"inline-flex\",\n whiteSpace: \"pre-wrap\",\n },\n});\n\nexport const EmbedByline = ({ type, description, children, visibleAlt, hideCopyright, ...props }: Props) => {\n const { t } = useTranslation();\n\n if (props.error) {\n const typeString = type === \"h5p\" ? \"H5P\" : t(`embed.type.${type}`).toLowerCase();\n return (\n <ErrorBylineWrapper>\n <ContentWrapper>\n <AlertLine />\n <BaseDescription>\n <span>{t(\"embed.embedError\", { type: typeString })}</span>\n </BaseDescription>\n </ContentWrapper>\n </ErrorBylineWrapper>\n );\n }\n\n const { copyright } = props;\n const hideByline = hideCopyright && !description;\n\n return (\n <>\n {!hideByline && (\n <BylineWrapper>\n <div>\n {!!hideCopyright && description}\n {!hideCopyright && (\n <LicenseContainerContent type={type} copyright={copyright}>\n {description}\n </LicenseContainerContent>\n )}\n {children}\n </div>\n </BylineWrapper>\n )}\n {visibleAlt ? (\n <StyledText color=\"text.subtle\" textStyle=\"label.medium\" asChild consumeCss>\n <span>{`Alt: ${visibleAlt}`}</span>\n </StyledText>\n ) : null}\n </>\n );\n};\n\ninterface LicenseContainerProps {\n children?: ReactNode;\n copyright: EmbedBylineTypeProps[\"copyright\"];\n type: Props[\"type\"];\n}\n\nconst StyledDescription = styled(BaseDescription, {\n base: {\n mobileWideDown: {\n display: \"grid\",\n gridTemplateColumns: \"1fr auto\",\n alignItems: \"center\",\n overflow: \"hidden\",\n _open: {\n display: \"inline\",\n },\n },\n },\n});\n\nconst TextContent = styled(\"span\", {\n base: {\n mobileWideDown: {\n whiteSpace: \"nowrap\",\n maxHeight: \"large\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n transitionProperty: \"max-height\",\n transitionDuration: \"slow\",\n transitionTimingFunction: \"ease-in\",\n marginInlineEnd: \"4xsmall\",\n _open: {\n whiteSpace: \"pre-wrap\",\n maxHeight: \"none\",\n },\n },\n },\n});\n\nconst StyledButton = styled(Button, {\n base: {\n mobileWide: {\n display: \"none\",\n },\n _print: {\n display: \"none\",\n },\n },\n});\n\ninterface LicenseDescriptionProps {\n children?: ReactNode;\n isOpen: boolean;\n setIsOpen: Dispatch<SetStateAction<boolean>>;\n}\n\nconst LicenseDescription = ({ children, isOpen, setIsOpen }: LicenseDescriptionProps) => {\n const open = isOpen ? { \"data-open\": \"\" } : {};\n const { t } = useTranslation();\n\n const handleToggle = () => {\n setIsOpen(!isOpen);\n };\n\n return (\n <ContentWrapper>\n <StyledDescription {...open}>\n <TextContent {...open}>{children}</TextContent>\n <StyledButton variant=\"link\" size=\"small\" onClick={handleToggle}>\n {isOpen ? `${t(\"audio.readLessDescriptionLabel\")}` : `${t(\"audio.readMoreDescriptionLabel\")}`}\n </StyledButton>\n </StyledDescription>\n </ContentWrapper>\n );\n};\n\nexport const LicenseContainerContent = ({ children, copyright, type }: LicenseContainerProps) => {\n const { t, i18n } = useTranslation();\n const license = copyright ? getLicenseByAbbreviation(copyright.license?.license ?? \"\", i18n.language) : undefined;\n const captionAuthors =\n [copyright?.creators, copyright?.rightsholders, copyright?.processors].find((authors) => authors?.length) ?? [];\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const content = (\n <>\n {children}\n {` ${t(`embed.type.${type}`)}${captionAuthors.length ? \": \" : \"\"}`}\n <span>{captionAuthors.map((author) => author.name).join(\", \")}</span>\n {license ? (\n <>\n {\" / \"}\n {<LicenseLink license={license} hideLink={!isOpen && !!children} />}\n </>\n ) : null}\n </>\n );\n\n if (children) {\n return (\n <LicenseDescription isOpen={isOpen} setIsOpen={setIsOpen}>\n {content}\n </LicenseDescription>\n );\n }\n\n return (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span>{content}</span>\n </Text>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EmbedByline.js","names":["Text","AlertLine","Button","rights","LicenseLink"],"sources":["../../src/LicenseByline/EmbedByline.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 { AlertLine } from \"@ndla/icons\";\nimport { getLicenseByAbbreviation, rights } from \"@ndla/licenses\";\nimport { Button, Text } from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { CopyrightDTO as ArticleCopyright } from \"@ndla/types-backend/article-api\";\nimport type { CopyrightDTO as AudioCopyright } from \"@ndla/types-backend/audio-api\";\nimport type { DraftCopyrightDTO as ConceptCopyright } from \"@ndla/types-backend/concept-api\";\nimport type { CopyrightDTO as ImageCopyright } from \"@ndla/types-backend/image-api\";\nimport type { BrightcoveCopyright } from \"@ndla/types-embed\";\nimport { type Dispatch, type ReactNode, type SetStateAction, useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { LicenseLink } from \"./LicenseLink\";\n\ninterface BaseProps {\n description?: ReactNode;\n children?: ReactNode;\n visibleAlt?: string;\n error?: true | false;\n hideDescription?: boolean;\n hideCopyright?: boolean;\n}\n\nexport interface EmbedBylineErrorProps extends BaseProps {\n type: EmbedBylineTypeProps[\"type\"] | \"h5p\" | \"external\" | \"code\";\n error: true;\n}\n\ninterface ImageProps extends BaseProps {\n type: \"image\";\n copyright: ImageCopyright | undefined;\n}\n\ninterface BrightcoveProps extends BaseProps {\n type: \"video\";\n copyright: BrightcoveCopyright | undefined;\n}\n\ninterface AudioProps extends BaseProps {\n type: \"audio\";\n copyright: AudioCopyright | undefined;\n}\n\ninterface PodcastProps extends BaseProps {\n type: \"podcast\";\n copyright: AudioCopyright | undefined;\n}\n\ninterface ConceptProps extends BaseProps {\n type: \"concept\" | \"gloss\";\n copyright: ConceptCopyright | undefined;\n}\n\ninterface CopyrightProps extends BaseProps {\n type: \"copyright\";\n copyright: ArticleCopyright | undefined;\n}\n\nexport type EmbedBylineTypeProps =\n | ImageProps\n | BrightcoveProps\n | AudioProps\n | PodcastProps\n | ConceptProps\n | CopyrightProps;\n\ntype Props = EmbedBylineTypeProps | EmbedBylineErrorProps;\n\nconst BylineWrapper = styled(\"figcaption\", {\n base: {\n display: \"flex\",\n flexDirection: \"column\",\n paddingBlock: \"xsmall\",\n textStyle: \"label.medium\",\n color: \"text.subtle\",\n },\n});\n\nconst ErrorBylineWrapper = styled(BylineWrapper, {\n base: {\n border: \"1px solid\",\n borderColor: \"stroke.error\",\n borderRadius: \"xsmall\",\n background: \"surface.dangerSubtle\",\n paddingInline: \"medium\",\n paddingBlock: \"medium\",\n },\n});\n\nconst StyledText = styled(Text, {\n base: {\n fontStyle: \"italic\",\n },\n});\n\nconst ContentWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n gap: \"xsmall\",\n alignItems: \"center\",\n textStyle: \"label.medium\",\n },\n});\n\nconst BaseDescription = styled(\"div\", {\n base: {\n display: \"inline-flex\",\n whiteSpace: \"pre-wrap\",\n },\n});\n\nexport const EmbedByline = ({ type, description, children, visibleAlt, hideCopyright, ...props }: Props) => {\n const { t } = useTranslation();\n\n if (props.error) {\n const typeString = type === \"h5p\" ? \"H5P\" : t(`embed.type.${type}`).toLowerCase();\n return (\n <ErrorBylineWrapper>\n <ContentWrapper>\n <AlertLine />\n <BaseDescription>\n <span>{t(\"embed.embedError\", { type: typeString })}</span>\n </BaseDescription>\n </ContentWrapper>\n </ErrorBylineWrapper>\n );\n }\n\n const { copyright } = props;\n const hideByline = hideCopyright && !description;\n\n return (\n <>\n {!hideByline && (\n <BylineWrapper>\n <div>\n {!!hideCopyright && description}\n {!hideCopyright && (\n <LicenseContainerContent type={type} copyright={copyright}>\n {description}\n </LicenseContainerContent>\n )}\n {children}\n </div>\n </BylineWrapper>\n )}\n {visibleAlt ? (\n <StyledText color=\"text.subtle\" textStyle=\"label.medium\" asChild consumeCss>\n <span>{`Alt: ${visibleAlt}`}</span>\n </StyledText>\n ) : null}\n </>\n );\n};\n\ninterface LicenseContainerProps {\n children?: ReactNode;\n copyright: EmbedBylineTypeProps[\"copyright\"];\n type: Props[\"type\"];\n}\n\nconst StyledDescription = styled(BaseDescription, {\n base: {\n mobileWideDown: {\n display: \"grid\",\n gridTemplateColumns: \"1fr auto\",\n alignItems: \"center\",\n overflow: \"hidden\",\n _open: {\n display: \"inline\",\n },\n },\n },\n});\n\nconst TextContent = styled(\"span\", {\n base: {\n mobileWideDown: {\n whiteSpace: \"nowrap\",\n maxHeight: \"large\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n transitionProperty: \"max-height\",\n transitionDuration: \"slow\",\n transitionTimingFunction: \"ease-in\",\n marginInlineEnd: \"4xsmall\",\n _open: {\n whiteSpace: \"pre-wrap\",\n maxHeight: \"none\",\n },\n },\n },\n});\n\nconst StyledButton = styled(Button, {\n base: {\n mobileWide: {\n display: \"none\",\n },\n _print: {\n display: \"none\",\n },\n },\n});\n\ninterface LicenseDescriptionProps {\n children?: ReactNode;\n isOpen: boolean;\n setIsOpen: Dispatch<SetStateAction<boolean>>;\n}\n\nconst LicenseDescription = ({ children, isOpen, setIsOpen }: LicenseDescriptionProps) => {\n const open = isOpen ? { \"data-open\": \"\" } : {};\n const { t } = useTranslation();\n\n const handleToggle = () => {\n setIsOpen(!isOpen);\n };\n\n return (\n <ContentWrapper>\n <StyledDescription {...open}>\n <TextContent {...open}>{children}</TextContent>\n <StyledButton variant=\"link\" size=\"small\" onClick={handleToggle}>\n {isOpen ? `${t(\"audio.readLessDescriptionLabel\")}` : `${t(\"audio.readMoreDescriptionLabel\")}`}\n </StyledButton>\n </StyledDescription>\n </ContentWrapper>\n );\n};\n\nexport const LicenseContainerContent = ({ children, copyright, type }: LicenseContainerProps) => {\n const { t, i18n } = useTranslation();\n const license = copyright ? getLicenseByAbbreviation(copyright.license?.license ?? \"\", i18n.language) : undefined;\n const shouldShowLicense = !!license && !license.rights.includes(rights.NA);\n const captionAuthors =\n [copyright?.creators, copyright?.rightsholders, copyright?.processors].find((authors) => authors?.length) ?? [];\n const [isOpen, setIsOpen] = useState<boolean>(false);\n\n const content = (\n <>\n {children}\n {` ${t(`embed.type.${type}`)}${captionAuthors.length ? \": \" : \"\"}`}\n <span>{captionAuthors.map((author) => author.name).join(\", \")}</span>\n {shouldShowLicense ? (\n <>\n {\" / \"}\n {<LicenseLink license={license} hideLink={!isOpen && !!children} />}\n </>\n ) : null}\n </>\n );\n\n if (children) {\n return (\n <LicenseDescription isOpen={isOpen} setIsOpen={setIsOpen}>\n {content}\n </LicenseDescription>\n );\n }\n\n return (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span>{content}</span>\n </Text>\n );\n};\n"],"mappings":"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"}
|
package/lib/Pitch/Pitch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pitch.js","names":["CardHeading","Text","CardRoot","CardImage","SafeLink","getPossiblyRelativeUrl","linkOverlay"],"sources":["../../src/Pitch/Pitch.tsx"],"sourcesContent":["/**\n * Copyright (c) 2024-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 { CardHeading, CardImage, CardRoot, Text } from \"@ndla/primitives\";\nimport { SafeLink } from \"@ndla/safelink\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { linkOverlay } from \"@ndla/styled-system/patterns\";\nimport parse from \"html-react-parser\";\nimport { getPossiblyRelativeUrl } from \"../utils/relativeUrl\";\n\nexport interface Props {\n title: string;\n url: string;\n description?: string;\n metaImage: {\n url: string;\n alt: string;\n };\n path?: string;\n}\n\nconst StyledCardHeading = styled(CardHeading, {\n base: {\n paddingBlockStart: \"medium\",\n },\n});\n\nconst StyledText = styled(Text, {\n base: {\n paddingBlockEnd: \"medium\",\n },\n});\n\nconst StyledCardRoot = styled(CardRoot, {\n base: {\n outline: \"0px\",\n boxShadow: \"none\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"small\",\n },\n});\n\nconst StyledCardImage = styled(CardImage, {\n base: {\n aspectRatio: \"16/9\",\n height: \"unset\",\n },\n});\n\nexport const Pitch = ({ title, url, metaImage, path, description }: Props) => {\n const href = getPossiblyRelativeUrl(url, path);\n\n return (\n <StyledCardRoot nonInteractive data-embed-type=\"pitch\" asChild consumeCss>\n <div>\n <StyledCardHeading textStyle=\"heading.small\" asChild consumeCss>\n <SafeLink to={href} unstyled css={linkOverlay.raw()}>\n {parse(title)}\n </SafeLink>\n </StyledCardHeading>\n {!!description && (\n <StyledText textStyle=\"body.xlarge\" asChild consumeCss>\n <div>{parse(description)}</div>\n </StyledText>\n )}\n <StyledCardImage\n variant=\"rounded\"\n src={metaImage.url}\n alt={metaImage.alt}\n sizes=\"480px\"\n fallbackWidth={300}\n width={550}\n height={310}\n />\n </div>\n </StyledCardRoot>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AA0BA,MAAM,qBAAA,GAAA,wBAAA,QAA2BA,iBAAAA,aAAa,EAC5C,MAAM,EACJ,mBAAmB,UACpB,EACF,CAAC;AAEF,MAAM,cAAA,GAAA,wBAAA,QAAoBC,iBAAAA,MAAM,EAC9B,MAAM,EACJ,iBAAiB,UAClB,EACF,CAAC;AAEF,MAAM,kBAAA,GAAA,wBAAA,QAAwBC,iBAAAA,UAAU,EACtC,MAAM;CACJ,SAAS;CACT,WAAW;CACX,SAAS;CACT,eAAe;CACf,KAAK;CACN,EACF,CAAC;AAEF,MAAM,mBAAA,GAAA,wBAAA,QAAyBC,iBAAAA,WAAW,EACxC,MAAM;CACJ,aAAa;CACb,QAAQ;CACT,EACF,CAAC;AAEF,MAAa,SAAS,EAAE,OAAO,KAAK,WAAW,MAAM,kBAAyB;AAG5E,QACE,iBAAA,GAAA,kBAAA,KAAC,gBAAD;EAAgB,gBAAA;EAAe,mBAAgB;EAAQ,SAAA;EAAQ,YAAA;YAC7D,iBAAA,GAAA,kBAAA,MAAC,OAAD,EAAA,UAAA;GACE,iBAAA,GAAA,kBAAA,KAAC,mBAAD;IAAmB,WAAU;IAAgB,SAAA;IAAQ,YAAA;cACnD,iBAAA,GAAA,kBAAA,KAACC,eAAAA,UAAD;KAAU,IANLC,oBAAAA,uBAAuB,KAAK,
|
|
1
|
+
{"version":3,"file":"Pitch.js","names":["CardHeading","Text","CardRoot","CardImage","SafeLink","getPossiblyRelativeUrl","linkOverlay"],"sources":["../../src/Pitch/Pitch.tsx"],"sourcesContent":["/**\n * Copyright (c) 2024-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 { CardHeading, CardImage, CardRoot, Text } from \"@ndla/primitives\";\nimport { SafeLink } from \"@ndla/safelink\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { linkOverlay } from \"@ndla/styled-system/patterns\";\nimport parse from \"html-react-parser\";\nimport { getPossiblyRelativeUrl } from \"../utils/relativeUrl\";\n\nexport interface Props {\n title: string;\n url: string;\n description?: string;\n metaImage: {\n url: string;\n alt: string;\n };\n path?: string;\n}\n\nconst StyledCardHeading = styled(CardHeading, {\n base: {\n paddingBlockStart: \"medium\",\n },\n});\n\nconst StyledText = styled(Text, {\n base: {\n paddingBlockEnd: \"medium\",\n },\n});\n\nconst StyledCardRoot = styled(CardRoot, {\n base: {\n outline: \"0px\",\n boxShadow: \"none\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"small\",\n },\n});\n\nconst StyledCardImage = styled(CardImage, {\n base: {\n aspectRatio: \"16/9\",\n height: \"unset\",\n },\n});\n\nexport const Pitch = ({ title, url, metaImage, path, description }: Props) => {\n const href = getPossiblyRelativeUrl(url, path);\n\n return (\n <StyledCardRoot nonInteractive data-embed-type=\"pitch\" asChild consumeCss>\n <div>\n <StyledCardHeading textStyle=\"heading.small\" asChild consumeCss>\n <SafeLink to={href} unstyled css={linkOverlay.raw()}>\n {parse(title)}\n </SafeLink>\n </StyledCardHeading>\n {!!description && (\n <StyledText textStyle=\"body.xlarge\" asChild consumeCss>\n <div>{parse(description)}</div>\n </StyledText>\n )}\n <StyledCardImage\n variant=\"rounded\"\n src={metaImage.url}\n alt={metaImage.alt}\n sizes=\"480px\"\n fallbackWidth={300}\n width={550}\n height={310}\n />\n </div>\n </StyledCardRoot>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AA0BA,MAAM,qBAAA,GAAA,wBAAA,QAA2BA,iBAAAA,aAAa,EAC5C,MAAM,EACJ,mBAAmB,UACpB,EACF,CAAC;AAEF,MAAM,cAAA,GAAA,wBAAA,QAAoBC,iBAAAA,MAAM,EAC9B,MAAM,EACJ,iBAAiB,UAClB,EACF,CAAC;AAEF,MAAM,kBAAA,GAAA,wBAAA,QAAwBC,iBAAAA,UAAU,EACtC,MAAM;CACJ,SAAS;CACT,WAAW;CACX,SAAS;CACT,eAAe;CACf,KAAK;CACN,EACF,CAAC;AAEF,MAAM,mBAAA,GAAA,wBAAA,QAAyBC,iBAAAA,WAAW,EACxC,MAAM;CACJ,aAAa;CACb,QAAQ;CACT,EACF,CAAC;AAEF,MAAa,SAAS,EAAE,OAAO,KAAK,WAAW,MAAM,kBAAyB;AAG5E,QACE,iBAAA,GAAA,kBAAA,KAAC,gBAAD;EAAgB,gBAAA;EAAe,mBAAgB;EAAQ,SAAA;EAAQ,YAAA;YAC7D,iBAAA,GAAA,kBAAA,MAAC,OAAD,EAAA,UAAA;GACE,iBAAA,GAAA,kBAAA,KAAC,mBAAD;IAAmB,WAAU;IAAgB,SAAA;IAAQ,YAAA;cACnD,iBAAA,GAAA,kBAAA,KAACC,eAAAA,UAAD;KAAU,IANLC,oBAAAA,uBAAuB,KAAK,KAMf;KAAE,UAAA;KAAS,KAAKC,6BAAAA,YAAY,KAAK;8CAC1C,MAAM;KACJ,CAAA;IACO,CAAA;GACnB,CAAC,CAAC,eACD,iBAAA,GAAA,kBAAA,KAAC,YAAD;IAAY,WAAU;IAAc,SAAA;IAAQ,YAAA;cAC1C,iBAAA,GAAA,kBAAA,KAAC,OAAD,EAAA,WAAA,GAAA,kBAAA,SAAY,YAAY,EAAO,CAAA;IACpB,CAAA;GAEf,iBAAA,GAAA,kBAAA,KAAC,iBAAD;IACE,SAAQ;IACR,KAAK,UAAU;IACf,KAAK,UAAU;IACf,OAAM;IACN,eAAe;IACf,OAAO;IACP,QAAQ;IACR,CAAA;GACE,EAAA,CAAA;EACS,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"licenseAttributes.js","names":[],"sources":["../../src/utils/licenseAttributes.ts"],"sourcesContent":["/**\n * Copyright (c) 2024-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 { getLicenseByAbbreviation, isCreativeCommonsLicense } from \"@ndla/licenses\";\n\nexport const licenseAttributes = (license: string | undefined, lang: string | undefined, url: string | undefined) => {\n const licenseAbbr = getLicenseByAbbreviation(license ? license : \"\", lang);\n\n const licenseProps = isCreativeCommonsLicense(licenseAbbr.rights)\n ? {\n \"xmlns:cc\": \"https://creativecommons.org/ns#\",\n \"xmlns:dct\": \"http://purl.org/dc/terms/\",\n about: url ?? undefined,\n }\n : {};\n\n return licenseProps;\n};\n"],"mappings":";;;;;;;;;;AAUA,MAAa,qBAAqB,SAA6B,MAA0B,QAA4B;AAWnH,SAAA,GAAA,eAAA,2BAAA,GAAA,eAAA,0BAV6C,UAAU,UAAU,IAAI,
|
|
1
|
+
{"version":3,"file":"licenseAttributes.js","names":[],"sources":["../../src/utils/licenseAttributes.ts"],"sourcesContent":["/**\n * Copyright (c) 2024-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 { getLicenseByAbbreviation, isCreativeCommonsLicense } from \"@ndla/licenses\";\n\nexport const licenseAttributes = (license: string | undefined, lang: string | undefined, url: string | undefined) => {\n const licenseAbbr = getLicenseByAbbreviation(license ? license : \"\", lang);\n\n const licenseProps = isCreativeCommonsLicense(licenseAbbr.rights)\n ? {\n \"xmlns:cc\": \"https://creativecommons.org/ns#\",\n \"xmlns:dct\": \"http://purl.org/dc/terms/\",\n about: url ?? undefined,\n }\n : {};\n\n return licenseProps;\n};\n"],"mappings":";;;;;;;;;;AAUA,MAAa,qBAAqB,SAA6B,MAA0B,QAA4B;AAWnH,SAAA,GAAA,eAAA,2BAAA,GAAA,eAAA,0BAV6C,UAAU,UAAU,IAAI,KAEZ,CAAC,OAAO,GAC7D;EACE,YAAY;EACZ,aAAa;EACb,OAAO,OAAO,KAAA;EACf,GACD,EAAE"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ndla/ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "56.0.
|
|
4
|
+
"version": "56.0.191-alpha.0",
|
|
5
5
|
"description": "UI component library for NDLA",
|
|
6
6
|
"license": "GPL-3.0",
|
|
7
7
|
"exports": {
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"@ark-ui/react": "^5.34.1",
|
|
40
40
|
"@ndla/core": "^6.0.7-alpha.0",
|
|
41
41
|
"@ndla/icons": "^8.0.89-alpha.0",
|
|
42
|
-
"@ndla/licenses": "^10.0.
|
|
42
|
+
"@ndla/licenses": "^10.0.12-alpha.0",
|
|
43
43
|
"@ndla/locales": "^0.0.3",
|
|
44
|
-
"@ndla/primitives": "^1.0.
|
|
45
|
-
"@ndla/safelink": "^7.0.
|
|
44
|
+
"@ndla/primitives": "^1.0.129-alpha.0",
|
|
45
|
+
"@ndla/safelink": "^7.0.132-alpha.0",
|
|
46
46
|
"@ndla/styled-system": "^0.0.49",
|
|
47
47
|
"@ndla/util": "^5.0.21-alpha.0",
|
|
48
48
|
"html-react-parser": "^6.0.0"
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"publishConfig": {
|
|
64
64
|
"access": "public"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "471ee3863b03f1cc6a48d09ab624fbd1a5613c6e"
|
|
67
67
|
}
|
|
@@ -47,6 +47,7 @@ export const makeIframeString = (url: string, width: string | number, height: st
|
|
|
47
47
|
export const isNumeric = (value: any) => !Number.isNaN(value - Number.parseFloat(value));
|
|
48
48
|
|
|
49
49
|
const getIframeProps = (data: BrightcoveEmbedData, sources: BrightcoveVideoSource[]) => {
|
|
50
|
+
// oxlint-disable-next-line typescript/no-useless-default-assignment
|
|
50
51
|
const { account, videoid, player = "default" } = data;
|
|
51
52
|
|
|
52
53
|
const source = sources.filter((s) => s.width && s.height).toSorted((a, b) => a!.height! - b.height!)[0];
|
|
@@ -201,3 +201,35 @@ export const InlineFailed: StoryObj<typeof ConceptEmbed> = {
|
|
|
201
201
|
children: "forklaring",
|
|
202
202
|
},
|
|
203
203
|
};
|
|
204
|
+
|
|
205
|
+
export const InlineNALicence: StoryObj<typeof ConceptEmbed> = {
|
|
206
|
+
args: {
|
|
207
|
+
embed: {
|
|
208
|
+
resource: "concept",
|
|
209
|
+
status: "success",
|
|
210
|
+
embedData: inlineEmbedData,
|
|
211
|
+
data: {
|
|
212
|
+
...blockMetaData,
|
|
213
|
+
concept: {
|
|
214
|
+
...blockMetaData.concept,
|
|
215
|
+
copyright: {
|
|
216
|
+
...blockMetaData.concept.copyright,
|
|
217
|
+
license: {
|
|
218
|
+
license: "N/A",
|
|
219
|
+
description: "N/A - ikke relevant",
|
|
220
|
+
url: "",
|
|
221
|
+
},
|
|
222
|
+
creators: [{ type: "writer", name: "Sissel Paaske" }],
|
|
223
|
+
processors: [
|
|
224
|
+
{ type: "processor", name: "Totaltekst" },
|
|
225
|
+
{ type: "correction", name: "Arbeidets art" },
|
|
226
|
+
],
|
|
227
|
+
rightsholders: [],
|
|
228
|
+
processed: false,
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
children: "forklaring",
|
|
234
|
+
},
|
|
235
|
+
};
|
|
@@ -360,7 +360,7 @@ export const FloatLeftExtraSmall: StoryObj<typeof ImageEmbed> = {
|
|
|
360
360
|
};
|
|
361
361
|
|
|
362
362
|
export const In2x2Grid: StoryFn<typeof ImageEmbed> = (args) => {
|
|
363
|
-
const items =
|
|
363
|
+
const items = Array.from<ReactNode>({ length: 4 }).fill(
|
|
364
364
|
<ImageEmbed
|
|
365
365
|
{...args}
|
|
366
366
|
embed={{
|
|
@@ -379,7 +379,7 @@ export const In2x2Grid: StoryFn<typeof ImageEmbed> = (args) => {
|
|
|
379
379
|
};
|
|
380
380
|
|
|
381
381
|
export const In4Grid: StoryFn<typeof ImageEmbed> = (args) => {
|
|
382
|
-
const items =
|
|
382
|
+
const items = Array.from<ReactNode>({ length: 4 }).fill(
|
|
383
383
|
<ImageEmbed
|
|
384
384
|
{...args}
|
|
385
385
|
embed={{
|
package/src/FactBox/FactBox.tsx
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { PageContent } from "@ndla/primitives";
|
|
10
10
|
import { ArticleContent, ArticleWrapper } from "@ndla/ui";
|
|
11
11
|
import type { Meta, StoryFn } from "@storybook/react";
|
|
12
|
+
import type { ReactNode } from "react";
|
|
12
13
|
import { Plain } from "../KeyFigure/KeyFigure.stories";
|
|
13
14
|
import { Default as PitchStory } from "../Pitch/Pitch.stories";
|
|
14
15
|
import { Grid, GridItem } from "./Grid";
|
|
@@ -46,20 +47,22 @@ const keyFigureArgs = [
|
|
|
46
47
|
|
|
47
48
|
export const GridKeyPerformanceStory: StoryFn<typeof Grid> = ({ ...args }) => {
|
|
48
49
|
const columns = args.columns === "2x2" ? 4 : parseInt(args.columns);
|
|
49
|
-
const items =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
const items = Array.from<ReactNode>({ length: columns })
|
|
51
|
+
.fill(0)
|
|
52
|
+
.map((_, idx) => {
|
|
53
|
+
const args = keyFigureArgs[idx % keyFigureArgs.length];
|
|
54
|
+
return (
|
|
55
|
+
<GridItem key={idx} data-type="grid-cell">
|
|
56
|
+
<Plain key={idx} {...args} />
|
|
57
|
+
</GridItem>
|
|
58
|
+
);
|
|
59
|
+
});
|
|
57
60
|
return <Grid {...args}>{items}</Grid>;
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
export const GridPitchStory: StoryFn<typeof Grid> = ({ ...args }) => {
|
|
61
64
|
const columns = args.columns === "2x2" ? 4 : parseInt(args.columns);
|
|
62
|
-
const items =
|
|
65
|
+
const items = Array.from<ReactNode>({ length: columns }).fill(
|
|
63
66
|
<GridItem data-type="grid-cell">
|
|
64
67
|
<PitchStory
|
|
65
68
|
// oxlint-disable-next-line typescript/no-non-null-asserted-optional-chain
|
|
@@ -77,27 +80,31 @@ export const GridPitchStory: StoryFn<typeof Grid> = ({ ...args }) => {
|
|
|
77
80
|
|
|
78
81
|
export const GridItemsWithBorders: StoryFn<typeof Grid> = ({ ...args }) => {
|
|
79
82
|
const columns = args.columns === "2x2" ? 4 : parseInt(args.columns);
|
|
80
|
-
const items =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
const items = Array.from<ReactNode>({ length: columns })
|
|
84
|
+
.fill(0)
|
|
85
|
+
.map((_, idx) => {
|
|
86
|
+
const args = keyFigureArgs[idx % keyFigureArgs.length];
|
|
87
|
+
return (
|
|
88
|
+
<GridItem key={idx} data-type="grid-cell" border={idx % 2 === 0}>
|
|
89
|
+
<Plain key={idx} {...args} />
|
|
90
|
+
</GridItem>
|
|
91
|
+
);
|
|
92
|
+
});
|
|
88
93
|
return <Grid {...args}>{items}</Grid>;
|
|
89
94
|
};
|
|
90
95
|
|
|
91
96
|
export const GridItemsWithBordersInsideGridWithBorder: StoryFn<typeof Grid> = ({ ...args }) => {
|
|
92
97
|
const columns = args.columns === "2x2" ? 4 : parseInt(args.columns);
|
|
93
|
-
const items =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
const items = Array.from<ReactNode>({ length: columns })
|
|
99
|
+
.fill(0)
|
|
100
|
+
.map((_, idx) => {
|
|
101
|
+
const args = keyFigureArgs[idx % keyFigureArgs.length];
|
|
102
|
+
return (
|
|
103
|
+
<GridItem key={idx} data-type="grid-cell" border={true}>
|
|
104
|
+
<Plain key={idx} {...args} />
|
|
105
|
+
</GridItem>
|
|
106
|
+
);
|
|
107
|
+
});
|
|
101
108
|
return (
|
|
102
109
|
<Grid {...args} border="lightBlue">
|
|
103
110
|
{items}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { AlertLine } from "@ndla/icons";
|
|
10
|
-
import { getLicenseByAbbreviation } from "@ndla/licenses";
|
|
10
|
+
import { getLicenseByAbbreviation, rights } from "@ndla/licenses";
|
|
11
11
|
import { Button, Text } from "@ndla/primitives";
|
|
12
12
|
import { styled } from "@ndla/styled-system/jsx";
|
|
13
13
|
import type { CopyrightDTO as ArticleCopyright } from "@ndla/types-backend/article-api";
|
|
@@ -239,6 +239,7 @@ const LicenseDescription = ({ children, isOpen, setIsOpen }: LicenseDescriptionP
|
|
|
239
239
|
export const LicenseContainerContent = ({ children, copyright, type }: LicenseContainerProps) => {
|
|
240
240
|
const { t, i18n } = useTranslation();
|
|
241
241
|
const license = copyright ? getLicenseByAbbreviation(copyright.license?.license ?? "", i18n.language) : undefined;
|
|
242
|
+
const shouldShowLicense = !!license && !license.rights.includes(rights.NA);
|
|
242
243
|
const captionAuthors =
|
|
243
244
|
[copyright?.creators, copyright?.rightsholders, copyright?.processors].find((authors) => authors?.length) ?? [];
|
|
244
245
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
|
@@ -248,7 +249,7 @@ export const LicenseContainerContent = ({ children, copyright, type }: LicenseCo
|
|
|
248
249
|
{children}
|
|
249
250
|
{` ${t(`embed.type.${type}`)}${captionAuthors.length ? ": " : ""}`}
|
|
250
251
|
<span>{captionAuthors.map((author) => author.name).join(", ")}</span>
|
|
251
|
-
{
|
|
252
|
+
{shouldShowLicense ? (
|
|
252
253
|
<>
|
|
253
254
|
{" / "}
|
|
254
255
|
{<LicenseLink license={license} hideLink={!isOpen && !!children} />}
|