@intlayer/design-system 8.7.0-canary.0 → 8.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/Browser/Browser.mjs.map +1 -1
- package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +2 -2
- package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +2 -2
- package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +3 -3
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +2 -2
- package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +1 -1
- package/dist/esm/components/Form/elements/FormElement.mjs +2 -1
- package/dist/esm/components/Form/elements/FormElement.mjs.map +1 -1
- package/dist/esm/components/Form/elements/FormElementWrapper.mjs.map +1 -1
- package/dist/esm/components/Form/elements/OTPElement.mjs +1 -1
- package/dist/esm/components/Form/layout/FormItemLayout.mjs +3 -2
- package/dist/esm/components/Form/layout/FormItemLayout.mjs.map +1 -1
- package/dist/esm/components/IDE/MonacoCode.mjs +1 -0
- package/dist/esm/components/IDE/MonacoCode.mjs.map +1 -1
- package/dist/esm/components/Link/Link.mjs.map +1 -1
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +1 -1
- package/dist/esm/components/MarkDownRender/MarkDownRender.mjs +2 -2
- package/dist/esm/components/MarkDownRender/MarkDownRender.mjs.map +1 -1
- package/dist/esm/components/Modal/Modal.mjs +2 -2
- package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
- package/dist/esm/components/Navbar/index.mjs +2 -57
- package/dist/esm/components/Navbar/index.mjs.map +1 -1
- package/dist/esm/components/Pagination/Pagination.mjs +1 -1
- package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -3
- package/dist/esm/components/Table/SmartTable.mjs +222 -0
- package/dist/esm/components/Table/SmartTable.mjs.map +1 -0
- package/dist/esm/components/Table/Table.mjs +7 -212
- package/dist/esm/components/Table/Table.mjs.map +1 -1
- package/dist/esm/components/Table/index.mjs +2 -1
- package/dist/esm/components/TextArea/ContentEditableTextArea.mjs +1 -1
- package/dist/esm/components/TextArea/ContentEditableTextArea.mjs.map +1 -1
- package/dist/esm/components/index.mjs +5 -1
- package/dist/esm/hooks/index.mjs +9 -9
- package/dist/esm/hooks/reactQuery.mjs +1 -3
- package/dist/esm/hooks/reactQuery.mjs.map +1 -1
- package/dist/esm/hooks/useAuth/useOAuth2.mjs +1 -1
- package/dist/esm/hooks/useAuth/useSession.mjs +1 -1
- package/dist/esm/libs/auth.mjs +7 -3
- package/dist/esm/libs/auth.mjs.map +1 -1
- package/dist/esm/routes.mjs +1 -1
- package/dist/esm/routes.mjs.map +1 -1
- package/dist/types/components/Button/Button.d.ts +1 -1
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +1 -1
- package/dist/types/components/Command/index.d.ts +1 -1
- package/dist/types/components/Container/index.d.ts +3 -3
- package/dist/types/components/Form/elements/FormElement.d.ts +1 -0
- package/dist/types/components/Form/elements/FormElement.d.ts.map +1 -1
- package/dist/types/components/Form/layout/FormItemLayout.d.ts +1 -0
- package/dist/types/components/Form/layout/FormItemLayout.d.ts.map +1 -1
- package/dist/types/components/Input/Checkbox.d.ts +1 -1
- package/dist/types/components/Link/Link.d.ts +1 -1
- package/dist/types/components/Link/Link.d.ts.map +1 -1
- package/dist/types/components/MarkDownRender/MarkDownRender.d.ts +3 -3
- package/dist/types/components/MarkDownRender/MarkDownRender.d.ts.map +1 -1
- package/dist/types/components/Navbar/index.d.ts +4 -1
- package/dist/types/components/Navbar/index.d.ts.map +1 -1
- package/dist/types/components/Pagination/Pagination.d.ts +1 -1
- package/dist/types/components/TabSelector/TabSelector.d.ts +1 -1
- package/dist/types/components/Table/SmartTable.d.ts +158 -0
- package/dist/types/components/Table/SmartTable.d.ts.map +1 -0
- package/dist/types/components/Table/Table.d.ts +8 -191
- package/dist/types/components/Table/Table.d.ts.map +1 -1
- package/dist/types/components/Table/index.d.ts +3 -2
- package/dist/types/components/TextArea/ContentEditableTextArea.d.ts +2 -2
- package/dist/types/components/TextArea/ContentEditableTextArea.d.ts.map +1 -1
- package/dist/types/components/Toaster/Toast.d.ts +1 -1
- package/dist/types/components/index.d.ts +6 -2
- package/dist/types/hooks/reactQuery.d.ts.map +1 -1
- package/dist/types/routes.d.ts +1 -1
- package/dist/types/routes.d.ts.map +1 -1
- package/package.json +22 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Browser.mjs","names":[],"sources":["../../../../src/components/Browser/Browser.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { ArrowLeft, ArrowRight, RotateCw } from 'lucide-react';\nimport {\n type CSSProperties,\n type FormEvent,\n type HTMLAttributes,\n type RefObject,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { Input, inputVariants } from '../Input';\n\nexport type BrowserProps = {\n initialUrl?: string;\n path?: string;\n className?: string;\n style?: CSSProperties;\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n 'aria-label'?: string;\n sandbox?: string;\n ref?: RefObject<HTMLIFrameElement | null>;\n domainRestriction?: string;\n} & HTMLAttributes<HTMLIFrameElement>;\n\nexport const Browser = ({\n initialUrl = 'https://example.com',\n path,\n className,\n style,\n size = 'md',\n 'aria-label': ariaLabel,\n sandbox = 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads',\n ref,\n domainRestriction,\n ...props\n}: BrowserProps) => {\n // --- State -----------------------------------------------------------------\n const [inputUrl, setInputUrl] = useState(initialUrl);\n const [currentUrl, setCurrentUrl] = useState(initialUrl);\n\n // History Management\n const [history, setHistory] = useState<string[]>([initialUrl]);\n const [currentIndex, setCurrentIndex] = useState(0);\n\n const [error, setError] = useState<string | null>(null);\n const [submitted, setSubmitted] = useState(false);\n const internalIframeRef = useRef<HTMLIFrameElement>(null);\n\n useImperativeHandle(ref, () => internalIframeRef.current!, []);\n const content = useIntlayer('browser');\n\n // --- Effects ---------------------------------------------------------------\n\n // Reset everything if initialUrl changes completely\n useEffect(() => {\n setInputUrl(initialUrl);\n setCurrentUrl(initialUrl);\n setHistory([initialUrl]);\n setCurrentIndex(0);\n setError(null);\n setSubmitted(false);\n }, [initialUrl]);\n\n // Sync external path changes with the URL bar and History\n useEffect(() => {\n if (!path) return;\n\n try {\n const baseOrigin = domainRestriction ?? initialUrl;\n const origin = new URL(baseOrigin).origin;\n const fullUrl = `${origin}${path}`;\n\n // Update Input (Always update the visual bar)\n setInputUrl(fullUrl);\n\n // Check internal iframe state to avoid reload if already there\n let isAlreadyAtUrl = false;\n if (internalIframeRef.current?.contentWindow) {\n try {\n const currentIframeHref =\n internalIframeRef.current.contentWindow.location.href;\n if (new URL(currentIframeHref).href === new URL(fullUrl).href) {\n isAlreadyAtUrl = true;\n }\n } catch {\n // Cross-origin access ignored\n }\n }\n\n // Update History Stack\n // We perform this check regardless of `isAlreadyAtUrl`.\n // If the path changed (even internally), we want to record it in the arrow stack.\n if (history[currentIndex] !== fullUrl) {\n setHistory((prev) => {\n const newHistory = prev.slice(0, currentIndex + 1);\n newHistory.push(fullUrl);\n return newHistory;\n });\n setCurrentIndex((prev) => prev + 1);\n }\n\n // Navigate (Update src) only if NOT already there\n // This prevents the iframe from refreshing when the user navigated inside it.\n if (!isAlreadyAtUrl) {\n setCurrentUrl(fullUrl);\n }\n\n setError(null);\n } catch {\n // Ignore invalid paths\n }\n }, [path, domainRestriction, initialUrl]); // Removed currentIndex dependency to prevent loops\n\n // --- Navigation Logic ------------------------------------------------------\n\n const handleNavigateTo = (url: string) => {\n try {\n const validated = normalizeUrl(url);\n\n // If we are navigating to the exact same URL, just reload\n if (validated === currentUrl) {\n handleReload();\n return;\n }\n\n setCurrentUrl(validated);\n setInputUrl(validated);\n setError(null);\n\n // Update History: Slice future if we went back, then push new\n const newHistory = history.slice(0, currentIndex + 1);\n newHistory.push(validated);\n setHistory(newHistory);\n setCurrentIndex(newHistory.length - 1);\n } catch (e) {\n if (\n e instanceof Error &&\n e.message === 'URL does not match allowed domain' &&\n domainRestriction\n ) {\n setError(\n content.domainRestrictionError?.value ??\n `Only URLs from ${domainRestriction} are allowed.`\n );\n } else {\n setError(content.errorMessage.value);\n }\n }\n };\n\n const handleBack = () => {\n if (currentIndex > 0) {\n const newIndex = currentIndex - 1;\n const prevUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(prevUrl);\n setInputUrl(prevUrl);\n setError(null);\n }\n };\n\n const handleForward = () => {\n if (currentIndex < history.length - 1) {\n const newIndex = currentIndex + 1;\n const nextUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(nextUrl);\n setInputUrl(nextUrl);\n setError(null);\n }\n };\n\n const handleSubmit = (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitted(true);\n handleNavigateTo(inputUrl);\n };\n\n const handleReload = () => {\n if (internalIframeRef.current) {\n // Create a clean reload effect\n const src = internalIframeRef.current.src;\n internalIframeRef.current.src = '';\n setTimeout(() => {\n if (internalIframeRef.current) internalIframeRef.current.src = src;\n }, 50);\n }\n };\n\n // --- Validation Helpers ----------------------------------------------------\n const isValidHostname = (host: string) => {\n if (host === 'localhost') return true;\n if (/^(\\d{1,3}\\.){3}\\d{1,3}$/.test(host)) return true;\n if (/^[a-f0-9:]+$/i.test(host)) return true;\n if (!/^[a-z0-9.-]+$/i.test(host)) return false;\n if (/^[-.]/.test(host) || /[-.]$/.test(host)) return false;\n if (host.includes('..')) return false;\n if (!host.includes('.')) return false;\n return true;\n };\n\n const getRestrictionOrigin = (): URL | null => {\n if (!domainRestriction) return null;\n try {\n return new URL(domainRestriction);\n } catch {\n return null;\n }\n };\n\n const normalizeUrl = (raw: string) => {\n const trimmed = raw.trim();\n if (!trimmed || /\\s/.test(trimmed)) throw new Error('Invalid');\n\n const restrictionOrigin = getRestrictionOrigin();\n const isRelativePath = trimmed.startsWith('/') && !trimmed.startsWith('//');\n\n if (isRelativePath) {\n if (restrictionOrigin) {\n return new URL(`${restrictionOrigin.origin}${trimmed}`).toString();\n }\n return new URL(`${new URL(currentUrl).origin}${trimmed}`).toString();\n }\n\n const hasProtocol = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed);\n const candidate = hasProtocol ? trimmed : `https://${trimmed}`;\n const url = new URL(candidate);\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error('Only http(s) is allowed');\n }\n\n if (!isValidHostname(url.hostname)) throw new Error('Invalid host');\n\n if (restrictionOrigin) {\n const urlMatches =\n url.hostname === restrictionOrigin.hostname &&\n url.protocol === restrictionOrigin.protocol &&\n (restrictionOrigin.port === '' ||\n url.port === restrictionOrigin.port ||\n url.host === restrictionOrigin.host);\n\n if (!urlMatches) throw new Error('URL does not match allowed domain');\n }\n\n return url.toString();\n };\n\n const showError = submitted && !!error;\n const canGoBack = currentIndex > 0;\n const canGoForward = currentIndex < history.length - 1;\n\n return (\n <section\n className={cn(\n 'flex w-full flex-col overflow-hidden rounded-xl bg-background shadow-[0_4px_12px_rgba(0,0,0,0.4),0_0_1px_rgba(0,0,0,0.2)]',\n className\n )}\n style={style}\n aria-label={ariaLabel ?? content.ariaLabel.value}\n >\n {/* Top bar */}\n <div className=\"relative z-10 flex shrink-0 items-center gap-3 rounded-t-xl bg-text/15 px-4 py-2\">\n {/* Navigation Controls */}\n <div className=\"flex items-center gap-1\">\n <Button\n type=\"button\"\n onClick={handleBack}\n disabled={!canGoBack}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.backButtonLabel.value}\n Icon={ArrowLeft}\n />\n <Button\n type=\"button\"\n onClick={handleForward}\n disabled={!canGoForward}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.forwardButtonLabel.value}\n Icon={ArrowRight}\n />\n </div>\n\n {/* URL Bar */}\n <form\n onSubmit={handleSubmit}\n noValidate\n className={cn(\n inputVariants(),\n 'flex w-full gap-2 rounded-xl p-0.5! supports-[corner-shape:squircle]:rounded-2xl',\n 'bg-neutral/10 text-text/50 placeholder:text-neutral/80'\n )}\n >\n <label htmlFor=\"browser-url\" className=\"sr-only\">\n {content.urlLabel.value}\n </label>\n <Input\n id=\"browser-url\"\n type=\"text\"\n inputMode=\"url\"\n spellCheck={false}\n autoCapitalize=\"off\"\n variant=\"invisible\"\n className=\"ml-3 p-0!\"\n size=\"sm\"\n autoCorrect=\"off\"\n value={inputUrl}\n onChange={(e) => {\n setInputUrl(e.target.value);\n if (showError) setError(null);\n }}\n placeholder={content.urlPlaceholder.value}\n aria-label={content.urlLabel.value}\n aria-invalid={showError}\n aria-describedby={showError ? 'browser-url-error' : undefined}\n />\n\n <Button\n type=\"button\"\n onClick={handleReload}\n variant=\"hoverable\"\n size=\"icon-md\"\n className=\"p-1!\"\n label={'content.reloadButtonTitle.value'}\n Icon={RotateCw}\n />\n\n {/* invisible submit */}\n <button type=\"submit\" className=\"sr-only absolute\" tabIndex={-1} />\n </form>\n\n {/* Error Message Tooltip */}\n {showError && (\n <div className=\"absolute top-full left-4 z-20 mt-1\">\n <p\n id=\"browser-url-error\"\n role=\"alert\"\n aria-live=\"assertive\"\n className=\"rounded-md bg-red-900/90 px-3 py-1.5 text-red-100 text-xs shadow-md backdrop-blur-sm\"\n >\n {error}\n </p>\n </div>\n )}\n </div>\n\n {/* Iframe */}\n <div className=\"relative z-0 flex min-h-0 w-full flex-1 flex-col overflow-hidden rounded-b-xl bg-background\">\n <iframe\n ref={internalIframeRef}\n src={currentUrl}\n title={content.iframeTitle.value}\n className=\"size-full flex-1\"\n sandbox={sandbox}\n loading=\"lazy\"\n aria-live=\"polite\"\n {...props}\n />\n </div>\n </section>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Browser.mjs","names":[],"sources":["../../../../src/components/Browser/Browser.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { ArrowLeft, ArrowRight, RotateCw } from 'lucide-react';\nimport {\n type CSSProperties,\n type SubmitEvent,\n type HTMLAttributes,\n type RefObject,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { Input, inputVariants } from '../Input';\n\nexport type BrowserProps = {\n initialUrl?: string;\n path?: string;\n className?: string;\n style?: CSSProperties;\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n 'aria-label'?: string;\n sandbox?: string;\n ref?: RefObject<HTMLIFrameElement | null>;\n domainRestriction?: string;\n} & HTMLAttributes<HTMLIFrameElement>;\n\nexport const Browser = ({\n initialUrl = 'https://example.com',\n path,\n className,\n style,\n size = 'md',\n 'aria-label': ariaLabel,\n sandbox = 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads',\n ref,\n domainRestriction,\n ...props\n}: BrowserProps) => {\n // --- State -----------------------------------------------------------------\n const [inputUrl, setInputUrl] = useState(initialUrl);\n const [currentUrl, setCurrentUrl] = useState(initialUrl);\n\n // History Management\n const [history, setHistory] = useState<string[]>([initialUrl]);\n const [currentIndex, setCurrentIndex] = useState(0);\n\n const [error, setError] = useState<string | null>(null);\n const [submitted, setSubmitted] = useState(false);\n const internalIframeRef = useRef<HTMLIFrameElement>(null);\n\n useImperativeHandle(ref, () => internalIframeRef.current!, []);\n const content = useIntlayer('browser');\n\n // --- Effects ---------------------------------------------------------------\n\n // Reset everything if initialUrl changes completely\n useEffect(() => {\n setInputUrl(initialUrl);\n setCurrentUrl(initialUrl);\n setHistory([initialUrl]);\n setCurrentIndex(0);\n setError(null);\n setSubmitted(false);\n }, [initialUrl]);\n\n // Sync external path changes with the URL bar and History\n useEffect(() => {\n if (!path) return;\n\n try {\n const baseOrigin = domainRestriction ?? initialUrl;\n const origin = new URL(baseOrigin).origin;\n const fullUrl = `${origin}${path}`;\n\n // Update Input (Always update the visual bar)\n setInputUrl(fullUrl);\n\n // Check internal iframe state to avoid reload if already there\n let isAlreadyAtUrl = false;\n if (internalIframeRef.current?.contentWindow) {\n try {\n const currentIframeHref =\n internalIframeRef.current.contentWindow.location.href;\n if (new URL(currentIframeHref).href === new URL(fullUrl).href) {\n isAlreadyAtUrl = true;\n }\n } catch {\n // Cross-origin access ignored\n }\n }\n\n // Update History Stack\n // We perform this check regardless of `isAlreadyAtUrl`.\n // If the path changed (even internally), we want to record it in the arrow stack.\n if (history[currentIndex] !== fullUrl) {\n setHistory((prev) => {\n const newHistory = prev.slice(0, currentIndex + 1);\n newHistory.push(fullUrl);\n return newHistory;\n });\n setCurrentIndex((prev) => prev + 1);\n }\n\n // Navigate (Update src) only if NOT already there\n // This prevents the iframe from refreshing when the user navigated inside it.\n if (!isAlreadyAtUrl) {\n setCurrentUrl(fullUrl);\n }\n\n setError(null);\n } catch {\n // Ignore invalid paths\n }\n }, [path, domainRestriction, initialUrl]); // Removed currentIndex dependency to prevent loops\n\n // --- Navigation Logic ------------------------------------------------------\n\n const handleNavigateTo = (url: string) => {\n try {\n const validated = normalizeUrl(url);\n\n // If we are navigating to the exact same URL, just reload\n if (validated === currentUrl) {\n handleReload();\n return;\n }\n\n setCurrentUrl(validated);\n setInputUrl(validated);\n setError(null);\n\n // Update History: Slice future if we went back, then push new\n const newHistory = history.slice(0, currentIndex + 1);\n newHistory.push(validated);\n setHistory(newHistory);\n setCurrentIndex(newHistory.length - 1);\n } catch (e) {\n if (\n e instanceof Error &&\n e.message === 'URL does not match allowed domain' &&\n domainRestriction\n ) {\n setError(\n content.domainRestrictionError?.value ??\n `Only URLs from ${domainRestriction} are allowed.`\n );\n } else {\n setError(content.errorMessage.value);\n }\n }\n };\n\n const handleBack = () => {\n if (currentIndex > 0) {\n const newIndex = currentIndex - 1;\n const prevUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(prevUrl);\n setInputUrl(prevUrl);\n setError(null);\n }\n };\n\n const handleForward = () => {\n if (currentIndex < history.length - 1) {\n const newIndex = currentIndex + 1;\n const nextUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(nextUrl);\n setInputUrl(nextUrl);\n setError(null);\n }\n };\n\n const handleSubmit = (e: SubmitEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitted(true);\n handleNavigateTo(inputUrl);\n };\n\n const handleReload = () => {\n if (internalIframeRef.current) {\n // Create a clean reload effect\n const src = internalIframeRef.current.src;\n internalIframeRef.current.src = '';\n setTimeout(() => {\n if (internalIframeRef.current) internalIframeRef.current.src = src;\n }, 50);\n }\n };\n\n // --- Validation Helpers ----------------------------------------------------\n const isValidHostname = (host: string) => {\n if (host === 'localhost') return true;\n if (/^(\\d{1,3}\\.){3}\\d{1,3}$/.test(host)) return true;\n if (/^[a-f0-9:]+$/i.test(host)) return true;\n if (!/^[a-z0-9.-]+$/i.test(host)) return false;\n if (/^[-.]/.test(host) || /[-.]$/.test(host)) return false;\n if (host.includes('..')) return false;\n if (!host.includes('.')) return false;\n return true;\n };\n\n const getRestrictionOrigin = (): URL | null => {\n if (!domainRestriction) return null;\n try {\n return new URL(domainRestriction);\n } catch {\n return null;\n }\n };\n\n const normalizeUrl = (raw: string) => {\n const trimmed = raw.trim();\n if (!trimmed || /\\s/.test(trimmed)) throw new Error('Invalid');\n\n const restrictionOrigin = getRestrictionOrigin();\n const isRelativePath = trimmed.startsWith('/') && !trimmed.startsWith('//');\n\n if (isRelativePath) {\n if (restrictionOrigin) {\n return new URL(`${restrictionOrigin.origin}${trimmed}`).toString();\n }\n return new URL(`${new URL(currentUrl).origin}${trimmed}`).toString();\n }\n\n const hasProtocol = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed);\n const candidate = hasProtocol ? trimmed : `https://${trimmed}`;\n const url = new URL(candidate);\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error('Only http(s) is allowed');\n }\n\n if (!isValidHostname(url.hostname)) throw new Error('Invalid host');\n\n if (restrictionOrigin) {\n const urlMatches =\n url.hostname === restrictionOrigin.hostname &&\n url.protocol === restrictionOrigin.protocol &&\n (restrictionOrigin.port === '' ||\n url.port === restrictionOrigin.port ||\n url.host === restrictionOrigin.host);\n\n if (!urlMatches) throw new Error('URL does not match allowed domain');\n }\n\n return url.toString();\n };\n\n const showError = submitted && !!error;\n const canGoBack = currentIndex > 0;\n const canGoForward = currentIndex < history.length - 1;\n\n return (\n <section\n className={cn(\n 'flex w-full flex-col overflow-hidden rounded-xl bg-background shadow-[0_4px_12px_rgba(0,0,0,0.4),0_0_1px_rgba(0,0,0,0.2)]',\n className\n )}\n style={style}\n aria-label={ariaLabel ?? content.ariaLabel.value}\n >\n {/* Top bar */}\n <div className=\"relative z-10 flex shrink-0 items-center gap-3 rounded-t-xl bg-text/15 px-4 py-2\">\n {/* Navigation Controls */}\n <div className=\"flex items-center gap-1\">\n <Button\n type=\"button\"\n onClick={handleBack}\n disabled={!canGoBack}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.backButtonLabel.value}\n Icon={ArrowLeft}\n />\n <Button\n type=\"button\"\n onClick={handleForward}\n disabled={!canGoForward}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.forwardButtonLabel.value}\n Icon={ArrowRight}\n />\n </div>\n\n {/* URL Bar */}\n <form\n onSubmit={handleSubmit}\n noValidate\n className={cn(\n inputVariants(),\n 'flex w-full gap-2 rounded-xl p-0.5! supports-[corner-shape:squircle]:rounded-2xl',\n 'bg-neutral/10 text-text/50 placeholder:text-neutral/80'\n )}\n >\n <label htmlFor=\"browser-url\" className=\"sr-only\">\n {content.urlLabel.value}\n </label>\n <Input\n id=\"browser-url\"\n type=\"text\"\n inputMode=\"url\"\n spellCheck={false}\n autoCapitalize=\"off\"\n variant=\"invisible\"\n className=\"ml-3 p-0!\"\n size=\"sm\"\n autoCorrect=\"off\"\n value={inputUrl}\n onChange={(e) => {\n setInputUrl(e.target.value);\n if (showError) setError(null);\n }}\n placeholder={content.urlPlaceholder.value}\n aria-label={content.urlLabel.value}\n aria-invalid={showError}\n aria-describedby={showError ? 'browser-url-error' : undefined}\n />\n\n <Button\n type=\"button\"\n onClick={handleReload}\n variant=\"hoverable\"\n size=\"icon-md\"\n className=\"p-1!\"\n label={'content.reloadButtonTitle.value'}\n Icon={RotateCw}\n />\n\n {/* invisible submit */}\n <button type=\"submit\" className=\"sr-only absolute\" tabIndex={-1} />\n </form>\n\n {/* Error Message Tooltip */}\n {showError && (\n <div className=\"absolute top-full left-4 z-20 mt-1\">\n <p\n id=\"browser-url-error\"\n role=\"alert\"\n aria-live=\"assertive\"\n className=\"rounded-md bg-red-900/90 px-3 py-1.5 text-red-100 text-xs shadow-md backdrop-blur-sm\"\n >\n {error}\n </p>\n </div>\n )}\n </div>\n\n {/* Iframe */}\n <div className=\"relative z-0 flex min-h-0 w-full flex-1 flex-col overflow-hidden rounded-b-xl bg-background\">\n <iframe\n ref={internalIframeRef}\n src={currentUrl}\n title={content.iframeTitle.value}\n className=\"size-full flex-1\"\n sandbox={sandbox}\n loading=\"lazy\"\n aria-live=\"polite\"\n {...props}\n />\n </div>\n </section>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useUser } from "../../hooks/useUser/index.mjs";
|
|
4
3
|
import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
|
|
5
4
|
import { AutoCompleteTextarea } from "../TextArea/AutocompleteTextArea.mjs";
|
|
5
|
+
import { useUser } from "../../hooks/useUser/index.mjs";
|
|
6
6
|
import { useEffect, useState } from "react";
|
|
7
7
|
import { Check, X } from "lucide-react";
|
|
8
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -40,7 +40,7 @@ const ContentEditor = ({ dictionary, isDarkMode }) => {
|
|
|
40
40
|
children: [typeof section === "object" && section && !isEditableBaseSection && Object.keys(section).length > 0 && /* @__PURE__ */ jsx(Container, {
|
|
41
41
|
border: true,
|
|
42
42
|
background: "none",
|
|
43
|
-
className: "top-
|
|
43
|
+
className: "top-10 flex h-full flex-col items-start gap-0.5 overflow-auto p-2 md:sticky md:max-w-[50%]",
|
|
44
44
|
roundedSize: "xl",
|
|
45
45
|
transparency: "xs",
|
|
46
46
|
children: /* @__PURE__ */ jsx(NavigationViewNode, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentEditor.mjs","names":[],"sources":["../../../../src/components/DictionaryFieldEditor/ContentEditor.tsx"],"sourcesContent":["'use client';\n\nimport { getContentNodeByKeyPath } from '@intlayer/core/dictionaryManipulator';\nimport {\n useEditedContent,\n useEditorLocale,\n useFocusUnmergedDictionary,\n} from '@intlayer/editor-react';\nimport type { Dictionary, LocalDictionaryId } from '@intlayer/types/dictionary';\nimport { type FC, useEffect } from 'react';\nimport { Container } from '../Container';\nimport { LocaleSwitcherContent } from '../LocaleSwitcherContentDropDown';\nimport { TextEditorContainer } from './ContentEditorView/TextEditor';\nimport { getIsEditableSection } from './getIsEditableSection';\nimport { KeyPathBreadcrumb } from './KeyPathBreadcrumb';\nimport { NavigationViewNode } from './NavigationView/NavigationViewNode';\n\ntype NodeEditorProps = {\n dictionary: Dictionary;\n isDarkMode?: boolean;\n};\n\nexport const ContentEditor: FC<NodeEditorProps> = ({\n dictionary,\n isDarkMode,\n}) => {\n const { content, key, localId } = dictionary;\n const { editedContent } = useEditedContent();\n const { focusedContent, setFocusedContentKeyPath } =\n useFocusUnmergedDictionary();\n\n const focusedKeyPath = focusedContent?.keyPath;\n const section =\n typeof editedContent?.[localId as LocalDictionaryId]?.content ===\n 'undefined'\n ? content\n : editedContent?.[localId as LocalDictionaryId]?.content;\n\n const currentLocale = useEditorLocale();\n const focusedSection = getContentNodeByKeyPath(\n section,\n focusedKeyPath ?? [],\n currentLocale\n );\n const isEditableBaseSection = getIsEditableSection(section);\n const isEditableFocusedSection = getIsEditableSection(focusedSection);\n\n useEffect(() => {\n if (typeof focusedSection === 'undefined') {\n setFocusedContentKeyPath(focusedContent?.keyPath?.slice(0, -1) ?? []);\n }\n }, []);\n\n return (\n <div>\n <div className=\"mb-6 flex items-center justify-between gap-2\">\n <KeyPathBreadcrumb\n dictionaryKey={key}\n keyPath={focusedKeyPath ?? []}\n onClickKeyPath={setFocusedContentKeyPath}\n />\n <div className=\"flex items-center gap-2\">\n <LocaleSwitcherContent />\n </div>\n </div>\n <div className=\"flex flex-1 gap-2 overflow-visible max-md:flex-col\">\n {typeof section === 'object' &&\n section &&\n !isEditableBaseSection &&\n Object.keys(section).length > 0 && (\n <Container\n border\n background=\"none\"\n className=\"top-
|
|
1
|
+
{"version":3,"file":"ContentEditor.mjs","names":[],"sources":["../../../../src/components/DictionaryFieldEditor/ContentEditor.tsx"],"sourcesContent":["'use client';\n\nimport { getContentNodeByKeyPath } from '@intlayer/core/dictionaryManipulator';\nimport {\n useEditedContent,\n useEditorLocale,\n useFocusUnmergedDictionary,\n} from '@intlayer/editor-react';\nimport type { Dictionary, LocalDictionaryId } from '@intlayer/types/dictionary';\nimport { type FC, useEffect } from 'react';\nimport { Container } from '../Container';\nimport { LocaleSwitcherContent } from '../LocaleSwitcherContentDropDown';\nimport { TextEditorContainer } from './ContentEditorView/TextEditor';\nimport { getIsEditableSection } from './getIsEditableSection';\nimport { KeyPathBreadcrumb } from './KeyPathBreadcrumb';\nimport { NavigationViewNode } from './NavigationView/NavigationViewNode';\n\ntype NodeEditorProps = {\n dictionary: Dictionary;\n isDarkMode?: boolean;\n};\n\nexport const ContentEditor: FC<NodeEditorProps> = ({\n dictionary,\n isDarkMode,\n}) => {\n const { content, key, localId } = dictionary;\n const { editedContent } = useEditedContent();\n const { focusedContent, setFocusedContentKeyPath } =\n useFocusUnmergedDictionary();\n\n const focusedKeyPath = focusedContent?.keyPath;\n const section =\n typeof editedContent?.[localId as LocalDictionaryId]?.content ===\n 'undefined'\n ? content\n : editedContent?.[localId as LocalDictionaryId]?.content;\n\n const currentLocale = useEditorLocale();\n const focusedSection = getContentNodeByKeyPath(\n section,\n focusedKeyPath ?? [],\n currentLocale\n );\n const isEditableBaseSection = getIsEditableSection(section);\n const isEditableFocusedSection = getIsEditableSection(focusedSection);\n\n useEffect(() => {\n if (typeof focusedSection === 'undefined') {\n setFocusedContentKeyPath(focusedContent?.keyPath?.slice(0, -1) ?? []);\n }\n }, []);\n\n return (\n <div>\n <div className=\"mb-6 flex items-center justify-between gap-2\">\n <KeyPathBreadcrumb\n dictionaryKey={key}\n keyPath={focusedKeyPath ?? []}\n onClickKeyPath={setFocusedContentKeyPath}\n />\n <div className=\"flex items-center gap-2\">\n <LocaleSwitcherContent />\n </div>\n </div>\n <div className=\"flex flex-1 gap-2 overflow-visible max-md:flex-col\">\n {typeof section === 'object' &&\n section &&\n !isEditableBaseSection &&\n Object.keys(section).length > 0 && (\n <Container\n border\n background=\"none\"\n className=\"top-10 flex h-full flex-col items-start gap-0.5 overflow-auto p-2 md:sticky md:max-w-[50%]\"\n roundedSize=\"xl\"\n transparency=\"xs\"\n >\n <NavigationViewNode\n keyPath={[]}\n section={section}\n dictionary={dictionary}\n />\n </Container>\n )}\n {(isEditableFocusedSection || (focusedKeyPath ?? []).length > 0) && (\n <TextEditorContainer\n keyPath={focusedKeyPath ?? []}\n section={focusedSection}\n dictionary={dictionary}\n isDarkMode={isDarkMode}\n />\n )}\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;AAsBA,MAAa,iBAAsC,EACjD,YACA,iBACI;CACJ,MAAM,EAAE,SAAS,KAAK,YAAY;CAClC,MAAM,EAAE,kBAAkB,kBAAkB;CAC5C,MAAM,EAAE,gBAAgB,6BACtB,4BAA4B;CAE9B,MAAM,iBAAiB,gBAAgB;CACvC,MAAM,UACJ,OAAO,gBAAgB,UAA+B,YACtD,cACI,UACA,gBAAgB,UAA+B;CAErD,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,iBAAiB,wBACrB,SACA,kBAAkB,EAAE,EACpB,cACD;CACD,MAAM,wBAAwB,qBAAqB,QAAQ;CAC3D,MAAM,2BAA2B,qBAAqB,eAAe;AAErE,iBAAgB;AACd,MAAI,OAAO,mBAAmB,YAC5B,0BAAyB,gBAAgB,SAAS,MAAM,GAAG,GAAG,IAAI,EAAE,CAAC;IAEtE,EAAE,CAAC;AAEN,QACE,qBAAC,OAAD,aACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,mBAAD;GACE,eAAe;GACf,SAAS,kBAAkB,EAAE;GAC7B,gBAAgB;GAChB,GACF,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,uBAAD,EAAyB;GACrB,EACF;KACN,qBAAC,OAAD;EAAK,WAAU;YAAf,CACG,OAAO,YAAY,YAClB,WACA,CAAC,yBACD,OAAO,KAAK,QAAQ,CAAC,SAAS,KAC5B,oBAAC,WAAD;GACE;GACA,YAAW;GACX,WAAU;GACV,aAAY;GACZ,cAAa;aAEb,oBAAC,oBAAD;IACE,SAAS,EAAE;IACF;IACG;IACZ;GACQ,IAEd,6BAA6B,kBAAkB,EAAE,EAAE,SAAS,MAC5D,oBAAC,qBAAD;GACE,SAAS,kBAAkB,EAAE;GAC7B,SAAS;GACG;GACA;GACZ,EAEA;IACF"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useAuditContentDeclarationField } from "../../../hooks/reactQuery.mjs";
|
|
4
3
|
import { Container } from "../../Container/index.mjs";
|
|
5
4
|
import { Button, ButtonColor, ButtonSize, ButtonTextAlign, ButtonVariant } from "../../Button/Button.mjs";
|
|
6
5
|
import { InputVariant } from "../../Input/Input.mjs";
|
|
7
6
|
import { SwitchSelector, SwitchSelectorColor, SwitchSelectorSize } from "../../SwitchSelector/index.mjs";
|
|
8
7
|
import { useLocaleSwitcherContent } from "../../LocaleSwitcherContentDropDown/LocaleSwitcherContentContext.mjs";
|
|
9
8
|
import { ContentEditorInput as ContentEditorInput$1 } from "../../ContentEditor/ContentEditorInput.mjs";
|
|
9
|
+
import { useAuditContentDeclarationField } from "../../../hooks/reactQuery.mjs";
|
|
10
10
|
import { ContentEditorTextArea as ContentEditorTextArea$1 } from "../../ContentEditor/ContentEditorTextArea.mjs";
|
|
11
11
|
import { renameKey } from "./object.mjs";
|
|
12
12
|
import { Label } from "../../Label/index.mjs";
|
|
@@ -15,9 +15,9 @@ import { EnumKeyInput } from "../EnumKeyInput.mjs";
|
|
|
15
15
|
import { Fragment, useState } from "react";
|
|
16
16
|
import { Plus, Trash, WandSparkles } from "lucide-react";
|
|
17
17
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
18
|
-
import { useConfiguration, useEditedContent } from "@intlayer/editor-react";
|
|
19
18
|
import { useIntlayer, useLocale } from "react-intlayer";
|
|
20
19
|
import { getLocaleName } from "@intlayer/core/localization";
|
|
20
|
+
import { useConfiguration, useEditedContent } from "@intlayer/editor-react";
|
|
21
21
|
import { getEmptyNode, getNodeType } from "@intlayer/core/dictionaryManipulator";
|
|
22
22
|
import * as NodeTypes from "@intlayer/types/nodeType";
|
|
23
23
|
|
package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { ButtonColor } from "../../Button/Button.mjs";
|
|
3
4
|
import { useSession } from "../../../hooks/useAuth/useSession.mjs";
|
|
4
5
|
import { useAddDictionary, useGetProjects } from "../../../hooks/reactQuery.mjs";
|
|
5
|
-
import { ButtonColor } from "../../Button/Button.mjs";
|
|
6
6
|
import { MultiSelect } from "../../Select/Multiselect.mjs";
|
|
7
7
|
import { useForm } from "../../Form/FormBase.mjs";
|
|
8
8
|
import { Form } from "../../Form/Form.mjs";
|
|
@@ -17,7 +17,7 @@ const DictionaryCreationForm = ({ onDictionaryCreated }) => {
|
|
|
17
17
|
const { mutate: addDictionary, isPending } = useAddDictionary();
|
|
18
18
|
const { data: projectsData } = useGetProjects();
|
|
19
19
|
const DictionarySchema = useDictionarySchema(String(project?.id));
|
|
20
|
-
const { form, isSubmitting } = useForm(DictionarySchema);
|
|
20
|
+
const { form, isSubmitting } = useForm(DictionarySchema, { defaultValues: { projectIds: [project?.id] } });
|
|
21
21
|
const { keyInput, createDictionaryButton, projectInput } = useIntlayer("dictionary-form");
|
|
22
22
|
const onSubmitSuccess = (data) => {
|
|
23
23
|
addDictionary({ dictionary: data }, { onSuccess: () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DictionaryCreationForm.mjs","names":[],"sources":["../../../../../src/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.tsx"],"sourcesContent":["'use client';\n\nimport { ButtonColor } from '@components/Button';\nimport { Form, useForm } from '@components/Form';\nimport { MultiSelect } from '@components/Select';\nimport { useAddDictionary, useGetProjects } from '@hooks/reactQuery';\nimport { useSession } from '@hooks/useAuth';\nimport type { FC } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport {\n type DictionaryFormData,\n useDictionarySchema,\n} from './useDictionaryFormSchema';\n\ntype DictionaryCreationFormProps = {\n onDictionaryCreated?: () => void;\n};\n\nexport const DictionaryCreationForm: FC<DictionaryCreationFormProps> = ({\n onDictionaryCreated,\n}) => {\n const { session } = useSession();\n const { project } = session ?? {};\n const { mutate: addDictionary, isPending } = useAddDictionary();\n const { data: projectsData } = useGetProjects();\n const DictionarySchema = useDictionarySchema(String(project?.id));\n const { form, isSubmitting } = useForm(DictionarySchema);\n const { keyInput, createDictionaryButton, projectInput } =\n useIntlayer('dictionary-form');\n\n const onSubmitSuccess = (data: DictionaryFormData) => {\n addDictionary(\n { dictionary: data },\n {\n onSuccess: () => {\n onDictionaryCreated?.();\n },\n }\n );\n };\n\n return (\n <Form\n schema={DictionarySchema}\n onSubmitSuccess={onSubmitSuccess}\n className=\"m-auto w-full max-w-[400px]\"\n {...form}\n >\n <Form.Input\n name=\"key\"\n label={keyInput.label.value}\n placeholder={keyInput.placeholder.value}\n isRequired\n />\n\n <Form.MultiSelect name=\"projectIds\" label={projectInput.label.value}>\n <MultiSelect.Trigger\n getBadgeValue={(value) =>\n projectsData?.data?.find((project) => String(project.id) === value)\n ?.name ?? value\n }\n >\n <MultiSelect.Input placeholder={projectInput.placeholder.value} />\n </MultiSelect.Trigger>\n <MultiSelect.Content>\n <MultiSelect.List>\n {projectsData?.data?.map((project) => (\n <MultiSelect.Item\n key={String(project.id)}\n value={String(project.id)}\n >\n {project.name}\n </MultiSelect.Item>\n ))}\n </MultiSelect.List>\n </MultiSelect.Content>\n </Form.MultiSelect>\n\n <Form.Button\n className=\"mt-12 ml-auto\"\n type=\"submit\"\n color={ButtonColor.TEXT}\n isLoading={isSubmitting || isPending}\n label={createDictionaryButton.ariaLabel.value}\n isFullWidth\n >\n {createDictionaryButton.text}\n </Form.Button>\n </Form>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAkBA,MAAa,0BAA2D,EACtE,0BACI;CACJ,MAAM,EAAE,YAAY,YAAY;CAChC,MAAM,EAAE,YAAY,WAAW,EAAE;CACjC,MAAM,EAAE,QAAQ,eAAe,cAAc,kBAAkB;CAC/D,MAAM,EAAE,MAAM,iBAAiB,gBAAgB;CAC/C,MAAM,mBAAmB,oBAAoB,OAAO,SAAS,GAAG,CAAC;CACjE,MAAM,EAAE,MAAM,iBAAiB,QAAQ,
|
|
1
|
+
{"version":3,"file":"DictionaryCreationForm.mjs","names":[],"sources":["../../../../../src/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.tsx"],"sourcesContent":["'use client';\n\nimport { ButtonColor } from '@components/Button';\nimport { Form, useForm } from '@components/Form';\nimport { MultiSelect } from '@components/Select';\nimport { useAddDictionary, useGetProjects } from '@hooks/reactQuery';\nimport { useSession } from '@hooks/useAuth';\nimport type { FC } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport {\n type DictionaryFormData,\n useDictionarySchema,\n} from './useDictionaryFormSchema';\n\ntype DictionaryCreationFormProps = {\n onDictionaryCreated?: () => void;\n};\n\nexport const DictionaryCreationForm: FC<DictionaryCreationFormProps> = ({\n onDictionaryCreated,\n}) => {\n const { session } = useSession();\n const { project } = session ?? {};\n const { mutate: addDictionary, isPending } = useAddDictionary();\n const { data: projectsData } = useGetProjects();\n const DictionarySchema = useDictionarySchema(String(project?.id));\n const { form, isSubmitting } = useForm(DictionarySchema, {\n defaultValues: {\n projectIds: [project?.id],\n },\n });\n const { keyInput, createDictionaryButton, projectInput } =\n useIntlayer('dictionary-form');\n\n const onSubmitSuccess = (data: DictionaryFormData) => {\n addDictionary(\n { dictionary: data },\n {\n onSuccess: () => {\n onDictionaryCreated?.();\n },\n }\n );\n };\n\n return (\n <Form\n schema={DictionarySchema}\n onSubmitSuccess={onSubmitSuccess}\n className=\"m-auto w-full max-w-[400px]\"\n {...form}\n >\n <Form.Input\n name=\"key\"\n label={keyInput.label.value}\n placeholder={keyInput.placeholder.value}\n isRequired\n />\n\n <Form.MultiSelect name=\"projectIds\" label={projectInput.label.value}>\n <MultiSelect.Trigger\n getBadgeValue={(value) =>\n projectsData?.data?.find((project) => String(project.id) === value)\n ?.name ?? value\n }\n >\n <MultiSelect.Input placeholder={projectInput.placeholder.value} />\n </MultiSelect.Trigger>\n <MultiSelect.Content>\n <MultiSelect.List>\n {projectsData?.data?.map((project) => (\n <MultiSelect.Item\n key={String(project.id)}\n value={String(project.id)}\n >\n {project.name}\n </MultiSelect.Item>\n ))}\n </MultiSelect.List>\n </MultiSelect.Content>\n </Form.MultiSelect>\n\n <Form.Button\n className=\"mt-12 ml-auto\"\n type=\"submit\"\n color={ButtonColor.TEXT}\n isLoading={isSubmitting || isPending}\n label={createDictionaryButton.ariaLabel.value}\n isFullWidth\n >\n {createDictionaryButton.text}\n </Form.Button>\n </Form>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAkBA,MAAa,0BAA2D,EACtE,0BACI;CACJ,MAAM,EAAE,YAAY,YAAY;CAChC,MAAM,EAAE,YAAY,WAAW,EAAE;CACjC,MAAM,EAAE,QAAQ,eAAe,cAAc,kBAAkB;CAC/D,MAAM,EAAE,MAAM,iBAAiB,gBAAgB;CAC/C,MAAM,mBAAmB,oBAAoB,OAAO,SAAS,GAAG,CAAC;CACjE,MAAM,EAAE,MAAM,iBAAiB,QAAQ,kBAAkB,EACvD,eAAe,EACb,YAAY,CAAC,SAAS,GAAG,EAC1B,EACF,CAAC;CACF,MAAM,EAAE,UAAU,wBAAwB,iBACxC,YAAY,kBAAkB;CAEhC,MAAM,mBAAmB,SAA6B;AACpD,gBACE,EAAE,YAAY,MAAM,EACpB,EACE,iBAAiB;AACf,0BAAuB;KAE1B,CACF;;AAGH,QACE,qBAAC,MAAD;EACE,QAAQ;EACS;EACjB,WAAU;EACV,GAAI;YAJN;GAME,oBAAC,KAAK,OAAN;IACE,MAAK;IACL,OAAO,SAAS,MAAM;IACtB,aAAa,SAAS,YAAY;IAClC;IACA;GAEF,qBAAC,KAAK,aAAN;IAAkB,MAAK;IAAa,OAAO,aAAa,MAAM;cAA9D,CACE,oBAAC,YAAY,SAAb;KACE,gBAAgB,UACd,cAAc,MAAM,MAAM,YAAY,OAAO,QAAQ,GAAG,KAAK,MAAM,EAC/D,QAAQ;eAGd,oBAAC,YAAY,OAAb,EAAmB,aAAa,aAAa,YAAY,OAAS;KAC9C,GACtB,oBAAC,YAAY,SAAb,YACE,oBAAC,YAAY,MAAb,YACG,cAAc,MAAM,KAAK,YACxB,oBAAC,YAAY,MAAb;KAEE,OAAO,OAAO,QAAQ,GAAG;eAExB,QAAQ;KACQ,EAJZ,OAAO,QAAQ,GAAG,CAIN,CACnB,EACe,GACC,EACL;;GAEnB,oBAAC,KAAK,QAAN;IACE,WAAU;IACV,MAAK;IACL,OAAO,YAAY;IACnB,WAAW,gBAAgB;IAC3B,OAAO,uBAAuB,UAAU;IACxC;cAEC,uBAAuB;IACZ;GACT"}
|
package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useSession } from "../../../hooks/useAuth/useSession.mjs";
|
|
4
|
-
import { useAuditContentDeclarationMetadata, useGetProjects, useGetTags } from "../../../hooks/reactQuery.mjs";
|
|
5
3
|
import { Loader } from "../../Loader/index.mjs";
|
|
6
4
|
import { ButtonColor, ButtonSize, ButtonVariant } from "../../Button/Button.mjs";
|
|
7
5
|
import { Checkbox } from "../../Input/Checkbox.mjs";
|
|
6
|
+
import { useSession } from "../../../hooks/useAuth/useSession.mjs";
|
|
7
|
+
import { useAuditContentDeclarationMetadata, useGetProjects, useGetTags } from "../../../hooks/reactQuery.mjs";
|
|
8
8
|
import { MultiSelect } from "../../Select/Multiselect.mjs";
|
|
9
9
|
import { Select } from "../../Select/Select.mjs";
|
|
10
10
|
import { useForm as useForm$1 } from "../../Form/FormBase.mjs";
|
|
@@ -13,8 +13,8 @@ import { useDictionaryDetailsSchema } from "./useDictionaryDetailsSchema.mjs";
|
|
|
13
13
|
import { useEffect } from "react";
|
|
14
14
|
import { WandSparkles } from "lucide-react";
|
|
15
15
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
-
import { useEditedContent } from "@intlayer/editor-react";
|
|
17
16
|
import { useIntlayer } from "react-intlayer";
|
|
17
|
+
import { useEditedContent } from "@intlayer/editor-react";
|
|
18
18
|
import { AnimatePresence, motion } from "framer-motion";
|
|
19
19
|
import { useWatch } from "react-hook-form";
|
|
20
20
|
|
|
@@ -12,8 +12,8 @@ import { StructureEditor } from "./StructureEditor.mjs";
|
|
|
12
12
|
import { useEffect } from "react";
|
|
13
13
|
import { ArrowLeft } from "lucide-react";
|
|
14
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
-
import { useConfiguration, useDictionariesRecordActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
|
|
16
15
|
import { useIntlayer } from "react-intlayer";
|
|
16
|
+
import { useConfiguration, useDictionariesRecordActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
|
|
17
17
|
|
|
18
18
|
//#region src/components/DictionaryFieldEditor/DictionaryFieldEditor.tsx
|
|
19
19
|
const DictionaryFieldEditor = ({ dictionary, onClickDictionaryList, isDarkMode, mode, onDelete, onSave, showReturnButton = true }) => {
|
|
@@ -3,9 +3,9 @@ import { Accordion } from "../../Accordion/Accordion.mjs";
|
|
|
3
3
|
import { getIsEditableSection } from "../getIsEditableSection.mjs";
|
|
4
4
|
import { ChevronRight, Plus } from "lucide-react";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
-
import { useEditedContentActions, useEditorLocale, useFocusUnmergedDictionary } from "@intlayer/editor-react";
|
|
7
6
|
import { internationalization } from "@intlayer/config/built";
|
|
8
7
|
import { useIntlayer } from "react-intlayer";
|
|
8
|
+
import { useEditedContentActions, useEditorLocale, useFocusUnmergedDictionary } from "@intlayer/editor-react";
|
|
9
9
|
import { getContentNodeByKeyPath, getEmptyNode, getNodeType } from "@intlayer/core/dictionaryManipulator";
|
|
10
10
|
import * as NodeTypes from "@intlayer/types/nodeType";
|
|
11
11
|
import { isSameKeyPath } from "@intlayer/core/utils";
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../../utils/cn.mjs";
|
|
4
|
+
import { ButtonColor, ButtonVariant } from "../../Button/Button.mjs";
|
|
4
5
|
import { useAuth } from "../../../hooks/useAuth/useAuth.mjs";
|
|
5
6
|
import { useDeleteDictionary, usePushDictionaries, useWriteDictionary } from "../../../hooks/reactQuery.mjs";
|
|
6
|
-
import { ButtonColor, ButtonVariant } from "../../Button/Button.mjs";
|
|
7
7
|
import { Modal, ModalSize } from "../../Modal/Modal.mjs";
|
|
8
8
|
import { Form } from "../../Form/Form.mjs";
|
|
9
9
|
import { useState } from "react";
|
|
10
10
|
import { ArrowUpFromLine, Download, RotateCcw, Save, Trash } from "lucide-react";
|
|
11
11
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
-
import { useDictionariesRecordActions, useEditedContent } from "@intlayer/editor-react";
|
|
13
12
|
import { useIntlayer } from "react-intlayer";
|
|
13
|
+
import { useDictionariesRecordActions, useEditedContent } from "@intlayer/editor-react";
|
|
14
14
|
|
|
15
15
|
//#region src/components/DictionaryFieldEditor/SaveForm/SaveForm.tsx
|
|
16
16
|
const SaveForm = ({ dictionary, mode, className, onDelete, onSave, ...props }) => {
|
|
@@ -7,8 +7,8 @@ import { EditableFieldInput } from "../../EditableField/EditableFieldInput.mjs";
|
|
|
7
7
|
import { NodeTypeSelector } from "../NodeTypeSelector.mjs";
|
|
8
8
|
import { Plus, Trash } from "lucide-react";
|
|
9
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import { useConfiguration, useEditedContentActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
|
|
11
10
|
import { useIntlayer } from "react-intlayer";
|
|
11
|
+
import { useConfiguration, useEditedContentActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
|
|
12
12
|
import { getDefaultNode, getNodeChildren, getNodeType } from "@intlayer/core/dictionaryManipulator";
|
|
13
13
|
import * as NodeTypes from "@intlayer/types/nodeType";
|
|
14
14
|
import { isSameKeyPath } from "@intlayer/core/utils";
|
|
@@ -7,7 +7,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
7
7
|
import { useFormContext } from "react-hook-form";
|
|
8
8
|
|
|
9
9
|
//#region src/components/Form/elements/FormElement.tsx
|
|
10
|
-
const FormFieldElement = ({ field, name, label, Element, isRequired = false, info, description, showErrorMessage = true, ...props }) => {
|
|
10
|
+
const FormFieldElement = ({ field, name, label, Element, isRequired = false, info, description, showErrorMessage = true, layoutClassName, ...props }) => {
|
|
11
11
|
const { error } = useFormField();
|
|
12
12
|
const { value: fieldValue, onChange: fieldOnChange, ...fieldRest } = field ?? {};
|
|
13
13
|
const propsAny = props;
|
|
@@ -24,6 +24,7 @@ const FormFieldElement = ({ field, name, label, Element, isRequired = false, inf
|
|
|
24
24
|
info,
|
|
25
25
|
showErrorMessage,
|
|
26
26
|
"aria-invalid": !!error,
|
|
27
|
+
className: layoutClassName,
|
|
27
28
|
children: /* @__PURE__ */ jsx(Element, {
|
|
28
29
|
"data-testid": "element",
|
|
29
30
|
id: name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormElement.mjs","names":[],"sources":["../../../../../src/components/Form/elements/FormElement.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps, ElementType, ReactNode } from 'react';\nimport {\n type ControllerRenderProps,\n type FieldValues,\n useFormContext,\n} from 'react-hook-form';\nimport { Form } from '../Form';\nimport { useFormField } from '../FormField';\nimport { FormItemLayout, type FormItemLayoutProps } from '../layout';\n\nexport type FormElementProps<T extends ElementType> = {\n name: string;\n Element: T;\n label?: ReactNode;\n isRequired?: boolean;\n info?: string;\n showErrorMessage?: boolean;\n focus?: boolean;\n} & Omit<FormItemLayoutProps, 'children'>;\n\ntype FormFieldElementProps<T extends ElementType> = FormElementProps<T> &\n ComponentProps<T> & {\n field: ControllerRenderProps<FieldValues, string>;\n };\n\nconst FormFieldElement = <T extends ElementType>({\n field,\n name,\n label,\n Element,\n isRequired = false,\n info,\n description,\n showErrorMessage = true,\n ...props\n}: FormFieldElementProps<T>) => {\n const { error } = useFormField();\n\n // Ensure controlled inputs and merge onChange with RHF controller\n const {\n value: fieldValue,\n onChange: fieldOnChange,\n ...fieldRest\n } = (field as unknown as {\n value: unknown;\n onChange: (...args: unknown[]) => void;\n }) ?? {};\n\n const propsAny = props as unknown as {\n value?: unknown;\n onChange?: (...args: unknown[]) => void;\n children?: unknown;\n };\n\n const mergedValue =\n propsAny.value !== undefined ? propsAny.value : (fieldValue ?? '');\n\n const mergedOnChange = (...args: unknown[]) => {\n if (typeof fieldOnChange === 'function') fieldOnChange(...args);\n if (typeof propsAny.onChange === 'function') propsAny.onChange(...args);\n };\n\n return (\n <FormItemLayout\n htmlFor={name}\n label={label}\n description={description}\n isRequired={isRequired}\n info={info}\n showErrorMessage={showErrorMessage}\n aria-invalid={!!error}\n >\n <Element\n data-testid=\"element\"\n id={name}\n {...fieldRest}\n {...props}\n // Force controlled value to avoid uncontrolled-to-controlled warnings\n value={mergedValue as never}\n // Merge onChange so RHF stays in sync while allowing custom handlers\n onChange={mergedOnChange as never}\n >\n {props.children}\n </Element>\n </FormItemLayout>\n );\n};\n\n/**\n * FormElement is a component that allows you to create a form element with a label, description, error message, and validation.\n *\n * The Element prop is the type of the element that will be rendered.\n * This element will interact with the FormContext and will be controlled by the FormControl component.\n * The props used to control the element will be `value` and `onChange`.\n */\nexport const FormElement = <T extends ElementType>(\n props: FormElementProps<T> & ComponentProps<T>\n) => {\n const { control } = useFormContext();\n\n return (\n <Form.Field\n control={control}\n name={props.name}\n render={({ field }) => <FormFieldElement {...props} field={field} />}\n />\n );\n};\n"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"FormElement.mjs","names":[],"sources":["../../../../../src/components/Form/elements/FormElement.tsx"],"sourcesContent":["'use client';\n\nimport type { ComponentProps, ElementType, ReactNode } from 'react';\nimport {\n type ControllerRenderProps,\n type FieldValues,\n useFormContext,\n} from 'react-hook-form';\nimport { Form } from '../Form';\nimport { useFormField } from '../FormField';\nimport { FormItemLayout, type FormItemLayoutProps } from '../layout';\n\nexport type FormElementProps<T extends ElementType> = {\n name: string;\n Element: T;\n label?: ReactNode;\n isRequired?: boolean;\n info?: string;\n showErrorMessage?: boolean;\n focus?: boolean;\n layoutClassName?: string;\n} & Omit<FormItemLayoutProps, 'children'>;\n\ntype FormFieldElementProps<T extends ElementType> = FormElementProps<T> &\n ComponentProps<T> & {\n field: ControllerRenderProps<FieldValues, string>;\n };\n\nconst FormFieldElement = <T extends ElementType>({\n field,\n name,\n label,\n Element,\n isRequired = false,\n info,\n description,\n showErrorMessage = true,\n layoutClassName,\n ...props\n}: FormFieldElementProps<T>) => {\n const { error } = useFormField();\n\n // Ensure controlled inputs and merge onChange with RHF controller\n const {\n value: fieldValue,\n onChange: fieldOnChange,\n ...fieldRest\n } = (field as unknown as {\n value: unknown;\n onChange: (...args: unknown[]) => void;\n }) ?? {};\n\n const propsAny = props as unknown as {\n value?: unknown;\n onChange?: (...args: unknown[]) => void;\n children?: unknown;\n };\n\n const mergedValue =\n propsAny.value !== undefined ? propsAny.value : (fieldValue ?? '');\n\n const mergedOnChange = (...args: unknown[]) => {\n if (typeof fieldOnChange === 'function') fieldOnChange(...args);\n if (typeof propsAny.onChange === 'function') propsAny.onChange(...args);\n };\n\n return (\n <FormItemLayout\n htmlFor={name}\n label={label}\n description={description}\n isRequired={isRequired}\n info={info}\n showErrorMessage={showErrorMessage}\n aria-invalid={!!error}\n className={layoutClassName}\n >\n <Element\n data-testid=\"element\"\n id={name}\n {...fieldRest}\n {...props}\n // Force controlled value to avoid uncontrolled-to-controlled warnings\n value={mergedValue as never}\n // Merge onChange so RHF stays in sync while allowing custom handlers\n onChange={mergedOnChange as never}\n >\n {props.children}\n </Element>\n </FormItemLayout>\n );\n};\n\n/**\n * FormElement is a component that allows you to create a form element with a label, description, error message, and validation.\n *\n * The Element prop is the type of the element that will be rendered.\n * This element will interact with the FormContext and will be controlled by the FormControl component.\n * The props used to control the element will be `value` and `onChange`.\n */\nexport const FormElement = <T extends ElementType>(\n props: FormElementProps<T> & ComponentProps<T>\n) => {\n const { control } = useFormContext();\n\n return (\n <Form.Field\n control={control}\n name={props.name}\n render={({ field }) => <FormFieldElement {...props} field={field} />}\n />\n );\n};\n"],"mappings":";;;;;;;;;AA4BA,MAAM,oBAA2C,EAC/C,OACA,MACA,OACA,SACA,aAAa,OACb,MACA,aACA,mBAAmB,MACnB,iBACA,GAAG,YAC2B;CAC9B,MAAM,EAAE,UAAU,cAAc;CAGhC,MAAM,EACJ,OAAO,YACP,UAAU,eACV,GAAG,cACA,SAGC,EAAE;CAER,MAAM,WAAW;CAMjB,MAAM,cACJ,SAAS,UAAU,SAAY,SAAS,QAAS,cAAc;CAEjE,MAAM,kBAAkB,GAAG,SAAoB;AAC7C,MAAI,OAAO,kBAAkB,WAAY,eAAc,GAAG,KAAK;AAC/D,MAAI,OAAO,SAAS,aAAa,WAAY,UAAS,SAAS,GAAG,KAAK;;AAGzE,QACE,oBAAC,gBAAD;EACE,SAAS;EACF;EACM;EACD;EACN;EACY;EAClB,gBAAc,CAAC,CAAC;EAChB,WAAW;YAEX,oBAAC,SAAD;GACE,eAAY;GACZ,IAAI;GACJ,GAAI;GACJ,GAAI;GAEJ,OAAO;GAEP,UAAU;aAET,MAAM;GACC;EACK;;;;;;;;;AAWrB,MAAa,eACX,UACG;CACH,MAAM,EAAE,YAAY,gBAAgB;AAEpC,QACE,oBAAC,KAAK,OAAN;EACW;EACT,MAAM,MAAM;EACZ,SAAS,EAAE,YAAY,oBAAC,kBAAD;GAAkB,GAAI;GAAc;GAAS;EACpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormElementWrapper.mjs","names":[],"sources":["../../../../../src/components/Form/elements/FormElementWrapper.tsx"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport type { FC,
|
|
1
|
+
{"version":3,"file":"FormElementWrapper.mjs","names":[],"sources":["../../../../../src/components/Form/elements/FormElementWrapper.tsx"],"sourcesContent":["'use client';\n\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport type { FC, SubmitEvent, HTMLProps } from 'react';\nimport { FormProvider, useForm } from 'react-hook-form';\nimport { z } from 'zod/v4';\n\nconst Schema = z.object({\n test: z.string().min(3, 'test error'),\n});\n\ntype FormElementWrapperProps = HTMLProps<HTMLFormElement> & {\n schema?: z.ZodObject;\n values?: z.infer<z.ZodObject>;\n};\n\nexport const FormElementWrapper: FC<FormElementWrapperProps> = (props) => {\n const objectFormSchema = props.schema ?? Schema;\n\n const form = useForm<z.infer<typeof objectFormSchema>>({\n resolver: zodResolver(objectFormSchema as any),\n values: props.values,\n });\n\n const { children, onSubmit, ...rest } = props;\n\n const onSubmitForm = (\n values: z.infer<typeof objectFormSchema>,\n event: SubmitEvent<HTMLFormElement>\n ) => {\n const parsedValues = objectFormSchema.safeParse(values);\n if (parsedValues.success) {\n onSubmit?.(event);\n }\n };\n\n return (\n <FormProvider {...form}>\n <form\n {...rest}\n onSubmit={(e) => {\n e.preventDefault();\n form.handleSubmit((values) => onSubmitForm(values, e));\n }}\n >\n {children}\n </form>\n </FormProvider>\n );\n};\n"],"mappings":";;;;;;;;AAOA,MAAM,SAAS,EAAE,OAAO,EACtB,MAAM,EAAE,QAAQ,CAAC,IAAI,GAAG,aAAa,EACtC,CAAC;AAOF,MAAa,sBAAmD,UAAU;CACxE,MAAM,mBAAmB,MAAM,UAAU;CAEzC,MAAM,OAAO,QAA0C;EACrD,UAAU,YAAY,iBAAwB;EAC9C,QAAQ,MAAM;EACf,CAAC;CAEF,MAAM,EAAE,UAAU,UAAU,GAAG,SAAS;CAExC,MAAM,gBACJ,QACA,UACG;AAEH,MADqB,iBAAiB,UAAU,OAAO,CACtC,QACf,YAAW,MAAM;;AAIrB,QACE,oBAAC,cAAD;EAAc,GAAI;YAChB,oBAAC,QAAD;GACE,GAAI;GACJ,WAAW,MAAM;AACf,MAAE,gBAAgB;AAClB,SAAK,cAAc,WAAW,aAAa,QAAQ,EAAE,CAAC;;GAGvD;GACI;EACM"}
|
|
@@ -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 { useFormField } from "../FormField.mjs";
|
|
6
6
|
import { FormItemLayout } from "../layout/FormItemLayout.mjs";
|
|
7
7
|
import { Form } from "../Form.mjs";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { cn } from "../../../utils/cn.mjs";
|
|
1
2
|
import { FormLabelLayout } from "./FormLabelLayout.mjs";
|
|
2
3
|
import { Form } from "../Form.mjs";
|
|
3
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
5
|
|
|
5
6
|
//#region src/components/Form/layout/FormItemLayout.tsx
|
|
6
|
-
const FormItemLayout = ({ label, description, isRequired, info, children, showErrorMessage = true, htmlFor }) => /* @__PURE__ */ jsxs(Form.Item, {
|
|
7
|
-
className: "flex w-full flex-col flex-wrap gap-2 px-1 py-2",
|
|
7
|
+
const FormItemLayout = ({ label, description, isRequired, info, children, showErrorMessage = true, htmlFor, className }) => /* @__PURE__ */ jsxs(Form.Item, {
|
|
8
|
+
className: cn("flex w-full flex-col flex-wrap gap-2 px-1 py-2", className),
|
|
8
9
|
children: [
|
|
9
10
|
(description || label) && /* @__PURE__ */ jsxs("div", {
|
|
10
11
|
className: "flex flex-col gap-1 p-1 leading-none",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormItemLayout.mjs","names":[],"sources":["../../../../../src/components/Form/layout/FormItemLayout.tsx"],"sourcesContent":["import type { FC, ReactNode } from 'react';\nimport { Form } from '../Form';\nimport { FormLabelLayout, type FormLabelLayoutProps } from './FormLabelLayout';\n\nexport type FormItemLayoutProps = Omit<FormLabelLayoutProps, 'children'> & {\n label?: ReactNode;\n description?: ReactNode;\n children: ReactNode;\n showErrorMessage?: boolean;\n};\n\nexport const FormItemLayout: FC<FormItemLayoutProps> = ({\n label,\n description,\n isRequired,\n info,\n children,\n showErrorMessage = true,\n htmlFor,\n}) => (\n <Form.Item
|
|
1
|
+
{"version":3,"file":"FormItemLayout.mjs","names":[],"sources":["../../../../../src/components/Form/layout/FormItemLayout.tsx"],"sourcesContent":["import { cn } from '@utils/cn';\nimport type { FC, ReactNode } from 'react';\nimport { Form } from '../Form';\nimport { FormLabelLayout, type FormLabelLayoutProps } from './FormLabelLayout';\n\nexport type FormItemLayoutProps = Omit<FormLabelLayoutProps, 'children'> & {\n label?: ReactNode;\n description?: ReactNode;\n children: ReactNode;\n showErrorMessage?: boolean;\n className?: string;\n};\n\nexport const FormItemLayout: FC<FormItemLayoutProps> = ({\n label,\n description,\n isRequired,\n info,\n children,\n showErrorMessage = true,\n htmlFor,\n className,\n}) => (\n <Form.Item\n className={cn('flex w-full flex-col flex-wrap gap-2 px-1 py-2', className)}\n >\n {(description || label) && (\n <div className=\"flex flex-col gap-1 p-1 leading-none\">\n {label && (\n <FormLabelLayout\n isRequired={isRequired}\n info={info}\n htmlFor={htmlFor}\n >\n {label}\n </FormLabelLayout>\n )}\n {description && <Form.Description>{description}</Form.Description>}\n </div>\n )}\n <Form.Control>{children}</Form.Control>\n\n {showErrorMessage && <Form.Message data-testid=\"error-message\" />}\n </Form.Item>\n);\n"],"mappings":";;;;;;AAaA,MAAa,kBAA2C,EACtD,OACA,aACA,YACA,MACA,UACA,mBAAmB,MACnB,SACA,gBAEA,qBAAC,KAAK,MAAN;CACE,WAAW,GAAG,kDAAkD,UAAU;WAD5E;GAGI,eAAe,UACf,qBAAC,OAAD;GAAK,WAAU;aAAf,CACG,SACC,oBAAC,iBAAD;IACc;IACN;IACG;cAER;IACe,GAEnB,eAAe,oBAAC,KAAK,aAAN,YAAmB,aAA+B,EAC9D;;EAER,oBAAC,KAAK,SAAN,EAAe,UAAwB;EAEtC,oBAAoB,oBAAC,KAAK,SAAN,EAAc,eAAY,iBAAkB;EACvD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MonacoCode.mjs","names":[],"sources":["../../../../src/components/IDE/MonacoCode.tsx"],"sourcesContent":["'use client';\n\nimport type { OnChange, OnMount } from '@monaco-editor/react';\nimport { cn } from '@utils/cn';\nimport { type FC, lazy, Suspense, useRef, useState } from 'react';\nimport { CopyButton } from '../CopyButton';\nimport { Loader } from '../Loader';\n\nconst Editor = lazy(() =>\n import('@monaco-editor/react').then((mod) => ({ default: mod.Editor }))\n);\n\ntype CodeCompProps = {\n children: string;\n language: string;\n isDarkMode?: boolean;\n showLineNumbers?: boolean;\n showCopyButton?: boolean;\n isReadOnly?: boolean;\n onChange?: OnChange;\n};\n\nexport const MonacoCode: FC<CodeCompProps> = ({\n children,\n language,\n isDarkMode,\n showLineNumbers,\n showCopyButton = true,\n isReadOnly = false,\n onChange,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const ideRef = useRef(null);\n const [editorSize, setEditorSize] = useState<{\n height: number;\n width: number;\n }>({ height: 0, width: 0 });\n\n const theme = isDarkMode ? 'vs-dark-transparent' : 'hc-light-theme';\n\n const handleMountIde: OnMount = (editor, monaco) => {\n // first time you set the height based on content Height\n\n ideRef.current = editor as any;\n const contentHeight = (editor.getContentHeight() ?? 0) + 25;\n\n monaco.editor.defineTheme('vs-dark-transparent', {\n base: 'vs-dark',\n inherit: true,\n rules: [],\n colors: {\n 'editor.background': '#00000000',\n },\n });\n monaco.editor.defineTheme('hc-light-theme', {\n base: 'vs',\n inherit: true,\n rules: [],\n colors: {\n 'editor.background': '#00000000',\n },\n });\n\n monaco.editor.setTheme(theme);\n\n // Disable TypeScript diagnostics\n monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: true, // Disables type checking\n noSyntaxValidation: true, // Disables syntax errors\n });\n\n // Disable JavaScript diagnostics\n monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: true,\n noSyntaxValidation: true,\n });\n\n // Disable unnecessary language features (e.g., suggestions, quick fixes)\n monaco.languages.typescript.typescriptDefaults.setCompilerOptions({\n noLib: true,\n allowNonTsExtensions: true,\n });\n\n monaco.languages.typescript.javascriptDefaults.setCompilerOptions({\n noLib: true,\n allowNonTsExtensions: true,\n });\n\n setEditorSize({\n height: contentHeight,\n width: containerRef.current?.clientWidth ?? 0,\n });\n };\n\n const isShowLineNumbers =\n showLineNumbers ??\n (typeof children === 'string' ? children.split('\\n').length > 1 : false);\n\n return (\n <div\n className={cn(\n 'relative h-full w-full text-sm',\n showLineNumbers && 'ml-0'\n )}\n >\n {showCopyButton && (\n <div className=\"sticky top-5 z-10\">\n <div\n className={cn('absolute right-2 bottom-0 flex h-7 items-center')}\n >\n <CopyButton content={children} />\n </div>\n </div>\n )}\n <div\n className=\"z-0 grid size-full grid-cols-[0px] overflow-auto\"\n ref={containerRef}\n >\n <Suspense fallback={<Loader />}>\n <Editor\n {...editorSize}\n defaultLanguage=\"typescript\"\n language={language}\n loading={<Loader />}\n defaultValue={String(children).replace(/\\n$/, '')}\n onMount={handleMountIde}\n onChange={onChange}\n options={{\n readOnly: isReadOnly,\n cursorStyle: 'line',\n minimap: { enabled: false },\n scrollbar: {\n vertical: 'hidden',\n verticalScrollbarSize: 0,\n alwaysConsumeMouseWheel: false,\n },\n folding: false, // Disable code folding\n renderValidationDecorations: 'off', // Disable error/warning decorations\n quickSuggestions: false, // Disable IntelliSense\n parameterHints: { enabled: false }, // Disable parameter hints\n suggestOnTriggerCharacters: false, // Disable suggestions on typing\n\n mouseWheelScrollSensitivity: 0,\n fastScrollSensitivity: 0,\n scrollBeyondLastLine: false,\n lineNumbers: isShowLineNumbers ? 'on' : 'off',\n }}\n theme={theme}\n className=\"my-2 rounded-md\"\n />\n </Suspense>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;AAQA,MAAM,SAAS,WACb,OAAO,wBAAwB,MAAM,SAAS,EAAE,SAAS,IAAI,QAAQ,EAAE,CACxE;AAYD,MAAa,cAAiC,EAC5C,UACA,UACA,YACA,iBACA,iBAAiB,MACjB,aAAa,OACb,eACI;CACJ,MAAM,eAAe,OAAuB,KAAK;CACjD,MAAM,SAAS,OAAO,KAAK;CAC3B,MAAM,CAAC,YAAY,iBAAiB,SAGjC;EAAE,QAAQ;EAAG,OAAO;EAAG,CAAC;CAE3B,MAAM,QAAQ,aAAa,wBAAwB;CAEnD,MAAM,kBAA2B,QAAQ,WAAW;AAGlD,SAAO,UAAU;EACjB,MAAM,iBAAiB,OAAO,kBAAkB,IAAI,KAAK;AAEzD,SAAO,OAAO,YAAY,uBAAuB;GAC/C,MAAM;GACN,SAAS;GACT,OAAO,EAAE;GACT,QAAQ,EACN,qBAAqB,aACtB;GACF,CAAC;AACF,SAAO,OAAO,YAAY,kBAAkB;GAC1C,MAAM;GACN,SAAS;GACT,OAAO,EAAE;GACT,QAAQ,EACN,qBAAqB,aACtB;GACF,CAAC;AAEF,SAAO,OAAO,SAAS,MAAM;AAG7B,SAAO,UAAU,WAAW,mBAAmB,sBAAsB;GACnE,sBAAsB;GACtB,oBAAoB;GACrB,CAAC;AAGF,SAAO,UAAU,WAAW,mBAAmB,sBAAsB;GACnE,sBAAsB;GACtB,oBAAoB;GACrB,CAAC;AAGF,SAAO,UAAU,WAAW,mBAAmB,mBAAmB;GAChE,OAAO;GACP,sBAAsB;GACvB,CAAC;AAEF,SAAO,UAAU,WAAW,mBAAmB,mBAAmB;GAChE,OAAO;GACP,sBAAsB;GACvB,CAAC;AAEF,gBAAc;GACZ,QAAQ;GACR,OAAO,aAAa,SAAS,eAAe;GAC7C,CAAC;;CAGJ,MAAM,oBACJ,oBACC,OAAO,aAAa,WAAW,SAAS,MAAM,KAAK,CAAC,SAAS,IAAI;AAEpE,QACE,qBAAC,OAAD;EACE,WAAW,GACT,kCACA,mBAAmB,OACpB;YAJH,CAMG,kBACC,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD;IACE,WAAW,GAAG,kDAAkD;cAEhE,oBAAC,YAAD,EAAY,SAAS,UAAY;IAC7B;GACF,GAER,oBAAC,OAAD;GACE,WAAU;GACV,KAAK;aAEL,oBAAC,UAAD;IAAU,UAAU,oBAAC,QAAD,EAAU;cAC5B,oBAAC,QAAD;KACE,GAAI;KACJ,iBAAgB;KACN;KACV,SAAS,oBAAC,QAAD,EAAU;KACnB,cAAc,OAAO,SAAS,CAAC,QAAQ,OAAO,GAAG;KACjD,SAAS;KACC;KACV,SAAS;MACP,UAAU;MACV,aAAa;MACb,SAAS,EAAE,SAAS,OAAO;MAC3B,WAAW;OACT,UAAU;OACV,uBAAuB;OACvB,yBAAyB;OAC1B;MACD,SAAS;MACT,6BAA6B;MAC7B,kBAAkB;MAClB,gBAAgB,EAAE,SAAS,OAAO;MAClC,4BAA4B;MAE5B,6BAA6B;MAC7B,uBAAuB;MACvB,sBAAsB;MACtB,aAAa,oBAAoB,OAAO;MACzC;KACM;KACP,WAAU;KACV;IACO;GACP,EACF"}
|
|
1
|
+
{"version":3,"file":"MonacoCode.mjs","names":[],"sources":["../../../../src/components/IDE/MonacoCode.tsx"],"sourcesContent":["'use client';\n\nimport type { OnChange, OnMount } from '@monaco-editor/react';\nimport { cn } from '@utils/cn';\nimport { type FC, lazy, Suspense, useRef, useState } from 'react';\nimport { CopyButton } from '../CopyButton';\nimport { Loader } from '../Loader';\n\nconst Editor = lazy(() =>\n import('@monaco-editor/react').then((mod) => ({ default: mod.Editor }))\n);\n\ntype CodeCompProps = {\n children: string;\n language: string;\n isDarkMode?: boolean;\n showLineNumbers?: boolean;\n showCopyButton?: boolean;\n isReadOnly?: boolean;\n onChange?: OnChange;\n};\n\nexport const MonacoCode: FC<CodeCompProps> = ({\n children,\n language,\n isDarkMode,\n showLineNumbers,\n showCopyButton = true,\n isReadOnly = false,\n onChange,\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const ideRef = useRef(null);\n const [editorSize, setEditorSize] = useState<{\n height: number;\n width: number;\n }>({ height: 0, width: 0 });\n\n const theme = isDarkMode ? 'vs-dark-transparent' : 'hc-light-theme';\n\n const handleMountIde: OnMount = (editor, monaco) => {\n // first time you set the height based on content Height\n\n ideRef.current = editor as any;\n const contentHeight = (editor.getContentHeight() ?? 0) + 25;\n\n monaco.editor.defineTheme('vs-dark-transparent', {\n base: 'vs-dark',\n inherit: true,\n rules: [],\n colors: {\n 'editor.background': '#00000000',\n },\n });\n monaco.editor.defineTheme('hc-light-theme', {\n base: 'vs',\n inherit: true,\n rules: [],\n colors: {\n 'editor.background': '#00000000',\n },\n });\n\n monaco.editor.setTheme(theme);\n\n // Disable TypeScript diagnostics\n monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: true, // Disables type checking\n noSyntaxValidation: true, // Disables syntax errors\n });\n\n // Disable JavaScript diagnostics\n monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: true,\n noSyntaxValidation: true,\n });\n\n // Disable unnecessary language features (e.g., suggestions, quick fixes)\n monaco.languages.typescript.typescriptDefaults.setCompilerOptions({\n noLib: true,\n allowNonTsExtensions: true,\n });\n\n monaco.languages.typescript.javascriptDefaults.setCompilerOptions({\n noLib: true,\n allowNonTsExtensions: true,\n });\n\n setEditorSize({\n height: contentHeight,\n width: containerRef.current?.clientWidth ?? 0,\n });\n };\n\n const isShowLineNumbers =\n showLineNumbers ??\n (typeof children === 'string' ? children.split('\\n').length > 1 : false);\n\n return (\n <div\n className={cn(\n 'relative h-full w-full text-sm',\n showLineNumbers && 'ml-0'\n )}\n >\n {showCopyButton && (\n <div className=\"sticky top-5 z-10\">\n <div\n className={cn('absolute right-2 bottom-0 flex h-7 items-center')}\n >\n <CopyButton content={children} />\n </div>\n </div>\n )}\n <div\n className=\"z-0 grid size-full grid-cols-[0px] overflow-auto\"\n ref={containerRef}\n >\n <Suspense fallback={<Loader />}>\n <Editor\n {...editorSize}\n defaultLanguage=\"typescript\"\n language={language}\n loading={<Loader />}\n defaultValue={String(children).replace(/\\n$/, '')}\n onMount={handleMountIde}\n onChange={onChange}\n options={{\n contextmenu: false,\n readOnly: isReadOnly,\n cursorStyle: 'line',\n minimap: { enabled: false },\n scrollbar: {\n vertical: 'hidden',\n verticalScrollbarSize: 0,\n alwaysConsumeMouseWheel: false,\n },\n folding: false, // Disable code folding\n renderValidationDecorations: 'off', // Disable error/warning decorations\n quickSuggestions: false, // Disable IntelliSense\n parameterHints: { enabled: false }, // Disable parameter hints\n suggestOnTriggerCharacters: false, // Disable suggestions on typing\n\n mouseWheelScrollSensitivity: 0,\n fastScrollSensitivity: 0,\n scrollBeyondLastLine: false,\n lineNumbers: isShowLineNumbers ? 'on' : 'off',\n }}\n theme={theme}\n className=\"my-2 rounded-md\"\n />\n </Suspense>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;AAQA,MAAM,SAAS,WACb,OAAO,wBAAwB,MAAM,SAAS,EAAE,SAAS,IAAI,QAAQ,EAAE,CACxE;AAYD,MAAa,cAAiC,EAC5C,UACA,UACA,YACA,iBACA,iBAAiB,MACjB,aAAa,OACb,eACI;CACJ,MAAM,eAAe,OAAuB,KAAK;CACjD,MAAM,SAAS,OAAO,KAAK;CAC3B,MAAM,CAAC,YAAY,iBAAiB,SAGjC;EAAE,QAAQ;EAAG,OAAO;EAAG,CAAC;CAE3B,MAAM,QAAQ,aAAa,wBAAwB;CAEnD,MAAM,kBAA2B,QAAQ,WAAW;AAGlD,SAAO,UAAU;EACjB,MAAM,iBAAiB,OAAO,kBAAkB,IAAI,KAAK;AAEzD,SAAO,OAAO,YAAY,uBAAuB;GAC/C,MAAM;GACN,SAAS;GACT,OAAO,EAAE;GACT,QAAQ,EACN,qBAAqB,aACtB;GACF,CAAC;AACF,SAAO,OAAO,YAAY,kBAAkB;GAC1C,MAAM;GACN,SAAS;GACT,OAAO,EAAE;GACT,QAAQ,EACN,qBAAqB,aACtB;GACF,CAAC;AAEF,SAAO,OAAO,SAAS,MAAM;AAG7B,SAAO,UAAU,WAAW,mBAAmB,sBAAsB;GACnE,sBAAsB;GACtB,oBAAoB;GACrB,CAAC;AAGF,SAAO,UAAU,WAAW,mBAAmB,sBAAsB;GACnE,sBAAsB;GACtB,oBAAoB;GACrB,CAAC;AAGF,SAAO,UAAU,WAAW,mBAAmB,mBAAmB;GAChE,OAAO;GACP,sBAAsB;GACvB,CAAC;AAEF,SAAO,UAAU,WAAW,mBAAmB,mBAAmB;GAChE,OAAO;GACP,sBAAsB;GACvB,CAAC;AAEF,gBAAc;GACZ,QAAQ;GACR,OAAO,aAAa,SAAS,eAAe;GAC7C,CAAC;;CAGJ,MAAM,oBACJ,oBACC,OAAO,aAAa,WAAW,SAAS,MAAM,KAAK,CAAC,SAAS,IAAI;AAEpE,QACE,qBAAC,OAAD;EACE,WAAW,GACT,kCACA,mBAAmB,OACpB;YAJH,CAMG,kBACC,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD;IACE,WAAW,GAAG,kDAAkD;cAEhE,oBAAC,YAAD,EAAY,SAAS,UAAY;IAC7B;GACF,GAER,oBAAC,OAAD;GACE,WAAU;GACV,KAAK;aAEL,oBAAC,UAAD;IAAU,UAAU,oBAAC,QAAD,EAAU;cAC5B,oBAAC,QAAD;KACE,GAAI;KACJ,iBAAgB;KACN;KACV,SAAS,oBAAC,QAAD,EAAU;KACnB,cAAc,OAAO,SAAS,CAAC,QAAQ,OAAO,GAAG;KACjD,SAAS;KACC;KACV,SAAS;MACP,aAAa;MACb,UAAU;MACV,aAAa;MACb,SAAS,EAAE,SAAS,OAAO;MAC3B,WAAW;OACT,UAAU;OACV,uBAAuB;OACvB,yBAAyB;OAC1B;MACD,SAAS;MACT,6BAA6B;MAC7B,kBAAkB;MAClB,gBAAgB,EAAE,SAAS,OAAO;MAClC,4BAA4B;MAE5B,6BAA6B;MAC7B,uBAAuB;MACvB,sBAAsB;MACtB,aAAa,oBAAoB,OAAO;MACzC;KACM;KACP,WAAU;KACV;IACO;GACP,EACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.mjs","names":[],"sources":["../../../../src/components/Link/Link.tsx"],"sourcesContent":["import { getLocalizedUrl } from '@intlayer/core/localization';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { cn } from '@utils/cn';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ExternalLink, MoveRight } from 'lucide-react';\nimport {\n type AnchorHTMLAttributes,\n type DetailedHTMLProps,\n type FC,\n isValidElement,\n type ReactNode,\n} from 'react';\n\n/**\n * Visual style variants for Link component\n */\nexport enum LinkVariant {\n DEFAULT = 'default',\n INVISIBLE_LINK = 'invisible-link',\n BUTTON = 'button',\n BUTTON_OUTLINED = 'button-outlined',\n HOVERABLE = 'hoverable',\n}\n\n/**\n * Color theme variants for Link component\n */\nexport enum LinkColor {\n PRIMARY = 'primary',\n SECONDARY = 'secondary',\n DESTRUCTIVE = 'destructive',\n NEUTRAL = 'neutral',\n LIGHT = 'light',\n DARK = 'dark',\n TEXT = 'text',\n TEXT_INVERSE = 'text-inverse',\n ERROR = 'error',\n SUCCESS = 'success',\n CUSTOM = 'custom',\n}\n\nexport enum LinkRoundedSize {\n NONE = 'none',\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n XL = 'xl',\n TWO_XL = '2xl',\n THREE_XL = '3xl',\n FULL = 'full',\n}\n\nexport enum LinkSize {\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n XL = 'xl',\n CUSTOM = 'custom',\n}\n\nexport enum LinkUnderlined {\n DEFAULT = 'default',\n TRUE = 'true',\n FALSE = 'false',\n}\n\nexport const linkVariants = cva(\n 'gap-3 transition-all duration-300 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n [`${LinkVariant.DEFAULT}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 font-medium decoration-[1.5] underline-offset-5 hover:bg-current/0 hover:text-current/80 hover:underline hover:underline-offset-6',\n [`${LinkVariant.INVISIBLE_LINK}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-5 hover:bg-current/0',\n\n [`${LinkVariant.BUTTON}`]:\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full bg-current text-center font-medium text-text ring-0 *:text-text-opposite hover:bg-current/90 hover:ring-5 aria-selected:ring-5',\n\n [`${LinkVariant.BUTTON_OUTLINED}`]:\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full border-[1.3px] border-current text-center font-medium text-text ring-0 *:text-text hover:bg-current/20 hover:ring-5 aria-selected:ring-5',\n\n [`${LinkVariant.HOVERABLE}`]:\n 'block rounded-lg border-none bg-current/0 hover:bg-current/10 aria-[current]:bg-current/5',\n },\n roundedSize: {\n [`${LinkRoundedSize.NONE}`]: 'rounded-none',\n [`${LinkRoundedSize.SM}`]:\n 'rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl',\n [`${LinkRoundedSize.MD}`]:\n 'rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl',\n [`${LinkRoundedSize.LG}`]:\n 'rounded-2xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-3xl',\n [`${LinkRoundedSize.XL}`]:\n 'rounded-3xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-4xl',\n [`${LinkRoundedSize.TWO_XL}`]:\n 'rounded-4xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[2.5rem]',\n [`${LinkRoundedSize.THREE_XL}`]:\n 'rounded-[2.5rem] [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[3rem]',\n [`${LinkRoundedSize.FULL}`]: 'rounded-full',\n },\n color: {\n [`${LinkColor.PRIMARY}`]: 'text-primary',\n [`${LinkColor.SECONDARY}`]: 'text-secondary',\n [`${LinkColor.DESTRUCTIVE}`]: 'text-destructive',\n [`${LinkColor.NEUTRAL}`]: 'text-neutral',\n [`${LinkColor.LIGHT}`]: 'text-white',\n [`${LinkColor.DARK}`]: 'text-neutral-800',\n [`${LinkColor.TEXT}`]: 'text-text',\n [`${LinkColor.TEXT_INVERSE}`]: 'text-text-opposite',\n [`${LinkColor.ERROR}`]: 'text-error',\n [`${LinkColor.SUCCESS}`]: 'text-success',\n [`${LinkColor.CUSTOM}`]: '',\n },\n size: {\n [`${LinkSize.SM}`]: 'text-sm',\n [`${LinkSize.MD}`]: 'text-base',\n [`${LinkSize.LG}`]: 'text-lg',\n [`${LinkSize.XL}`]: 'text-xl',\n [`${LinkSize.CUSTOM}`]: '',\n },\n underlined: {\n [LinkUnderlined.DEFAULT]: '',\n [LinkUnderlined.TRUE]: 'underline',\n [LinkUnderlined.FALSE]: 'no-underline',\n },\n },\n // Compound variants handle height and padding\n compoundVariants: [\n // ---------------------------------------------------------\n // FIX START: Correctly Handle Contrast for TEXT_INVERSE\n // ---------------------------------------------------------\n {\n // Filled Button + Inverse Color (e.g., White Button):\n // We DO NOT override parent text color (it must remain 'text-opposite' so bg-current is white).\n // We ONLY override children to be 'text-text' (Dark) so they show up on white.\n variant: LinkVariant.BUTTON,\n color: LinkColor.TEXT_INVERSE,\n class: '*:text-text',\n },\n {\n // Outlined Button + Inverse Color (e.g., White Border):\n // Parent is 'text-opposite' (Border is white).\n // Children must also be 'text-opposite' (White text) to show on dark background.\n variant: LinkVariant.BUTTON_OUTLINED,\n color: LinkColor.TEXT_INVERSE,\n class: 'text-text-opposite *:text-text-opposite',\n },\n\n // Min height and padding for button variants\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.SM,\n class: 'min-h-7 px-3 max-md:py-1',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.MD,\n class: 'min-h-8 px-6 max-md:py-2',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.LG,\n class: 'min-h-10 px-8 max-md:py-3',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.XL,\n class: 'min-h-11 px-10 max-md:py-4',\n },\n // Ring color variants\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.PRIMARY,\n class: 'ring-primary/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.SECONDARY,\n class: 'ring-secondary/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.DESTRUCTIVE,\n class: 'ring-destructive/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.NEUTRAL,\n class: 'ring-neutral/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.LIGHT,\n class: 'ring-white/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.DARK,\n class: 'ring-neutral-800/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.TEXT,\n class: 'ring-text/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.TEXT_INVERSE,\n class: 'ring-text-opposite/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.ERROR,\n class: 'ring-error/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.SUCCESS,\n class: 'ring-success/20',\n },\n ],\n\n defaultVariants: {\n variant: LinkVariant.DEFAULT,\n roundedSize: LinkRoundedSize.MD,\n underlined: LinkUnderlined.DEFAULT,\n size: LinkSize.MD,\n },\n }\n);\n\nexport type LinkProps = DetailedHTMLProps<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n HTMLAnchorElement\n> &\n VariantProps<typeof linkVariants> & {\n label: string;\n isExternalLink?: boolean;\n isPageSection?: boolean;\n isActive?: boolean;\n locale?: LocalesValues;\n };\n\nexport const checkIsExternalLink = ({\n href,\n isExternalLink: isExternalLinkProp,\n}: LinkProps): boolean => {\n const isValidHref = typeof href === 'string' && href.trim() !== '';\n const isExternalLink =\n isExternalLinkProp === true ||\n (typeof isExternalLinkProp === 'undefined' &&\n isValidHref &&\n /^https?:\\/\\//.test(href));\n\n return isExternalLink;\n};\n\nexport const isTextChildren = (children: ReactNode): boolean => {\n if (typeof children === 'string' || typeof children === 'number') {\n return true;\n }\n if (Array.isArray(children)) {\n return children.every(isTextChildren);\n }\n if (isValidElement(children)) {\n return isTextChildren(\n (children.props as { children?: ReactNode }).children\n );\n }\n return false;\n};\n\nexport const Link: FC<LinkProps> = (props) => {\n const {\n variant = LinkVariant.DEFAULT,\n color = LinkColor.CUSTOM,\n roundedSize,\n children,\n label,\n className,\n isActive,\n underlined,\n locale,\n size,\n isExternalLink: isExternalLinkProp,\n isPageSection: isPageSectionProp,\n href: hrefProp,\n ...otherProps\n } = props;\n\n const isExternalLink = isExternalLinkProp ?? checkIsExternalLink(props);\n const isPageSection = isPageSectionProp ?? hrefProp?.startsWith('#') ?? false;\n\n const isChildrenString = isTextChildren(children);\n const isButton =\n variant === LinkVariant.BUTTON || variant === LinkVariant.BUTTON_OUTLINED;\n\n const rel = isExternalLink ? 'noopener noreferrer nofollow' : undefined;\n\n const target = isExternalLink ? '_blank' : '_self';\n\n const href =\n locale && hrefProp && !isExternalLink && !isPageSection\n ? getLocalizedUrl(hrefProp, locale)\n : hrefProp;\n\n return (\n <a\n href={href}\n aria-label={label}\n rel={rel}\n target={target}\n aria-current={isActive ? 'page' : undefined}\n suppressHydrationWarning\n className={cn(\n linkVariants({\n variant,\n color,\n roundedSize,\n underlined,\n size,\n className,\n })\n )}\n {...otherProps}\n >\n {isButton && isChildrenString ? <span>{children}</span> : children}\n\n {isExternalLink && isChildrenString && (\n <ExternalLink className=\"ml-2 inline-block size-4\" />\n )}\n {isPageSection && <MoveRight className=\"ml-2 inline-block size-4\" />}\n </a>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Link.mjs","names":[],"sources":["../../../../src/components/Link/Link.tsx"],"sourcesContent":["import { getLocalizedUrl } from '@intlayer/core/localization';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { cn } from '@utils/cn';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ExternalLink, MoveRight } from 'lucide-react';\nimport {\n type AnchorHTMLAttributes,\n type DetailedHTMLProps,\n type FC,\n isValidElement,\n type ReactNode,\n} from 'react';\n\n/**\n * Visual style variants for Link component\n */\nexport enum LinkVariant {\n DEFAULT = 'default',\n INVISIBLE_LINK = 'invisible-link',\n BUTTON = 'button',\n BUTTON_OUTLINED = 'button-outlined',\n HOVERABLE = 'hoverable',\n}\n\n/**\n * Color theme variants for Link component\n */\nexport enum LinkColor {\n PRIMARY = 'primary',\n SECONDARY = 'secondary',\n DESTRUCTIVE = 'destructive',\n NEUTRAL = 'neutral',\n LIGHT = 'light',\n DARK = 'dark',\n TEXT = 'text',\n TEXT_INVERSE = 'text-inverse',\n ERROR = 'error',\n SUCCESS = 'success',\n CUSTOM = 'custom',\n}\n\nexport enum LinkRoundedSize {\n NONE = 'none',\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n XL = 'xl',\n TWO_XL = '2xl',\n THREE_XL = '3xl',\n FULL = 'full',\n}\n\nexport enum LinkSize {\n SM = 'sm',\n MD = 'md',\n LG = 'lg',\n XL = 'xl',\n CUSTOM = 'custom',\n}\n\nexport enum LinkUnderlined {\n DEFAULT = 'default',\n TRUE = 'true',\n FALSE = 'false',\n}\n\nexport const linkVariants = cva(\n 'gap-3 transition-all duration-300 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n [`${LinkVariant.DEFAULT}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 font-medium decoration-[1.5] underline-offset-5 hover:bg-current/0 hover:text-current/80 hover:underline hover:underline-offset-6',\n [`${LinkVariant.INVISIBLE_LINK}`]:\n 'h-auto justify-start border-inherit bg-current/0 px-1 underline-offset-5 hover:bg-current/0',\n\n [`${LinkVariant.BUTTON}`]:\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full bg-current text-center font-medium text-text ring-0 *:text-text-opposite hover:bg-current/90 hover:ring-5 aria-selected:ring-5',\n\n [`${LinkVariant.BUTTON_OUTLINED}`]:\n 'relative flex cursor-pointer flex-row items-center justify-center gap-2 rounded-full border-[1.3px] border-current text-center font-medium text-text ring-0 *:text-text hover:bg-current/20 hover:ring-5 aria-selected:ring-5',\n\n [`${LinkVariant.HOVERABLE}`]:\n 'block rounded-lg border-none bg-current/0 hover:bg-current/10 aria-[current]:bg-current/5',\n },\n roundedSize: {\n [`${LinkRoundedSize.NONE}`]: 'rounded-none',\n [`${LinkRoundedSize.SM}`]:\n 'rounded-lg [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl',\n [`${LinkRoundedSize.MD}`]:\n 'rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl',\n [`${LinkRoundedSize.LG}`]:\n 'rounded-2xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-3xl',\n [`${LinkRoundedSize.XL}`]:\n 'rounded-3xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-4xl',\n [`${LinkRoundedSize.TWO_XL}`]:\n 'rounded-4xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[2.5rem]',\n [`${LinkRoundedSize.THREE_XL}`]:\n 'rounded-[2.5rem] [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-[3rem]',\n [`${LinkRoundedSize.FULL}`]: 'rounded-full',\n },\n color: {\n [`${LinkColor.PRIMARY}`]: 'text-primary',\n [`${LinkColor.SECONDARY}`]: 'text-secondary',\n [`${LinkColor.DESTRUCTIVE}`]: 'text-destructive',\n [`${LinkColor.NEUTRAL}`]: 'text-neutral',\n [`${LinkColor.LIGHT}`]: 'text-white',\n [`${LinkColor.DARK}`]: 'text-neutral-800',\n [`${LinkColor.TEXT}`]: 'text-text',\n [`${LinkColor.TEXT_INVERSE}`]: 'text-text-opposite',\n [`${LinkColor.ERROR}`]: 'text-error',\n [`${LinkColor.SUCCESS}`]: 'text-success',\n [`${LinkColor.CUSTOM}`]: '',\n },\n size: {\n [`${LinkSize.SM}`]: 'text-sm',\n [`${LinkSize.MD}`]: 'text-base',\n [`${LinkSize.LG}`]: 'text-lg',\n [`${LinkSize.XL}`]: 'text-xl',\n [`${LinkSize.CUSTOM}`]: '',\n },\n underlined: {\n [LinkUnderlined.DEFAULT]: '',\n [LinkUnderlined.TRUE]: 'underline',\n [LinkUnderlined.FALSE]: 'no-underline',\n },\n },\n // Compound variants handle height and padding\n compoundVariants: [\n // ---------------------------------------------------------\n // FIX START: Correctly Handle Contrast for TEXT_INVERSE\n // ---------------------------------------------------------\n {\n // Filled Button + Inverse Color (e.g., White Button):\n // We DO NOT override parent text color (it must remain 'text-opposite' so bg-current is white).\n // We ONLY override children to be 'text-text' (Dark) so they show up on white.\n variant: LinkVariant.BUTTON,\n color: LinkColor.TEXT_INVERSE,\n class: '*:text-text',\n },\n {\n // Outlined Button + Inverse Color (e.g., White Border):\n // Parent is 'text-opposite' (Border is white).\n // Children must also be 'text-opposite' (White text) to show on dark background.\n variant: LinkVariant.BUTTON_OUTLINED,\n color: LinkColor.TEXT_INVERSE,\n class: 'text-text-opposite *:text-text-opposite',\n },\n\n // Min height and padding for button variants\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.SM,\n class: 'min-h-7 px-3 max-md:py-1',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.MD,\n class: 'min-h-8 px-6 max-md:py-2',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.LG,\n class: 'min-h-10 px-8 max-md:py-3',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n size: LinkSize.XL,\n class: 'min-h-11 px-10 max-md:py-4',\n },\n // Ring color variants\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.PRIMARY,\n class: 'ring-primary/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.SECONDARY,\n class: 'ring-secondary/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.DESTRUCTIVE,\n class: 'ring-destructive/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.NEUTRAL,\n class: 'ring-neutral/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.LIGHT,\n class: 'ring-white/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.DARK,\n class: 'ring-neutral-800/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.TEXT,\n class: 'ring-text/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.TEXT_INVERSE,\n class: 'ring-text-opposite/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.ERROR,\n class: 'ring-error/20',\n },\n {\n variant: [LinkVariant.BUTTON, LinkVariant.BUTTON_OUTLINED],\n color: LinkColor.SUCCESS,\n class: 'ring-success/20',\n },\n ],\n\n defaultVariants: {\n variant: LinkVariant.DEFAULT,\n roundedSize: LinkRoundedSize.MD,\n underlined: LinkUnderlined.DEFAULT,\n size: LinkSize.MD,\n },\n }\n);\n\nexport type LinkProps = DetailedHTMLProps<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n HTMLAnchorElement\n> &\n VariantProps<typeof linkVariants> & {\n label: string;\n isExternalLink?: boolean;\n isPageSection?: boolean;\n isActive?: boolean;\n locale?: LocalesValues;\n };\n\nexport const checkIsExternalLink = ({\n href,\n isExternalLink: isExternalLinkProp,\n}: Pick<LinkProps, 'href' | 'isExternalLink'>): boolean => {\n const isValidHref = typeof href === 'string' && href.trim() !== '';\n const isExternalLink =\n isExternalLinkProp === true ||\n (typeof isExternalLinkProp === 'undefined' &&\n isValidHref &&\n /^https?:\\/\\//.test(href));\n\n return isExternalLink;\n};\n\nexport const isTextChildren = (children: ReactNode): boolean => {\n if (typeof children === 'string' || typeof children === 'number') {\n return true;\n }\n if (Array.isArray(children)) {\n return children.every(isTextChildren);\n }\n if (isValidElement(children)) {\n return isTextChildren(\n (children.props as { children?: ReactNode }).children\n );\n }\n return false;\n};\n\nexport const Link: FC<LinkProps> = (props) => {\n const {\n variant = LinkVariant.DEFAULT,\n color = LinkColor.CUSTOM,\n roundedSize,\n children,\n label,\n className,\n isActive,\n underlined,\n locale,\n size,\n isExternalLink: isExternalLinkProp,\n isPageSection: isPageSectionProp,\n href: hrefProp,\n ...otherProps\n } = props;\n\n const isExternalLink = isExternalLinkProp ?? checkIsExternalLink(props);\n const isPageSection = isPageSectionProp ?? hrefProp?.startsWith('#') ?? false;\n\n const isChildrenString = isTextChildren(children);\n const isButton =\n variant === LinkVariant.BUTTON || variant === LinkVariant.BUTTON_OUTLINED;\n\n const rel = isExternalLink ? 'noopener noreferrer nofollow' : undefined;\n\n const target = isExternalLink ? '_blank' : '_self';\n\n const href =\n locale && hrefProp && !isExternalLink && !isPageSection\n ? getLocalizedUrl(hrefProp, locale)\n : hrefProp;\n\n return (\n <a\n href={href}\n aria-label={label}\n rel={rel}\n target={target}\n aria-current={isActive ? 'page' : undefined}\n suppressHydrationWarning\n className={cn(\n linkVariants({\n variant,\n color,\n roundedSize,\n underlined,\n size,\n className,\n })\n )}\n {...otherProps}\n >\n {isButton && isChildrenString ? <span>{children}</span> : children}\n\n {isExternalLink && isChildrenString && (\n <ExternalLink className=\"ml-2 inline-block size-4\" />\n )}\n {isPageSection && <MoveRight className=\"ml-2 inline-block size-4\" />}\n </a>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { usePersistedStore } from "../../hooks/usePersistedStore.mjs";
|
|
4
3
|
import { Container } from "../Container/index.mjs";
|
|
5
4
|
import { Button, ButtonColor, ButtonSize, ButtonTextAlign, ButtonVariant } from "../Button/Button.mjs";
|
|
6
5
|
import { Input } from "../Input/Input.mjs";
|
|
7
6
|
import { SwitchSelector, SwitchSelectorColor, SwitchSelectorSize } from "../SwitchSelector/index.mjs";
|
|
7
|
+
import { usePersistedStore } from "../../hooks/usePersistedStore.mjs";
|
|
8
8
|
import { DropDown } from "../DropDown/index.mjs";
|
|
9
9
|
import { useLocaleSwitcherContent } from "./LocaleSwitcherContentContext.mjs";
|
|
10
10
|
import { useMemo, useRef, useState } from "react";
|
|
@@ -5,7 +5,7 @@ import { CodeProvider } from "../IDE/CodeContext.mjs";
|
|
|
5
5
|
import { Code } from "../IDE/Code.mjs";
|
|
6
6
|
import { TabProvider } from "../Tab/TabContext.mjs";
|
|
7
7
|
import { Tab } from "../Tab/Tab.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { SmartTable } from "../Table/SmartTable.mjs";
|
|
9
9
|
import { memo } from "react";
|
|
10
10
|
import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
|
|
11
11
|
import { renderMarkdown } from "react-intlayer";
|
|
@@ -98,7 +98,7 @@ const createLinkRenderer = (locale) => {
|
|
|
98
98
|
});
|
|
99
99
|
};
|
|
100
100
|
const PreRenderer = (props) => /* @__PURE__ */ jsx(Fragment$1, { children: props.children });
|
|
101
|
-
const TableRenderer = (props) => /* @__PURE__ */ jsx(
|
|
101
|
+
const TableRenderer = (props) => /* @__PURE__ */ jsx(SmartTable, {
|
|
102
102
|
isRollable: true,
|
|
103
103
|
displayModal: true,
|
|
104
104
|
...props
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkDownRender.mjs","names":[],"sources":["../../../../src/components/MarkDownRender/MarkDownRender.tsx"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { cn } from '@utils/cn';\nimport type { ComponentProps, ComponentPropsWithoutRef, FC } from 'react';\nimport { memo } from 'react';\nimport {\n type MarkdownRenderer as MarkdownRendererIntlayer,\n renderMarkdown,\n} from 'react-intlayer';\nimport type { BundledLanguage } from 'shiki/bundle/web';\nimport { H1, H2, H3, H4, H5, H6 } from '../Headers';\nimport { Code } from '../IDE/Code';\nimport { CodeProvider } from '../IDE/CodeContext';\nimport { Link } from '../Link';\nimport { Tab } from '../Tab';\nimport { TabProvider } from '../Tab/TabContext';\nimport { Table } from '../Table';\n\n// Extracted, stable component renderers\nconst H1Renderer = (props: ComponentProps<'h1'>) => (\n <H1 isClickable className=\"text-text\" {...props} />\n);\nconst H2Renderer = (props: ComponentProps<'h2'>) => (\n <H2 isClickable className=\"mt-16 text-text\" {...props} />\n);\nconst H3Renderer = (props: ComponentProps<'h3'>) => (\n <H3 isClickable className=\"mt-5 text-text\" {...props} />\n);\nconst H4Renderer = (props: ComponentProps<'h4'>) => (\n <H4 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst H5Renderer = (props: ComponentProps<'h5'>) => (\n <H5 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst H6Renderer = (props: ComponentProps<'h6'>) => (\n <H6 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst StrongRenderer = (props: ComponentProps<'strong'>) => (\n <strong className=\"text-text\" {...props} />\n);\n\nconst MemoizedCodeBlock = memo(\n ({\n className,\n children,\n isDarkMode,\n ...rest\n }: ComponentProps<'code'> & { isDarkMode?: boolean }) => {\n const content = String(children ?? '').replace(/\\n$/, '');\n const isBlock = !!className;\n\n if (!isBlock) {\n const decodedContent = content.replace(\n /&(?:amp;)?#(\\d+);/g,\n (_, code: string) => String.fromCharCode(parseInt(code, 10))\n );\n return (\n <code className=\"rounded-md border border-neutral/30 bg-card/60 box-decoration-clone px-1.5 py-0.5 font-mono text-sm\">\n {decodedContent}\n </code>\n );\n }\n\n const language = (className?.replace(/lang(?:uage)?-/, '') ||\n 'plaintext') as BundledLanguage;\n\n return (\n <Code {...rest} language={language} showHeader isDarkMode={isDarkMode}>\n {content}\n </Code>\n );\n },\n (prevProps, nextProps) =>\n prevProps.children === nextProps.children &&\n prevProps.className === nextProps.className &&\n prevProps.isDarkMode === nextProps.isDarkMode\n);\n\nconst createCodeRenderer = (isDarkMode?: boolean) => {\n return function CodeWrapper(props: ComponentProps<'code'>) {\n return <MemoizedCodeBlock {...props} isDarkMode={isDarkMode} />;\n };\n};\n\nconst BlockquoteRenderer = ({\n className,\n ...props\n}: ComponentProps<'blockquote'>) => (\n <blockquote\n className={cn(\n 'mt-5 gap-3 border-card border-l-4 pl-5 text-neutral [&_strong]:text-neutral',\n className\n )}\n {...props}\n />\n);\n\nconst UlRenderer = ({ className, ...props }: ComponentProps<'ul'>) => (\n <ul\n className={cn(\n 'mt-5 flex list-disc flex-col gap-3 pl-5 marker:text-neutral/80',\n className\n )}\n {...props}\n />\n);\n\nconst OlRenderer = ({ className, ...props }: ComponentProps<'ol'>) => (\n <ol\n className={cn(\n 'mt-5 flex list-decimal flex-col gap-3 pl-5 marker:text-neutral/80',\n className\n )}\n {...props}\n />\n);\n\nconst ImgRenderer = ({\n className,\n alt,\n src,\n ...props\n}: ComponentProps<'img'>) => (\n <img\n {...props}\n alt={alt ?? ''}\n loading=\"lazy\"\n className={cn('max-h-[80vh] max-w-full rounded-md', className)}\n src={\n src?.includes('github.com')\n ? src\n ?.replace('github.com', 'raw.githubusercontent.com')\n .replace('/blob/', '/') // GitHub raw URLs do not use /blob/\n : src\n }\n />\n);\n\nconst createLinkRenderer = (locale?: LocalesValues) => {\n return (props: ComponentProps<'a'>) => (\n <Link\n isExternalLink={props.href?.startsWith('http')}\n underlined\n locale={locale}\n label=\"\"\n color=\"text\"\n {...(props as any)}\n />\n );\n};\n\nconst PreRenderer = (props: ComponentProps<'pre'>) => <>{props.children}</>;\nconst TableRenderer = (props: ComponentProps<typeof Table>) => (\n <Table isRollable displayModal {...props} />\n);\nconst ThRenderer = ({ className, ...props }: ComponentProps<'th'>) => (\n <th\n className={cn('border-neutral border-b bg-neutral/10 p-4', className)}\n {...props}\n />\n);\nconst TrRenderer = ({ className, ...props }: ComponentProps<'tr'>) => (\n <tr className={cn('hover:/10 hover:bg-neutral/10', className)} {...props} />\n);\nconst TdRenderer = ({ className, ...props }: ComponentProps<'td'>) => (\n <td\n className={cn('border-neutral-500/50 border-b p-4', className)}\n {...props}\n />\n);\nconst HrRenderer = ({ className, ...props }: ComponentProps<'hr'>) => (\n <hr className={cn('mx-6 mt-16 text-neutral', className)} {...props} />\n);\n\nconst TabsRenderer = (props: ComponentProps<typeof Tab>) => (\n <Tab\n {...props}\n className=\"rounded-xl border border-card\"\n headerClassName=\"sticky rounded-xl top-24 z-5 bg-background/70 backdrop-blur overflow-x-auto\"\n />\n);\nconst ColumnsRenderer = ({\n className,\n ...props\n}: ComponentPropsWithoutRef<'div'>) => (\n <div className={cn('flex gap-4 max-md:flex-col', className)} {...props} />\n);\nconst ColumnRenderer = ({\n className,\n ...props\n}: ComponentPropsWithoutRef<'div'>) => (\n <div className={cn('flex-1', className)} {...props} />\n);\n\n// Static configuration object for static renderers\nconst staticMarkdownComponents = {\n h1: H1Renderer,\n h2: H2Renderer,\n h3: H3Renderer,\n h4: H4Renderer,\n h5: H5Renderer,\n h6: H6Renderer,\n strong: StrongRenderer,\n blockquote: BlockquoteRenderer,\n ul: UlRenderer,\n ol: OlRenderer,\n img: ImgRenderer,\n pre: PreRenderer,\n table: TableRenderer,\n th: ThRenderer,\n tr: TrRenderer,\n td: TdRenderer,\n hr: HrRenderer,\n Tabs: TabsRenderer,\n Tab: Tab.Item,\n Columns: ColumnsRenderer,\n Column: ColumnRenderer,\n};\n\n// Factory function to create components with dynamic props\nconst createMarkdownComponents = (\n isDarkMode?: boolean,\n locale?: LocalesValues\n) => ({\n ...staticMarkdownComponents,\n code: createCodeRenderer(isDarkMode),\n a: createLinkRenderer(locale),\n});\n\n// Export static renderers for backward compatibility\nexport const baseMarkdownComponents = staticMarkdownComponents;\n\ntype MarkdownRendererProps = {\n children: string;\n isDarkMode?: boolean;\n locale?: LocalesValues;\n forceBlock?: boolean;\n preserveFrontmatter?: boolean;\n tagfilter?: boolean;\n components?: ComponentProps<typeof MarkdownRendererIntlayer>['components'];\n wrapper?: ComponentProps<typeof MarkdownRendererIntlayer>['wrapper'];\n};\n\nexport const getIntlayerMarkdownOptions = (_isDarkMode?: boolean) => ({\n components: baseMarkdownComponents,\n});\n\nexport const MarkdownRenderer: FC<MarkdownRendererProps> = ({\n children,\n isDarkMode = false,\n locale,\n forceBlock,\n preserveFrontmatter,\n tagfilter,\n components: componentsProp,\n wrapper,\n}) => {\n const markdownComponents = createMarkdownComponents(isDarkMode, locale);\n\n const markdownContent = renderMarkdown(children, {\n components: {\n ...markdownComponents,\n ...componentsProp,\n },\n wrapper,\n forceBlock,\n preserveFrontmatter,\n tagfilter,\n });\n\n return (\n <CodeProvider>\n <TabProvider>{markdownContent}</TabProvider>\n </CodeProvider>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MarkDownRender.mjs","names":[],"sources":["../../../../src/components/MarkDownRender/MarkDownRender.tsx"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { cn } from '@utils/cn';\nimport type { ComponentProps, ComponentPropsWithoutRef, FC } from 'react';\nimport { memo } from 'react';\nimport {\n type MarkdownRenderer as MarkdownRendererIntlayer,\n renderMarkdown,\n} from 'react-intlayer';\nimport type { BundledLanguage } from 'shiki/bundle/web';\nimport { H1, H2, H3, H4, H5, H6 } from '../Headers';\nimport { Code } from '../IDE/Code';\nimport { CodeProvider } from '../IDE/CodeContext';\nimport { Link } from '../Link';\nimport { Tab } from '../Tab';\nimport { TabProvider } from '../Tab/TabContext';\nimport { SmartTable } from '../Table';\n\n// Extracted, stable component renderers\nconst H1Renderer = (props: ComponentProps<'h1'>) => (\n <H1 isClickable className=\"text-text\" {...props} />\n);\nconst H2Renderer = (props: ComponentProps<'h2'>) => (\n <H2 isClickable className=\"mt-16 text-text\" {...props} />\n);\nconst H3Renderer = (props: ComponentProps<'h3'>) => (\n <H3 isClickable className=\"mt-5 text-text\" {...props} />\n);\nconst H4Renderer = (props: ComponentProps<'h4'>) => (\n <H4 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst H5Renderer = (props: ComponentProps<'h5'>) => (\n <H5 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst H6Renderer = (props: ComponentProps<'h6'>) => (\n <H6 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst StrongRenderer = (props: ComponentProps<'strong'>) => (\n <strong className=\"text-text\" {...props} />\n);\n\nconst MemoizedCodeBlock = memo(\n ({\n className,\n children,\n isDarkMode,\n ...rest\n }: ComponentProps<'code'> & { isDarkMode?: boolean }) => {\n const content = String(children ?? '').replace(/\\n$/, '');\n const isBlock = !!className;\n\n if (!isBlock) {\n const decodedContent = content.replace(\n /&(?:amp;)?#(\\d+);/g,\n (_, code: string) => String.fromCharCode(parseInt(code, 10))\n );\n return (\n <code className=\"rounded-md border border-neutral/30 bg-card/60 box-decoration-clone px-1.5 py-0.5 font-mono text-sm\">\n {decodedContent}\n </code>\n );\n }\n\n const language = (className?.replace(/lang(?:uage)?-/, '') ||\n 'plaintext') as BundledLanguage;\n\n return (\n <Code {...rest} language={language} showHeader isDarkMode={isDarkMode}>\n {content}\n </Code>\n );\n },\n (prevProps, nextProps) =>\n prevProps.children === nextProps.children &&\n prevProps.className === nextProps.className &&\n prevProps.isDarkMode === nextProps.isDarkMode\n);\n\nconst createCodeRenderer = (isDarkMode?: boolean) => {\n return function CodeWrapper(props: ComponentProps<'code'>) {\n return <MemoizedCodeBlock {...props} isDarkMode={isDarkMode} />;\n };\n};\n\nconst BlockquoteRenderer = ({\n className,\n ...props\n}: ComponentProps<'blockquote'>) => (\n <blockquote\n className={cn(\n 'mt-5 gap-3 border-card border-l-4 pl-5 text-neutral [&_strong]:text-neutral',\n className\n )}\n {...props}\n />\n);\n\nconst UlRenderer = ({ className, ...props }: ComponentProps<'ul'>) => (\n <ul\n className={cn(\n 'mt-5 flex list-disc flex-col gap-3 pl-5 marker:text-neutral/80',\n className\n )}\n {...props}\n />\n);\n\nconst OlRenderer = ({ className, ...props }: ComponentProps<'ol'>) => (\n <ol\n className={cn(\n 'mt-5 flex list-decimal flex-col gap-3 pl-5 marker:text-neutral/80',\n className\n )}\n {...props}\n />\n);\n\nconst ImgRenderer = ({\n className,\n alt,\n src,\n ...props\n}: ComponentProps<'img'>) => (\n <img\n {...props}\n alt={alt ?? ''}\n loading=\"lazy\"\n className={cn('max-h-[80vh] max-w-full rounded-md', className)}\n src={\n src?.includes('github.com')\n ? src\n ?.replace('github.com', 'raw.githubusercontent.com')\n .replace('/blob/', '/') // GitHub raw URLs do not use /blob/\n : src\n }\n />\n);\n\nconst createLinkRenderer = (locale?: LocalesValues) => {\n return (props: ComponentProps<'a'>) => (\n <Link\n isExternalLink={props.href?.startsWith('http')}\n underlined\n locale={locale}\n label=\"\"\n color=\"text\"\n {...(props as any)}\n />\n );\n};\n\nconst PreRenderer = (props: ComponentProps<'pre'>) => <>{props.children}</>;\nconst TableRenderer = (props: ComponentProps<typeof SmartTable>) => (\n <SmartTable isRollable displayModal {...props} />\n);\nconst ThRenderer = ({ className, ...props }: ComponentProps<'th'>) => (\n <th\n className={cn('border-neutral border-b bg-neutral/10 p-4', className)}\n {...props}\n />\n);\nconst TrRenderer = ({ className, ...props }: ComponentProps<'tr'>) => (\n <tr className={cn('hover:/10 hover:bg-neutral/10', className)} {...props} />\n);\nconst TdRenderer = ({ className, ...props }: ComponentProps<'td'>) => (\n <td\n className={cn('border-neutral-500/50 border-b p-4', className)}\n {...props}\n />\n);\nconst HrRenderer = ({ className, ...props }: ComponentProps<'hr'>) => (\n <hr className={cn('mx-6 mt-16 text-neutral', className)} {...props} />\n);\n\nconst TabsRenderer = (props: ComponentProps<typeof Tab>) => (\n <Tab\n {...props}\n className=\"rounded-xl border border-card\"\n headerClassName=\"sticky rounded-xl top-24 z-5 bg-background/70 backdrop-blur overflow-x-auto\"\n />\n);\nconst ColumnsRenderer = ({\n className,\n ...props\n}: ComponentPropsWithoutRef<'div'>) => (\n <div className={cn('flex gap-4 max-md:flex-col', className)} {...props} />\n);\nconst ColumnRenderer = ({\n className,\n ...props\n}: ComponentPropsWithoutRef<'div'>) => (\n <div className={cn('flex-1', className)} {...props} />\n);\n\n// Static configuration object for static renderers\nconst staticMarkdownComponents = {\n h1: H1Renderer,\n h2: H2Renderer,\n h3: H3Renderer,\n h4: H4Renderer,\n h5: H5Renderer,\n h6: H6Renderer,\n strong: StrongRenderer,\n blockquote: BlockquoteRenderer,\n ul: UlRenderer,\n ol: OlRenderer,\n img: ImgRenderer,\n pre: PreRenderer,\n table: TableRenderer,\n th: ThRenderer,\n tr: TrRenderer,\n td: TdRenderer,\n hr: HrRenderer,\n Tabs: TabsRenderer,\n Tab: Tab.Item,\n Columns: ColumnsRenderer,\n Column: ColumnRenderer,\n};\n\n// Factory function to create components with dynamic props\nconst createMarkdownComponents = (\n isDarkMode?: boolean,\n locale?: LocalesValues\n) => ({\n ...staticMarkdownComponents,\n code: createCodeRenderer(isDarkMode),\n a: createLinkRenderer(locale),\n});\n\n// Export static renderers for backward compatibility\nexport const baseMarkdownComponents = staticMarkdownComponents;\n\ntype MarkdownRendererProps = {\n children: string;\n isDarkMode?: boolean;\n locale?: LocalesValues;\n forceBlock?: boolean;\n preserveFrontmatter?: boolean;\n tagfilter?: boolean;\n components?: ComponentProps<typeof MarkdownRendererIntlayer>['components'];\n wrapper?: ComponentProps<typeof MarkdownRendererIntlayer>['wrapper'];\n};\n\nexport const getIntlayerMarkdownOptions = (_isDarkMode?: boolean) => ({\n components: baseMarkdownComponents,\n});\n\nexport const MarkdownRenderer: FC<MarkdownRendererProps> = ({\n children,\n isDarkMode = false,\n locale,\n forceBlock,\n preserveFrontmatter,\n tagfilter,\n components: componentsProp,\n wrapper,\n}) => {\n const markdownComponents = createMarkdownComponents(isDarkMode, locale);\n\n const markdownContent = renderMarkdown(children, {\n components: {\n ...markdownComponents,\n ...componentsProp,\n },\n wrapper,\n forceBlock,\n preserveFrontmatter,\n tagfilter,\n });\n\n return (\n <CodeProvider>\n <TabProvider>{markdownContent}</TabProvider>\n </CodeProvider>\n );\n};\n"],"mappings":"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"}
|