@intlayer/design-system 8.9.5 → 8.9.6-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 (62) hide show
  1. package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
  2. package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs +17 -9
  3. package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs.map +1 -1
  4. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/SafeHtmlRenderer.mjs +20 -0
  5. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/SafeHtmlRenderer.mjs.map +1 -0
  6. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +83 -49
  7. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs.map +1 -1
  8. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +1 -1
  9. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +4 -4
  10. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +57 -35
  11. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs.map +1 -1
  12. package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +20 -8
  13. package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs.map +1 -1
  14. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +3 -3
  15. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +22 -52
  16. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs.map +1 -1
  17. package/dist/esm/components/Form/elements/OTPElement.mjs +1 -1
  18. package/dist/esm/components/IDE/CodeFormatSelector.mjs +1 -1
  19. package/dist/esm/components/IDE/ContentDeclarationFormatSelector.mjs +1 -1
  20. package/dist/esm/components/IDE/PackageManagerSelector.mjs +1 -1
  21. package/dist/esm/components/LanguageBackground/index.mjs +4 -4
  22. package/dist/esm/components/LanguageBackground/index.mjs.map +1 -1
  23. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +1 -1
  24. package/dist/esm/components/Modal/Modal.mjs +2 -2
  25. package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
  26. package/dist/esm/components/Pagination/Pagination.mjs +1 -1
  27. package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -3
  28. package/dist/esm/components/Tab/Tab.mjs +1 -1
  29. package/dist/esm/components/Table/SmartTable.mjs +1 -1
  30. package/dist/esm/components/index.mjs +11 -11
  31. package/dist/esm/hooks/index.mjs +11 -11
  32. package/dist/esm/hooks/reactQuery.mjs +17 -1
  33. package/dist/esm/hooks/reactQuery.mjs.map +1 -1
  34. package/dist/esm/hooks/useAuth/useOAuth2.mjs +1 -1
  35. package/dist/esm/hooks/useAuth/useSession.mjs +1 -1
  36. package/dist/esm/libs/auth.mjs +1 -1
  37. package/dist/types/components/Badge/index.d.ts +3 -3
  38. package/dist/types/components/Button/Button.d.ts +5 -5
  39. package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +3 -3
  40. package/dist/types/components/Command/index.d.ts +2 -2
  41. package/dist/types/components/Container/index.d.ts +8 -8
  42. package/dist/types/components/DictionaryFieldEditor/ContentEditorView/SafeHtmlRenderer.d.ts +11 -0
  43. package/dist/types/components/DictionaryFieldEditor/ContentEditorView/SafeHtmlRenderer.d.ts.map +1 -0
  44. package/dist/types/components/DictionaryFieldEditor/ContentEditorView/TextEditor.d.ts +4 -3
  45. package/dist/types/components/DictionaryFieldEditor/ContentEditorView/TextEditor.d.ts.map +1 -1
  46. package/dist/types/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.d.ts.map +1 -1
  47. package/dist/types/components/DictionaryFieldEditor/StructureView/StructureView.d.ts.map +1 -1
  48. package/dist/types/components/Input/Checkbox.d.ts +2 -2
  49. package/dist/types/components/Input/Input.d.ts +1 -1
  50. package/dist/types/components/Input/OTPInput.d.ts +1 -1
  51. package/dist/types/components/LanguageBackground/index.d.ts.map +1 -1
  52. package/dist/types/components/Link/Link.d.ts +3 -3
  53. package/dist/types/components/Pagination/Pagination.d.ts +2 -2
  54. package/dist/types/components/SwitchSelector/SwitchSelector.d.ts +1 -1
  55. package/dist/types/components/SwitchSelector/VerticalSwitchSelector.d.ts +1 -1
  56. package/dist/types/components/TabSelector/TabSelector.d.ts +1 -1
  57. package/dist/types/components/Tag/index.d.ts +3 -3
  58. package/dist/types/components/Toaster/Toast.d.ts +1 -1
  59. package/dist/types/hooks/index.d.ts +2 -2
  60. package/dist/types/hooks/reactQuery.d.ts +3 -1
  61. package/dist/types/hooks/reactQuery.d.ts.map +1 -1
  62. package/package.json +22 -19
@@ -4,17 +4,17 @@ import { Container } from "../Container/index.mjs";
4
4
  import { Button, ButtonColor, ButtonVariant } from "../Button/Button.mjs";
5
5
  import { CopyToClipboard } from "../CopyToClipboard/index.mjs";
6
6
  import { LocaleSwitcherContentProvider } from "../LocaleSwitcherContentDropDown/LocaleSwitcherContentContext.mjs";
7
- import { Tab } from "../Tab/Tab.mjs";
8
7
  import { ContentEditor } from "./ContentEditor.mjs";
8
+ import { TabSelector, TabSelectorColor } from "../TabSelector/TabSelector.mjs";
9
9
  import { DictionaryDetailsForm } from "./DictionaryDetails/DictionaryDetailsForm.mjs";
10
10
  import { JSONEditor } from "./JSONEditor.mjs";
11
11
  import { SaveForm } from "./SaveForm/SaveForm.mjs";
12
12
  import { StructureEditor } from "./StructureEditor.mjs";
13
- import { useEffect } from "react";
13
+ import { useEffect, useState } from "react";
14
14
  import { ArrowLeft } from "lucide-react";
15
15
  import { jsx, jsxs } from "react/jsx-runtime";
