@intlayer/design-system 9.5.1 → 9.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/Form/elements/OTPElement.mjs +1 -1
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +1 -1
- package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs +53 -61
- package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs.map +1 -1
- package/dist/esm/components/MarkDownRender/index.mjs +2 -1
- package/dist/esm/components/MarkDownRender/youtubeUrl.mjs +22 -0
- package/dist/esm/components/MarkDownRender/youtubeUrl.mjs.map +1 -0
- package/dist/esm/components/Modal/Modal.mjs +2 -2
- package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
- package/dist/esm/components/Pagination/Pagination.mjs +1 -1
- package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -3
- package/dist/esm/components/Tab/Tab.mjs +1 -1
- package/dist/esm/components/index.mjs +2 -1
- package/dist/esm/hooks/index.mjs +8 -8
- package/dist/types/components/MarkDownRender/MarkDownIframe.d.ts.map +1 -1
- package/dist/types/components/MarkDownRender/index.d.ts +2 -1
- package/dist/types/components/MarkDownRender/youtubeUrl.d.ts +17 -0
- package/dist/types/components/MarkDownRender/youtubeUrl.d.ts.map +1 -0
- package/dist/types/components/index.d.ts +2 -1
- package/package.json +25 -25
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useItemSelector } from "../../../hooks/useItemSelector.mjs";
|
|
4
3
|
import { InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "../../Input/OTPInput.mjs";
|
|
4
|
+
import { useItemSelector } from "../../../hooks/useItemSelector.mjs";
|
|
5
5
|
import { FormField, useFormField } from "../FormField.mjs";
|
|
6
6
|
import { FormItemLayout } from "../layout/FormItemLayout.mjs";
|
|
7
7
|
import { useEffect, useRef } from "react";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { usePersistedStore } from "../../hooks/usePersistedStore.mjs";
|
|
4
3
|
import { Button } from "../Button/Button.mjs";
|
|
5
4
|
import { Container } from "../Container/index.mjs";
|
|
6
5
|
import { DropDown } from "../DropDown/index.mjs";
|
|
7
6
|
import { Input } from "../Input/Input.mjs";
|
|
8
7
|
import { SwitchSelector } from "../SwitchSelector/SwitchSelector.mjs";
|
|
8
|
+
import { usePersistedStore } from "../../hooks/usePersistedStore.mjs";
|
|
9
9
|
import { useLocaleSwitcherContent } from "./LocaleSwitcherContentContext.mjs";
|
|
10
10
|
import { useMemo, useRef, useState } from "react";
|
|
11
11
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -5,16 +5,58 @@ import { Button } from "../Button/Button.mjs";
|
|
|
5
5
|
import { Link } from "../Link/Link.mjs";
|
|
6
6
|
import { Container } from "../Container/index.mjs";
|
|
7
7
|
import { Modal } from "../Modal/Modal.mjs";
|
|
8
|
+
import { getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl } from "./youtubeUrl.mjs";
|
|
8
9
|
import { useEffect, useRef, useState } from "react";
|
|
9
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import { MoveDiagonal
|
|
11
|
+
import { MoveDiagonal } from "lucide-react";
|
|
11
12
|
|
|
12
13
|
//#region src/components/MarkDownRender/MarkDownIframe.tsx
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The features the YouTube player asks for, as shipped by YouTube's own embed code.
|
|
16
|
+
*/
|
|
17
|
+
const YOUTUBE_PLAYER_ALLOW = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share";
|
|
18
|
+
/**
|
|
19
|
+
* Turns whatever the markdown handed over into what the frame is rendered with.
|
|
20
|
+
*
|
|
21
|
+
* A YouTube address, in any of its forms, becomes the player embed carrying
|
|
22
|
+
* the attributes YouTube's own embed code ships with. Query parameters are
|
|
23
|
+
* dropped on purpose: docs written for one origin (`origin=…`) break the
|
|
24
|
+
* player on every other one.
|
|
25
|
+
*
|
|
26
|
+
* `referrerPolicy` is the attribute that matters: the player refuses to start
|
|
27
|
+
* ("Video player configuration error", error 153) unless the request carries
|
|
28
|
+
* a referrer, and a page served with `Referrer-Policy: same-origin` sends none
|
|
29
|
+
* to a cross-origin frame. The attribute overrides the page policy for this
|
|
30
|
+
* frame only.
|
|
31
|
+
*/
|
|
32
|
+
const resolveFrame = (src, frameProps) => {
|
|
33
|
+
const youtubeVideoId = getYoutubeVideoId(src);
|
|
34
|
+
if (!youtubeVideoId) return {
|
|
35
|
+
src,
|
|
36
|
+
frameProps,
|
|
37
|
+
isYoutubeVideo: false
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
isYoutubeVideo: true,
|
|
41
|
+
src: getYoutubeEmbedUrl(youtubeVideoId),
|
|
42
|
+
frameProps: {
|
|
43
|
+
...frameProps,
|
|
44
|
+
allow: YOUTUBE_PLAYER_ALLOW,
|
|
45
|
+
allowFullScreen: true,
|
|
46
|
+
referrerPolicy: "strict-origin-when-cross-origin"
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
const getEmbedLinkMeta = (src) => {
|
|
14
51
|
if (!src) return {
|
|
15
52
|
href: "",
|
|
16
53
|
label: ""
|
|
17
54
|
};
|
|
55
|
+
const youtubeVideoId = getYoutubeVideoId(src);
|
|
56
|
+
if (youtubeVideoId) return {
|
|
57
|
+
href: getYoutubeWatchUrl(youtubeVideoId),
|
|
58
|
+
label: "youtube.com"
|
|
59
|
+
};
|
|
18
60
|
if (/^https?:\/\//i.test(src)) try {
|
|
19
61
|
const url = new URL(src);
|
|
20
62
|
return {
|
|
@@ -31,21 +73,6 @@ function embedLinkMeta(src) {
|
|
|
31
73
|
href: src,
|
|
32
74
|
label: src
|
|
33
75
|
};
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Reads the video id out of a YouTube embed address.
|
|
37
|
-
*
|
|
38
|
-
* @returns The video id, or `null` when the address is not a YouTube embed.
|
|
39
|
-
*/
|
|
40
|
-
const getYoutubeVideoId = (src) => {
|
|
41
|
-
if (!src || !/^https?:\/\//i.test(src)) return null;
|
|
42
|
-
try {
|
|
43
|
-
const url = new URL(src);
|
|
44
|
-
if (!/(^|\.)youtube(-nocookie)?\.com$/.test(url.hostname)) return null;
|
|
45
|
-
return url.pathname.replace(/^\/embed\//, "").split("/")[0] || null;
|
|
46
|
-
} catch {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
76
|
};
|
|
50
77
|
/**
|
|
51
78
|
* Tracks whether an element has come close enough to the viewport to be worth
|
|
@@ -85,63 +112,28 @@ const useHasBecomeVisible = () => {
|
|
|
85
112
|
};
|
|
86
113
|
};
|
|
87
114
|
/**
|
|
88
|
-
* The embed itself
|
|
89
|
-
*
|
|
90
|
-
* A YouTube player pulls well over a megabyte of script before it can show a
|
|
91
|
-
* single frame. Standing in for it with its own thumbnail until the reader
|
|
92
|
-
* presses play keeps that cost on the readers who actually watch the video.
|
|
115
|
+
* The embed itself, mounted once it comes close to the viewport.
|
|
93
116
|
*/
|
|
94
117
|
const EmbeddedFrame = ({ src, title, className, frameProps }) => {
|
|
95
|
-
const [isPlayRequested, setIsPlayRequested] = useState(false);
|
|
96
118
|
const { elementRef, hasBecomeVisible } = useHasBecomeVisible();
|
|
97
|
-
|
|
98
|
-
if (youtubeVideoId && !isPlayRequested) return /* @__PURE__ */ jsxs("button", {
|
|
99
|
-
type: "button",
|
|
100
|
-
"aria-label": title ?? "Play video",
|
|
101
|
-
onClick: () => setIsPlayRequested(true),
|
|
102
|
-
className: cn("group relative block cursor-pointer border-0 bg-card p-0", className),
|
|
103
|
-
children: [/* @__PURE__ */ jsxs("picture", { children: [/* @__PURE__ */ jsx("source", {
|
|
104
|
-
srcSet: `https://i.ytimg.com/vi_webp/${youtubeVideoId}/hqdefault.webp`,
|
|
105
|
-
type: "image/webp"
|
|
106
|
-
}), /* @__PURE__ */ jsx("img", {
|
|
107
|
-
src: `https://i.ytimg.com/vi/${youtubeVideoId}/hqdefault.jpg`,
|
|
108
|
-
alt: "",
|
|
109
|
-
width: 480,
|
|
110
|
-
height: 360,
|
|
111
|
-
fetchPriority: "high",
|
|
112
|
-
decoding: "async",
|
|
113
|
-
className: "size-full object-cover"
|
|
114
|
-
})] }), /* @__PURE__ */ jsx("span", {
|
|
115
|
-
className: "absolute inset-0 flex items-center justify-center",
|
|
116
|
-
children: /* @__PURE__ */ jsx("span", {
|
|
117
|
-
className: "flex size-14 items-center justify-center rounded-full bg-text/70 text-text-opposite transition-transform group-hover:scale-110",
|
|
118
|
-
children: /* @__PURE__ */ jsx(Play, { className: "size-6 translate-x-0.5 fill-current" })
|
|
119
|
-
})
|
|
120
|
-
})]
|
|
121
|
-
});
|
|
122
|
-
if (!hasBecomeVisible && !isPlayRequested) return /* @__PURE__ */ jsx("div", {
|
|
119
|
+
if (!hasBecomeVisible) return /* @__PURE__ */ jsx("div", {
|
|
123
120
|
ref: elementRef,
|
|
124
121
|
"aria-hidden": true,
|
|
125
122
|
className
|
|
126
123
|
});
|
|
127
|
-
const frameSrc = (() => {
|
|
128
|
-
if (!isPlayRequested || !youtubeVideoId || !src) return src;
|
|
129
|
-
const playbackSrc = new URL(src);
|
|
130
|
-
playbackSrc.searchParams.set("autoplay", "1");
|
|
131
|
-
return playbackSrc.href;
|
|
132
|
-
})();
|
|
133
124
|
return /* @__PURE__ */ jsx("iframe", {
|
|
134
125
|
...frameProps,
|
|
135
|
-
src
|
|
126
|
+
src,
|
|
136
127
|
title,
|
|
137
128
|
loading: "lazy",
|
|
138
129
|
className
|
|
139
130
|
});
|
|
140
131
|
};
|
|
141
132
|
const MarkDownIframe = (props) => {
|
|
142
|
-
const { src, className, title, ...rest } = props;
|
|
133
|
+
const { src: rawSrc, className, title, ...rest } = props;
|
|
143
134
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
144
|
-
const {
|
|
135
|
+
const { src, frameProps, isYoutubeVideo } = resolveFrame(rawSrc, rest);
|
|
136
|
+
const { href, label } = getEmbedLinkMeta(rawSrc);
|
|
145
137
|
return /* @__PURE__ */ jsxs(Container, {
|
|
146
138
|
roundedSize: "2xl",
|
|
147
139
|
border: true,
|
|
@@ -152,8 +144,8 @@ const MarkDownIframe = (props) => {
|
|
|
152
144
|
/* @__PURE__ */ jsx(EmbeddedFrame, {
|
|
153
145
|
src,
|
|
154
146
|
title,
|
|
155
|
-
frameProps
|
|
156
|
-
className: cn("block max-h-[80vh] min-h-[12rem] w-full border-0", className)
|
|
147
|
+
frameProps,
|
|
148
|
+
className: cn("block max-h-[80vh] min-h-[12rem] w-full border-0", isYoutubeVideo && "aspect-video", className)
|
|
157
149
|
}),
|
|
158
150
|
/* @__PURE__ */ jsxs("div", {
|
|
159
151
|
className: "flex items-center justify-between gap-3 px-3 py-1",
|
|
@@ -190,7 +182,7 @@ const MarkDownIframe = (props) => {
|
|
|
190
182
|
className: "overflow-hidden p-0",
|
|
191
183
|
gap: "none",
|
|
192
184
|
children: /* @__PURE__ */ jsx("iframe", {
|
|
193
|
-
...
|
|
185
|
+
...frameProps,
|
|
194
186
|
src,
|
|
195
187
|
title: title ?? "Embedded content",
|
|
196
188
|
allowFullScreen: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkDownIframe.mjs","names":[],"sources":["../../../../src/components/MarkDownRender/MarkDownIframe.tsx"],"sourcesContent":["'use client';\n\nimport { Button } from '@components/Button';\nimport { Container } from '@components/Container';\nimport { Link } from '@components/Link';\nimport { Modal } from '@components/Modal';\nimport { cn } from '@utils/cn';\nimport { MoveDiagonal, Play } from 'lucide-react';\nimport {\n type ComponentProps,\n type FC,\n useEffect,\n useRef,\n useState,\n} from 'react';\n\nfunction embedLinkMeta(src: string | undefined): {\n href: string;\n label: string;\n} {\n if (!src) return { href: '', label: '' };\n if (/^https?:\\/\\//i.test(src)) {\n try {\n const url = new URL(src);\n return { href: url.href, label: url.host };\n } catch {\n return { href: src, label: src };\n }\n }\n return { href: src, label: src };\n}\n\n/**\n * Reads the video id out of a YouTube embed address.\n *\n * @returns The video id, or `null` when the address is not a YouTube embed.\n */\nconst getYoutubeVideoId = (src: string | undefined): string | null => {\n if (!src || !/^https?:\\/\\//i.test(src)) return null;\n\n try {\n const url = new URL(src);\n if (!/(^|\\.)youtube(-nocookie)?\\.com$/.test(url.hostname)) return null;\n\n const videoId = url.pathname.replace(/^\\/embed\\//, '').split('/')[0];\n\n return videoId || null;\n } catch {\n return null;\n }\n};\n\n/**\n * Tracks whether an element has come close enough to the viewport to be worth\n * loading.\n *\n * `loading=\"lazy\"` is not enough for embeds inside tabs or carousels: the\n * browser only defers frames that are far down the page, so a frame parked\n * off-screen by a transform — an inactive tab panel — still loads immediately.\n * A live-app embed costs upwards of a megabyte and seconds of main thread,\n * which is the whole page's performance budget spent on something nobody is\n * looking at.\n *\n * @returns A ref to attach to the placeholder, and whether it became visible.\n */\nconst useHasBecomeVisible = <ElementType extends HTMLElement>() => {\n const elementRef = useRef<ElementType>(null);\n const [hasBecomeVisible, setHasBecomeVisible] = useState(false);\n\n useEffect(() => {\n const element = elementRef.current;\n if (!element || hasBecomeVisible) return;\n\n if (typeof IntersectionObserver === 'undefined') {\n setHasBecomeVisible(true);\n return;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n setHasBecomeVisible(true);\n observer.disconnect();\n }\n },\n { rootMargin: '200px' }\n );\n\n observer.observe(element);\n\n return () => observer.disconnect();\n }, [hasBecomeVisible]);\n\n return { elementRef, hasBecomeVisible };\n};\n\ntype EmbeddedFrameProps = {\n src: string | undefined;\n title: string | undefined;\n className: string;\n frameProps: Omit<ComponentProps<'iframe'>, 'src' | 'title' | 'className'>;\n};\n\n/**\n * The embed itself: a poster for YouTube, deferred loading for anything else.\n *\n * A YouTube player pulls well over a megabyte of script before it can show a\n * single frame. Standing in for it with its own thumbnail until the reader\n * presses play keeps that cost on the readers who actually watch the video.\n */\nconst EmbeddedFrame: FC<EmbeddedFrameProps> = ({\n src,\n title,\n className,\n frameProps,\n}) => {\n const [isPlayRequested, setIsPlayRequested] = useState(false);\n const { elementRef, hasBecomeVisible } =\n useHasBecomeVisible<HTMLDivElement>();\n const youtubeVideoId = getYoutubeVideoId(src);\n\n if (youtubeVideoId && !isPlayRequested) {\n return (\n <button\n type=\"button\"\n aria-label={title ?? 'Play video'}\n onClick={() => setIsPlayRequested(true)}\n className={cn(\n 'group relative block cursor-pointer border-0 bg-card p-0',\n className\n )}\n >\n {/*\n * The poster stands in for the player, so on a page that opens with a\n * video it is the largest element painted — deferring it would defer\n * the page's LCP. It is the one image here worth fetching eagerly.\n */}\n <picture>\n {/*\n * YouTube serves the same poster as WebP under `vi_webp`, at roughly\n * a third of the JPEG's weight. The `img` below stays as the\n * fallback for the browsers that cannot decode it.\n */}\n <source\n srcSet={`https://i.ytimg.com/vi_webp/${youtubeVideoId}/hqdefault.webp`}\n type=\"image/webp\"\n />\n <img\n src={`https://i.ytimg.com/vi/${youtubeVideoId}/hqdefault.jpg`}\n alt=\"\"\n width={480}\n height={360}\n fetchPriority=\"high\"\n decoding=\"async\"\n className=\"size-full object-cover\"\n />\n </picture>\n <span className=\"absolute inset-0 flex items-center justify-center\">\n <span className=\"flex size-14 items-center justify-center rounded-full bg-text/70 text-text-opposite transition-transform group-hover:scale-110\">\n <Play className=\"size-6 translate-x-0.5 fill-current\" />\n </span>\n </span>\n </button>\n );\n }\n\n if (!hasBecomeVisible && !isPlayRequested) {\n // Same box as the frame it stands in for, so nothing shifts once it loads.\n return <div ref={elementRef} aria-hidden className={className} />;\n }\n\n const frameSrc = (() => {\n if (!isPlayRequested || !youtubeVideoId || !src) return src;\n\n const playbackSrc = new URL(src);\n playbackSrc.searchParams.set('autoplay', '1');\n\n return playbackSrc.href;\n })();\n\n return (\n <iframe\n {...frameProps}\n src={frameSrc}\n title={title}\n loading=\"lazy\"\n className={className}\n />\n );\n};\n\nexport const MarkDownIframe: FC<ComponentProps<'iframe'>> = (props) => {\n const { src, className, title, ...rest } = props;\n const [isModalOpen, setIsModalOpen] = useState(false);\n const { href, label } = embedLinkMeta(src);\n\n return (\n <Container\n roundedSize=\"2xl\"\n border\n borderColor=\"neutral\"\n className=\"overflow-hidden p-0\"\n gap=\"none\"\n >\n <EmbeddedFrame\n src={src}\n title={title}\n frameProps={rest}\n className={cn(\n 'block max-h-[80vh] min-h-[12rem] w-full border-0',\n className\n )}\n />\n <div className=\"flex items-center justify-between gap-3 px-3 py-1\">\n {href ? (\n <Link\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n label=\"\"\n color=\"neutral\"\n className=\"inline-flex min-w-0 max-w-[calc(100%-3rem)] items-center gap-2 text-muted-foreground text-xs underline-offset-2 hover:text-foreground hover:underline\"\n >\n {label}\n </Link>\n ) : (\n <span className=\"text-neutral text-sm\">Embedded frame</span>\n )}\n <Button\n variant=\"hoverable\"\n size=\"icon-md\"\n onClick={() => setIsModalOpen(true)}\n label=\"Open embedded page in fullscreen\"\n Icon={MoveDiagonal}\n />\n </div>\n\n <Modal\n isOpen={isModalOpen}\n onClose={() => setIsModalOpen(false)}\n size=\"unset\"\n hasCloseButton\n isScrollable\n padding=\"sm\"\n >\n {isModalOpen && src ? (\n <Container\n roundedSize=\"2xl\"\n border\n borderColor=\"neutral\"\n className=\"overflow-hidden p-0\"\n gap=\"none\"\n >\n <iframe\n {...rest}\n src={src}\n title={title ?? 'Embedded content'}\n allowFullScreen\n className=\"block min-h-[82vh] w-full border-0\"\n />\n </Container>\n ) : null}\n </Modal>\n </Container>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MarkDownIframe.mjs","names":[],"sources":["../../../../src/components/MarkDownRender/MarkDownIframe.tsx"],"sourcesContent":["'use client';\n\nimport { Button } from '@components/Button';\nimport { Container } from '@components/Container';\nimport { Link } from '@components/Link';\nimport { Modal } from '@components/Modal';\nimport { cn } from '@utils/cn';\nimport { MoveDiagonal } from 'lucide-react';\nimport {\n type ComponentProps,\n type FC,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport {\n getYoutubeEmbedUrl,\n getYoutubeVideoId,\n getYoutubeWatchUrl,\n} from './youtubeUrl';\n\ntype FrameProps = Omit<ComponentProps<'iframe'>, 'src' | 'title' | 'className'>;\n\n/**\n * The features the YouTube player asks for, as shipped by YouTube's own embed code.\n */\nconst YOUTUBE_PLAYER_ALLOW =\n 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share';\n\ntype ResolvedFrame = {\n src: string | undefined;\n frameProps: FrameProps;\n isYoutubeVideo: boolean;\n};\n\n/**\n * Turns whatever the markdown handed over into what the frame is rendered with.\n *\n * A YouTube address, in any of its forms, becomes the player embed carrying\n * the attributes YouTube's own embed code ships with. Query parameters are\n * dropped on purpose: docs written for one origin (`origin=…`) break the\n * player on every other one.\n *\n * `referrerPolicy` is the attribute that matters: the player refuses to start\n * (\"Video player configuration error\", error 153) unless the request carries\n * a referrer, and a page served with `Referrer-Policy: same-origin` sends none\n * to a cross-origin frame. The attribute overrides the page policy for this\n * frame only.\n */\nconst resolveFrame = (\n src: string | undefined,\n frameProps: FrameProps\n): ResolvedFrame => {\n const youtubeVideoId = getYoutubeVideoId(src);\n\n if (!youtubeVideoId) return { src, frameProps, isYoutubeVideo: false };\n\n return {\n isYoutubeVideo: true,\n src: getYoutubeEmbedUrl(youtubeVideoId),\n frameProps: {\n ...frameProps,\n allow: YOUTUBE_PLAYER_ALLOW,\n allowFullScreen: true,\n referrerPolicy: 'strict-origin-when-cross-origin',\n },\n };\n};\n\nconst getEmbedLinkMeta = (\n src: string | undefined\n): { href: string; label: string } => {\n if (!src) return { href: '', label: '' };\n\n const youtubeVideoId = getYoutubeVideoId(src);\n if (youtubeVideoId) {\n return {\n href: getYoutubeWatchUrl(youtubeVideoId),\n label: 'youtube.com',\n };\n }\n\n if (/^https?:\\/\\//i.test(src)) {\n try {\n const url = new URL(src);\n return { href: url.href, label: url.host };\n } catch {\n return { href: src, label: src };\n }\n }\n\n return { href: src, label: src };\n};\n\n/**\n * Tracks whether an element has come close enough to the viewport to be worth\n * loading.\n *\n * `loading=\"lazy\"` is not enough for embeds inside tabs or carousels: the\n * browser only defers frames that are far down the page, so a frame parked\n * off-screen by a transform — an inactive tab panel — still loads immediately.\n * A live-app embed costs upwards of a megabyte and seconds of main thread,\n * which is the whole page's performance budget spent on something nobody is\n * looking at.\n *\n * @returns A ref to attach to the placeholder, and whether it became visible.\n */\nconst useHasBecomeVisible = <ElementType extends HTMLElement>() => {\n const elementRef = useRef<ElementType>(null);\n const [hasBecomeVisible, setHasBecomeVisible] = useState(false);\n\n useEffect(() => {\n const element = elementRef.current;\n if (!element || hasBecomeVisible) return;\n\n if (typeof IntersectionObserver === 'undefined') {\n setHasBecomeVisible(true);\n return;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n setHasBecomeVisible(true);\n observer.disconnect();\n }\n },\n { rootMargin: '200px' }\n );\n\n observer.observe(element);\n\n return () => observer.disconnect();\n }, [hasBecomeVisible]);\n\n return { elementRef, hasBecomeVisible };\n};\n\ntype EmbeddedFrameProps = Pick<ResolvedFrame, 'src' | 'frameProps'> & {\n title: string | undefined;\n className: string;\n};\n\n/**\n * The embed itself, mounted once it comes close to the viewport.\n */\nconst EmbeddedFrame: FC<EmbeddedFrameProps> = ({\n src,\n title,\n className,\n frameProps,\n}) => {\n const { elementRef, hasBecomeVisible } =\n useHasBecomeVisible<HTMLDivElement>();\n\n if (!hasBecomeVisible) {\n // Same box as the frame it stands in for, so nothing shifts once it loads.\n return <div ref={elementRef} aria-hidden className={className} />;\n }\n\n return (\n <iframe\n {...frameProps}\n src={src}\n title={title}\n loading=\"lazy\"\n className={className}\n />\n );\n};\n\nexport const MarkDownIframe: FC<ComponentProps<'iframe'>> = (props) => {\n const { src: rawSrc, className, title, ...rest } = props;\n const [isModalOpen, setIsModalOpen] = useState(false);\n const { src, frameProps, isYoutubeVideo } = resolveFrame(rawSrc, rest);\n const { href, label } = getEmbedLinkMeta(rawSrc);\n\n return (\n <Container\n roundedSize=\"2xl\"\n border\n borderColor=\"neutral\"\n className=\"overflow-hidden p-0\"\n gap=\"none\"\n >\n <EmbeddedFrame\n src={src}\n title={title}\n frameProps={frameProps}\n className={cn(\n 'block max-h-[80vh] min-h-[12rem] w-full border-0',\n isYoutubeVideo && 'aspect-video',\n className\n )}\n />\n <div className=\"flex items-center justify-between gap-3 px-3 py-1\">\n {href ? (\n <Link\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n label=\"\"\n color=\"neutral\"\n className=\"inline-flex min-w-0 max-w-[calc(100%-3rem)] items-center gap-2 text-muted-foreground text-xs underline-offset-2 hover:text-foreground hover:underline\"\n >\n {label}\n </Link>\n ) : (\n <span className=\"text-neutral text-sm\">Embedded frame</span>\n )}\n <Button\n variant=\"hoverable\"\n size=\"icon-md\"\n onClick={() => setIsModalOpen(true)}\n label=\"Open embedded page in fullscreen\"\n Icon={MoveDiagonal}\n />\n </div>\n\n <Modal\n isOpen={isModalOpen}\n onClose={() => setIsModalOpen(false)}\n size=\"unset\"\n hasCloseButton\n isScrollable\n padding=\"sm\"\n >\n {isModalOpen && src ? (\n <Container\n roundedSize=\"2xl\"\n border\n borderColor=\"neutral\"\n className=\"overflow-hidden p-0\"\n gap=\"none\"\n >\n <iframe\n {...frameProps}\n src={src}\n title={title ?? 'Embedded content'}\n allowFullScreen\n className=\"block min-h-[82vh] w-full border-0\"\n />\n </Container>\n ) : null}\n </Modal>\n </Container>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
+
import { getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl } from "./youtubeUrl.mjs";
|
|
1
2
|
import { MarkDownIframe } from "./MarkDownIframe.mjs";
|
|
2
3
|
import { MarkdownRenderer, baseMarkdownComponents, getIntlayerMarkdownOptions } from "./MarkDownRender.mjs";
|
|
3
4
|
|
|
4
|
-
export { MarkDownIframe, MarkdownRenderer, baseMarkdownComponents, getIntlayerMarkdownOptions };
|
|
5
|
+
export { MarkDownIframe, MarkdownRenderer, baseMarkdownComponents, getIntlayerMarkdownOptions, getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/components/MarkDownRender/youtubeUrl.ts
|
|
2
|
+
/**
|
|
3
|
+
* Reads the video id out of a YouTube address (embed, watch, youtu.be, shorts, etc.).
|
|
4
|
+
*
|
|
5
|
+
* @returns The video id, or `null` when the address is not a YouTube URL.
|
|
6
|
+
*/
|
|
7
|
+
const getYoutubeVideoId = (src) => {
|
|
8
|
+
if (!src) return null;
|
|
9
|
+
return src.match(/(?:youtu\.be\/|youtube(?:-nocookie)?\.com\/(?:embed\/|v\/|watch\?v=|shorts\/))([\w-]{11})/i)?.[1] ?? null;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* The address the YouTube player is loaded from for a given video.
|
|
13
|
+
*/
|
|
14
|
+
const getYoutubeEmbedUrl = (videoId) => `https://www.youtube.com/embed/${videoId}`;
|
|
15
|
+
/**
|
|
16
|
+
* The address of the video on youtube.com itself.
|
|
17
|
+
*/
|
|
18
|
+
const getYoutubeWatchUrl = (videoId) => `https://www.youtube.com/watch?v=${videoId}`;
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl };
|
|
22
|
+
//# sourceMappingURL=youtubeUrl.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"youtubeUrl.mjs","names":[],"sources":["../../../../src/components/MarkDownRender/youtubeUrl.ts"],"sourcesContent":["/**\n * Reads the video id out of a YouTube address (embed, watch, youtu.be, shorts, etc.).\n *\n * @returns The video id, or `null` when the address is not a YouTube URL.\n */\nexport const getYoutubeVideoId = (src: string | undefined): string | null => {\n if (!src) return null;\n\n const match = src.match(\n /(?:youtu\\.be\\/|youtube(?:-nocookie)?\\.com\\/(?:embed\\/|v\\/|watch\\?v=|shorts\\/))([\\w-]{11})/i\n );\n\n return match?.[1] ?? null;\n};\n\n/**\n * The address the YouTube player is loaded from for a given video.\n */\nexport const getYoutubeEmbedUrl = (videoId: string): string =>\n `https://www.youtube.com/embed/${videoId}`;\n\n/**\n * The address of the video on youtube.com itself.\n */\nexport const getYoutubeWatchUrl = (videoId: string): string =>\n `https://www.youtube.com/watch?v=${videoId}`;\n"],"mappings":";;;;;;AAKA,MAAa,qBAAqB,QAA2C;CAC3E,IAAI,CAAC,KAAK,OAAO;CAMjB,OAJc,IAAI,MAChB,4FAGS,CAAC,GAAG,MAAM;AACvB;;;;AAKA,MAAa,sBAAsB,YACjC,iCAAiC;;;;AAKnC,MAAa,sBAAsB,YACjC,mCAAmC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
-
import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
|
|
5
|
-
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
6
4
|
import { Button } from "../Button/Button.mjs";
|
|
7
5
|
import { Container } from "../Container/index.mjs";
|
|
6
|
+
import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
|
|
7
|
+
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
8
8
|
import { H3 } from "../Headers/index.mjs";
|
|
9
9
|
import { useEffect } from "react";
|
|
10
10
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
+
import { MaxHeightSmoother } from "../MaxHeightSmoother/index.mjs";
|
|
4
5
|
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
5
6
|
import { useScrollDetection } from "../../hooks/useScrollDetection.mjs";
|
|
6
|
-
import { MaxHeightSmoother } from "../MaxHeightSmoother/index.mjs";
|
|
7
7
|
import { Burger } from "./Burger.mjs";
|
|
8
8
|
import { useEffect, useRef, useState } from "react";
|
|
9
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
-
import { useItemSelector } from "../../hooks/useItemSelector.mjs";
|
|
5
4
|
import { Button } from "../Button/Button.mjs";
|
|
5
|
+
import { useItemSelector } from "../../hooks/useItemSelector.mjs";
|
|
6
6
|
import { useEffect, useRef } from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { cva } from "class-variance-authority";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
|
|
4
|
-
import { useDevice } from "../../hooks/useDevice.mjs";
|
|
5
|
-
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
6
3
|
import { Button } from "../Button/Button.mjs";
|
|
7
4
|
import { Container } from "../Container/index.mjs";
|
|
5
|
+
import { useDevice } from "../../hooks/useDevice.mjs";
|
|
8
6
|
import { KeyboardShortcut } from "../KeyboardShortcut/KeyboardShortcut.mjs";
|
|
9
7
|
import { Popover } from "../Popover/dynamic.mjs";
|
|
8
|
+
import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
|
|
9
|
+
import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
|
|
10
10
|
import { MaxWidthSmoother } from "../MaxWidthSmoother/index.mjs";
|
|
11
11
|
import { isElementAtTopAndNotCovered } from "./isElementAtTopAndNotCovered.mjs";
|
|
12
12
|
import { useIsRightDrawerOpen, useRightDrawerActions } from "./useRightDrawer.mjs";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
-
import { useHorizontalSwipe } from "../../hooks/useHorizontalSwipe.mjs";
|
|
5
4
|
import { TabSelector } from "../TabSelector/TabSelector.mjs";
|
|
5
|
+
import { useHorizontalSwipe } from "../../hooks/useHorizontalSwipe.mjs";
|
|
6
6
|
import { useTabContext } from "./TabContext.mjs";
|
|
7
7
|
import { Children, createContext, isValidElement, useState } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -115,6 +115,7 @@ import { KeyboardScreenAdapter } from "./KeyboardScreenAdapter/index.mjs";
|
|
|
115
115
|
import { LanguageBackground } from "./LanguageBackground/LanguageBackground.mjs";
|
|
116
116
|
import { LanguageSection, LocalCardList } from "./LanguageBackground/LanguageSection.mjs";
|
|
117
117
|
import { LocaleSwitcher } from "./LocaleSwitcherDropDown/LocaleSwitcher.mjs";
|
|
118
|
+
import { getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl } from "./MarkDownRender/youtubeUrl.mjs";
|
|
118
119
|
import { MarkDownIframe } from "./MarkDownRender/MarkDownIframe.mjs";
|
|
119
120
|
import { Tab } from "./Tab/Tab.mjs";
|
|
120
121
|
import { Table } from "./Table/Table.mjs";
|
|
@@ -142,4 +143,4 @@ import { Terminal } from "./Terminal/Terminal.mjs";
|
|
|
142
143
|
import { DesktopThemeSwitcher } from "./ThemeSwitcherDropDown/DesktopThemeSwitcher.mjs";
|
|
143
144
|
import { MobileThemeSwitcher } from "./ThemeSwitcherDropDown/MobileThemeSwitcher.mjs";
|
|
144
145
|
|
|
145
|
-
export { Accordion, AutoCompleteTextarea, AutoSizedTextArea, Avatar, Badge, BitbucketLogo, Breadcrumb, Browser, Burger, Button, Carousel, Checkbox, ClickOutsideDiv, Code, CodeBlock, CodeDefault, CodeHighlighted, CollapsibleTable, Command, CommandRoot, Container, ContentEditableTextArea, ContentEditor, ContentEditorInput, ContentEditorTextArea, ContentSelector, CopyButton, CopyToClipboard, DesktopNavbar, DesktopThemeSwitcher, Detail, DictionaryCreationForm, DictionaryEditor, DictionaryFieldEditor, DiscordLogo, DotPattern, DropDown, EditableFieldInput, EditableFieldTextArea, ExpandCollapse, FacebookLogo, FileList, Flag, flags_exports as Flags, Footer, Form, AutoSizedTextAreaElement as FormAutoSizedTextArea, Button as FormButton, CheckboxElement as FormCheckbox, FormControl, FormDescription, EditableFieldInputElement as FormEditableFieldInput, EditableFieldTextAreaElement as FormEditableFieldTextArea, FormElement, FormField, InputElement as FormInput, InputPasswordElement as FormInputPassword, FormItem, FormLabelLayout as FormLabel, FormMessage, MultiSelectElement as FormMultiSelect, OTPElement as FormOTP, SearchInputElement as FormSearchInput, SelectElement as FormSelect, SwitchSelectorElement as FormSwitchSelector, TextAreaElement as FormTextArea, GitHubLogo, GitLabLogo, GoogleLogo, GridDistortionPattern, GridPattern, H1, H2, H3, H4, H5, H6, HTMLRenderer, HeightResizer, HideShow, Hr, IDE, InformationTag, Input, InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, InputPassword, InstagramLogo, KeyPathBreadcrumb, KeyboardScreenAdapter, KeyboardShortcut, Label, LanguageBackground, LanguageSection, Link, LinkedInLogo, Loader, LocalCardList, LocaleSwitcher, LocaleSwitcherContent, LocaleSwitcherContentProvider, Logo, LogoTextOnly, LogoWithText, LogoWithTextBelow, MarkDownIframe, MarkdownEditor, MarkdownRenderer, MaxHeightSmoother, MaxWidthSmoother, MobileNavbar, MobileThemeSwitcher, Modal, MultiSelect, Navbar, NodeEditor, NumberItemsSelector, OTPInput, OTPInputContext, Pagination, Popover, PopoverStatic, PressableSpan, ProductHuntLogo, Radio, RightDrawer, SaveForm, SearchInput, Select, SelectContent, SelectLabel, SelectSeparator, ShowingResultsNumberItems, SmartTable, SocialNetworks, Spotlight, Step, Steps, SwitchSelector, Tab, TabSelector, Table, Tag, Td, TechLogo, techLogos_exports as TechLogos, Terminal, TextArea, TextEditor, TextEditorContainer, Th, TiktokLogo, Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, Tr, VersionSwitcher, VersionSwitcherProvider, VerticalSwitchSelector, WithResizer, XLogo, YoutubeLogo, badgeVariants, baseMarkdownComponents, buttonVariants, checkIsExternalLink, checkboxVariants, choiceVariant, containerVariants, createEditorUploadFn, defaultChoices, drawerManager, getCapitals, getIntlayerHTMLOptions, getIntlayerMarkdownOptions, indicatorVariant, inputSlotVariants, inputVariants, isTextChildren, linkVariants, paginationVariants, radioVariants, reducer, shikiWrapperClassName, switchSelectorVariant, toast, toastVariants, traceKeys, useContentEditable, useCopyToClipboard, useForm, useFormField, useIsRightDrawerOpen, useLocaleSwitcherContent, usePasswordManagerBadge, usePopoverIds, usePrevious, useRightDrawer, useRightDrawerActions, useToast, useVersionSwitcher };
|
|
146
|
+
export { Accordion, AutoCompleteTextarea, AutoSizedTextArea, Avatar, Badge, BitbucketLogo, Breadcrumb, Browser, Burger, Button, Carousel, Checkbox, ClickOutsideDiv, Code, CodeBlock, CodeDefault, CodeHighlighted, CollapsibleTable, Command, CommandRoot, Container, ContentEditableTextArea, ContentEditor, ContentEditorInput, ContentEditorTextArea, ContentSelector, CopyButton, CopyToClipboard, DesktopNavbar, DesktopThemeSwitcher, Detail, DictionaryCreationForm, DictionaryEditor, DictionaryFieldEditor, DiscordLogo, DotPattern, DropDown, EditableFieldInput, EditableFieldTextArea, ExpandCollapse, FacebookLogo, FileList, Flag, flags_exports as Flags, Footer, Form, AutoSizedTextAreaElement as FormAutoSizedTextArea, Button as FormButton, CheckboxElement as FormCheckbox, FormControl, FormDescription, EditableFieldInputElement as FormEditableFieldInput, EditableFieldTextAreaElement as FormEditableFieldTextArea, FormElement, FormField, InputElement as FormInput, InputPasswordElement as FormInputPassword, FormItem, FormLabelLayout as FormLabel, FormMessage, MultiSelectElement as FormMultiSelect, OTPElement as FormOTP, SearchInputElement as FormSearchInput, SelectElement as FormSelect, SwitchSelectorElement as FormSwitchSelector, TextAreaElement as FormTextArea, GitHubLogo, GitLabLogo, GoogleLogo, GridDistortionPattern, GridPattern, H1, H2, H3, H4, H5, H6, HTMLRenderer, HeightResizer, HideShow, Hr, IDE, InformationTag, Input, InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, InputPassword, InstagramLogo, KeyPathBreadcrumb, KeyboardScreenAdapter, KeyboardShortcut, Label, LanguageBackground, LanguageSection, Link, LinkedInLogo, Loader, LocalCardList, LocaleSwitcher, LocaleSwitcherContent, LocaleSwitcherContentProvider, Logo, LogoTextOnly, LogoWithText, LogoWithTextBelow, MarkDownIframe, MarkdownEditor, MarkdownRenderer, MaxHeightSmoother, MaxWidthSmoother, MobileNavbar, MobileThemeSwitcher, Modal, MultiSelect, Navbar, NodeEditor, NumberItemsSelector, OTPInput, OTPInputContext, Pagination, Popover, PopoverStatic, PressableSpan, ProductHuntLogo, Radio, RightDrawer, SaveForm, SearchInput, Select, SelectContent, SelectLabel, SelectSeparator, ShowingResultsNumberItems, SmartTable, SocialNetworks, Spotlight, Step, Steps, SwitchSelector, Tab, TabSelector, Table, Tag, Td, TechLogo, techLogos_exports as TechLogos, Terminal, TextArea, TextEditor, TextEditorContainer, Th, TiktokLogo, Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, Tr, VersionSwitcher, VersionSwitcherProvider, VerticalSwitchSelector, WithResizer, XLogo, YoutubeLogo, badgeVariants, baseMarkdownComponents, buttonVariants, checkIsExternalLink, checkboxVariants, choiceVariant, containerVariants, createEditorUploadFn, defaultChoices, drawerManager, getCapitals, getIntlayerHTMLOptions, getIntlayerMarkdownOptions, getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl, indicatorVariant, inputSlotVariants, inputVariants, isTextChildren, linkVariants, paginationVariants, radioVariants, reducer, shikiWrapperClassName, switchSelectorVariant, toast, toastVariants, traceKeys, useContentEditable, useCopyToClipboard, useForm, useFormField, useIsRightDrawerOpen, useLocaleSwitcherContent, usePasswordManagerBadge, usePopoverIds, usePrevious, useRightDrawer, useRightDrawerActions, useToast, useVersionSwitcher };
|
package/dist/esm/hooks/index.mjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { useScrollY } from "./useScrollY.mjs";
|
|
1
|
+
import { calculateIsMobile, checkIsIOS, checkIsIphoneOrSafariDevice, checkIsMac, checkIsMobileScreen, checkIsMobileUserAgent, getBreakpointFromSize, useDevice } from "./useDevice.mjs";
|
|
2
|
+
import { useItemSelector } from "./useItemSelector.mjs";
|
|
4
3
|
import { usePersistedStore } from "./usePersistedStore.mjs";
|
|
4
|
+
import { useGetElementById } from "./useGetElementById.mjs";
|
|
5
|
+
import { useGetElementOrWindow } from "./useGetElementOrWindow.mjs";
|
|
5
6
|
import { useHorizontalSwipe } from "./useHorizontalSwipe.mjs";
|
|
6
|
-
import { useItemSelector } from "./useItemSelector.mjs";
|
|
7
|
-
import { NO_HIGHLIGHTED_INDEX, useListKeyboardNavigation } from "./useListKeyboardNavigation.mjs";
|
|
8
|
-
import { calculateIsMobile, checkIsIOS, checkIsIphoneOrSafariDevice, checkIsMac, checkIsMobileScreen, checkIsMobileUserAgent, getBreakpointFromSize, useDevice } from "./useDevice.mjs";
|
|
9
|
-
import { useSearch } from "./useSearch.mjs";
|
|
10
7
|
import { useIsMounted } from "./useIsMounted.mjs";
|
|
11
|
-
import {
|
|
8
|
+
import { useKeyboardDetector } from "./useKeyboardDetector.mjs";
|
|
9
|
+
import { NO_HIGHLIGHTED_INDEX, useListKeyboardNavigation } from "./useListKeyboardNavigation.mjs";
|
|
12
10
|
import { useScreenWidth } from "./useScreenWidth.mjs";
|
|
13
11
|
import { useScrollBlockage } from "./useScrollBlockage/index.mjs";
|
|
14
12
|
import { useScrollDetection } from "./useScrollDetection.mjs";
|
|
13
|
+
import { useScrollY } from "./useScrollY.mjs";
|
|
14
|
+
import { useSearch } from "./useSearch.mjs";
|
|
15
15
|
import { useStickToBottom } from "./useStickToBottom.mjs";
|
|
16
16
|
|
|
17
17
|
export { NO_HIGHLIGHTED_INDEX, calculateIsMobile, checkIsIOS, checkIsIphoneOrSafariDevice, checkIsMac, checkIsMobileScreen, checkIsMobileUserAgent, getBreakpointFromSize, useDevice, useGetElementById, useGetElementOrWindow, useHorizontalSwipe, useIsMounted, useItemSelector, useKeyboardDetector, useListKeyboardNavigation, usePersistedStore, useScreenWidth, useScrollBlockage, useScrollDetection, useScrollY, useSearch, useStickToBottom };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkDownIframe.d.ts","names":[],"sources":["../../../../src/components/MarkDownRender/MarkDownIframe.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"MarkDownIframe.d.ts","names":[],"sources":["../../../../src/components/MarkDownRender/MarkDownIframe.tsx"],"mappings":";;qBA2Ka,gBAAgB,GAAG"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { MarkDownIframe } from "./MarkDownIframe.js";
|
|
2
|
+
import { getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl } from "./youtubeUrl.js";
|
|
2
3
|
import { MarkdownRenderer, ParsedMarkdown, baseMarkdownComponents, getIntlayerMarkdownOptions } from "./MarkDownRender.js";
|
|
3
|
-
export { MarkDownIframe, MarkdownRenderer, type ParsedMarkdown, baseMarkdownComponents, getIntlayerMarkdownOptions };
|
|
4
|
+
export { MarkDownIframe, MarkdownRenderer, type ParsedMarkdown, baseMarkdownComponents, getIntlayerMarkdownOptions, getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/components/MarkDownRender/youtubeUrl.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Reads the video id out of a YouTube address (embed, watch, youtu.be, shorts, etc.).
|
|
4
|
+
*
|
|
5
|
+
* @returns The video id, or `null` when the address is not a YouTube URL.
|
|
6
|
+
*/
|
|
7
|
+
export declare const getYoutubeVideoId: (src: string | undefined) => string | null;
|
|
8
|
+
/**
|
|
9
|
+
* The address the YouTube player is loaded from for a given video.
|
|
10
|
+
*/
|
|
11
|
+
export declare const getYoutubeEmbedUrl: (videoId: string) => string;
|
|
12
|
+
/**
|
|
13
|
+
* The address of the video on youtube.com itself.
|
|
14
|
+
*/
|
|
15
|
+
export declare const getYoutubeWatchUrl: (videoId: string) => string;
|
|
16
|
+
//#endregion
|
|
17
|
+
//# sourceMappingURL=youtubeUrl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"youtubeUrl.d.ts","names":[],"sources":["../../../../src/components/MarkDownRender/youtubeUrl.ts"],"mappings":";;;;;;qBAKa,oBAAiB;;;;qBAajB,qBAAkB;;;;qBAMlB,qBAAkB"}
|
|
@@ -114,6 +114,7 @@ import { LogoWithText } from "./Logo/LogoWithText.js";
|
|
|
114
114
|
import { LogoWithTextBelow } from "./Logo/LogoWithTextBelow.js";
|
|
115
115
|
import "./Logo/index.js";
|
|
116
116
|
import { MarkDownIframe } from "./MarkDownRender/MarkDownIframe.js";
|
|
117
|
+
import { getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl } from "./MarkDownRender/youtubeUrl.js";
|
|
117
118
|
import "./MarkDownRender/index.js";
|
|
118
119
|
import { CreateEditorUploadFnOptions, UploadImageFn, createEditorUploadFn } from "./MarkdownEditor/imageUpload.js";
|
|
119
120
|
import { MarkdownEditor, MarkdownEditorProps } from "./MarkdownEditor/MarkdownEditor.js";
|
|
@@ -183,4 +184,4 @@ import { reducer, toast, useToast } from "./Toaster/useToast.js";
|
|
|
183
184
|
import "./Toaster/index.js";
|
|
184
185
|
import { WithResizer } from "./WithResizer/index.js";
|
|
185
186
|
import { MarkdownRenderer, ParsedMarkdown, baseMarkdownComponents, getIntlayerMarkdownOptions } from "./MarkDownRender/MarkDownRender.js";
|
|
186
|
-
export { Accordion, AccordionProps, AutoCompleteTextarea, AutoSizedTextArea, AutoSizedTextAreaProps, AutocompleteTextAreaProps, Avatar, AvatarProps, Badge, BadgeColor, BadgeProps, BadgeSize, BadgeVariant, BadgeVariantProps, BitbucketLogo, Breadcrumb, BreadcrumbLink, BreadcrumbProps, Browser, BrowserProps, Burger, Button, ButtonColor, ButtonProps, ButtonSize, ButtonTextAlign, ButtonVariant, Carousel, Checkbox, CheckboxColor, CheckboxProps, CheckboxSize, ClickOutsideDiv, ClickOutsideDivProps, Code, CodeBlock, CodeBlockProps, CodeCompAttributes, CodeDefault, CodeHighlighted, type CodeLanguage, CollapsibleTable, CollapsibleTableProps, Command, CommandRoot, Container, ContainerBackground, ContainerBorderColor, ContainerGap, ContainerPadding, ContainerProps, ContainerRoundedSize, ContainerSeparator, ContainerTransparency, ContentEditableTextArea, ContentEditableTextAreaHandle, ContentEditableTextAreaProps, ContentEditor, ContentEditorInput, ContentEditorInputProps, ContentEditorProps, ContentEditorTextArea, ContentEditorTextAreaProps, ContentSelector, CopyButton, CopyToClipboard, CopyToClipboardProps, type CreateEditorUploadFnOptions, DesktopNavbar, DesktopThemeSwitcher, Detail, DetailProps, DictionaryCreationForm, DictionaryEditor, DictionaryFieldEditor, DiscordLogo, DotPattern, DropDown, DropDownAlign, DropDownProps, DropDownType, DropDownYAlign, EditableFieldInput, EditableFieldTextArea, ExpandCollapse, ExpandCollapseProps, FacebookLogo, FileList, FileListProps, Flag, flags_d_exports as Flags, Footer, FooterLink, Form, AutoSizedTextAreaElement as FormAutoSizedTextArea, Button as FormButton, CheckboxElement as FormCheckbox, FormControl, FormDescription, EditableFieldInputElement as FormEditableFieldInput, EditableFieldTextAreaElement as FormEditableFieldTextArea, FormElement, FormField, InputElement as FormInput, InputPasswordElement as FormInputPassword, FormItem, FormLabelLayout as FormLabel, FormMessage, MultiSelectElement as FormMultiSelect, OTPElement as FormOTP, SearchInputElement as FormSearchInput, SelectElement as FormSelect, SwitchSelectorElement as FormSwitchSelector, TextAreaElement as FormTextArea, GitHubLogo, GitLabLogo, GoogleLogo, GridDistortionPattern, GridPattern, H1, H2, H3, H4, H5, H6, HTMLRenderer, HeadingProps, HeightResizer, HideShow, HideShowProps, Hr, IDE, IDEProps, InformationTag, Input, InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, InputPassword, InputProps, InputSize, InputVariant, InstagramLogo, KeyList, KeyPathBreadcrumb, KeyboardScreenAdapter, KeyboardShortcut, KeyboardShortcutProps, KeyboardShortcutType, Label, LabelProps, LanguageBackground, LanguageSection, Link, LinkColor, LinkGroup, LinkProps, LinkRoundedSize, LinkSize, LinkUnderlined, LinkVariant, LinkedInLogo, Loader, LoaderProps, LocalCardList, LocaleSwitcher, LocaleSwitcherContent, LocaleSwitcherContentProps, LocaleSwitcherContentProvider, LocaleSwitcherProps, Logo, LogoTextOnly, LogoWithText, LogoWithTextBelow, MarkDownIframe, MarkdownEditor, type MarkdownEditorProps, MarkdownRenderer, MaxHeightSmoother, MaxWidthSmoother, MobileNavbar, MobileThemeSwitcher, Modal, ModalSize, Modes, MultiSelect, Navbar, NodeEditor, NodeEditorProps, NumberItemsSelector, NumberItemsSelectorProps, OTPInput, OTPInputContext, OTPInputProps, Pagination, PaginationProps, PaginationSize, PaginationVariant, PanelProps, type ParsedMarkdown, Popover, PopoverProps, PopoverStatic, PopoverType, PopoverXAlign, PopoverYAlign, PressableSpan, ProductHuntLogo, Radio, RadioColor, RadioProps, RadioSize, RenderProps, RightDrawer, SaveForm, SearchInput, Select, SelectContent, SelectContentPosition, SelectLabel, SelectSeparator, ShowingResultsNumberItems, ShowingResultsNumberItemsProps, SlotProps, SmartTable, SocialNetworks, Spotlight, Step, Steps, SwitchSelector, SwitchSelectorBaseProps, SwitchSelectorChoice, SwitchSelectorChoices, SwitchSelectorColor, SwitchSelectorProps, SwitchSelectorSize, Tab, TabItemProps, TabProps, TabSelector, TabSelectorColor, TabSelectorItemProps, TabSelectorProps, Table, TableProps, Tag, TagBackground, TagBorder, TagColor, TagRoundedSize, TagSize, Td, TechLogo, type TechLogoName, techLogos_d_exports as TechLogos, Terminal, TerminalProps, TextArea, TextAreaProps, TextEditor, TextEditorContainer, TextEditorProps, Th, TiktokLogo, Toast, ToastAction, ToastActionElement, ToastClose, ToastDescription, ToastProps, ToastProvider, ToastTitle, ToastViewport, Toaster, Tr, TriggerProps, type UploadImageFn, VersionSwitcher, VersionSwitcherProps, VersionSwitcherProvider, VerticalSwitchSelector, VerticalSwitchSelectorProps, WithResizer, XLogo, YoutubeLogo, badgeVariants, baseMarkdownComponents, buttonVariants, checkIsExternalLink, checkboxVariants, choiceVariant, containerVariants, createEditorUploadFn, defaultChoices, drawerManager, getCapitals, getIntlayerHTMLOptions, getIntlayerMarkdownOptions, indicatorVariant, inputSlotVariants, inputVariants, isTextChildren, linkVariants, paginationVariants, radioVariants, reducer, shikiWrapperClassName, switchSelectorVariant, toast, toastVariants, traceKeys, useContentEditable, useCopyToClipboard, useForm, useFormField, useIsRightDrawerOpen, useLocaleSwitcherContent, usePasswordManagerBadge, usePopoverIds, usePrevious, useRightDrawer, useRightDrawerActions, useToast, useVersionSwitcher };
|
|
187
|
+
export { Accordion, AccordionProps, AutoCompleteTextarea, AutoSizedTextArea, AutoSizedTextAreaProps, AutocompleteTextAreaProps, Avatar, AvatarProps, Badge, BadgeColor, BadgeProps, BadgeSize, BadgeVariant, BadgeVariantProps, BitbucketLogo, Breadcrumb, BreadcrumbLink, BreadcrumbProps, Browser, BrowserProps, Burger, Button, ButtonColor, ButtonProps, ButtonSize, ButtonTextAlign, ButtonVariant, Carousel, Checkbox, CheckboxColor, CheckboxProps, CheckboxSize, ClickOutsideDiv, ClickOutsideDivProps, Code, CodeBlock, CodeBlockProps, CodeCompAttributes, CodeDefault, CodeHighlighted, type CodeLanguage, CollapsibleTable, CollapsibleTableProps, Command, CommandRoot, Container, ContainerBackground, ContainerBorderColor, ContainerGap, ContainerPadding, ContainerProps, ContainerRoundedSize, ContainerSeparator, ContainerTransparency, ContentEditableTextArea, ContentEditableTextAreaHandle, ContentEditableTextAreaProps, ContentEditor, ContentEditorInput, ContentEditorInputProps, ContentEditorProps, ContentEditorTextArea, ContentEditorTextAreaProps, ContentSelector, CopyButton, CopyToClipboard, CopyToClipboardProps, type CreateEditorUploadFnOptions, DesktopNavbar, DesktopThemeSwitcher, Detail, DetailProps, DictionaryCreationForm, DictionaryEditor, DictionaryFieldEditor, DiscordLogo, DotPattern, DropDown, DropDownAlign, DropDownProps, DropDownType, DropDownYAlign, EditableFieldInput, EditableFieldTextArea, ExpandCollapse, ExpandCollapseProps, FacebookLogo, FileList, FileListProps, Flag, flags_d_exports as Flags, Footer, FooterLink, Form, AutoSizedTextAreaElement as FormAutoSizedTextArea, Button as FormButton, CheckboxElement as FormCheckbox, FormControl, FormDescription, EditableFieldInputElement as FormEditableFieldInput, EditableFieldTextAreaElement as FormEditableFieldTextArea, FormElement, FormField, InputElement as FormInput, InputPasswordElement as FormInputPassword, FormItem, FormLabelLayout as FormLabel, FormMessage, MultiSelectElement as FormMultiSelect, OTPElement as FormOTP, SearchInputElement as FormSearchInput, SelectElement as FormSelect, SwitchSelectorElement as FormSwitchSelector, TextAreaElement as FormTextArea, GitHubLogo, GitLabLogo, GoogleLogo, GridDistortionPattern, GridPattern, H1, H2, H3, H4, H5, H6, HTMLRenderer, HeadingProps, HeightResizer, HideShow, HideShowProps, Hr, IDE, IDEProps, InformationTag, Input, InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, InputPassword, InputProps, InputSize, InputVariant, InstagramLogo, KeyList, KeyPathBreadcrumb, KeyboardScreenAdapter, KeyboardShortcut, KeyboardShortcutProps, KeyboardShortcutType, Label, LabelProps, LanguageBackground, LanguageSection, Link, LinkColor, LinkGroup, LinkProps, LinkRoundedSize, LinkSize, LinkUnderlined, LinkVariant, LinkedInLogo, Loader, LoaderProps, LocalCardList, LocaleSwitcher, LocaleSwitcherContent, LocaleSwitcherContentProps, LocaleSwitcherContentProvider, LocaleSwitcherProps, Logo, LogoTextOnly, LogoWithText, LogoWithTextBelow, MarkDownIframe, MarkdownEditor, type MarkdownEditorProps, MarkdownRenderer, MaxHeightSmoother, MaxWidthSmoother, MobileNavbar, MobileThemeSwitcher, Modal, ModalSize, Modes, MultiSelect, Navbar, NodeEditor, NodeEditorProps, NumberItemsSelector, NumberItemsSelectorProps, OTPInput, OTPInputContext, OTPInputProps, Pagination, PaginationProps, PaginationSize, PaginationVariant, PanelProps, type ParsedMarkdown, Popover, PopoverProps, PopoverStatic, PopoverType, PopoverXAlign, PopoverYAlign, PressableSpan, ProductHuntLogo, Radio, RadioColor, RadioProps, RadioSize, RenderProps, RightDrawer, SaveForm, SearchInput, Select, SelectContent, SelectContentPosition, SelectLabel, SelectSeparator, ShowingResultsNumberItems, ShowingResultsNumberItemsProps, SlotProps, SmartTable, SocialNetworks, Spotlight, Step, Steps, SwitchSelector, SwitchSelectorBaseProps, SwitchSelectorChoice, SwitchSelectorChoices, SwitchSelectorColor, SwitchSelectorProps, SwitchSelectorSize, Tab, TabItemProps, TabProps, TabSelector, TabSelectorColor, TabSelectorItemProps, TabSelectorProps, Table, TableProps, Tag, TagBackground, TagBorder, TagColor, TagRoundedSize, TagSize, Td, TechLogo, type TechLogoName, techLogos_d_exports as TechLogos, Terminal, TerminalProps, TextArea, TextAreaProps, TextEditor, TextEditorContainer, TextEditorProps, Th, TiktokLogo, Toast, ToastAction, ToastActionElement, ToastClose, ToastDescription, ToastProps, ToastProvider, ToastTitle, ToastViewport, Toaster, Tr, TriggerProps, type UploadImageFn, VersionSwitcher, VersionSwitcherProps, VersionSwitcherProvider, VerticalSwitchSelector, VerticalSwitchSelectorProps, WithResizer, XLogo, YoutubeLogo, badgeVariants, baseMarkdownComponents, buttonVariants, checkIsExternalLink, checkboxVariants, choiceVariant, containerVariants, createEditorUploadFn, defaultChoices, drawerManager, getCapitals, getIntlayerHTMLOptions, getIntlayerMarkdownOptions, getYoutubeEmbedUrl, getYoutubeVideoId, getYoutubeWatchUrl, indicatorVariant, inputSlotVariants, inputVariants, isTextChildren, linkVariants, paginationVariants, radioVariants, reducer, shikiWrapperClassName, switchSelectorVariant, toast, toastVariants, traceKeys, useContentEditable, useCopyToClipboard, useForm, useFormField, useIsRightDrawerOpen, useLocaleSwitcherContent, usePasswordManagerBadge, usePopoverIds, usePrevious, useRightDrawer, useRightDrawerActions, useToast, useVersionSwitcher };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/design-system",
|
|
3
|
-
"version": "9.5.
|
|
3
|
+
"version": "9.5.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Intlayer design system, including UI components used in the Intlayer editor, website, and visual editor/CMS.",
|
|
6
6
|
"keywords": [
|
|
@@ -455,15 +455,15 @@
|
|
|
455
455
|
"typecheck_": "tsc --noEmit --project tsconfig.types.json"
|
|
456
456
|
},
|
|
457
457
|
"dependencies": {
|
|
458
|
-
"@better-auth/passkey": "1.7.
|
|
459
|
-
"@better-auth/sso": "1.7.
|
|
460
|
-
"@intlayer/api": "9.5.
|
|
461
|
-
"@intlayer/config": "9.5.
|
|
462
|
-
"@intlayer/core": "9.5.
|
|
463
|
-
"@intlayer/dictionaries-entry": "9.5.
|
|
464
|
-
"@intlayer/editor-react": "9.5.
|
|
465
|
-
"@intlayer/engine": "9.5.
|
|
466
|
-
"@intlayer/types": "9.5.
|
|
458
|
+
"@better-auth/passkey": "1.7.4",
|
|
459
|
+
"@better-auth/sso": "1.7.4",
|
|
460
|
+
"@intlayer/api": "9.5.2",
|
|
461
|
+
"@intlayer/config": "9.5.2",
|
|
462
|
+
"@intlayer/core": "9.5.2",
|
|
463
|
+
"@intlayer/dictionaries-entry": "9.5.2",
|
|
464
|
+
"@intlayer/editor-react": "9.5.2",
|
|
465
|
+
"@intlayer/engine": "9.5.2",
|
|
466
|
+
"@intlayer/types": "9.5.2",
|
|
467
467
|
"@radix-ui/react-dialog": "1.1.23",
|
|
468
468
|
"@radix-ui/react-select": "2.3.7",
|
|
469
469
|
"@radix-ui/react-slot": "1.3.3",
|
|
@@ -471,7 +471,7 @@
|
|
|
471
471
|
"@tailwindcss/aspect-ratio": "0.4.2",
|
|
472
472
|
"@tanstack/query-async-storage-persister": "5.102.8",
|
|
473
473
|
"@tanstack/react-query-persist-client": "5.102.8",
|
|
474
|
-
"@tanstack/react-virtual": "3.14.
|
|
474
|
+
"@tanstack/react-virtual": "3.14.12",
|
|
475
475
|
"@tiptap/core": "3.31.3",
|
|
476
476
|
"@tiptap/extension-character-count": "3.31.3",
|
|
477
477
|
"@tiptap/extension-code-block": "3.31.3",
|
|
@@ -490,22 +490,22 @@
|
|
|
490
490
|
"@tiptap/react": "3.31.3",
|
|
491
491
|
"@tiptap/starter-kit": "3.31.3",
|
|
492
492
|
"@tiptap/suggestion": "3.31.3",
|
|
493
|
-
"better-auth": "1.7.
|
|
493
|
+
"better-auth": "1.7.4",
|
|
494
494
|
"class-variance-authority": "0.7.1",
|
|
495
495
|
"cmdk": "1.1.1",
|
|
496
496
|
"cnfast": "0.2.0",
|
|
497
497
|
"defu": "6.1.7",
|
|
498
498
|
"dompurify": "3.4.15",
|
|
499
499
|
"isomorphic-dompurify": "4.1.0",
|
|
500
|
-
"react-intlayer": "9.5.
|
|
500
|
+
"react-intlayer": "9.5.2",
|
|
501
501
|
"rollup-preserve-directives": "1.1.3",
|
|
502
502
|
"tiptap-extension-global-drag-handle": "^0.1.18",
|
|
503
503
|
"tiptap-markdown": "^0.9.0",
|
|
504
504
|
"tunnel-rat": "^0.1.2",
|
|
505
|
-
"zod": "4.
|
|
505
|
+
"zod": "4.6.2"
|
|
506
506
|
},
|
|
507
507
|
"devDependencies": {
|
|
508
|
-
"@intlayer/backend": "9.5.
|
|
508
|
+
"@intlayer/backend": "9.5.2",
|
|
509
509
|
"@shikijs/core": "4.4.3",
|
|
510
510
|
"@shikijs/engine-oniguruma": "4.4.3",
|
|
511
511
|
"@shikijs/transformers": "4.4.3",
|
|
@@ -526,27 +526,27 @@
|
|
|
526
526
|
"@testing-library/user-event": "14.6.7",
|
|
527
527
|
"@types/dompurify": "3.2.0",
|
|
528
528
|
"@types/espree": "11.1.0",
|
|
529
|
-
"@types/node": "
|
|
530
|
-
"@types/react": "19.
|
|
531
|
-
"@types/react-dom": "19.
|
|
529
|
+
"@types/node": "^22",
|
|
530
|
+
"@types/react": "19.3.0",
|
|
531
|
+
"@types/react-dom": "19.3.0",
|
|
532
532
|
"@utils/ts-config": "1.0.4",
|
|
533
533
|
"@utils/ts-config-types": "1.0.4",
|
|
534
534
|
"fast-glob": "3.3.3",
|
|
535
|
-
"intlayer": "9.5.
|
|
535
|
+
"intlayer": "9.5.2",
|
|
536
536
|
"rimraf": "6.1.3",
|
|
537
537
|
"shiki": "4.4.3",
|
|
538
538
|
"storybook": "10.6.0",
|
|
539
539
|
"tsdown": "0.23.0",
|
|
540
540
|
"typescript": "7.0.2",
|
|
541
|
-
"vite": "8.
|
|
542
|
-
"vite-intlayer": "9.5.
|
|
541
|
+
"vite": "8.3.0",
|
|
542
|
+
"vite-intlayer": "9.5.2",
|
|
543
543
|
"vite-plugin-dts": "5.1.0",
|
|
544
544
|
"vitest": "5.0.0"
|
|
545
545
|
},
|
|
546
546
|
"peerDependencies": {
|
|
547
547
|
"@better-fetch/fetch": "1.3.1",
|
|
548
548
|
"@hookform/resolvers": "5.9.1",
|
|
549
|
-
"@intlayer/backend": "9.5.
|
|
549
|
+
"@intlayer/backend": "9.5.2",
|
|
550
550
|
"@monaco-editor/react": "4.7.0",
|
|
551
551
|
"@shikijs/core": "4.4.3",
|
|
552
552
|
"@shikijs/engine-oniguruma": "4.4.3",
|
|
@@ -555,12 +555,12 @@
|
|
|
555
555
|
"@tanstack/react-query-devtools": "5.102.8",
|
|
556
556
|
"framer-motion": "13.2.0",
|
|
557
557
|
"fuse.js": "7.5.0",
|
|
558
|
-
"intlayer": "9.5.
|
|
559
|
-
"lucide-react": "1.
|
|
558
|
+
"intlayer": "9.5.2",
|
|
559
|
+
"lucide-react": "1.45.0",
|
|
560
560
|
"react": ">=16.0.0",
|
|
561
561
|
"react-dom": ">=16.0.0",
|
|
562
562
|
"react-hook-form": "7.87.0",
|
|
563
|
-
"react-intlayer": "9.5.
|
|
563
|
+
"react-intlayer": "9.5.2",
|
|
564
564
|
"shiki": "4.4.3",
|
|
565
565
|
"tailwindcss": "4.3.3"
|
|
566
566
|
},
|