@neo4j-ndl/react 4.21.2 → 4.22.1

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 (185) hide show
  1. package/lib/cjs/_common/form-control/FormFieldLabel.js +52 -0
  2. package/lib/cjs/_common/form-control/FormFieldLabel.js.map +1 -0
  3. package/lib/cjs/_common/form-control/FormFieldMessage.js +72 -0
  4. package/lib/cjs/_common/form-control/FormFieldMessage.js.map +1 -0
  5. package/lib/cjs/_common/form-control/form-control-types.js +23 -0
  6. package/lib/cjs/_common/form-control/form-control-types.js.map +1 -0
  7. package/lib/cjs/_common/form-control/index.js +39 -0
  8. package/lib/cjs/_common/form-control/index.js.map +1 -0
  9. package/lib/cjs/_common/form-control/use-form-field.js +76 -0
  10. package/lib/cjs/_common/form-control/use-form-field.js.map +1 -0
  11. package/lib/cjs/_common/form-control/use-inline-field-label.js +76 -0
  12. package/lib/cjs/_common/form-control/use-inline-field-label.js.map +1 -0
  13. package/lib/cjs/checkbox/Checkbox.js +9 -21
  14. package/lib/cjs/checkbox/Checkbox.js.map +1 -1
  15. package/lib/cjs/combobox/Combobox.js +61 -45
  16. package/lib/cjs/combobox/Combobox.js.map +1 -1
  17. package/lib/cjs/combobox/combobox-types.js.map +1 -1
  18. package/lib/cjs/date-picker/DatePicker.js.map +1 -1
  19. package/lib/cjs/dropzone/stories/dropzone-full.story.js +5 -5
  20. package/lib/cjs/dropzone/stories/dropzone-full.story.js.map +1 -1
  21. package/lib/cjs/helpers/index.js +1 -0
  22. package/lib/cjs/helpers/index.js.map +1 -1
  23. package/lib/cjs/helpers/platform.js +59 -0
  24. package/lib/cjs/helpers/platform.js.map +1 -0
  25. package/lib/cjs/kbd/kbd-utils.js +6 -22
  26. package/lib/cjs/kbd/kbd-utils.js.map +1 -1
  27. package/lib/cjs/next/tree-view/TreeView.js +384 -66
  28. package/lib/cjs/next/tree-view/TreeView.js.map +1 -1
  29. package/lib/cjs/next/tree-view/selection.js +181 -0
  30. package/lib/cjs/next/tree-view/selection.js.map +1 -0
  31. package/lib/cjs/next/tree-view/stories/index.js +13 -1
  32. package/lib/cjs/next/tree-view/stories/index.js.map +1 -1
  33. package/lib/cjs/next/tree-view/stories/tree-view-large.story.js +57 -0
  34. package/lib/cjs/next/tree-view/stories/tree-view-large.story.js.map +1 -0
  35. package/lib/cjs/next/tree-view/stories/tree-view-lazy.story.js +1 -0
  36. package/lib/cjs/next/tree-view/stories/tree-view-lazy.story.js.map +1 -1
  37. package/lib/cjs/next/tree-view/stories/tree-view-multi.story.js +16 -40
  38. package/lib/cjs/next/tree-view/stories/tree-view-multi.story.js.map +1 -1
  39. package/lib/cjs/next/tree-view/stories/tree-view-multiple-replace.story.js +38 -0
  40. package/lib/cjs/next/tree-view/stories/tree-view-multiple-replace.story.js.map +1 -0
  41. package/lib/cjs/next/tree-view/stories/tree-view-non-selectable-folders.story.js +7 -4
  42. package/lib/cjs/next/tree-view/stories/tree-view-non-selectable-folders.story.js.map +1 -1
  43. package/lib/cjs/next/tree-view/stories/tree-view-root-selection.story.js +125 -0
  44. package/lib/cjs/next/tree-view/stories/tree-view-root-selection.story.js.map +1 -0
  45. package/lib/cjs/radio/Radio.js +12 -22
  46. package/lib/cjs/radio/Radio.js.map +1 -1
  47. package/lib/cjs/select/Select.js +14 -5
  48. package/lib/cjs/select/Select.js.map +1 -1
  49. package/lib/cjs/select/types.js.map +1 -1
  50. package/lib/cjs/switch/Switch.js +9 -21
  51. package/lib/cjs/switch/Switch.js.map +1 -1
  52. package/lib/cjs/text-area/TextArea.js +8 -21
  53. package/lib/cjs/text-area/TextArea.js.map +1 -1
  54. package/lib/cjs/text-input/TextInput.js +15 -38
  55. package/lib/cjs/text-input/TextInput.js.map +1 -1
  56. package/lib/cjs/text-input/stories/text-input-sizes.story.js +1 -1
  57. package/lib/cjs/text-input/stories/text-input-sizes.story.js.map +1 -1
  58. package/lib/cjs/time-picker/TimePicker.js +13 -7
  59. package/lib/cjs/time-picker/TimePicker.js.map +1 -1
  60. package/lib/cjs/timezone-picker/TimeZonePicker.js +13 -7
  61. package/lib/cjs/timezone-picker/TimeZonePicker.js.map +1 -1
  62. package/lib/cjs/toast/ToastControlled.js +1 -1
  63. package/lib/cjs/toast/ToastControlled.js.map +1 -1
  64. package/lib/esm/_common/form-control/FormFieldLabel.js +45 -0
  65. package/lib/esm/_common/form-control/FormFieldLabel.js.map +1 -0
  66. package/lib/esm/_common/form-control/FormFieldMessage.js +65 -0
  67. package/lib/esm/_common/form-control/FormFieldMessage.js.map +1 -0
  68. package/lib/esm/_common/form-control/form-control-types.js +22 -0
  69. package/lib/esm/_common/form-control/form-control-types.js.map +1 -0
  70. package/lib/esm/_common/form-control/index.js +32 -0
  71. package/lib/esm/_common/form-control/index.js.map +1 -0
  72. package/lib/esm/_common/form-control/use-form-field.js +72 -0
  73. package/lib/esm/_common/form-control/use-form-field.js.map +1 -0
  74. package/lib/esm/_common/form-control/use-inline-field-label.js +69 -0
  75. package/lib/esm/_common/form-control/use-inline-field-label.js.map +1 -0
  76. package/lib/esm/checkbox/Checkbox.js +10 -22
  77. package/lib/esm/checkbox/Checkbox.js.map +1 -1
  78. package/lib/esm/combobox/Combobox.js +62 -46
  79. package/lib/esm/combobox/Combobox.js.map +1 -1
  80. package/lib/esm/combobox/combobox-types.js.map +1 -1
  81. package/lib/esm/date-picker/DatePicker.js.map +1 -1
  82. package/lib/esm/dropzone/stories/dropzone-full.story.js +5 -5
  83. package/lib/esm/dropzone/stories/dropzone-full.story.js.map +1 -1
  84. package/lib/esm/helpers/index.js +1 -0
  85. package/lib/esm/helpers/index.js.map +1 -1
  86. package/lib/esm/helpers/platform.js +55 -0
  87. package/lib/esm/helpers/platform.js.map +1 -0
  88. package/lib/esm/kbd/kbd-utils.js +2 -18
  89. package/lib/esm/kbd/kbd-utils.js.map +1 -1
  90. package/lib/esm/next/tree-view/TreeView.js +385 -67
  91. package/lib/esm/next/tree-view/TreeView.js.map +1 -1
  92. package/lib/esm/next/tree-view/selection.js +175 -0
  93. package/lib/esm/next/tree-view/selection.js.map +1 -0
  94. package/lib/esm/next/tree-view/stories/index.js +9 -0
  95. package/lib/esm/next/tree-view/stories/index.js.map +1 -1
  96. package/lib/esm/next/tree-view/stories/tree-view-large.story.js +55 -0
  97. package/lib/esm/next/tree-view/stories/tree-view-large.story.js.map +1 -0
  98. package/lib/esm/next/tree-view/stories/tree-view-lazy.story.js +1 -0
  99. package/lib/esm/next/tree-view/stories/tree-view-lazy.story.js.map +1 -1
  100. package/lib/esm/next/tree-view/stories/tree-view-multi.story.js +16 -40
  101. package/lib/esm/next/tree-view/stories/tree-view-multi.story.js.map +1 -1
  102. package/lib/esm/next/tree-view/stories/tree-view-multiple-replace.story.js +36 -0
  103. package/lib/esm/next/tree-view/stories/tree-view-multiple-replace.story.js.map +1 -0
  104. package/lib/esm/next/tree-view/stories/tree-view-non-selectable-folders.story.js +7 -4
  105. package/lib/esm/next/tree-view/stories/tree-view-non-selectable-folders.story.js.map +1 -1
  106. package/lib/esm/next/tree-view/stories/tree-view-root-selection.story.js +123 -0
  107. package/lib/esm/next/tree-view/stories/tree-view-root-selection.story.js.map +1 -0
  108. package/lib/esm/radio/Radio.js +12 -22
  109. package/lib/esm/radio/Radio.js.map +1 -1
  110. package/lib/esm/select/Select.js +14 -5
  111. package/lib/esm/select/Select.js.map +1 -1
  112. package/lib/esm/select/types.js.map +1 -1
  113. package/lib/esm/switch/Switch.js +10 -22
  114. package/lib/esm/switch/Switch.js.map +1 -1
  115. package/lib/esm/text-area/TextArea.js +9 -22
  116. package/lib/esm/text-area/TextArea.js.map +1 -1
  117. package/lib/esm/text-input/TextInput.js +15 -38
  118. package/lib/esm/text-input/TextInput.js.map +1 -1
  119. package/lib/esm/text-input/stories/text-input-sizes.story.js +1 -1
  120. package/lib/esm/text-input/stories/text-input-sizes.story.js.map +1 -1
  121. package/lib/esm/time-picker/TimePicker.js +13 -7
  122. package/lib/esm/time-picker/TimePicker.js.map +1 -1
  123. package/lib/esm/timezone-picker/TimeZonePicker.js +13 -7
  124. package/lib/esm/timezone-picker/TimeZonePicker.js.map +1 -1
  125. package/lib/esm/toast/ToastControlled.js +1 -1
  126. package/lib/esm/toast/ToastControlled.js.map +1 -1
  127. package/lib/types/_common/form-control/FormFieldLabel.d.ts +58 -0
  128. package/lib/types/_common/form-control/FormFieldLabel.d.ts.map +1 -0
  129. package/lib/types/_common/form-control/FormFieldMessage.d.ts +46 -0
  130. package/lib/types/_common/form-control/FormFieldMessage.d.ts.map +1 -0
  131. package/lib/types/_common/form-control/form-control-types.d.ts +92 -0
  132. package/lib/types/_common/form-control/form-control-types.d.ts.map +1 -0
  133. package/lib/types/_common/form-control/index.d.ts +33 -0
  134. package/lib/types/_common/form-control/index.d.ts.map +1 -0
  135. package/lib/types/_common/form-control/use-form-field.d.ts +53 -0
  136. package/lib/types/_common/form-control/use-form-field.d.ts.map +1 -0
  137. package/lib/types/_common/form-control/use-inline-field-label.d.ts +69 -0
  138. package/lib/types/_common/form-control/use-inline-field-label.d.ts.map +1 -0
  139. package/lib/types/checkbox/Checkbox.d.ts.map +1 -1
  140. package/lib/types/combobox/Combobox.d.ts.map +1 -1
  141. package/lib/types/combobox/combobox-types.d.ts +1 -1
  142. package/lib/types/combobox/combobox-types.d.ts.map +1 -1
  143. package/lib/types/helpers/index.d.ts +1 -0
  144. package/lib/types/helpers/index.d.ts.map +1 -1
  145. package/lib/types/helpers/platform.d.ts +29 -0
  146. package/lib/types/helpers/platform.d.ts.map +1 -0
  147. package/lib/types/kbd/kbd-utils.d.ts +2 -5
  148. package/lib/types/kbd/kbd-utils.d.ts.map +1 -1
  149. package/lib/types/next/tree-view/TreeView.d.ts +29 -5
  150. package/lib/types/next/tree-view/TreeView.d.ts.map +1 -1
  151. package/lib/types/next/tree-view/selection.d.ts +78 -0
  152. package/lib/types/next/tree-view/selection.d.ts.map +1 -0
  153. package/lib/types/next/tree-view/stories/index.d.ts +6 -0
  154. package/lib/types/next/tree-view/stories/index.d.ts.map +1 -1
  155. package/lib/types/next/tree-view/stories/tree-view-large.story.d.ts +24 -0
  156. package/lib/types/next/tree-view/stories/tree-view-large.story.d.ts.map +1 -0
  157. package/lib/types/next/tree-view/stories/tree-view-lazy.story.d.ts.map +1 -1
  158. package/lib/types/next/tree-view/stories/tree-view-multi.story.d.ts +10 -0
  159. package/lib/types/next/tree-view/stories/tree-view-multi.story.d.ts.map +1 -1
  160. package/lib/types/next/tree-view/stories/tree-view-multiple-replace.story.d.ts +29 -0
  161. package/lib/types/next/tree-view/stories/tree-view-multiple-replace.story.d.ts.map +1 -0
  162. package/lib/types/next/tree-view/stories/tree-view-non-selectable-folders.story.d.ts +5 -0
  163. package/lib/types/next/tree-view/stories/tree-view-non-selectable-folders.story.d.ts.map +1 -1
  164. package/lib/types/next/tree-view/stories/tree-view-root-selection.story.d.ts +24 -0
  165. package/lib/types/next/tree-view/stories/tree-view-root-selection.story.d.ts.map +1 -0
  166. package/lib/types/radio/Radio.d.ts.map +1 -1
  167. package/lib/types/select/Select.d.ts.map +1 -1
  168. package/lib/types/select/types.d.ts.map +1 -1
  169. package/lib/types/switch/Switch.d.ts.map +1 -1
  170. package/lib/types/text-area/TextArea.d.ts.map +1 -1
  171. package/lib/types/text-input/TextInput.d.ts.map +1 -1
  172. package/lib/types/text-input/stories/text-input-sizes.story.d.ts.map +1 -1
  173. package/lib/types/time-picker/TimePicker.d.ts +3 -1
  174. package/lib/types/time-picker/TimePicker.d.ts.map +1 -1
  175. package/lib/types/timezone-picker/TimeZonePicker.d.ts +4 -1
  176. package/lib/types/timezone-picker/TimeZonePicker.d.ts.map +1 -1
  177. package/package.json +2 -2
  178. package/skills/ndl-react/SKILL.md +1 -1
  179. package/skills/ndl-react/components/color-picker.md +32 -32
  180. package/skills/ndl-react/components/combobox.md +2 -2
  181. package/skills/ndl-react/components/dropzone.md +5 -5
  182. package/skills/ndl-react/components/next/tree-view.md +444 -104
  183. package/skills/ndl-react/components/text-input.md +6 -0
  184. package/skills/ndl-react/components/time-picker.md +1 -0
  185. package/skills/ndl-react/components/timezone-picker.md +1 -0