16
- import { useConfiguration, useDictionariesRecordActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
17
16
  import { useIntlayer } from "react-intlayer";
17
+ import { useConfiguration, useDictionariesRecordActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
18
18
 
19
19
  //#region src/components/DictionaryFieldEditor/DictionaryFieldEditor.tsx
20
20
  const DictionaryFieldEditor = ({ dictionary, onClickDictionaryList, isDarkMode, mode, onDelete, onSave, showReturnButton = true }) => {
@@ -22,6 +22,7 @@ const DictionaryFieldEditor = ({ dictionary, onClickDictionaryList, isDarkMode,
22
22
  const { returnToDictionaryList } = useIntlayer("dictionary-field-editor");
23
23
  const { focusedContent, setFocusedContent } = useFocusUnmergedDictionary();
24
24
  const { setLocaleDictionary } = useDictionariesRecordActions();
25
+ const [activeTab, setActiveTab] = useState("content");
25
26
  useEffect(() => {
26
27
  setFocusedContent({
27
28
  ...focusedContent ?? {},
@@ -44,45 +45,66 @@ const DictionaryFieldEditor = ({ dictionary, onClickDictionaryList, isDarkMode,
44
45
  label: returnToDictionaryList.label.value,
45
46
  children: returnToDictionaryList.text
46
47
  }),
47
- /* @__PURE__ */ jsx("div", {
48
- className: "mb-22 min-h-0 flex-1",
49
- children: /* @__PURE__ */ jsxs(Tab, {
50
- defaultTab: "content",
51
- variant: "ghost",
52
- fullHeight: true,
53
- headerClassName: "sticky top-0 z-10 rounded-xl bg-background/20 pb-4",
54
- children: [
55
- mode.includes("remote") && /* @__PURE__ */ jsx(Tab.Item, {
56
- label: "Details",
57
- value: "details",
58
- children: /* @__PURE__ */ jsx(DictionaryDetailsForm, {
48
+ /* @__PURE__ */ jsxs("div", {
49
+ className: "mb-22 flex min-h-0 flex-1 flex-col overflow-hidden",
50
+ children: [/* @__PURE__ */ jsx("div", {
51
+ className: "sticky top-0 z-10 flex shrink-0 gap-3 rounded-xl bg-background/20 p-3 pb-4",
52
+ children: /* @__PURE__ */ jsx(TabSelector, {
53
+ selectedChoice: activeTab,
54
+ tabs: [
55
+ ...mode.includes("remote") ? [/* @__PURE__ */ jsx("button", {
56
+ className: "cursor-pointer whitespace-nowrap rounded-md px-4 py-1 font-medium text-sm transition-colors focus:outline-none",
57
+ "data-active": activeTab === "details",
58
+ onClick: () => setActiveTab("details"),
59
+ type: "button",
60
+ children: "Details"
61
+ }, "details")] : [],
62
+ /* @__PURE__ */ jsx("button", {
63
+ className: "cursor-pointer whitespace-nowrap rounded-md px-4 py-1 font-medium text-sm transition-colors focus:outline-none",
64
+ "data-active": activeTab === "structure",
65
+ onClick: () => setActiveTab("structure"),
66
+ type: "button",
67
+ children: "Structure"
68
+ }, "structure"),
69
+ /* @__PURE__ */ jsx("button", {
70
+ className: "cursor-pointer whitespace-nowrap rounded-md px-4 py-1 font-medium text-sm transition-colors focus:outline-none",
71
+ "data-active": activeTab === "content",
72
+ onClick: () => setActiveTab("content"),
73
+ type: "button",
74
+ children: "Content"
75
+ }, "content"),
76
+ /* @__PURE__ */ jsx("button", {
77
+ className: "cursor-pointer whitespace-nowrap rounded-md px-4 py-1 font-medium text-sm transition-colors focus:outline-none",
78
+ "data-active": activeTab === "json",
79
+ onClick: () => setActiveTab("json"),
80
+ type: "button",
81
+ children: "JSON"
82
+ }, "json")
83
+ ],
84
+ hoverable: true,
85
+ color: "text"
86
+ })
87
+ }), /* @__PURE__ */ jsx("div", {
88
+ className: "min-h-0 flex-1 overflow-y-auto p-6",
89
+ children: /* @__PURE__ */ jsxs("div", {
90
+ className: "flex w-full min-w-0 flex-col items-stretch gap-6",
91
+ children: [
92
+ mode.includes("remote") && activeTab === "details" && /* @__PURE__ */ jsx(DictionaryDetailsForm, {
59
93
  dictionary,
60
94
  mode
61
- })
62
- }),
63
- /* @__PURE__ */ jsx(Tab.Item, {
64
- label: "Structure",
65
- value: "structure",
66
- children: /* @__PURE__ */ jsx(StructureEditor, { dictionary })
67
- }),
68
- /* @__PURE__ */ jsx(Tab.Item, {
69
- label: "Content",
70
- value: "content",
71
- children: /* @__PURE__ */ jsx(ContentEditor, {
95
+ }),
96
+ activeTab === "structure" && /* @__PURE__ */ jsx(StructureEditor, { dictionary }),
97
+ activeTab === "content" && /* @__PURE__ */ jsx(ContentEditor, {
72
98
  dictionary,
73
99
  isDarkMode
74
- })
75
- }),
76
- /* @__PURE__ */ jsx(Tab.Item, {
77
- label: "JSON",
78
- value: "json",
79
- children: /* @__PURE__ */ jsx(JSONEditor, {
100
+ }),
101
+ activeTab === "json" && /* @__PURE__ */ jsx(JSONEditor, {
80
102
  dictionary,
81
103
  isDarkMode
82
104
  })
83
- })
84
- ]
85
- })
105
+ ]
106
+ })
107
+ })]
86
108
  }),
87
109
  /* @__PURE__ */ jsx("div", {
88
110
  className: "absolute bottom-3 z-20 w-full p-2",
@@ -1 +1 @@
1
- {"version":3,"file":"DictionaryFieldEditor.mjs","names":[],"sources":["../../../../src/components/DictionaryFieldEditor/DictionaryFieldEditor.tsx"],"sourcesContent":["'use client';\n\nimport { Container } from '@components/Container';\nimport { CopyToClipboard } from '@components/CopyToClipboard';\nimport {\n useConfiguration,\n useDictionariesRecordActions,\n useFocusUnmergedDictionary,\n} from '@intlayer/editor-react';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { ArrowLeft } from 'lucide-react';\nimport { type FC, useEffect } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button, ButtonColor, ButtonVariant } from '../Button';\nimport { LocaleSwitcherContentProvider } from '../LocaleSwitcherContentDropDown';\nimport { Tab } from '../Tab';\nimport { ContentEditor } from './ContentEditor';\nimport { DictionaryDetailsForm } from './DictionaryDetails/DictionaryDetailsForm';\nimport { JSONEditor } from './JSONEditor';\nimport { SaveForm } from './SaveForm/SaveForm';\nimport { StructureEditor } from './StructureEditor';\n\ntype DictionaryFieldEditorProps = {\n dictionary: Dictionary;\n onClickDictionaryList?: () => void;\n onDelete?: () => void;\n onSave?: () => void;\n isDarkMode?: boolean;\n mode: ('local' | 'remote')[];\n showReturnButton?: boolean;\n};\n\nexport const DictionaryFieldEditor: FC<DictionaryFieldEditorProps> = ({\n dictionary,\n onClickDictionaryList,\n isDarkMode,\n mode,\n onDelete,\n onSave,\n showReturnButton = true,\n}) => {\n const config = useConfiguration();\n const { returnToDictionaryList } = useIntlayer('dictionary-field-editor');\n const { focusedContent, setFocusedContent } = useFocusUnmergedDictionary();\n const { setLocaleDictionary } = useDictionariesRecordActions();\n\n useEffect(() => {\n setFocusedContent({\n ...(focusedContent ?? {}),\n dictionaryKey: dictionary.key,\n dictionaryLocalId: dictionary.localId,\n });\n setLocaleDictionary(dictionary);\n }, []);\n\n return (\n <LocaleSwitcherContentProvider\n availableLocales={config?.internationalization?.locales ?? []}\n >\n <div className=\"relative flex h-full min-h-0 w-full flex-1 flex-col md:overflow-hidden\">\n {showReturnButton && (\n <Button\n onClick={onClickDictionaryList}\n variant={ButtonVariant.HOVERABLE}\n className=\"z-10 mr-auto mb-6 ml-5 shrink-0\"\n color={ButtonColor.TEXT}\n Icon={ArrowLeft}\n label={returnToDictionaryList.label.value}\n >\n {returnToDictionaryList.text}\n </Button>\n )}\n\n <div className=\"mb-22 min-h-0 flex-1\">\n <Tab\n defaultTab=\"content\"\n variant=\"ghost\"\n fullHeight\n headerClassName=\"sticky top-0 z-10 rounded-xl bg-background/20 pb-4\"\n >\n {mode.includes('remote') && (\n <Tab.Item label=\"Details\" value=\"details\">\n <DictionaryDetailsForm dictionary={dictionary} mode={mode} />\n </Tab.Item>\n )}\n <Tab.Item label=\"Structure\" value=\"structure\">\n <StructureEditor dictionary={dictionary} />\n </Tab.Item>\n <Tab.Item label=\"Content\" value=\"content\">\n <ContentEditor dictionary={dictionary} isDarkMode={isDarkMode} />\n </Tab.Item>\n <Tab.Item label=\"JSON\" value=\"json\">\n <JSONEditor dictionary={dictionary} isDarkMode={isDarkMode} />\n </Tab.Item>\n </Tab>\n </div>\n\n <div className=\"absolute bottom-3 z-20 w-full p-2\">\n <Container\n color=\"card\"\n roundedSize=\"2xl\"\n padding=\"sm\"\n className=\"w-full shrink-0 flex-row flex-wrap items-center justify-end gap-10 bg-background/20 md:bottom-0\"\n >\n <CopyToClipboard\n text={dictionary.id!}\n className=\"text-nowrap text-neutral text-sm\"\n size={9}\n >\n {dictionary.id}\n </CopyToClipboard>\n <SaveForm\n dictionary={dictionary}\n mode={mode}\n onDelete={() => {\n setFocusedContent(null);\n onDelete?.();\n }}\n onSave={onSave}\n />\n </Container>\n </div>\n </div>\n </LocaleSwitcherContentProvider>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgCA,MAAa,yBAAyD,EACpE,YACA,uBACA,YACA,MACA,UACA,QACA,mBAAmB,WACf;CACJ,MAAM,SAAS,kBAAkB;CACjC,MAAM,EAAE,2BAA2B,YAAY,0BAA0B;CACzE,MAAM,EAAE,gBAAgB,sBAAsB,4BAA4B;CAC1E,MAAM,EAAE,wBAAwB,8BAA8B;CAE9D,gBAAgB;EACd,kBAAkB;GAChB,GAAI,kBAAkB,EAAE;GACxB,eAAe,WAAW;GAC1B,mBAAmB,WAAW;GAC/B,CAAC;EACF,oBAAoB,WAAW;IAC9B,EAAE,CAAC;CAEN,OACE,oBAAC,+BAAD;EACE,kBAAkB,QAAQ,sBAAsB,WAAW,EAAE;YAE7D,qBAAC,OAAD;GAAK,WAAU;aAAf;IACG,oBACC,oBAAC,QAAD;KACE,SAAS;KACT;KACA,WAAU;KACV;KACA,MAAM;KACN,OAAO,uBAAuB,MAAM;eAEnC,uBAAuB;KACjB;IAGX,oBAAC,OAAD;KAAK,WAAU;eACb,qBAAC,KAAD;MACE,YAAW;MACX,SAAQ;MACR;MACA,iBAAgB;gBAJlB;OAMG,KAAK,SAAS,SAAS,IACtB,oBAAC,IAAI,MAAL;QAAU,OAAM;QAAU,OAAM;kBAC9B,oBAAC,uBAAD;SAAmC;SAAkB;SAAQ;QACpD;OAEb,oBAAC,IAAI,MAAL;QAAU,OAAM;QAAY,OAAM;kBAChC,oBAAC,iBAAD,EAA6B,YAAc;QAClC;OACX,oBAAC,IAAI,MAAL;QAAU,OAAM;QAAU,OAAM;kBAC9B,oBAAC,eAAD;SAA2B;SAAwB;SAAc;QACxD;OACX,oBAAC,IAAI,MAAL;QAAU,OAAM;QAAO,OAAM;kBAC3B,oBAAC,YAAD;SAAwB;SAAwB;SAAc;QACrD;OACP;;KACF;IAEN,oBAAC,OAAD;KAAK,WAAU;eACb,qBAAC,WAAD;MACE,OAAM;MACN,aAAY;MACZ,SAAQ;MACR,WAAU;gBAJZ,CAME,oBAAC,iBAAD;OACE,MAAM,WAAW;OACjB,WAAU;OACV,MAAM;iBAEL,WAAW;OACI,GAClB,oBAAC,UAAD;OACc;OACN;OACN,gBAAgB;QACd,kBAAkB,KAAK;QACvB,YAAY;;OAEN;OACR,EACQ;;KACR;IACF;;EACwB"}
1
+ {"version":3,"file":"DictionaryFieldEditor.mjs","names":[],"sources":["../../../../src/components/DictionaryFieldEditor/DictionaryFieldEditor.tsx"],"sourcesContent":["'use client';\n\nimport { Container } from '@components/Container';\nimport { CopyToClipboard } from '@components/CopyToClipboard';\nimport {\n useConfiguration,\n useDictionariesRecordActions,\n useFocusUnmergedDictionary,\n} from '@intlayer/editor-react';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport { ArrowLeft } from 'lucide-react';\nimport { type FC, useEffect, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { Button, ButtonColor, ButtonVariant } from '../Button';\nimport { LocaleSwitcherContentProvider } from '../LocaleSwitcherContentDropDown';\nimport { TabSelector, TabSelectorColor } from '../TabSelector';\nimport { ContentEditor } from './ContentEditor';\nimport { DictionaryDetailsForm } from './DictionaryDetails/DictionaryDetailsForm';\nimport { JSONEditor } from './JSONEditor';\nimport { SaveForm } from './SaveForm/SaveForm';\nimport { StructureEditor } from './StructureEditor';\n\ntype DictionaryFieldEditorProps = {\n dictionary: Dictionary;\n onClickDictionaryList?: () => void;\n onDelete?: () => void;\n onSave?: () => void;\n isDarkMode?: boolean;\n mode: ('local' | 'remote')[];\n showReturnButton?: boolean;\n};\n\nexport const DictionaryFieldEditor: FC<DictionaryFieldEditorProps> = ({\n dictionary,\n onClickDictionaryList,\n isDarkMode,\n mode,\n onDelete,\n onSave,\n showReturnButton = true,\n}) => {\n const config = useConfiguration();\n const { returnToDictionaryList } = useIntlayer('dictionary-field-editor');\n const { focusedContent, setFocusedContent } = useFocusUnmergedDictionary();\n const { setLocaleDictionary } = useDictionariesRecordActions();\n const [activeTab, setActiveTab] = useState<string>('content');\n\n useEffect(() => {\n setFocusedContent({\n ...(focusedContent ?? {}),\n dictionaryKey: dictionary.key,\n dictionaryLocalId: dictionary.localId,\n });\n setLocaleDictionary(dictionary);\n }, []);\n\n return (\n <LocaleSwitcherContentProvider\n availableLocales={config?.internationalization?.locales ?? []}\n >\n <div className=\"relative flex h-full min-h-0 w-full flex-1 flex-col md:overflow-hidden\">\n {showReturnButton && (\n <Button\n onClick={onClickDictionaryList}\n variant={ButtonVariant.HOVERABLE}\n className=\"z-10 mr-auto mb-6 ml-5 shrink-0\"\n color={ButtonColor.TEXT}\n Icon={ArrowLeft}\n label={returnToDictionaryList.label.value}\n >\n {returnToDictionaryList.text}\n </Button>\n )}\n\n <div className=\"mb-22 flex min-h-0 flex-1 flex-col overflow-hidden\">\n {/* Tab headers */}\n <div className=\"sticky top-0 z-10 flex shrink-0 gap-3 rounded-xl bg-background/20 p-3 pb-4\">\n <TabSelector\n selectedChoice={activeTab}\n tabs={[\n ...(mode.includes('remote')\n ? [\n <button\n key=\"details\"\n className=\"cursor-pointer whitespace-nowrap rounded-md px-4 py-1 font-medium text-sm transition-colors focus:outline-none\"\n data-active={activeTab === 'details'}\n onClick={() => setActiveTab('details')}\n type=\"button\"\n >\n Details\n </button>,\n ]\n : []),\n <button\n key=\"structure\"\n className=\"cursor-pointer whitespace-nowrap rounded-md px-4 py-1 font-medium text-sm transition-colors focus:outline-none\"\n data-active={activeTab === 'structure'}\n onClick={() => setActiveTab('structure')}\n type=\"button\"\n >\n Structure\n </button>,\n <button\n key=\"content\"\n className=\"cursor-pointer whitespace-nowrap rounded-md px-4 py-1 font-medium text-sm transition-colors focus:outline-none\"\n data-active={activeTab === 'content'}\n onClick={() => setActiveTab('content')}\n type=\"button\"\n >\n Content\n </button>,\n <button\n key=\"json\"\n className=\"cursor-pointer whitespace-nowrap rounded-md px-4 py-1 font-medium text-sm transition-colors focus:outline-none\"\n data-active={activeTab === 'json'}\n onClick={() => setActiveTab('json')}\n type=\"button\"\n >\n JSON\n </button>,\n ]}\n hoverable\n color={TabSelectorColor.TEXT}\n />\n </div>\n {/* Tab content — only active panel is mounted */}\n <div className=\"min-h-0 flex-1 overflow-y-auto p-6\">\n <div className=\"flex w-full min-w-0 flex-col items-stretch gap-6\">\n {mode.includes('remote') && activeTab === 'details' && (\n <DictionaryDetailsForm dictionary={dictionary} mode={mode} />\n )}\n {activeTab === 'structure' && (\n <StructureEditor dictionary={dictionary} />\n )}\n {activeTab === 'content' && (\n <ContentEditor\n dictionary={dictionary}\n isDarkMode={isDarkMode}\n />\n )}\n {activeTab === 'json' && (\n <JSONEditor dictionary={dictionary} isDarkMode={isDarkMode} />\n )}\n </div>\n </div>\n </div>\n\n <div className=\"absolute bottom-3 z-20 w-full p-2\">\n <Container\n color=\"card\"\n roundedSize=\"2xl\"\n padding=\"sm\"\n className=\"w-full shrink-0 flex-row flex-wrap items-center justify-end gap-10 bg-background/20 md:bottom-0\"\n >\n <CopyToClipboard\n text={dictionary.id!}\n className=\"text-nowrap text-neutral text-sm\"\n size={9}\n >\n {dictionary.id}\n </CopyToClipboard>\n <SaveForm\n dictionary={dictionary}\n mode={mode}\n onDelete={() => {\n setFocusedContent(null);\n onDelete?.();\n }}\n onSave={onSave}\n />\n </Container>\n </div>\n </div>\n </LocaleSwitcherContentProvider>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgCA,MAAa,yBAAyD,EACpE,YACA,uBACA,YACA,MACA,UACA,QACA,mBAAmB,WACf;CACJ,MAAM,SAAS,kBAAkB;CACjC,MAAM,EAAE,2BAA2B,YAAY,0BAA0B;CACzE,MAAM,EAAE,gBAAgB,sBAAsB,4BAA4B;CAC1E,MAAM,EAAE,wBAAwB,8BAA8B;CAC9D,MAAM,CAAC,WAAW,gBAAgB,SAAiB,UAAU;CAE7D,gBAAgB;EACd,kBAAkB;GAChB,GAAI,kBAAkB,EAAE;GACxB,eAAe,WAAW;GAC1B,mBAAmB,WAAW;GAC/B,CAAC;EACF,oBAAoB,WAAW;IAC9B,EAAE,CAAC;CAEN,OACE,oBAAC,+BAAD;EACE,kBAAkB,QAAQ,sBAAsB,WAAW,EAAE;YAE7D,qBAAC,OAAD;GAAK,WAAU;aAAf;IACG,oBACC,oBAAC,QAAD;KACE,SAAS;KACT;KACA,WAAU;KACV;KACA,MAAM;KACN,OAAO,uBAAuB,MAAM;eAEnC,uBAAuB;KACjB;IAGX,qBAAC,OAAD;KAAK,WAAU;eAAf,CAEE,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,aAAD;OACE,gBAAgB;OAChB,MAAM;QACJ,GAAI,KAAK,SAAS,SAAS,GACvB,CACE,oBAAC,UAAD;SAEE,WAAU;SACV,eAAa,cAAc;SAC3B,eAAe,aAAa,UAAU;SACtC,MAAK;mBACN;SAEQ,EAPH,UAOG,CACV,GACD,EAAE;QACN,oBAAC,UAAD;SAEE,WAAU;SACV,eAAa,cAAc;SAC3B,eAAe,aAAa,YAAY;SACxC,MAAK;mBACN;SAEQ,EAPH,YAOG;QACT,oBAAC,UAAD;SAEE,WAAU;SACV,eAAa,cAAc;SAC3B,eAAe,aAAa,UAAU;SACtC,MAAK;mBACN;SAEQ,EAPH,UAOG;QACT,oBAAC,UAAD;SAEE,WAAU;SACV,eAAa,cAAc;SAC3B,eAAe,aAAa,OAAO;SACnC,MAAK;mBACN;SAEQ,EAPH,OAOG;QACV;OACD;OACA;OACA;MACE,GAEN,oBAAC,OAAD;MAAK,WAAU;gBACb,qBAAC,OAAD;OAAK,WAAU;iBAAf;QACG,KAAK,SAAS,SAAS,IAAI,cAAc,aACxC,oBAAC,uBAAD;SAAmC;SAAkB;SAAQ;QAE9D,cAAc,eACb,oBAAC,iBAAD,EAA6B,YAAc;QAE5C,cAAc,aACb,oBAAC,eAAD;SACc;SACA;SACZ;QAEH,cAAc,UACb,oBAAC,YAAD;SAAwB;SAAwB;SAAc;QAE5D;;MACF,EACF;;IAEN,oBAAC,OAAD;KAAK,WAAU;eACb,qBAAC,WAAD;MACE,OAAM;MACN,aAAY;MACZ,SAAQ;MACR,WAAU;gBAJZ,CAME,oBAAC,iBAAD;OACE,MAAM,WAAW;OACjB,WAAU;OACV,MAAM;iBAEL,WAAW;OACI,GAClB,oBAAC,UAAD;OACc;OACN;OACN,gBAAgB;QACd,kBAAkB,KAAK;QACvB,YAAY;;OAEN;OACR,EACQ;;KACR;IACF;;EACwB"}
@@ -1,15 +1,16 @@
1
1
  import { Button, ButtonColor, ButtonTextAlign, ButtonVariant } from "../../Button/Button.mjs";
2
2
  import { Accordion } from "../../Accordion/Accordion.mjs";
3
3
  import { getIsEditableSection } from "../getIsEditableSection.mjs";
4
+ import { useState } from "react";
4
5
  import { ChevronRight, Plus } from "lucide-react";
5
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
- import { internationalization } from "@intlayer/config/built";
7
- import { useEditedContentActions, useEditorLocale, useFocusUnmergedDictionary } from "@intlayer/editor-react";
6
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
7
  import { useIntlayer } from "react-intlayer";
8
+ import { useEditedContentActions, useEditorLocale, useFocusUnmergedDictionary } from "@intlayer/editor-react";
9
9
  import { getContentNodeByKeyPath, getEmptyNode, getNodeType } from "@intlayer/core/dictionaryManipulator";
10
10
  import * as NodeTypes from "@intlayer/types/nodeType";
11
11
  import { isSameKeyPath } from "@intlayer/core/utils";
12
12
  import { camelCaseToSentence } from "@intlayer/config/client";
13
+ import { internationalization } from "@intlayer/config/built";
13
14
 
14
15
  //#region src/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.tsx
15
16
  const traceKeys = [
@@ -17,6 +18,17 @@ const traceKeys = [
17
18
  "id",
18
19
  "nodeType"
19
20
  ];
21
+ const GatedAccordion = ({ children, onToggle, ...props }) => {
22
+ const [hasOpened, setHasOpened] = useState(false);
23
+ return /* @__PURE__ */ jsx(Accordion, {
24
+ ...props,
25
+ onToggle: (isOpen) => {
26
+ if (isOpen && !hasOpened) setHasOpened(true);
27
+ onToggle?.(isOpen);
28
+ },
29
+ children: hasOpened ? children : null
30
+ });
31
+ };
20
32
  const NavigationViewNode = ({ section: sectionProp, keyPath, dictionary }) => {
21
33
  const { locales } = internationalization;
22
34
  const section = getContentNodeByKeyPath(sectionProp, keyPath, useEditorLocale());
@@ -26,7 +38,7 @@ const NavigationViewNode = ({ section: sectionProp, keyPath, dictionary }) => {
26
38
  const nodeType = getNodeType(section);
27
39
  const getIsSelected = (keyPath) => (focusedContent?.keyPath?.length ?? 0) > 0 && isSameKeyPath(keyPath, focusedContent?.keyPath ?? []);
28
40
  const isEditableSubSection = getIsEditableSection(section);
29
- if (!section) return /* @__PURE__ */ jsx(Fragment, {});
41
+ if (!section) return /* @__PURE__ */ jsx(Fragment$1, {});
30
42
  if (isEditableSubSection) return /* @__PURE__ */ jsx(Button, {
31
43
  label: goToField.label.value,
32
44
  variant: "hoverable",
@@ -37,7 +49,7 @@ const NavigationViewNode = ({ section: sectionProp, keyPath, dictionary }) => {
37
49
  children: camelCaseToSentence(keyPath[keyPath.length - 1].key)
38
50
  });
39
51
  if (typeof section === "object") {
40
- if (nodeType === NodeTypes.REACT_NODE) return /* @__PURE__ */ jsx(Fragment, { children: "React Node" });
52
+ if (nodeType === NodeTypes.REACT_NODE) return /* @__PURE__ */ jsx(Fragment$1, { children: "React Node" });
41
53
  if (nodeType === NodeTypes.TRANSLATION) return /* @__PURE__ */ jsx("div", {
42
54
  className: "flex flex-col justify-between gap-2",
43
55
  children: locales.map((translationKey) => {
@@ -81,7 +93,7 @@ const NavigationViewNode = ({ section: sectionProp, keyPath, dictionary }) => {
81
93
  isActive: getIsSelected(childKeyPath),
82
94
  children: ["Item ", index]
83
95
  }, JSON.stringify(childKeyPath));
84
- return /* @__PURE__ */ jsx(Accordion, {
96
+ return /* @__PURE__ */ jsx(GatedAccordion, {
85
97
  label: `${goToField.label.value} ${index}`,
86
98
  header: `Item ${index}`,
87
99
  isActive: getIsSelected(childKeyPath),
@@ -139,7 +151,7 @@ const NavigationViewNode = ({ section: sectionProp, keyPath, dictionary }) => {
139
151
  IconRight: ChevronRight,
140
152
  children: camelCaseToSentence(key)
141
153
  }, key);
142
- return /* @__PURE__ */ jsx(Accordion, {
154
+ return /* @__PURE__ */ jsx(GatedAccordion, {
143
155
  label: `${goToField.label.value} ${key}`,
144
156
  isActive: getIsSelected(childKeyPath),
145
157
  onClick: () => setFocusedContentKeyPath(childKeyPath),
@@ -159,7 +171,7 @@ const NavigationViewNode = ({ section: sectionProp, keyPath, dictionary }) => {
159
171
  })
160
172
  });
161
173
  }
162
- return /* @__PURE__ */ jsxs(Fragment, { children: [
174
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
163
175
  "Error loading section --",
164
176
  nodeType,
165
177
  "--",
@@ -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.PLURAL ||\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, type AccordionProps } 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, type ReactNode, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { getIsEditableSection } from '../getIsEditableSection';\n\nexport const traceKeys: string[] = ['filePath', 'id', 'nodeType'];\n\ntype GatedAccordionProps = AccordionProps & { children: ReactNode };\n\n// Renders children only after the accordion is first opened (mount-once pattern).\n// Prevents the entire recursive subtree from mounting on initial render.\nconst GatedAccordion: FC<GatedAccordionProps> = ({\n children,\n onToggle,\n ...props\n}) => {\n const [hasOpened, setHasOpened] = useState(false);\n return (\n <Accordion\n {...props}\n onToggle={(isOpen) => {\n if (isOpen && !hasOpened) setHasOpened(true);\n onToggle?.(isOpen);\n }}\n >\n {hasOpened ? children : null}\n </Accordion>\n );\n};\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.PLURAL ||\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 <GatedAccordion\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 </GatedAccordion>\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 <GatedAccordion\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 </GatedAccordion>\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,16 +1,16 @@
1
1
  'use client';
2
2
 
3
3
  import { cn } from "../../../utils/cn.mjs";
4
+ import { ButtonColor, ButtonVariant } from "../../Button/Button.mjs";
4
5
  import { useAuth } from "../../../hooks/useAuth/useAuth.mjs";
5
6
  import { useDeleteDictionary, usePushDictionaries, useWriteDictionary } from "../../../hooks/reactQuery.mjs";
6
- import { ButtonColor, ButtonVariant } from "../../Button/Button.mjs";
7
- import { Modal, ModalSize } from "../../Modal/Modal.mjs";
8
7
  import { Form } from "../../Form/Form.mjs";
8
+ import { Modal, ModalSize } from "../../Modal/Modal.mjs";
9
9
  import { useState } from "react";
10
10
  import { ArrowUpFromLine, Download, RotateCcw, Save, Trash } from "lucide-react";
11
11
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
- import { useDictionariesRecordActions, useEditedContent } from "@intlayer/editor-react";
13
12
  import { useIntlayer } from "react-intlayer";
13
+ import { useDictionariesRecordActions, useEditedContent } from "@intlayer/editor-react";
14
14
 
15
15
  //#region src/components/DictionaryFieldEditor/SaveForm/SaveForm.tsx
16
16
  const SaveForm = ({ dictionary, mode, className, onDelete, onSave, ...props }) => {
@@ -5,22 +5,20 @@ import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../../Button/But
5
5
  import { InputVariant } from "../../Input/Input.mjs";
6
6
  import { EditableFieldInput } from "../../EditableField/EditableFieldInput.mjs";
7
7
  import { NodeTypeSelector } from "../NodeTypeSelector.mjs";
8
- import { memo, useMemo, useRef } from "react";
9
8
  import { Plus, Trash } from "lucide-react";
10
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
- import { useConfiguration, useEditedContentActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
10
  import { useIntlayer } from "react-intlayer";
11
+ import { useConfiguration, useEditedContentActions, useFocusUnmergedDictionary } from "@intlayer/editor-react";
13
12
  import { getDefaultNode, getNodeChildren, getNodeType } from "@intlayer/core/dictionaryManipulator";
14
13
  import * as NodeTypes from "@intlayer/types/nodeType";
15
14
  import { isSameKeyPath } from "@intlayer/core/utils";
16
15
  import { camelCaseToSentence } from "@intlayer/config/client";
17
- import { useVirtualizer } from "@tanstack/react-virtual";
18
16
 
19
17
  //#region src/components/DictionaryFieldEditor/StructureView/StructureView.tsx
20
18
  const NodeTypeView = ({ section, dictionaryLocalId, keyPath, onNodeTypeChange: onNodeTypeChangeProp }) => {
21
19
  const locales = useConfiguration()?.internationalization?.locales ?? [];
22
- const nodeType = useMemo(() => getNodeType(section), [section]);
23
- const children = useMemo(() => getNodeChildren(section), [section]);
20
+ const nodeType = getNodeType(section);
21
+ const children = getNodeChildren(section);
24
22
  const onNodeTypeChange = (content) => {
25
23
  onNodeTypeChangeProp(getDefaultNode(nodeType, locales, content));
26
24
  };
@@ -61,7 +59,7 @@ const NodeTypeView = ({ section, dictionaryLocalId, keyPath, onNodeTypeChange: o
61
59
  })]
62
60
  });
63
61
  }
64
- if (nodeType === NodeTypes.OBJECT) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(NodeTypeSelector, {
62
+ if (nodeType === NodeTypes.OBJECT) return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(NodeTypeSelector, {
65
63
  section,
66
64
  onValueChange: (nodeType) => onNodeTypeChangeProp(getDefaultNode(nodeType, locales))
67
65
  }), /* @__PURE__ */ jsx("div", {
@@ -77,7 +75,7 @@ const NodeTypeView = ({ section, dictionaryLocalId, keyPath, onNodeTypeChange: o
77
75
  onValueChange: (nodeType) => onNodeTypeChangeProp(getDefaultNode(nodeType, locales))
78
76
  });
79
77
  };
80
- const NodeView = memo(({ sectionKey, section, keyPath, dictionaryLocalId }) => {
78
+ const NodeView = ({ sectionKey, section, keyPath, dictionaryLocalId }) => {
81
79
  const { focusedContent, setFocusedContentKeyPath } = useFocusUnmergedDictionary();
82
80
  const { renameEditedContent, addEditedContent } = useEditedContentActions();
83
81
  const { titleInput, deleteButton } = useIntlayer("structure-view");
@@ -142,63 +140,35 @@ const NodeView = memo(({ sectionKey, section, keyPath, dictionaryLocalId }) => {
142
140
  })]
143
141
  })
144
142
  });
145
- });
143
+ };
146
144
  const ObjectView = ({ section, keyPath, dictionaryLocalId }) => {
147
145
  const { addNodeButton } = useIntlayer("structure-view");
148
146
  const { setFocusedContentKeyPath } = useFocusUnmergedDictionary();
149
147
  const { addEditedContent } = useEditedContentActions();
150
- const keys = useMemo(() => section && typeof section === "object" ? Object.keys(section) : [], [section]);
151
- const parentRef = useRef(null);
152
- const rowVirtualizer = useVirtualizer({
153
- count: keys.length,
154
- getScrollElement: () => parentRef.current,
155
- estimateSize: () => 140,
156
- overscan: 5
157
- });
158
148
  if (!section || typeof section !== "object") return /* @__PURE__ */ jsx("div", { children: "Not an object" });
159
149
  return /* @__PURE__ */ jsxs("div", {
160
- className: "flex flex-col gap-2",
161
- children: [/* @__PURE__ */ jsx("div", {
162
- ref: parentRef,
163
- className: "flex max-h-[800px] flex-col gap-4 overflow-y-auto pr-2",
164
- children: /* @__PURE__ */ jsx("div", {
165
- style: {
166
- height: `${rowVirtualizer.getTotalSize()}px`,
167
- width: "100%",
168
- position: "relative"
169
- },
170
- children: rowVirtualizer.getVirtualItems().map((virtualRow) => {
171
- const key = keys[virtualRow.index];
172
- return /* @__PURE__ */ jsx("div", {
173
- "data-index": virtualRow.index,
174
- ref: rowVirtualizer.measureElement,
175
- style: {
176
- position: "absolute",
177
- top: 0,
178
- left: 0,
179
- width: "100%",
180
- transform: `translateY(${virtualRow.start}px)`
181
- },
182
- className: "pb-4",
183
- children: /* @__PURE__ */ jsx(NodeView, {
184
- sectionKey: key,
185
- section: section?.[key],
186
- keyPath: [...keyPath, {
187
- type: NodeTypes.OBJECT,
188
- key
189
- }],
190
- dictionaryLocalId
191
- })
192
- }, virtualRow.key);
150
+ className: "flex flex-col gap-2 overflow-y-auto",
151
+ children: [/* @__PURE__ */ jsx("ul", {
152
+ className: "mr-auto flex flex-col gap-4",
153
+ children: Object.keys(section).map((key) => /* @__PURE__ */ jsx("li", {
154
+ className: "flex w-full",
155
+ children: /* @__PURE__ */ jsx(NodeView, {
156
+ sectionKey: key,
157
+ section: section?.[key],
158
+ keyPath: [...keyPath, {
159
+ type: NodeTypes.OBJECT,
160
+ key
161
+ }],
162
+ dictionaryLocalId
193
163
  })
194
- })
164
+ }, `${JSON.stringify(keyPath)}-object-${key}`))
195
165
  }), /* @__PURE__ */ jsx(Button, {
196
166
  label: addNodeButton.label.value,
197
167
  variant: "hoverable",
198
168
  size: "md",
199
169
  color: "text",
200
170
  Icon: Plus,
201
- className: "mt-2 flex-1",
171
+ className: "flex-1",
202
172
  onClick: () => {
203
173
  const newKey = "newKey";
204
174
  const newKeyPath = [...keyPath, {
@@ -1 +1 @@
1
- {"version":3,"file":"StructureView.mjs","names":[],"sources":["../../../../../src/components/DictionaryFieldEditor/StructureView/StructureView.tsx"],"sourcesContent":["'use client';\n\nimport {\n Button,\n ButtonColor,\n ButtonSize,\n ButtonVariant,\n} from '@components/Button';\nimport { Container } from '@components/Container';\nimport { EditableFieldInput } from '@components/EditableField';\nimport { InputVariant } from '@components/Input';\nimport { camelCaseToSentence } from '@intlayer/config/client';\nimport {\n getDefaultNode,\n getNodeChildren,\n getNodeType,\n} from '@intlayer/core/dictionaryManipulator';\nimport { isSameKeyPath } from '@intlayer/core/utils';\nimport {\n useConfiguration,\n useEditedContentActions,\n useFocusUnmergedDictionary,\n} from '@intlayer/editor-react';\nimport type { LocalDictionaryId, TypedNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { useVirtualizer } from '@tanstack/react-virtual';\nimport type { ContentNode } from 'intlayer';\nimport { Plus, Trash } from 'lucide-react';\nimport { type FC, memo, useMemo, useRef } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { NodeTypeSelector } from '../NodeTypeSelector';\n\ntype NodeTypeViewProps = {\n dictionaryLocalId: LocalDictionaryId;\n keyPath: KeyPath[];\n section: ContentNode;\n onNodeTypeChange: (content?: ContentNode) => void;\n};\n\nconst NodeTypeView: FC<NodeTypeViewProps> = ({\n section,\n dictionaryLocalId,\n keyPath,\n onNodeTypeChange: onNodeTypeChangeProp,\n}) => {\n const locales = useConfiguration()?.internationalization?.locales ?? [];\n\n // Memoize node type and children calculations\n const nodeType = useMemo(() => getNodeType(section), [section]);\n const children = useMemo(() => getNodeChildren(section), [section]);\n\n const onNodeTypeChange = (content?: ContentNode) => {\n const transformedContent = getDefaultNode(\n nodeType,\n locales,\n content\n ) as ContentNode;\n\n onNodeTypeChangeProp(transformedContent);\n };\n\n if (\n nodeType === NodeTypes.TRANSLATION ||\n nodeType === NodeTypes.CONDITION ||\n nodeType === NodeTypes.GENDER ||\n nodeType === NodeTypes.ENUMERATION ||\n nodeType === NodeTypes.PLURAL\n ) {\n const firstKey = Object.keys(\n (section as unknown as TypedNode)[nodeType as keyof typeof section]\n )[0];\n const childrenKeyPath = [\n ...keyPath,\n { type: nodeType, key: firstKey },\n ] as KeyPath[];\n\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <NodeTypeSelector\n section={section}\n onValueChange={(nodeType) =>\n onNodeTypeChangeProp(\n getDefaultNode(nodeType, locales) as ContentNode\n )\n }\n />\n\n <NodeTypeView\n section={children}\n keyPath={childrenKeyPath}\n dictionaryLocalId={dictionaryLocalId}\n onNodeTypeChange={onNodeTypeChange}\n />\n </div>\n );\n }\n\n if (nodeType === NodeTypes.ARRAY) {\n const childrenKeyPath = [...keyPath, { type: nodeType, key: 0 } as KeyPath];\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <NodeTypeSelector\n section={section}\n onValueChange={(nodeType) =>\n onNodeTypeChangeProp(\n getDefaultNode(nodeType, locales) as ContentNode\n )\n }\n />\n\n <NodeTypeView\n section={children}\n keyPath={childrenKeyPath}\n dictionaryLocalId={dictionaryLocalId}\n onNodeTypeChange={onNodeTypeChange}\n />\n </div>\n );\n }\n\n if (nodeType === NodeTypes.OBJECT) {\n return (\n <>\n <NodeTypeSelector\n section={section}\n onValueChange={(nodeType) =>\n onNodeTypeChangeProp(\n getDefaultNode(nodeType, locales) as ContentNode\n )\n }\n />\n <div className=\"mt-6 ml-10\">\n <StructureView\n keyPath={keyPath}\n section={section}\n dictionaryLocalId={dictionaryLocalId}\n />\n </div>\n </>\n );\n }\n\n return (\n <NodeTypeSelector\n section={section}\n onValueChange={(nodeType) =>\n onNodeTypeChangeProp(getDefaultNode(nodeType, locales) as ContentNode)\n }\n />\n );\n};\n\ntype NodeWrapperProps = {\n sectionKey?: string;\n dictionaryLocalId: LocalDictionaryId;\n keyPath: KeyPath[];\n section: ContentNode;\n};\n\nexport const NodeView: FC<NodeWrapperProps> = memo(\n ({ sectionKey, section, keyPath, dictionaryLocalId }) => {\n const { focusedContent, setFocusedContentKeyPath } =\n useFocusUnmergedDictionary();\n const { renameEditedContent, addEditedContent } = useEditedContentActions();\n\n const { titleInput, deleteButton } = useIntlayer('structure-view');\n\n const handleRenameNodeKey = (keyName: string) => {\n renameEditedContent(dictionaryLocalId, keyName, keyPath);\n const prevKeyPath: KeyPath[] = keyPath.slice(0, -1);\n const lastKeyPath: KeyPath = keyPath[keyPath.length - 1];\n const newKeyPath: KeyPath[] = [\n ...prevKeyPath,\n { ...lastKeyPath, key: keyName } as KeyPath,\n ];\n setFocusedContentKeyPath(newKeyPath);\n };\n\n return (\n <Container\n transparency=\"xl\"\n roundedSize=\"xl\"\n className=\"w-full min-w-80 gap-2 overflow-auto px-5 py-2\"\n border\n borderColor=\"text\"\n background=\"none\"\n aria-selected={isSameKeyPath(keyPath, focusedContent?.keyPath ?? [])}\n onClick={() => setFocusedContentKeyPath(keyPath)}\n >\n <div className=\"flex w-full flex-col items-start justify-between gap-3\">\n {typeof sectionKey === 'string' && (\n <div className=\"w-full\">\n <div className=\"flex w-full items-center justify-between gap-10\">\n <EditableFieldInput\n name=\"key\"\n aria-label=\"Key\"\n placeholder={titleInput.placeholder.value}\n defaultValue={sectionKey}\n onSave={(value) => handleRenameNodeKey(value)}\n variant={InputVariant.INVISIBLE}\n />\n <Button\n label={deleteButton.label.value}\n variant={ButtonVariant.HOVERABLE}\n size={ButtonSize.ICON_SM}\n color={ButtonColor.TEXT}\n className=\"translate-x-2\"\n Icon={Trash}\n onClick={() => {\n addEditedContent(dictionaryLocalId, undefined, keyPath);\n\n const parentKeyPath: KeyPath[] = keyPath.slice(0, -1);\n setFocusedContentKeyPath(parentKeyPath);\n }}\n />\n </div>\n\n <span className=\"ml-3 text-neutral text-sm\">\n ( {camelCaseToSentence(sectionKey)} )\n </span>\n </div>\n )}\n <NodeTypeView\n keyPath={keyPath}\n dictionaryLocalId={dictionaryLocalId}\n section={section}\n onNodeTypeChange={(content) => {\n addEditedContent(dictionaryLocalId, content, keyPath);\n }}\n />\n </div>\n </Container>\n );\n }\n);\n\ntype ObjectViewProps = {\n dictionaryLocalId: LocalDictionaryId;\n keyPath: KeyPath[];\n section: ContentNode;\n};\n\nexport const ObjectView: FC<ObjectViewProps> = ({\n section,\n keyPath,\n dictionaryLocalId,\n}) => {\n const { addNodeButton } = useIntlayer('structure-view');\n const { setFocusedContentKeyPath } = useFocusUnmergedDictionary();\n const { addEditedContent } = useEditedContentActions();\n\n // 1. Memoize keys to avoid unnecessary virtualizer resets\n const keys = useMemo(\n () => (section && typeof section === 'object' ? Object.keys(section) : []),\n [section]\n );\n\n // 2. Setup virtualization for large objects\n const parentRef = useRef<HTMLDivElement>(null);\n\n const rowVirtualizer = useVirtualizer({\n count: keys.length,\n getScrollElement: () => parentRef.current,\n estimateSize: () => 140, // Estimated height for a NodeView\n overscan: 5,\n });\n\n if (!section || typeof section !== 'object') {\n return <div>Not an object</div>;\n }\n\n return (\n <div className=\"flex flex-col gap-2\">\n <div\n ref={parentRef}\n className=\"flex max-h-[800px] flex-col gap-4 overflow-y-auto pr-2\"\n >\n <div\n style={{\n height: `${rowVirtualizer.getTotalSize()}px`,\n width: '100%',\n position: 'relative',\n }}\n >\n {rowVirtualizer.getVirtualItems().map((virtualRow) => {\n const key = keys[virtualRow.index];\n return (\n <div\n key={virtualRow.key}\n data-index={virtualRow.index}\n ref={rowVirtualizer.measureElement}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n transform: `translateY(${virtualRow.start}px)`,\n }}\n className=\"pb-4\"\n >\n <NodeView\n sectionKey={key}\n section={section?.[key as keyof typeof section]}\n keyPath={[\n ...keyPath,\n { type: NodeTypes.OBJECT, key } as KeyPath,\n ]}\n dictionaryLocalId={dictionaryLocalId}\n />\n </div>\n );\n })}\n </div>\n </div>\n\n <Button\n label={addNodeButton.label.value}\n variant={ButtonVariant.HOVERABLE}\n size={ButtonSize.MD}\n color={ButtonColor.TEXT}\n Icon={Plus}\n className=\"mt-2 flex-1\"\n onClick={() => {\n const newKey = 'newKey';\n const newKeyPath = [\n ...keyPath,\n { type: NodeTypes.OBJECT, key: newKey },\n ] as KeyPath[];\n addEditedContent(dictionaryLocalId, '', newKeyPath);\n setFocusedContentKeyPath(newKeyPath);\n }}\n >\n {addNodeButton.text}\n </Button>\n </div>\n );\n};\n\ntype StructureViewProps = {\n dictionaryLocalId: LocalDictionaryId;\n keyPath: KeyPath[];\n section: ContentNode;\n};\n\nexport const StructureView: FC<StructureViewProps> = ({\n section,\n keyPath,\n dictionaryLocalId,\n}) => {\n if (\n !section ||\n typeof section !== 'object' ||\n typeof section.nodeType === 'string'\n ) {\n return (\n <NodeView\n sectionKey={'content'}\n section={section}\n keyPath={keyPath}\n dictionaryLocalId={dictionaryLocalId}\n />\n );\n }\n\n return (\n <ObjectView\n section={section}\n keyPath={keyPath}\n dictionaryLocalId={dictionaryLocalId}\n />\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"StructureView.mjs","names":[],"sources":["../../../../../src/components/DictionaryFieldEditor/StructureView/StructureView.tsx"],"sourcesContent":["'use client';\n\nimport {\n Button,\n ButtonColor,\n ButtonSize,\n ButtonVariant,\n} from '@components/Button';\nimport { Container } from '@components/Container';\nimport { EditableFieldInput } from '@components/EditableField';\nimport { InputVariant } from '@components/Input';\nimport { camelCaseToSentence } from '@intlayer/config/client';\nimport {\n getDefaultNode,\n getNodeChildren,\n getNodeType,\n} from '@intlayer/core/dictionaryManipulator';\nimport { isSameKeyPath } from '@intlayer/core/utils';\nimport {\n useConfiguration,\n useEditedContentActions,\n useFocusUnmergedDictionary,\n} from '@intlayer/editor-react';\nimport type { LocalDictionaryId, TypedNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type { ContentNode } from 'intlayer';\nimport { Plus, Trash } from 'lucide-react';\nimport type { FC } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { NodeTypeSelector } from '../NodeTypeSelector';\n\ntype NodeTypeViewProps = {\n dictionaryLocalId: LocalDictionaryId;\n keyPath: KeyPath[];\n section: ContentNode;\n onNodeTypeChange: (content?: ContentNode) => void;\n};\n\nconst NodeTypeView: FC<NodeTypeViewProps> = ({\n section,\n dictionaryLocalId,\n keyPath,\n onNodeTypeChange: onNodeTypeChangeProp,\n}) => {\n const locales = useConfiguration()?.internationalization?.locales ?? [];\n const nodeType = getNodeType(section);\n const children = getNodeChildren(section);\n\n const onNodeTypeChange = (content?: ContentNode) => {\n const transformedContent = getDefaultNode(\n nodeType,\n locales,\n content\n ) as ContentNode;\n\n onNodeTypeChangeProp(transformedContent);\n };\n\n if (\n nodeType === NodeTypes.TRANSLATION ||\n nodeType === NodeTypes.CONDITION ||\n nodeType === NodeTypes.GENDER ||\n nodeType === NodeTypes.ENUMERATION ||\n nodeType === NodeTypes.PLURAL\n ) {\n const firstKey = Object.keys(\n (section as unknown as TypedNode)[nodeType as keyof typeof section]\n )[0];\n const childrenKeyPath = [\n ...keyPath,\n { type: nodeType, key: firstKey },\n ] as KeyPath[];\n\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <NodeTypeSelector\n section={section}\n onValueChange={(nodeType) =>\n onNodeTypeChangeProp(\n getDefaultNode(nodeType, locales) as ContentNode\n )\n }\n />\n\n <NodeTypeView\n section={children}\n keyPath={childrenKeyPath}\n dictionaryLocalId={dictionaryLocalId}\n onNodeTypeChange={onNodeTypeChange}\n />\n </div>\n );\n }\n\n if (nodeType === NodeTypes.ARRAY) {\n const childrenKeyPath = [...keyPath, { type: nodeType, key: 0 } as KeyPath];\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <NodeTypeSelector\n section={section}\n onValueChange={(nodeType) =>\n onNodeTypeChangeProp(\n getDefaultNode(nodeType, locales) as ContentNode\n )\n }\n />\n\n <NodeTypeView\n section={children}\n keyPath={childrenKeyPath}\n dictionaryLocalId={dictionaryLocalId}\n onNodeTypeChange={onNodeTypeChange}\n />\n </div>\n );\n }\n\n if (nodeType === NodeTypes.OBJECT) {\n return (\n <>\n <NodeTypeSelector\n section={section}\n onValueChange={(nodeType) =>\n onNodeTypeChangeProp(\n getDefaultNode(nodeType, locales) as ContentNode\n )\n }\n />\n <div className=\"mt-6 ml-10\">\n <StructureView\n keyPath={keyPath}\n section={section}\n dictionaryLocalId={dictionaryLocalId}\n />\n </div>\n </>\n );\n }\n\n return (\n <NodeTypeSelector\n section={section}\n onValueChange={(nodeType) =>\n onNodeTypeChangeProp(getDefaultNode(nodeType, locales) as ContentNode)\n }\n />\n );\n};\n\ntype NodeWrapperProps = {\n sectionKey?: string;\n dictionaryLocalId: LocalDictionaryId;\n keyPath: KeyPath[];\n section: ContentNode;\n};\n\nexport const NodeView: FC<NodeWrapperProps> = ({\n sectionKey,\n section,\n keyPath,\n dictionaryLocalId,\n}) => {\n const { focusedContent, setFocusedContentKeyPath } =\n useFocusUnmergedDictionary();\n const { renameEditedContent, addEditedContent } = useEditedContentActions();\n\n const { titleInput, deleteButton } = useIntlayer('structure-view');\n\n const handleRenameNodeKey = (keyName: string) => {\n renameEditedContent(dictionaryLocalId, keyName, keyPath);\n const prevKeyPath: KeyPath[] = keyPath.slice(0, -1);\n const lastKeyPath: KeyPath = keyPath[keyPath.length - 1];\n const newKeyPath: KeyPath[] = [\n ...prevKeyPath,\n { ...lastKeyPath, key: keyName } as KeyPath,\n ];\n setFocusedContentKeyPath(newKeyPath);\n };\n\n return (\n <Container\n transparency=\"xl\"\n roundedSize=\"xl\"\n className=\"w-full min-w-80 gap-2 overflow-auto px-5 py-2\"\n border\n borderColor=\"text\"\n background=\"none\"\n aria-selected={isSameKeyPath(keyPath, focusedContent?.keyPath ?? [])}\n onClick={() => setFocusedContentKeyPath(keyPath)}\n >\n <div className=\"flex w-full flex-col items-start justify-between gap-3\">\n {typeof sectionKey === 'string' && (\n <div className=\"w-full\">\n <div className=\"flex w-full items-center justify-between gap-10\">\n <EditableFieldInput\n name=\"key\"\n aria-label=\"Key\"\n placeholder={titleInput.placeholder.value}\n defaultValue={sectionKey}\n onSave={(value) => handleRenameNodeKey(value)}\n variant={InputVariant.INVISIBLE}\n />\n <Button\n label={deleteButton.label.value}\n variant={ButtonVariant.HOVERABLE}\n size={ButtonSize.ICON_SM}\n color={ButtonColor.TEXT}\n className=\"translate-x-2\"\n Icon={Trash}\n onClick={() => {\n addEditedContent(dictionaryLocalId, undefined, keyPath);\n\n const parentKeyPath: KeyPath[] = keyPath.slice(0, -1);\n setFocusedContentKeyPath(parentKeyPath);\n }}\n />\n </div>\n\n <span className=\"ml-3 text-neutral text-sm\">\n ( {camelCaseToSentence(sectionKey)} )\n </span>\n </div>\n )}\n <NodeTypeView\n keyPath={keyPath}\n dictionaryLocalId={dictionaryLocalId}\n section={section}\n onNodeTypeChange={(content) => {\n addEditedContent(dictionaryLocalId, content, keyPath);\n }}\n />\n </div>\n </Container>\n );\n};\n\ntype ObjectViewProps = {\n dictionaryLocalId: LocalDictionaryId;\n keyPath: KeyPath[];\n section: ContentNode;\n};\n\nexport const ObjectView: FC<ObjectViewProps> = ({\n section,\n keyPath,\n dictionaryLocalId,\n}) => {\n const { addNodeButton } = useIntlayer('structure-view');\n const { setFocusedContentKeyPath } = useFocusUnmergedDictionary();\n const { addEditedContent } = useEditedContentActions();\n\n if (!section || typeof section !== 'object') {\n return <div>Not an object</div>;\n }\n\n return (\n <div className=\"flex flex-col gap-2 overflow-y-auto\">\n <ul className=\"mr-auto flex flex-col gap-4\">\n {Object.keys(section).map((key) => (\n <li\n key={`${JSON.stringify(keyPath)}-object-${key}`}\n className=\"flex w-full\"\n >\n <NodeView\n sectionKey={key}\n section={section?.[key as keyof typeof section]}\n keyPath={[...keyPath, { type: NodeTypes.OBJECT, key }]}\n dictionaryLocalId={dictionaryLocalId}\n />\n </li>\n ))}\n </ul>\n <Button\n label={addNodeButton.label.value}\n variant={ButtonVariant.HOVERABLE}\n size={ButtonSize.MD}\n color={ButtonColor.TEXT}\n Icon={Plus}\n className=\"flex-1\"\n onClick={() => {\n const newKey = 'newKey';\n const newKeyPath = [\n ...keyPath,\n { type: NodeTypes.OBJECT, key: newKey },\n ] as KeyPath[];\n addEditedContent(dictionaryLocalId, '', newKeyPath);\n setFocusedContentKeyPath(newKeyPath);\n }}\n >\n {addNodeButton.text}\n </Button>\n </div>\n );\n};\n\ntype StructureViewProps = {\n dictionaryLocalId: LocalDictionaryId;\n keyPath: KeyPath[];\n section: ContentNode;\n};\n\nexport const StructureView: FC<StructureViewProps> = ({\n section,\n keyPath,\n dictionaryLocalId,\n}) => {\n if (\n !section ||\n typeof section !== 'object' ||\n typeof section.nodeType === 'string'\n ) {\n return (\n <NodeView\n sectionKey={'content'}\n section={section}\n keyPath={keyPath}\n dictionaryLocalId={dictionaryLocalId}\n />\n );\n }\n\n return (\n <ObjectView\n section={section}\n keyPath={keyPath}\n dictionaryLocalId={dictionaryLocalId}\n />\n );\n};\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
- import { useItemSelector } from "../../../hooks/useItemSelector.mjs";
4
3
  import { InputIndicator, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "../../Input/OTPInput.mjs";
4
+ import { useItemSelector } from "../../../hooks/useItemSelector.mjs";
5
5
  import { useFormField } from "../FormField.mjs";
6
6
  import { FormItemLayout } from "../layout/FormItemLayout.mjs";
7
7
  import { Form } from "../Form.mjs";
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
- import { useCodeContext } from "./CodeContext.mjs";
4
3
  import { Select } from "../Select/Select.mjs";
4
+ import { useCodeContext } from "./CodeContext.mjs";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useIntlayer } from "react-intlayer";
7
7
 
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
- import { useCodeContext } from "./CodeContext.mjs";
4
3
  import { Select } from "../Select/Select.mjs";
4
+ import { useCodeContext } from "./CodeContext.mjs";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useIntlayer } from "react-intlayer";
7
7
 
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
- import { useCodeContext } from "./CodeContext.mjs";
4
3
  import { Select } from "../Select/Select.mjs";
4
+ import { useCodeContext } from "./CodeContext.mjs";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useIntlayer } from "react-intlayer";
7
7
 
@@ -3,7 +3,7 @@
3
3
  import { cn } from "../../utils/cn.mjs";
4
4
  import { Container } from "../Container/index.mjs";
5
5
  import { Flag } from "../Flags/Flag.mjs";
6
- import { useEffect, useState } from "react";
6
+ import { Suspense, useEffect, useState } from "react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { ALL_LOCALES, getHTMLTextDir, getLocaleName } from "intlayer";
9
9
 
@@ -56,9 +56,9 @@ const LanguageSection = ({ className, ...props }) => {
56
56
  return /* @__PURE__ */ jsx("section", {
57
57
  className: cn("mask-[linear-gradient(to_right,transparent_0,black_128px,black_calc(100%-128px),transparent_100%)] my-10 w-full overflow-hidden", className),
58
58
  ...props,
59
- children: /* @__PURE__ */ jsxs("div", {
59
+ children: /* @__PURE__ */ jsx("div", {
60
60
  className: "relative flex w-full flex-col gap-5 py-3",
61
- children: [
61
+ children: /* @__PURE__ */ jsxs(Suspense, { children: [
62
62
  /* @__PURE__ */ jsx(LocalCardList, {
63
63
  localeList: firstPart,
64
64
  className: "horizontal-loop-1"
@@ -75,7 +75,7 @@ const LanguageSection = ({ className, ...props }) => {
75
75
  localeList: fourthPart,
76
76
  className: "horizontal-loop-2"
77
77
  })
78
- ]
78
+ ] })
79
79
  })
80
80
  });
81
81
  };