@intlayer/design-system 8.10.0-canary.0 → 8.10.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.
Files changed (29) hide show
  1. package/dist/esm/components/Browser/Browser.mjs +3 -3
  2. package/dist/esm/components/Browser/Browser.mjs.map +1 -1
  3. package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
  4. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +4 -7
  5. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs.map +1 -1
  6. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +1 -1
  7. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +3 -3
  8. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +1 -1
  9. package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +1 -1
  10. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +2 -2
  11. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +1 -1
  12. package/dist/esm/components/Form/elements/OTPElement.mjs +1 -1
  13. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +1 -1
  14. package/dist/esm/components/Modal/Modal.mjs +2 -2
  15. package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
  16. package/dist/esm/components/Pagination/Pagination.mjs +1 -1
  17. package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -3
  18. package/dist/esm/components/Tab/Tab.mjs +1 -1
  19. package/dist/esm/hooks/index.mjs +9 -9
  20. package/dist/types/components/Badge/index.d.ts +1 -1
  21. package/dist/types/components/Button/Button.d.ts +2 -2
  22. package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +1 -1
  23. package/dist/types/components/Command/index.d.ts +2 -2
  24. package/dist/types/components/Container/index.d.ts +3 -3
  25. package/dist/types/components/DictionaryFieldEditor/ContentEditorView/TextEditor.d.ts.map +1 -1
  26. package/dist/types/components/Input/Checkbox.d.ts +1 -1
  27. package/dist/types/components/Link/Link.d.ts +1 -1
  28. package/dist/types/components/Tag/index.d.ts +1 -1
  29. package/package.json +18 -18