@@ -137,6 +137,7 @@ function renderNode(node, ctx) {
137
137
  node.children.length > 0;
138
138
  const state = ctx.getNodeState(node.id);
139
139
  return ((0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: node.label, hasChildren: hasChildren, isExpanded: state.isExpanded, isLoading: state.isLoading, isSelected: ctx.selectedId === node.id, leadingVisual: iconForNode(node), onExpandedChange: (expanded) => ctx.handleExpand(node.id, expanded), onSelectedChange: () => ctx.handleSelect(node.id), children: [hasChildren && state.isLoading && !state.hasLoaded && ((0, jsx_runtime_1.jsx)(next_1.TreeView.SkeletonItem, { rows: 2 })), hasChildren &&
140
+ state.isExpanded &&
140
141
  state.hasLoaded &&
141
142
  node.children.map((child) => renderNode(child, ctx))] }, node.id));
142
143
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tree-view-lazy.story.js","sourceRoot":"","sources":["../../../../../src/next/tree-view/stories/tree-view-lazy.story.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport '@neo4j-ndl/base/lib/neo4j-ds-styles.css';\n\nimport {\n DocumentIconOutline,\n FolderIconSolid,\n PhotoIconOutline,\n} from '@neo4j-ndl/react/icons';\nimport { TreeView } from '@neo4j-ndl/react/next';\nimport { useCallback, useMemo, useRef, useState } from 'react';\n\ntype TreeNode = {\n id: string;\n label: string;\n children?: TreeNode[];\n};\n\nconst TREE_DATA: TreeNode[] = [\n {\n children: [\n {\n children: [\n { id: 'app-tsx', label: 'App.tsx' },\n { id: 'index-tsx', label: 'index.tsx' },\n { id: 'styles-css', label: 'styles.css' },\n ],\n id: 'frontend',\n label: 'Frontend',\n },\n {\n children: [\n { id: 'server-ts', label: 'server.ts' },\n { id: 'routes-ts', label: 'routes.ts' },\n ],\n id: 'backend',\n label: 'Backend',\n },\n { id: 'readme-md', label: 'README.md' },\n ],\n id: 'projects',\n label: 'Projects',\n },\n {\n children: [\n {\n children: [\n { id: 'beach-jpg', label: 'beach.jpg' },\n { id: 'sunset-jpg', label: 'sunset.jpg' },\n ],\n id: 'vacation',\n label: 'Vacation',\n },\n { id: 'profile-png', label: 'profile.png' },\n ],\n id: 'photos',\n label: 'Photos',\n },\n {\n children: [\n { id: 'resume-pdf', label: 'resume.pdf' },\n { id: 'cover-letter-pdf', label: 'cover-letter.pdf' },\n { id: 'notes-txt', label: 'notes.txt' },\n ],\n id: 'documents',\n label: 'Documents',\n },\n {\n children: [\n {\n children: [\n { id: 'chill-m3u', label: 'chill.m3u' },\n { id: 'workout-m3u', label: 'workout.m3u' },\n ],\n id: 'playlists',\n label: 'Playlists',\n },\n { id: 'favorites-m3u', label: 'favorites.m3u' },\n ],\n id: 'music',\n label: 'Music',\n },\n { id: 'todo-txt', label: 'TODO.txt' },\n];\n\nconst LOAD_DELAY_MS = 600;\n\nfunction iconForNode(node: TreeNode) {\n if (node.children) {\n return <FolderIconSolid />;\n }\n if (/\\.(jpg|jpeg|png|gif|svg)$/i.test(node.label)) {\n return <PhotoIconOutline />;\n }\n return <DocumentIconOutline />;\n}\n\ntype NodeState = {\n isExpanded: boolean;\n isLoading: boolean;\n hasLoaded: boolean;\n};\n\nconst INITIAL_NODE_STATE: NodeState = {\n hasLoaded: false,\n isExpanded: false,\n isLoading: false,\n};\n\nfunction useTreeState() {\n const [nodeStates, setNodeStates] = useState<Record<string, NodeState>>({});\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const timers = useRef<Record<string, ReturnType<typeof setTimeout>>>({});\n\n const getNodeState = useCallback(\n (id: string): NodeState => nodeStates[id] ?? INITIAL_NODE_STATE,\n [nodeStates],\n );\n\n const handleExpand = useCallback((id: string, expanded: boolean) => {\n setNodeStates((prev) => {\n const current = prev[id] ?? INITIAL_NODE_STATE;\n if (expanded && !current.hasLoaded) {\n if (timers.current[id]) {\n clearTimeout(timers.current[id]);\n }\n timers.current[id] = setTimeout(() => {\n setNodeStates((prev) => ({\n ...prev,\n [id]: { hasLoaded: true, isExpanded: true, isLoading: false },\n }));\n delete timers.current[id];\n }, LOAD_DELAY_MS);\n return {\n ...prev,\n [id]: { hasLoaded: false, isExpanded: true, isLoading: true },\n };\n }\n return { ...prev, [id]: { ...current, isExpanded: expanded } };\n });\n }, []);\n\n const handleSelect = useCallback(\n (id: string) => setSelectedId((prev) => (prev === id ? null : id)),\n [],\n );\n\n return { getNodeState, handleExpand, handleSelect, selectedId };\n}\n\ntype RenderContext = {\n getNodeState: (id: string) => NodeState;\n selectedId: string | null;\n handleExpand: (id: string, expanded: boolean) => void;\n handleSelect: (id: string) => void;\n};\n\nfunction renderNode(node: TreeNode, ctx: RenderContext) {\n const hasChildren =\n node.children !== undefined &&\n node.children !== null &&\n node.children.length > 0;\n const state = ctx.getNodeState(node.id);\n\n return (\n <TreeView.Item\n key={node.id}\n title={node.label}\n hasChildren={hasChildren}\n isExpanded={state.isExpanded}\n isLoading={state.isLoading}\n isSelected={ctx.selectedId === node.id}\n leadingVisual={iconForNode(node)}\n onExpandedChange={(expanded: boolean) =>\n ctx.handleExpand(node.id, expanded)\n }\n onSelectedChange={() => ctx.handleSelect(node.id)}\n >\n {hasChildren && state.isLoading && !state.hasLoaded && (\n <TreeView.SkeletonItem rows={2} />\n )}\n {hasChildren &&\n state.hasLoaded &&\n node.children!.map((child) => renderNode(child, ctx))}\n </TreeView.Item>\n );\n}\n\nconst Component = () => {\n const { getNodeState, selectedId, handleExpand, handleSelect } =\n useTreeState();\n\n const ctx = useMemo<RenderContext>(\n () => ({ getNodeState, handleExpand, handleSelect, selectedId }),\n [getNodeState, selectedId, handleExpand, handleSelect],\n );\n\n return (\n <TreeView ariaLabel=\"Lazy-loaded file explorer\">\n {TREE_DATA.map((node) => renderNode(node, ctx))}\n </TreeView>\n );\n};\n\nexport default Component;\n"]}
1
+ {"version":3,"file":"tree-view-lazy.story.js","sourceRoot":"","sources":["../../../../../src/next/tree-view/stories/tree-view-lazy.story.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport '@neo4j-ndl/base/lib/neo4j-ds-styles.css';\n\nimport {\n DocumentIconOutline,\n FolderIconSolid,\n PhotoIconOutline,\n} from '@neo4j-ndl/react/icons';\nimport { TreeView } from '@neo4j-ndl/react/next';\nimport { useCallback, useMemo, useRef, useState } from 'react';\n\ntype TreeNode = {\n id: string;\n label: string;\n children?: TreeNode[];\n};\n\nconst TREE_DATA: TreeNode[] = [\n {\n children: [\n {\n children: [\n { id: 'app-tsx', label: 'App.tsx' },\n { id: 'index-tsx', label: 'index.tsx' },\n { id: 'styles-css', label: 'styles.css' },\n ],\n id: 'frontend',\n label: 'Frontend',\n },\n {\n children: [\n { id: 'server-ts', label: 'server.ts' },\n { id: 'routes-ts', label: 'routes.ts' },\n ],\n id: 'backend',\n label: 'Backend',\n },\n { id: 'readme-md', label: 'README.md' },\n ],\n id: 'projects',\n label: 'Projects',\n },\n {\n children: [\n {\n children: [\n { id: 'beach-jpg', label: 'beach.jpg' },\n { id: 'sunset-jpg', label: 'sunset.jpg' },\n ],\n id: 'vacation',\n label: 'Vacation',\n },\n { id: 'profile-png', label: 'profile.png' },\n ],\n id: 'photos',\n label: 'Photos',\n },\n {\n children: [\n { id: 'resume-pdf', label: 'resume.pdf' },\n { id: 'cover-letter-pdf', label: 'cover-letter.pdf' },\n { id: 'notes-txt', label: 'notes.txt' },\n ],\n id: 'documents',\n label: 'Documents',\n },\n {\n children: [\n {\n children: [\n { id: 'chill-m3u', label: 'chill.m3u' },\n { id: 'workout-m3u', label: 'workout.m3u' },\n ],\n id: 'playlists',\n label: 'Playlists',\n },\n { id: 'favorites-m3u', label: 'favorites.m3u' },\n ],\n id: 'music',\n label: 'Music',\n },\n { id: 'todo-txt', label: 'TODO.txt' },\n];\n\nconst LOAD_DELAY_MS = 600;\n\nfunction iconForNode(node: TreeNode) {\n if (node.children) {\n return <FolderIconSolid />;\n }\n if (/\\.(jpg|jpeg|png|gif|svg)$/i.test(node.label)) {\n return <PhotoIconOutline />;\n }\n return <DocumentIconOutline />;\n}\n\ntype NodeState = {\n isExpanded: boolean;\n isLoading: boolean;\n hasLoaded: boolean;\n};\n\nconst INITIAL_NODE_STATE: NodeState = {\n hasLoaded: false,\n isExpanded: false,\n isLoading: false,\n};\n\nfunction useTreeState() {\n const [nodeStates, setNodeStates] = useState<Record<string, NodeState>>({});\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const timers = useRef<Record<string, ReturnType<typeof setTimeout>>>({});\n\n const getNodeState = useCallback(\n (id: string): NodeState => nodeStates[id] ?? INITIAL_NODE_STATE,\n [nodeStates],\n );\n\n const handleExpand = useCallback((id: string, expanded: boolean) => {\n setNodeStates((prev) => {\n const current = prev[id] ?? INITIAL_NODE_STATE;\n if (expanded && !current.hasLoaded) {\n if (timers.current[id]) {\n clearTimeout(timers.current[id]);\n }\n timers.current[id] = setTimeout(() => {\n setNodeStates((prev) => ({\n ...prev,\n [id]: { hasLoaded: true, isExpanded: true, isLoading: false },\n }));\n delete timers.current[id];\n }, LOAD_DELAY_MS);\n return {\n ...prev,\n [id]: { hasLoaded: false, isExpanded: true, isLoading: true },\n };\n }\n return { ...prev, [id]: { ...current, isExpanded: expanded } };\n });\n }, []);\n\n const handleSelect = useCallback(\n (id: string) => setSelectedId((prev) => (prev === id ? null : id)),\n [],\n );\n\n return { getNodeState, handleExpand, handleSelect, selectedId };\n}\n\ntype RenderContext = {\n getNodeState: (id: string) => NodeState;\n selectedId: string | null;\n handleExpand: (id: string, expanded: boolean) => void;\n handleSelect: (id: string) => void;\n};\n\nfunction renderNode(node: TreeNode, ctx: RenderContext) {\n const hasChildren =\n node.children !== undefined &&\n node.children !== null &&\n node.children.length > 0;\n const state = ctx.getNodeState(node.id);\n\n return (\n <TreeView.Item\n key={node.id}\n title={node.label}\n hasChildren={hasChildren}\n isExpanded={state.isExpanded}\n isLoading={state.isLoading}\n isSelected={ctx.selectedId === node.id}\n leadingVisual={iconForNode(node)}\n onExpandedChange={(expanded: boolean) =>\n ctx.handleExpand(node.id, expanded)\n }\n onSelectedChange={() => ctx.handleSelect(node.id)}\n >\n {hasChildren && state.isLoading && !state.hasLoaded && (\n <TreeView.SkeletonItem rows={2} />\n )}\n {/* Rendering children only while expanded keeps collapsed subtrees out\n of the DOM, so large trees only pay for the rows the user can see.\n All item state lives outside the tree (keyed by node id), so nothing\n is lost when a subtree unmounts on collapse. */}\n {hasChildren &&\n state.isExpanded &&\n state.hasLoaded &&\n node.children!.map((child) => renderNode(child, ctx))}\n </TreeView.Item>\n );\n}\n\nconst Component = () => {\n const { getNodeState, selectedId, handleExpand, handleSelect } =\n useTreeState();\n\n const ctx = useMemo<RenderContext>(\n () => ({ getNodeState, handleExpand, handleSelect, selectedId }),\n [getNodeState, selectedId, handleExpand, handleSelect],\n );\n\n return (\n <TreeView ariaLabel=\"Lazy-loaded file explorer\">\n {TREE_DATA.map((node) => renderNode(node, ctx))}\n </TreeView>\n );\n};\n\nexport default Component;\n"]}
@@ -25,49 +25,25 @@ require("@neo4j-ndl/base/lib/neo4j-ds-styles.css");
25
25
  const icons_1 = require("@neo4j-ndl/react/icons");
