@intlayer/design-system 9.4.2 → 9.4.3

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.
Files changed (62) hide show
  1. package/dist/esm/api/index.mjs +2 -2
  2. package/dist/esm/api/useUser/index.mjs +1 -1
  3. package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
  4. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +2 -2
  5. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +1 -1
  6. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +6 -6
  7. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +1 -1
  8. package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +1 -1
  9. package/dist/esm/components/DictionaryFieldEditor/NodeEditor.mjs +2 -2
  10. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +2 -2
  11. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +1 -1
  12. package/dist/esm/components/Form/elements/OTPElement.mjs +1 -1
  13. package/dist/esm/components/IDE/CodeBlockHighlight.mjs +1 -1
  14. package/dist/esm/components/IDE/CodeBlockHighlight.mjs.map +1 -1
  15. package/dist/esm/components/IDE/CodeBlockServer.mjs +1 -1
  16. package/dist/esm/components/IDE/CodeBlockServer.mjs.map +1 -1
  17. package/dist/esm/components/IDE/CodeBlockShiki.mjs +6 -48
  18. package/dist/esm/components/IDE/CodeBlockShiki.mjs.map +1 -1
  19. package/dist/esm/components/IDE/shikiBundle.mjs +61 -0
  20. package/dist/esm/components/IDE/shikiBundle.mjs.map +1 -0
  21. package/dist/esm/components/IDE/shikiLanguages.mjs +2 -39
  22. package/dist/esm/components/IDE/shikiLanguages.mjs.map +1 -1
  23. package/dist/esm/components/IDE/shikiThemes.mjs.map +1 -1
  24. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +1 -1
  25. package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs +7 -2
  26. package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs.map +1 -1
  27. package/dist/esm/components/MarkdownEditor/extensions.mjs +1 -1
  28. package/dist/esm/components/MarkdownEditor/extensions.mjs.map +1 -1
  29. package/dist/esm/components/MarkdownEditor/novel/extensions/code-block-shiki.mjs +197 -0
  30. package/dist/esm/components/MarkdownEditor/novel/extensions/code-block-shiki.mjs.map +1 -0
  31. package/dist/esm/components/MarkdownEditor/novel/extensions/index.mjs +2 -1
  32. package/dist/esm/components/MarkdownEditor/novel/extensions/index.mjs.map +1 -1
  33. package/dist/esm/components/MarkdownEditor/novel/index.mjs +2 -1
  34. package/dist/esm/components/Modal/Modal.mjs +2 -2
  35. package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
  36. package/dist/esm/components/Pagination/Pagination.mjs +1 -1
  37. package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -3
  38. package/dist/esm/components/Tab/Tab.mjs +1 -1
  39. package/dist/esm/components/TechLogo/logos/HTMX.mjs +2 -2
  40. package/dist/esm/components/TechLogo/logos/HTMX.mjs.map +1 -1
  41. package/dist/esm/hooks/index.mjs +7 -7
  42. package/dist/esm/routes.mjs +22 -6
  43. package/dist/esm/routes.mjs.map +1 -1
  44. package/dist/types/components/IDE/CodeBlockServer.d.ts +1 -1
  45. package/dist/types/components/IDE/CodeBlockServer.d.ts.map +1 -1
  46. package/dist/types/components/IDE/CodeBlockShiki.d.ts.map +1 -1
  47. package/dist/types/components/IDE/shikiBundle.d.ts +74 -0
  48. package/dist/types/components/IDE/shikiBundle.d.ts.map +1 -0
  49. package/dist/types/components/IDE/shikiLanguages.d.ts +2 -39
  50. package/dist/types/components/IDE/shikiLanguages.d.ts.map +1 -1
  51. package/dist/types/components/IDE/shikiThemes.d.ts +3 -1
  52. package/dist/types/components/IDE/shikiThemes.d.ts.map +1 -1
  53. package/dist/types/components/MarkDownRender/MarkDownIframe.d.ts.map +1 -1
  54. package/dist/types/components/MarkdownEditor/novel/extensions/code-block-shiki.d.ts +15 -0
  55. package/dist/types/components/MarkdownEditor/novel/extensions/code-block-shiki.d.ts.map +1 -0
  56. package/dist/types/components/MarkdownEditor/novel/extensions/index.d.ts +2 -1
  57. package/dist/types/components/MarkdownEditor/novel/extensions/index.d.ts.map +1 -1
  58. package/dist/types/components/MarkdownEditor/novel/index.d.ts +2 -1
  59. package/dist/types/routes.d.ts +19 -3
  60. package/dist/types/routes.d.ts.map +1 -1
  61. package/package.json +30 -16
  62. package/src/components/MarkdownEditor/markdown-editor.css +1 -1
