@intlayer/design-system 8.7.6 → 8.7.8-canary.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 (117) hide show
  1. package/dist/esm/components/Breadcrumb/index.mjs.map +1 -1
  2. package/dist/esm/components/Browser/Browser.mjs.map +1 -1
  3. package/dist/esm/components/Carousel/index.mjs.map +1 -1
  4. package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
  5. package/dist/esm/components/DictionaryEditor/NodeWrapper/BooleanWrapper.mjs.map +1 -1
  6. package/dist/esm/components/DictionaryEditor/NodeWrapper/NestedObjectWrapper.mjs.map +1 -1
  7. package/dist/esm/components/DictionaryEditor/NodeWrapper/NumberWrapper.mjs.map +1 -1
  8. package/dist/esm/components/DictionaryEditor/NodeWrapper/index.mjs.map +1 -1
  9. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +2 -2
  10. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +1 -1
  11. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +3 -3
  12. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +1 -1
  13. package/dist/esm/components/DictionaryFieldEditor/EnumKeyInput.mjs.map +1 -1
  14. package/dist/esm/components/DictionaryFieldEditor/KeyPathBreadcrumb.mjs.map +1 -1
  15. package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +2 -2
  16. package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs.map +1 -1
  17. package/dist/esm/components/DictionaryFieldEditor/NodeTypeSelector.mjs.map +1 -1
  18. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +2 -2
  19. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs.map +1 -1
  20. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +1 -1
  21. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs.map +1 -1
  22. package/dist/esm/components/EditableField/EditableFieldInput.mjs.map +1 -1
  23. package/dist/esm/components/Flags/Flag.mjs.map +1 -1
  24. package/dist/esm/components/Form/FormField.mjs.map +1 -1
  25. package/dist/esm/components/Form/FormItem.mjs.map +1 -1
  26. package/dist/esm/components/Form/elements/FormElementWrapper.mjs.map +1 -1
  27. package/dist/esm/components/Form/elements/OTPElement.mjs +1 -1
  28. package/dist/esm/components/HTMLRender/HTMLRender.mjs.map +1 -1
  29. package/dist/esm/components/Headers/index.mjs.map +1 -1
  30. package/dist/esm/components/HeightResizer/index.mjs +25 -0
  31. package/dist/esm/components/HeightResizer/index.mjs.map +1 -1
  32. package/dist/esm/components/IDE/Code.mjs +96 -13
  33. package/dist/esm/components/IDE/Code.mjs.map +1 -1
  34. package/dist/esm/components/IDE/CodeBlockHighlight.mjs +77 -0
  35. package/dist/esm/components/IDE/CodeBlockHighlight.mjs.map +1 -0
  36. package/dist/esm/components/IDE/CodeBlockServer.mjs.map +1 -1
  37. package/dist/esm/components/IDE/CodeConditionalRenderer.mjs +15 -4
  38. package/dist/esm/components/IDE/CodeConditionalRenderer.mjs.map +1 -1
  39. package/dist/esm/components/IDE/CodeFormatSelector.mjs +5 -4
  40. package/dist/esm/components/IDE/CodeFormatSelector.mjs.map +1 -1
  41. package/dist/esm/components/IDE/FileTree.mjs.map +1 -1
  42. package/dist/esm/components/IDE/IDE.mjs.map +1 -1
  43. package/dist/esm/components/IDE/codeTransformer.mjs +228 -0
  44. package/dist/esm/components/IDE/codeTransformer.mjs.map +1 -0
  45. package/dist/esm/components/Input/OTPInput.mjs.map +1 -1
  46. package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs.map +1 -1
  47. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +1 -1
  48. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs.map +1 -1
  49. package/dist/esm/components/LocaleSwitcherDropDown/LocaleSwitcher.mjs.map +1 -1
  50. package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs +101 -0
  51. package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs.map +1 -0
  52. package/dist/esm/components/MarkDownRender/MarkDownRender.mjs +2 -9
  53. package/dist/esm/components/MarkDownRender/MarkDownRender.mjs.map +1 -1
  54. package/dist/esm/components/Modal/Modal.mjs +2 -2
  55. package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
  56. package/dist/esm/components/Navbar/index.mjs +1 -3
  57. package/dist/esm/components/Navbar/index.mjs.map +1 -1
  58. package/dist/esm/components/Navbar/useNavigation.mjs +3 -0
  59. package/dist/esm/components/Navbar/useNavigation.mjs.map +1 -1
  60. package/dist/esm/components/Pagination/Pagination.mjs +1 -1
  61. package/dist/esm/components/Popover/dynamic.mjs.map +1 -1
  62. package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -3
  63. package/dist/esm/components/Select/Multiselect.mjs.map +1 -1
  64. package/dist/esm/components/Tab/Tab.mjs.map +1 -1
  65. package/dist/esm/components/TechLogo/TechLogo.mjs.map +1 -1
  66. package/dist/esm/components/TextArea/AutocompleteTextArea.mjs.map +1 -1
  67. package/dist/esm/components/TextArea/ContentEditableTextArea.mjs.map +1 -1
  68. package/dist/esm/components/Toaster/Toast.mjs +6 -1
  69. package/dist/esm/components/Toaster/Toast.mjs.map +1 -1
  70. package/dist/esm/components/WithResizer/index.mjs +24 -0
  71. package/dist/esm/components/WithResizer/index.mjs.map +1 -1
  72. package/dist/esm/hooks/index.mjs +11 -11
  73. package/dist/esm/hooks/reactQuery.mjs +49 -2
  74. package/dist/esm/hooks/reactQuery.mjs.map +1 -1
  75. package/dist/esm/hooks/useAuth/useOAuth2.mjs +1 -1
  76. package/dist/esm/hooks/useAuth/useOAuth2.mjs.map +1 -1
  77. package/dist/esm/hooks/useAuth/useSession.mjs +1 -1
  78. package/dist/esm/hooks/useAuth/useSession.mjs.map +1 -1
  79. package/dist/esm/hooks/useDevice.mjs.map +1 -1
  80. package/dist/esm/hooks/useHorizontalSwipe.mjs.map +1 -1
  81. package/dist/esm/hooks/useIsDarkMode.mjs.map +1 -1
  82. package/dist/esm/hooks/useKeyboardDetector.mjs.map +1 -1
  83. package/dist/esm/hooks/useScrollBlockage/useScrollBlockageStore.mjs.map +1 -1
  84. package/dist/esm/libs/auth.mjs +1 -1
  85. package/dist/esm/libs/auth.mjs.map +1 -1
  86. package/dist/esm/providers/ReactQueryProvider.mjs.map +1 -1
  87. package/dist/esm/tailwind.config.mjs.map +1 -1
  88. package/dist/types/components/Badge/index.d.ts +2 -2
  89. package/dist/types/components/Button/Button.d.ts +4 -4
  90. package/dist/types/components/Command/index.d.ts +1 -1
  91. package/dist/types/components/Container/index.d.ts +7 -7
  92. package/dist/types/components/HeightResizer/index.d.ts.map +1 -1
  93. package/dist/types/components/IDE/Code.d.ts +3 -3
  94. package/dist/types/components/IDE/Code.d.ts.map +1 -1
  95. package/dist/types/components/IDE/CodeBlockHighlight.d.ts +20 -0
  96. package/dist/types/components/IDE/CodeBlockHighlight.d.ts.map +1 -0
  97. package/dist/types/components/IDE/CodeConditionalRenderer.d.ts.map +1 -1
  98. package/dist/types/components/IDE/CodeFormatSelector.d.ts +5 -1
  99. package/dist/types/components/IDE/CodeFormatSelector.d.ts.map +1 -1
  100. package/dist/types/components/IDE/codeTransformer.d.ts +25 -0
  101. package/dist/types/components/IDE/codeTransformer.d.ts.map +1 -0
  102. package/dist/types/components/Input/Checkbox.d.ts +2 -2
  103. package/dist/types/components/Link/Link.d.ts +4 -4
  104. package/dist/types/components/MarkDownRender/MarkDownIframe.d.ts +7 -0
  105. package/dist/types/components/MarkDownRender/MarkDownIframe.d.ts.map +1 -0
  106. package/dist/types/components/MarkDownRender/MarkDownRender.d.ts.map +1 -1
  107. package/dist/types/components/Pagination/Pagination.d.ts +1 -1
  108. package/dist/types/components/SwitchSelector/index.d.ts +1 -1
  109. package/dist/types/components/Tab/Tab.d.ts +1 -1
  110. package/dist/types/components/TabSelector/TabSelector.d.ts +1 -1
  111. package/dist/types/components/Tag/index.d.ts +3 -3
  112. package/dist/types/components/Toaster/Toast.d.ts +1 -1
  113. package/dist/types/components/WithResizer/index.d.ts.map +1 -1
  114. package/dist/types/hooks/index.d.ts +2 -2
  115. package/dist/types/hooks/reactQuery.d.ts +8 -1
  116. package/dist/types/hooks/reactQuery.d.ts.map +1 -1
  117. package/package.json +25 -25
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/components/Breadcrumb/index.tsx"],"sourcesContent":["'use client';\n\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { cn } from '@utils/cn';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { getIntlayer } from 'intlayer';\nimport { ChevronRightIcon } from 'lucide-react';\nimport { type FC, Fragment, type HTMLAttributes, type ReactNode } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button, type ButtonProps, ButtonVariant } from '../Button';\nimport { Link, LinkColor } from '../Link';\n\n/**\n * Props for LinkLink sub-component that renders breadcrumb items as links\n */\ntype LinkLinkProps = {\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n /**\n * Locale for internationalization\n */\n locale?: LocalesValues;\n /**\n * URL to navigate to\n */\n href?: string;\n /**\n * Link color\n */\n color?: LinkColor | `${LinkColor}`;\n /**\n * Click handler\n */\n onClick?: () => void;\n /**\n * Children content\n */\n children?: string;\n /**\n * Additional CSS classes\n */\n className?: string;\n} & Omit<\n HTMLAttributes<HTMLAnchorElement>,\n 'href' | 'onClick' | 'color' | 'children' | 'className'\n>;\n\n/**\n * Maps LinkColor to corresponding Tailwind text color classes\n */\nconst getColorClass = (color?: LinkColor | `${LinkColor}`): string => {\n if (!color) return '';\n\n const colorMap: Record<LinkColor, string> = {\n [LinkColor.PRIMARY]: 'text-primary',\n [LinkColor.SECONDARY]: 'text-secondary',\n [LinkColor.DESTRUCTIVE]: 'text-destructive',\n [LinkColor.NEUTRAL]: 'text-neutral',\n [LinkColor.LIGHT]: 'text-white',\n [LinkColor.DARK]: 'text-neutral-800',\n [LinkColor.TEXT]: 'text-text',\n [LinkColor.TEXT_INVERSE]: 'text-text-opposite',\n [LinkColor.ERROR]: 'text-error',\n [LinkColor.SUCCESS]: 'text-success',\n [LinkColor.CUSTOM]: '',\n };\n\n return colorMap[color as LinkColor] || '';\n};\n\n/**\n * Breadcrumb variant styles using class-variance-authority\n */\nconst breadcrumbVariants = cva('flex flex-row flex-wrap items-center text-sm', {\n variants: {\n size: {\n small: 'gap-1 text-xs',\n medium: 'gap-2 text-sm',\n large: 'gap-3 text-base',\n },\n spacing: {\n compact: 'gap-1',\n normal: 'gap-2',\n loose: 'gap-4',\n },\n },\n defaultVariants: {\n size: 'medium',\n spacing: 'normal',\n },\n});\n\n/**\n * LinkLink sub-component for breadcrumb items that navigate to other pages\n */\nconst LinkLink: FC<LinkLinkProps> = ({\n href,\n lang,\n children,\n onClick,\n color,\n position,\n locale,\n className,\n ...props\n}) => {\n const content = getIntlayer('breadcrumb');\n const linkLabel = content.linkLabel;\n\n return (\n <>\n <Link\n href={href}\n locale={locale}\n color={color}\n onClick={onClick}\n itemProp=\"item\"\n isExternalLink={false}\n itemScope\n itemType=\"https://schema.org/WebPage\"\n {...props}\n label={`${linkLabel} ${children}`}\n itemID={href}\n size=\"sm\"\n >\n <span itemProp=\"name\">{children}</span>\n </Link>\n <meta itemProp=\"position\" content={position.toString()} />\n </>\n );\n};\n\n/**\n * Props for ButtonLink sub-component that renders breadcrumb items as interactive buttons\n */\ntype ButtonButtonProps = {\n /**\n * Text content for the breadcrumb button\n */\n children: string;\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n} & Omit<ButtonProps, 'children' | 'label'>;\n\n/**\n * ButtonLink sub-component for breadcrumb items with click handlers\n */\nconst ButtonLink: FC<ButtonButtonProps> = ({\n children: text,\n onClick,\n color,\n position,\n className,\n ...props\n}) => {\n const { linkLabel } = useIntlayer('breadcrumb');\n\n return (\n <>\n <Button\n onClick={onClick}\n variant={ButtonVariant.LINK}\n label={`${linkLabel} ${text}`}\n color={color}\n itemProp=\"item\"\n {...props}\n >\n <span itemProp=\"name\">{text}</span>\n </Button>\n <meta itemProp=\"position\" content={position.toString()} />\n </>\n );\n};\n\n/**\n * Props for Span sub-component that renders static breadcrumb text\n */\ntype SpanProps = {\n /**\n * Text content for the static breadcrumb item\n */\n children: string;\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n} & HTMLAttributes<HTMLSpanElement>;\n\n/**\n * Span sub-component for static breadcrumb text items\n */\nconst Span: FC<SpanProps> = ({ children, position, className, ...props }) => (\n <span\n itemProp=\"item\"\n className={cn(\n 'inline-flex items-center',\n 'font-medium text-neutral-700',\n 'transition-colors duration-200',\n className\n )}\n >\n <span itemProp=\"name\" {...props}>\n {children}\n </span>\n <meta itemProp=\"position\" content={position.toString()} />\n </span>\n);\n\n/**\n * Detailed breadcrumb link configuration with optional href or onClick\n */\ntype DetailedBreadcrumbLink = {\n /**\n * URL to navigate to when the breadcrumb item is clicked\n */\n href?: string;\n /**\n * Text content to display for this breadcrumb item\n */\n text: string;\n /**\n * Custom click handler function for interactive breadcrumb items\n */\n onClick?: () => void;\n};\n\n/**\n * Union type representing different breadcrumb item configurations:\n * - string: Simple text breadcrumb item\n * - DetailedBreadcrumbLink: Object with href, text, and/or onClick properties\n */\nexport type BreadcrumbLink = string | DetailedBreadcrumbLink;\n\nexport type BreadcrumbProps = {\n /**\n * Array of breadcrumb items\n */\n links: BreadcrumbLink[];\n /**\n * Color scheme for breadcrumb links\n * @default LinkColor.TEXT\n */\n color?: LinkColor | `${LinkColor}`;\n /**\n * Locale for internationalization\n */\n locale?: LocalesValues;\n /**\n * Element type for ARIA current attribute\n * @default 'page'\n */\n elementType?: 'page' | 'location';\n /**\n * Custom separator between breadcrumb items\n * @default ChevronRightIcon\n */\n separator?: ReactNode;\n /**\n * ARIA label for breadcrumb navigation\n * @default 'breadcrumb'\n */\n ariaLabel?: string;\n /**\n * Whether to include structured data markup\n * @default true\n */\n includeStructuredData?: boolean;\n /**\n * Maximum number of breadcrumb items to show before truncation\n */\n maxItems?: number;\n} & VariantProps<typeof breadcrumbVariants> &\n HTMLAttributes<HTMLOListElement>;\n\n/**\n * Breadcrumb component providing navigational context with accessibility features\n *\n * Features:\n * - Supports links, buttons, and static text elements\n * - Full keyboard navigation support\n * - ARIA attributes for screen readers\n * - Schema.org structured data for SEO\n * - Customizable separators and styling\n * - Internationalization support\n * - Responsive design variants\n *\n * @example\n * ```tsx\n * <Breadcrumb\n * links={[\n * 'Home',\n * { href: '/products', text: 'Products' },\n * { onClick: handleCategory, text: 'Electronics' },\n * 'Smartphones'\n * ]}\n * size=\"medium\"\n * ariaLabel=\"Product navigation\"\n * />\n * ```\n */\nexport const Breadcrumb: FC<BreadcrumbProps> = ({\n links,\n className,\n color = LinkColor.TEXT,\n locale,\n elementType = 'page',\n separator = <ChevronRightIcon size={10} />,\n ariaLabel = 'breadcrumb',\n includeStructuredData = true,\n maxItems,\n size,\n spacing,\n ...props\n}) => {\n const displayLinks =\n maxItems && links.length > maxItems\n ? [...links.slice(0, 1), '...', ...links.slice(-(maxItems - 2))]\n : links;\n\n return (\n <nav aria-label={ariaLabel}>\n <ol\n className={cn(breadcrumbVariants({ size, spacing }), className)}\n {...(includeStructuredData && {\n itemScope: true,\n itemType: 'http://schema.org/BreadcrumbList',\n })}\n {...props}\n >\n {displayLinks.map((link, index) => {\n const isLastLink = index === displayLinks.length - 1;\n const isLink =\n typeof link === 'object' && typeof link.href === 'string';\n const isButton =\n typeof link === 'object' && typeof link.onClick === 'function';\n const isActive = index === displayLinks.length - 1;\n const ariaCurrent = isActive ? elementType : undefined;\n const isTruncated = link === '...';\n\n const text = (link as DetailedBreadcrumbLink).text ?? link;\n\n const separatorColorClass = getColorClass(color);\n\n if (isTruncated) {\n return (\n <Fragment key={`truncated-${text}`}>\n <li className=\"flex items-center\" aria-hidden=\"true\">\n <span className=\"text-neutral-500\">…</span>\n </li>\n {!isLastLink && (\n <li aria-hidden=\"true\" className=\"flex items-center\">\n <span className={cn(separatorColorClass)}>{separator}</span>\n </li>\n )}\n </Fragment>\n );\n }\n\n let section = (\n <Span\n key={text}\n position={index + 1}\n aria-current={ariaCurrent}\n className={cn(\n 'transition-colors duration-200',\n isActive && 'text-neutral-900'\n )}\n >\n {text}\n </Span>\n );\n\n if (isLink) {\n section = (\n <LinkLink\n key={text}\n href={link.href!}\n color={color}\n position={index + 1}\n locale={locale}\n aria-current={ariaCurrent}\n className={cn(isActive && 'cursor-default text-neutral-900')}\n >\n {text}\n </LinkLink>\n );\n } else if (isButton) {\n section = (\n <ButtonLink\n key={text}\n onClick={link.onClick!}\n color={color}\n position={index + 1}\n aria-current={ariaCurrent}\n className={cn(isActive && 'cursor-default text-neutral-900')}\n >\n {text}\n </ButtonLink>\n );\n }\n\n const listElement = (\n <li\n {...(includeStructuredData && {\n itemProp: 'itemListElement',\n itemScope: true,\n itemType: 'https://schema.org/ListItem',\n })}\n key={text}\n className=\"flex items-center\"\n >\n {section}\n </li>\n );\n\n if (isLastLink) {\n return listElement;\n }\n\n return (\n <Fragment key={text}>\n {listElement}\n <li aria-hidden=\"true\" className=\"flex items-center\">\n <span className={cn(separatorColorClass)}>{separator}</span>\n </li>\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/components/Breadcrumb/index.tsx"],"sourcesContent":["'use client';\n\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { cn } from '@utils/cn';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { getIntlayer } from 'intlayer';\nimport { ChevronRightIcon } from 'lucide-react';\nimport { type FC, Fragment, type HTMLAttributes, type ReactNode } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button, type ButtonProps, ButtonVariant } from '../Button';\nimport { Link, LinkColor } from '../Link';\n\n/**\n * Props for LinkLink sub-component that renders breadcrumb items as links\n */\ntype LinkLinkProps = {\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n /**\n * Locale for internationalization\n */\n locale?: LocalesValues;\n /**\n * URL to navigate to\n */\n href?: string;\n /**\n * Link color\n */\n color?: LinkColor | `${LinkColor}`;\n /**\n * Click handler\n */\n onClick?: () => void;\n /**\n * Children content\n */\n children?: string;\n /**\n * Additional CSS classes\n */\n className?: string;\n} & Omit<\n HTMLAttributes<HTMLAnchorElement>,\n 'href' | 'onClick' | 'color' | 'children' | 'className'\n>;\n\n/**\n * Maps LinkColor to corresponding Tailwind text color classes\n */\nconst getColorClass = (color?: LinkColor | `${LinkColor}`): string => {\n if (!color) return '';\n\n const colorMap: Record<LinkColor, string> = {\n [LinkColor.PRIMARY]: 'text-primary',\n [LinkColor.SECONDARY]: 'text-secondary',\n [LinkColor.DESTRUCTIVE]: 'text-destructive',\n [LinkColor.NEUTRAL]: 'text-neutral',\n [LinkColor.LIGHT]: 'text-white',\n [LinkColor.DARK]: 'text-neutral-800',\n [LinkColor.TEXT]: 'text-text',\n [LinkColor.TEXT_INVERSE]: 'text-text-opposite',\n [LinkColor.ERROR]: 'text-error',\n [LinkColor.SUCCESS]: 'text-success',\n [LinkColor.CUSTOM]: '',\n };\n\n return colorMap[color as LinkColor] || '';\n};\n\n/**\n * Breadcrumb variant styles using class-variance-authority\n */\nconst breadcrumbVariants = cva('flex flex-row flex-wrap items-center text-sm', {\n variants: {\n size: {\n small: 'gap-1 text-xs',\n medium: 'gap-2 text-sm',\n large: 'gap-3 text-base',\n },\n spacing: {\n compact: 'gap-1',\n normal: 'gap-2',\n loose: 'gap-4',\n },\n },\n defaultVariants: {\n size: 'medium',\n spacing: 'normal',\n },\n});\n\n/**\n * LinkLink sub-component for breadcrumb items that navigate to other pages\n */\nconst LinkLink: FC<LinkLinkProps> = ({\n href,\n lang,\n children,\n onClick,\n color,\n position,\n locale,\n className,\n ...props\n}) => {\n const content = getIntlayer('breadcrumb');\n const linkLabel = content.linkLabel;\n\n return (\n <>\n <Link\n href={href}\n locale={locale}\n color={color}\n onClick={onClick}\n itemProp=\"item\"\n isExternalLink={false}\n itemScope\n itemType=\"https://schema.org/WebPage\"\n {...props}\n label={`${linkLabel} ${children}`}\n itemID={href}\n size=\"sm\"\n >\n <span itemProp=\"name\">{children}</span>\n </Link>\n <meta itemProp=\"position\" content={position.toString()} />\n </>\n );\n};\n\n/**\n * Props for ButtonLink sub-component that renders breadcrumb items as interactive buttons\n */\ntype ButtonButtonProps = {\n /**\n * Text content for the breadcrumb button\n */\n children: string;\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n} & Omit<ButtonProps, 'children' | 'label'>;\n\n/**\n * ButtonLink sub-component for breadcrumb items with click handlers\n */\nconst ButtonLink: FC<ButtonButtonProps> = ({\n children: text,\n onClick,\n color,\n position,\n className,\n ...props\n}) => {\n const { linkLabel } = useIntlayer('breadcrumb');\n\n return (\n <>\n <Button\n onClick={onClick}\n variant={ButtonVariant.LINK}\n label={`${linkLabel} ${text}`}\n color={color}\n itemProp=\"item\"\n {...props}\n >\n <span itemProp=\"name\">{text}</span>\n </Button>\n <meta itemProp=\"position\" content={position.toString()} />\n </>\n );\n};\n\n/**\n * Props for Span sub-component that renders static breadcrumb text\n */\ntype SpanProps = {\n /**\n * Text content for the static breadcrumb item\n */\n children: string;\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n} & HTMLAttributes<HTMLSpanElement>;\n\n/**\n * Span sub-component for static breadcrumb text items\n */\nconst Span: FC<SpanProps> = ({ children, position, className, ...props }) => (\n <span\n itemProp=\"item\"\n className={cn(\n 'inline-flex items-center',\n 'font-medium text-neutral-700',\n 'transition-colors duration-200',\n className\n )}\n >\n <span itemProp=\"name\" {...props}>\n {children}\n </span>\n <meta itemProp=\"position\" content={position.toString()} />\n </span>\n);\n\n/**\n * Detailed breadcrumb link configuration with optional href or onClick\n */\ntype DetailedBreadcrumbLink = {\n /**\n * URL to navigate to when the breadcrumb item is clicked\n */\n href?: string;\n /**\n * Text content to display for this breadcrumb item\n */\n text: string;\n /**\n * Custom click handler function for interactive breadcrumb items\n */\n onClick?: () => void;\n};\n\n/**\n * Union type representing different breadcrumb item configurations:\n * - string: Simple text breadcrumb item\n * - DetailedBreadcrumbLink: Object with href, text, and/or onClick properties\n */\nexport type BreadcrumbLink = string | DetailedBreadcrumbLink;\n\nexport type BreadcrumbProps = {\n /**\n * Array of breadcrumb items\n */\n links: BreadcrumbLink[];\n /**\n * Color scheme for breadcrumb links\n * @default LinkColor.TEXT\n */\n color?: LinkColor | `${LinkColor}`;\n /**\n * Locale for internationalization\n */\n locale?: LocalesValues;\n /**\n * Element type for ARIA current attribute\n * @default 'page'\n */\n elementType?: 'page' | 'location';\n /**\n * Custom separator between breadcrumb items\n * @default ChevronRightIcon\n */\n separator?: ReactNode;\n /**\n * ARIA label for breadcrumb navigation\n * @default 'breadcrumb'\n */\n ariaLabel?: string;\n /**\n * Whether to include structured data markup\n * @default true\n */\n includeStructuredData?: boolean;\n /**\n * Maximum number of breadcrumb items to show before truncation\n */\n maxItems?: number;\n} & VariantProps<typeof breadcrumbVariants> &\n HTMLAttributes<HTMLOListElement>;\n\n/**\n * Breadcrumb component providing navigational context with accessibility features\n *\n * Features:\n * - Supports links, buttons, and static text elements\n * - Full keyboard navigation support\n * - ARIA attributes for screen readers\n * - Schema.org structured data for SEO\n * - Customizable separators and styling\n * - Internationalization support\n * - Responsive design variants\n *\n * @example\n * ```tsx\n * <Breadcrumb\n * links={[\n * 'Home',\n * { href: '/products', text: 'Products' },\n * { onClick: handleCategory, text: 'Electronics' },\n * 'Smartphones'\n * ]}\n * size=\"medium\"\n * ariaLabel=\"Product navigation\"\n * />\n * ```\n */\nexport const Breadcrumb: FC<BreadcrumbProps> = ({\n links,\n className,\n color = LinkColor.TEXT,\n locale,\n elementType = 'page',\n separator = <ChevronRightIcon size={10} />,\n ariaLabel = 'breadcrumb',\n includeStructuredData = true,\n maxItems,\n size,\n spacing,\n ...props\n}) => {\n const displayLinks =\n maxItems && links.length > maxItems\n ? [...links.slice(0, 1), '...', ...links.slice(-(maxItems - 2))]\n : links;\n\n return (\n <nav aria-label={ariaLabel}>\n <ol\n className={cn(breadcrumbVariants({ size, spacing }), className)}\n {...(includeStructuredData && {\n itemScope: true,\n itemType: 'http://schema.org/BreadcrumbList',\n })}\n {...props}\n >\n {displayLinks.map((link, index) => {\n const isLastLink = index === displayLinks.length - 1;\n const isLink =\n typeof link === 'object' && typeof link.href === 'string';\n const isButton =\n typeof link === 'object' && typeof link.onClick === 'function';\n const isActive = index === displayLinks.length - 1;\n const ariaCurrent = isActive ? elementType : undefined;\n const isTruncated = link === '...';\n\n const text = (link as DetailedBreadcrumbLink).text ?? link;\n\n const separatorColorClass = getColorClass(color);\n\n if (isTruncated) {\n return (\n <Fragment key={`truncated-${text}`}>\n <li className=\"flex items-center\" aria-hidden=\"true\">\n <span className=\"text-neutral-500\">…</span>\n </li>\n {!isLastLink && (\n <li aria-hidden=\"true\" className=\"flex items-center\">\n <span className={cn(separatorColorClass)}>{separator}</span>\n </li>\n )}\n </Fragment>\n );\n }\n\n let section = (\n <Span\n key={text}\n position={index + 1}\n aria-current={ariaCurrent}\n className={cn(\n 'transition-colors duration-200',\n isActive && 'text-neutral-900'\n )}\n >\n {text}\n </Span>\n );\n\n if (isLink) {\n section = (\n <LinkLink\n key={text}\n href={link.href!}\n color={color}\n position={index + 1}\n locale={locale}\n aria-current={ariaCurrent}\n className={cn(isActive && 'cursor-default text-neutral-900')}\n >\n {text}\n </LinkLink>\n );\n } else if (isButton) {\n section = (\n <ButtonLink\n key={text}\n onClick={link.onClick!}\n color={color}\n position={index + 1}\n aria-current={ariaCurrent}\n className={cn(isActive && 'cursor-default text-neutral-900')}\n >\n {text}\n </ButtonLink>\n );\n }\n\n const listElement = (\n <li\n {...(includeStructuredData && {\n itemProp: 'itemListElement',\n itemScope: true,\n itemType: 'https://schema.org/ListItem',\n })}\n key={text}\n className=\"flex items-center\"\n >\n {section}\n </li>\n );\n\n if (isLastLink) {\n return listElement;\n }\n\n return (\n <Fragment key={text}>\n {listElement}\n <li aria-hidden=\"true\" className=\"flex items-center\">\n <span className={cn(separatorColorClass)}>{separator}</span>\n </li>\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Browser.mjs","names":[],"sources":["../../../../src/components/Browser/Browser.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { ArrowLeft, ArrowRight, RotateCw } from 'lucide-react';\nimport {\n type CSSProperties,\n type SubmitEvent,\n type HTMLAttributes,\n type RefObject,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { Input, inputVariants } from '../Input';\n\nexport type BrowserProps = {\n initialUrl?: string;\n path?: string;\n className?: string;\n style?: CSSProperties;\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n 'aria-label'?: string;\n sandbox?: string;\n ref?: RefObject<HTMLIFrameElement | null>;\n domainRestriction?: string;\n} & HTMLAttributes<HTMLIFrameElement>;\n\nexport const Browser = ({\n initialUrl = 'https://example.com',\n path,\n className,\n style,\n size = 'md',\n 'aria-label': ariaLabel,\n sandbox = 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads',\n ref,\n domainRestriction,\n ...props\n}: BrowserProps) => {\n // --- State -----------------------------------------------------------------\n const [inputUrl, setInputUrl] = useState(initialUrl);\n const [currentUrl, setCurrentUrl] = useState(initialUrl);\n\n // History Management\n const [history, setHistory] = useState<string[]>([initialUrl]);\n const [currentIndex, setCurrentIndex] = useState(0);\n\n const [error, setError] = useState<string | null>(null);\n const [submitted, setSubmitted] = useState(false);\n const internalIframeRef = useRef<HTMLIFrameElement>(null);\n\n useImperativeHandle(ref, () => internalIframeRef.current!, []);\n const content = useIntlayer('browser');\n\n // --- Effects ---------------------------------------------------------------\n\n // Reset everything if initialUrl changes completely\n useEffect(() => {\n setInputUrl(initialUrl);\n setCurrentUrl(initialUrl);\n setHistory([initialUrl]);\n setCurrentIndex(0);\n setError(null);\n setSubmitted(false);\n }, [initialUrl]);\n\n // Sync external path changes with the URL bar and History\n useEffect(() => {\n if (!path) return;\n\n try {\n const baseOrigin = domainRestriction ?? initialUrl;\n const origin = new URL(baseOrigin).origin;\n const fullUrl = `${origin}${path}`;\n\n // Update Input (Always update the visual bar)\n setInputUrl(fullUrl);\n\n // Check internal iframe state to avoid reload if already there\n let isAlreadyAtUrl = false;\n if (internalIframeRef.current?.contentWindow) {\n try {\n const currentIframeHref =\n internalIframeRef.current.contentWindow.location.href;\n if (new URL(currentIframeHref).href === new URL(fullUrl).href) {\n isAlreadyAtUrl = true;\n }\n } catch {\n // Cross-origin access ignored\n }\n }\n\n // Update History Stack\n // We perform this check regardless of `isAlreadyAtUrl`.\n // If the path changed (even internally), we want to record it in the arrow stack.\n if (history[currentIndex] !== fullUrl) {\n setHistory((prev) => {\n const newHistory = prev.slice(0, currentIndex + 1);\n newHistory.push(fullUrl);\n return newHistory;\n });\n setCurrentIndex((prev) => prev + 1);\n }\n\n // Navigate (Update src) only if NOT already there\n // This prevents the iframe from refreshing when the user navigated inside it.\n if (!isAlreadyAtUrl) {\n setCurrentUrl(fullUrl);\n }\n\n setError(null);\n } catch {\n // Ignore invalid paths\n }\n }, [path, domainRestriction, initialUrl]); // Removed currentIndex dependency to prevent loops\n\n // --- Navigation Logic ------------------------------------------------------\n\n const handleNavigateTo = (url: string) => {\n try {\n const validated = normalizeUrl(url);\n\n // If we are navigating to the exact same URL, just reload\n if (validated === currentUrl) {\n handleReload();\n return;\n }\n\n setCurrentUrl(validated);\n setInputUrl(validated);\n setError(null);\n\n // Update History: Slice future if we went back, then push new\n const newHistory = history.slice(0, currentIndex + 1);\n newHistory.push(validated);\n setHistory(newHistory);\n setCurrentIndex(newHistory.length - 1);\n } catch (e) {\n if (\n e instanceof Error &&\n e.message === 'URL does not match allowed domain' &&\n domainRestriction\n ) {\n setError(\n content.domainRestrictionError?.value ??\n `Only URLs from ${domainRestriction} are allowed.`\n );\n } else {\n setError(content.errorMessage.value);\n }\n }\n };\n\n const handleBack = () => {\n if (currentIndex > 0) {\n const newIndex = currentIndex - 1;\n const prevUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(prevUrl);\n setInputUrl(prevUrl);\n setError(null);\n }\n };\n\n const handleForward = () => {\n if (currentIndex < history.length - 1) {\n const newIndex = currentIndex + 1;\n const nextUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(nextUrl);\n setInputUrl(nextUrl);\n setError(null);\n }\n };\n\n const handleSubmit = (e: SubmitEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitted(true);\n handleNavigateTo(inputUrl);\n };\n\n const handleReload = () => {\n if (internalIframeRef.current) {\n // Create a clean reload effect\n const src = internalIframeRef.current.src;\n internalIframeRef.current.src = '';\n setTimeout(() => {\n if (internalIframeRef.current) internalIframeRef.current.src = src;\n }, 50);\n }\n };\n\n // --- Validation Helpers ----------------------------------------------------\n const isValidHostname = (host: string) => {\n if (host === 'localhost') return true;\n if (/^(\\d{1,3}\\.){3}\\d{1,3}$/.test(host)) return true;\n if (/^[a-f0-9:]+$/i.test(host)) return true;\n if (!/^[a-z0-9.-]+$/i.test(host)) return false;\n if (/^[-.]/.test(host) || /[-.]$/.test(host)) return false;\n if (host.includes('..')) return false;\n if (!host.includes('.')) return false;\n return true;\n };\n\n const getRestrictionOrigin = (): URL | null => {\n if (!domainRestriction) return null;\n try {\n return new URL(domainRestriction);\n } catch {\n return null;\n }\n };\n\n const normalizeUrl = (raw: string) => {\n const trimmed = raw.trim();\n if (!trimmed || /\\s/.test(trimmed)) throw new Error('Invalid');\n\n const restrictionOrigin = getRestrictionOrigin();\n const isRelativePath = trimmed.startsWith('/') && !trimmed.startsWith('//');\n\n if (isRelativePath) {\n if (restrictionOrigin) {\n return new URL(`${restrictionOrigin.origin}${trimmed}`).toString();\n }\n return new URL(`${new URL(currentUrl).origin}${trimmed}`).toString();\n }\n\n const hasProtocol = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed);\n const candidate = hasProtocol ? trimmed : `https://${trimmed}`;\n const url = new URL(candidate);\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error('Only http(s) is allowed');\n }\n\n if (!isValidHostname(url.hostname)) throw new Error('Invalid host');\n\n if (restrictionOrigin) {\n const urlMatches =\n url.hostname === restrictionOrigin.hostname &&\n url.protocol === restrictionOrigin.protocol &&\n (restrictionOrigin.port === '' ||\n url.port === restrictionOrigin.port ||\n url.host === restrictionOrigin.host);\n\n if (!urlMatches) throw new Error('URL does not match allowed domain');\n }\n\n return url.toString();\n };\n\n const showError = submitted && !!error;\n const canGoBack = currentIndex > 0;\n const canGoForward = currentIndex < history.length - 1;\n\n return (\n <section\n className={cn(\n 'flex w-full flex-col overflow-hidden rounded-xl bg-background shadow-[0_4px_12px_rgba(0,0,0,0.4),0_0_1px_rgba(0,0,0,0.2)]',\n className\n )}\n style={style}\n aria-label={ariaLabel ?? content.ariaLabel.value}\n >\n {/* Top bar */}\n <div className=\"relative z-10 flex shrink-0 items-center gap-3 rounded-t-xl bg-text/15 px-4 py-2\">\n {/* Navigation Controls */}\n <div className=\"flex items-center gap-1\">\n <Button\n type=\"button\"\n onClick={handleBack}\n disabled={!canGoBack}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.backButtonLabel.value}\n Icon={ArrowLeft}\n />\n <Button\n type=\"button\"\n onClick={handleForward}\n disabled={!canGoForward}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.forwardButtonLabel.value}\n Icon={ArrowRight}\n />\n </div>\n\n {/* URL Bar */}\n <form\n onSubmit={handleSubmit}\n noValidate\n className={cn(\n inputVariants(),\n 'flex w-full gap-2 rounded-xl p-0.5! supports-[corner-shape:squircle]:rounded-2xl',\n 'bg-neutral/10 text-text/50 placeholder:text-neutral/80'\n )}\n >\n <label htmlFor=\"browser-url\" className=\"sr-only\">\n {content.urlLabel.value}\n </label>\n <Input\n id=\"browser-url\"\n type=\"text\"\n inputMode=\"url\"\n spellCheck={false}\n autoCapitalize=\"off\"\n variant=\"invisible\"\n className=\"ml-3 p-0!\"\n size=\"sm\"\n autoCorrect=\"off\"\n value={inputUrl}\n onChange={(e) => {\n setInputUrl(e.target.value);\n if (showError) setError(null);\n }}\n placeholder={content.urlPlaceholder.value}\n aria-label={content.urlLabel.value}\n aria-invalid={showError}\n aria-describedby={showError ? 'browser-url-error' : undefined}\n />\n\n <Button\n type=\"button\"\n onClick={handleReload}\n variant=\"hoverable\"\n size=\"icon-md\"\n className=\"p-1!\"\n label={'content.reloadButtonTitle.value'}\n Icon={RotateCw}\n />\n\n {/* invisible submit */}\n <button type=\"submit\" className=\"sr-only absolute\" tabIndex={-1} />\n </form>\n\n {/* Error Message Tooltip */}\n {showError && (\n <div className=\"absolute top-full left-4 z-20 mt-1\">\n <p\n id=\"browser-url-error\"\n role=\"alert\"\n aria-live=\"assertive\"\n className=\"rounded-md bg-red-900/90 px-3 py-1.5 text-red-100 text-xs shadow-md backdrop-blur-sm\"\n >\n {error}\n </p>\n </div>\n )}\n </div>\n\n {/* Iframe */}\n <div className=\"relative z-0 flex min-h-0 w-full flex-1 flex-col overflow-hidden rounded-b-xl bg-background\">\n <iframe\n ref={internalIframeRef}\n src={currentUrl}\n title={content.iframeTitle.value}\n className=\"size-full flex-1\"\n sandbox={sandbox}\n loading=\"lazy\"\n aria-live=\"polite\"\n {...props}\n />\n </div>\n </section>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"Browser.mjs","names":[],"sources":["../../../../src/components/Browser/Browser.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { ArrowLeft, ArrowRight, RotateCw } from 'lucide-react';\nimport {\n type CSSProperties,\n type SubmitEvent,\n type HTMLAttributes,\n type RefObject,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button } from '../Button';\nimport { Input, inputVariants } from '../Input';\n\nexport type BrowserProps = {\n initialUrl?: string;\n path?: string;\n className?: string;\n style?: CSSProperties;\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n 'aria-label'?: string;\n sandbox?: string;\n ref?: RefObject<HTMLIFrameElement | null>;\n domainRestriction?: string;\n} & HTMLAttributes<HTMLIFrameElement>;\n\nexport const Browser = ({\n initialUrl = 'https://example.com',\n path,\n className,\n style,\n size = 'md',\n 'aria-label': ariaLabel,\n sandbox = 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads',\n ref,\n domainRestriction,\n ...props\n}: BrowserProps) => {\n // --- State -----------------------------------------------------------------\n const [inputUrl, setInputUrl] = useState(initialUrl);\n const [currentUrl, setCurrentUrl] = useState(initialUrl);\n\n // History Management\n const [history, setHistory] = useState<string[]>([initialUrl]);\n const [currentIndex, setCurrentIndex] = useState(0);\n\n const [error, setError] = useState<string | null>(null);\n const [submitted, setSubmitted] = useState(false);\n const internalIframeRef = useRef<HTMLIFrameElement>(null);\n\n useImperativeHandle(ref, () => internalIframeRef.current!, []);\n const content = useIntlayer('browser');\n\n // --- Effects ---------------------------------------------------------------\n\n // Reset everything if initialUrl changes completely\n useEffect(() => {\n setInputUrl(initialUrl);\n setCurrentUrl(initialUrl);\n setHistory([initialUrl]);\n setCurrentIndex(0);\n setError(null);\n setSubmitted(false);\n }, [initialUrl]);\n\n // Sync external path changes with the URL bar and History\n useEffect(() => {\n if (!path) return;\n\n try {\n const baseOrigin = domainRestriction ?? initialUrl;\n const origin = new URL(baseOrigin).origin;\n const fullUrl = `${origin}${path}`;\n\n // Update Input (Always update the visual bar)\n setInputUrl(fullUrl);\n\n // Check internal iframe state to avoid reload if already there\n let isAlreadyAtUrl = false;\n if (internalIframeRef.current?.contentWindow) {\n try {\n const currentIframeHref =\n internalIframeRef.current.contentWindow.location.href;\n if (new URL(currentIframeHref).href === new URL(fullUrl).href) {\n isAlreadyAtUrl = true;\n }\n } catch {\n // Cross-origin access ignored\n }\n }\n\n // Update History Stack\n // We perform this check regardless of `isAlreadyAtUrl`.\n // If the path changed (even internally), we want to record it in the arrow stack.\n if (history[currentIndex] !== fullUrl) {\n setHistory((prev) => {\n const newHistory = prev.slice(0, currentIndex + 1);\n newHistory.push(fullUrl);\n return newHistory;\n });\n setCurrentIndex((prev) => prev + 1);\n }\n\n // Navigate (Update src) only if NOT already there\n // This prevents the iframe from refreshing when the user navigated inside it.\n if (!isAlreadyAtUrl) {\n setCurrentUrl(fullUrl);\n }\n\n setError(null);\n } catch {\n // Ignore invalid paths\n }\n }, [path, domainRestriction, initialUrl]); // Removed currentIndex dependency to prevent loops\n\n // --- Navigation Logic ------------------------------------------------------\n\n const handleNavigateTo = (url: string) => {\n try {\n const validated = normalizeUrl(url);\n\n // If we are navigating to the exact same URL, just reload\n if (validated === currentUrl) {\n handleReload();\n return;\n }\n\n setCurrentUrl(validated);\n setInputUrl(validated);\n setError(null);\n\n // Update History: Slice future if we went back, then push new\n const newHistory = history.slice(0, currentIndex + 1);\n newHistory.push(validated);\n setHistory(newHistory);\n setCurrentIndex(newHistory.length - 1);\n } catch (e) {\n if (\n e instanceof Error &&\n e.message === 'URL does not match allowed domain' &&\n domainRestriction\n ) {\n setError(\n content.domainRestrictionError?.value ??\n `Only URLs from ${domainRestriction} are allowed.`\n );\n } else {\n setError(content.errorMessage.value);\n }\n }\n };\n\n const handleBack = () => {\n if (currentIndex > 0) {\n const newIndex = currentIndex - 1;\n const prevUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(prevUrl);\n setInputUrl(prevUrl);\n setError(null);\n }\n };\n\n const handleForward = () => {\n if (currentIndex < history.length - 1) {\n const newIndex = currentIndex + 1;\n const nextUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(nextUrl);\n setInputUrl(nextUrl);\n setError(null);\n }\n };\n\n const handleSubmit = (e: SubmitEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitted(true);\n handleNavigateTo(inputUrl);\n };\n\n const handleReload = () => {\n if (internalIframeRef.current) {\n // Create a clean reload effect\n const src = internalIframeRef.current.src;\n internalIframeRef.current.src = '';\n setTimeout(() => {\n if (internalIframeRef.current) internalIframeRef.current.src = src;\n }, 50);\n }\n };\n\n // --- Validation Helpers ----------------------------------------------------\n const isValidHostname = (host: string) => {\n if (host === 'localhost') return true;\n if (/^(\\d{1,3}\\.){3}\\d{1,3}$/.test(host)) return true;\n if (/^[a-f0-9:]+$/i.test(host)) return true;\n if (!/^[a-z0-9.-]+$/i.test(host)) return false;\n if (/^[-.]/.test(host) || /[-.]$/.test(host)) return false;\n if (host.includes('..')) return false;\n if (!host.includes('.')) return false;\n return true;\n };\n\n const getRestrictionOrigin = (): URL | null => {\n if (!domainRestriction) return null;\n try {\n return new URL(domainRestriction);\n } catch {\n return null;\n }\n };\n\n const normalizeUrl = (raw: string) => {\n const trimmed = raw.trim();\n if (!trimmed || /\\s/.test(trimmed)) throw new Error('Invalid');\n\n const restrictionOrigin = getRestrictionOrigin();\n const isRelativePath = trimmed.startsWith('/') && !trimmed.startsWith('//');\n\n if (isRelativePath) {\n if (restrictionOrigin) {\n return new URL(`${restrictionOrigin.origin}${trimmed}`).toString();\n }\n return new URL(`${new URL(currentUrl).origin}${trimmed}`).toString();\n }\n\n const hasProtocol = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed);\n const candidate = hasProtocol ? trimmed : `https://${trimmed}`;\n const url = new URL(candidate);\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error('Only http(s) is allowed');\n }\n\n if (!isValidHostname(url.hostname)) throw new Error('Invalid host');\n\n if (restrictionOrigin) {\n const urlMatches =\n url.hostname === restrictionOrigin.hostname &&\n url.protocol === restrictionOrigin.protocol &&\n (restrictionOrigin.port === '' ||\n url.port === restrictionOrigin.port ||\n url.host === restrictionOrigin.host);\n\n if (!urlMatches) throw new Error('URL does not match allowed domain');\n }\n\n return url.toString();\n };\n\n const showError = submitted && !!error;\n const canGoBack = currentIndex > 0;\n const canGoForward = currentIndex < history.length - 1;\n\n return (\n <section\n className={cn(\n 'flex w-full flex-col overflow-hidden rounded-xl bg-background shadow-[0_4px_12px_rgba(0,0,0,0.4),0_0_1px_rgba(0,0,0,0.2)]',\n className\n )}\n style={style}\n aria-label={ariaLabel ?? content.ariaLabel.value}\n >\n {/* Top bar */}\n <div className=\"relative z-10 flex shrink-0 items-center gap-3 rounded-t-xl bg-text/15 px-4 py-2\">\n {/* Navigation Controls */}\n <div className=\"flex items-center gap-1\">\n <Button\n type=\"button\"\n onClick={handleBack}\n disabled={!canGoBack}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.backButtonLabel.value}\n Icon={ArrowLeft}\n />\n <Button\n type=\"button\"\n onClick={handleForward}\n disabled={!canGoForward}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.forwardButtonLabel.value}\n Icon={ArrowRight}\n />\n </div>\n\n {/* URL Bar */}\n <form\n onSubmit={handleSubmit}\n noValidate\n className={cn(\n inputVariants(),\n 'flex w-full gap-2 rounded-xl p-0.5! supports-[corner-shape:squircle]:rounded-2xl',\n 'bg-neutral/10 text-text/50 placeholder:text-neutral/80'\n )}\n >\n <label htmlFor=\"browser-url\" className=\"sr-only\">\n {content.urlLabel.value}\n </label>\n <Input\n id=\"browser-url\"\n type=\"text\"\n inputMode=\"url\"\n spellCheck={false}\n autoCapitalize=\"off\"\n variant=\"invisible\"\n className=\"ml-3 p-0!\"\n size=\"sm\"\n autoCorrect=\"off\"\n value={inputUrl}\n onChange={(e) => {\n setInputUrl(e.target.value);\n if (showError) setError(null);\n }}\n placeholder={content.urlPlaceholder.value}\n aria-label={content.urlLabel.value}\n aria-invalid={showError}\n aria-describedby={showError ? 'browser-url-error' : undefined}\n />\n\n <Button\n type=\"button\"\n onClick={handleReload}\n variant=\"hoverable\"\n size=\"icon-md\"\n className=\"p-1!\"\n label={'content.reloadButtonTitle.value'}\n Icon={RotateCw}\n />\n\n {/* invisible submit */}\n <button type=\"submit\" className=\"sr-only absolute\" tabIndex={-1} />\n </form>\n\n {/* Error Message Tooltip */}\n {showError && (\n <div className=\"absolute top-full left-4 z-20 mt-1\">\n <p\n id=\"browser-url-error\"\n role=\"alert\"\n aria-live=\"assertive\"\n className=\"rounded-md bg-red-900/90 px-3 py-1.5 text-red-100 text-xs shadow-md backdrop-blur-sm\"\n >\n {error}\n </p>\n </div>\n )}\n </div>\n\n {/* Iframe */}\n <div className=\"relative z-0 flex min-h-0 w-full flex-1 flex-col overflow-hidden rounded-b-xl bg-background\">\n <iframe\n ref={internalIframeRef}\n src={currentUrl}\n title={content.iframeTitle.value}\n className=\"size-full flex-1\"\n sandbox={sandbox}\n loading=\"lazy\"\n aria-live=\"polite\"\n {...props}\n />\n </div>\n </section>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/components/Carousel/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n Button,\n ButtonColor,\n ButtonSize,\n ButtonVariant,\n} from '@components/Button';\nimport { KeyboardShortcut } from '@components/KeyboardShortcut';\nimport { Popover } from '@components/Popover';\nimport { cn } from '@utils/cn';\nimport { ChevronLeft, ChevronRight } from 'lucide-react';\nimport {\n Children,\n createContext,\n type FC,\n type HTMLAttributes,\n isValidElement,\n type MouseEventHandler,\n type ReactElement,\n type ReactNode,\n type TouchEventHandler,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\n\n// ------------------------------------------------------------------\n// Configuration\n// ------------------------------------------------------------------\nconst SWIPE_THRESHOLD_DIVISOR = 5;\nconst TRANSITION_DELAY_MS = 50;\n\n// ------------------------------------------------------------------\n// Context Definition\n// ------------------------------------------------------------------\ntype CarouselContextValue = {\n selectedIndex: number;\n setSelectedIndex: (index: number) => void;\n totalItems: number;\n handlePrev: () => void;\n handleNext: () => void;\n};\n\nconst CarouselContext = createContext<CarouselContextValue | null>(null);\n\nconst useCarousel = () => {\n const context = useContext(CarouselContext);\n if (!context) {\n throw new Error('useCarousel must be used within a Carousel');\n }\n return context;\n};\n\n// ------------------------------------------------------------------\n// Helper Functions\n// ------------------------------------------------------------------\nconst getCardStyle = (index: number, displayedIndex: number) => {\n const diff = Math.abs(index - displayedIndex);\n switch (diff) {\n case 0:\n return 'opacity-100 z-40';\n case 1:\n return 'opacity-75 z-30 cursor-pointer';\n case 2:\n return 'opacity-50 z-20 pointer-events-none';\n default:\n return 'opacity-0 z-10 pointer-events-none';\n }\n};\n\nconst getCardScale = (index: number, displayedIndex: number) => {\n const diff = Math.abs(index - displayedIndex);\n switch (diff) {\n case 0:\n return 1;\n case 1:\n return 0.9;\n case 2:\n return 0.8;\n default:\n return 0.7;\n }\n};\n\n// This allows the calculation to work on SSR without hydration mismatch.\n// Your original logic: (3 * screenWidth) / 10 === 30% of viewport width\nconst getCardPositionX = (\n index: number,\n displayedIndex: number,\n containerWidth: number\n) => {\n const diff = index - displayedIndex;\n const gapPercentage = containerWidth < 600 ? 0.15 : 0.3; // Dropped to 15% for a tighter cluster\n const step = Math.min(containerWidth * gapPercentage, 300);\n\n // The 'px' here is mandatory\n return `${diff * step}px`;\n};\n\n// ------------------------------------------------------------------\n// Sub-Component: Item\n// ------------------------------------------------------------------\ntype CarouselItemProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n};\n\nconst CarouselItem: FC<CarouselItemProps> = ({\n children,\n className,\n ...props\n}) => {\n return (\n <div className={cn('h-full w-full', className)} {...props}>\n {children}\n </div>\n );\n};\n\n// ------------------------------------------------------------------\n// Sub-Component: Indicators (Controller)\n// ------------------------------------------------------------------\ntype CarouselIndicatorsProps = HTMLAttributes<HTMLDivElement> & {\n disableKeyboardShortcuts?: boolean;\n};\n\nconst CarouselIndicators: FC<CarouselIndicatorsProps> = ({\n className,\n disableKeyboardShortcuts = false,\n ...props\n}) => {\n const {\n selectedIndex,\n setSelectedIndex,\n totalItems,\n handlePrev,\n handleNext,\n } = useCarousel();\n const { goToSlide, previousSlide, nextSlide } = useIntlayer('carousel');\n\n if (totalItems <= 1) return null;\n\n return (\n <div\n className={cn(\n 'absolute bottom-4 left-1/2 z-50 flex -translate-x-1/2 flex-row items-center gap-2',\n className\n )}\n {...props}\n >\n <Popover identifier=\"carousel-prev\">\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.NEUTRAL}\n label={previousSlide.value}\n roundedSize=\"full\"\n onClick={(e) => {\n e.stopPropagation();\n handlePrev();\n }}\n Icon={ChevronLeft}\n size={ButtonSize.ICON_MD}\n disabled={selectedIndex === 0}\n />\n\n <Popover.Detail identifier=\"carousel-prev\">\n <div className=\"flex items-center gap-2 p-2\">\n <span className=\"whitespace-nowrap text-neutral text-xs\">\n {previousSlide.value}\n </span>\n <KeyboardShortcut\n shortcut=\"ArrowLeft\"\n disabled={disableKeyboardShortcuts}\n size=\"sm\"\n onTriggered={handlePrev}\n />\n </div>\n </Popover.Detail>\n </Popover>\n\n {Array.from({ length: totalItems }).map((_, index) => {\n const isActive = index === selectedIndex;\n return (\n <button\n key={index}\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setSelectedIndex(index);\n }}\n aria-label={goToSlide({ index: index + 1 }).value}\n className={cn(\n 'h-2.5 w-2.5 rounded-full transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-neutral-400 focus:ring-offset-2',\n isActive ? 'scale-110 bg-text' : 'bg-text/20 hover:bg-text/40'\n )}\n />\n );\n })}\n\n <Popover identifier=\"carousel-next\">\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.NEUTRAL}\n roundedSize=\"full\"\n label={nextSlide.value}\n onClick={(e) => {\n e.stopPropagation();\n handleNext();\n }}\n Icon={ChevronRight}\n size={ButtonSize.ICON_MD}\n disabled={selectedIndex === totalItems - 1}\n />\n\n <Popover.Detail identifier=\"carousel-next\">\n <div className=\"flex items-center gap-2 p-2\">\n <span className=\"whitespace-nowrap text-neutral text-xs\">\n {nextSlide.value}\n </span>\n <KeyboardShortcut\n shortcut=\"ArrowRight\"\n size=\"sm\"\n onTriggered={handleNext}\n disabled={disableKeyboardShortcuts}\n />\n </div>\n </Popover.Detail>\n </Popover>\n </div>\n );\n};\n\n// ------------------------------------------------------------------\n// Main Component: Carousel Root\n// ------------------------------------------------------------------\ntype CarouselProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n initialIndex?: number;\n onIndexChange?: (index: number) => void;\n};\n\nconst partitionCarouselChildren = (\n children: ReactNode[]\n): [ReactElement[], ReactNode[]] => {\n const slides: ReactElement[] = [];\n const others: ReactNode[] = [];\n\n children.forEach((child) => {\n if (isValidElement(child) && child.type === CarouselItem) {\n slides.push(child);\n } else {\n others.push(child);\n }\n });\n\n return [slides, others];\n};\n\nconst CarouselRoot: FC<CarouselProps> = ({\n children,\n className,\n initialIndex = 0,\n onIndexChange,\n ...props\n}) => {\n const allChildren = Children.toArray(children);\n const [slides, others] = partitionCarouselChildren(allChildren);\n const totalItems = slides.length;\n\n // State Management\n const [selectedIndex, setSelectedIndex] = useState<number>(initialIndex);\n const [displayedIndex, setDisplayedIndex] = useState<number>(initialIndex);\n const [containerHeight, setContainerHeight] = useState<number>(0);\n const [containerWidth, setContainerWidth] = useState<number>(0);\n\n useEffect(() => {\n const calculateDimensions = () => {\n if (!containerRef.current) return;\n\n // Track Width\n const width = containerRef.current.clientWidth;\n setContainerWidth(width);\n\n // Track Height (existing logic)\n const heights = itemsRef.current.map((item) => item?.offsetHeight || 0);\n const maxHeight = Math.max(0, ...heights);\n if (maxHeight > 0) {\n setContainerHeight(maxHeight + 40);\n }\n };\n\n calculateDimensions();\n\n const observer = new ResizeObserver(() => {\n calculateDimensions();\n });\n\n if (containerRef.current) observer.observe(containerRef.current);\n itemsRef.current.forEach((item) => {\n if (item) observer.observe(item);\n });\n\n return () => observer.disconnect();\n }, [totalItems]);\n\n // Drag State\n const [startX, setStartX] = useState(0);\n const [isDragging, setIsDragging] = useState(false);\n\n // Refs\n const containerRef = useRef<HTMLDivElement>(null);\n const itemsRef = useRef<(HTMLDivElement | null)[]>([]);\n\n // Navigation Logic\n const handleSwitchItem = (diff: number) => {\n if (containerWidth === 0) return;\n\n // Use container width for the threshold\n const swipeStep = containerWidth / SWIPE_THRESHOLD_DIVISOR;\n const numSwipe = Math.round(diff / swipeStep);\n\n if (Math.abs(numSwipe) >= 1) {\n const newIndex = displayedIndex - numSwipe;\n const clampedIndex = Math.max(0, Math.min(newIndex, totalItems - 1));\n\n if (clampedIndex !== selectedIndex) {\n setSelectedIndex(clampedIndex);\n setStartX((prev) => prev + diff);\n }\n }\n };\n\n const handleNext = () => {\n setSelectedIndex((prev) => Math.min(prev + 1, totalItems - 1));\n };\n\n const handlePrev = () => {\n setSelectedIndex((prev) => Math.max(prev - 1, 0));\n };\n\n // Input Handlers\n const handleMouseDown: MouseEventHandler<HTMLDivElement> = (e) => {\n setIsDragging(true);\n setStartX(e.clientX);\n };\n const handleMouseMove: MouseEventHandler<HTMLDivElement> = (e) => {\n if (isDragging) handleSwitchItem(e.clientX - startX);\n };\n const handleDragEnd = () => setIsDragging(false);\n const handleTouchStart: TouchEventHandler<HTMLDivElement> = (e) => {\n setIsDragging(true);\n setStartX(e.touches[0].clientX);\n };\n const handleTouchMove: TouchEventHandler<HTMLDivElement> = (e) => {\n if (isDragging) handleSwitchItem(e.touches[0].clientX - startX);\n };\n\n // Effects\n useEffect(() => {\n if (selectedIndex) onIndexChange?.(selectedIndex);\n }, [selectedIndex, onIndexChange]);\n\n useEffect(() => {\n let interval: NodeJS.Timeout;\n\n if (selectedIndex !== displayedIndex) {\n interval = setInterval(() => {\n setDisplayedIndex((prev) => {\n if (prev === selectedIndex) {\n clearInterval(interval);\n return prev;\n }\n return prev < selectedIndex ? prev + 1 : prev - 1;\n });\n }, TRANSITION_DELAY_MS);\n }\n return () => clearInterval(interval);\n }, [selectedIndex, displayedIndex]);\n\n // Calculate height based on the MAX height of ALL items\n useEffect(() => {\n const calculateMaxHeight = () => {\n const heights = itemsRef.current.map((item) => item?.offsetHeight || 0);\n const maxHeight = Math.max(0, ...heights);\n\n if (maxHeight > 0) {\n setContainerHeight(maxHeight + 40);\n }\n };\n\n calculateMaxHeight();\n\n const observer = new ResizeObserver(() => {\n calculateMaxHeight();\n });\n\n itemsRef.current.forEach((item) => {\n if (item) observer.observe(item);\n });\n\n return () => observer.disconnect();\n }, [totalItems]); // Removed isMounted dependency\n\n return (\n <CarouselContext.Provider\n value={{\n selectedIndex,\n setSelectedIndex,\n totalItems,\n handlePrev,\n handleNext,\n }}\n >\n <div\n ref={containerRef}\n className={cn(\n 'relative flex w-full cursor-grab select-none items-center overflow-hidden outline-none transition-[height] duration-300 ease-in-out focus:outline-none focus:outline-none focus:ring-0 active:cursor-grabbing',\n 'max-w-[1400px]',\n className\n )}\n style={{\n height: containerHeight > 0 ? containerHeight : 'auto',\n minHeight: '400px',\n }}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleDragEnd}\n onMouseLeave={handleDragEnd}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleDragEnd}\n role=\"region\"\n aria-label=\"Carousel\"\n {...props}\n >\n {slides.map((child, index) => {\n return (\n <div\n key={index}\n role=\"button\"\n tabIndex={0}\n ref={(el) => {\n itemsRef.current[index] = el;\n }}\n // FIX 2: Removed isMounted checks and invisible classes.\n // CSS units allow correct SSR rendering.\n className={cn(\n 'absolute left-1/2 -translate-x-1/2 transition-all duration-300 ease-in-out',\n 'outline-none ring-0 focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0',\n getCardStyle(index, displayedIndex)\n )}\n onClick={(e) => {\n e.stopPropagation();\n setSelectedIndex(index);\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') setSelectedIndex(index);\n }}\n style={{\n transform: `\n translateX(${getCardPositionX(\n index,\n displayedIndex,\n containerWidth\n )})\n scale(${getCardScale(index, displayedIndex)})\n `,\n }}\n >\n {child}\n </div>\n );\n })}\n\n {others}\n </div>\n </CarouselContext.Provider>\n );\n};\n\nexport const Carousel = Object.assign(CarouselRoot, {\n Item: CarouselItem,\n Indicators: CarouselIndicators,\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/components/Carousel/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n Button,\n ButtonColor,\n ButtonSize,\n ButtonVariant,\n} from '@components/Button';\nimport { KeyboardShortcut } from '@components/KeyboardShortcut';\nimport { Popover } from '@components/Popover';\nimport { cn } from '@utils/cn';\nimport { ChevronLeft, ChevronRight } from 'lucide-react';\nimport {\n Children,\n createContext,\n type FC,\n type HTMLAttributes,\n isValidElement,\n type MouseEventHandler,\n type ReactElement,\n type ReactNode,\n type TouchEventHandler,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\n\n// ------------------------------------------------------------------\n// Configuration\n// ------------------------------------------------------------------\nconst SWIPE_THRESHOLD_DIVISOR = 5;\nconst TRANSITION_DELAY_MS = 50;\n\n// ------------------------------------------------------------------\n// Context Definition\n// ------------------------------------------------------------------\ntype CarouselContextValue = {\n selectedIndex: number;\n setSelectedIndex: (index: number) => void;\n totalItems: number;\n handlePrev: () => void;\n handleNext: () => void;\n};\n\nconst CarouselContext = createContext<CarouselContextValue | null>(null);\n\nconst useCarousel = () => {\n const context = useContext(CarouselContext);\n if (!context) {\n throw new Error('useCarousel must be used within a Carousel');\n }\n return context;\n};\n\n// ------------------------------------------------------------------\n// Helper Functions\n// ------------------------------------------------------------------\nconst getCardStyle = (index: number, displayedIndex: number) => {\n const diff = Math.abs(index - displayedIndex);\n switch (diff) {\n case 0:\n return 'opacity-100 z-40';\n case 1:\n return 'opacity-75 z-30 cursor-pointer';\n case 2:\n return 'opacity-50 z-20 pointer-events-none';\n default:\n return 'opacity-0 z-10 pointer-events-none';\n }\n};\n\nconst getCardScale = (index: number, displayedIndex: number) => {\n const diff = Math.abs(index - displayedIndex);\n switch (diff) {\n case 0:\n return 1;\n case 1:\n return 0.9;\n case 2:\n return 0.8;\n default:\n return 0.7;\n }\n};\n\n// This allows the calculation to work on SSR without hydration mismatch.\n// Your original logic: (3 * screenWidth) / 10 === 30% of viewport width\nconst getCardPositionX = (\n index: number,\n displayedIndex: number,\n containerWidth: number\n) => {\n const diff = index - displayedIndex;\n const gapPercentage = containerWidth < 600 ? 0.15 : 0.3; // Dropped to 15% for a tighter cluster\n const step = Math.min(containerWidth * gapPercentage, 300);\n\n // The 'px' here is mandatory\n return `${diff * step}px`;\n};\n\n// ------------------------------------------------------------------\n// Sub-Component: Item\n// ------------------------------------------------------------------\ntype CarouselItemProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n};\n\nconst CarouselItem: FC<CarouselItemProps> = ({\n children,\n className,\n ...props\n}) => {\n return (\n <div className={cn('h-full w-full', className)} {...props}>\n {children}\n </div>\n );\n};\n\n// ------------------------------------------------------------------\n// Sub-Component: Indicators (Controller)\n// ------------------------------------------------------------------\ntype CarouselIndicatorsProps = HTMLAttributes<HTMLDivElement> & {\n disableKeyboardShortcuts?: boolean;\n};\n\nconst CarouselIndicators: FC<CarouselIndicatorsProps> = ({\n className,\n disableKeyboardShortcuts = false,\n ...props\n}) => {\n const {\n selectedIndex,\n setSelectedIndex,\n totalItems,\n handlePrev,\n handleNext,\n } = useCarousel();\n const { goToSlide, previousSlide, nextSlide } = useIntlayer('carousel');\n\n if (totalItems <= 1) return null;\n\n return (\n <div\n className={cn(\n 'absolute bottom-4 left-1/2 z-50 flex -translate-x-1/2 flex-row items-center gap-2',\n className\n )}\n {...props}\n >\n <Popover identifier=\"carousel-prev\">\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.NEUTRAL}\n label={previousSlide.value}\n roundedSize=\"full\"\n onClick={(e) => {\n e.stopPropagation();\n handlePrev();\n }}\n Icon={ChevronLeft}\n size={ButtonSize.ICON_MD}\n disabled={selectedIndex === 0}\n />\n\n <Popover.Detail identifier=\"carousel-prev\">\n <div className=\"flex items-center gap-2 p-2\">\n <span className=\"whitespace-nowrap text-neutral text-xs\">\n {previousSlide.value}\n </span>\n <KeyboardShortcut\n shortcut=\"ArrowLeft\"\n disabled={disableKeyboardShortcuts}\n size=\"sm\"\n onTriggered={handlePrev}\n />\n </div>\n </Popover.Detail>\n </Popover>\n\n {Array.from({ length: totalItems }).map((_, index) => {\n const isActive = index === selectedIndex;\n return (\n <button\n key={index}\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setSelectedIndex(index);\n }}\n aria-label={goToSlide({ index: index + 1 }).value}\n className={cn(\n 'h-2.5 w-2.5 rounded-full transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-neutral-400 focus:ring-offset-2',\n isActive ? 'scale-110 bg-text' : 'bg-text/20 hover:bg-text/40'\n )}\n />\n );\n })}\n\n <Popover identifier=\"carousel-next\">\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.NEUTRAL}\n roundedSize=\"full\"\n label={nextSlide.value}\n onClick={(e) => {\n e.stopPropagation();\n handleNext();\n }}\n Icon={ChevronRight}\n size={ButtonSize.ICON_MD}\n disabled={selectedIndex === totalItems - 1}\n />\n\n <Popover.Detail identifier=\"carousel-next\">\n <div className=\"flex items-center gap-2 p-2\">\n <span className=\"whitespace-nowrap text-neutral text-xs\">\n {nextSlide.value}\n </span>\n <KeyboardShortcut\n shortcut=\"ArrowRight\"\n size=\"sm\"\n onTriggered={handleNext}\n disabled={disableKeyboardShortcuts}\n />\n </div>\n </Popover.Detail>\n </Popover>\n </div>\n );\n};\n\n// ------------------------------------------------------------------\n// Main Component: Carousel Root\n// ------------------------------------------------------------------\ntype CarouselProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n initialIndex?: number;\n onIndexChange?: (index: number) => void;\n};\n\nconst partitionCarouselChildren = (\n children: ReactNode[]\n): [ReactElement[], ReactNode[]] => {\n const slides: ReactElement[] = [];\n const others: ReactNode[] = [];\n\n children.forEach((child) => {\n if (isValidElement(child) && child.type === CarouselItem) {\n slides.push(child);\n } else {\n others.push(child);\n }\n });\n\n return [slides, others];\n};\n\nconst CarouselRoot: FC<CarouselProps> = ({\n children,\n className,\n initialIndex = 0,\n onIndexChange,\n ...props\n}) => {\n const allChildren = Children.toArray(children);\n const [slides, others] = partitionCarouselChildren(allChildren);\n const totalItems = slides.length;\n\n // State Management\n const [selectedIndex, setSelectedIndex] = useState<number>(initialIndex);\n const [displayedIndex, setDisplayedIndex] = useState<number>(initialIndex);\n const [containerHeight, setContainerHeight] = useState<number>(0);\n const [containerWidth, setContainerWidth] = useState<number>(0);\n\n useEffect(() => {\n const calculateDimensions = () => {\n if (!containerRef.current) return;\n\n // Track Width\n const width = containerRef.current.clientWidth;\n setContainerWidth(width);\n\n // Track Height (existing logic)\n const heights = itemsRef.current.map((item) => item?.offsetHeight || 0);\n const maxHeight = Math.max(0, ...heights);\n if (maxHeight > 0) {\n setContainerHeight(maxHeight + 40);\n }\n };\n\n calculateDimensions();\n\n const observer = new ResizeObserver(() => {\n calculateDimensions();\n });\n\n if (containerRef.current) observer.observe(containerRef.current);\n itemsRef.current.forEach((item) => {\n if (item) observer.observe(item);\n });\n\n return () => observer.disconnect();\n }, [totalItems]);\n\n // Drag State\n const [startX, setStartX] = useState(0);\n const [isDragging, setIsDragging] = useState(false);\n\n // Refs\n const containerRef = useRef<HTMLDivElement>(null);\n const itemsRef = useRef<(HTMLDivElement | null)[]>([]);\n\n // Navigation Logic\n const handleSwitchItem = (diff: number) => {\n if (containerWidth === 0) return;\n\n // Use container width for the threshold\n const swipeStep = containerWidth / SWIPE_THRESHOLD_DIVISOR;\n const numSwipe = Math.round(diff / swipeStep);\n\n if (Math.abs(numSwipe) >= 1) {\n const newIndex = displayedIndex - numSwipe;\n const clampedIndex = Math.max(0, Math.min(newIndex, totalItems - 1));\n\n if (clampedIndex !== selectedIndex) {\n setSelectedIndex(clampedIndex);\n setStartX((prev) => prev + diff);\n }\n }\n };\n\n const handleNext = () => {\n setSelectedIndex((prev) => Math.min(prev + 1, totalItems - 1));\n };\n\n const handlePrev = () => {\n setSelectedIndex((prev) => Math.max(prev - 1, 0));\n };\n\n // Input Handlers\n const handleMouseDown: MouseEventHandler<HTMLDivElement> = (e) => {\n setIsDragging(true);\n setStartX(e.clientX);\n };\n const handleMouseMove: MouseEventHandler<HTMLDivElement> = (e) => {\n if (isDragging) handleSwitchItem(e.clientX - startX);\n };\n const handleDragEnd = () => setIsDragging(false);\n const handleTouchStart: TouchEventHandler<HTMLDivElement> = (e) => {\n setIsDragging(true);\n setStartX(e.touches[0].clientX);\n };\n const handleTouchMove: TouchEventHandler<HTMLDivElement> = (e) => {\n if (isDragging) handleSwitchItem(e.touches[0].clientX - startX);\n };\n\n // Effects\n useEffect(() => {\n if (selectedIndex) onIndexChange?.(selectedIndex);\n }, [selectedIndex, onIndexChange]);\n\n useEffect(() => {\n let interval: NodeJS.Timeout;\n\n if (selectedIndex !== displayedIndex) {\n interval = setInterval(() => {\n setDisplayedIndex((prev) => {\n if (prev === selectedIndex) {\n clearInterval(interval);\n return prev;\n }\n return prev < selectedIndex ? prev + 1 : prev - 1;\n });\n }, TRANSITION_DELAY_MS);\n }\n return () => clearInterval(interval);\n }, [selectedIndex, displayedIndex]);\n\n // Calculate height based on the MAX height of ALL items\n useEffect(() => {\n const calculateMaxHeight = () => {\n const heights = itemsRef.current.map((item) => item?.offsetHeight || 0);\n const maxHeight = Math.max(0, ...heights);\n\n if (maxHeight > 0) {\n setContainerHeight(maxHeight + 40);\n }\n };\n\n calculateMaxHeight();\n\n const observer = new ResizeObserver(() => {\n calculateMaxHeight();\n });\n\n itemsRef.current.forEach((item) => {\n if (item) observer.observe(item);\n });\n\n return () => observer.disconnect();\n }, [totalItems]); // Removed isMounted dependency\n\n return (\n <CarouselContext.Provider\n value={{\n selectedIndex,\n setSelectedIndex,\n totalItems,\n handlePrev,\n handleNext,\n }}\n >\n <div\n ref={containerRef}\n className={cn(\n 'relative flex w-full cursor-grab select-none items-center overflow-hidden outline-none transition-[height] duration-300 ease-in-out focus:outline-none focus:outline-none focus:ring-0 active:cursor-grabbing',\n 'max-w-[1400px]',\n className\n )}\n style={{\n height: containerHeight > 0 ? containerHeight : 'auto',\n minHeight: '400px',\n }}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleDragEnd}\n onMouseLeave={handleDragEnd}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleDragEnd}\n role=\"region\"\n aria-label=\"Carousel\"\n {...props}\n >\n {slides.map((child, index) => {\n return (\n <div\n key={index}\n role=\"button\"\n tabIndex={0}\n ref={(el) => {\n itemsRef.current[index] = el;\n }}\n // FIX 2: Removed isMounted checks and invisible classes.\n // CSS units allow correct SSR rendering.\n className={cn(\n 'absolute left-1/2 -translate-x-1/2 transition-all duration-300 ease-in-out',\n 'outline-none ring-0 focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0',\n getCardStyle(index, displayedIndex)\n )}\n onClick={(e) => {\n e.stopPropagation();\n setSelectedIndex(index);\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') setSelectedIndex(index);\n }}\n style={{\n transform: `\n translateX(${getCardPositionX(\n index,\n displayedIndex,\n containerWidth\n )})\n scale(${getCardScale(index, displayedIndex)})\n `,\n }}\n >\n {child}\n </div>\n );\n })}\n\n {others}\n </div>\n </CarouselContext.Provider>\n );\n};\n\nexport const Carousel = Object.assign(CarouselRoot, {\n Item: CarouselItem,\n Indicators: CarouselIndicators,\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";
3
4
  import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
4
5
  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 +1 @@
1
- {"version":3,"file":"BooleanWrapper.mjs","names":[],"sources":["../../../../../src/components/DictionaryEditor/NodeWrapper/BooleanWrapper.tsx"],"sourcesContent":["'use client';\n\nimport { getContentNodeByKeyPath } from '@intlayer/core/dictionaryManipulator';\nimport { useEditorLocale } from '@intlayer/editor-react';\nimport { cn } from '@utils/cn';\nimport type { FC } from 'react';\nimport { SwitchSelector } from '../../SwitchSelector';\nimport type { NodeWrapperProps } from './index';\n\nexport type BooleanWrapperProps = Omit<NodeWrapperProps, 'section'> & {\n section: boolean;\n};\n\nexport const BooleanWrapper: FC<BooleanWrapperProps> = ({\n keyPath,\n section,\n editedContent,\n onContentChange,\n onFocusKeyPath,\n}) => {\n const currentLocale = useEditorLocale();\n const editedContentValue = getContentNodeByKeyPath(\n editedContent,\n keyPath,\n currentLocale\n );\n\n if (\n editedContentValue !== undefined &&\n typeof editedContentValue !== 'boolean'\n ) {\n return (\n <>\n Error loading section - Edited content incoherence with the original\n content format\n </>\n );\n }\n\n const level = keyPath.length;\n const value = editedContentValue ?? section;\n\n return (\n <button\n type=\"button\"\n className={cn(\n 'w-full rounded-md p-2 text-left transition',\n 'hover:bg-card/30 [&:has(.section:hover)]:bg-transparent',\n level === 2 && 'hover:bg-card/30',\n level >= 3 && ''\n )}\n onClick={(e) => {\n e.stopPropagation();\n onFocusKeyPath(keyPath);\n }}\n >\n <SwitchSelector\n value={value}\n onChange={(newValue) =>\n onContentChange({ keyPath, newValue: String(newValue) })\n }\n />\n </button>\n );\n};\n"],"mappings":";;;;;;;;;AAaA,MAAa,kBAA2C,EACtD,SACA,SACA,eACA,iBACA,qBACI;CAEJ,MAAM,qBAAqB,wBACzB,eACA,SAHoB,iBAAiB,CAKtC;AAED,KACE,uBAAuB,UACvB,OAAO,uBAAuB,UAE9B,QACE,0CAAE,uFAGC;CAIP,MAAM,QAAQ,QAAQ;CACtB,MAAM,QAAQ,sBAAsB;AAEpC,QACE,oBAAC,UAAD;EACE,MAAK;EACL,WAAW,GACT,8CACA,2DACA,UAAU,KAAK,oBACf,SAAS,KAAK,GACf;EACD,UAAU,MAAM;AACd,KAAE,iBAAiB;AACnB,kBAAe,QAAQ;;YAGzB,oBAAC,gBAAD;GACS;GACP,WAAW,aACT,gBAAgB;IAAE;IAAS,UAAU,OAAO,SAAS;IAAE,CAAC;GAE1D;EACK"}
1
+ {"version":3,"file":"BooleanWrapper.mjs","names":[],"sources":["../../../../../src/components/DictionaryEditor/NodeWrapper/BooleanWrapper.tsx"],"sourcesContent":["'use client';\n\nimport { getContentNodeByKeyPath } from '@intlayer/core/dictionaryManipulator';\nimport { useEditorLocale } from '@intlayer/editor-react';\nimport { cn } from '@utils/cn';\nimport type { FC } from 'react';\nimport { SwitchSelector } from '../../SwitchSelector';\nimport type { NodeWrapperProps } from './index';\n\nexport type BooleanWrapperProps = Omit<NodeWrapperProps, 'section'> & {\n section: boolean;\n};\n\nexport const BooleanWrapper: FC<BooleanWrapperProps> = ({\n keyPath,\n section,\n editedContent,\n onContentChange,\n onFocusKeyPath,\n}) => {\n const currentLocale = useEditorLocale();\n const editedContentValue = getContentNodeByKeyPath(\n editedContent,\n keyPath,\n currentLocale\n );\n\n if (\n editedContentValue !== undefined &&\n typeof editedContentValue !== 'boolean'\n ) {\n return (\n <>\n Error loading section - Edited content incoherence with the original\n content format\n </>\n );\n }\n\n const level = keyPath.length;\n const value = editedContentValue ?? section;\n\n return (\n <button\n type=\"button\"\n className={cn(\n 'w-full rounded-md p-2 text-left transition',\n 'hover:bg-card/30 [&:has(.section:hover)]:bg-transparent',\n level === 2 && 'hover:bg-card/30',\n level >= 3 && ''\n )}\n onClick={(e) => {\n e.stopPropagation();\n onFocusKeyPath(keyPath);\n }}\n >\n <SwitchSelector\n value={value}\n onChange={(newValue) =>\n onContentChange({ keyPath, newValue: String(newValue) })\n }\n />\n </button>\n );\n};\n"],"mappings":";;;;;;;;;AAaA,MAAa,kBAA2C,EACtD,SACA,SACA,eACA,iBACA,qBACI;CAEJ,MAAM,qBAAqB,wBACzB,eACA,SAHoB,iBAIP,CACd;AAED,KACE,uBAAuB,UACvB,OAAO,uBAAuB,UAE9B,QACE,0CAAE,uFAGC;CAIP,MAAM,QAAQ,QAAQ;CACtB,MAAM,QAAQ,sBAAsB;AAEpC,QACE,oBAAC,UAAD;EACE,MAAK;EACL,WAAW,GACT,8CACA,2DACA,UAAU,KAAK,oBACf,SAAS,KAAK,GACf;EACD,UAAU,MAAM;AACd,KAAE,iBAAiB;AACnB,kBAAe,QAAQ;;YAGzB,oBAAC,gBAAD;GACS;GACP,WAAW,aACT,gBAAgB;IAAE;IAAS,UAAU,OAAO,SAAS;IAAE,CAAC;GAE1D;EACK"}
@@ -1 +1 @@
1
- {"version":3,"file":"NestedObjectWrapper.mjs","names":[],"sources":["../../../../../src/components/DictionaryEditor/NodeWrapper/NestedObjectWrapper.tsx"],"sourcesContent":["import { camelCaseToSentence } from '@intlayer/config/client';\nimport { isSameKeyPath } from '@intlayer/core/utils';\nimport type { ContentNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\n\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { type FC, memo, useMemo } from 'react';\nimport { ItemLayout } from '../ItemLayout';\nimport { NodeWrapper, type NodeWrapperProps, traceKeys } from './index';\n\ntype NestedObjectWrapperProps = Omit<NodeWrapperProps, 'section'> & {\n section: Record<string, ContentNode>;\n};\n\nexport const NestedObjectWrapper: FC<NestedObjectWrapperProps> = memo(\n (props) => {\n const { keyPath, section, focusedKeyPath = [], onFocusKeyPath } = props;\n\n const sectionKeys = useMemo(\n () =>\n Object.keys(section ?? {}).filter((key) => !traceKeys.includes(key)),\n [section]\n );\n\n return sectionKeys.map((key) => {\n const newKeyPathEl: KeyPath = { key, type: NodeTypes.OBJECT };\n const newKeyPath: KeyPath[] = [...keyPath, newKeyPathEl];\n\n const isSelected = isSameKeyPath(newKeyPath, focusedKeyPath);\n\n return (\n <ItemLayout\n level={keyPath.length}\n key={key}\n title={camelCaseToSentence(key)}\n description=\"\"\n isSelected={isSelected}\n onClick={(e) => {\n e.stopPropagation();\n\n if (isSelected) {\n onFocusKeyPath([]);\n } else {\n onFocusKeyPath(newKeyPath);\n }\n }}\n >\n <NodeWrapper {...props} keyPath={newKeyPath} section={section[key]} />\n </ItemLayout>\n );\n });\n }\n);\n"],"mappings":";;;;;;;;;AAcA,MAAa,sBAAoD,MAC9D,UAAU;CACT,MAAM,EAAE,SAAS,SAAS,iBAAiB,EAAE,EAAE,mBAAmB;AAQlE,QANoB,cAEhB,OAAO,KAAK,WAAW,EAAE,CAAC,CAAC,QAAQ,QAAQ,CAAC,UAAU,SAAS,IAAI,CAAC,EACtE,CAAC,QAAQ,CACV,CAEkB,KAAK,QAAQ;EAC9B,MAAM,eAAwB;GAAE;GAAK,MAAM,UAAU;GAAQ;EAC7D,MAAM,aAAwB,CAAC,GAAG,SAAS,aAAa;EAExD,MAAM,aAAa,cAAc,YAAY,eAAe;AAE5D,SACE,oBAAC,YAAD;GACE,OAAO,QAAQ;GAEf,OAAO,oBAAoB,IAAI;GAC/B,aAAY;GACA;GACZ,UAAU,MAAM;AACd,MAAE,iBAAiB;AAEnB,QAAI,WACF,gBAAe,EAAE,CAAC;QAElB,gBAAe,WAAW;;aAI9B,oBAAC,aAAD;IAAa,GAAI;IAAO,SAAS;IAAY,SAAS,QAAQ;IAAQ;GAC3D,EAfN,IAeM;GAEf;EAEL"}
1
+ {"version":3,"file":"NestedObjectWrapper.mjs","names":[],"sources":["../../../../../src/components/DictionaryEditor/NodeWrapper/NestedObjectWrapper.tsx"],"sourcesContent":["import { camelCaseToSentence } from '@intlayer/config/client';\nimport { isSameKeyPath } from '@intlayer/core/utils';\nimport type { ContentNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\n\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { type FC, memo, useMemo } from 'react';\nimport { ItemLayout } from '../ItemLayout';\nimport { NodeWrapper, type NodeWrapperProps, traceKeys } from './index';\n\ntype NestedObjectWrapperProps = Omit<NodeWrapperProps, 'section'> & {\n section: Record<string, ContentNode>;\n};\n\nexport const NestedObjectWrapper: FC<NestedObjectWrapperProps> = memo(\n (props) => {\n const { keyPath, section, focusedKeyPath = [], onFocusKeyPath } = props;\n\n const sectionKeys = useMemo(\n () =>\n Object.keys(section ?? {}).filter((key) => !traceKeys.includes(key)),\n [section]\n );\n\n return sectionKeys.map((key) => {\n const newKeyPathEl: KeyPath = { key, type: NodeTypes.OBJECT };\n const newKeyPath: KeyPath[] = [...keyPath, newKeyPathEl];\n\n const isSelected = isSameKeyPath(newKeyPath, focusedKeyPath);\n\n return (\n <ItemLayout\n level={keyPath.length}\n key={key}\n title={camelCaseToSentence(key)}\n description=\"\"\n isSelected={isSelected}\n onClick={(e) => {\n e.stopPropagation();\n\n if (isSelected) {\n onFocusKeyPath([]);\n } else {\n onFocusKeyPath(newKeyPath);\n }\n }}\n >\n <NodeWrapper {...props} keyPath={newKeyPath} section={section[key]} />\n </ItemLayout>\n );\n });\n }\n);\n"],"mappings":";;;;;;;;;AAcA,MAAa,sBAAoD,MAC9D,UAAU;CACT,MAAM,EAAE,SAAS,SAAS,iBAAiB,EAAE,EAAE,mBAAmB;AAQlE,QANoB,cAEhB,OAAO,KAAK,WAAW,EAAE,CAAC,CAAC,QAAQ,QAAQ,CAAC,UAAU,SAAS,IAAI,CAAC,EACtE,CAAC,QAAQ,CAGO,CAAC,KAAK,QAAQ;EAC9B,MAAM,eAAwB;GAAE;GAAK,MAAM,UAAU;GAAQ;EAC7D,MAAM,aAAwB,CAAC,GAAG,SAAS,aAAa;EAExD,MAAM,aAAa,cAAc,YAAY,eAAe;AAE5D,SACE,oBAAC,YAAD;GACE,OAAO,QAAQ;GAEf,OAAO,oBAAoB,IAAI;GAC/B,aAAY;GACA;GACZ,UAAU,MAAM;AACd,MAAE,iBAAiB;AAEnB,QAAI,WACF,gBAAe,EAAE,CAAC;QAElB,gBAAe,WAAW;;aAI9B,oBAAC,aAAD;IAAa,GAAI;IAAO,SAAS;IAAY,SAAS,QAAQ;IAAQ;GAC3D,EAfN,IAeM;GAEf;EAEL"}
@@ -1 +1 @@
1
- {"version":3,"file":"NumberWrapper.mjs","names":[],"sources":["../../../../../src/components/DictionaryEditor/NodeWrapper/NumberWrapper.tsx"],"sourcesContent":["import { EditableFieldInput } from '@components/EditableField';\nimport { getContentNodeByKeyPath } from '@intlayer/core/dictionaryManipulator';\nimport { useEditorLocale } from '@intlayer/editor-react';\nimport { cn } from '@utils/cn';\nimport type { FC } from 'react';\nimport type { NodeWrapperProps } from './index';\n\nexport type NumberWrapperProps = Omit<NodeWrapperProps, 'section'> & {\n section: number;\n};\n\nexport const NumberWrapper: FC<NumberWrapperProps> = ({\n keyPath,\n section,\n editedContent,\n onContentChange,\n onFocusKeyPath,\n}) => {\n const currentLocale = useEditorLocale();\n const editedContentValue = getContentNodeByKeyPath(\n editedContent,\n keyPath,\n currentLocale\n );\n\n if (\n editedContentValue !== undefined &&\n typeof editedContentValue !== 'number'\n ) {\n return (\n <>\n Error loading section - Edited content incoherence with the original\n content format\n </>\n );\n }\n\n const level = keyPath.length;\n const content = String(editedContentValue ?? section);\n\n return (\n <button\n type=\"button\"\n className={cn(\n 'w-full rounded-md p-2 text-left transition',\n 'hover:bg-card/30 [&:has(.section:hover)]:bg-transparent',\n level === 2 && 'hover:bg-card/30',\n level >= 3 && ''\n )}\n onClick={(e) => {\n e.stopPropagation();\n onFocusKeyPath(keyPath);\n }}\n >\n <EditableFieldInput\n aria-label=\"Editable number field\"\n type=\"number\"\n defaultValue={content}\n onSave={(newValue) => onContentChange({ keyPath, newValue })}\n onCancel={() => null}\n />\n </button>\n );\n};\n"],"mappings":";;;;;;;AAWA,MAAa,iBAAyC,EACpD,SACA,SACA,eACA,iBACA,qBACI;CAEJ,MAAM,qBAAqB,wBACzB,eACA,SAHoB,iBAAiB,CAKtC;AAED,KACE,uBAAuB,UACvB,OAAO,uBAAuB,SAE9B,QACE,0CAAE,uFAGC;CAIP,MAAM,QAAQ,QAAQ;CACtB,MAAM,UAAU,OAAO,sBAAsB,QAAQ;AAErD,QACE,oBAAC,UAAD;EACE,MAAK;EACL,WAAW,GACT,8CACA,2DACA,UAAU,KAAK,oBACf,SAAS,KAAK,GACf;EACD,UAAU,MAAM;AACd,KAAE,iBAAiB;AACnB,kBAAe,QAAQ;;YAGzB,oBAAC,oBAAD;GACE,cAAW;GACX,MAAK;GACL,cAAc;GACd,SAAS,aAAa,gBAAgB;IAAE;IAAS;IAAU,CAAC;GAC5D,gBAAgB;GAChB;EACK"}
1
+ {"version":3,"file":"NumberWrapper.mjs","names":[],"sources":["../../../../../src/components/DictionaryEditor/NodeWrapper/NumberWrapper.tsx"],"sourcesContent":["import { EditableFieldInput } from '@components/EditableField';\nimport { getContentNodeByKeyPath } from '@intlayer/core/dictionaryManipulator';\nimport { useEditorLocale } from '@intlayer/editor-react';\nimport { cn } from '@utils/cn';\nimport type { FC } from 'react';\nimport type { NodeWrapperProps } from './index';\n\nexport type NumberWrapperProps = Omit<NodeWrapperProps, 'section'> & {\n section: number;\n};\n\nexport const NumberWrapper: FC<NumberWrapperProps> = ({\n keyPath,\n section,\n editedContent,\n onContentChange,\n onFocusKeyPath,\n}) => {\n const currentLocale = useEditorLocale();\n const editedContentValue = getContentNodeByKeyPath(\n editedContent,\n keyPath,\n currentLocale\n );\n\n if (\n editedContentValue !== undefined &&\n typeof editedContentValue !== 'number'\n ) {\n return (\n <>\n Error loading section - Edited content incoherence with the original\n content format\n </>\n );\n }\n\n const level = keyPath.length;\n const content = String(editedContentValue ?? section);\n\n return (\n <button\n type=\"button\"\n className={cn(\n 'w-full rounded-md p-2 text-left transition',\n 'hover:bg-card/30 [&:has(.section:hover)]:bg-transparent',\n level === 2 && 'hover:bg-card/30',\n level >= 3 && ''\n )}\n onClick={(e) => {\n e.stopPropagation();\n onFocusKeyPath(keyPath);\n }}\n >\n <EditableFieldInput\n aria-label=\"Editable number field\"\n type=\"number\"\n defaultValue={content}\n onSave={(newValue) => onContentChange({ keyPath, newValue })}\n onCancel={() => null}\n />\n </button>\n );\n};\n"],"mappings":";;;;;;;AAWA,MAAa,iBAAyC,EACpD,SACA,SACA,eACA,iBACA,qBACI;CAEJ,MAAM,qBAAqB,wBACzB,eACA,SAHoB,iBAIP,CACd;AAED,KACE,uBAAuB,UACvB,OAAO,uBAAuB,SAE9B,QACE,0CAAE,uFAGC;CAIP,MAAM,QAAQ,QAAQ;CACtB,MAAM,UAAU,OAAO,sBAAsB,QAAQ;AAErD,QACE,oBAAC,UAAD;EACE,MAAK;EACL,WAAW,GACT,8CACA,2DACA,UAAU,KAAK,oBACf,SAAS,KAAK,GACf;EACD,UAAU,MAAM;AACd,KAAE,iBAAiB;AACnB,kBAAe,QAAQ;;YAGzB,oBAAC,oBAAD;GACE,cAAW;GACX,MAAK;GACL,cAAc;GACd,SAAS,aAAa,gBAAgB;IAAE;IAAS;IAAU,CAAC;GAC5D,gBAAgB;GAChB;EACK"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/components/DictionaryEditor/NodeWrapper/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n getContentNodeByKeyPath,\n getNodeType,\n} from '@intlayer/core/dictionaryManipulator';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n HTMLContent,\n InsertionContent,\n MarkdownContent,\n TranslationContent,\n} from '@intlayer/core/transpiler';\nimport { useEditorLocale } 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 * as NodeTypes from '@intlayer/types/nodeType';\nimport { type FC, memo, type ReactNode, useMemo } from 'react';\nimport { ArrayWrapper } from './ArrayWrapper';\nimport { BooleanWrapper } from './BooleanWrapper';\nimport { ConditionWrapper } from './ConditionWrapper';\nimport { EnumerationWrapper } from './EnumerationWrapper';\nimport { FileWrapper } from './FileWrapper';\nimport { HtmlWrapper } from './HtmlWrapper';\nimport { InsertionWrapper } from './InsertionWrapper';\nimport { MarkdownWrapper } from './MarkdownWrapper';\nimport { NestedObjectWrapper } from './NestedObjectWrapper';\nimport { NumberWrapper } from './NumberWrapper';\nimport { StringWrapper } from './StringWrapper';\nimport { TranslationWrapper } from './TranslationWrapper';\n\nexport const traceKeys: string[] = ['filePath', 'id', 'nodeType'];\n\nexport type NodeWrapperProps = {\n keyPath: KeyPath[];\n dictionary: Dictionary;\n section: ContentNode;\n onContentChange: (content: { keyPath: KeyPath[]; newValue: string }) => void;\n locale: Locale;\n editedContent: ContentNode;\n focusedKeyPath: KeyPath[] | undefined;\n onFocusKeyPath: (keyPath: KeyPath[]) => void;\n onClickEdit?: (keyPath: KeyPath[]) => void;\n renderSection?: (content: string) => ReactNode;\n};\n\nexport const NodeWrapper: FC<NodeWrapperProps> = memo((props) => {\n const currentLocale = useEditorLocale();\n const section = useMemo(() => {\n const editedContentValue = getContentNodeByKeyPath(\n props.editedContent,\n props.keyPath,\n currentLocale\n );\n return editedContentValue ?? props.section;\n }, [props.editedContent, props.keyPath, props.section]);\n\n const nodeType = useMemo(() => getNodeType(section), [section]);\n\n if (typeof section === 'object') {\n if (nodeType === NodeTypes.REACT_NODE) {\n return (\n <span className=\"text-neutral text-xs\">React node not editable</span>\n );\n }\n\n if (nodeType === NodeTypes.NESTED) {\n return (\n <div className=\"ml-2 grid grid-cols-[auto,1fr] gap-2\">\n [Nested] Dictionary\n </div>\n );\n }\n\n if (nodeType === NodeTypes.MARKDOWN) {\n return (\n <MarkdownWrapper\n {...props}\n section={section as MarkdownContent<ContentNode>}\n />\n );\n }\n\n if (nodeType === NodeTypes.HTML) {\n return (\n <HtmlWrapper {...props} section={section as HTMLContent<ContentNode>} />\n );\n }\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return (\n <TranslationWrapper\n {...props}\n section={section as TranslationContent<ContentNode>}\n />\n );\n }\n\n if (nodeType === NodeTypes.ENUMERATION) {\n return (\n <EnumerationWrapper\n {...props}\n section={section as EnumerationContent<ContentNode>}\n />\n );\n }\n\n if (nodeType === NodeTypes.CONDITION) {\n return (\n <ConditionWrapper\n {...props}\n section={section as ConditionContent<ContentNode>}\n />\n );\n }\n\n if (nodeType === NodeTypes.INSERTION) {\n return (\n <InsertionWrapper\n {...props}\n section={section as InsertionContent<ContentNode>}\n />\n );\n }\n\n if (nodeType === NodeTypes.ARRAY) {\n return (\n <ArrayWrapper\n {...props}\n section={section as unknown as ContentNode[]}\n />\n );\n }\n\n if (nodeType === NodeTypes.FILE) {\n return <FileWrapper {...props} section={section as FileContent} />;\n }\n\n return (\n <NestedObjectWrapper\n {...props}\n section={section as unknown as Record<string, ContentNode>}\n />\n );\n }\n\n if (typeof section === 'string') {\n return <StringWrapper {...props} section={section} />;\n }\n\n if (typeof section === 'number') {\n return <NumberWrapper {...props} section={section} />;\n }\n\n if (typeof section === 'boolean') {\n return <BooleanWrapper {...props} section={section} />;\n }\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAkCA,MAAa,YAAsB;CAAC;CAAY;CAAM;CAAW;AAejE,MAAa,cAAoC,MAAM,UAAU;CAC/D,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,UAAU,cAAc;AAM5B,SAL2B,wBACzB,MAAM,eACN,MAAM,SACN,cACD,IAC4B,MAAM;IAClC;EAAC,MAAM;EAAe,MAAM;EAAS,MAAM;EAAQ,CAAC;CAEvD,MAAM,WAAW,cAAc,YAAY,QAAQ,EAAE,CAAC,QAAQ,CAAC;AAE/D,KAAI,OAAO,YAAY,UAAU;AAC/B,MAAI,aAAa,UAAU,WACzB,QACE,oBAAC,QAAD;GAAM,WAAU;aAAuB;GAA8B;AAIzE,MAAI,aAAa,UAAU,OACzB,QACE,oBAAC,OAAD;GAAK,WAAU;aAAuC;GAEhD;AAIV,MAAI,aAAa,UAAU,SACzB,QACE,oBAAC,iBAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,KACzB,QACE,oBAAC,aAAD;GAAa,GAAI;GAAgB;GAAuC;AAI5E,MAAI,aAAa,UAAU,YACzB,QACE,oBAAC,oBAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,YACzB,QACE,oBAAC,oBAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,UACzB,QACE,oBAAC,kBAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,UACzB,QACE,oBAAC,kBAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,MACzB,QACE,oBAAC,cAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,KACzB,QAAO,oBAAC,aAAD;GAAa,GAAI;GAAgB;GAA0B;AAGpE,SACE,oBAAC,qBAAD;GACE,GAAI;GACK;GACT;;AAIN,KAAI,OAAO,YAAY,SACrB,QAAO,oBAAC,eAAD;EAAe,GAAI;EAAgB;EAAW;AAGvD,KAAI,OAAO,YAAY,SACrB,QAAO,oBAAC,eAAD;EAAe,GAAI;EAAgB;EAAW;AAGvD,KAAI,OAAO,YAAY,UACrB,QAAO,oBAAC,gBAAD;EAAgB,GAAI;EAAgB;EAAW;EAExD"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../src/components/DictionaryEditor/NodeWrapper/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n getContentNodeByKeyPath,\n getNodeType,\n} from '@intlayer/core/dictionaryManipulator';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n HTMLContent,\n InsertionContent,\n MarkdownContent,\n TranslationContent,\n} from '@intlayer/core/transpiler';\nimport { useEditorLocale } 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 * as NodeTypes from '@intlayer/types/nodeType';\nimport { type FC, memo, type ReactNode, useMemo } from 'react';\nimport { ArrayWrapper } from './ArrayWrapper';\nimport { BooleanWrapper } from './BooleanWrapper';\nimport { ConditionWrapper } from './ConditionWrapper';\nimport { EnumerationWrapper } from './EnumerationWrapper';\nimport { FileWrapper } from './FileWrapper';\nimport { HtmlWrapper } from './HtmlWrapper';\nimport { InsertionWrapper } from './InsertionWrapper';\nimport { MarkdownWrapper } from './MarkdownWrapper';\nimport { NestedObjectWrapper } from './NestedObjectWrapper';\nimport { NumberWrapper } from './NumberWrapper';\nimport { StringWrapper } from './StringWrapper';\nimport { TranslationWrapper } from './TranslationWrapper';\n\nexport const traceKeys: string[] = ['filePath', 'id', 'nodeType'];\n\nexport type NodeWrapperProps = {\n keyPath: KeyPath[];\n dictionary: Dictionary;\n section: ContentNode;\n onContentChange: (content: { keyPath: KeyPath[]; newValue: string }) => void;\n locale: Locale;\n editedContent: ContentNode;\n focusedKeyPath: KeyPath[] | undefined;\n onFocusKeyPath: (keyPath: KeyPath[]) => void;\n onClickEdit?: (keyPath: KeyPath[]) => void;\n renderSection?: (content: string) => ReactNode;\n};\n\nexport const NodeWrapper: FC<NodeWrapperProps> = memo((props) => {\n const currentLocale = useEditorLocale();\n const section = useMemo(() => {\n const editedContentValue = getContentNodeByKeyPath(\n props.editedContent,\n props.keyPath,\n currentLocale\n );\n return editedContentValue ?? props.section;\n }, [props.editedContent, props.keyPath, props.section]);\n\n const nodeType = useMemo(() => getNodeType(section), [section]);\n\n if (typeof section === 'object') {\n if (nodeType === NodeTypes.REACT_NODE) {\n return (\n <span className=\"text-neutral text-xs\">React node not editable</span>\n );\n }\n\n if (nodeType === NodeTypes.NESTED) {\n return (\n <div className=\"ml-2 grid grid-cols-[auto,1fr] gap-2\">\n [Nested] Dictionary\n </div>\n );\n }\n\n if (nodeType === NodeTypes.MARKDOWN) {\n return (\n <MarkdownWrapper\n {...props}\n section={section as MarkdownContent<ContentNode>}\n />\n );\n }\n\n if (nodeType === NodeTypes.HTML) {\n return (\n <HtmlWrapper {...props} section={section as HTMLContent<ContentNode>} />\n );\n }\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return (\n <TranslationWrapper\n {...props}\n section={section as TranslationContent<ContentNode>}\n />\n );\n }\n\n if (nodeType === NodeTypes.ENUMERATION) {\n return (\n <EnumerationWrapper\n {...props}\n section={section as EnumerationContent<ContentNode>}\n />\n );\n }\n\n if (nodeType === NodeTypes.CONDITION) {\n return (\n <ConditionWrapper\n {...props}\n section={section as ConditionContent<ContentNode>}\n />\n );\n }\n\n if (nodeType === NodeTypes.INSERTION) {\n return (\n <InsertionWrapper\n {...props}\n section={section as InsertionContent<ContentNode>}\n />\n );\n }\n\n if (nodeType === NodeTypes.ARRAY) {\n return (\n <ArrayWrapper\n {...props}\n section={section as unknown as ContentNode[]}\n />\n );\n }\n\n if (nodeType === NodeTypes.FILE) {\n return <FileWrapper {...props} section={section as FileContent} />;\n }\n\n return (\n <NestedObjectWrapper\n {...props}\n section={section as unknown as Record<string, ContentNode>}\n />\n );\n }\n\n if (typeof section === 'string') {\n return <StringWrapper {...props} section={section} />;\n }\n\n if (typeof section === 'number') {\n return <NumberWrapper {...props} section={section} />;\n }\n\n if (typeof section === 'boolean') {\n return <BooleanWrapper {...props} section={section} />;\n }\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAkCA,MAAa,YAAsB;CAAC;CAAY;CAAM;CAAW;AAejE,MAAa,cAAoC,MAAM,UAAU;CAC/D,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,UAAU,cAAc;AAM5B,SAL2B,wBACzB,MAAM,eACN,MAAM,SACN,cAEuB,IAAI,MAAM;IAClC;EAAC,MAAM;EAAe,MAAM;EAAS,MAAM;EAAQ,CAAC;CAEvD,MAAM,WAAW,cAAc,YAAY,QAAQ,EAAE,CAAC,QAAQ,CAAC;AAE/D,KAAI,OAAO,YAAY,UAAU;AAC/B,MAAI,aAAa,UAAU,WACzB,QACE,oBAAC,QAAD;GAAM,WAAU;aAAuB;GAA8B;AAIzE,MAAI,aAAa,UAAU,OACzB,QACE,oBAAC,OAAD;GAAK,WAAU;aAAuC;GAEhD;AAIV,MAAI,aAAa,UAAU,SACzB,QACE,oBAAC,iBAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,KACzB,QACE,oBAAC,aAAD;GAAa,GAAI;GAAgB;GAAuC;AAI5E,MAAI,aAAa,UAAU,YACzB,QACE,oBAAC,oBAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,YACzB,QACE,oBAAC,oBAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,UACzB,QACE,oBAAC,kBAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,UACzB,QACE,oBAAC,kBAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,MACzB,QACE,oBAAC,cAAD;GACE,GAAI;GACK;GACT;AAIN,MAAI,aAAa,UAAU,KACzB,QAAO,oBAAC,aAAD;GAAa,GAAI;GAAgB;GAA0B;AAGpE,SACE,oBAAC,qBAAD;GACE,GAAI;GACK;GACT;;AAIN,KAAI,OAAO,YAAY,SACrB,QAAO,oBAAC,eAAD;EAAe,GAAI;EAAgB;EAAW;AAGvD,KAAI,OAAO,YAAY,SACrB,QAAO,oBAAC,eAAD;EAAe,GAAI;EAAgB;EAAW;AAGvD,KAAI,OAAO,YAAY,UACrB,QAAO,oBAAC,gBAAD;EAAgB,GAAI;EAAgB;EAAW;EAExD"}
@@ -1,12 +1,12 @@
1
1
  'use client';
2
2
 
3
+ import { useAuditContentDeclarationField } from "../../../hooks/reactQuery.mjs";
3
4
  import { Container } from "../../Container/index.mjs";
4
5
  import { Button, ButtonColor, ButtonSize, ButtonTextAlign, ButtonVariant } from "../../Button/Button.mjs";
5
6
  import { InputVariant } from "../../Input/Input.mjs";
6
7
  import { SwitchSelector, SwitchSelectorColor, SwitchSelectorSize } from "../../SwitchSelector/index.mjs";
7
8
  import { useLocaleSwitcherContent } from "../../LocaleSwitcherContentDropDown/LocaleSwitcherContentContext.mjs";
8
9
  import { ContentEditorInput as ContentEditorInput$1 } from "../../ContentEditor/ContentEditorInput.mjs";
9
- import { useAuditContentDeclarationField } from "../../../hooks/reactQuery.mjs";
10
10
  import { ContentEditorTextArea as ContentEditorTextArea$1 } from "../../ContentEditor/ContentEditorTextArea.mjs";
11
11
  import { renameKey } from "./object.mjs";
12
12
  import { Label } from "../../Label/index.mjs";
@@ -15,9 +15,9 @@ import { EnumKeyInput } from "../EnumKeyInput.mjs";
15
15
  import { Fragment, useState } from "react";
16
16
  import { Plus, Trash, WandSparkles } from "lucide-react";
17
17
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
18
+ import { useConfiguration, useEditedContent } from "@intlayer/editor-react";
18
19
  import { useIntlayer, useLocale } from "react-intlayer";
19
20
  import { getLocaleName } from "@intlayer/core/localization";
20
- import { useConfiguration, useEditedContent } from "@intlayer/editor-react";
21
21
  import { getEmptyNode, getNodeType } from "@intlayer/core/dictionaryManipulator";
22
22
  import * as NodeTypes from "@intlayer/types/nodeType";
23
23
 
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { ButtonColor } from "../../Button/Button.mjs";
4
3
  import { useSession } from "../../../hooks/useAuth/useSession.mjs";
5
4
  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";
3
5
  import { Loader } from "../../Loader/index.mjs";
4
6
  import { ButtonColor, ButtonSize, ButtonVariant } from "../../Button/Button.mjs";
5
7
  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 { useIntlayer } from "react-intlayer";
17
16
  import { useEditedContent } from "@intlayer/editor-react";
17
+ import { useIntlayer } from "react-intlayer";
18
18
  import { AnimatePresence, motion } from "framer-motion";
19
19
  import { useWatch } from "react-hook-form";
20
20
 
@@ -12,8 +12,8 @@ import { StructureEditor } from "./StructureEditor.mjs";
12
12
  import { useEffect } from "react";
13
13
  import { ArrowLeft } from "lucide-react";
14
14
  import { jsx, jsxs } from "react/jsx-runtime";
15
- import { useIntlayer } from "react-intlayer";
16
15
  import { useConfiguration, useDictionariesRecordActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
16
+ import { useIntlayer } from "react-intlayer";
17
17
 
18
18
  //#region src/components/DictionaryFieldEditor/DictionaryFieldEditor.tsx
19
19
  const DictionaryFieldEditor = ({ dictionary, onClickDictionaryList, isDarkMode, mode, onDelete, onSave, showReturnButton = true }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"EnumKeyInput.mjs","names":[],"sources":["../../../../src/components/DictionaryFieldEditor/EnumKeyInput.tsx"],"sourcesContent":["'use client';\n\nimport { type FC, useEffect, useMemo, useState } from 'react';\nimport { Input } from '../Input';\nimport { Select } from '../Select';\n\nconst extractInitialState = (\n value: string | number\n): { comparator: string | undefined; numberValue: string | undefined } => {\n let comparator: string | undefined;\n let numberValue: string | undefined;\n\n if (typeof value === 'number' || !Number.isNaN(Number(value))) {\n // If value is a number or numeric string, set comparator to '=' and numberValue accordingly\n comparator = '=';\n numberValue = value.toString();\n } else if (typeof value === 'string') {\n // Define possible comparators\n const comparators = ['<=', '>=', '<', '>', '='];\n // Find the comparator that matches the start of the string\n const matchedComparator = comparators.find((comp) =>\n value.startsWith(comp)\n );\n if (matchedComparator) {\n comparator = matchedComparator;\n numberValue = value.slice(matchedComparator.length);\n }\n }\n\n return { comparator, numberValue };\n};\n\ntype EnumKeyInputProps = {\n value: string | number;\n onChange: (value: string) => void;\n};\n\n/**\n * Example of values:\n * - `<1`\n * - `>-44.3`\n * - `=999`\n * - `<=1`\n * - `>=1`\n * - 88\n * - `-1`\n *\n */\nexport const EnumKeyInput: FC<EnumKeyInputProps> = ({ value, onChange }) => {\n const { comparator: initialComparator, numberValue: initialNumberValue } =\n useMemo(() => extractInitialState(value), [value]);\n const [comparator, setComparator] = useState<string | null>(\n initialComparator ?? null\n );\n const [numberValue, setNumberValue] = useState<string | null>(\n initialNumberValue ?? null\n );\n\n useEffect(() => {\n if (\n comparator &&\n numberValue &&\n (comparator !== initialComparator || numberValue !== initialNumberValue)\n ) {\n const newValue = `${comparator}${numberValue}`;\n\n onChange(newValue);\n }\n }, [\n comparator,\n initialComparator,\n initialNumberValue,\n numberValue,\n onChange,\n ]);\n\n return (\n <div className=\"flex gap-1\">\n <Select onValueChange={setComparator} defaultValue={initialComparator}>\n <Select.Trigger className=\"w-20\">\n <Select.Value placeholder=\"Select a comparator\" />\n </Select.Trigger>\n <Select.Content>\n <Select.Item value=\"<\">{`<`}</Select.Item>\n <Select.Item value=\"<=\">{`<=`}</Select.Item>\n <Select.Item value=\"=\">{`=`}</Select.Item>\n <Select.Item value=\">=\">{`>=`}</Select.Item>\n <Select.Item value=\">\">{`>`}</Select.Item>\n </Select.Content>\n </Select>\n <Input\n type=\"number\"\n aria-label=\"Quantity\"\n defaultValue={numberValue ?? undefined}\n onChange={(e) => setNumberValue(e.target.value)}\n className=\"min-w-4\"\n />\n </div>\n );\n};\n"],"mappings":";;;;;;;;AAMA,MAAM,uBACJ,UACwE;CACxE,IAAI;CACJ,IAAI;AAEJ,KAAI,OAAO,UAAU,YAAY,CAAC,OAAO,MAAM,OAAO,MAAM,CAAC,EAAE;AAE7D,eAAa;AACb,gBAAc,MAAM,UAAU;YACrB,OAAO,UAAU,UAAU;EAIpC,MAAM,oBAFc;GAAC;GAAM;GAAM;GAAK;GAAK;GAAI,CAET,MAAM,SAC1C,MAAM,WAAW,KAAK,CACvB;AACD,MAAI,mBAAmB;AACrB,gBAAa;AACb,iBAAc,MAAM,MAAM,kBAAkB,OAAO;;;AAIvD,QAAO;EAAE;EAAY;EAAa;;;;;;;;;;;;;AAmBpC,MAAa,gBAAuC,EAAE,OAAO,eAAe;CAC1E,MAAM,EAAE,YAAY,mBAAmB,aAAa,uBAClD,cAAc,oBAAoB,MAAM,EAAE,CAAC,MAAM,CAAC;CACpD,MAAM,CAAC,YAAY,iBAAiB,SAClC,qBAAqB,KACtB;CACD,MAAM,CAAC,aAAa,kBAAkB,SACpC,sBAAsB,KACvB;AAED,iBAAgB;AACd,MACE,cACA,gBACC,eAAe,qBAAqB,gBAAgB,oBAIrD,UAFiB,GAAG,aAAa,cAEf;IAEnB;EACD;EACA;EACA;EACA;EACA;EACD,CAAC;AAEF,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,QAAD;GAAQ,eAAe;GAAe,cAAc;aAApD,CACE,oBAAC,OAAO,SAAR;IAAgB,WAAU;cACxB,oBAAC,OAAO,OAAR,EAAc,aAAY,uBAAwB;IACnC,GACjB,qBAAC,OAAO,SAAR;IACE,oBAAC,OAAO,MAAR;KAAa,OAAM;eAAK;KAAkB;IAC1C,oBAAC,OAAO,MAAR;KAAa,OAAM;eAAM;KAAmB;IAC5C,oBAAC,OAAO,MAAR;KAAa,OAAM;eAAK;KAAkB;IAC1C,oBAAC,OAAO,MAAR;KAAa,OAAM;eAAM;KAAmB;IAC5C,oBAAC,OAAO,MAAR;KAAa,OAAM;eAAK;KAAkB;IAC3B,IACV;MACT,oBAAC,OAAD;GACE,MAAK;GACL,cAAW;GACX,cAAc,eAAe;GAC7B,WAAW,MAAM,eAAe,EAAE,OAAO,MAAM;GAC/C,WAAU;GACV,EACE"}
1
+ {"version":3,"file":"EnumKeyInput.mjs","names":[],"sources":["../../../../src/components/DictionaryFieldEditor/EnumKeyInput.tsx"],"sourcesContent":["'use client';\n\nimport { type FC, useEffect, useMemo, useState } from 'react';\nimport { Input } from '../Input';\nimport { Select } from '../Select';\n\nconst extractInitialState = (\n value: string | number\n): { comparator: string | undefined; numberValue: string | undefined } => {\n let comparator: string | undefined;\n let numberValue: string | undefined;\n\n if (typeof value === 'number' || !Number.isNaN(Number(value))) {\n // If value is a number or numeric string, set comparator to '=' and numberValue accordingly\n comparator = '=';\n numberValue = value.toString();\n } else if (typeof value === 'string') {\n // Define possible comparators\n const comparators = ['<=', '>=', '<', '>', '='];\n // Find the comparator that matches the start of the string\n const matchedComparator = comparators.find((comp) =>\n value.startsWith(comp)\n );\n if (matchedComparator) {\n comparator = matchedComparator;\n numberValue = value.slice(matchedComparator.length);\n }\n }\n\n return { comparator, numberValue };\n};\n\ntype EnumKeyInputProps = {\n value: string | number;\n onChange: (value: string) => void;\n};\n\n/**\n * Example of values:\n * - `<1`\n * - `>-44.3`\n * - `=999`\n * - `<=1`\n * - `>=1`\n * - 88\n * - `-1`\n *\n */\nexport const EnumKeyInput: FC<EnumKeyInputProps> = ({ value, onChange }) => {\n const { comparator: initialComparator, numberValue: initialNumberValue } =\n useMemo(() => extractInitialState(value), [value]);\n const [comparator, setComparator] = useState<string | null>(\n initialComparator ?? null\n );\n const [numberValue, setNumberValue] = useState<string | null>(\n initialNumberValue ?? null\n );\n\n useEffect(() => {\n if (\n comparator &&\n numberValue &&\n (comparator !== initialComparator || numberValue !== initialNumberValue)\n ) {\n const newValue = `${comparator}${numberValue}`;\n\n onChange(newValue);\n }\n }, [\n comparator,\n initialComparator,\n initialNumberValue,\n numberValue,\n onChange,\n ]);\n\n return (\n <div className=\"flex gap-1\">\n <Select onValueChange={setComparator} defaultValue={initialComparator}>\n <Select.Trigger className=\"w-20\">\n <Select.Value placeholder=\"Select a comparator\" />\n </Select.Trigger>\n <Select.Content>\n <Select.Item value=\"<\">{`<`}</Select.Item>\n <Select.Item value=\"<=\">{`<=`}</Select.Item>\n <Select.Item value=\"=\">{`=`}</Select.Item>\n <Select.Item value=\">=\">{`>=`}</Select.Item>\n <Select.Item value=\">\">{`>`}</Select.Item>\n </Select.Content>\n </Select>\n <Input\n type=\"number\"\n aria-label=\"Quantity\"\n defaultValue={numberValue ?? undefined}\n onChange={(e) => setNumberValue(e.target.value)}\n className=\"min-w-4\"\n />\n </div>\n );\n};\n"],"mappings":";;;;;;;;AAMA,MAAM,uBACJ,UACwE;CACxE,IAAI;CACJ,IAAI;AAEJ,KAAI,OAAO,UAAU,YAAY,CAAC,OAAO,MAAM,OAAO,MAAM,CAAC,EAAE;AAE7D,eAAa;AACb,gBAAc,MAAM,UAAU;YACrB,OAAO,UAAU,UAAU;EAIpC,MAAM,oBAAoB;GAFL;GAAM;GAAM;GAAK;GAAK;GAEN,CAAC,MAAM,SAC1C,MAAM,WAAW,KAAK,CACvB;AACD,MAAI,mBAAmB;AACrB,gBAAa;AACb,iBAAc,MAAM,MAAM,kBAAkB,OAAO;;;AAIvD,QAAO;EAAE;EAAY;EAAa;;;;;;;;;;;;;AAmBpC,MAAa,gBAAuC,EAAE,OAAO,eAAe;CAC1E,MAAM,EAAE,YAAY,mBAAmB,aAAa,uBAClD,cAAc,oBAAoB,MAAM,EAAE,CAAC,MAAM,CAAC;CACpD,MAAM,CAAC,YAAY,iBAAiB,SAClC,qBAAqB,KACtB;CACD,MAAM,CAAC,aAAa,kBAAkB,SACpC,sBAAsB,KACvB;AAED,iBAAgB;AACd,MACE,cACA,gBACC,eAAe,qBAAqB,gBAAgB,oBAIrD,UAAS,GAFW,aAAa,cAEf;IAEnB;EACD;EACA;EACA;EACA;EACA;EACD,CAAC;AAEF,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,QAAD;GAAQ,eAAe;GAAe,cAAc;aAApD,CACE,oBAAC,OAAO,SAAR;IAAgB,WAAU;cACxB,oBAAC,OAAO,OAAR,EAAc,aAAY,uBAAwB;IACnC,GACjB,qBAAC,OAAO,SAAR;IACE,oBAAC,OAAO,MAAR;KAAa,OAAM;eAAK;KAAkB;IAC1C,oBAAC,OAAO,MAAR;KAAa,OAAM;eAAM;KAAmB;IAC5C,oBAAC,OAAO,MAAR;KAAa,OAAM;eAAK;KAAkB;IAC1C,oBAAC,OAAO,MAAR;KAAa,OAAM;eAAM;KAAmB;IAC5C,oBAAC,OAAO,MAAR;KAAa,OAAM;eAAK;KAAkB;IAC3B,IACV;MACT,oBAAC,OAAD;GACE,MAAK;GACL,cAAW;GACX,cAAc,eAAe;GAC7B,WAAW,MAAM,eAAe,EAAE,OAAO,MAAM;GAC/C,WAAU;GACV,EACE"}
@@ -1 +1 @@
1
- {"version":3,"file":"KeyPathBreadcrumb.mjs","names":[],"sources":["../../../../src/components/DictionaryFieldEditor/KeyPathBreadcrumb.tsx"],"sourcesContent":["import { camelCaseToSentence } from '@intlayer/config/client';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { FC } from 'react';\nimport { Breadcrumb, type BreadcrumbLink } from '../Breadcrumb';\nimport type { LinkColor } from '../Link';\n\ntype KeyPathBreadcrumbProps = {\n dictionaryKey: string;\n keyPath: KeyPath[];\n onClickKeyPath?: (keyPath: KeyPath[]) => void;\n locale?: Locale;\n color?: LinkColor | `${LinkColor}`;\n showDictionaryKey?: boolean;\n};\n\nexport const KeyPathBreadcrumb: FC<KeyPathBreadcrumbProps> = ({\n keyPath,\n dictionaryKey,\n onClickKeyPath,\n locale,\n color,\n showDictionaryKey = true,\n}) => {\n const formattedKeyPath: BreadcrumbLink[] = [\n ...(showDictionaryKey\n ? [\n {\n text: camelCaseToSentence(dictionaryKey),\n onClick: onClickKeyPath ? () => onClickKeyPath([]) : undefined,\n },\n ]\n : []),\n ...keyPath.map((el, index) => ({\n onClick: onClickKeyPath\n ? () =>\n // With keyPath = [{type: NodeTypes.Object, key: '0'}, {type: NodeTypes.Array, key: '0'}, {type: NodeTypes.Object, key: '1'}]\n // If index is 0 -> onFocusKeyPath([{type: NodeTypes.Object, key: '0'}])\n // If index is 1 -> onFocusKeyPath([{type: NodeTypes.Object, key: '0'}, {type: NodeTypes.Array, key: '0'}])\n onClickKeyPath?.(keyPath.slice(0, index + 1))\n : undefined,\n\n text: el.key?.toString() ?? '',\n })),\n ];\n\n return (\n <Breadcrumb\n links={formattedKeyPath}\n locale={locale}\n elementType=\"location\"\n color={color}\n />\n );\n};\n"],"mappings":";;;;;AAgBA,MAAa,qBAAiD,EAC5D,SACA,eACA,gBACA,QACA,OACA,oBAAoB,WAChB;AAuBJ,QACE,oBAAC,YAAD;EACE,OAxBuC,CACzC,GAAI,oBACA,CACE;GACE,MAAM,oBAAoB,cAAc;GACxC,SAAS,uBAAuB,eAAe,EAAE,CAAC,GAAG;GACtD,CACF,GACD,EAAE,EACN,GAAG,QAAQ,KAAK,IAAI,WAAW;GAC7B,SAAS,uBAKH,iBAAiB,QAAQ,MAAM,GAAG,QAAQ,EAAE,CAAC,GAC/C;GAEJ,MAAM,GAAG,KAAK,UAAU,IAAI;GAC7B,EAAE,CACJ;EAKW;EACR,aAAY;EACL;EACP"}
1
+ {"version":3,"file":"KeyPathBreadcrumb.mjs","names":[],"sources":["../../../../src/components/DictionaryFieldEditor/KeyPathBreadcrumb.tsx"],"sourcesContent":["import { camelCaseToSentence } from '@intlayer/config/client';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { FC } from 'react';\nimport { Breadcrumb, type BreadcrumbLink } from '../Breadcrumb';\nimport type { LinkColor } from '../Link';\n\ntype KeyPathBreadcrumbProps = {\n dictionaryKey: string;\n keyPath: KeyPath[];\n onClickKeyPath?: (keyPath: KeyPath[]) => void;\n locale?: Locale;\n color?: LinkColor | `${LinkColor}`;\n showDictionaryKey?: boolean;\n};\n\nexport const KeyPathBreadcrumb: FC<KeyPathBreadcrumbProps> = ({\n keyPath,\n dictionaryKey,\n onClickKeyPath,\n locale,\n color,\n showDictionaryKey = true,\n}) => {\n const formattedKeyPath: BreadcrumbLink[] = [\n ...(showDictionaryKey\n ? [\n {\n text: camelCaseToSentence(dictionaryKey),\n onClick: onClickKeyPath ? () => onClickKeyPath([]) : undefined,\n },\n ]\n : []),\n ...keyPath.map((el, index) => ({\n onClick: onClickKeyPath\n ? () =>\n // With keyPath = [{type: NodeTypes.Object, key: '0'}, {type: NodeTypes.Array, key: '0'}, {type: NodeTypes.Object, key: '1'}]\n // If index is 0 -> onFocusKeyPath([{type: NodeTypes.Object, key: '0'}])\n // If index is 1 -> onFocusKeyPath([{type: NodeTypes.Object, key: '0'}, {type: NodeTypes.Array, key: '0'}])\n onClickKeyPath?.(keyPath.slice(0, index + 1))\n : undefined,\n\n text: el.key?.toString() ?? '',\n })),\n ];\n\n return (\n <Breadcrumb\n links={formattedKeyPath}\n locale={locale}\n elementType=\"location\"\n color={color}\n />\n );\n};\n"],"mappings":";;;;;AAgBA,MAAa,qBAAiD,EAC5D,SACA,eACA,gBACA,QACA,OACA,oBAAoB,WAChB;AAuBJ,QACE,oBAAC,YAAD;EACE,OAAO,CAvBT,GAAI,oBACA,CACE;GACE,MAAM,oBAAoB,cAAc;GACxC,SAAS,uBAAuB,eAAe,EAAE,CAAC,GAAG;GACtD,CACF,GACD,EAAE,EACN,GAAG,QAAQ,KAAK,IAAI,WAAW;GAC7B,SAAS,uBAKH,iBAAiB,QAAQ,MAAM,GAAG,QAAQ,EAAE,CAAC,GAC/C;GAEJ,MAAM,GAAG,KAAK,UAAU,IAAI;GAC7B,EAAE,CAKsB;EACf;EACR,aAAY;EACL;EACP"}
@@ -3,13 +3,13 @@ import { Accordion } from "../../Accordion/Accordion.mjs";
3
3
  import { getIsEditableSection } from "../getIsEditableSection.mjs";
4
4
  import { ChevronRight, Plus } from "lucide-react";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
- import { useIntlayer } from "react-intlayer";
6
+ import { internationalization } from "@intlayer/config/built";
7
7
  import { useEditedContentActions, useEditorLocale, useFocusUnmergedDictionary } from "@intlayer/editor-react";
8
+ import { useIntlayer } from "react-intlayer";
8
9
  import { getContentNodeByKeyPath, getEmptyNode, getNodeType } from "@intlayer/core/dictionaryManipulator";
9
10
  import * as NodeTypes from "@intlayer/types/nodeType";
10
11
  import { isSameKeyPath } from "@intlayer/core/utils";
11
12
  import { camelCaseToSentence } from "@intlayer/config/client";
12
- import { internationalization } from "@intlayer/config/built";
13
13
 
14
14
  //#region src/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.tsx
15
15
  const traceKeys = [
@@ -1 +1 @@
1
- {"version":3,"file":"NavigationViewNode.mjs","names":[],"sources":["../../../../../src/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.tsx"],"sourcesContent":["import { Accordion } from '@components/Accordion';\nimport {\n Button,\n ButtonColor,\n ButtonTextAlign,\n ButtonVariant,\n} from '@components/Button';\nimport { internationalization } from '@intlayer/config/built';\nimport { camelCaseToSentence } from '@intlayer/config/client';\nimport {\n getContentNodeByKeyPath,\n getEmptyNode,\n getNodeType,\n} from '@intlayer/core/dictionaryManipulator';\nimport { isSameKeyPath } from '@intlayer/core/utils';\nimport {\n useEditedContentActions,\n useEditorLocale,\n useFocusUnmergedDictionary,\n} from '@intlayer/editor-react';\nimport type { LocalDictionaryId } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { ContentNode, Dictionary } from 'intlayer';\nimport { ChevronRight, Plus } from 'lucide-react';\nimport type { FC } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { getIsEditableSection } from '../getIsEditableSection';\n\nexport const traceKeys: string[] = ['filePath', 'id', 'nodeType'];\n\nexport type NodeWrapperProps = {\n keyPath: KeyPath[];\n section: ContentNode;\n dictionary: Dictionary;\n};\n\nexport const NavigationViewNode: FC<NodeWrapperProps> = ({\n section: sectionProp,\n keyPath,\n dictionary,\n}) => {\n const { locales } = internationalization;\n\n const currentLocale = useEditorLocale();\n const section = getContentNodeByKeyPath(sectionProp, keyPath, currentLocale);\n const { addEditedContent } = useEditedContentActions();\n const { setFocusedContentKeyPath, focusedContent } =\n useFocusUnmergedDictionary();\n const { addNewElement, goToField } = useIntlayer('navigation-view');\n const nodeType = getNodeType(section);\n const getIsSelected = (keyPath: KeyPath[]) =>\n (focusedContent?.keyPath?.length ?? 0) > 0 &&\n isSameKeyPath(keyPath, focusedContent?.keyPath ?? []);\n const isEditableSubSection = getIsEditableSection(section);\n\n if (!section) return <></>;\n\n if (isEditableSubSection) {\n return (\n <Button\n label={goToField.label.value}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n className=\"w-full\"\n onClick={() => setFocusedContentKeyPath(keyPath)}\n IconRight={ChevronRight}\n >\n {camelCaseToSentence(keyPath[keyPath.length - 1].key as string)}\n </Button>\n );\n }\n\n if (typeof section === 'object') {\n if (nodeType === NodeTypes.REACT_NODE) {\n return <>React Node</>;\n }\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return (\n <div className=\"flex flex-col justify-between gap-2\">\n {locales.map((translationKey) => {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: NodeTypes.TRANSLATION, key: translationKey },\n ];\n\n return (\n <NavigationViewNode\n key={translationKey}\n keyPath={childKeyPath}\n section={sectionProp}\n dictionary={dictionary}\n />\n );\n })}\n </div>\n );\n }\n\n if (\n nodeType === NodeTypes.ENUMERATION ||\n nodeType === NodeTypes.CONDITION\n ) {\n return (\n <div className=\"flex flex-col justify-between gap-2\">\n {Object.keys(\n (section as any)[nodeType as unknown as keyof typeof section]\n ).map((key) => {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: nodeType, key },\n ];\n\n return (\n <NavigationViewNode\n key={key}\n keyPath={childKeyPath}\n section={sectionProp}\n dictionary={dictionary}\n />\n );\n })}\n </div>\n );\n }\n\n if (nodeType === NodeTypes.ARRAY) {\n return (\n <div className=\"flex flex-col justify-between gap-2\">\n {(section as unknown as ContentNode[]).map((subSection, index) => {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: NodeTypes.ARRAY, key: index },\n ];\n\n const isEditableSubSection = getIsEditableSection(subSection);\n\n if (isEditableSubSection) {\n return (\n <Button\n key={JSON.stringify(childKeyPath)}\n label={`${goToField.label.value} ${index}`}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n className=\"w-full\"\n onClick={() => setFocusedContentKeyPath(childKeyPath)}\n IconRight={ChevronRight}\n isActive={getIsSelected(childKeyPath)}\n >\n Item {index}\n </Button>\n );\n }\n\n return (\n <Accordion\n key={JSON.stringify(childKeyPath)}\n label={`${goToField.label.value} ${index}`}\n header={`Item ${index}`}\n isActive={getIsSelected(childKeyPath)}\n onClick={() => setFocusedContentKeyPath(childKeyPath)}\n >\n <div className=\"mt-2 flex w-full max-w-full\">\n <div className=\"flex-1 pl-10\">\n <NavigationViewNode\n keyPath={childKeyPath}\n section={sectionProp}\n dictionary={dictionary}\n />\n </div>\n </div>\n </Accordion>\n );\n })}\n\n <Button\n label={addNewElement.label.value}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.NEUTRAL}\n textAlign={ButtonTextAlign.LEFT}\n onClick={() => {\n const newKeyPath: KeyPath[] = [\n ...keyPath,\n {\n type: NodeTypes.ARRAY,\n key: (section as unknown as ContentNode[]).length,\n },\n ];\n const sectionArray = section as unknown as ContentNode[];\n const emptySectionEl =\n getEmptyNode(\n sectionArray[\n (sectionArray.length - 1) as keyof typeof sectionArray\n ] as ContentNode\n ) ?? '';\n addEditedContent(\n dictionary.localId as LocalDictionaryId,\n emptySectionEl,\n newKeyPath,\n false\n );\n setFocusedContentKeyPath(newKeyPath);\n }}\n Icon={Plus}\n >\n {addNewElement.text}\n </Button>\n </div>\n );\n }\n\n if (typeof section.nodeType === 'string') {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: section.nodeType } as KeyPath,\n ];\n\n return (\n <NavigationViewNode\n keyPath={childKeyPath}\n section={sectionProp}\n dictionary={dictionary}\n />\n );\n }\n\n const sectionArray = Object.keys(section);\n return (\n <div className=\"flex w-full max-w-full flex-col justify-between gap-2\">\n {sectionArray.map((key) => {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: NodeTypes.OBJECT, key },\n ];\n\n const subSection = getContentNodeByKeyPath(sectionProp, childKeyPath);\n const isEditableSubSection = getIsEditableSection(subSection);\n\n if (isEditableSubSection) {\n return (\n <Button\n label={`${goToField.label.value} ${key}`}\n key={key}\n isActive={getIsSelected(childKeyPath)}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n className=\"w-full\"\n onClick={() => setFocusedContentKeyPath(childKeyPath)}\n IconRight={ChevronRight}\n >\n {camelCaseToSentence(key)}\n </Button>\n );\n }\n\n return (\n <Accordion\n key={key}\n label={`${goToField.label.value} ${key}`}\n isActive={getIsSelected(childKeyPath)}\n onClick={() => setFocusedContentKeyPath(childKeyPath)}\n header={camelCaseToSentence(key)}\n >\n <div className=\"mt-2 flex w-full max-w-full\">\n <div className=\"flex-1 pl-10\">\n <NavigationViewNode\n keyPath={childKeyPath}\n section={sectionProp}\n dictionary={dictionary}\n />\n </div>\n </div>\n </Accordion>\n );\n })}\n </div>\n );\n }\n\n return (\n <>\n Error loading section --\n {nodeType}\n --\n {JSON.stringify(section)}\n --\n {JSON.stringify(keyPath)}\n </>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"NavigationViewNode.mjs","names":[],"sources":["../../../../../src/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.tsx"],"sourcesContent":["import { Accordion } from '@components/Accordion';\nimport {\n Button,\n ButtonColor,\n ButtonTextAlign,\n ButtonVariant,\n} from '@components/Button';\nimport { internationalization } from '@intlayer/config/built';\nimport { camelCaseToSentence } from '@intlayer/config/client';\nimport {\n getContentNodeByKeyPath,\n getEmptyNode,\n getNodeType,\n} from '@intlayer/core/dictionaryManipulator';\nimport { isSameKeyPath } from '@intlayer/core/utils';\nimport {\n useEditedContentActions,\n useEditorLocale,\n useFocusUnmergedDictionary,\n} from '@intlayer/editor-react';\nimport type { LocalDictionaryId } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { ContentNode, Dictionary } from 'intlayer';\nimport { ChevronRight, Plus } from 'lucide-react';\nimport type { FC } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { getIsEditableSection } from '../getIsEditableSection';\n\nexport const traceKeys: string[] = ['filePath', 'id', 'nodeType'];\n\nexport type NodeWrapperProps = {\n keyPath: KeyPath[];\n section: ContentNode;\n dictionary: Dictionary;\n};\n\nexport const NavigationViewNode: FC<NodeWrapperProps> = ({\n section: sectionProp,\n keyPath,\n dictionary,\n}) => {\n const { locales } = internationalization;\n\n const currentLocale = useEditorLocale();\n const section = getContentNodeByKeyPath(sectionProp, keyPath, currentLocale);\n const { addEditedContent } = useEditedContentActions();\n const { setFocusedContentKeyPath, focusedContent } =\n useFocusUnmergedDictionary();\n const { addNewElement, goToField } = useIntlayer('navigation-view');\n const nodeType = getNodeType(section);\n const getIsSelected = (keyPath: KeyPath[]) =>\n (focusedContent?.keyPath?.length ?? 0) > 0 &&\n isSameKeyPath(keyPath, focusedContent?.keyPath ?? []);\n const isEditableSubSection = getIsEditableSection(section);\n\n if (!section) return <></>;\n\n if (isEditableSubSection) {\n return (\n <Button\n label={goToField.label.value}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n className=\"w-full\"\n onClick={() => setFocusedContentKeyPath(keyPath)}\n IconRight={ChevronRight}\n >\n {camelCaseToSentence(keyPath[keyPath.length - 1].key as string)}\n </Button>\n );\n }\n\n if (typeof section === 'object') {\n if (nodeType === NodeTypes.REACT_NODE) {\n return <>React Node</>;\n }\n\n if (nodeType === NodeTypes.TRANSLATION) {\n return (\n <div className=\"flex flex-col justify-between gap-2\">\n {locales.map((translationKey) => {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: NodeTypes.TRANSLATION, key: translationKey },\n ];\n\n return (\n <NavigationViewNode\n key={translationKey}\n keyPath={childKeyPath}\n section={sectionProp}\n dictionary={dictionary}\n />\n );\n })}\n </div>\n );\n }\n\n if (\n nodeType === NodeTypes.ENUMERATION ||\n nodeType === NodeTypes.CONDITION\n ) {\n return (\n <div className=\"flex flex-col justify-between gap-2\">\n {Object.keys(\n (section as any)[nodeType as unknown as keyof typeof section]\n ).map((key) => {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: nodeType, key },\n ];\n\n return (\n <NavigationViewNode\n key={key}\n keyPath={childKeyPath}\n section={sectionProp}\n dictionary={dictionary}\n />\n );\n })}\n </div>\n );\n }\n\n if (nodeType === NodeTypes.ARRAY) {\n return (\n <div className=\"flex flex-col justify-between gap-2\">\n {(section as unknown as ContentNode[]).map((subSection, index) => {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: NodeTypes.ARRAY, key: index },\n ];\n\n const isEditableSubSection = getIsEditableSection(subSection);\n\n if (isEditableSubSection) {\n return (\n <Button\n key={JSON.stringify(childKeyPath)}\n label={`${goToField.label.value} ${index}`}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n className=\"w-full\"\n onClick={() => setFocusedContentKeyPath(childKeyPath)}\n IconRight={ChevronRight}\n isActive={getIsSelected(childKeyPath)}\n >\n Item {index}\n </Button>\n );\n }\n\n return (\n <Accordion\n key={JSON.stringify(childKeyPath)}\n label={`${goToField.label.value} ${index}`}\n header={`Item ${index}`}\n isActive={getIsSelected(childKeyPath)}\n onClick={() => setFocusedContentKeyPath(childKeyPath)}\n >\n <div className=\"mt-2 flex w-full max-w-full\">\n <div className=\"flex-1 pl-10\">\n <NavigationViewNode\n keyPath={childKeyPath}\n section={sectionProp}\n dictionary={dictionary}\n />\n </div>\n </div>\n </Accordion>\n );\n })}\n\n <Button\n label={addNewElement.label.value}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.NEUTRAL}\n textAlign={ButtonTextAlign.LEFT}\n onClick={() => {\n const newKeyPath: KeyPath[] = [\n ...keyPath,\n {\n type: NodeTypes.ARRAY,\n key: (section as unknown as ContentNode[]).length,\n },\n ];\n const sectionArray = section as unknown as ContentNode[];\n const emptySectionEl =\n getEmptyNode(\n sectionArray[\n (sectionArray.length - 1) as keyof typeof sectionArray\n ] as ContentNode\n ) ?? '';\n addEditedContent(\n dictionary.localId as LocalDictionaryId,\n emptySectionEl,\n newKeyPath,\n false\n );\n setFocusedContentKeyPath(newKeyPath);\n }}\n Icon={Plus}\n >\n {addNewElement.text}\n </Button>\n </div>\n );\n }\n\n if (typeof section.nodeType === 'string') {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: section.nodeType } as KeyPath,\n ];\n\n return (\n <NavigationViewNode\n keyPath={childKeyPath}\n section={sectionProp}\n dictionary={dictionary}\n />\n );\n }\n\n const sectionArray = Object.keys(section);\n return (\n <div className=\"flex w-full max-w-full flex-col justify-between gap-2\">\n {sectionArray.map((key) => {\n const childKeyPath: KeyPath[] = [\n ...keyPath,\n { type: NodeTypes.OBJECT, key },\n ];\n\n const subSection = getContentNodeByKeyPath(sectionProp, childKeyPath);\n const isEditableSubSection = getIsEditableSection(subSection);\n\n if (isEditableSubSection) {\n return (\n <Button\n label={`${goToField.label.value} ${key}`}\n key={key}\n isActive={getIsSelected(childKeyPath)}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n className=\"w-full\"\n onClick={() => setFocusedContentKeyPath(childKeyPath)}\n IconRight={ChevronRight}\n >\n {camelCaseToSentence(key)}\n </Button>\n );\n }\n\n return (\n <Accordion\n key={key}\n label={`${goToField.label.value} ${key}`}\n isActive={getIsSelected(childKeyPath)}\n onClick={() => setFocusedContentKeyPath(childKeyPath)}\n header={camelCaseToSentence(key)}\n >\n <div className=\"mt-2 flex w-full max-w-full\">\n <div className=\"flex-1 pl-10\">\n <NavigationViewNode\n keyPath={childKeyPath}\n section={sectionProp}\n dictionary={dictionary}\n />\n </div>\n </div>\n </Accordion>\n );\n })}\n </div>\n );\n }\n\n return (\n <>\n Error loading section --\n {nodeType}\n --\n {JSON.stringify(section)}\n --\n {JSON.stringify(keyPath)}\n </>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeTypeSelector.mjs","names":[],"sources":["../../../../src/components/DictionaryFieldEditor/NodeTypeSelector.tsx"],"sourcesContent":["'use client';\n\nimport { getNodeType } from '@intlayer/core/dictionaryManipulator';\nimport type { ContentNode } from '@intlayer/types/dictionary';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { type FC, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Select } from '../Select';\n\ntype NodeTypeSelectorProps = {\n section: ContentNode;\n onValueChange: (keyType: NodeType) => void;\n};\n\nexport const NodeTypeSelector: FC<NodeTypeSelectorProps> = ({\n section,\n onValueChange: onValueChangeProp,\n}) => {\n const {\n multilingual,\n text,\n number,\n boolean,\n node,\n array,\n enumeration,\n triggerPlaceHolder,\n nest,\n gender,\n condition,\n markdown,\n insertion,\n reactNode,\n file,\n } = useIntlayer('node-type-selector');\n const nodeType = getNodeType(section);\n const [keyType, setKeyType] = useState<NodeType>(nodeType);\n\n const onValueChange = (keyType: NodeType) => {\n setKeyType(keyType);\n onValueChangeProp(keyType);\n };\n\n return (\n <Select value={keyType} onValueChange={onValueChange}>\n <Select.Trigger>\n <Select.Value placeholder={triggerPlaceHolder} />\n </Select.Trigger>\n <Select.Content>\n <Select.Item value={NodeTypes.TRANSLATION}>{multilingual}</Select.Item>\n <Select.Item value={NodeTypes.TEXT}>{text}</Select.Item>\n <Select.Item value={NodeTypes.NUMBER}>{number}</Select.Item>\n <Select.Item value={NodeTypes.BOOLEAN}>{boolean}</Select.Item>\n <Select.Item value={NodeTypes.OBJECT}>{node}</Select.Item>\n <Select.Item value={NodeTypes.ARRAY}>{array}</Select.Item>\n <Select.Item value={NodeTypes.ENUMERATION}>{enumeration}</Select.Item>\n <Select.Item value={NodeTypes.GENDER}>{gender}</Select.Item>\n <Select.Item value={NodeTypes.INSERTION}>{insertion}</Select.Item>\n <Select.Item value={NodeTypes.MARKDOWN}>{markdown}</Select.Item>\n <Select.Item value={NodeTypes.NESTED}>{nest}</Select.Item>\n <Select.Item value={NodeTypes.CONDITION}>{condition}</Select.Item>\n <Select.Item value={NodeTypes.REACT_NODE} disabled>\n {reactNode}\n </Select.Item>\n <Select.Item value={NodeTypes.FILE}>{file}</Select.Item>\n </Select.Content>\n </Select>\n );\n};\n"],"mappings":";;;;;;;;;;AAeA,MAAa,oBAA+C,EAC1D,SACA,eAAe,wBACX;CACJ,MAAM,EACJ,cACA,MACA,QACA,SACA,MACA,OACA,aACA,oBACA,MACA,QACA,WACA,UACA,WACA,WACA,SACE,YAAY,qBAAqB;CAErC,MAAM,CAAC,SAAS,cAAc,SADb,YAAY,QAAQ,CACqB;CAE1D,MAAM,iBAAiB,YAAsB;AAC3C,aAAW,QAAQ;AACnB,oBAAkB,QAAQ;;AAG5B,QACE,qBAAC,QAAD;EAAQ,OAAO;EAAwB;YAAvC,CACE,oBAAC,OAAO,SAAR,YACE,oBAAC,OAAO,OAAR,EAAc,aAAa,oBAAsB,GAClC,GACjB,qBAAC,OAAO,SAAR;GACE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAc;IAA2B;GACvE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAO;IAAmB;GACxD,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAS;IAAqB;GAC5D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAU;IAAsB;GAC9D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAS;IAAmB;GAC1D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAQ;IAAoB;GAC1D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAc;IAA0B;GACtE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAS;IAAqB;GAC5D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAY;IAAwB;GAClE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAW;IAAuB;GAChE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAS;IAAmB;GAC1D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAY;IAAwB;GAClE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;IAAY;cACvC;IACW;GACd,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAO;IAAmB;GACzC,IACV"}
1
+ {"version":3,"file":"NodeTypeSelector.mjs","names":[],"sources":["../../../../src/components/DictionaryFieldEditor/NodeTypeSelector.tsx"],"sourcesContent":["'use client';\n\nimport { getNodeType } from '@intlayer/core/dictionaryManipulator';\nimport type { ContentNode } from '@intlayer/types/dictionary';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { type FC, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Select } from '../Select';\n\ntype NodeTypeSelectorProps = {\n section: ContentNode;\n onValueChange: (keyType: NodeType) => void;\n};\n\nexport const NodeTypeSelector: FC<NodeTypeSelectorProps> = ({\n section,\n onValueChange: onValueChangeProp,\n}) => {\n const {\n multilingual,\n text,\n number,\n boolean,\n node,\n array,\n enumeration,\n triggerPlaceHolder,\n nest,\n gender,\n condition,\n markdown,\n insertion,\n reactNode,\n file,\n } = useIntlayer('node-type-selector');\n const nodeType = getNodeType(section);\n const [keyType, setKeyType] = useState<NodeType>(nodeType);\n\n const onValueChange = (keyType: NodeType) => {\n setKeyType(keyType);\n onValueChangeProp(keyType);\n };\n\n return (\n <Select value={keyType} onValueChange={onValueChange}>\n <Select.Trigger>\n <Select.Value placeholder={triggerPlaceHolder} />\n </Select.Trigger>\n <Select.Content>\n <Select.Item value={NodeTypes.TRANSLATION}>{multilingual}</Select.Item>\n <Select.Item value={NodeTypes.TEXT}>{text}</Select.Item>\n <Select.Item value={NodeTypes.NUMBER}>{number}</Select.Item>\n <Select.Item value={NodeTypes.BOOLEAN}>{boolean}</Select.Item>\n <Select.Item value={NodeTypes.OBJECT}>{node}</Select.Item>\n <Select.Item value={NodeTypes.ARRAY}>{array}</Select.Item>\n <Select.Item value={NodeTypes.ENUMERATION}>{enumeration}</Select.Item>\n <Select.Item value={NodeTypes.GENDER}>{gender}</Select.Item>\n <Select.Item value={NodeTypes.INSERTION}>{insertion}</Select.Item>\n <Select.Item value={NodeTypes.MARKDOWN}>{markdown}</Select.Item>\n <Select.Item value={NodeTypes.NESTED}>{nest}</Select.Item>\n <Select.Item value={NodeTypes.CONDITION}>{condition}</Select.Item>\n <Select.Item value={NodeTypes.REACT_NODE} disabled>\n {reactNode}\n </Select.Item>\n <Select.Item value={NodeTypes.FILE}>{file}</Select.Item>\n </Select.Content>\n </Select>\n );\n};\n"],"mappings":";;;;;;;;;;AAeA,MAAa,oBAA+C,EAC1D,SACA,eAAe,wBACX;CACJ,MAAM,EACJ,cACA,MACA,QACA,SACA,MACA,OACA,aACA,oBACA,MACA,QACA,WACA,UACA,WACA,WACA,SACE,YAAY,qBAAqB;CAErC,MAAM,CAAC,SAAS,cAAc,SADb,YAAY,QAC4B,CAAC;CAE1D,MAAM,iBAAiB,YAAsB;AAC3C,aAAW,QAAQ;AACnB,oBAAkB,QAAQ;;AAG5B,QACE,qBAAC,QAAD;EAAQ,OAAO;EAAwB;YAAvC,CACE,oBAAC,OAAO,SAAR,YACE,oBAAC,OAAO,OAAR,EAAc,aAAa,oBAAsB,GAClC,GACjB,qBAAC,OAAO,SAAR;GACE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAc;IAA2B;GACvE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAO;IAAmB;GACxD,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAS;IAAqB;GAC5D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAU;IAAsB;GAC9D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAS;IAAmB;GAC1D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAQ;IAAoB;GAC1D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAc;IAA0B;GACtE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAS;IAAqB;GAC5D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAY;IAAwB;GAClE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAW;IAAuB;GAChE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAS;IAAmB;GAC1D,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAY;IAAwB;GAClE,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;IAAY;cACvC;IACW;GACd,oBAAC,OAAO,MAAR;IAAa,OAAO,UAAU;cAAO;IAAmB;GACzC,IACV"}