@@ -292,7 +292,7 @@ const Browser = ({ initialUrl = "https://example.com", path, className, style, s
292
292
  isFocusable: true,
293
293
  isOverable: true,
294
294
  children: /* @__PURE__ */ jsxs(Container, {
295
- className: "min-w-48 rounded-md!",
295
+ className: "min-w-28 rounded-md!",
296
296
  roundedSize: "sm",
297
297
  border: true,
298
298
  borderColor: "neutral",
@@ -308,7 +308,7 @@ const Browser = ({ initialUrl = "https://example.com", path, className, style, s
308
308
  size: "sm"
309
309
  })
310
310
  }), /* @__PURE__ */ jsx("ul", {
311
- className: "max-h-64 divide-y divide-dotted divide-neutral/30 overflow-y-auto p-1",
311
+ className: "max-h-64 divide-y divide-dotted divide-neutral/30 overflow-y-auto p-1 text-center",
312
312
  "aria-label": content.sitemapButtonLabel.value,
313
313
  children: sitemapLoading ? /* @__PURE__ */ jsx("li", {
314
314
  className: "px-3 py-4 text-center text-neutral text-xs",
@@ -322,7 +322,7 @@ const Browser = ({ initialUrl = "https://example.com", path, className, style, s
322
322
  variant: "hoverable",
323
323
  color: "text",
324
324
  size: "sm",
325
- className: "w-full justify-start",
325
+ className: "w-full text-left",
326
326
  label: url,
327
327
  onClick: () => {
328
328
  handleNavigateTo(url);
@@ -1 +1 @@
1
- {"version":3,"file":"Browser.mjs","names":[],"sources":["../../../../src/components/Browser/Browser.tsx"],"sourcesContent":["'use client';\n\nimport { Container } from '@components/Container';\nimport { cn } from '@utils/cn';\nimport {\n ArrowLeft,\n ArrowRight,\n Globe,\n List,\n RotateCw,\n ScanSearch,\n} from 'lucide-react';\nimport {\n type CSSProperties,\n type HTMLAttributes,\n type RefObject,\n type SubmitEvent,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { ClickOutsideDiv } from '../ClickOutsideDiv';\nimport { DropDown } from '../DropDown';\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\nconst getUrlPath = (url: string) => {\n try {\n const { pathname, search, hash } = new URL(url);\n return `${pathname}${search}${hash}` || '/';\n } catch {\n return url;\n }\n};\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 // Sitemap explorer state\n const [sitemapOpen, setSitemapOpen] = useState(false);\n const [sitemapUrls, setSitemapUrls] = useState<string[]>([]);\n const [sitemapSearch, setSitemapSearch] = useState('');\n const [sitemapLoading, setSitemapLoading] = useState(false);\n const [sitemapFetched, setSitemapFetched] = useState(false);\n const [sitemapError, setSitemapError] = useState(false);\n const sitemapInputRef = useRef<HTMLInputElement>(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 setSitemapOpen(false);\n setSitemapUrls([]);\n setSitemapSearch('');\n setSitemapFetched(false);\n setSitemapError(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 regardless of isAlreadyAtUrl so arrow navigation is always correct\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 only if NOT already there to avoid refreshing on internal iframe navigation\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 // Imperatively keep the iframe src in sync with currentUrl.\n // React's attribute reconciliation can be unreliable for cross-origin iframes after\n // internal navigation, so this effect is the source of truth for navigation.\n useEffect(() => {\n const iframe = internalIframeRef.current;\n if (!iframe) return;\n if (iframe.src !== currentUrl) {\n iframe.src = currentUrl;\n }\n }, [currentUrl]);\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 const iframe = internalIframeRef.current;\n if (!iframe) return;\n const src = iframe.src;\n iframe.src = '';\n setTimeout(() => {\n if (internalIframeRef.current) internalIframeRef.current.src = src;\n }, 50);\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 handleSitemapToggle = async () => {\n const nextOpen = !sitemapOpen;\n setSitemapOpen(nextOpen);\n\n if (nextOpen && !sitemapFetched) {\n setSitemapLoading(true);\n setSitemapError(false);\n setSitemapFetched(true);\n try {\n const { extractUrlFromSitemap } = await import(\n './extractUrlFromSitemap'\n );\n const urls = await extractUrlFromSitemap(currentUrl);\n setSitemapUrls(urls);\n if (urls.length === 0) setSitemapError(false);\n } catch {\n setSitemapError(true);\n } finally {\n setSitemapLoading(false);\n }\n setTimeout(() => sitemapInputRef.current?.focus(), 50);\n }\n };\n\n const filteredSitemapUrls = useMemo(() => {\n const query = sitemapSearch.trim().toLowerCase();\n if (!query) return sitemapUrls;\n return sitemapUrls.filter((url) => url.toLowerCase().includes(query));\n }, [sitemapUrls, sitemapSearch]);\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 {/* Sitemap Explorer */}\n <ClickOutsideDiv\n onClickOutSide={() => setSitemapOpen(false)}\n disabled={!sitemapOpen}\n role=\"none\"\n >\n <DropDown identifier=\"sitemap-explorer\">\n <DropDown.Trigger\n identifier=\"sitemap-explorer-trigger\"\n type=\"button\"\n color=\"text\"\n onClick={handleSitemapToggle}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.sitemapButtonLabel.value}\n Icon={ScanSearch}\n />\n\n <DropDown.Panel\n identifier=\"sitemap-explorer\"\n isHidden={!sitemapOpen}\n align=\"end\"\n isFocusable\n isOverable\n >\n <Container\n className=\"min-w-48 rounded-md!\"\n roundedSize=\"sm\"\n border\n borderColor=\"neutral\"\n >\n <div className=\"p-2\">\n <Input\n type=\"search\"\n ref={sitemapInputRef}\n aria-label={content.sitemapSearchAriaLabel.value}\n placeholder={content.sitemapSearchPlaceholder.value}\n onChange={(e) => setSitemapSearch(e.target.value)}\n value={sitemapSearch}\n size=\"sm\"\n />\n </div>\n <ul\n className=\"max-h-64 divide-y divide-dotted divide-neutral/30 overflow-y-auto p-1\"\n aria-label={content.sitemapButtonLabel.value}\n >\n {sitemapLoading ? (\n <li className=\"px-3 py-4 text-center text-neutral text-xs\">\n {content.sitemapLoading.value}\n </li>\n ) : sitemapError ||\n (!sitemapLoading && filteredSitemapUrls.length === 0) ? (\n <li className=\"px-3 py-4 text-center text-neutral text-xs\">\n {sitemapError\n ? content.sitemapError.value\n : content.sitemapEmpty.value}\n </li>\n ) : (\n filteredSitemapUrls.map((url) => (\n <li key={url} className=\"py-0.5\">\n <Button\n variant=\"hoverable\"\n color=\"text\"\n size=\"sm\"\n className=\"w-full justify-start\"\n label={url}\n onClick={() => {\n handleNavigateTo(url);\n setSitemapOpen(false);\n }}\n >\n <span className=\"max-w-64 truncate text-left text-base\">\n {getUrlPath(url)}\n </span>\n </Button>\n </li>\n ))\n )}\n </ul>\n </Container>\n </DropDown.Panel>\n </DropDown>\n </ClickOutsideDiv>\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 { Container } from '@components/Container';\nimport { cn } from '@utils/cn';\nimport {\n ArrowLeft,\n ArrowRight,\n Globe,\n List,\n RotateCw,\n ScanSearch,\n} from 'lucide-react';\nimport {\n type CSSProperties,\n type HTMLAttributes,\n type RefObject,\n type SubmitEvent,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { ClickOutsideDiv } from '../ClickOutsideDiv';\nimport { DropDown } from '../DropDown';\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\nconst getUrlPath = (url: string) => {\n try {\n const { pathname, search, hash } = new URL(url);\n return `${pathname}${search}${hash}` || '/';\n } catch {\n return url;\n }\n};\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 // Sitemap explorer state\n const [sitemapOpen, setSitemapOpen] = useState(false);\n const [sitemapUrls, setSitemapUrls] = useState<string[]>([]);\n const [sitemapSearch, setSitemapSearch] = useState('');\n const [sitemapLoading, setSitemapLoading] = useState(false);\n const [sitemapFetched, setSitemapFetched] = useState(false);\n const [sitemapError, setSitemapError] = useState(false);\n const sitemapInputRef = useRef<HTMLInputElement>(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 setSitemapOpen(false);\n setSitemapUrls([]);\n setSitemapSearch('');\n setSitemapFetched(false);\n setSitemapError(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 regardless of isAlreadyAtUrl so arrow navigation is always correct\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 only if NOT already there to avoid refreshing on internal iframe navigation\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 // Imperatively keep the iframe src in sync with currentUrl.\n // React's attribute reconciliation can be unreliable for cross-origin iframes after\n // internal navigation, so this effect is the source of truth for navigation.\n useEffect(() => {\n const iframe = internalIframeRef.current;\n if (!iframe) return;\n if (iframe.src !== currentUrl) {\n iframe.src = currentUrl;\n }\n }, [currentUrl]);\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 const iframe = internalIframeRef.current;\n if (!iframe) return;\n const src = iframe.src;\n iframe.src = '';\n setTimeout(() => {\n if (internalIframeRef.current) internalIframeRef.current.src = src;\n }, 50);\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 handleSitemapToggle = async () => {\n const nextOpen = !sitemapOpen;\n setSitemapOpen(nextOpen);\n\n if (nextOpen && !sitemapFetched) {\n setSitemapLoading(true);\n setSitemapError(false);\n setSitemapFetched(true);\n try {\n const { extractUrlFromSitemap } = await import(\n './extractUrlFromSitemap'\n );\n const urls = await extractUrlFromSitemap(currentUrl);\n setSitemapUrls(urls);\n if (urls.length === 0) setSitemapError(false);\n } catch {\n setSitemapError(true);\n } finally {\n setSitemapLoading(false);\n }\n setTimeout(() => sitemapInputRef.current?.focus(), 50);\n }\n };\n\n const filteredSitemapUrls = useMemo(() => {\n const query = sitemapSearch.trim().toLowerCase();\n if (!query) return sitemapUrls;\n return sitemapUrls.filter((url) => url.toLowerCase().includes(query));\n }, [sitemapUrls, sitemapSearch]);\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 {/* Sitemap Explorer */}\n <ClickOutsideDiv\n onClickOutSide={() => setSitemapOpen(false)}\n disabled={!sitemapOpen}\n role=\"none\"\n >\n <DropDown identifier=\"sitemap-explorer\">\n <DropDown.Trigger\n identifier=\"sitemap-explorer-trigger\"\n type=\"button\"\n color=\"text\"\n onClick={handleSitemapToggle}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.sitemapButtonLabel.value}\n Icon={ScanSearch}\n />\n\n <DropDown.Panel\n identifier=\"sitemap-explorer\"\n isHidden={!sitemapOpen}\n align=\"end\"\n isFocusable\n isOverable\n >\n <Container\n className=\"min-w-28 rounded-md!\"\n roundedSize=\"sm\"\n border\n borderColor=\"neutral\"\n >\n <div className=\"p-2\">\n <Input\n type=\"search\"\n ref={sitemapInputRef}\n aria-label={content.sitemapSearchAriaLabel.value}\n placeholder={content.sitemapSearchPlaceholder.value}\n onChange={(e) => setSitemapSearch(e.target.value)}\n value={sitemapSearch}\n size=\"sm\"\n />\n </div>\n <ul\n className=\"max-h-64 divide-y divide-dotted divide-neutral/30 overflow-y-auto p-1 text-center\"\n aria-label={content.sitemapButtonLabel.value}\n >\n {sitemapLoading ? (\n <li className=\"px-3 py-4 text-center text-neutral text-xs\">\n {content.sitemapLoading.value}\n </li>\n ) : sitemapError ||\n (!sitemapLoading && filteredSitemapUrls.length === 0) ? (\n <li className=\"px-3 py-4 text-center text-neutral text-xs\">\n {sitemapError\n ? content.sitemapError.value\n : content.sitemapEmpty.value}\n </li>\n ) : (\n filteredSitemapUrls.map((url) => (\n <li key={url} className=\"py-0.5\">\n <Button\n variant=\"hoverable\"\n color=\"text\"\n size=\"sm\"\n className=\"w-full text-left\"\n label={url}\n onClick={() => {\n handleNavigateTo(url);\n setSitemapOpen(false);\n }}\n >\n <span className=\"max-w-64 truncate text-left text-base\">\n {getUrlPath(url)}\n </span>\n </Button>\n </li>\n ))\n )}\n </ul>\n </Container>\n </DropDown.Panel>\n </DropDown>\n </ClickOutsideDiv>\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";
@@ -1,6 +1,5 @@
1
1
  'use client';
2
2
 
3
- import { useAuditContentDeclarationField } from "../../../hooks/reactQuery.mjs";
4
3
  import { Container } from "../../Container/index.mjs";
5
4
  import { Loader } from "../../Loader/index.mjs";
6
5
  import { Button, ButtonColor, ButtonSize, ButtonTextAlign, ButtonVariant } from "../../Button/Button.mjs";
@@ -9,6 +8,7 @@ import { InputVariant } from "../../Input/Input.mjs";
9
8
  import { SwitchSelector, SwitchSelectorColor, SwitchSelectorSize } from "../../SwitchSelector/SwitchSelector.mjs";
10
9
  import { useLocaleSwitcherContent } from "../../LocaleSwitcherContentDropDown/LocaleSwitcherContentContext.mjs";
11
10
  import { ContentEditorInput as ContentEditorInput$1 } from "../../ContentEditor/ContentEditorInput.mjs";
11
+ import { useAuditContentDeclarationField } from "../../../hooks/reactQuery.mjs";
12
12
  import { ContentEditorTextArea as ContentEditorTextArea$1 } from "../../ContentEditor/ContentEditorTextArea.mjs";
13
13
  import { renameKey } from "./object.mjs";
14
14
  import { Label } from "../../Label/index.mjs";
@@ -17,9 +17,9 @@ import { SafeHtmlRenderer } from "./SafeHtmlRenderer.mjs";
17
17
  import { Fragment, Suspense, lazy, memo, useState } from "react";
18
18
  import { Plus, Trash, WandSparkles } from "lucide-react";
19
19
  import { jsx, jsxs } from "react/jsx-runtime";
20
- import { useConfiguration, useEditedContent } from "@intlayer/editor-react";
21
20
  import { useIntlayer, useLocale } from "react-intlayer";
22
21
  import { getLocaleName } from "@intlayer/core/localization";
22
+ import { useConfiguration, useEditedContent } from "@intlayer/editor-react";
23
23
  import { getEmptyNode, getNodeType } from "@intlayer/core/dictionaryManipulator";
24
24
  import * as NodeTypes from "@intlayer/types/nodeType";
25
25
  import { camelCaseToSentence } from "@intlayer/config/client";
@@ -112,16 +112,13 @@ const ContentEditorToggle = ({ dictionary, keyPath, ...props }) => {
112
112
  };
113
113
  const TranslationTextEditor = ({ section, keyPath, dictionary, renderSection }) => {
114
114
  const { locale, defaultLocale } = useLocale();
115
- const { selectedLocales, availableLocales } = useLocaleSwitcherContent();
116
- const sectionContent = section[NodeTypes.TRANSLATION];
117
- const sectionContentKeys = Object.keys(sectionContent);
118
- const localesList = availableLocales.length > selectedLocales.length ? selectedLocales : [...new Set([...availableLocales, ...sectionContentKeys])];
115
+ const { selectedLocales } = useLocaleSwitcherContent();
119
116
  const content = section[NodeTypes.TRANSLATION];
120
117
  return /* @__PURE__ */ jsx("table", {
121
118
  className: "w-full",
122
119
  children: /* @__PURE__ */ jsx("tbody", {
123
120
  className: "flex w-full flex-col gap-2",
124
- children: localesList.map((translationKey) => {
121
+ children: selectedLocales.map((translationKey) => {
125
122
  const uniqueKey = `${JSON.stringify(keyPath)}-translation-${translationKey}`;
126
123
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("tr", {
127
124
  className: "mt-2 w-full p-2 text-xs",
@@ -1 +1 @@
1
- {"version":3,"file":"TextEditor.mjs","names":["ContentEditorTextAreaBase","ContentEditorInputBase"],"sources":["../../../../../src/components/DictionaryFieldEditor/ContentEditorView/TextEditor.tsx"],"sourcesContent":["'use client';\n\nimport { Accordion } from '@components/Accordion';\nimport {\n Button,\n ButtonColor,\n ButtonSize,\n ButtonTextAlign,\n ButtonVariant,\n} from '@components/Button';\nimport { Container } from '@components/Container';\nimport {\n ContentEditorInput as ContentEditorInputBase,\n type ContentEditorInputProps as ContentEditorInputPropsBase,\n} from '@components/ContentEditor/ContentEditorInput';\nimport {\n ContentEditorTextArea as ContentEditorTextAreaBase,\n type ContentEditorTextAreaProps as ContentEditorTextAreaPropsBase,\n} from '@components/ContentEditor/ContentEditorTextArea';\nimport { renameKey } from '@components/DictionaryFieldEditor/ContentEditorView/object';\nimport { InputVariant } from '@components/Input';\nimport { Label } from '@components/Label';\nimport { Loader } from '@components/Loader';\nimport { useLocaleSwitcherContent } from '@components/LocaleSwitcherContentDropDown';\nimport {\n SwitchSelector,\n type SwitchSelectorChoices,\n SwitchSelectorColor,\n type SwitchSelectorProps,\n SwitchSelectorSize,\n} from '@components/SwitchSelector';\nimport { useAuditContentDeclarationField } from '@hooks/reactQuery';\nimport { camelCaseToSentence } from '@intlayer/config/client';\nimport {\n getEmptyNode,\n getNodeType,\n} from '@intlayer/core/dictionaryManipulator';\nimport { getLocaleName } from '@intlayer/core/localization';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n GenderContent,\n HTMLContent,\n InsertionContent,\n MarkdownContent,\n PluralContent,\n TranslationContent,\n} from '@intlayer/core/transpiler';\nimport { useConfiguration, useEditedContent } from '@intlayer/editor-react';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { Plus, Trash, WandSparkles } from 'lucide-react';\nimport {\n type FC,\n Fragment,\n lazy,\n memo,\n type ReactNode,\n Suspense,\n useState,\n} from 'react';\nimport { useIntlayer, useLocale } from 'react-intlayer';\nimport { EnumKeyInput } from '../EnumKeyInput';\nimport { SafeHtmlRenderer } from './SafeHtmlRenderer';\n\nconst LazyMarkdownRenderer = lazy(() =>\n import('@components/MarkDownRender').then((m) => ({\n default: m.MarkdownRenderer,\n }))\n);\n\n// Renders children only after the accordion is first opened (mount-once pattern).\n// Prevents deeply nested sub-trees from mounting on initial render.\ntype CollapsibleEditorProps = TextEditorProps & { label: string };\nconst CollapsibleEditor = memo<CollapsibleEditorProps>(\n function CollapsibleEditor({ label, ...editorProps }) {\n const [hasOpened, setHasOpened] = useState(false);\n return (\n <Accordion\n header={label}\n label={label}\n onToggle={(isOpen) => {\n if (isOpen && !hasOpened) setHasOpened(true);\n }}\n >\n {hasOpened ? <TextEditor {...editorProps} /> : null}\n </Accordion>\n );\n }\n);\n\nexport const traceKeys: string[] = ['filePath', 'id', 'nodeType'];\n\ntype ContentEditorTextAreaProps = Omit<\n ContentEditorTextAreaPropsBase,\n 'onContentChange'\n> & {\n keyPath: KeyPath[];\n dictionary: Dictionary;\n};\n\nconst ContentEditorTextArea: FC<ContentEditorTextAreaProps> = ({\n keyPath,\n dictionary,\n ...props\n}) => {\n const { editedContent, addEditedContent } = useEditedContent();\n const configuration = useConfiguration();\n const { mutate: auditContentDeclarationField, isPending: isAuditing } =\n useAuditContentDeclarationField();\n\n return (\n <ContentEditorTextAreaBase\n variant={InputVariant.DEFAULT}\n onContentChange={(newValue) =>\n addEditedContent(dictionary.localId!, newValue, keyPath)\n }\n additionalButtons={\n <Button\n Icon={WandSparkles}\n label=\"Audit\"\n variant={ButtonVariant.HOVERABLE}\n size={ButtonSize.ICON_SM}\n color={ButtonColor.TEXT}\n className=\"cursor-pointer hover:scale-110\"\n isLoading={isAuditing}\n onClick={() => {\n auditContentDeclarationField(\n {\n fileContent: JSON.stringify({\n ...dictionary,\n ...(editedContent?.[dictionary.localId!] ?? {}),\n }),\n keyPath,\n locales: configuration?.internationalization.locales ?? [],\n aiOptions: {\n apiKey: configuration?.ai?.apiKey,\n model: configuration?.ai?.model,\n temperature: configuration?.ai?.temperature,\n },\n },\n {\n onSuccess: (response) => {\n if (!response?.data) return;\n\n try {\n const editedContent = response.data.fileContent as string;\n\n addEditedContent(\n dictionary.localId!,\n editedContent,\n keyPath\n );\n } catch (error) {\n console.error(error);\n }\n },\n }\n );\n }}\n />\n }\n {...props}\n />\n );\n};\n\ntype ContentEditorInputProps = Omit<\n ContentEditorInputPropsBase,\n 'onContentChange'\n> & {\n keyPath: KeyPath[];\n dictionary: Dictionary;\n};\n\nconst ContentEditorInput: FC<ContentEditorInputProps> = ({\n keyPath,\n dictionary,\n ...props\n}) => {\n const { addEditedContent } = useEditedContent();\n\n return (\n <ContentEditorInputBase\n variant={InputVariant.DEFAULT}\n onContentChange={(newValue) =>\n addEditedContent(dictionary.localId!, newValue, keyPath)\n }\n {...props}\n />\n );\n};\n\nconst toggleContent = [\n {\n content: 'False',\n value: false,\n },\n {\n content: 'True',\n value: true,\n },\n] as SwitchSelectorChoices<boolean>;\n\ntype ContentEditorToggleProps = SwitchSelectorProps & {\n dictionary: Dictionary;\n keyPath: KeyPath[];\n};\n\nconst ContentEditorToggle: FC<ContentEditorToggleProps> = ({\n dictionary,\n keyPath,\n ...props\n}) => {\n const { addEditedContent } = useEditedContent();\n\n return (\n <SwitchSelector\n choices={toggleContent}\n value={true}\n onChange={(value) =>\n addEditedContent(dictionary.localId!, value, keyPath)\n }\n color={SwitchSelectorColor.TEXT}\n size={SwitchSelectorSize.SM}\n {...props}\n />\n );\n};\n\nexport type TextEditorProps = {\n dictionary: Dictionary;\n keyPath: KeyPath[];\n section: ContentNode;\n isDarkMode?: boolean;\n renderSection?: (content: string) => ReactNode;\n onContentChange?: (newValue: string) => void;\n};\n\nconst TranslationTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}: TextEditorProps) => {\n const { locale, defaultLocale } = useLocale();\n const { selectedLocales, availableLocales } = useLocaleSwitcherContent();\n\n const sectionContent = (section as TranslationContent<string>)[\n NodeTypes.TRANSLATION\n ] as Record<Locale, string>;\n\n const sectionContentKeys = Object.keys(sectionContent) as LocalesValues[];\n\n const isFiltered = availableLocales.length > selectedLocales.length;\n\n const localesList = isFiltered\n ? selectedLocales\n : // If the translation include content in other locales, we display all of them\n [...new Set([...availableLocales, ...sectionContentKeys])];\n\n const content: any = (section as TranslationContent<string>)[\n NodeTypes.TRANSLATION\n ];\n\n return (\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {localesList.map((translationKey) => {\n const uniqueKey = `${JSON.stringify(keyPath)}-translation-${translationKey}`;\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 w-full p-2 text-xs\">\n <td className=\"flex w-full\">\n {getLocaleName(translationKey, locale)}\n </td>\n </tr>\n <tr className=\"flex\">\n <td className=\"flex w-full\">\n <TextEditorContainer\n section={\n content[translationKey] ??\n getEmptyNode(content[defaultLocale])\n }\n keyPath={[\n ...keyPath,\n { type: NodeTypes.TRANSLATION, key: translationKey },\n ]}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nconst EnumerationTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const { addEditedContent } = useEditedContent();\n const { addNewEnumeration, removeEnumeration } =\n useIntlayer('navigation-view');\n\n const content = (section as EnumerationContent<string>)[\n NodeTypes.ENUMERATION\n ];\n const firstKey = Object.keys(content)[0] as keyof typeof content;\n\n return (\n <div className=\"flex flex-col gap-2\">\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {Object.keys(\n (section as EnumerationContent<ContentNode>)[NodeTypes.ENUMERATION]\n ).map((enumKey) => {\n const childrenKeyPath = [\n ...keyPath,\n { type: NodeTypes.ENUMERATION, key: enumKey },\n ] as KeyPath[];\n const uniqueKey = `${JSON.stringify(keyPath)}-enumeration-${enumKey}`;\n\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 w-full\">\n <td className=\"flex w-full\">\n <div className=\"flex flex-1\">\n <Button\n label={removeEnumeration.label.value}\n variant=\"hoverable\"\n size=\"sm\"\n color=\"error\"\n className=\"ml-auto text-neutral hover:text-error\"\n Icon={Trash}\n onClick={() =>\n addEditedContent(\n dictionary.localId!,\n undefined,\n childrenKeyPath\n )\n }\n >\n {removeEnumeration.text}\n </Button>\n </div>\n </td>\n </tr>\n <tr className=\"w-full p-2\">\n <td className=\"flex w-full\">\n <EnumKeyInput\n value={enumKey}\n onChange={(value) => {\n const preValueContent = (\n section as EnumerationContent<string>\n )[NodeTypes.ENUMERATION];\n\n const newValueContent = renameKey(\n preValueContent,\n enumKey as keyof typeof preValueContent,\n value\n );\n const newValue = {\n ...(section as EnumerationContent<string>),\n [NodeTypes.ENUMERATION]: newValueContent,\n };\n\n console.log('newValue', newValue);\n\n addEditedContent(\n dictionary.localId!,\n newValue,\n keyPath\n );\n }}\n />\n </td>\n </tr>\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditor\n section={\n content[enumKey as keyof typeof content] ??\n getEmptyNode(content[firstKey])\n }\n keyPath={childrenKeyPath}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n\n <Button\n label={addNewEnumeration.label.value}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.NEUTRAL}\n textAlign={ButtonTextAlign.LEFT}\n isFullWidth\n onClick={() =>\n addEditedContent(\n dictionary.localId!,\n getEmptyNode(content[firstKey]) ?? '',\n [...keyPath, { type: NodeTypes.ENUMERATION, key: 'unknown' }]\n )\n }\n Icon={Plus}\n className=\"m-2\"\n >\n {addNewEnumeration.text}\n </Button>\n </div>\n );\n};\n\nconst ConditionTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const content = (section as ConditionContent<string>)[NodeTypes.CONDITION];\n\n return (\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {['true', 'false', 'fallback'].map((condKey) => {\n const uniqueKey = `${JSON.stringify(keyPath)}-condition-${condKey}`;\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 block w-full p-2 text-xs\">\n <td className=\"flex w-full\">{String(condKey)}</td>\n </tr>\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditorContainer\n section={\n content[condKey as keyof typeof content] ??\n getEmptyNode(content.true)\n }\n keyPath={[\n ...keyPath,\n {\n type: NodeTypes.CONDITION,\n key: condKey,\n } as KeyPath,\n ]}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nconst GenderTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const content = (section as GenderContent<string>)[NodeTypes.GENDER];\n\n return (\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {['male', 'female', 'fallback'].map((condKey) => {\n const uniqueKey = `${JSON.stringify(keyPath)}-gender-${condKey}`;\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 block w-full p-2 text-xs\">\n <td className=\"flex w-full\">{String(condKey)}</td>\n </tr>\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditorContainer\n section={\n content[condKey as keyof typeof content] ??\n getEmptyNode(content.male)\n }\n keyPath={[\n ...keyPath,\n {\n type: NodeTypes.GENDER,\n key: condKey,\n } as KeyPath,\n ]}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nconst PLURAL_CATEGORIES = ['zero', 'one', 'two', 'few', 'many', 'other'];\n\nconst PluralTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const content = (section as PluralContent<string>)[NodeTypes.PLURAL];\n\n return (\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {PLURAL_CATEGORIES.map((pluralKey) => {\n const uniqueKey = `${JSON.stringify(keyPath)}-plural-${pluralKey}`;\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 block w-full p-2 text-xs\">\n <td className=\"flex w-full\">{pluralKey}</td>\n </tr>\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditorContainer\n section={\n content[pluralKey as keyof typeof content] ??\n getEmptyNode(content.other)\n }\n keyPath={[\n ...keyPath,\n {\n type: NodeTypes.PLURAL,\n key: pluralKey,\n } as KeyPath,\n ]}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nconst ArrayTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const { addEditedContent } = useEditedContent();\n const { addNewElement, removeElement } = useIntlayer('navigation-view');\n\n return (\n <div className=\"flex flex-col gap-2\">\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {(section as unknown as ContentNode[]).map((subSection, index) => {\n const uniqueKey = `${JSON.stringify(keyPath)}-array-${index}`;\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 w-full p-2\">\n <td className=\"flex w-full\">\n <div className=\"flex w-full items-center justify-between gap-2\">\n <span className=\"text-xs\">{String(index)}</span>\n <Button\n label={removeElement.label.value}\n variant=\"hoverable\"\n size=\"sm\"\n color=\"error\"\n className=\"ml-auto text-neutral hover:text-error\"\n onClick={() => {\n const newKeyPath: KeyPath[] = [\n ...keyPath,\n {\n type: NodeTypes.ARRAY,\n key: index, // Fixed: Use index instead of length\n },\n ];\n addEditedContent(\n dictionary.localId!,\n undefined,\n newKeyPath\n );\n }}\n Icon={Trash}\n >\n {removeElement.text}\n </Button>\n </div>\n </td>\n </tr>\n\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditorContainer\n section={\n subSection ??\n getEmptyNode((section as unknown as ContentNode[])[0])\n }\n keyPath={[\n ...keyPath,\n {\n type: NodeTypes.ARRAY,\n key: index,\n },\n ]}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n <Button\n label={addNewElement.label.value}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.NEUTRAL}\n textAlign={ButtonTextAlign.LEFT}\n isFullWidth\n onClick={() => {\n const newKeyPath: KeyPath[] = [\n ...keyPath,\n {\n type: NodeTypes.ARRAY,\n key: (section as unknown as ContentNode[]).length, // Keeps length for adding new items\n },\n ];\n addEditedContent(\n dictionary.localId!,\n getEmptyNode((section as unknown as ContentNode[])[0]) ?? '',\n newKeyPath,\n false\n );\n }}\n Icon={Plus}\n >\n {addNewElement.text}\n </Button>\n </div>\n );\n};\n\nconst ObjectTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const typedSection = section as unknown as Record<string, ContentNode>;\n const firstKey = Object.keys(typedSection)[0] as keyof typeof section;\n\n return (\n <table className=\"w-full\">\n <tbody className=\"flex flex-col gap-2\">\n {Object.keys(typedSection).map((key) => {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: NodeTypes.OBJECT, key },\n ];\n const subSection =\n typedSection[key as keyof typeof section] ??\n getEmptyNode(typedSection[firstKey]);\n const uniqueKey = `${JSON.stringify(keyPath)}-object-${key}`;\n // Collapse any object/array (typed or plain) — only true primitives render inline.\n // getIsEditableSection can't be used here: it inspects getNodeChildren(), which for\n // translation nodes returns the first locale value (a string), causing translation\n // subtrees to be mistakenly treated as leaves and mounted all at once.\n const isLeaf = subSection === null || typeof subSection !== 'object';\n\n if (isLeaf) {\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 p-2 text-xs\">\n <td className=\"flex w-full\">{String(key)}</td>\n </tr>\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditor\n section={subSection}\n keyPath={childKeyPath}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n }\n\n return (\n <tr\n key={uniqueKey}\n className=\"block w-full border-neutral/10 border-t py-1\"\n >\n <td className=\"flex w-full\">\n <CollapsibleEditor\n label={camelCaseToSentence(key)}\n section={subSection}\n keyPath={childKeyPath}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nenum MarkdownViewMode {\n Edit,\n Preview,\n}\n\nenum HtmlViewMode {\n Edit,\n Preview,\n}\n\nconst HtmlTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n}) => {\n const [mode, setMode] = useState(HtmlViewMode.Edit);\n const toggleContent = [\n {\n content: 'Edit',\n value: HtmlViewMode.Edit,\n },\n {\n content: 'Preview',\n value: HtmlViewMode.Preview,\n },\n ] as SwitchSelectorChoices<HtmlViewMode>;\n const childKeyPath: KeyPath[] = [...keyPath, { type: NodeTypes.HTML }];\n\n const content = (section as HTMLContent<ContentNode>)[\n NodeTypes.HTML\n ] as ContentNode;\n\n return (\n <div className=\"flex w-full flex-col justify-center gap-6 p-2\">\n <SwitchSelector\n choices={toggleContent}\n value={mode}\n onChange={setMode}\n color={SwitchSelectorColor.TEXT}\n size={SwitchSelectorSize.SM}\n className=\"ml-auto\"\n />\n\n <TextEditorContainer\n section={content}\n keyPath={childKeyPath}\n dictionary={dictionary}\n renderSection={\n mode === HtmlViewMode.Preview\n ? (rawContent) => <SafeHtmlRenderer rawContent={rawContent} />\n : undefined\n }\n />\n </div>\n );\n};\n\nconst MarkdownTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n isDarkMode,\n}) => {\n const [mode, setMode] = useState(MarkdownViewMode.Edit);\n const toggleContent = [\n {\n content: 'Edit',\n value: MarkdownViewMode.Edit,\n },\n {\n content: 'Preview',\n value: MarkdownViewMode.Preview,\n },\n ] as SwitchSelectorChoices<MarkdownViewMode>;\n const childKeyPath: KeyPath[] = [...keyPath, { type: NodeTypes.MARKDOWN }];\n\n const content = ((section as MarkdownContent<ContentNode>)[\n NodeTypes.MARKDOWN\n ] ?? '') as ContentNode;\n\n return (\n <div className=\"flex w-full flex-col justify-center gap-6 p-2\">\n <SwitchSelector\n choices={toggleContent}\n value={mode}\n onChange={setMode}\n color={SwitchSelectorColor.TEXT}\n size={SwitchSelectorSize.SM}\n className=\"ml-auto\"\n />\n\n <TextEditorContainer\n section={content}\n keyPath={childKeyPath}\n dictionary={dictionary}\n renderSection={\n mode === MarkdownViewMode.Preview\n ? (content) => (\n <Suspense fallback={<Loader />}>\n <LazyMarkdownRenderer isDarkMode={isDarkMode}>\n {content}\n </LazyMarkdownRenderer>\n </Suspense>\n )\n : undefined\n }\n />\n </div>\n );\n};\n\nconst InsertionTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n ...props\n}) => {\n const childKeyPath: KeyPath[] = [...keyPath, { type: NodeTypes.INSERTION }];\n\n const content = (section as InsertionContent<ContentNode>)[\n NodeTypes.INSERTION\n ];\n\n return (\n <div className=\"flex w-full flex-col justify-center gap-6 p-2\">\n <TextEditorContainer\n section={content}\n keyPath={childKeyPath}\n {...props}\n />\n </div>\n );\n};\n\nconst FileTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n ...props\n}) => {\n const childKeyPath: KeyPath[] = [...keyPath, { type: NodeTypes.FILE }];\n\n const fileUrl = (section as FileContent)[NodeTypes.FILE];\n const { content } = section as FileContent;\n\n return (\n <div className=\"flex w-full flex-col justify-center gap-6 p-2\">\n <span className=\"text-neutral text-sm\">{fileUrl} </span>\n <TextEditorContainer\n section={content}\n keyPath={childKeyPath}\n {...props}\n />\n </div>\n );\n};\n\nconst NestedTextEditor: FC<TextEditorProps> = ({\n keyPath,\n dictionary,\n renderSection,\n section,\n ...props\n}) => {\n const { addEditedContent } = useEditedContent();\n\n const content = (section as any)[NodeTypes.NESTED];\n const childrenKeyPath = [...keyPath, { type: NodeTypes.NESTED }] as KeyPath[];\n\n return (\n <div className=\"flex w-full flex-col gap-4 p-2\">\n <Label>Dictionary key</Label>\n <ContentEditorInputBase\n aria-label=\"Edit field\"\n type=\"text\"\n variant={InputVariant.DEFAULT}\n {...props}\n onContentChange={(newValue) => {\n addEditedContent(\n dictionary.localId!,\n {\n ...content,\n dictionaryKey: String(newValue),\n },\n childrenKeyPath\n );\n }}\n >\n {content.dictionaryKey ?? ''}\n </ContentEditorInputBase>\n\n <Label>Path (optional)</Label>\n <ContentEditorInputBase\n aria-label=\"Edit field\"\n type=\"text\"\n variant={InputVariant.DEFAULT}\n {...props}\n onContentChange={(newValue) => {\n addEditedContent(\n dictionary.localId!,\n {\n ...content,\n path: newValue !== '' ? newValue : undefined,\n },\n childrenKeyPath\n );\n }}\n >\n {content.path ?? ''}\n </ContentEditorInputBase>\n </div>\n );\n};\n\nexport const TextEditor = memo<TextEditorProps>(function TextEditor({\n section,\n keyPath,\n dictionary,\n renderSection,\n isDarkMode,\n}) {\n const { tsxNotEditable } = useIntlayer('navigation-view');\n const nodeType = getNodeType(section);\n\n if (nodeType === NodeTypes.REACT_NODE) {\n return (\n <div className=\"flex w-full flex-col gap-2\">\n <span>(React Node)</span>\n <span className=\"flex text-neutral text-xs\">{tsxNotEditable}</span>\n </div>\n );\n }\n\n if (nodeType === NodeTypes.NESTED) {\n return (\n <NestedTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return (\n <TranslationTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.ENUMERATION) {\n return (\n <EnumerationTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.CONDITION) {\n return (\n <ConditionTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.GENDER) {\n return (\n <GenderTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.PLURAL) {\n return (\n <PluralTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.INSERTION) {\n return (\n <InsertionTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.MARKDOWN) {\n return (\n <MarkdownTextEditor\n dictionary={dictionary}\n keyPath={keyPath}\n section={section}\n isDarkMode={isDarkMode}\n />\n );\n }\n\n if (nodeType === NodeTypes.HTML) {\n return (\n <HtmlTextEditor\n dictionary={dictionary}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.FILE) {\n return (\n <FileTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.ARRAY) {\n return (\n <ArrayTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.OBJECT) {\n return (\n <ObjectTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.NUMBER) {\n return (\n <div className=\"w-full p-2\">\n <ContentEditorInput\n dictionary={dictionary}\n keyPath={keyPath}\n type=\"number\"\n aria-label=\"Edit field\"\n >\n {section as number}\n </ContentEditorInput>\n </div>\n );\n }\n\n if (nodeType === NodeTypes.TEXT) {\n return (\n <div className=\"w-full p-2\">\n {typeof renderSection === 'function' ? (\n renderSection(section as string)\n ) : (\n <ContentEditorTextArea\n variant={InputVariant.DEFAULT}\n aria-label=\"Edit field\"\n keyPath={keyPath}\n dictionary={dictionary}\n >\n {section as string}\n </ContentEditorTextArea>\n )}\n </div>\n );\n }\n\n if (nodeType === NodeTypes.BOOLEAN) {\n return (\n <div className=\"w-full p-2\">\n <ContentEditorToggle\n dictionary={dictionary}\n keyPath={keyPath}\n value={section as boolean}\n />\n </div>\n );\n }\n\n return (\n <div className=\"w-full p-2\">\n Error. Format not supported.\n {JSON.stringify(section, null, 2)}\n {JSON.stringify(keyPath, null, 2)}\n NodeType : {nodeType}\n </div>\n );\n});\n\nexport const TextEditorContainer = memo<TextEditorProps>(\n function TextEditorContainer(props) {\n return (\n <Container\n border\n background=\"none\"\n className=\"top-6 flex h-full flex-1 flex-col gap-6 overflow-hidden p-2 md:sticky\"\n roundedSize=\"2xl\"\n >\n <TextEditor {...props} />\n </Container>\n );\n }\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"TextEditor.mjs","names":["ContentEditorTextAreaBase","ContentEditorInputBase"],"sources":["../../../../../src/components/DictionaryFieldEditor/ContentEditorView/TextEditor.tsx"],"sourcesContent":["'use client';\n\nimport { Accordion } from '@components/Accordion';\nimport {\n Button,\n ButtonColor,\n ButtonSize,\n ButtonTextAlign,\n ButtonVariant,\n} from '@components/Button';\nimport { Container } from '@components/Container';\nimport {\n ContentEditorInput as ContentEditorInputBase,\n type ContentEditorInputProps as ContentEditorInputPropsBase,\n} from '@components/ContentEditor/ContentEditorInput';\nimport {\n ContentEditorTextArea as ContentEditorTextAreaBase,\n type ContentEditorTextAreaProps as ContentEditorTextAreaPropsBase,\n} from '@components/ContentEditor/ContentEditorTextArea';\nimport { renameKey } from '@components/DictionaryFieldEditor/ContentEditorView/object';\nimport { InputVariant } from '@components/Input';\nimport { Label } from '@components/Label';\nimport { Loader } from '@components/Loader';\nimport { useLocaleSwitcherContent } from '@components/LocaleSwitcherContentDropDown';\nimport {\n SwitchSelector,\n type SwitchSelectorChoices,\n SwitchSelectorColor,\n type SwitchSelectorProps,\n SwitchSelectorSize,\n} from '@components/SwitchSelector';\nimport { useAuditContentDeclarationField } from '@hooks/reactQuery';\nimport { camelCaseToSentence } from '@intlayer/config/client';\nimport {\n getEmptyNode,\n getNodeType,\n} from '@intlayer/core/dictionaryManipulator';\nimport { getLocaleName } from '@intlayer/core/localization';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n GenderContent,\n HTMLContent,\n InsertionContent,\n MarkdownContent,\n PluralContent,\n TranslationContent,\n} from '@intlayer/core/transpiler';\nimport { useConfiguration, useEditedContent } from '@intlayer/editor-react';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { ContentNode, Dictionary } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { Plus, Trash, WandSparkles } from 'lucide-react';\nimport {\n type FC,\n Fragment,\n lazy,\n memo,\n type ReactNode,\n Suspense,\n useState,\n} from 'react';\nimport { useIntlayer, useLocale } from 'react-intlayer';\nimport { EnumKeyInput } from '../EnumKeyInput';\nimport { SafeHtmlRenderer } from './SafeHtmlRenderer';\n\nconst LazyMarkdownRenderer = lazy(() =>\n import('@components/MarkDownRender').then((m) => ({\n default: m.MarkdownRenderer,\n }))\n);\n\n// Renders children only after the accordion is first opened (mount-once pattern).\n// Prevents deeply nested sub-trees from mounting on initial render.\ntype CollapsibleEditorProps = TextEditorProps & { label: string };\nconst CollapsibleEditor = memo<CollapsibleEditorProps>(\n function CollapsibleEditor({ label, ...editorProps }) {\n const [hasOpened, setHasOpened] = useState(false);\n return (\n <Accordion\n header={label}\n label={label}\n onToggle={(isOpen) => {\n if (isOpen && !hasOpened) setHasOpened(true);\n }}\n >\n {hasOpened ? <TextEditor {...editorProps} /> : null}\n </Accordion>\n );\n }\n);\n\nexport const traceKeys: string[] = ['filePath', 'id', 'nodeType'];\n\ntype ContentEditorTextAreaProps = Omit<\n ContentEditorTextAreaPropsBase,\n 'onContentChange'\n> & {\n keyPath: KeyPath[];\n dictionary: Dictionary;\n};\n\nconst ContentEditorTextArea: FC<ContentEditorTextAreaProps> = ({\n keyPath,\n dictionary,\n ...props\n}) => {\n const { editedContent, addEditedContent } = useEditedContent();\n const configuration = useConfiguration();\n const { mutate: auditContentDeclarationField, isPending: isAuditing } =\n useAuditContentDeclarationField();\n\n return (\n <ContentEditorTextAreaBase\n variant={InputVariant.DEFAULT}\n onContentChange={(newValue) =>\n addEditedContent(dictionary.localId!, newValue, keyPath)\n }\n additionalButtons={\n <Button\n Icon={WandSparkles}\n label=\"Audit\"\n variant={ButtonVariant.HOVERABLE}\n size={ButtonSize.ICON_SM}\n color={ButtonColor.TEXT}\n className=\"cursor-pointer hover:scale-110\"\n isLoading={isAuditing}\n onClick={() => {\n auditContentDeclarationField(\n {\n fileContent: JSON.stringify({\n ...dictionary,\n ...(editedContent?.[dictionary.localId!] ?? {}),\n }),\n keyPath,\n locales: configuration?.internationalization.locales ?? [],\n aiOptions: {\n apiKey: configuration?.ai?.apiKey,\n model: configuration?.ai?.model,\n temperature: configuration?.ai?.temperature,\n },\n },\n {\n onSuccess: (response) => {\n if (!response?.data) return;\n\n try {\n const editedContent = response.data.fileContent as string;\n\n addEditedContent(\n dictionary.localId!,\n editedContent,\n keyPath\n );\n } catch (error) {\n console.error(error);\n }\n },\n }\n );\n }}\n />\n }\n {...props}\n />\n );\n};\n\ntype ContentEditorInputProps = Omit<\n ContentEditorInputPropsBase,\n 'onContentChange'\n> & {\n keyPath: KeyPath[];\n dictionary: Dictionary;\n};\n\nconst ContentEditorInput: FC<ContentEditorInputProps> = ({\n keyPath,\n dictionary,\n ...props\n}) => {\n const { addEditedContent } = useEditedContent();\n\n return (\n <ContentEditorInputBase\n variant={InputVariant.DEFAULT}\n onContentChange={(newValue) =>\n addEditedContent(dictionary.localId!, newValue, keyPath)\n }\n {...props}\n />\n );\n};\n\nconst toggleContent = [\n {\n content: 'False',\n value: false,\n },\n {\n content: 'True',\n value: true,\n },\n] as SwitchSelectorChoices<boolean>;\n\ntype ContentEditorToggleProps = SwitchSelectorProps & {\n dictionary: Dictionary;\n keyPath: KeyPath[];\n};\n\nconst ContentEditorToggle: FC<ContentEditorToggleProps> = ({\n dictionary,\n keyPath,\n ...props\n}) => {\n const { addEditedContent } = useEditedContent();\n\n return (\n <SwitchSelector\n choices={toggleContent}\n value={true}\n onChange={(value) =>\n addEditedContent(dictionary.localId!, value, keyPath)\n }\n color={SwitchSelectorColor.TEXT}\n size={SwitchSelectorSize.SM}\n {...props}\n />\n );\n};\n\nexport type TextEditorProps = {\n dictionary: Dictionary;\n keyPath: KeyPath[];\n section: ContentNode;\n isDarkMode?: boolean;\n renderSection?: (content: string) => ReactNode;\n onContentChange?: (newValue: string) => void;\n};\n\nconst TranslationTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}: TextEditorProps) => {\n const { locale, defaultLocale } = useLocale();\n const { selectedLocales } = useLocaleSwitcherContent();\n\n const content: any = (section as TranslationContent<string>)[\n NodeTypes.TRANSLATION\n ];\n\n return (\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {selectedLocales.map((translationKey) => {\n const uniqueKey = `${JSON.stringify(keyPath)}-translation-${translationKey}`;\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 w-full p-2 text-xs\">\n <td className=\"flex w-full\">\n {getLocaleName(translationKey, locale)}\n </td>\n </tr>\n <tr className=\"flex\">\n <td className=\"flex w-full\">\n <TextEditorContainer\n section={\n content[translationKey] ??\n getEmptyNode(content[defaultLocale])\n }\n keyPath={[\n ...keyPath,\n { type: NodeTypes.TRANSLATION, key: translationKey },\n ]}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nconst EnumerationTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const { addEditedContent } = useEditedContent();\n const { addNewEnumeration, removeEnumeration } =\n useIntlayer('navigation-view');\n\n const content = (section as EnumerationContent<string>)[\n NodeTypes.ENUMERATION\n ];\n const firstKey = Object.keys(content)[0] as keyof typeof content;\n\n return (\n <div className=\"flex flex-col gap-2\">\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {Object.keys(\n (section as EnumerationContent<ContentNode>)[NodeTypes.ENUMERATION]\n ).map((enumKey) => {\n const childrenKeyPath = [\n ...keyPath,\n { type: NodeTypes.ENUMERATION, key: enumKey },\n ] as KeyPath[];\n const uniqueKey = `${JSON.stringify(keyPath)}-enumeration-${enumKey}`;\n\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 w-full\">\n <td className=\"flex w-full\">\n <div className=\"flex flex-1\">\n <Button\n label={removeEnumeration.label.value}\n variant=\"hoverable\"\n size=\"sm\"\n color=\"error\"\n className=\"ml-auto text-neutral hover:text-error\"\n Icon={Trash}\n onClick={() =>\n addEditedContent(\n dictionary.localId!,\n undefined,\n childrenKeyPath\n )\n }\n >\n {removeEnumeration.text}\n </Button>\n </div>\n </td>\n </tr>\n <tr className=\"w-full p-2\">\n <td className=\"flex w-full\">\n <EnumKeyInput\n value={enumKey}\n onChange={(value) => {\n const preValueContent = (\n section as EnumerationContent<string>\n )[NodeTypes.ENUMERATION];\n\n const newValueContent = renameKey(\n preValueContent,\n enumKey as keyof typeof preValueContent,\n value\n );\n const newValue = {\n ...(section as EnumerationContent<string>),\n [NodeTypes.ENUMERATION]: newValueContent,\n };\n\n console.log('newValue', newValue);\n\n addEditedContent(\n dictionary.localId!,\n newValue,\n keyPath\n );\n }}\n />\n </td>\n </tr>\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditor\n section={\n content[enumKey as keyof typeof content] ??\n getEmptyNode(content[firstKey])\n }\n keyPath={childrenKeyPath}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n\n <Button\n label={addNewEnumeration.label.value}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.NEUTRAL}\n textAlign={ButtonTextAlign.LEFT}\n isFullWidth\n onClick={() =>\n addEditedContent(\n dictionary.localId!,\n getEmptyNode(content[firstKey]) ?? '',\n [...keyPath, { type: NodeTypes.ENUMERATION, key: 'unknown' }]\n )\n }\n Icon={Plus}\n className=\"m-2\"\n >\n {addNewEnumeration.text}\n </Button>\n </div>\n );\n};\n\nconst ConditionTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const content = (section as ConditionContent<string>)[NodeTypes.CONDITION];\n\n return (\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {['true', 'false', 'fallback'].map((condKey) => {\n const uniqueKey = `${JSON.stringify(keyPath)}-condition-${condKey}`;\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 block w-full p-2 text-xs\">\n <td className=\"flex w-full\">{String(condKey)}</td>\n </tr>\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditorContainer\n section={\n content[condKey as keyof typeof content] ??\n getEmptyNode(content.true)\n }\n keyPath={[\n ...keyPath,\n {\n type: NodeTypes.CONDITION,\n key: condKey,\n } as KeyPath,\n ]}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nconst GenderTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const content = (section as GenderContent<string>)[NodeTypes.GENDER];\n\n return (\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {['male', 'female', 'fallback'].map((condKey) => {\n const uniqueKey = `${JSON.stringify(keyPath)}-gender-${condKey}`;\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 block w-full p-2 text-xs\">\n <td className=\"flex w-full\">{String(condKey)}</td>\n </tr>\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditorContainer\n section={\n content[condKey as keyof typeof content] ??\n getEmptyNode(content.male)\n }\n keyPath={[\n ...keyPath,\n {\n type: NodeTypes.GENDER,\n key: condKey,\n } as KeyPath,\n ]}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nconst PLURAL_CATEGORIES = ['zero', 'one', 'two', 'few', 'many', 'other'];\n\nconst PluralTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const content = (section as PluralContent<string>)[NodeTypes.PLURAL];\n\n return (\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {PLURAL_CATEGORIES.map((pluralKey) => {\n const uniqueKey = `${JSON.stringify(keyPath)}-plural-${pluralKey}`;\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 block w-full p-2 text-xs\">\n <td className=\"flex w-full\">{pluralKey}</td>\n </tr>\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditorContainer\n section={\n content[pluralKey as keyof typeof content] ??\n getEmptyNode(content.other)\n }\n keyPath={[\n ...keyPath,\n {\n type: NodeTypes.PLURAL,\n key: pluralKey,\n } as KeyPath,\n ]}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nconst ArrayTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const { addEditedContent } = useEditedContent();\n const { addNewElement, removeElement } = useIntlayer('navigation-view');\n\n return (\n <div className=\"flex flex-col gap-2\">\n <table className=\"w-full\">\n <tbody className=\"flex w-full flex-col gap-2\">\n {(section as unknown as ContentNode[]).map((subSection, index) => {\n const uniqueKey = `${JSON.stringify(keyPath)}-array-${index}`;\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 w-full p-2\">\n <td className=\"flex w-full\">\n <div className=\"flex w-full items-center justify-between gap-2\">\n <span className=\"text-xs\">{String(index)}</span>\n <Button\n label={removeElement.label.value}\n variant=\"hoverable\"\n size=\"sm\"\n color=\"error\"\n className=\"ml-auto text-neutral hover:text-error\"\n onClick={() => {\n const newKeyPath: KeyPath[] = [\n ...keyPath,\n {\n type: NodeTypes.ARRAY,\n key: index, // Fixed: Use index instead of length\n },\n ];\n addEditedContent(\n dictionary.localId!,\n undefined,\n newKeyPath\n );\n }}\n Icon={Trash}\n >\n {removeElement.text}\n </Button>\n </div>\n </td>\n </tr>\n\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditorContainer\n section={\n subSection ??\n getEmptyNode((section as unknown as ContentNode[])[0])\n }\n keyPath={[\n ...keyPath,\n {\n type: NodeTypes.ARRAY,\n key: index,\n },\n ]}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n })}\n </tbody>\n </table>\n <Button\n label={addNewElement.label.value}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.NEUTRAL}\n textAlign={ButtonTextAlign.LEFT}\n isFullWidth\n onClick={() => {\n const newKeyPath: KeyPath[] = [\n ...keyPath,\n {\n type: NodeTypes.ARRAY,\n key: (section as unknown as ContentNode[]).length, // Keeps length for adding new items\n },\n ];\n addEditedContent(\n dictionary.localId!,\n getEmptyNode((section as unknown as ContentNode[])[0]) ?? '',\n newKeyPath,\n false\n );\n }}\n Icon={Plus}\n >\n {addNewElement.text}\n </Button>\n </div>\n );\n};\n\nconst ObjectTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n renderSection,\n}) => {\n const typedSection = section as unknown as Record<string, ContentNode>;\n const firstKey = Object.keys(typedSection)[0] as keyof typeof section;\n\n return (\n <table className=\"w-full\">\n <tbody className=\"flex flex-col gap-2\">\n {Object.keys(typedSection).map((key) => {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: NodeTypes.OBJECT, key },\n ];\n const subSection =\n typedSection[key as keyof typeof section] ??\n getEmptyNode(typedSection[firstKey]);\n const uniqueKey = `${JSON.stringify(keyPath)}-object-${key}`;\n // Collapse any object/array (typed or plain) — only true primitives render inline.\n // getIsEditableSection can't be used here: it inspects getNodeChildren(), which for\n // translation nodes returns the first locale value (a string), causing translation\n // subtrees to be mistakenly treated as leaves and mounted all at once.\n const isLeaf = subSection === null || typeof subSection !== 'object';\n\n if (isLeaf) {\n return (\n <Fragment key={uniqueKey}>\n <tr className=\"mt-2 p-2 text-xs\">\n <td className=\"flex w-full\">{String(key)}</td>\n </tr>\n <tr className=\"block w-full\">\n <td className=\"flex w-full\">\n <TextEditor\n section={subSection}\n keyPath={childKeyPath}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n </Fragment>\n );\n }\n\n return (\n <tr\n key={uniqueKey}\n className=\"block w-full border-neutral/10 border-t py-1\"\n >\n <td className=\"flex w-full\">\n <CollapsibleEditor\n label={camelCaseToSentence(key)}\n section={subSection}\n keyPath={childKeyPath}\n dictionary={dictionary}\n renderSection={renderSection}\n />\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n );\n};\n\nenum MarkdownViewMode {\n Edit,\n Preview,\n}\n\nenum HtmlViewMode {\n Edit,\n Preview,\n}\n\nconst HtmlTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n}) => {\n const [mode, setMode] = useState(HtmlViewMode.Edit);\n const toggleContent = [\n {\n content: 'Edit',\n value: HtmlViewMode.Edit,\n },\n {\n content: 'Preview',\n value: HtmlViewMode.Preview,\n },\n ] as SwitchSelectorChoices<HtmlViewMode>;\n const childKeyPath: KeyPath[] = [...keyPath, { type: NodeTypes.HTML }];\n\n const content = (section as HTMLContent<ContentNode>)[\n NodeTypes.HTML\n ] as ContentNode;\n\n return (\n <div className=\"flex w-full flex-col justify-center gap-6 p-2\">\n <SwitchSelector\n choices={toggleContent}\n value={mode}\n onChange={setMode}\n color={SwitchSelectorColor.TEXT}\n size={SwitchSelectorSize.SM}\n className=\"ml-auto\"\n />\n\n <TextEditorContainer\n section={content}\n keyPath={childKeyPath}\n dictionary={dictionary}\n renderSection={\n mode === HtmlViewMode.Preview\n ? (rawContent) => <SafeHtmlRenderer rawContent={rawContent} />\n : undefined\n }\n />\n </div>\n );\n};\n\nconst MarkdownTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n dictionary,\n isDarkMode,\n}) => {\n const [mode, setMode] = useState(MarkdownViewMode.Edit);\n const toggleContent = [\n {\n content: 'Edit',\n value: MarkdownViewMode.Edit,\n },\n {\n content: 'Preview',\n value: MarkdownViewMode.Preview,\n },\n ] as SwitchSelectorChoices<MarkdownViewMode>;\n const childKeyPath: KeyPath[] = [...keyPath, { type: NodeTypes.MARKDOWN }];\n\n const content = ((section as MarkdownContent<ContentNode>)[\n NodeTypes.MARKDOWN\n ] ?? '') as ContentNode;\n\n return (\n <div className=\"flex w-full flex-col justify-center gap-6 p-2\">\n <SwitchSelector\n choices={toggleContent}\n value={mode}\n onChange={setMode}\n color={SwitchSelectorColor.TEXT}\n size={SwitchSelectorSize.SM}\n className=\"ml-auto\"\n />\n\n <TextEditorContainer\n section={content}\n keyPath={childKeyPath}\n dictionary={dictionary}\n renderSection={\n mode === MarkdownViewMode.Preview\n ? (content) => (\n <Suspense fallback={<Loader />}>\n <LazyMarkdownRenderer isDarkMode={isDarkMode}>\n {content}\n </LazyMarkdownRenderer>\n </Suspense>\n )\n : undefined\n }\n />\n </div>\n );\n};\n\nconst InsertionTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n ...props\n}) => {\n const childKeyPath: KeyPath[] = [...keyPath, { type: NodeTypes.INSERTION }];\n\n const content = (section as InsertionContent<ContentNode>)[\n NodeTypes.INSERTION\n ];\n\n return (\n <div className=\"flex w-full flex-col justify-center gap-6 p-2\">\n <TextEditorContainer\n section={content}\n keyPath={childKeyPath}\n {...props}\n />\n </div>\n );\n};\n\nconst FileTextEditor: FC<TextEditorProps> = ({\n section,\n keyPath,\n ...props\n}) => {\n const childKeyPath: KeyPath[] = [...keyPath, { type: NodeTypes.FILE }];\n\n const fileUrl = (section as FileContent)[NodeTypes.FILE];\n const { content } = section as FileContent;\n\n return (\n <div className=\"flex w-full flex-col justify-center gap-6 p-2\">\n <span className=\"text-neutral text-sm\">{fileUrl} </span>\n <TextEditorContainer\n section={content}\n keyPath={childKeyPath}\n {...props}\n />\n </div>\n );\n};\n\nconst NestedTextEditor: FC<TextEditorProps> = ({\n keyPath,\n dictionary,\n renderSection,\n section,\n ...props\n}) => {\n const { addEditedContent } = useEditedContent();\n\n const content = (section as any)[NodeTypes.NESTED];\n const childrenKeyPath = [...keyPath, { type: NodeTypes.NESTED }] as KeyPath[];\n\n return (\n <div className=\"flex w-full flex-col gap-4 p-2\">\n <Label>Dictionary key</Label>\n <ContentEditorInputBase\n aria-label=\"Edit field\"\n type=\"text\"\n variant={InputVariant.DEFAULT}\n {...props}\n onContentChange={(newValue) => {\n addEditedContent(\n dictionary.localId!,\n {\n ...content,\n dictionaryKey: String(newValue),\n },\n childrenKeyPath\n );\n }}\n >\n {content.dictionaryKey ?? ''}\n </ContentEditorInputBase>\n\n <Label>Path (optional)</Label>\n <ContentEditorInputBase\n aria-label=\"Edit field\"\n type=\"text\"\n variant={InputVariant.DEFAULT}\n {...props}\n onContentChange={(newValue) => {\n addEditedContent(\n dictionary.localId!,\n {\n ...content,\n path: newValue !== '' ? newValue : undefined,\n },\n childrenKeyPath\n );\n }}\n >\n {content.path ?? ''}\n </ContentEditorInputBase>\n </div>\n );\n};\n\nexport const TextEditor = memo<TextEditorProps>(function TextEditor({\n section,\n keyPath,\n dictionary,\n renderSection,\n isDarkMode,\n}) {\n const { tsxNotEditable } = useIntlayer('navigation-view');\n const nodeType = getNodeType(section);\n\n if (nodeType === NodeTypes.REACT_NODE) {\n return (\n <div className=\"flex w-full flex-col gap-2\">\n <span>(React Node)</span>\n <span className=\"flex text-neutral text-xs\">{tsxNotEditable}</span>\n </div>\n );\n }\n\n if (nodeType === NodeTypes.NESTED) {\n return (\n <NestedTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return (\n <TranslationTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.ENUMERATION) {\n return (\n <EnumerationTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.CONDITION) {\n return (\n <ConditionTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.GENDER) {\n return (\n <GenderTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.PLURAL) {\n return (\n <PluralTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.INSERTION) {\n return (\n <InsertionTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.MARKDOWN) {\n return (\n <MarkdownTextEditor\n dictionary={dictionary}\n keyPath={keyPath}\n section={section}\n isDarkMode={isDarkMode}\n />\n );\n }\n\n if (nodeType === NodeTypes.HTML) {\n return (\n <HtmlTextEditor\n dictionary={dictionary}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.FILE) {\n return (\n <FileTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.ARRAY) {\n return (\n <ArrayTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.OBJECT) {\n return (\n <ObjectTextEditor\n dictionary={dictionary}\n renderSection={renderSection}\n keyPath={keyPath}\n section={section}\n />\n );\n }\n\n if (nodeType === NodeTypes.NUMBER) {\n return (\n <div className=\"w-full p-2\">\n <ContentEditorInput\n dictionary={dictionary}\n keyPath={keyPath}\n type=\"number\"\n aria-label=\"Edit field\"\n >\n {section as number}\n </ContentEditorInput>\n </div>\n );\n }\n\n if (nodeType === NodeTypes.TEXT) {\n return (\n <div className=\"w-full p-2\">\n {typeof renderSection === 'function' ? (\n renderSection(section as string)\n ) : (\n <ContentEditorTextArea\n variant={InputVariant.DEFAULT}\n aria-label=\"Edit field\"\n keyPath={keyPath}\n dictionary={dictionary}\n >\n {section as string}\n </ContentEditorTextArea>\n )}\n </div>\n );\n }\n\n if (nodeType === NodeTypes.BOOLEAN) {\n return (\n <div className=\"w-full p-2\">\n <ContentEditorToggle\n dictionary={dictionary}\n keyPath={keyPath}\n value={section as boolean}\n />\n </div>\n );\n }\n\n return (\n <div className=\"w-full p-2\">\n Error. Format not supported.\n {JSON.stringify(section, null, 2)}\n {JSON.stringify(keyPath, null, 2)}\n NodeType : {nodeType}\n </div>\n );\n});\n\nexport const TextEditorContainer = memo<TextEditorProps>(\n function TextEditorContainer(props) {\n return (\n <Container\n border\n background=\"none\"\n className=\"top-6 flex h-full flex-1 flex-col gap-6 overflow-hidden p-2 md:sticky\"\n roundedSize=\"2xl\"\n >\n <TextEditor {...props} />\n </Container>\n );\n }\n);\n"],"mappings":"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"}
@@ -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";
@@ -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 { useWatch } from "react-hook-form";
19
19
  import { AnimatePresence, motion } from "framer-motion";
20
20
 
@@ -13,8 +13,8 @@ import { StructureEditor } from "./StructureEditor.mjs";
13
13
  import { useEffect, useState } from "react";
14
14
  import { ArrowLeft } from "lucide-react";
15
15
  import { jsx, jsxs } from "react/jsx-runtime";
16
- import { useConfiguration, useDictionariesRecordActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
17
16
  import { useIntlayer } from "react-intlayer";
17
+ import { useConfiguration, useDictionariesRecordActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
18
18
 
19
19
  //#region src/components/DictionaryFieldEditor/DictionaryFieldEditor.tsx
20
20
  const DictionaryFieldEditor = ({ dictionary, onClickDictionaryList, isDarkMode, mode, onDelete, onSave, showReturnButton = true }) => {
@@ -5,8 +5,8 @@ import { getIsEditableSection } from "../getIsEditableSection.mjs";
5
5
  import { useState } from "react";
6
6
  import { ChevronRight, Plus } from "lucide-react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
- import { useEditedContentActions, useEditorLocale, useFocusUnmergedDictionary } from "@intlayer/editor-react";
9
8
  import { useIntlayer } from "react-intlayer";
9
+ import { useEditedContentActions, useEditorLocale, useFocusUnmergedDictionary } from "@intlayer/editor-react";
10
10
  import { getContentNodeByKeyPath, getEmptyNode, getNodeType } from "@intlayer/core/dictionaryManipulator";
11
11
  import * as NodeTypes from "@intlayer/types/nodeType";
12
12
  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 { Form } from "../../Form/Form.mjs";
8
8
  import { Modal, ModalSize } from "../../Modal/Modal.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";
@@ -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,11 +1,11 @@
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 { DropDown } from "../DropDown/index.mjs";
7
6
  import { Input } from "../Input/Input.mjs";
8
7
  import { SwitchSelector, SwitchSelectorColor, SwitchSelectorSize } from "../SwitchSelector/SwitchSelector.mjs";
8
+ import { usePersistedStore } from "../../hooks/usePersistedStore.mjs";
9
9
  import { useLocaleSwitcherContent } from "./LocaleSwitcherContentContext.mjs";
10
10
  import { useMemo, useRef, useState } from "react";
11
11
  import { Check, Globe, MoveVertical } from "lucide-react";
@@ -1,10 +1,10 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../utils/cn.mjs";
4
- import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
5
- import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
6
4
  import { Container } from "../Container/index.mjs";
7
5
  import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
6
+ import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
7
+ import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
8
8
  import { H3 } from "../Headers/index.mjs";
9
9
  import { useEffect } from "react";
10
10
  import { cva } from "class-variance-authority";
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../utils/cn.mjs";
4
+ import { MaxHeightSmoother } from "../MaxHeightSmoother/index.mjs";
4
5
  import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
5
6
  import { useScrollDetection } from "../../hooks/useScrollDetection.mjs";
6
- import { MaxHeightSmoother } from "../MaxHeightSmoother/index.mjs";
7
7
  import { Burger } from "./Burger.mjs";
8
8
  import { useRef, useState } from "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../utils/cn.mjs";
4
- import { useItemSelector } from "../../hooks/useItemSelector.mjs";
5
4
  import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
5
+ import { useItemSelector } from "../../hooks/useItemSelector.mjs";
6
6
  import { useEffect, useRef } from "react";
7
7
  import { cva } from "class-variance-authority";
8
8
  import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
@@ -1,12 +1,12 @@
1
1
  'use client';
2
2
 
3
- import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
4
- import { useDevice } from "../../hooks/useDevice.mjs";
5
- import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
6
3
  import { Container } from "../Container/index.mjs";
7
4
  import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
5
+ import { useDevice } from "../../hooks/useDevice.mjs";
8
6
  import { KeyboardShortcut } from "../KeyboardShortcut/KeyboardShortcut.mjs";
9
7
  import { Popover } from "../Popover/dynamic.mjs";
8
+ import { useGetElementOrWindow } from "../../hooks/useGetElementOrWindow.mjs";
9
+ import { useScrollBlockage } from "../../hooks/useScrollBlockage/index.mjs";
10
10
  import { MaxWidthSmoother } from "../MaxWidthSmoother/index.mjs";
11
11
  import { isElementAtTopAndNotCovered } from "./isElementAtTopAndNotCovered.mjs";
12
12
  import { useRightDrawer } from "./useRightDrawer.mjs";
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../utils/cn.mjs";
4
- import { useHorizontalSwipe } from "../../hooks/useHorizontalSwipe.mjs";
5
4
  import { TabSelector, TabSelectorColor } from "../TabSelector/TabSelector.mjs";
5
+ import { useHorizontalSwipe } from "../../hooks/useHorizontalSwipe.mjs";
6
6
  import { useTabContext } from "./TabContext.mjs";
7
7
  import { Children, createContext, isValidElement, useState } from "react";
8
8
  import { cva } from "class-variance-authority";
@@ -1,22 +1,22 @@
1
- import { useKeyboardDetector } from "./useKeyboardDetector.mjs";
2
- import { useGetElementOrWindow } from "./useGetElementOrWindow.mjs";
3
- import { useScrollY } from "./useScrollY.mjs";
4
- import { usePersistedStore } from "./usePersistedStore.mjs";
5
- import { useHorizontalSwipe } from "./useHorizontalSwipe.mjs";
6
- import { useItemSelector } from "./useItemSelector.mjs";
7
1
  import { calculateIsMobile, checkIsIOS, checkIsIphoneOrSafariDevice, checkIsMac, checkIsMobileScreen, checkIsMobileUserAgent, getBreakpointFromSize, useDevice } from "./useDevice.mjs";
2
+ import { useItemSelector } from "./useItemSelector.mjs";
3
+ import { usePersistedStore } from "./usePersistedStore.mjs";
8
4
  import { useOAuth2 } from "./useAuth/useOAuth2.mjs";
9
5
  import { useSession } from "./useAuth/useSession.mjs";
10
6
  import { useAuth } from "./useAuth/useAuth.mjs";
11
7
  import { useIntlayerAuth, useIntlayerOAuth } from "./useIntlayerAPI.mjs";
12
8
  import { useAddDictionary, useAddNewAccessKey, useAddOrganization, useAddOrganizationMember, useAddPasskey, useAddProject, useAddTag, useAppQuery, useAskDocQuestion, useAskResetPassword, useAuditContentDeclaration, useAuditContentDeclarationField, useAuditContentDeclarationMetadata, useAuditScan, useAuditTag, useAutocomplete, useBitbucketAuth, useBitbucketCheckConfig, useBitbucketGetConfigFile, useBitbucketRepos, useCancelSubscription, useChangePassword, useChat, useCreatePortalSession, useCreateUser, useDeleteAccessKey, useDeleteDictionary, useDeleteOrganization, useDeleteOrganizationById, useDeletePasskey, useDeleteProject, useDeleteProjectById, useDeleteSSOProvider, useDeleteShowcaseProject, useDeleteTag, useDeleteUser, useDisableTwoFactor, useEnableTwoFactor, useFillAllTranslations, useGetCIConfig, useGetDictionaries, useGetDictionariesKeys, useGetDictionary, useGetDiscussions, useGetDiscussionsData, useGetEditorDictionaries, useGetInvoices, useGetNewsletterStatus, useGetOrganizations, useGetOtherShowcaseProjects, useGetPaymentMethod, useGetPricing, useGetProjects, useGetRecursiveAuditStatus, useGetShowcaseProjectById, useGetShowcaseProjects, useGetSubscription, useGetTags, useGetUserByAccount, useGetUserById, useGetUsers, useGetVerifyEmailStatus, useGithubAuth, useGithubCheckConfig, useGithubGetAuthUrl, useGithubGetConfigFile, useGithubRepos, useGithubToken, useGitlabAuth, useGitlabCheckConfig, useGitlabGetConfigFile, useGitlabProjects, useInfiniteGetDictionaries, useLinkSocial, useListAccounts, useListPasskeys, useListSSOProviders, useLogin, useLogout, usePauseTranslationJob, usePushCIConfig, usePushDictionaries, usePushProjectConfiguration, useQueryClient, useRefreshAccessKey, useRegister, useRegisterSSO, useResetPassword, useResumeTranslationJob, useSearchDoc, useSelectOrganization, useSelectProject, useSignInMagicLink, useSignInPasskey, useSignInSSO, useStartRecursiveAudit, useStopTranslationJob, useSubmitShowcaseProject, useSubscribeToNewsletter, useToggleShowcaseDownvote, useToggleShowcaseUpvote, useTranslateJSONDeclaration, useTriggerBuild, useTriggerWebhook, useUnlinkAccount, useUnselectOrganization, useUnselectProject, useUnsubscribeFromNewsletter, useUpdateDictionary, useUpdateOrganization, useUpdateOrganizationMembers, useUpdateOrganizationMembersById, useUpdateProject, useUpdateProjectMembers, useUpdateShowcaseProject, useUpdateTag, useUpdateUser, useUploadUserAvatar, useVerifyBackupCode, useVerifyEmail, useVerifyTotp, useWriteDictionary } from "./reactQuery.mjs";
13
- import { useSearch } from "./useSearch.mjs";
14
- import { useIsMounted } from "./useIsMounted.mjs";
9
+ import { useUser } from "./useUser/index.mjs";
15
10
  import { useGetElementById } from "./useGetElementById.mjs";
11
+ import { useGetElementOrWindow } from "./useGetElementOrWindow.mjs";
12
+ import { useHorizontalSwipe } from "./useHorizontalSwipe.mjs";
16
13
  import { useIsDarkMode } from "./useIsDarkMode.mjs";
14
+ import { useIsMounted } from "./useIsMounted.mjs";
15
+ import { useKeyboardDetector } from "./useKeyboardDetector.mjs";
17
16
  import { useScreenWidth } from "./useScreenWidth.mjs";
18
17
  import { useScrollBlockage } from "./useScrollBlockage/index.mjs";
19
18
  import { useScrollDetection } from "./useScrollDetection.mjs";
20
- import { useUser } from "./useUser/index.mjs";
19
+ import { useScrollY } from "./useScrollY.mjs";
20
+ import { useSearch } from "./useSearch.mjs";
21
21
 
22
22
  export { calculateIsMobile, checkIsIOS, checkIsIphoneOrSafariDevice, checkIsMac, checkIsMobileScreen, checkIsMobileUserAgent, getBreakpointFromSize, useAddDictionary, useAddNewAccessKey, useAddOrganization, useAddOrganizationMember, useAddPasskey, useAddProject, useAddTag, useAppQuery, useAskDocQuestion, useAskResetPassword, useAuditContentDeclaration, useAuditContentDeclarationField, useAuditContentDeclarationMetadata, useAuditScan, useAuditTag, useAuth, useAutocomplete, useBitbucketAuth, useBitbucketCheckConfig, useBitbucketGetConfigFile, useBitbucketRepos, useCancelSubscription, useChangePassword, useChat, useCreatePortalSession, useCreateUser, useDeleteAccessKey, useDeleteDictionary, useDeleteOrganization, useDeleteOrganizationById, useDeletePasskey, useDeleteProject, useDeleteProjectById, useDeleteSSOProvider, useDeleteShowcaseProject, useDeleteTag, useDeleteUser, useDevice, useDisableTwoFactor, useEnableTwoFactor, useFillAllTranslations, useGetCIConfig, useGetDictionaries, useGetDictionariesKeys, useGetDictionary, useGetDiscussions, useGetDiscussionsData, useGetEditorDictionaries, useGetElementById, useGetElementOrWindow, useGetInvoices, useGetNewsletterStatus, useGetOrganizations, useGetOtherShowcaseProjects, useGetPaymentMethod, useGetPricing, useGetProjects, useGetRecursiveAuditStatus, useGetShowcaseProjectById, useGetShowcaseProjects, useGetSubscription, useGetTags, useGetUserByAccount, useGetUserById, useGetUsers, useGetVerifyEmailStatus, useGithubAuth, useGithubCheckConfig, useGithubGetAuthUrl, useGithubGetConfigFile, useGithubRepos, useGithubToken, useGitlabAuth, useGitlabCheckConfig, useGitlabGetConfigFile, useGitlabProjects, useHorizontalSwipe, useInfiniteGetDictionaries, useIntlayerAuth, useIntlayerOAuth, useIsDarkMode, useIsMounted, useItemSelector, useKeyboardDetector, useLinkSocial, useListAccounts, useListPasskeys, useListSSOProviders, useLogin, useLogout, useOAuth2, usePauseTranslationJob, usePersistedStore, usePushCIConfig, usePushDictionaries, usePushProjectConfiguration, useQueryClient, useRefreshAccessKey, useRegister, useRegisterSSO, useResetPassword, useResumeTranslationJob, useScreenWidth, useScrollBlockage, useScrollDetection, useScrollY, useSearch, useSearchDoc, useSelectOrganization, useSelectProject, useSession, useSignInMagicLink, useSignInPasskey, useSignInSSO, useStartRecursiveAudit, useStopTranslationJob, useSubmitShowcaseProject, useSubscribeToNewsletter, useToggleShowcaseDownvote, useToggleShowcaseUpvote, useTranslateJSONDeclaration, useTriggerBuild, useTriggerWebhook, useUnlinkAccount, useUnselectOrganization, useUnselectProject, useUnsubscribeFromNewsletter, useUpdateDictionary, useUpdateOrganization, useUpdateOrganizationMembers, useUpdateOrganizationMembersById, useUpdateProject, useUpdateProjectMembers, useUpdateShowcaseProject, useUpdateTag, useUpdateUser, useUploadUserAvatar, useUser, useVerifyBackupCode, useVerifyEmail, useVerifyTotp, useWriteDictionary };
@@ -42,7 +42,7 @@ declare enum BadgeSize {
42
42
  * @description Defines the styling variants for different badge combinations
43
43
  */
44
44
  declare const badgeVariants: (props?: {
45
- color?: "text" | "primary" | "secondary" | "destructive" | "neutral" | "light" | "dark" | "error" | "custom" | "success";
45
+ color?: "text" | "error" | "custom" | "primary" | "secondary" | "destructive" | "neutral" | "light" | "dark" | "success";
46
46
  variant?: "none" | "default" | "outline" | "hoverable";
47
47
  size?: "sm" | "md" | "lg";
48
48
  } & import("class-variance-authority/types").ClassProp) => string;
@@ -61,9 +61,9 @@ declare enum ButtonTextAlign {
61
61
  */
62
62
  declare const buttonVariants: (props?: {
63
63
  size?: "xs" | "sm" | "md" | "lg" | "xl" | "icon-sm" | "icon-md" | "icon-lg" | "icon-xl";
64
- color?: "text" | "primary" | "secondary" | "destructive" | "neutral" | "light" | "dark" | "error" | "custom" | "card" | "current" | "text-inverse" | "success";
64
+ color?: "text" | "error" | "custom" | "primary" | "secondary" | "destructive" | "neutral" | "card" | "light" | "dark" | "current" | "text-inverse" | "success";
65
65
  roundedSize?: "sm" | "md" | "lg" | "xl" | "2xl" | "none" | "3xl" | "4xl" | "5xl" | "full";
66
- variant?: "input" | "none" | "default" | "outline" | "link" | "invisible-link" | "hoverable" | "fade";
66
+ variant?: "none" | "default" | "input" | "outline" | "link" | "invisible-link" | "hoverable" | "fade";
67
67
  textAlign?: "left" | "center" | "right";
68
68
  isFullWidth?: boolean;
69
69
  } & import("class-variance-authority/types").ClassProp) => string;
@@ -4,7 +4,7 @@ import { VariantProps } from "class-variance-authority";
4
4
  //#region src/components/CollapsibleTable/CollapsibleTable.d.ts
5
5
  declare const collapsibleTableVariants: (props?: {
6
6
  size?: "sm" | "md" | "lg" | "xl" | "full";
7
- variant?: "default" | "ghost" | "dark" | "outlined";
7
+ variant?: "default" | "dark" | "ghost" | "outlined";
8
8
  spacing?: "sm" | "md" | "lg" | "none" | "auto";
9
9
  } & import("class-variance-authority/types").ClassProp) => string;
10
10
  interface CollapsibleTableProps extends Omit<HTMLAttributes<HTMLElement>, 'title'>, VariantProps<typeof collapsibleTableVariants> {
@@ -27,7 +27,7 @@ declare const Command: {
27
27
  ref?: React.Ref<HTMLInputElement>;
28
28
  } & {
29
29
  asChild?: boolean;
30
- }, "key" | keyof import("react").InputHTMLAttributes<HTMLInputElement> | "asChild">, "type" | "onChange" | "value"> & {
30
+ }, "key" | keyof import("react").InputHTMLAttributes<HTMLInputElement> | "asChild">, "onChange" | "type" | "value"> & {
31
31
  value?: string;
32
32
  onValueChange?: (search: string) => void;
33
33
  } & import("react").RefAttributes<HTMLInputElement>>;
@@ -71,7 +71,7 @@ declare const Command: {
71
71
  ref?: React.Ref<HTMLDivElement>;
72
72
  } & {
73
73
  asChild?: boolean;
74
- }, "key" | keyof HTMLAttributes<HTMLDivElement> | "asChild">, "onSelect" | "value" | "disabled"> & {
74
+ }, "key" | keyof HTMLAttributes<HTMLDivElement> | "asChild">, "onSelect" | "disabled" | "value"> & {
75
75
  disabled?: boolean;
76
76
  onSelect?: (value: string) => void;
77
77
  value?: string;
@@ -7,13 +7,13 @@ import { VariantProps } from "class-variance-authority";
7
7
  * Provides flexible styling options for background, padding, borders, and layout
8
8
  */
9
9
  declare const containerVariants: (props?: {
10
- roundedSize?: "sm" | "md" | "lg" | "xl" | "2xl" | "none" | "full" | "3xl" | "4xl";
10
+ roundedSize?: "sm" | "md" | "lg" | "xl" | "2xl" | "none" | "3xl" | "4xl" | "full";
11
11
  transparency?: "xs" | "sm" | "md" | "lg" | "xl" | "none" | "full";
12
12
  padding?: "sm" | "md" | "lg" | "xl" | "2xl" | "none";
13
13
  separator?: "both" | "without" | "x" | "y";
14
- border?: "with" | "none";
14
+ border?: "none" | "with";
15
15
  borderColor?: "error" | "success" | "text" | "primary" | "secondary" | "neutral" | "card" | "warning";
16
- background?: "with" | "none" | "hoverable";
16
+ background?: "none" | "with" | "hoverable";
17
17
  gap?: "sm" | "md" | "lg" | "xl" | "2xl" | "none";
18
18
  } & import("class-variance-authority/types").ClassProp) => string;
19
19
  /** Available rounded corner sizes for the container */
@@ -1 +1 @@
1
- {"version":3,"file":"TextEditor.d.ts","names":[],"sources":["../../../../../src/components/DictionaryFieldEditor/ContentEditorView/TextEditor.tsx"],"mappings":";;;;;cA+Fa,SAAA;AAAA,KA2ID,eAAA;EACV,UAAA,EAAY,UAAA;EACZ,OAAA,EAAS,OAAA;EACT,OAAA,EAAS,WAAA;EACT,UAAA;EACA,aAAA,IAAiB,OAAA,aAAoB,SAAA;EACrC,eAAA,IAAmB,QAAA;AAAA;AAAA,cAqsBR,UAAA,kBAAU,oBAAA,CAAA,eAAA;AAAA,cA8MV,mBAAA,kBAAmB,oBAAA,CAAA,eAAA"}
1
+ {"version":3,"file":"TextEditor.d.ts","names":[],"sources":["../../../../../src/components/DictionaryFieldEditor/ContentEditorView/TextEditor.tsx"],"mappings":";;;;;cA+Fa,SAAA;AAAA,KA2ID,eAAA;EACV,UAAA,EAAY,UAAA;EACZ,OAAA,EAAS,OAAA;EACT,OAAA,EAAS,WAAA;EACT,UAAA;EACA,aAAA,IAAiB,OAAA,aAAoB,SAAA;EACrC,eAAA,IAAmB,QAAA;AAAA;AAAA,cAwrBR,UAAA,kBAAU,oBAAA,CAAA,eAAA;AAAA,cA8MV,mBAAA,kBAAmB,oBAAA,CAAA,eAAA"}
@@ -5,7 +5,7 @@ import { VariantProps } from "class-variance-authority";
5
5
  declare const checkboxVariants: (props?: {
6
6
  variant?: "default";
7
7
  size?: "xs" | "sm" | "md" | "lg";
8
- color?: "error" | "success" | "text" | "primary" | "secondary" | "destructive" | "neutral" | "light" | "dark" | "custom" | "text-inverse";
8
+ color?: "error" | "success" | "text" | "custom" | "primary" | "secondary" | "destructive" | "neutral" | "light" | "dark" | "text-inverse";
9
9
  validationStyleEnabled?: "enabled" | "disabled";
10
10
  } & import("class-variance-authority/types").ClassProp) => string;
11
11
  declare enum CheckboxSize {
@@ -54,7 +54,7 @@ declare enum LinkUnderlined {
54
54
  declare const linkVariants: (props?: {
55
55
  variant?: "default" | "invisible-link" | "hoverable" | "button" | "button-outlined";
56
56
  roundedSize?: "sm" | "md" | "lg" | "xl" | "2xl" | "none" | "3xl" | "full";
57
- color?: "text" | "primary" | "secondary" | "destructive" | "neutral" | "light" | "dark" | "error" | "custom" | "text-inverse" | "success";
57
+ color?: "text" | "error" | "custom" | "primary" | "secondary" | "destructive" | "neutral" | "light" | "dark" | "text-inverse" | "success";
58
58
  size?: "sm" | "md" | "lg" | "xl" | "custom";
59
59
  underlined?: boolean | LinkUnderlined.DEFAULT;
60
60
  } & import("class-variance-authority/types").ClassProp) => string;
@@ -185,7 +185,7 @@ declare enum TagBackground {
185
185
  }
186
186
  declare const containerVariants: (props?: {
187
187
  roundedSize?: "sm" | "md" | "lg" | "xl" | "2xl" | "none" | "3xl" | "full";
188
- color?: "text" | "primary" | "neutral" | "error" | "success" | "warning" | "blue" | "yellow" | "green" | "red" | "orange" | "purple" | "pink" | "brown" | "gray" | "black" | "white";
188
+ color?: "text" | "error" | "primary" | "neutral" | "success" | "warning" | "blue" | "yellow" | "green" | "red" | "orange" | "purple" | "pink" | "brown" | "gray" | "black" | "white";
189
189
  size?: "xs" | "sm" | "md" | "lg" | "xl";
190
190
  border?: "none" | "with";
191
191
  background?: "none" | "with";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/design-system",
3
- "version": "8.10.0-canary.0",
3
+ "version": "8.10.0",
4
4
  "private": false,
5
5
  "description": "Intlayer design system, including UI components used in the Intlayer editor, website, and visual editor/CMS.",
6
6
  "keywords": [
@@ -421,12 +421,12 @@
421
421
  "dependencies": {
422
422
  "@better-auth/passkey": "1.6.11",
423
423
  "@better-auth/sso": "1.6.11",
424
- "@intlayer/api": "8.10.0-canary.0",
425
- "@intlayer/config": "8.10.0-canary.0",
426
- "@intlayer/core": "8.10.0-canary.0",
427
- "@intlayer/dictionaries-entry": "8.10.0-canary.0",
428
- "@intlayer/editor-react": "8.10.0-canary.0",
429
- "@intlayer/types": "8.10.0-canary.0",
424
+ "@intlayer/api": "8.10.0",
425
+ "@intlayer/config": "8.10.0",
426
+ "@intlayer/core": "8.10.0",
427
+ "@intlayer/dictionaries-entry": "8.10.0",
428
+ "@intlayer/editor-react": "8.10.0",
429
+ "@intlayer/types": "8.10.0",
430
430
  "@radix-ui/react-dialog": "1.1.15",
431
431
  "@radix-ui/react-select": "2.2.6",
432
432
  "@radix-ui/react-slot": "1.2.4",
@@ -441,12 +441,12 @@
441
441
  "defu": "6.1.7",
442
442
  "dompurify": "^3.4.3",
443
443
  "isomorphic-dompurify": "^3.13.0",
444
- "react-intlayer": "8.10.0-canary.0",
444
+ "react-intlayer": "8.10.0",
445
445
  "rollup-preserve-directives": "1.1.3",
446
446
  "zod": "4.4.3"
447
447
  },
448
448
  "devDependencies": {
449
- "@intlayer/backend": "8.10.0-canary.0",
449
+ "@intlayer/backend": "8.10.0",
450
450
  "@shikijs/transformers": "4.0.2",
451
451
  "@storybook/addon-a11y": "8.6.14",
452
452
  "@storybook/addon-essentials": "8.6.14",
@@ -470,14 +470,14 @@
470
470
  "@testing-library/user-event": "14.6.1",
471
471
  "@types/dompurify": "^3.2.0",
472
472
  "@types/espree": "11.1.0",
473
- "@types/node": "25.9.0",
474
- "@types/react": "19.2.14",
473
+ "@types/node": "25.9.1",
474
+ "@types/react": "19.2.15",
475
475
  "@types/react-dom": "19.2.3",
476
476
  "@utils/ts-config": "1.0.4",
477
477
  "@utils/ts-config-types": "1.0.4",
478
478
  "clsx": "2.1.1",
479
479
  "fast-glob": "3.3.3",
480
- "intlayer": "8.10.0-canary.0",
480
+ "intlayer": "8.10.0",
481
481
  "rimraf": "6.1.3",
482
482
  "shiki": "4.0.2",
483
483
  "storybook": "8.6.17",
@@ -485,26 +485,26 @@
485
485
  "tsdown": "0.22.00",
486
486
  "typescript": "6.0.3",
487
487
  "vite": "8.0.13",
488
- "vite-intlayer": "8.10.0-canary.0",
489
- "vite-plugin-dts": "5.0.0",
488
+ "vite-intlayer": "8.10.0",
489
+ "vite-plugin-dts": "5.0.1",
490
490
  "vitest": "4.1.6"
491
491
  },
492
492
  "peerDependencies": {
493
493
  "@better-fetch/fetch": "1.1.21",
494
494
  "@hookform/resolvers": "5.2.2",
495
- "@intlayer/backend": "8.10.0-canary.0",
495
+ "@intlayer/backend": "8.10.0",
496
496
  "@monaco-editor/react": "4.7.0",
497
497
  "@shikijs/transformers": "4.0.2",
498
498
  "@tanstack/react-query": "5.100.11",
499
- "@tanstack/react-query-devtools": "5.100.10",
499
+ "@tanstack/react-query-devtools": "5.100.11",
500
500
  "framer-motion": "12.39.0",
501
501
  "fuse.js": "7.3.0",
502
- "intlayer": "8.10.0-canary.0",
502
+ "intlayer": "8.10.0",
503
503
  "lucide-react": "1.16.0",
504
504
  "react": ">=16.0.0",
505
505
  "react-dom": ">=16.0.0",
506
506
  "react-hook-form": "7.76.0",
507
- "react-intlayer": "8.10.0-canary.0",
507
+ "react-intlayer": "8.10.0",
508
508
  "shiki": "4.0.2",
509
509
  "tailwindcss": "4.3.0"
510
510
  },