@@ -100,13 +100,18 @@ const EmbeddedFrame = ({ src, title, className, frameProps }) => {
100
100
  "aria-label": title ?? "Play video",
101
101
  onClick: () => setIsPlayRequested(true),
102
102
  className: cn("group relative block cursor-pointer border-0 bg-card p-0", className),
103
- children: [/* @__PURE__ */ jsx("img", {
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", {
104
107
  src: `https://i.ytimg.com/vi/${youtubeVideoId}/hqdefault.jpg`,
105
108
  alt: "",
109
+ width: 480,
110
+ height: 360,
106
111
  fetchPriority: "high",
107
112
  decoding: "async",
108
113
  className: "size-full object-cover"
109
- }), /* @__PURE__ */ jsx("span", {
114
+ })] }), /* @__PURE__ */ jsx("span", {
110
115
  className: "absolute inset-0 flex items-center justify-center",
111
116
  children: /* @__PURE__ */ jsx("span", {
112
117
  className: "flex size-14 items-center justify-center rounded-full bg-text/70 text-text-opposite transition-transform group-hover:scale-110",
@@ -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 <img\n src={`https://i.ytimg.com/vi/${youtubeVideoId}/hqdefault.jpg`}\n alt=\"\"\n fetchPriority=\"high\"\n decoding=\"async\"\n className=\"size-full object-cover\"\n />\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, 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,10 +1,10 @@
1
1
  import CustomKeymap from "./novel/extensions/custom-keymap.mjs";
2
2
  import UpdatedImage from "./novel/extensions/updated-image.mjs";
3
3
  import { AIHighlight } from "./novel/extensions/ai-highlight.mjs";
4
+ import { CodeBlockShiki } from "./novel/extensions/code-block-shiki.mjs";
4
5
  import { CharacterCount, Color, GlobalDragHandle, HighlightExtension, HorizontalRule as Horizontal, MarkdownExtension, Placeholder as PlaceholderExtension, StarterKit, TaskItem, TaskList, TextStyle, TiptapImage, TiptapLink, TiptapUnderline, Youtube } from "./novel/extensions/index.mjs";
5
6
  import { UploadImagesPlugin } from "./novel/plugins/upload-images.mjs";
6
7
  import { cx } from "class-variance-authority";
7
- import { CodeBlockShiki } from "tiptap-extension-code-block-shiki";
8
8
 
9
9
  //#region src/components/MarkdownEditor/extensions.ts
10
10
  const aiHighlight = AIHighlight;
@@ -1 +1 @@
1
- {"version":3,"file":"extensions.mjs","names":["HorizontalRule","Placeholder"],"sources":["../../../../src/components/MarkdownEditor/extensions.ts"],"sourcesContent":["import { cx } from 'class-variance-authority';\nimport { CodeBlockShiki } from 'tiptap-extension-code-block-shiki';\nimport {\n AIHighlight,\n CharacterCount,\n Color,\n CustomKeymap,\n GlobalDragHandle,\n HighlightExtension,\n HorizontalRule,\n MarkdownExtension,\n Placeholder,\n StarterKit,\n TaskItem,\n TaskList,\n TextStyle,\n TiptapImage,\n TiptapLink,\n TiptapUnderline,\n UpdatedImage,\n UploadImagesPlugin,\n Youtube,\n} from './novel';\n\nconst aiHighlight = AIHighlight;\n\nconst tiptapLink = TiptapLink.configure({\n HTMLAttributes: {\n class: cx(\n 'text-muted-foreground underline underline-offset-[3px] hover:text-primary transition-colors cursor-pointer'\n ),\n },\n});\n\nconst tiptapImage = TiptapImage.extend({\n addProseMirrorPlugins() {\n return [\n UploadImagesPlugin({\n imageClass: cx('opacity-40 rounded-lg border border-stone-200'),\n }),\n ];\n },\n}).configure({\n allowBase64: true,\n HTMLAttributes: {\n class: cx('rounded-lg border border-muted'),\n },\n});\n\nconst updatedImage = UpdatedImage.configure({\n HTMLAttributes: {\n class: cx('rounded-lg border border-muted'),\n },\n});\n\nconst taskList = TaskList.configure({\n HTMLAttributes: {\n class: cx('not-prose pl-2'),\n },\n});\n\nconst taskItem = TaskItem.configure({\n HTMLAttributes: {\n class: cx('flex gap-2 items-start my-4'),\n },\n nested: true,\n});\n\nconst horizontalRule = HorizontalRule.configure({\n HTMLAttributes: {\n class: cx('mt-4 mb-6 border-t border-muted-foreground'),\n },\n});\n\nconst starterKit = StarterKit.configure({\n bulletList: {\n HTMLAttributes: {\n class: cx('list-disc list-outside leading-3 -mt-2'),\n },\n },\n orderedList: {\n HTMLAttributes: {\n class: cx('list-decimal list-outside leading-3 -mt-2'),\n },\n },\n listItem: {\n HTMLAttributes: {\n class: cx('leading-normal -mb-2'),\n },\n },\n blockquote: {\n HTMLAttributes: {\n class: cx('border-l-4 border-primary'),\n },\n },\n // Disabled in favor of the shiki-powered `codeBlock` extension below.\n codeBlock: false,\n code: {\n HTMLAttributes: {\n class: cx('rounded-md bg-muted px-1.5 py-1 font-mono font-medium'),\n spellcheck: 'false',\n },\n },\n horizontalRule: false,\n dropcursor: {\n color: '#DBEAFE',\n width: 4,\n },\n gapcursor: false,\n});\n\n/**\n * Code block with syntax highlighting powered by shiki (the same highlighter\n * the rest of the design-system uses in `IDE/CodeBlockShiki` and\n * `MarkDownRender`). Languages are lazy-loaded on demand and the dual\n * `github-light` / `github-dark` themes emit `--shiki-dark` CSS variables that\n * `markdown-editor.css` toggles under `[data-theme=\"dark\"]`.\n */\nconst codeBlock = CodeBlockShiki.configure({\n defaultLanguage: null,\n defaultTheme: 'github-light',\n themes: {\n light: 'github-light',\n dark: 'github-dark',\n },\n HTMLAttributes: {\n class: cx(\n 'rounded-md bg-muted text-muted-foreground border p-5 font-mono font-medium'\n ),\n },\n});\n\nconst youtube = Youtube.configure({\n HTMLAttributes: {\n class: cx('rounded-lg border border-muted'),\n },\n inline: false,\n});\n\nconst characterCount = CharacterCount.configure();\n\nconst markdownExtension = MarkdownExtension.configure({\n html: true,\n tightLists: true,\n tightListClass: 'tight',\n bulletListMarker: '-',\n linkify: false,\n breaks: false,\n transformPastedText: false,\n transformCopiedText: false,\n});\n\n/**\n * Default Tiptap/Novel extensions powering the MarkdownEditor.\n *\n * The slash-command extension is intentionally not included here because it\n * needs a runtime image-upload handler; it is appended by the editor itself.\n */\nexport const defaultExtensions = [\n starterKit,\n Placeholder,\n tiptapLink,\n tiptapImage,\n updatedImage,\n taskList,\n taskItem,\n horizontalRule,\n aiHighlight,\n codeBlock,\n youtube,\n characterCount,\n TiptapUnderline,\n markdownExtension,\n HighlightExtension,\n TextStyle,\n Color,\n CustomKeymap,\n GlobalDragHandle,\n];\n"],"mappings":";;;;;;;;;AAwBA,MAAM,cAAc;AAEpB,MAAM,aAAa,WAAW,UAAU,EACtC,gBAAgB,EACd,OAAO,GACL,4GACF,EACF,EACF,CAAC;AAED,MAAM,cAAc,YAAY,OAAO,EACrC,wBAAwB;CACtB,OAAO,CACL,mBAAmB,EACjB,YAAY,GAAG,+CAA+C,EAChE,CAAC,CACH;AACF,EACF,CAAC,CAAC,CAAC,UAAU;CACX,aAAa;CACb,gBAAgB,EACd,OAAO,GAAG,gCAAgC,EAC5C;AACF,CAAC;AAED,MAAM,eAAe,aAAa,UAAU,EAC1C,gBAAgB,EACd,OAAO,GAAG,gCAAgC,EAC5C,EACF,CAAC;AAED,MAAM,WAAW,SAAS,UAAU,EAClC,gBAAgB,EACd,OAAO,GAAG,gBAAgB,EAC5B,EACF,CAAC;AAED,MAAM,WAAW,SAAS,UAAU;CAClC,gBAAgB,EACd,OAAO,GAAG,6BAA6B,EACzC;CACA,QAAQ;AACV,CAAC;AAED,MAAM,iBAAiBA,WAAe,UAAU,EAC9C,gBAAgB,EACd,OAAO,GAAG,4CAA4C,EACxD,EACF,CAAC;AAED,MAAM,aAAa,WAAW,UAAU;CACtC,YAAY,EACV,gBAAgB,EACd,OAAO,GAAG,wCAAwC,EACpD,EACF;CACA,aAAa,EACX,gBAAgB,EACd,OAAO,GAAG,2CAA2C,EACvD,EACF;CACA,UAAU,EACR,gBAAgB,EACd,OAAO,GAAG,sBAAsB,EAClC,EACF;CACA,YAAY,EACV,gBAAgB,EACd,OAAO,GAAG,2BAA2B,EACvC,EACF;CAEA,WAAW;CACX,MAAM,EACJ,gBAAgB;EACd,OAAO,GAAG,uDAAuD;EACjE,YAAY;CACd,EACF;CACA,gBAAgB;CAChB,YAAY;EACV,OAAO;EACP,OAAO;CACT;CACA,WAAW;AACb,CAAC;;;;;;;;AASD,MAAM,YAAY,eAAe,UAAU;CACzC,iBAAiB;CACjB,cAAc;CACd,QAAQ;EACN,OAAO;EACP,MAAM;CACR;CACA,gBAAgB,EACd,OAAO,GACL,4EACF,EACF;AACF,CAAC;AAED,MAAM,UAAU,QAAQ,UAAU;CAChC,gBAAgB,EACd,OAAO,GAAG,gCAAgC,EAC5C;CACA,QAAQ;AACV,CAAC;AAED,MAAM,iBAAiB,eAAe,UAAU;AAEhD,MAAM,oBAAoB,kBAAkB,UAAU;CACpD,MAAM;CACN,YAAY;CACZ,gBAAgB;CAChB,kBAAkB;CAClB,SAAS;CACT,QAAQ;CACR,qBAAqB;CACrB,qBAAqB;AACvB,CAAC;;;;;;;AAQD,MAAa,oBAAoB;CAC/B;CACAC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
1
+ {"version":3,"file":"extensions.mjs","names":["HorizontalRule","Placeholder"],"sources":["../../../../src/components/MarkdownEditor/extensions.ts"],"sourcesContent":["import { cx } from 'class-variance-authority';\nimport {\n AIHighlight,\n CharacterCount,\n CodeBlockShiki,\n Color,\n CustomKeymap,\n GlobalDragHandle,\n HighlightExtension,\n HorizontalRule,\n MarkdownExtension,\n Placeholder,\n StarterKit,\n TaskItem,\n TaskList,\n TextStyle,\n TiptapImage,\n TiptapLink,\n TiptapUnderline,\n UpdatedImage,\n UploadImagesPlugin,\n Youtube,\n} from './novel';\n\nconst aiHighlight = AIHighlight;\n\nconst tiptapLink = TiptapLink.configure({\n HTMLAttributes: {\n class: cx(\n 'text-muted-foreground underline underline-offset-[3px] hover:text-primary transition-colors cursor-pointer'\n ),\n },\n});\n\nconst tiptapImage = TiptapImage.extend({\n addProseMirrorPlugins() {\n return [\n UploadImagesPlugin({\n imageClass: cx('opacity-40 rounded-lg border border-stone-200'),\n }),\n ];\n },\n}).configure({\n allowBase64: true,\n HTMLAttributes: {\n class: cx('rounded-lg border border-muted'),\n },\n});\n\nconst updatedImage = UpdatedImage.configure({\n HTMLAttributes: {\n class: cx('rounded-lg border border-muted'),\n },\n});\n\nconst taskList = TaskList.configure({\n HTMLAttributes: {\n class: cx('not-prose pl-2'),\n },\n});\n\nconst taskItem = TaskItem.configure({\n HTMLAttributes: {\n class: cx('flex gap-2 items-start my-4'),\n },\n nested: true,\n});\n\nconst horizontalRule = HorizontalRule.configure({\n HTMLAttributes: {\n class: cx('mt-4 mb-6 border-t border-muted-foreground'),\n },\n});\n\nconst starterKit = StarterKit.configure({\n bulletList: {\n HTMLAttributes: {\n class: cx('list-disc list-outside leading-3 -mt-2'),\n },\n },\n orderedList: {\n HTMLAttributes: {\n class: cx('list-decimal list-outside leading-3 -mt-2'),\n },\n },\n listItem: {\n HTMLAttributes: {\n class: cx('leading-normal -mb-2'),\n },\n },\n blockquote: {\n HTMLAttributes: {\n class: cx('border-l-4 border-primary'),\n },\n },\n // Disabled in favor of the shiki-powered `codeBlock` extension below.\n codeBlock: false,\n code: {\n HTMLAttributes: {\n class: cx('rounded-md bg-muted px-1.5 py-1 font-mono font-medium'),\n spellcheck: 'false',\n },\n },\n horizontalRule: false,\n dropcursor: {\n color: '#DBEAFE',\n width: 4,\n },\n gapcursor: false,\n});\n\n/**\n * Code block with syntax highlighting powered by shiki (the same highlighter\n * the rest of the design-system uses in `IDE/CodeBlockShiki` and\n * `MarkDownRender`). Languages are lazy-loaded on demand and the dual\n * `github-light` / `github-dark` themes emit `--shiki-dark` CSS variables that\n * `markdown-editor.css` toggles under `[data-theme=\"dark\"]`.\n */\nconst codeBlock = CodeBlockShiki.configure({\n defaultLanguage: null,\n defaultTheme: 'github-light',\n themes: {\n light: 'github-light',\n dark: 'github-dark',\n },\n HTMLAttributes: {\n class: cx(\n 'rounded-md bg-muted text-muted-foreground border p-5 font-mono font-medium'\n ),\n },\n});\n\nconst youtube = Youtube.configure({\n HTMLAttributes: {\n class: cx('rounded-lg border border-muted'),\n },\n inline: false,\n});\n\nconst characterCount = CharacterCount.configure();\n\nconst markdownExtension = MarkdownExtension.configure({\n html: true,\n tightLists: true,\n tightListClass: 'tight',\n bulletListMarker: '-',\n linkify: false,\n breaks: false,\n transformPastedText: false,\n transformCopiedText: false,\n});\n\n/**\n * Default Tiptap/Novel extensions powering the MarkdownEditor.\n *\n * The slash-command extension is intentionally not included here because it\n * needs a runtime image-upload handler; it is appended by the editor itself.\n */\nexport const defaultExtensions = [\n starterKit,\n Placeholder,\n tiptapLink,\n tiptapImage,\n updatedImage,\n taskList,\n taskItem,\n horizontalRule,\n aiHighlight,\n codeBlock,\n youtube,\n characterCount,\n TiptapUnderline,\n markdownExtension,\n HighlightExtension,\n TextStyle,\n Color,\n CustomKeymap,\n GlobalDragHandle,\n];\n"],"mappings":";;;;;;;;;AAwBA,MAAM,cAAc;AAEpB,MAAM,aAAa,WAAW,UAAU,EACtC,gBAAgB,EACd,OAAO,GACL,4GACF,EACF,EACF,CAAC;AAED,MAAM,cAAc,YAAY,OAAO,EACrC,wBAAwB;CACtB,OAAO,CACL,mBAAmB,EACjB,YAAY,GAAG,+CAA+C,EAChE,CAAC,CACH;AACF,EACF,CAAC,CAAC,CAAC,UAAU;CACX,aAAa;CACb,gBAAgB,EACd,OAAO,GAAG,gCAAgC,EAC5C;AACF,CAAC;AAED,MAAM,eAAe,aAAa,UAAU,EAC1C,gBAAgB,EACd,OAAO,GAAG,gCAAgC,EAC5C,EACF,CAAC;AAED,MAAM,WAAW,SAAS,UAAU,EAClC,gBAAgB,EACd,OAAO,GAAG,gBAAgB,EAC5B,EACF,CAAC;AAED,MAAM,WAAW,SAAS,UAAU;CAClC,gBAAgB,EACd,OAAO,GAAG,6BAA6B,EACzC;CACA,QAAQ;AACV,CAAC;AAED,MAAM,iBAAiBA,WAAe,UAAU,EAC9C,gBAAgB,EACd,OAAO,GAAG,4CAA4C,EACxD,EACF,CAAC;AAED,MAAM,aAAa,WAAW,UAAU;CACtC,YAAY,EACV,gBAAgB,EACd,OAAO,GAAG,wCAAwC,EACpD,EACF;CACA,aAAa,EACX,gBAAgB,EACd,OAAO,GAAG,2CAA2C,EACvD,EACF;CACA,UAAU,EACR,gBAAgB,EACd,OAAO,GAAG,sBAAsB,EAClC,EACF;CACA,YAAY,EACV,gBAAgB,EACd,OAAO,GAAG,2BAA2B,EACvC,EACF;CAEA,WAAW;CACX,MAAM,EACJ,gBAAgB;EACd,OAAO,GAAG,uDAAuD;EACjE,YAAY;CACd,EACF;CACA,gBAAgB;CAChB,YAAY;EACV,OAAO;EACP,OAAO;CACT;CACA,WAAW;AACb,CAAC;;;;;;;;AASD,MAAM,YAAY,eAAe,UAAU;CACzC,iBAAiB;CACjB,cAAc;CACd,QAAQ;EACN,OAAO;EACP,MAAM;CACR;CACA,gBAAgB,EACd,OAAO,GACL,4EACF,EACF;AACF,CAAC;AAED,MAAM,UAAU,QAAQ,UAAU;CAChC,gBAAgB,EACd,OAAO,GAAG,gCAAgC,EAC5C;CACA,QAAQ;AACV,CAAC;AAED,MAAM,iBAAiB,eAAe,UAAU;AAEhD,MAAM,oBAAoB,kBAAkB,UAAU;CACpD,MAAM;CACN,YAAY;CACZ,gBAAgB;CAChB,kBAAkB;CAClB,SAAS;CACT,QAAQ;CACR,qBAAqB;CACrB,qBAAqB;AACvB,CAAC;;;;;;;AAQD,MAAa,oBAAoB;CAC/B;CACAC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
@@ -0,0 +1,197 @@
1
+ import { bundledLanguages, bundledThemes, getSingletonHighlighter } from "../../../IDE/shikiBundle.mjs";
2
+ import { findChildren } from "@tiptap/core";
3
+ import { CodeBlock } from "@tiptap/extension-code-block";
4
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
5
+ import { Decoration, DecorationSet } from "@tiptap/pm/view";
6
+
7
+ //#region src/components/MarkdownEditor/novel/extensions/code-block-shiki.ts
8
+ const formatStyles = (styles) => Object.entries(styles).filter(([_, value]) => Boolean(value)).map(([key, value]) => `${key}:${value}`).join(";");
9
+ let sharedHighlighter = null;
10
+ const loadingLangs = /* @__PURE__ */ new Set();
11
+ const loadingThemes = /* @__PURE__ */ new Set();
12
+ const renderDecorations = ({ doc, name, defaultLanguage, defaultTheme, themes, highlighter }) => {
13
+ if (!highlighter) return DecorationSet.empty;
14
+ const decorations = [];
15
+ const loadedLangs = highlighter.getLoadedLanguages();
16
+ const loadedThemes = highlighter.getLoadedThemes();
17
+ const resolveTheme = (themeName) => loadedThemes.includes(themeName) ? themeName : loadedThemes[0] ?? "github-light";
18
+ findChildren(doc, (node) => node.type.name === name).forEach((block) => {
19
+ let from = block.pos + 1;
20
+ let language = block.node.attrs.language || defaultLanguage;
21
+ const blockTheme = block.node.attrs.theme || defaultTheme;
22
+ const lightTheme = block.node.attrs.themes?.light || themes?.light || blockTheme;
23
+ const darkTheme = block.node.attrs.themes?.dark || themes?.dark || blockTheme;
24
+ if (!loadedLangs.includes(language)) language = "plaintext";
25
+ if (themes) {
26
+ const tokensResult = highlighter.codeToTokens(block.node.textContent, {
27
+ lang: language,
28
+ themes: {
29
+ light: resolveTheme(lightTheme),
30
+ dark: resolveTheme(darkTheme)
31
+ }
32
+ });
33
+ const preStyles = {};
34
+ if (tokensResult.bg) preStyles["background-color"] = tokensResult.bg;
35
+ if (tokensResult.fg) preStyles.color = tokensResult.fg;
36
+ decorations.push(Decoration.node(block.pos, block.pos + block.node.nodeSize, {
37
+ style: formatStyles(preStyles),
38
+ class: "shiki"
39
+ }));
40
+ for (const line of tokensResult.tokens) {
41
+ for (const token of line) {
42
+ const to = from + token.content.length;
43
+ const style = formatStyles(token.htmlStyle || {});
44
+ decorations.push(Decoration.inline(from, to, { style }));
45
+ from = to;
46
+ }
47
+ from += 1;
48
+ }
49
+ } else {
50
+ const activeTheme = resolveTheme(blockTheme);
51
+ const tokensResult = highlighter.codeToTokens(block.node.textContent, {
52
+ lang: language,
53
+ theme: activeTheme
54
+ });
55
+ const themeObj = highlighter.getTheme(activeTheme);
56
+ decorations.push(Decoration.node(block.pos, block.pos + block.node.nodeSize, {
57
+ style: formatStyles({ "background-color": themeObj.bg }),
58
+ class: "shiki"
59
+ }));
60
+ for (const line of tokensResult.tokens) {
61
+ for (const token of line) {
62
+ const to = from + token.content.length;
63
+ const style = formatStyles({ color: token.color || "inherit" });
64
+ decorations.push(Decoration.inline(from, to, { style }));
65
+ from = to;
66
+ }
67
+ from += 1;
68
+ }
69
+ }
70
+ });
71
+ return DecorationSet.create(doc, decorations);
72
+ };
73
+ const createShikiPlugin = ({ name, defaultLanguage, defaultTheme, themes }) => {
74
+ const loadMissing = async (doc) => {
75
+ if (!sharedHighlighter) return false;
76
+ const blocks = findChildren(doc, (node) => node.type.name === name);
77
+ const loadedLangs = sharedHighlighter.getLoadedLanguages();
78
+ const loadedThemes = sharedHighlighter.getLoadedThemes();
79
+ const langsToLoad = /* @__PURE__ */ new Set();
80
+ const themesToLoad = /* @__PURE__ */ new Set();
81
+ for (const block of blocks) {
82
+ const lang = block.node.attrs.language || defaultLanguage;
83
+ if (lang && !loadedLangs.includes(lang) && lang in bundledLanguages && !loadingLangs.has(lang)) langsToLoad.add(lang);
84
+ if (themes) {
85
+ const light = block.node.attrs.themes?.light || themes.light;
86
+ const dark = block.node.attrs.themes?.dark || themes.dark;
87
+ if (light && !loadedThemes.includes(light) && light in bundledThemes && !loadingThemes.has(light)) themesToLoad.add(light);
88
+ if (dark && !loadedThemes.includes(dark) && dark in bundledThemes && !loadingThemes.has(dark)) themesToLoad.add(dark);
89
+ } else {
90
+ const theme = block.node.attrs.theme || defaultTheme;
91
+ if (theme && !loadedThemes.includes(theme) && theme in bundledThemes && !loadingThemes.has(theme)) themesToLoad.add(theme);
92
+ }
93
+ }
94
+ if (langsToLoad.size === 0 && themesToLoad.size === 0) return false;
95
+ for (const l of langsToLoad) loadingLangs.add(l);
96
+ for (const t of themesToLoad) loadingThemes.add(t);
97
+ try {
98
+ await Promise.all([...Array.from(langsToLoad).map((l) => sharedHighlighter.loadLanguage(l)), ...Array.from(themesToLoad).map((t) => sharedHighlighter.loadTheme(t))]);
99
+ return true;
100
+ } finally {
101
+ for (const l of langsToLoad) loadingLangs.delete(l);
102
+ for (const t of themesToLoad) loadingThemes.delete(t);
103
+ }
104
+ };
105
+ const plugin = new Plugin({
106
+ key: new PluginKey("shiki"),
107
+ view(editorView) {
108
+ let isDestroyed = false;
109
+ const init = async () => {
110
+ if (!sharedHighlighter) sharedHighlighter = await getSingletonHighlighter();
111
+ if (isDestroyed) return;
112
+ await loadMissing(editorView.state.doc);
113
+ if (isDestroyed) return;
114
+ editorView.dispatch(editorView.state.tr.setMeta("shikiPluginForceDecoration", true));
115
+ };
116
+ init();
117
+ return {
118
+ update(view) {
119
+ loadMissing(view.state.doc).then((hasLoadedNew) => {
120
+ if (hasLoadedNew && !isDestroyed) view.dispatch(view.state.tr.setMeta("shikiPluginForceDecoration", true));
121
+ });
122
+ },
123
+ destroy() {
124
+ isDestroyed = true;
125
+ }
126
+ };
127
+ },
128
+ state: {
129
+ init: (_, { doc }) => renderDecorations({
130
+ doc,
131
+ name,
132
+ defaultLanguage,
133
+ defaultTheme,
134
+ themes,
135
+ highlighter: sharedHighlighter
136
+ }),
137
+ apply: (tr, decorationSet, oldState, newState) => {
138
+ const oldHead = oldState.selection.$head.parent.type.name;
139
+ const newHead = newState.selection.$head.parent.type.name;
140
+ const oldBlocks = findChildren(oldState.doc, (node) => node.type.name === name);
141
+ const newBlocks = findChildren(newState.doc, (node) => node.type.name === name);
142
+ const docChanged = tr.docChanged && ([oldHead, newHead].includes(name) || oldBlocks.length !== newBlocks.length || tr.steps.some((step) => {
143
+ const { from, to } = step;
144
+ return from !== void 0 && to !== void 0 && oldBlocks.some((block) => block.pos >= from && block.pos + block.node.nodeSize <= to);
145
+ }));
146
+ if (tr.getMeta("shikiPluginForceDecoration") || docChanged) return renderDecorations({
147
+ doc: tr.doc,
148
+ name,
149
+ defaultLanguage,
150
+ defaultTheme,
151
+ themes,
152
+ highlighter: sharedHighlighter
153
+ });
154
+ return decorationSet.map(tr.mapping, tr.doc);
155
+ }
156
+ },
157
+ props: { decorations(state) {
158
+ return plugin.getState(state);
159
+ } }
160
+ });
161
+ return plugin;
162
+ };
163
+ const CodeBlockShiki = CodeBlock.extend({
164
+ addOptions() {
165
+ return {
166
+ ...this.parent?.(),
167
+ defaultLanguage: null,
168
+ defaultTheme: "github-light",
169
+ themes: null
170
+ };
171
+ },
172
+ markdownTokenName: "code",
173
+ parseMarkdown(rawNode, builder) {
174
+ if (rawNode.raw?.startsWith("```") === false && rawNode.raw?.startsWith("~~~") === false && rawNode.codeBlockStyle !== "indented") return [];
175
+ return builder.createNode("codeBlock", { language: rawNode.lang || null }, rawNode.text ? [builder.createTextNode(rawNode.text)] : []);
176
+ },
177
+ renderMarkdown(node, builder) {
178
+ const lang = node.attrs?.language || "";
179
+ return node.content ? [
180
+ `\`\`\`${lang}`,
181
+ builder.renderChildren(node.content),
182
+ "```"
183
+ ].join("\n") : `\`\`\`${lang}\n\n\`\`\``;
184
+ },
185
+ addProseMirrorPlugins() {
186
+ return [...this.parent?.() || [], createShikiPlugin({
187
+ name: this.name,
188
+ defaultLanguage: this.options.defaultLanguage,
189
+ defaultTheme: this.options.defaultTheme,
190
+ themes: this.options.themes
191
+ })];
192
+ }
193
+ });
194
+
195
+ //#endregion
196
+ export { CodeBlockShiki };
197
+ //# sourceMappingURL=code-block-shiki.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-block-shiki.mjs","names":[],"sources":["../../../../../../src/components/MarkdownEditor/novel/extensions/code-block-shiki.ts"],"sourcesContent":["import { findChildren } from '@tiptap/core';\nimport { CodeBlock, type CodeBlockOptions } from '@tiptap/extension-code-block';\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport {\n type BundledLanguage,\n type BundledTheme,\n bundledLanguages,\n bundledThemes,\n getSingletonHighlighter,\n type Highlighter,\n} from '../../../IDE/shikiBundle';\n\nexport interface CodeBlockShikiOptions extends CodeBlockOptions {\n defaultLanguage: BundledLanguage | null;\n defaultTheme: BundledTheme | string;\n themes?: {\n light: BundledTheme;\n dark: BundledTheme;\n } | null;\n}\n\nconst formatStyles = (styles: Record<string, string>): string =>\n Object.entries(styles)\n .filter(([_, value]) => Boolean(value))\n .map(([key, value]) => `${key}:${value}`)\n .join(';');\n\nlet sharedHighlighter: Highlighter | null = null;\nconst loadingLangs = new Set<string>();\nconst loadingThemes = new Set<string>();\n\nconst renderDecorations = ({\n doc,\n name,\n defaultLanguage,\n defaultTheme,\n themes,\n highlighter,\n}: {\n doc: ProseMirrorNode;\n name: string;\n defaultLanguage?: BundledLanguage | null;\n defaultTheme: BundledTheme | string;\n themes?: { light: BundledTheme; dark: BundledTheme } | null;\n highlighter: Highlighter | null;\n}): DecorationSet => {\n if (!highlighter) {\n return DecorationSet.empty;\n }\n\n const decorations: Decoration[] = [];\n const loadedLangs = highlighter.getLoadedLanguages();\n const loadedThemes = highlighter.getLoadedThemes();\n\n const resolveTheme = (themeName: string) =>\n loadedThemes.includes(themeName)\n ? themeName\n : (loadedThemes[0] ?? 'github-light');\n\n findChildren(doc, (node) => node.type.name === name).forEach((block) => {\n let from = block.pos + 1;\n let language = (block.node.attrs.language || defaultLanguage) as string;\n const blockTheme = (block.node.attrs.theme || defaultTheme) as string;\n const lightTheme = (block.node.attrs.themes?.light ||\n themes?.light ||\n blockTheme) as string;\n const darkTheme = (block.node.attrs.themes?.dark ||\n themes?.dark ||\n blockTheme) as string;\n\n if (!loadedLangs.includes(language)) {\n language = 'plaintext';\n }\n\n if (themes) {\n const tokensResult = highlighter.codeToTokens(block.node.textContent, {\n lang: language as BundledLanguage,\n themes: {\n light: resolveTheme(lightTheme),\n dark: resolveTheme(darkTheme),\n },\n });\n\n const preStyles: Record<string, string> = {};\n if (tokensResult.bg) preStyles['background-color'] = tokensResult.bg;\n if (tokensResult.fg) preStyles.color = tokensResult.fg;\n\n decorations.push(\n Decoration.node(block.pos, block.pos + block.node.nodeSize, {\n style: formatStyles(preStyles),\n class: 'shiki',\n })\n );\n\n for (const line of tokensResult.tokens) {\n for (const token of line) {\n const to = from + token.content.length;\n const style = formatStyles(\n (token.htmlStyle as Record<string, string>) || {}\n );\n decorations.push(Decoration.inline(from, to, { style }));\n from = to;\n }\n from += 1;\n }\n } else {\n const activeTheme = resolveTheme(blockTheme);\n const tokensResult = highlighter.codeToTokens(block.node.textContent, {\n lang: language as BundledLanguage,\n theme: activeTheme,\n });\n\n const themeObj = highlighter.getTheme(activeTheme);\n decorations.push(\n Decoration.node(block.pos, block.pos + block.node.nodeSize, {\n style: formatStyles({ 'background-color': themeObj.bg }),\n class: 'shiki',\n })\n );\n\n for (const line of tokensResult.tokens) {\n for (const token of line) {\n const to = from + token.content.length;\n const style = formatStyles({ color: token.color || 'inherit' });\n decorations.push(Decoration.inline(from, to, { style }));\n from = to;\n }\n from += 1;\n }\n }\n });\n\n return DecorationSet.create(doc, decorations);\n};\n\nconst createShikiPlugin = ({\n name,\n defaultLanguage,\n defaultTheme,\n themes,\n}: {\n name: string;\n defaultLanguage?: BundledLanguage | null;\n defaultTheme: BundledTheme | string;\n themes?: { light: BundledTheme; dark: BundledTheme } | null;\n}) => {\n const loadMissing = async (doc: ProseMirrorNode): Promise<boolean> => {\n if (!sharedHighlighter) return false;\n const blocks = findChildren(doc, (node) => node.type.name === name);\n const loadedLangs = sharedHighlighter.getLoadedLanguages();\n const loadedThemes = sharedHighlighter.getLoadedThemes();\n\n const langsToLoad = new Set<string>();\n const themesToLoad = new Set<string>();\n\n for (const block of blocks) {\n const lang = block.node.attrs.language || defaultLanguage;\n if (\n lang &&\n !loadedLangs.includes(lang) &&\n lang in bundledLanguages &&\n !loadingLangs.has(lang)\n ) {\n langsToLoad.add(lang);\n }\n\n if (themes) {\n const light = block.node.attrs.themes?.light || themes.light;\n const dark = block.node.attrs.themes?.dark || themes.dark;\n if (\n light &&\n !loadedThemes.includes(light) &&\n light in bundledThemes &&\n !loadingThemes.has(light)\n ) {\n themesToLoad.add(light);\n }\n if (\n dark &&\n !loadedThemes.includes(dark) &&\n dark in bundledThemes &&\n !loadingThemes.has(dark)\n ) {\n themesToLoad.add(dark);\n }\n } else {\n const theme = block.node.attrs.theme || defaultTheme;\n if (\n theme &&\n !loadedThemes.includes(theme) &&\n theme in bundledThemes &&\n !loadingThemes.has(theme)\n ) {\n themesToLoad.add(theme);\n }\n }\n }\n\n if (langsToLoad.size === 0 && themesToLoad.size === 0) return false;\n\n for (const l of langsToLoad) {\n loadingLangs.add(l);\n }\n for (const t of themesToLoad) {\n loadingThemes.add(t);\n }\n\n try {\n await Promise.all([\n ...Array.from(langsToLoad).map((l) =>\n sharedHighlighter!.loadLanguage(l as BundledLanguage)\n ),\n ...Array.from(themesToLoad).map((t) =>\n sharedHighlighter!.loadTheme(t as BundledTheme)\n ),\n ]);\n return true;\n } finally {\n for (const l of langsToLoad) {\n loadingLangs.delete(l);\n }\n for (const t of themesToLoad) {\n loadingThemes.delete(t);\n }\n }\n };\n\n const plugin: Plugin = new Plugin({\n key: new PluginKey('shiki'),\n view(editorView) {\n let isDestroyed = false;\n\n const init = async () => {\n if (!sharedHighlighter) {\n sharedHighlighter = await getSingletonHighlighter();\n }\n if (isDestroyed) return;\n await loadMissing(editorView.state.doc);\n if (isDestroyed) return;\n editorView.dispatch(\n editorView.state.tr.setMeta('shikiPluginForceDecoration', true)\n );\n };\n\n init();\n\n return {\n update(view) {\n loadMissing(view.state.doc).then((hasLoadedNew) => {\n if (hasLoadedNew && !isDestroyed) {\n view.dispatch(\n view.state.tr.setMeta('shikiPluginForceDecoration', true)\n );\n }\n });\n },\n destroy() {\n isDestroyed = true;\n },\n };\n },\n state: {\n init: (_, { doc }) =>\n renderDecorations({\n doc,\n name,\n defaultLanguage,\n defaultTheme,\n themes,\n highlighter: sharedHighlighter,\n }),\n apply: (tr, decorationSet, oldState, newState) => {\n const oldHead = oldState.selection.$head.parent.type.name;\n const newHead = newState.selection.$head.parent.type.name;\n const oldBlocks = findChildren(\n oldState.doc,\n (node) => node.type.name === name\n );\n const newBlocks = findChildren(\n newState.doc,\n (node) => node.type.name === name\n );\n\n const docChanged =\n tr.docChanged &&\n ([oldHead, newHead].includes(name) ||\n oldBlocks.length !== newBlocks.length ||\n tr.steps.some((step) => {\n // @ts-expect-error step boundaries\n const { from, to } = step;\n return (\n from !== undefined &&\n to !== undefined &&\n oldBlocks.some(\n (block) =>\n block.pos >= from && block.pos + block.node.nodeSize <= to\n )\n );\n }));\n\n if (tr.getMeta('shikiPluginForceDecoration') || docChanged) {\n return renderDecorations({\n doc: tr.doc,\n name,\n defaultLanguage,\n defaultTheme,\n themes,\n highlighter: sharedHighlighter,\n });\n }\n\n return decorationSet.map(tr.mapping, tr.doc);\n },\n },\n props: {\n decorations(state) {\n return plugin.getState(state);\n },\n },\n });\n\n return plugin;\n};\n\nexport const CodeBlockShiki = CodeBlock.extend<CodeBlockShikiOptions>({\n addOptions() {\n return {\n ...this.parent?.(),\n defaultLanguage: null,\n defaultTheme: 'github-light',\n themes: null,\n };\n },\n\n // @ts-expect-error tiptap-markdown integration property\n markdownTokenName: 'code',\n\n parseMarkdown(rawNode: any, builder: any) {\n if (\n rawNode.raw?.startsWith('```') === false &&\n rawNode.raw?.startsWith('~~~') === false &&\n rawNode.codeBlockStyle !== 'indented'\n ) {\n return [];\n }\n return builder.createNode(\n 'codeBlock',\n { language: rawNode.lang || null },\n rawNode.text ? [builder.createTextNode(rawNode.text)] : []\n );\n },\n\n renderMarkdown(node: any, builder: any) {\n const lang = node.attrs?.language || '';\n return node.content\n ? [`\\`\\`\\`${lang}`, builder.renderChildren(node.content), '```'].join(\n '\\n'\n )\n : `\\`\\`\\`${lang}\\n\\n\\`\\`\\``;\n },\n\n addProseMirrorPlugins() {\n return [\n ...(this.parent?.() || []),\n createShikiPlugin({\n name: this.name,\n defaultLanguage: this.options.defaultLanguage,\n defaultTheme: this.options.defaultTheme,\n themes: this.options.themes,\n }),\n ];\n },\n});\n"],"mappings":"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"}
@@ -2,6 +2,7 @@ import CustomKeymap from "./custom-keymap.mjs";
2
2
  import { ImageResizer } from "./image-resizer.mjs";
3
3
  import UpdatedImage from "./updated-image.mjs";
4
4
  import { AIHighlight, addAIHighlight, inputRegex, pasteRegex, removeAIHighlight } from "./ai-highlight.mjs";
5
+ import { CodeBlockShiki } from "./code-block-shiki.mjs";
5
6
  import { Command, createSuggestionItems, handleCommandNavigation, renderItems } from "./slash-command.mjs";
6
7
  import { InputRule } from "@tiptap/core";
7
8
  import CharacterCount from "@tiptap/extension-character-count";
@@ -47,5 +48,5 @@ const Horizontal = HorizontalRule.extend({ addInputRules() {
47
48
  } });
48
49
 
49
50
  //#endregion
50
- export { AIHighlight, CharacterCount, Color, Command, CustomKeymap, GlobalDragHandle, HighlightExtension, Horizontal as HorizontalRule, ImageResizer, InputRule, MarkdownExtension, PlaceholderExtension as Placeholder, StarterKit, TaskItem, TaskList, TextStyle, TiptapImage, TiptapLink, TiptapUnderline, UpdatedImage, Youtube, addAIHighlight, createSuggestionItems, handleCommandNavigation, inputRegex, pasteRegex, removeAIHighlight, renderItems };
51
+ export { AIHighlight, CharacterCount, CodeBlockShiki, Color, Command, CustomKeymap, GlobalDragHandle, HighlightExtension, Horizontal as HorizontalRule, ImageResizer, InputRule, MarkdownExtension, PlaceholderExtension as Placeholder, StarterKit, TaskItem, TaskList, TextStyle, TiptapImage, TiptapLink, TiptapUnderline, UpdatedImage, Youtube, addAIHighlight, createSuggestionItems, handleCommandNavigation, inputRegex, pasteRegex, removeAIHighlight, renderItems };
51
52
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../src/components/MarkdownEditor/novel/extensions/index.ts"],"sourcesContent":["import { InputRule } from '@tiptap/core';\nimport CharacterCount from '@tiptap/extension-character-count';\nimport { Color } from '@tiptap/extension-color';\nimport Highlight from '@tiptap/extension-highlight';\nimport HorizontalRule from '@tiptap/extension-horizontal-rule';\nimport TiptapImage from '@tiptap/extension-image';\nimport TiptapLink from '@tiptap/extension-link';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { TaskItem } from '@tiptap/extension-task-item';\nimport { TaskList } from '@tiptap/extension-task-list';\nimport { TextStyle } from '@tiptap/extension-text-style';\nimport TiptapUnderline from '@tiptap/extension-underline';\nimport Youtube from '@tiptap/extension-youtube';\nimport StarterKit from '@tiptap/starter-kit';\nimport GlobalDragHandle from 'tiptap-extension-global-drag-handle';\nimport { Markdown } from 'tiptap-markdown';\nimport CustomKeymap from './custom-keymap';\nimport { ImageResizer } from './image-resizer';\nimport UpdatedImage from './updated-image';\n\nconst PlaceholderExtension = Placeholder.configure({\n placeholder: ({ node }) => {\n if (node.type.name === 'heading') {\n return `Heading ${node.attrs.level}`;\n }\n return \"Press '/' for commands\";\n },\n includeChildren: true,\n});\n\nconst HighlightExtension = Highlight.configure({\n multicolor: true,\n});\n\nconst MarkdownExtension = Markdown.configure({\n html: false,\n transformCopiedText: true,\n});\n\nconst Horizontal = HorizontalRule.extend({\n addInputRules() {\n return [\n new InputRule({\n find: /^(?:---|—-|___\\s|\\*\\*\\*\\s)$/u,\n handler: ({ state, range }) => {\n const attributes = {};\n\n const { tr } = state;\n const start = range.from;\n const end = range.to;\n\n tr.insert(start - 1, this.type.create(attributes)).delete(\n tr.mapping.map(start),\n tr.mapping.map(end)\n );\n },\n }),\n ];\n },\n});\n\nexport * from './ai-highlight';\nexport * from './slash-command';\nexport {\n CharacterCount,\n Color,\n CustomKeymap,\n GlobalDragHandle,\n HighlightExtension,\n Horizontal as HorizontalRule,\n ImageResizer,\n InputRule,\n MarkdownExtension,\n PlaceholderExtension as Placeholder,\n StarterKit,\n TaskItem,\n TaskList,\n TextStyle,\n TiptapImage,\n TiptapLink,\n TiptapUnderline,\n UpdatedImage,\n Youtube,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAM,uBAAuB,YAAY,UAAU;CACjD,cAAc,EAAE,WAAW;EACzB,IAAI,KAAK,KAAK,SAAS,WACrB,OAAO,WAAW,KAAK,MAAM;EAE/B,OAAO;CACT;CACA,iBAAiB;AACnB,CAAC;AAED,MAAM,qBAAqB,UAAU,UAAU,EAC7C,YAAY,KACd,CAAC;AAED,MAAM,oBAAoB,SAAS,UAAU;CAC3C,MAAM;CACN,qBAAqB;AACvB,CAAC;AAED,MAAM,aAAa,eAAe,OAAO,EACvC,gBAAgB;CACd,OAAO,CACL,IAAI,UAAU;EACZ,MAAM;EACN,UAAU,EAAE,OAAO,YAAY;GAC7B,MAAM,aAAa,CAAC;GAEpB,MAAM,EAAE,OAAO;GACf,MAAM,QAAQ,MAAM;GACpB,MAAM,MAAM,MAAM;GAElB,GAAG,OAAO,QAAQ,GAAG,KAAK,KAAK,OAAO,UAAU,CAAC,CAAC,CAAC,OACjD,GAAG,QAAQ,IAAI,KAAK,GACpB,GAAG,QAAQ,IAAI,GAAG,CACpB;EACF;CACF,CAAC,CACH;AACF,EACF,CAAC"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../src/components/MarkdownEditor/novel/extensions/index.ts"],"sourcesContent":["import { InputRule } from '@tiptap/core';\nimport CharacterCount from '@tiptap/extension-character-count';\nimport { Color } from '@tiptap/extension-color';\nimport Highlight from '@tiptap/extension-highlight';\nimport HorizontalRule from '@tiptap/extension-horizontal-rule';\nimport TiptapImage from '@tiptap/extension-image';\nimport TiptapLink from '@tiptap/extension-link';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { TaskItem } from '@tiptap/extension-task-item';\nimport { TaskList } from '@tiptap/extension-task-list';\nimport { TextStyle } from '@tiptap/extension-text-style';\nimport TiptapUnderline from '@tiptap/extension-underline';\nimport Youtube from '@tiptap/extension-youtube';\nimport StarterKit from '@tiptap/starter-kit';\nimport GlobalDragHandle from 'tiptap-extension-global-drag-handle';\nimport { Markdown } from 'tiptap-markdown';\nimport CustomKeymap from './custom-keymap';\nimport { ImageResizer } from './image-resizer';\nimport UpdatedImage from './updated-image';\n\nconst PlaceholderExtension = Placeholder.configure({\n placeholder: ({ node }) => {\n if (node.type.name === 'heading') {\n return `Heading ${node.attrs.level}`;\n }\n return \"Press '/' for commands\";\n },\n includeChildren: true,\n});\n\nconst HighlightExtension = Highlight.configure({\n multicolor: true,\n});\n\nconst MarkdownExtension = Markdown.configure({\n html: false,\n transformCopiedText: true,\n});\n\nconst Horizontal = HorizontalRule.extend({\n addInputRules() {\n return [\n new InputRule({\n find: /^(?:---|—-|___\\s|\\*\\*\\*\\s)$/u,\n handler: ({ state, range }) => {\n const attributes = {};\n\n const { tr } = state;\n const start = range.from;\n const end = range.to;\n\n tr.insert(start - 1, this.type.create(attributes)).delete(\n tr.mapping.map(start),\n tr.mapping.map(end)\n );\n },\n }),\n ];\n },\n});\n\nexport * from './ai-highlight';\nexport * from './code-block-shiki';\nexport * from './slash-command';\nexport {\n CharacterCount,\n Color,\n CustomKeymap,\n GlobalDragHandle,\n HighlightExtension,\n Horizontal as HorizontalRule,\n ImageResizer,\n InputRule,\n MarkdownExtension,\n PlaceholderExtension as Placeholder,\n StarterKit,\n TaskItem,\n TaskList,\n TextStyle,\n TiptapImage,\n TiptapLink,\n TiptapUnderline,\n UpdatedImage,\n Youtube,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAM,uBAAuB,YAAY,UAAU;CACjD,cAAc,EAAE,WAAW;EACzB,IAAI,KAAK,KAAK,SAAS,WACrB,OAAO,WAAW,KAAK,MAAM;EAE/B,OAAO;CACT;CACA,iBAAiB;AACnB,CAAC;AAED,MAAM,qBAAqB,UAAU,UAAU,EAC7C,YAAY,KACd,CAAC;AAED,MAAM,oBAAoB,SAAS,UAAU;CAC3C,MAAM;CACN,qBAAqB;AACvB,CAAC;AAED,MAAM,aAAa,eAAe,OAAO,EACvC,gBAAgB;CACd,OAAO,CACL,IAAI,UAAU;EACZ,MAAM;EACN,UAAU,EAAE,OAAO,YAAY;GAC7B,MAAM,aAAa,CAAC;GAEpB,MAAM,EAAE,OAAO;GACf,MAAM,QAAQ,MAAM;GACpB,MAAM,MAAM,MAAM;GAElB,GAAG,OAAO,QAAQ,GAAG,KAAK,KAAK,OAAO,UAAU,CAAC,CAAC,CAAC,OACjD,GAAG,QAAQ,IAAI,KAAK,GACpB,GAAG,QAAQ,IAAI,GAAG,CACpB;EACF;CACF,CAAC,CACH;AACF,EACF,CAAC"}
@@ -9,9 +9,10 @@ import CustomKeymap from "./extensions/custom-keymap.mjs";
9
9
  import { ImageResizer } from "./extensions/image-resizer.mjs";
10
10
  import UpdatedImage from "./extensions/updated-image.mjs";
11
11
  import { AIHighlight, addAIHighlight, removeAIHighlight } from "./extensions/ai-highlight.mjs";
12
+ import { CodeBlockShiki } from "./extensions/code-block-shiki.mjs";
12
13
  import { Command, createSuggestionItems, handleCommandNavigation, renderItems } from "./extensions/slash-command.mjs";
13
14
  import { CharacterCount, Color, GlobalDragHandle, HighlightExtension, HorizontalRule as Horizontal, InputRule, MarkdownExtension, Placeholder as PlaceholderExtension, StarterKit, TaskItem, TaskList, TextStyle, TiptapImage, TiptapLink, TiptapUnderline, Youtube } from "./extensions/index.mjs";
14
15
  import { UploadImagesPlugin, createImageUpload, handleImageDrop, handleImagePaste } from "./plugins/upload-images.mjs";
15
16
  import { getAllContent, getPrevText, getUrlFromString, isValidUrl } from "./utils/index.mjs";
16
17
 
17
- export { AIHighlight, CharacterCount, Color, Command, CustomKeymap, EditorBubble, EditorBubbleItem, EditorCommand, EditorCommandEmpty, EditorCommandItem, EditorCommandList, EditorContent, EditorRoot, GlobalDragHandle, HighlightExtension, Horizontal as HorizontalRule, ImageResizer, InputRule, MarkdownExtension, PlaceholderExtension as Placeholder, StarterKit, TaskItem, TaskList, TextStyle, TiptapImage, TiptapLink, TiptapUnderline, UpdatedImage, UploadImagesPlugin, Youtube, addAIHighlight, createImageUpload, createSuggestionItems, getAllContent, getPrevText, getUrlFromString, handleCommandNavigation, handleImageDrop, handleImagePaste, isValidUrl, queryStore, rangeStore, removeAIHighlight, renderItems, useEditor, useQuery, useRange };
18
+ export { AIHighlight, CharacterCount, CodeBlockShiki, Color, Command, CustomKeymap, EditorBubble, EditorBubbleItem, EditorCommand, EditorCommandEmpty, EditorCommandItem, EditorCommandList, EditorContent, EditorRoot, GlobalDragHandle, HighlightExtension, Horizontal as HorizontalRule, ImageResizer, InputRule, MarkdownExtension, PlaceholderExtension as Placeholder, StarterKit, TaskItem, TaskList, TextStyle, TiptapImage, TiptapLink, TiptapUnderline, UpdatedImage, UploadImagesPlugin, Youtube, addAIHighlight, createImageUpload, createSuggestionItems, getAllContent, getPrevText, getUrlFromString, handleCommandNavigation, handleImageDrop, handleImagePaste, isValidUrl, queryStore, rangeStore, removeAIHighlight, renderItems, useEditor, useQuery, useRange };
@@ -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";
@@ -12,11 +12,11 @@ const HTMXLogo = (props) => /* @__PURE__ */ jsx("svg", {
12
12
  ...props,
13
13
  children: /* @__PURE__ */ jsxs("g", { children: [
14
14
  /* @__PURE__ */ jsx("polygon", {
15
- fill: "#111111",
15
+ fill: "currentColor",
16
16
  points: "181.394935 42.749283 256 74.2039835 256 96.0617321 181.394935 127.078518 175.477838 105.581524 230.646979 84.8771384 175.477838 64.0931689"
17
17
  }),
18
18
  /* @__PURE__ */ jsx("polygon", {
19
- fill: "#111111",
19
+ fill: "currentColor",
20
20
  points: "74.6050654 42.7484751 6.6060424e-14 74.2039835 1.83634114e-13 96.0617321 74.6050654 127.078518 80.5221623 105.581524 25.3530206 84.8771384 80.5221623 64.0931689"
21
21
  }),
22
22
  /* @__PURE__ */ jsx("polygon", {
@@ -1 +1 @@
1
- {"version":3,"file":"HTMX.mjs","names":[],"sources":["../../../../../src/components/TechLogo/logos/HTMX.tsx"],"sourcesContent":["import type { FC, SVGProps } from 'react';\n\nexport const HTMXLogo: FC<SVGProps<SVGSVGElement>> = (props) => (\n <svg\n width=\"256px\"\n height=\"168px\"\n viewBox=\"0 0 256 168\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-label=\"HTMX logo\"\n preserveAspectRatio=\"xMidYMid\"\n {...props}\n >\n <g>\n <polygon\n fill=\"#111111\"\n points=\"181.394935 42.749283 256 74.2039835 256 96.0617321 181.394935 127.078518 175.477838 105.581524 230.646979 84.8771384 175.477838 64.0931689\"\n ></polygon>\n <polygon\n fill=\"#111111\"\n points=\"74.6050654 42.7484751 6.6060424e-14 74.2039835 1.83634114e-13 96.0617321 74.6050654 127.078518 80.5221623 105.581524 25.3530206 84.8771384 80.5221623 64.0931689\"\n ></polygon>\n <polygon\n fill=\"#4065C5\"\n points=\"144.339858 -1.59458264e-15 170.003907 -1.59458264e-15 112.990192 167.110525 85.996093 167.110525\"\n ></polygon>\n </g>\n </svg>\n);\n"],"mappings":";;;AAEA,MAAa,YAAyC,UACpD,oBAAC,OAAD;CACE,OAAM;CACN,QAAO;CACP,SAAQ;CACR,SAAQ;CACR,OAAM;CACN,cAAW;CACX,qBAAoB;CACpB,GAAI;WAEJ,qBAAC,KAAD;EACE,oBAAC,WAAD;GACE,MAAK;GACL,QAAO;EACC;EACV,oBAAC,WAAD;GACE,MAAK;GACL,QAAO;EACC;EACV,oBAAC,WAAD;GACE,MAAK;GACL,QAAO;EACC;CACT;AACA"}
1
+ {"version":3,"file":"HTMX.mjs","names":[],"sources":["../../../../../src/components/TechLogo/logos/HTMX.tsx"],"sourcesContent":["import type { FC, SVGProps } from 'react';\n\nexport const HTMXLogo: FC<SVGProps<SVGSVGElement>> = (props) => (\n <svg\n width=\"256px\"\n height=\"168px\"\n viewBox=\"0 0 256 168\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-label=\"HTMX logo\"\n preserveAspectRatio=\"xMidYMid\"\n {...props}\n >\n <g>\n <polygon\n fill=\"currentColor\"\n points=\"181.394935 42.749283 256 74.2039835 256 96.0617321 181.394935 127.078518 175.477838 105.581524 230.646979 84.8771384 175.477838 64.0931689\"\n ></polygon>\n <polygon\n fill=\"currentColor\"\n points=\"74.6050654 42.7484751 6.6060424e-14 74.2039835 1.83634114e-13 96.0617321 74.6050654 127.078518 80.5221623 105.581524 25.3530206 84.8771384 80.5221623 64.0931689\"\n ></polygon>\n <polygon\n fill=\"#4065C5\"\n points=\"144.339858 -1.59458264e-15 170.003907 -1.59458264e-15 112.990192 167.110525 85.996093 167.110525\"\n ></polygon>\n </g>\n </svg>\n);\n"],"mappings":";;;AAEA,MAAa,YAAyC,UACpD,oBAAC,OAAD;CACE,OAAM;CACN,QAAO;CACP,SAAQ;CACR,SAAQ;CACR,OAAM;CACN,cAAW;CACX,qBAAoB;CACpB,GAAI;WAEJ,qBAAC,KAAD;EACE,oBAAC,WAAD;GACE,MAAK;GACL,QAAO;EACC;EACV,oBAAC,WAAD;GACE,MAAK;GACL,QAAO;EACC;EACV,oBAAC,WAAD;GACE,MAAK;GACL,QAAO;EACC;CACT;AACA"}
@@ -1,16 +1,16 @@
1
- import { useKeyboardDetector } from "./useKeyboardDetector.mjs";
2
- import { useGetElementOrWindow } from "./useGetElementOrWindow.mjs";
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 { calculateIsMobile, checkIsIOS, checkIsIphoneOrSafariDevice, checkIsMac, checkIsMobileScreen, checkIsMobileUserAgent, getBreakpointFromSize, useDevice } from "./useDevice.mjs";
8
- import { useSearch } from "./useSearch.mjs";
9
7
  import { useIsMounted } from "./useIsMounted.mjs";
10
- import { useGetElementById } from "./useGetElementById.mjs";
8
+ import { useKeyboardDetector } from "./useKeyboardDetector.mjs";
11
9
  import { useScreenWidth } from "./useScreenWidth.mjs";
12
10
  import { useScrollBlockage } from "./useScrollBlockage/index.mjs";
13
11
  import { useScrollDetection } from "./useScrollDetection.mjs";
12
+ import { useScrollY } from "./useScrollY.mjs";
13
+ import { useSearch } from "./useSearch.mjs";
14
14
  import { useStickToBottom } from "./useStickToBottom.mjs";
15
15
 
16
16
  export { calculateIsMobile, checkIsIOS, checkIsIphoneOrSafariDevice, checkIsMac, checkIsMobileScreen, checkIsMobileUserAgent, getBreakpointFromSize, useDevice, useGetElementById, useGetElementOrWindow, useHorizontalSwipe, useIsMounted, useItemSelector, useKeyboardDetector, usePersistedStore, useScreenWidth, useScrollBlockage, useScrollDetection, useScrollY, useSearch, useStickToBottom };