26
26
  const next_1 = require("@neo4j-ndl/react/next");
27
27
  const react_1 = require("react");
28
- const WORK_CHILDREN = ['report', 'presentation'];
29
- const DOC_CHILDREN = ['work', 'resume'];
30
- const IMAGE_CHILDREN = ['photo', 'screenshot'];
31
- const DISABLED_KEYS = new Set(['presentation']);
32
- function getParentChecked(checked, childKeys) {
33
- const enabledKeys = childKeys.filter((key) => !DISABLED_KEYS.has(key));
34
- if (enabledKeys.length === 0) {
35
- return { isChecked: false, isIndeterminate: false };
36
- }
37
- const checkedCount = enabledKeys.filter((key) => checked[key]).length;
38
- if (checkedCount === 0) {
39
- return { isChecked: false, isIndeterminate: false };
40
- }
41
- if (checkedCount === enabledKeys.length) {
42
- return { isChecked: true, isIndeterminate: false };
43
- }
44
- return { isChecked: false, isIndeterminate: true };
45
- }
28
+ /**
29
+ * Every row owns its own checkbox: `onSelectedChange` reports the state the row
30
+ * should end up in, and the story stores exactly that. Folders are ordinary
31
+ * selectable rows here, unrelated to what sits inside them.
32
+ *
33
+ * Deriving a folder's state from its children instead needs the tree to own the
34
+ * selection, since a Shift range moves several rows at once and a cascade has
35
+ * to be applied to the whole set in one pass. See the root-managed selection
36
+ * story for that.
37
+ */
46
38
  const Component = () => {
39
+ var _a, _b, _c, _d, _e, _f, _g, _h;
47
40
  const [expanded, setExpanded] = (0, react_1.useState)({});
48
- const [checked, setChecked] = (0, react_1.useState)({});
49
- const toggle = (key) => setExpanded((prev) => (Object.assign(Object.assign({}, prev), { [key]: !prev[key] })));
50
- const toggleCheck = (0, react_1.useCallback)((key) => {
51
- setChecked((prev) => (Object.assign(Object.assign({}, prev), { [key]: !prev[key] })));
41
+ const [selected, setSelected] = (0, react_1.useState)({});
42
+ const toggleExpanded = (key) => setExpanded((prev) => (Object.assign(Object.assign({}, prev), { [key]: !prev[key] })));
43
+ const setRowSelected = (0, react_1.useCallback)((key, isSelected) => {
44
+ setSelected((prev) => (Object.assign(Object.assign({}, prev), { [key]: isSelected })));
52
45
  }, []);
53
- const toggleParent = (0, react_1.useCallback)((childKeys) => {
54
- const enabledKeys = childKeys.filter((key) => !DISABLED_KEYS.has(key));
55
- const isAllChecked = enabledKeys.every((key) => checked[key]);
56
- setChecked((prev) => {
57
- const next = Object.assign({}, prev);
58
- for (const key of enabledKeys) {
59
- next[key] = !isAllChecked;
60
- }
61
- return next;
62
- });
63
- }, [checked]);
64
- const docState = getParentChecked(checked, [
65
- ...DOC_CHILDREN,
66
- ...WORK_CHILDREN,
67
- ]);
68
- const workState = getParentChecked(checked, WORK_CHILDREN);
69
- const imageState = getParentChecked(checked, IMAGE_CHILDREN);
70
- return ((0, jsx_runtime_1.jsxs)(next_1.TreeView, { ariaLabel: "File explorer", selectionMode: "multiple", children: [(0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: "Documents", hasChildren: true, isExpanded: expanded['documents'], onExpandedChange: () => toggle('documents'), isSelected: docState.isChecked, isIndeterminate: docState.isIndeterminate, onSelectedChange: () => toggleParent([...DOC_CHILDREN, ...WORK_CHILDREN]), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: "Work", hasChildren: true, isExpanded: expanded['work'], onExpandedChange: () => toggle('work'), isSelected: workState.isChecked, isIndeterminate: workState.isIndeterminate, onSelectedChange: () => toggleParent(WORK_CHILDREN), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Report.pdf", isSelected: !!checked['report'], onSelectedChange: () => toggleCheck('report'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Presentation.pptx", isDisabled: true, onSelectedChange: () => null, leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Resume.pdf", isSelected: !!checked['resume'], onSelectedChange: () => toggleCheck('resume'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] }), (0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: "Images", hasChildren: true, isExpanded: expanded['images'], onExpandedChange: () => toggle('images'), isSelected: imageState.isChecked, isIndeterminate: imageState.isIndeterminate, onSelectedChange: () => toggleParent(IMAGE_CHILDREN), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Photo.jpg", isSelected: !!checked['photo'], onSelectedChange: () => toggleCheck('photo'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.PhotoIconOutline, {}) }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Screenshot.png", isSelected: !!checked['screenshot'], onSelectedChange: () => toggleCheck('screenshot'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.PhotoIconOutline, {}) })] })] }));
46
+ return ((0, jsx_runtime_1.jsxs)(next_1.TreeView, { ariaLabel: "File explorer", selectionMode: "multiple", children: [(0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: "Documents", hasChildren: true, isExpanded: expanded['documents'], onExpandedChange: () => toggleExpanded('documents'), isSelected: (_a = selected['documents']) !== null && _a !== void 0 ? _a : false, onSelectedChange: (isSelected) => setRowSelected('documents', isSelected), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: "Work", hasChildren: true, isExpanded: expanded['work'], onExpandedChange: () => toggleExpanded('work'), isSelected: (_b = selected['work']) !== null && _b !== void 0 ? _b : false, onSelectedChange: (isSelected) => setRowSelected('work', isSelected), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Report.pdf", isSelected: (_c = selected['report']) !== null && _c !== void 0 ? _c : false, onSelectedChange: (isSelected) => setRowSelected('report', isSelected), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Presentation.pptx", isDisabled: true, isSelected: (_d = selected['presentation']) !== null && _d !== void 0 ? _d : false, onSelectedChange: (isSelected) => setRowSelected('presentation', isSelected), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Resume.pdf", isSelected: (_e = selected['resume']) !== null && _e !== void 0 ? _e : false, onSelectedChange: (isSelected) => setRowSelected('resume', isSelected), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] }), (0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: "Images", hasChildren: true, isExpanded: expanded['images'], onExpandedChange: () => toggleExpanded('images'), isSelected: (_f = selected['images']) !== null && _f !== void 0 ? _f : false, onSelectedChange: (isSelected) => setRowSelected('images', isSelected), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Photo.jpg", isSelected: (_g = selected['photo']) !== null && _g !== void 0 ? _g : false, onSelectedChange: (isSelected) => setRowSelected('photo', isSelected), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.PhotoIconOutline, {}) }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Screenshot.png", isSelected: (_h = selected['screenshot']) !== null && _h !== void 0 ? _h : false, onSelectedChange: (isSelected) => setRowSelected('screenshot', isSelected), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.PhotoIconOutline, {}) })] })] }));
71
47
  };
72
48
  exports.default = Component;
73
49
  //# sourceMappingURL=tree-view-multi.story.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree-view-multi.story.js","sourceRoot":"","sources":["../../../../../src/next/tree-view/stories/tree-view-multi.story.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport '@neo4j-ndl/base/lib/neo4j-ds-styles.css';\n\nimport {\n DocumentIconOutline,\n FolderIconSolid,\n PhotoIconOutline,\n} from '@neo4j-ndl/react/icons';\nimport { TreeView } from '@neo4j-ndl/react/next';\nimport { useCallback, useState } from 'react';\n\ntype CheckedState = Record<string, boolean>;\n\nconst WORK_CHILDREN = ['report', 'presentation'] as const;\nconst DOC_CHILDREN = ['work', 'resume'] as const;\nconst IMAGE_CHILDREN = ['photo', 'screenshot'] as const;\nconst DISABLED_KEYS = new Set(['presentation']);\n\nfunction getParentChecked(\n checked: CheckedState,\n childKeys: readonly string[],\n): { isChecked: boolean; isIndeterminate: boolean } {\n const enabledKeys = childKeys.filter((key) => !DISABLED_KEYS.has(key));\n if (enabledKeys.length === 0) {\n return { isChecked: false, isIndeterminate: false };\n }\n const checkedCount = enabledKeys.filter((key) => checked[key]).length;\n if (checkedCount === 0) {\n return { isChecked: false, isIndeterminate: false };\n }\n if (checkedCount === enabledKeys.length) {\n return { isChecked: true, isIndeterminate: false };\n }\n return { isChecked: false, isIndeterminate: true };\n}\n\nconst Component = () => {\n const [expanded, setExpanded] = useState<Record<string, boolean>>({});\n const [checked, setChecked] = useState<CheckedState>({});\n\n const toggle = (key: string) =>\n setExpanded((prev) => ({ ...prev, [key]: !prev[key] }));\n\n const toggleCheck = useCallback((key: string) => {\n setChecked((prev) => ({ ...prev, [key]: !prev[key] }));\n }, []);\n\n const toggleParent = useCallback(\n (childKeys: readonly string[]) => {\n const enabledKeys = childKeys.filter((key) => !DISABLED_KEYS.has(key));\n const isAllChecked = enabledKeys.every((key) => checked[key]);\n setChecked((prev) => {\n const next = { ...prev };\n for (const key of enabledKeys) {\n next[key] = !isAllChecked;\n }\n return next;\n });\n },\n [checked],\n );\n\n const docState = getParentChecked(checked, [\n ...DOC_CHILDREN,\n ...WORK_CHILDREN,\n ]);\n const workState = getParentChecked(checked, WORK_CHILDREN);\n const imageState = getParentChecked(checked, IMAGE_CHILDREN);\n\n return (\n <TreeView ariaLabel=\"File explorer\" selectionMode=\"multiple\">\n <TreeView.Item\n title=\"Documents\"\n hasChildren\n isExpanded={expanded['documents']}\n onExpandedChange={() => toggle('documents')}\n isSelected={docState.isChecked}\n isIndeterminate={docState.isIndeterminate}\n onSelectedChange={() =>\n toggleParent([...DOC_CHILDREN, ...WORK_CHILDREN])\n }\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n title=\"Work\"\n hasChildren\n isExpanded={expanded['work']}\n onExpandedChange={() => toggle('work')}\n isSelected={workState.isChecked}\n isIndeterminate={workState.isIndeterminate}\n onSelectedChange={() => toggleParent(WORK_CHILDREN)}\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n title=\"Report.pdf\"\n isSelected={!!checked['report']}\n onSelectedChange={() => toggleCheck('report')}\n leadingVisual={<DocumentIconOutline />}\n />\n <TreeView.Item\n title=\"Presentation.pptx\"\n isDisabled\n onSelectedChange={() => null}\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n <TreeView.Item\n title=\"Resume.pdf\"\n isSelected={!!checked['resume']}\n onSelectedChange={() => toggleCheck('resume')}\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n <TreeView.Item\n title=\"Images\"\n hasChildren\n isExpanded={expanded['images']}\n onExpandedChange={() => toggle('images')}\n isSelected={imageState.isChecked}\n isIndeterminate={imageState.isIndeterminate}\n onSelectedChange={() => toggleParent(IMAGE_CHILDREN)}\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n title=\"Photo.jpg\"\n isSelected={!!checked['photo']}\n onSelectedChange={() => toggleCheck('photo')}\n leadingVisual={<PhotoIconOutline />}\n />\n <TreeView.Item\n title=\"Screenshot.png\"\n isSelected={!!checked['screenshot']}\n onSelectedChange={() => toggleCheck('screenshot')}\n leadingVisual={<PhotoIconOutline />}\n />\n </TreeView.Item>\n </TreeView>\n );\n};\n\nexport default Component;\n"]}
1
+ {"version":3,"file":"tree-view-multi.story.js","sourceRoot":"","sources":["../../../../../src/next/tree-view/stories/tree-view-multi.story.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport '@neo4j-ndl/base/lib/neo4j-ds-styles.css';\n\nimport {\n DocumentIconOutline,\n FolderIconSolid,\n PhotoIconOutline,\n} from '@neo4j-ndl/react/icons';\nimport { TreeView } from '@neo4j-ndl/react/next';\nimport { useCallback, useState } from 'react';\n\n/**\n * Every row owns its own checkbox: `onSelectedChange` reports the state the row\n * should end up in, and the story stores exactly that. Folders are ordinary\n * selectable rows here, unrelated to what sits inside them.\n *\n * Deriving a folder's state from its children instead needs the tree to own the\n * selection, since a Shift range moves several rows at once and a cascade has\n * to be applied to the whole set in one pass. See the root-managed selection\n * story for that.\n */\nconst Component = () => {\n const [expanded, setExpanded] = useState<Record<string, boolean>>({});\n const [selected, setSelected] = useState<Record<string, boolean>>({});\n\n const toggleExpanded = (key: string) =>\n setExpanded((prev) => ({ ...prev, [key]: !prev[key] }));\n\n const setRowSelected = useCallback((key: string, isSelected: boolean) => {\n setSelected((prev) => ({ ...prev, [key]: isSelected }));\n }, []);\n\n return (\n <TreeView ariaLabel=\"File explorer\" selectionMode=\"multiple\">\n <TreeView.Item\n title=\"Documents\"\n hasChildren\n isExpanded={expanded['documents']}\n onExpandedChange={() => toggleExpanded('documents')}\n isSelected={selected['documents'] ?? false}\n onSelectedChange={(isSelected) =>\n setRowSelected('documents', isSelected)\n }\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n title=\"Work\"\n hasChildren\n isExpanded={expanded['work']}\n onExpandedChange={() => toggleExpanded('work')}\n isSelected={selected['work'] ?? false}\n onSelectedChange={(isSelected) => setRowSelected('work', isSelected)}\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n title=\"Report.pdf\"\n isSelected={selected['report'] ?? false}\n onSelectedChange={(isSelected) =>\n setRowSelected('report', isSelected)\n }\n leadingVisual={<DocumentIconOutline />}\n />\n <TreeView.Item\n title=\"Presentation.pptx\"\n isDisabled\n isSelected={selected['presentation'] ?? false}\n onSelectedChange={(isSelected) =>\n setRowSelected('presentation', isSelected)\n }\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n <TreeView.Item\n title=\"Resume.pdf\"\n isSelected={selected['resume'] ?? false}\n onSelectedChange={(isSelected) =>\n setRowSelected('resume', isSelected)\n }\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n <TreeView.Item\n title=\"Images\"\n hasChildren\n isExpanded={expanded['images']}\n onExpandedChange={() => toggleExpanded('images')}\n isSelected={selected['images'] ?? false}\n onSelectedChange={(isSelected) => setRowSelected('images', isSelected)}\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n title=\"Photo.jpg\"\n isSelected={selected['photo'] ?? false}\n onSelectedChange={(isSelected) => setRowSelected('photo', isSelected)}\n leadingVisual={<PhotoIconOutline />}\n />\n <TreeView.Item\n title=\"Screenshot.png\"\n isSelected={selected['screenshot'] ?? false}\n onSelectedChange={(isSelected) =>\n setRowSelected('screenshot', isSelected)\n }\n leadingVisual={<PhotoIconOutline />}\n />\n </TreeView.Item>\n </TreeView>\n );\n};\n\nexport default Component;\n"]}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ /**
5
+ *
6
+ * Copyright (c) "Neo4j"
7
+ * Neo4j Sweden AB [http://neo4j.com]
8
+ *
9
+ * This file is part of Neo4j.
10
+ *
11
+ * Neo4j is free software: you can redistribute it and/or modify
12
+ * it under the terms of the GNU General Public License as published by
13
+ * the Free Software Foundation, either version 3 of the License, or
14
+ * (at your option) any later version.
15
+ *
16
+ * This program is distributed in the hope that it will be useful,
17
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ * GNU General Public License for more details.
20
+ *
21
+ * You should have received a copy of the GNU General Public License
22
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
+ */
24
+ require("@neo4j-ndl/base/lib/neo4j-ds-styles.css");
25
+ const icons_1 = require("@neo4j-ndl/react/icons");
26
+ const next_1 = require("@neo4j-ndl/react/next");
27
+ const react_1 = require("react");
28
+ /**
29
+ * Letting the tree own the selection keeps the items declarative: they carry an
30
+ * `id` and nothing else, and a Shift range that moves several rows at once
31
+ * arrives as a single `onSelectedIdsChange`.
32
+ */
33
+ const Component = () => {
34
+ const [selectedIds, setSelectedIds] = (0, react_1.useState)([]);
35
+ return ((0, jsx_runtime_1.jsxs)(next_1.TreeView, { ariaLabel: "File explorer", selectionMode: "multiple-replace", selectedIds: selectedIds, onSelectedIdsChange: setSelectedIds, children: [(0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { id: "documents", title: "Documents", hasChildren: true, defaultExpanded: true, leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { id: "work", title: "Work", hasChildren: true, defaultExpanded: true, leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: "report", title: "Report.pdf", isDisabled: true, leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: "presentation", title: "Presentation.pptx", leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: "resume", title: "Resume.pdf", leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] }), (0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { id: "images", title: "Images", hasChildren: true, leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: "photo", title: "Photo.jpg", leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.PhotoIconOutline, {}) }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: "screenshot", title: "Screenshot.png", leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.PhotoIconOutline, {}) })] })] }));
36
+ };
37
+ exports.default = Component;
38
+ //# sourceMappingURL=tree-view-multiple-replace.story.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree-view-multiple-replace.story.js","sourceRoot":"","sources":["../../../../../src/next/tree-view/stories/tree-view-multiple-replace.story.tsx"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,mDAAiD;AAEjD,kDAIgC;AAChC,gDAAiD;AACjD,iCAAiC;AAEjC;;;;GAIG;AACH,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,IAAA,gBAAQ,EAAW,EAAE,CAAC,CAAC;IAE7D,OAAO,CACL,wBAAC,eAAQ,IACP,SAAS,EAAC,eAAe,EACzB,aAAa,EAAC,kBAAkB,EAChC,WAAW,EAAE,WAAW,EACxB,mBAAmB,EAAE,cAAc,aAEnC,wBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,WAAW,EACd,KAAK,EAAC,WAAW,EACjB,WAAW,QACX,eAAe,QACf,aAAa,EAAE,uBAAC,uBAAe,KAAG,aAElC,wBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,MAAM,EACT,KAAK,EAAC,MAAM,EACZ,WAAW,QACX,eAAe,QACf,aAAa,EAAE,uBAAC,uBAAe,KAAG,aAElC,uBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,QAAQ,EACX,KAAK,EAAC,YAAY,EAClB,UAAU,QACV,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,EACF,uBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,cAAc,EACjB,KAAK,EAAC,mBAAmB,EACzB,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,IACY,EAChB,uBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,QAAQ,EACX,KAAK,EAAC,YAAY,EAClB,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,IACY,EAChB,wBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,QAAQ,EACX,KAAK,EAAC,QAAQ,EACd,WAAW,QACX,aAAa,EAAE,uBAAC,uBAAe,KAAG,aAElC,uBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,OAAO,EACV,KAAK,EAAC,WAAW,EACjB,aAAa,EAAE,uBAAC,wBAAgB,KAAG,GACnC,EACF,uBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,YAAY,EACf,KAAK,EAAC,gBAAgB,EACtB,aAAa,EAAE,uBAAC,wBAAgB,KAAG,GACnC,IACY,IACP,CACZ,CAAC;AACJ,CAAC,CAAC;AAEF,kBAAe,SAAS,CAAC","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport '@neo4j-ndl/base/lib/neo4j-ds-styles.css';\n\nimport {\n DocumentIconOutline,\n FolderIconSolid,\n PhotoIconOutline,\n} from '@neo4j-ndl/react/icons';\nimport { TreeView } from '@neo4j-ndl/react/next';\nimport { useState } from 'react';\n\n/**\n * Letting the tree own the selection keeps the items declarative: they carry an\n * `id` and nothing else, and a Shift range that moves several rows at once\n * arrives as a single `onSelectedIdsChange`.\n */\nconst Component = () => {\n const [selectedIds, setSelectedIds] = useState<string[]>([]);\n\n return (\n <TreeView\n ariaLabel=\"File explorer\"\n selectionMode=\"multiple-replace\"\n selectedIds={selectedIds}\n onSelectedIdsChange={setSelectedIds}\n >\n <TreeView.Item\n id=\"documents\"\n title=\"Documents\"\n hasChildren\n defaultExpanded\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n id=\"work\"\n title=\"Work\"\n hasChildren\n defaultExpanded\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n id=\"report\"\n title=\"Report.pdf\"\n isDisabled\n leadingVisual={<DocumentIconOutline />}\n />\n <TreeView.Item\n id=\"presentation\"\n title=\"Presentation.pptx\"\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n <TreeView.Item\n id=\"resume\"\n title=\"Resume.pdf\"\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n <TreeView.Item\n id=\"images\"\n title=\"Images\"\n hasChildren\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n id=\"photo\"\n title=\"Photo.jpg\"\n leadingVisual={<PhotoIconOutline />}\n />\n <TreeView.Item\n id=\"screenshot\"\n title=\"Screenshot.png\"\n leadingVisual={<PhotoIconOutline />}\n />\n </TreeView.Item>\n </TreeView>\n );\n};\n\nexport default Component;\n"]}
@@ -25,11 +25,14 @@ require("@neo4j-ndl/base/lib/neo4j-ds-styles.css");
25
25
  const icons_1 = require("@neo4j-ndl/react/icons");
26
26
  const next_1 = require("@neo4j-ndl/react/next");
27
27
  const react_1 = require("react");
28
+ /**
29
+ * Folders here are pure containers: `isSelectable={false}` makes them expand on
30
+ * click without ever becoming part of the selection, and screen readers
31
+ * announce them as non-selectable rather than as unselected rows.
32
+ */
28
33
  const Component = () => {
29
- const [expanded, setExpanded] = (0, react_1.useState)({});
30
- const [selected, setSelected] = (0, react_1.useState)(null);
31
- const toggle = (key) => setExpanded((prev) => (Object.assign(Object.assign({}, prev), { [key]: !prev[key] })));
32
- return ((0, jsx_runtime_1.jsxs)(next_1.TreeView, { ariaLabel: "File explorer", children: [(0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: "Documents", hasChildren: true, isExpanded: expanded['documents'], onExpandedChange: () => toggle('documents'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: "Work", hasChildren: true, isExpanded: expanded['work'], onExpandedChange: () => toggle('work'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Report.pdf", isSelected: selected === 'report', onSelectedChange: () => setSelected('report'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Presentation.pptx", isSelected: selected === 'presentation', onSelectedChange: () => setSelected('presentation'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Resume.pdf", isSelected: selected === 'resume', onSelectedChange: () => setSelected('resume'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] }), (0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { title: "Images", hasChildren: true, isExpanded: expanded['images'], onExpandedChange: () => toggle('images'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Photo.jpg", isSelected: selected === 'photo', onSelectedChange: () => setSelected('photo'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { title: "Screenshot.png", isSelected: selected === 'screenshot', onSelectedChange: () => setSelected('screenshot'), leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] })] }));
34
+ const [selectedIds, setSelectedIds] = (0, react_1.useState)([]);
35
+ return ((0, jsx_runtime_1.jsxs)(next_1.TreeView, { ariaLabel: "File explorer", selectedIds: selectedIds, onSelectedIdsChange: setSelectedIds, children: [(0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { id: "documents", title: "Documents", hasChildren: true, isSelectable: false, leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { id: "work", title: "Work", hasChildren: true, isSelectable: false, leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: "report", title: "Report.pdf", leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: "presentation", title: "Presentation.pptx", leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: "resume", title: "Resume.pdf", leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] }), (0, jsx_runtime_1.jsxs)(next_1.TreeView.Item, { id: "images", title: "Images", hasChildren: true, isSelectable: false, leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {}), children: [(0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: "photo", title: "Photo.jpg", leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) }), (0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: "screenshot", title: "Screenshot.png", leadingVisual: (0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {}) })] })] }));
33
36
  };
34
37
  exports.default = Component;
35
38
  //# sourceMappingURL=tree-view-non-selectable-folders.story.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree-view-non-selectable-folders.story.js","sourceRoot":"","sources":["../../../../../src/next/tree-view/stories/tree-view-non-selectable-folders.story.tsx"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,mDAAiD;AAEjD,kDAA8E;AAC9E,gDAAiD;AACjD,iCAAiC;AAEjC,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,IAAA,gBAAQ,EAA0B,EAAE,CAAC,CAAC;IACtE,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,IAAA,gBAAQ,EAAgB,IAAI,CAAC,CAAC;IAE9D,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,EAAE,CAC7B,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iCAAM,IAAI,KAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAG,CAAC,CAAC;IAE1D,OAAO,CACL,wBAAC,eAAQ,IAAC,SAAS,EAAC,eAAe,aACjC,wBAAC,eAAQ,CAAC,IAAI,IACZ,KAAK,EAAC,WAAW,EACjB,WAAW,QACX,UAAU,EAAE,QAAQ,CAAC,WAAW,CAAC,EACjC,gBAAgB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,EAC3C,aAAa,EAAE,uBAAC,uBAAe,KAAG,aAElC,wBAAC,eAAQ,CAAC,IAAI,IACZ,KAAK,EAAC,MAAM,EACZ,WAAW,QACX,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC5B,gBAAgB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EACtC,aAAa,EAAE,uBAAC,uBAAe,KAAG,aAElC,uBAAC,eAAQ,CAAC,IAAI,IACZ,KAAK,EAAC,YAAY,EAClB,UAAU,EAAE,QAAQ,KAAK,QAAQ,EACjC,gBAAgB,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,EAC7C,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,EACF,uBAAC,eAAQ,CAAC,IAAI,IACZ,KAAK,EAAC,mBAAmB,EACzB,UAAU,EAAE,QAAQ,KAAK,cAAc,EACvC,gBAAgB,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,cAAc,CAAC,EACnD,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,IACY,EAChB,uBAAC,eAAQ,CAAC,IAAI,IACZ,KAAK,EAAC,YAAY,EAClB,UAAU,EAAE,QAAQ,KAAK,QAAQ,EACjC,gBAAgB,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,EAC7C,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,IACY,EAChB,wBAAC,eAAQ,CAAC,IAAI,IACZ,KAAK,EAAC,QAAQ,EACd,WAAW,QACX,UAAU,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC9B,gBAAgB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EACxC,aAAa,EAAE,uBAAC,uBAAe,KAAG,aAElC,uBAAC,eAAQ,CAAC,IAAI,IACZ,KAAK,EAAC,WAAW,EACjB,UAAU,EAAE,QAAQ,KAAK,OAAO,EAChC,gBAAgB,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,EAC5C,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,EACF,uBAAC,eAAQ,CAAC,IAAI,IACZ,KAAK,EAAC,gBAAgB,EACtB,UAAU,EAAE,QAAQ,KAAK,YAAY,EACrC,gBAAgB,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EACjD,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,IACY,IACP,CACZ,CAAC;AACJ,CAAC,CAAC;AAEF,kBAAe,SAAS,CAAC","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport '@neo4j-ndl/base/lib/neo4j-ds-styles.css';\n\nimport { DocumentIconOutline, FolderIconSolid } from '@neo4j-ndl/react/icons';\nimport { TreeView } from '@neo4j-ndl/react/next';\nimport { useState } from 'react';\n\nconst Component = () => {\n const [expanded, setExpanded] = useState<Record<string, boolean>>({});\n const [selected, setSelected] = useState<string | null>(null);\n\n const toggle = (key: string) =>\n setExpanded((prev) => ({ ...prev, [key]: !prev[key] }));\n\n return (\n <TreeView ariaLabel=\"File explorer\">\n <TreeView.Item\n title=\"Documents\"\n hasChildren\n isExpanded={expanded['documents']}\n onExpandedChange={() => toggle('documents')}\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n title=\"Work\"\n hasChildren\n isExpanded={expanded['work']}\n onExpandedChange={() => toggle('work')}\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n title=\"Report.pdf\"\n isSelected={selected === 'report'}\n onSelectedChange={() => setSelected('report')}\n leadingVisual={<DocumentIconOutline />}\n />\n <TreeView.Item\n title=\"Presentation.pptx\"\n isSelected={selected === 'presentation'}\n onSelectedChange={() => setSelected('presentation')}\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n <TreeView.Item\n title=\"Resume.pdf\"\n isSelected={selected === 'resume'}\n onSelectedChange={() => setSelected('resume')}\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n <TreeView.Item\n title=\"Images\"\n hasChildren\n isExpanded={expanded['images']}\n onExpandedChange={() => toggle('images')}\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n title=\"Photo.jpg\"\n isSelected={selected === 'photo'}\n onSelectedChange={() => setSelected('photo')}\n leadingVisual={<DocumentIconOutline />}\n />\n <TreeView.Item\n title=\"Screenshot.png\"\n isSelected={selected === 'screenshot'}\n onSelectedChange={() => setSelected('screenshot')}\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n </TreeView>\n );\n};\n\nexport default Component;\n"]}
1
+ {"version":3,"file":"tree-view-non-selectable-folders.story.js","sourceRoot":"","sources":["../../../../../src/next/tree-view/stories/tree-view-non-selectable-folders.story.tsx"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,mDAAiD;AAEjD,kDAA8E;AAC9E,gDAAiD;AACjD,iCAAiC;AAEjC;;;;GAIG;AACH,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,IAAA,gBAAQ,EAAW,EAAE,CAAC,CAAC;IAE7D,OAAO,CACL,wBAAC,eAAQ,IACP,SAAS,EAAC,eAAe,EACzB,WAAW,EAAE,WAAW,EACxB,mBAAmB,EAAE,cAAc,aAEnC,wBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,WAAW,EACd,KAAK,EAAC,WAAW,EACjB,WAAW,QACX,YAAY,EAAE,KAAK,EACnB,aAAa,EAAE,uBAAC,uBAAe,KAAG,aAElC,wBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,MAAM,EACT,KAAK,EAAC,MAAM,EACZ,WAAW,QACX,YAAY,EAAE,KAAK,EACnB,aAAa,EAAE,uBAAC,uBAAe,KAAG,aAElC,uBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,QAAQ,EACX,KAAK,EAAC,YAAY,EAClB,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,EACF,uBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,cAAc,EACjB,KAAK,EAAC,mBAAmB,EACzB,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,IACY,EAChB,uBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,QAAQ,EACX,KAAK,EAAC,YAAY,EAClB,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,IACY,EAChB,wBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,QAAQ,EACX,KAAK,EAAC,QAAQ,EACd,WAAW,QACX,YAAY,EAAE,KAAK,EACnB,aAAa,EAAE,uBAAC,uBAAe,KAAG,aAElC,uBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,OAAO,EACV,KAAK,EAAC,WAAW,EACjB,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,EACF,uBAAC,eAAQ,CAAC,IAAI,IACZ,EAAE,EAAC,YAAY,EACf,KAAK,EAAC,gBAAgB,EACtB,aAAa,EAAE,uBAAC,2BAAmB,KAAG,GACtC,IACY,IACP,CACZ,CAAC;AACJ,CAAC,CAAC;AAEF,kBAAe,SAAS,CAAC","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport '@neo4j-ndl/base/lib/neo4j-ds-styles.css';\n\nimport { DocumentIconOutline, FolderIconSolid } from '@neo4j-ndl/react/icons';\nimport { TreeView } from '@neo4j-ndl/react/next';\nimport { useState } from 'react';\n\n/**\n * Folders here are pure containers: `isSelectable={false}` makes them expand on\n * click without ever becoming part of the selection, and screen readers\n * announce them as non-selectable rather than as unselected rows.\n */\nconst Component = () => {\n const [selectedIds, setSelectedIds] = useState<string[]>([]);\n\n return (\n <TreeView\n ariaLabel=\"File explorer\"\n selectedIds={selectedIds}\n onSelectedIdsChange={setSelectedIds}\n >\n <TreeView.Item\n id=\"documents\"\n title=\"Documents\"\n hasChildren\n isSelectable={false}\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n id=\"work\"\n title=\"Work\"\n hasChildren\n isSelectable={false}\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n id=\"report\"\n title=\"Report.pdf\"\n leadingVisual={<DocumentIconOutline />}\n />\n <TreeView.Item\n id=\"presentation\"\n title=\"Presentation.pptx\"\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n <TreeView.Item\n id=\"resume\"\n title=\"Resume.pdf\"\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n <TreeView.Item\n id=\"images\"\n title=\"Images\"\n hasChildren\n isSelectable={false}\n leadingVisual={<FolderIconSolid />}\n >\n <TreeView.Item\n id=\"photo\"\n title=\"Photo.jpg\"\n leadingVisual={<DocumentIconOutline />}\n />\n <TreeView.Item\n id=\"screenshot\"\n title=\"Screenshot.png\"\n leadingVisual={<DocumentIconOutline />}\n />\n </TreeView.Item>\n </TreeView>\n );\n};\n\nexport default Component;\n"]}
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsx_runtime_1 = require("react/jsx-runtime");
4
+ /**
5
+ *
6
+ * Copyright (c) "Neo4j"
7
+ * Neo4j Sweden AB [http://neo4j.com]
8
+ *
9
+ * This file is part of Neo4j.
10
+ *
11
+ * Neo4j is free software: you can redistribute it and/or modify
12
+ * it under the terms of the GNU General Public License as published by
13
+ * the Free Software Foundation, either version 3 of the License, or
14
+ * (at your option) any later version.
15
+ *
16
+ * This program is distributed in the hope that it will be useful,
17
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ * GNU General Public License for more details.
20
+ *
21
+ * You should have received a copy of the GNU General Public License
22
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
23
+ */
24
+ require("@neo4j-ndl/base/lib/neo4j-ds-styles.css");
25
+ const icons_1 = require("@neo4j-ndl/react/icons");
26
+ const next_1 = require("@neo4j-ndl/react/next");
27
+ const react_1 = require("react");
28
+ const files = [
29
+ {
30
+ children: [
31
+ {
32
+ children: [
33
+ { id: 'report', title: 'Report.pdf' },
34
+ { id: 'presentation', title: 'Presentation.pptx' },
35
+ ],
36
+ id: 'work',
37
+ title: 'Work',
38
+ },
39
+ { id: 'resume', title: 'Resume.pdf' },
40
+ ],
41
+ id: 'documents',
42
+ title: 'Documents',
43
+ },
44
+ {
45
+ children: [
46
+ { id: 'photo', title: 'Photo.jpg' },
47
+ { id: 'screenshot', title: 'Screenshot.png' },
48
+ ],
49
+ id: 'images',
50
+ title: 'Images',
51
+ },
52
+ ];
53
+ const walk = (nodes, visit) => {
54
+ nodes.forEach((node) => {
55
+ var _a;
56
+ visit(node);
57
+ walk((_a = node.children) !== null && _a !== void 0 ? _a : [], visit);
58
+ });
59
+ };
60
+ const getDescendantIds = (node) => {
61
+ var _a;
62
+ return ((_a = node.children) !== null && _a !== void 0 ? _a : []).flatMap((child) => [
63
+ child.id,
64
+ ...getDescendantIds(child),
65
+ ]);
66
+ };
67
+ const getLeafIds = (node) => node.children === undefined ? [node.id] : node.children.flatMap(getLeafIds);
68
+ /** Folders follow their contents: selected only when every leaf below them is. */
69
+ const syncFolders = (nodes, selected) => {
70
+ nodes.forEach((node) => {
71
+ if (node.children === undefined) {
72
+ return;
73
+ }
74
+ syncFolders(node.children, selected);
75
+ if (getLeafIds(node).every((id) => selected.has(id))) {
76
+ selected.add(node.id);
77
+ }
78
+ else {
79
+ selected.delete(node.id);
80
+ }
81
+ });
82
+ };
83
+ const Component = () => {
84
+ const [selectedIds, setSelectedIds] = (0, react_1.useState)(['resume']);
85
+ const selected = new Set(selectedIds);
86
+ /**
87
+ * The tree reports the whole selection at once, so cascading folders onto
88
+ * their contents takes a single pass even when a Shift range flipped many
89
+ * rows.
90
+ */
91
+ const handleSelectedIdsChange = (0, react_1.useCallback)((nextIds) => {
92
+ setSelectedIds((previousIds) => {
93
+ const next = new Set(nextIds);
94
+ const previous = new Set(previousIds);
95
+ walk(files, (node) => {
96
+ const isSelected = next.has(node.id);
97
+ if (node.children === undefined ||
98
+ isSelected === previous.has(node.id)) {
99
+ return;
100
+ }
101
+ getDescendantIds(node).forEach((id) => {
102
+ if (isSelected) {
103
+ next.add(id);
104
+ }
105
+ else {
106
+ next.delete(id);
107
+ }
108
+ });
109
+ });
110
+ syncFolders(files, next);
111
+ return [...next];
112
+ });
113
+ }, []);
114
+ const renderNode = (node) => {
115
+ var _a;
116
+ const leafIds = getLeafIds(node);
117
+ const selectedLeafCount = leafIds.filter((id) => selected.has(id)).length;
118
+ return ((0, jsx_runtime_1.jsx)(next_1.TreeView.Item, { id: node.id, title: node.title, defaultExpanded: true, isIndeterminate: node.children !== undefined &&
119
+ selectedLeafCount > 0 &&
120
+ selectedLeafCount < leafIds.length, leadingVisual: node.children === undefined ? ((0, jsx_runtime_1.jsx)(icons_1.DocumentIconOutline, {})) : ((0, jsx_runtime_1.jsx)(icons_1.FolderIconSolid, {})), children: (_a = node.children) === null || _a === void 0 ? void 0 : _a.map(renderNode) }, node.id));
121
+ };
122
+ return ((0, jsx_runtime_1.jsx)(next_1.TreeView, { ariaLabel: "File explorer", selectionMode: "multiple", selectedIds: selectedIds, onSelectedIdsChange: handleSelectedIdsChange, children: files.map(renderNode) }));
123
+ };
124
+ exports.default = Component;
125
+ //# sourceMappingURL=tree-view-root-selection.story.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree-view-root-selection.story.js","sourceRoot":"","sources":["../../../../../src/next/tree-view/stories/tree-view-root-selection.story.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport '@neo4j-ndl/base/lib/neo4j-ds-styles.css';\n\nimport { DocumentIconOutline, FolderIconSolid } from '@neo4j-ndl/react/icons';\nimport { TreeView } from '@neo4j-ndl/react/next';\nimport { useCallback, useState } from 'react';\n\ntype FileNode = {\n children?: FileNode[];\n id: string;\n title: string;\n};\n\nconst files: FileNode[] = [\n {\n children: [\n {\n children: [\n { id: 'report', title: 'Report.pdf' },\n { id: 'presentation', title: 'Presentation.pptx' },\n ],\n id: 'work',\n title: 'Work',\n },\n { id: 'resume', title: 'Resume.pdf' },\n ],\n id: 'documents',\n title: 'Documents',\n },\n {\n children: [\n { id: 'photo', title: 'Photo.jpg' },\n { id: 'screenshot', title: 'Screenshot.png' },\n ],\n id: 'images',\n title: 'Images',\n },\n];\n\nconst walk = (nodes: FileNode[], visit: (node: FileNode) => void) => {\n nodes.forEach((node) => {\n visit(node);\n walk(node.children ?? [], visit);\n });\n};\n\nconst getDescendantIds = (node: FileNode): string[] =>\n (node.children ?? []).flatMap((child) => [\n child.id,\n ...getDescendantIds(child),\n ]);\n\nconst getLeafIds = (node: FileNode): string[] =>\n node.children === undefined ? [node.id] : node.children.flatMap(getLeafIds);\n\n/** Folders follow their contents: selected only when every leaf below them is. */\nconst syncFolders = (nodes: FileNode[], selected: Set<string>) => {\n nodes.forEach((node) => {\n if (node.children === undefined) {\n return;\n }\n syncFolders(node.children, selected);\n if (getLeafIds(node).every((id) => selected.has(id))) {\n selected.add(node.id);\n } else {\n selected.delete(node.id);\n }\n });\n};\n\nconst Component = () => {\n const [selectedIds, setSelectedIds] = useState<string[]>(['resume']);\n const selected = new Set(selectedIds);\n\n /**\n * The tree reports the whole selection at once, so cascading folders onto\n * their contents takes a single pass even when a Shift range flipped many\n * rows.\n */\n const handleSelectedIdsChange = useCallback((nextIds: string[]) => {\n setSelectedIds((previousIds) => {\n const next = new Set(nextIds);\n const previous = new Set(previousIds);\n walk(files, (node) => {\n const isSelected = next.has(node.id);\n if (\n node.children === undefined ||\n isSelected === previous.has(node.id)\n ) {\n return;\n }\n getDescendantIds(node).forEach((id) => {\n if (isSelected) {\n next.add(id);\n } else {\n next.delete(id);\n }\n });\n });\n syncFolders(files, next);\n return [...next];\n });\n }, []);\n\n const renderNode = (node: FileNode) => {\n const leafIds = getLeafIds(node);\n const selectedLeafCount = leafIds.filter((id) => selected.has(id)).length;\n return (\n <TreeView.Item\n key={node.id}\n id={node.id}\n title={node.title}\n defaultExpanded\n isIndeterminate={\n node.children !== undefined &&\n selectedLeafCount > 0 &&\n selectedLeafCount < leafIds.length\n }\n leadingVisual={\n node.children === undefined ? (\n <DocumentIconOutline />\n ) : (\n <FolderIconSolid />\n )\n }\n >\n {node.children?.map(renderNode)}\n </TreeView.Item>\n );\n };\n\n return (\n <TreeView\n ariaLabel=\"File explorer\"\n selectionMode=\"multiple\"\n selectedIds={selectedIds}\n onSelectedIdsChange={handleSelectedIdsChange}\n >\n {files.map(renderNode)}\n </TreeView>\n );\n};\n\nexport default Component;\n"]}
@@ -37,9 +37,8 @@ const jsx_runtime_1 = require("react/jsx-runtime");
37
37
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
38
38
  */
39
39
  const classnames_1 = __importDefault(require("classnames"));
40
- const react_1 = require("react");
40
+ const form_control_1 = require("../_common/form-control");
41
41
  const use_semi_controlled_input_1 = require("../_common/use-semi-controlled-input");
42
- const utils_1 = require("../_common/utils");
43
42
  const Radio = (_a) => {
44
43
  var _b;
45
44
  var { ariaLabel, isDisabled = false, isDefaultChecked, label, isFluid = false, isChecked, hasLeadingLabel, onChange, className, style, onClick, value, htmlAttributes, ref } = _a, restProps = __rest(_a, ["ariaLabel", "isDisabled", "isDefaultChecked", "label", "isFluid", "isChecked", "hasLeadingLabel", "onChange", "className", "style", "onClick", "value", "htmlAttributes", "ref"]);
@@ -49,29 +48,20 @@ const Radio = (_a) => {
49
48
  onChange,
50
49
  state: (_b = isChecked !== null && isChecked !== void 0 ? isChecked : isDefaultChecked) !== null && _b !== void 0 ? _b : false,
51
50
  });
52
- const labelWrappingClasses = (0, classnames_1.default)('ndl-radio-label', {
53
- 'ndl-disabled': isDisabled,
54
- 'ndl-fluid': isFluid,
55
- });
56
51
  const radioClasses = (0, classnames_1.default)('ndl-radio', className, {
57
52
  'ndl-disabled': isDisabled,
58
53
  });
59
- /** TODO: Label handling. We can get rid of this annoying stuff as soon as we do proper form control. */
60
- const labelContent = (0, react_1.useMemo)(() => {
61
- if (Boolean(label) === false) {
62
- return null;
63
- }
64
- if (typeof label === 'string') {
65
- return ((0, jsx_runtime_1.jsx)("span", { title: label, className: "ndl-radio-label-text", children: label }));
66
- }
67
- return label;
68
- }, [label]);
69
- (0, react_1.useEffect)(() => {
70
- if (Boolean(label) === false && Boolean(ariaLabel) === false) {
71
- (0, utils_1.needleWarningMessage)('Radio needs a valid label or ariaLabel: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI');
72
- }
73
- }, [ariaLabel, label]);
74
- return ((0, jsx_runtime_1.jsxs)("label", { className: labelWrappingClasses, children: [hasLeadingLabel === true && labelContent, (0, jsx_runtime_1.jsx)("input", Object.assign({ ref: ref, type: "radio", "aria-label": ariaLabel, disabled: isDisabled, checked: isCheckedState, onClick: onClick, onChange: internalOnChange, value: value, style: style, className: radioClasses }, restProps, htmlAttributes)), Boolean(hasLeadingLabel) === false && labelContent] }));
54
+ const { labelContent, fieldClassName } = (0, form_control_1.useInlineFieldLabel)({
55
+ ariaLabel,
56
+ componentName: 'Radio',
57
+ isDisabled,
58
+ isFluid,
59
+ // TODO v5: decide whether all selection controls should truncate; today
60
+ // only Radio does.
61
+ isTruncated: true,
62
+ label,
63
+ });
64
+ return ((0, jsx_runtime_1.jsxs)("label", { className: fieldClassName, children: [hasLeadingLabel === true && labelContent, (0, jsx_runtime_1.jsx)("input", Object.assign({ ref: ref, type: "radio", "aria-label": ariaLabel, disabled: isDisabled, checked: isCheckedState, onClick: onClick, onChange: internalOnChange, value: value, style: style, className: radioClasses }, restProps, htmlAttributes)), Boolean(hasLeadingLabel) === false && labelContent] }));
75
65
  };
76
66
  exports.Radio = Radio;
77
67
  //# sourceMappingURL=Radio.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Radio.js","sourceRoot":"","sources":["../../../src/radio/Radio.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,4DAAoC;AACpC,iCAA2C;AAG3C,oFAA8E;AAC9E,4CAAwD;AAgCjD,MAAM,KAAK,GAAG,CAAC,EAgBa,EAAE,EAAE;;QAhBjB,EACpB,SAAS,EACT,UAAU,GAAG,KAAK,EAClB,gBAAgB,EAChB,KAAK,EACL,OAAO,GAAG,KAAK,EACf,SAAS,EACT,eAAe,EACf,QAAQ,EACR,SAAS,EACT,KAAK,EACL,OAAO,EACP,KAAK,EACL,cAAc,EACd,GAAG,OAE8B,EAD9B,SAAS,cAfQ,kLAgBrB,CADa;IAEZ,MAAM,CAAC,cAAc,EAAE,gBAAgB,CAAC,GAAG,IAAA,kDAAsB,EAAC;QAChE,SAAS,EAAE,OAAO;QAClB,YAAY,EAAE,SAAS,KAAK,SAAS;QACrC,QAAQ;QACR,KAAK,EAAE,MAAA,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,gBAAgB,mCAAI,KAAK;KAC9C,CAAC,CAAC;IAEH,MAAM,oBAAoB,GAAG,IAAA,oBAAU,EAAC,iBAAiB,EAAE;QACzD,cAAc,EAAE,UAAU;QAC1B,WAAW,EAAE,OAAO;KACrB,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,IAAA,oBAAU,EAAC,WAAW,EAAE,SAAS,EAAE;QACtD,cAAc,EAAE,UAAU;KAC3B,CAAC,CAAC;IAEH,wGAAwG;IACxG,MAAM,YAAY,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE;QAChC,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,CACL,iCAAM,KAAK,EAAE,KAAK,EAAE,SAAS,EAAC,sBAAsB,YACjD,KAAK,GACD,CACR,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,OAAO,CAAC,SAAS,CAAC,KAAK,KAAK,EAAE,CAAC;YAC7D,IAAA,4BAAoB,EAClB,4GAA4G,CAC7G,CAAC;QACJ,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;IAEvB,OAAO,CACL,mCAAO,SAAS,EAAE,oBAAoB,aACnC,eAAe,KAAK,IAAI,IAAI,YAAY,EACzC,gDACE,GAAG,EAAE,GAAG,EACR,IAAI,EAAC,OAAO,gBACA,SAAS,EACrB,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,YAAY,IACnB,SAAS,EACT,cAAc,EAClB,EACD,OAAO,CAAC,eAAe,CAAC,KAAK,KAAK,IAAI,YAAY,IAC7C,CACT,CAAC;AACJ,CAAC,CAAC;AA7EW,QAAA,KAAK,SA6EhB","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport classNames from 'classnames';\nimport { useEffect, useMemo } from 'react';\n\nimport { type CommonProps, type HtmlAttributes } from '../_common/types';\nimport { useSemiControlledInput } from '../_common/use-semi-controlled-input';\nimport { needleWarningMessage } from '../_common/utils';\n\ntype RadioProps = {\n /** Whether the radio is checked */\n isChecked?: boolean;\n /** Selects the radio by default in uncontrolled mode */\n isDefaultChecked?: boolean;\n /** Whether the radio is disabled */\n isDisabled?: boolean;\n /** Whether the radio & label should take the full available width of its container */\n isFluid?: boolean;\n /** Whether the label should be displayed before the radio */\n hasLeadingLabel?: boolean;\n /** The callback function triggered when the radio value changes */\n onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;\n /** The value of the radio */\n value?: HtmlAttributes<'input'>['value'];\n /** The callback function triggered when the radio is clicked */\n onClick?: (event: React.MouseEvent<HTMLInputElement>) => void;\n} & (\n | {\n /** The aria label of the radio. Required if the label is not a string. */\n ariaLabel: string;\n /** The label of the radio. If not a string, supply an aria label for screen reader support. */\n label?: undefined;\n }\n | {\n ariaLabel?: string;\n label: React.ReactNode;\n }\n);\n\nexport const Radio = ({\n ariaLabel,\n isDisabled = false,\n isDefaultChecked,\n label,\n isFluid = false,\n isChecked,\n hasLeadingLabel,\n onChange,\n className,\n style,\n onClick,\n value,\n htmlAttributes,\n ref,\n ...restProps\n}: CommonProps<'input', RadioProps>) => {\n const [isCheckedState, internalOnChange] = useSemiControlledInput({\n inputType: 'radio',\n isControlled: isChecked !== undefined,\n onChange,\n state: isChecked ?? isDefaultChecked ?? false,\n });\n\n const labelWrappingClasses = classNames('ndl-radio-label', {\n 'ndl-disabled': isDisabled,\n 'ndl-fluid': isFluid,\n });\n\n const radioClasses = classNames('ndl-radio', className, {\n 'ndl-disabled': isDisabled,\n });\n\n /** TODO: Label handling. We can get rid of this annoying stuff as soon as we do proper form control. */\n const labelContent = useMemo(() => {\n if (Boolean(label) === false) {\n return null;\n }\n\n if (typeof label === 'string') {\n return (\n <span title={label} className=\"ndl-radio-label-text\">\n {label}\n </span>\n );\n }\n return label;\n }, [label]);\n\n useEffect(() => {\n if (Boolean(label) === false && Boolean(ariaLabel) === false) {\n needleWarningMessage(\n 'Radio needs a valid label or ariaLabel: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI',\n );\n }\n }, [ariaLabel, label]);\n\n return (\n <label className={labelWrappingClasses}>\n {hasLeadingLabel === true && labelContent}\n <input\n ref={ref}\n type=\"radio\"\n aria-label={ariaLabel}\n disabled={isDisabled}\n checked={isCheckedState}\n onClick={onClick}\n onChange={internalOnChange}\n value={value}\n style={style}\n className={radioClasses}\n {...restProps}\n {...htmlAttributes}\n />\n {Boolean(hasLeadingLabel) === false && labelContent}\n </label>\n );\n};\n"]}
1
+ {"version":3,"file":"Radio.js","sourceRoot":"","sources":["../../../src/radio/Radio.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,4DAAoC;AAEpC,0DAA8D;AAE9D,oFAA8E;AAqCvE,MAAM,KAAK,GAAG,CAAC,EAgBa,EAAE,EAAE;;QAhBjB,EACpB,SAAS,EACT,UAAU,GAAG,KAAK,EAClB,gBAAgB,EAChB,KAAK,EACL,OAAO,GAAG,KAAK,EACf,SAAS,EACT,eAAe,EACf,QAAQ,EACR,SAAS,EACT,KAAK,EACL,OAAO,EACP,KAAK,EACL,cAAc,EACd,GAAG,OAE8B,EAD9B,SAAS,cAfQ,kLAgBrB,CADa;IAEZ,MAAM,CAAC,cAAc,EAAE,gBAAgB,CAAC,GAAG,IAAA,kDAAsB,EAAC;QAChE,SAAS,EAAE,OAAO;QAClB,YAAY,EAAE,SAAS,KAAK,SAAS;QACrC,QAAQ;QACR,KAAK,EAAE,MAAA,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,gBAAgB,mCAAI,KAAK;KAC9C,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,IAAA,oBAAU,EAAC,WAAW,EAAE,SAAS,EAAE;QACtD,cAAc,EAAE,UAAU;KAC3B,CAAC,CAAC;IAEH,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,GAAG,IAAA,kCAAmB,EAAC;QAC3D,SAAS;QACT,aAAa,EAAE,OAAO;QACtB,UAAU;QACV,OAAO;QACP,wEAAwE;QACxE,mBAAmB;QACnB,WAAW,EAAE,IAAI;QACjB,KAAK;KACN,CAAC,CAAC;IAEH,OAAO,CACL,mCAAO,SAAS,EAAE,cAAc,aAC7B,eAAe,KAAK,IAAI,IAAI,YAAY,EACzC,gDACE,GAAG,EAAE,GAAG,EACR,IAAI,EAAC,OAAO,gBACA,SAAS,EACrB,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,YAAY,IACnB,SAAS,EACT,cAAc,EAClB,EACD,OAAO,CAAC,eAAe,CAAC,KAAK,KAAK,IAAI,YAAY,IAC7C,CACT,CAAC;AACJ,CAAC,CAAC;AA3DW,QAAA,KAAK,SA2DhB","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport classNames from 'classnames';\n\nimport { useInlineFieldLabel } from '../_common/form-control';\nimport { type CommonProps, type HtmlAttributes } from '../_common/types';\nimport { useSemiControlledInput } from '../_common/use-semi-controlled-input';\n\ntype RadioProps = {\n /** Whether the radio is checked */\n isChecked?: boolean;\n /** Selects the radio by default in uncontrolled mode */\n isDefaultChecked?: boolean;\n /** Whether the radio is disabled */\n isDisabled?: boolean;\n /** Whether the radio & label should take the full available width of its container */\n isFluid?: boolean;\n /** Whether the label should be displayed before the radio */\n hasLeadingLabel?: boolean;\n /** The callback function triggered when the radio value changes */\n onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;\n /** The value of the radio */\n value?: HtmlAttributes<'input'>['value'];\n /** The callback function triggered when the radio is clicked */\n onClick?: (event: React.MouseEvent<HTMLInputElement>) => void;\n} & (\n | {\n /** The aria label of the radio. Required if the label is not a string. */\n ariaLabel: string;\n // TODO v5: inconsistent naming. Naming the radio takes a union of `label`\n // and `ariaLabel`, so the accessible name comes from a different prop\n // depending on what the label renders. Combobox instead requires the\n // label and clips it with `hasVisuallyHiddenLabel`, and TextInput reaches\n // for htmlAttributes['aria-label'].\n /** The label of the radio. If not a string, supply an aria label for screen reader support. */\n label?: undefined;\n }\n | {\n ariaLabel?: string;\n label: React.ReactNode;\n }\n);\n\nexport const Radio = ({\n ariaLabel,\n isDisabled = false,\n isDefaultChecked,\n label,\n isFluid = false,\n isChecked,\n hasLeadingLabel,\n onChange,\n className,\n style,\n onClick,\n value,\n htmlAttributes,\n ref,\n ...restProps\n}: CommonProps<'input', RadioProps>) => {\n const [isCheckedState, internalOnChange] = useSemiControlledInput({\n inputType: 'radio',\n isControlled: isChecked !== undefined,\n onChange,\n state: isChecked ?? isDefaultChecked ?? false,\n });\n\n const radioClasses = classNames('ndl-radio', className, {\n 'ndl-disabled': isDisabled,\n });\n\n const { labelContent, fieldClassName } = useInlineFieldLabel({\n ariaLabel,\n componentName: 'Radio',\n isDisabled,\n isFluid,\n // TODO v5: decide whether all selection controls should truncate; today\n // only Radio does.\n isTruncated: true,\n label,\n });\n\n return (\n <label className={fieldClassName}>\n {hasLeadingLabel === true && labelContent}\n <input\n ref={ref}\n type=\"radio\"\n aria-label={ariaLabel}\n disabled={isDisabled}\n checked={isCheckedState}\n onClick={onClick}\n onChange={internalOnChange}\n value={value}\n style={style}\n className={radioClasses}\n {...restProps}\n {...htmlAttributes}\n />\n {Boolean(hasLeadingLabel) === false && labelContent}\n </label>\n );\n};\n"]}
@@ -43,10 +43,9 @@ const react_select_1 = __importDefault(require("react-select"));
43
43
  const async_1 = __importDefault(require("react-select/async"));
44
44
  /** Different types of select components */
45
45
  const creatable_1 = __importDefault(require("react-select/creatable"));
46
+ const form_control_1 = require("../_common/form-control");
46
47
  const utils_1 = require("../_common/utils");
47
48
  const dialog_context_1 = require("../dialog/dialog-context");
48
- const ExclamationCircleIconSolid_1 = require("../icons/generated/heroIcons/ExclamationCircleIconSolid");
49
- const typography_1 = require("../typography");
50
49
  const Overrides_1 = require("./Overrides");
51
50
  /**
52
51
  *
@@ -102,8 +101,18 @@ const Select = (_a) => {
102
101
  const isInsideDialog = (0, dialog_context_1.useIsInsideDialog)();
103
102
  const menuPosition = isInsideDialog ? 'fixed' : 'absolute';
104
103
  const identifier = (0, react_1.useId)();
105
- const helpTextId = (0, react_1.useId)();
106
- const errorTextId = (0, react_1.useId)();
104
+ // The shared form field resolves the ids and which message is displayed -
105
+ // an error always replaces the help text. Select has no required support;
106
+ // it is deprecated in favor of Combobox, which has isRequired and
107
+ // hasRequiredIndicator.
108
+ const { field } = (0, form_control_1.useFormField)({
109
+ controlId: identifier,
110
+ errorText,
111
+ helpText,
112
+ label,
113
+ });
114
+ const helpTextId = field.helpTextId;
115
+ const errorTextId = field.errorTextId;
107
116
  const [isMenuOpen, setIsMenuOpen] = (0, react_1.useState)(false);
108
117
  const handleMenuOpen = () => {
109
118
  setIsMenuOpen(true);
@@ -164,7 +173,7 @@ const Select = (_a) => {
164
173
  'ndl-multi': selectProps.isMulti,
165
174
  'ndl-small': size === 'small',
166
175
  });
167
- return ((0, jsx_runtime_1.jsxs)(Component, Object.assign({ ref: ref, className: classes, style: style }, restProps, htmlAttributes, { children: [Boolean(label) && (0, jsx_runtime_1.jsx)("label", { htmlFor: identifier, children: label }), SelectElement, Boolean(helpText) && Boolean(errorText) === false && ((0, jsx_runtime_1.jsx)(typography_1.Typography, { variant: size === 'large' ? 'body-medium' : 'body-small', className: "ndl-sub-text", htmlAttributes: { id: helpTextId }, children: helpText })), Boolean(errorText) && ((0, jsx_runtime_1.jsxs)("div", { className: "n-flex n-flex-row n-gap-token-4 n-items-center", children: [(0, jsx_runtime_1.jsx)(ExclamationCircleIconSolid_1.ExclamationCircleIconSolid, { className: "ndl-error-icon", htmlAttributes: { role: 'img', type: 'solid' } }), (0, jsx_runtime_1.jsx)("span", { id: errorTextId, className: "ndl-sub-text ndl-error-text", children: errorText })] }))] })));
176
+ return ((0, jsx_runtime_1.jsxs)(Component, Object.assign({ ref: ref, className: classes, style: style }, restProps, htmlAttributes, { children: [Boolean(label) && (0, jsx_runtime_1.jsx)(form_control_1.FormFieldLabel, { field: field, size: size }), SelectElement, (0, jsx_runtime_1.jsx)(form_control_1.FormFieldMessage, { field: field, size: size })] })));
168
177
  };
169
178
  exports.Select = Select;
170
179
  //# sourceMappingURL=Select.js.map