@mantine/core 9.0.1 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/components/Blockquote/Blockquote.cjs +5 -6
- package/cjs/components/Blockquote/Blockquote.cjs.map +1 -1
- package/cjs/components/Flex/Flex.cjs +7 -2
- package/cjs/components/Flex/Flex.cjs.map +1 -1
- package/cjs/components/FloatingIndicator/FloatingIndicator.cjs +1 -2
- package/cjs/components/FloatingIndicator/FloatingIndicator.cjs.map +1 -1
- package/cjs/components/MaskInput/MaskInput.cjs +24 -0
- package/cjs/components/MaskInput/MaskInput.cjs.map +1 -0
- package/cjs/components/MaskInput/use-mask-input-props.cjs +29 -0
- package/cjs/components/MaskInput/use-mask-input-props.cjs.map +1 -0
- package/cjs/components/Rating/Rating.cjs +1 -2
- package/cjs/components/Rating/Rating.cjs.map +1 -1
- package/cjs/components/SemiCircleProgress/SemiCircleProgress.cjs +2 -0
- package/cjs/components/SemiCircleProgress/SemiCircleProgress.cjs.map +1 -1
- package/cjs/components/Slider/Marks/Marks.cjs +3 -2
- package/cjs/components/Slider/Marks/Marks.cjs.map +1 -1
- package/cjs/components/Slider/Marks/is-mark-filled.cjs +2 -1
- package/cjs/components/Slider/Marks/is-mark-filled.cjs.map +1 -1
- package/cjs/components/Slider/Slider/Slider.cjs +12 -3
- package/cjs/components/Slider/Slider/Slider.cjs.map +1 -1
- package/cjs/components/Slider/Track/Track.cjs +3 -2
- package/cjs/components/Slider/Track/Track.cjs.map +1 -1
- package/cjs/components/Tabs/Tabs.cjs +3 -1
- package/cjs/components/Tabs/Tabs.cjs.map +1 -1
- package/cjs/components/Tabs/Tabs.context.cjs.map +1 -1
- package/cjs/components/Tabs/TabsPanel/TabsPanel.cjs +2 -1
- package/cjs/components/Tabs/TabsPanel/TabsPanel.cjs.map +1 -1
- package/cjs/components/Textarea/Autosize.cjs +1 -0
- package/cjs/components/Textarea/Autosize.cjs.map +1 -1
- package/cjs/components/Tree/FlatTreeNode.cjs +102 -0
- package/cjs/components/Tree/FlatTreeNode.cjs.map +1 -0
- package/cjs/components/Tree/Tree.cjs +10 -2
- package/cjs/components/Tree/Tree.cjs.map +1 -1
- package/cjs/components/Tree/Tree.module.cjs.map +1 -1
- package/cjs/components/Tree/TreeNode.cjs +65 -27
- package/cjs/components/Tree/TreeNode.cjs.map +1 -1
- package/cjs/components/Tree/filter-tree-data/filter-tree-data.cjs +23 -0
- package/cjs/components/Tree/filter-tree-data/filter-tree-data.cjs.map +1 -0
- package/cjs/components/Tree/flatten-tree-data/flatten-tree-data.cjs +28 -0
- package/cjs/components/Tree/flatten-tree-data/flatten-tree-data.cjs.map +1 -0
- package/cjs/components/Tree/get-children-nodes-values/get-children-nodes-values.cjs +1 -0
- package/cjs/components/Tree/merge-async-children/merge-async-children.cjs +32 -0
- package/cjs/components/Tree/merge-async-children/merge-async-children.cjs.map +1 -0
- package/cjs/components/Tree/move-tree-node/move-tree-node.cjs +78 -0
- package/cjs/components/Tree/move-tree-node/move-tree-node.cjs.map +1 -0
- package/cjs/components/Tree/use-tree-node-drag-drop.cjs +96 -0
- package/cjs/components/Tree/use-tree-node-drag-drop.cjs.map +1 -0
- package/cjs/components/Tree/use-tree.cjs +176 -26
- package/cjs/components/Tree/use-tree.cjs.map +1 -1
- package/cjs/core/Box/Box.cjs +6 -2
- package/cjs/core/Box/Box.cjs.map +1 -1
- package/cjs/core/InlineStyles/InlineStyles.cjs +14 -2
- package/cjs/core/InlineStyles/InlineStyles.cjs.map +1 -1
- package/cjs/core/InlineStyles/hash-styles.cjs +15 -0
- package/cjs/core/InlineStyles/hash-styles.cjs.map +1 -0
- package/cjs/core/MantineProvider/Mantine.context.cjs +4 -0
- package/cjs/core/MantineProvider/Mantine.context.cjs.map +1 -1
- package/cjs/core/MantineProvider/MantineProvider.cjs +3 -2
- package/cjs/core/MantineProvider/MantineProvider.cjs.map +1 -1
- package/cjs/core/MantineProvider/color-functions/default-variant-colors-resolver/default-variant-colors-resolver.cjs +3 -4
- package/cjs/core/MantineProvider/color-functions/default-variant-colors-resolver/default-variant-colors-resolver.cjs.map +1 -1
- package/cjs/index.cjs +16 -0
- package/esm/components/Blockquote/Blockquote.mjs +5 -6
- package/esm/components/Blockquote/Blockquote.mjs.map +1 -1
- package/esm/components/Flex/Flex.mjs +7 -2
- package/esm/components/Flex/Flex.mjs.map +1 -1
- package/esm/components/FloatingIndicator/FloatingIndicator.mjs +1 -2
- package/esm/components/FloatingIndicator/FloatingIndicator.mjs.map +1 -1
- package/esm/components/MaskInput/MaskInput.mjs +23 -0
- package/esm/components/MaskInput/MaskInput.mjs.map +1 -0
- package/esm/components/MaskInput/use-mask-input-props.mjs +28 -0
- package/esm/components/MaskInput/use-mask-input-props.mjs.map +1 -0
- package/esm/components/Rating/Rating.mjs +1 -2
- package/esm/components/Rating/Rating.mjs.map +1 -1
- package/esm/components/SemiCircleProgress/SemiCircleProgress.mjs +2 -0
- package/esm/components/SemiCircleProgress/SemiCircleProgress.mjs.map +1 -1
- package/esm/components/Slider/Marks/Marks.mjs +3 -2
- package/esm/components/Slider/Marks/Marks.mjs.map +1 -1
- package/esm/components/Slider/Marks/is-mark-filled.mjs +2 -1
- package/esm/components/Slider/Marks/is-mark-filled.mjs.map +1 -1
- package/esm/components/Slider/Slider/Slider.mjs +12 -3
- package/esm/components/Slider/Slider/Slider.mjs.map +1 -1
- package/esm/components/Slider/Track/Track.mjs +3 -2
- package/esm/components/Slider/Track/Track.mjs.map +1 -1
- package/esm/components/Tabs/Tabs.context.mjs.map +1 -1
- package/esm/components/Tabs/Tabs.mjs +3 -1
- package/esm/components/Tabs/Tabs.mjs.map +1 -1
- package/esm/components/Tabs/TabsPanel/TabsPanel.mjs +2 -1
- package/esm/components/Tabs/TabsPanel/TabsPanel.mjs.map +1 -1
- package/esm/components/Textarea/Autosize.mjs +1 -0
- package/esm/components/Textarea/Autosize.mjs.map +1 -1
- package/esm/components/Tree/FlatTreeNode.mjs +101 -0
- package/esm/components/Tree/FlatTreeNode.mjs.map +1 -0
- package/esm/components/Tree/Tree.mjs +11 -3
- package/esm/components/Tree/Tree.mjs.map +1 -1
- package/esm/components/Tree/Tree.module.mjs.map +1 -1
- package/esm/components/Tree/TreeNode.mjs +65 -27
- package/esm/components/Tree/TreeNode.mjs.map +1 -1
- package/esm/components/Tree/filter-tree-data/filter-tree-data.mjs +22 -0
- package/esm/components/Tree/filter-tree-data/filter-tree-data.mjs.map +1 -0
- package/esm/components/Tree/flatten-tree-data/flatten-tree-data.mjs +28 -0
- package/esm/components/Tree/flatten-tree-data/flatten-tree-data.mjs.map +1 -0
- package/esm/components/Tree/get-children-nodes-values/get-children-nodes-values.mjs +1 -1
- package/esm/components/Tree/merge-async-children/merge-async-children.mjs +32 -0
- package/esm/components/Tree/merge-async-children/merge-async-children.mjs.map +1 -0
- package/esm/components/Tree/move-tree-node/move-tree-node.mjs +78 -0
- package/esm/components/Tree/move-tree-node/move-tree-node.mjs.map +1 -0
- package/esm/components/Tree/use-tree-node-drag-drop.mjs +96 -0
- package/esm/components/Tree/use-tree-node-drag-drop.mjs.map +1 -0
- package/esm/components/Tree/use-tree.mjs +177 -27
- package/esm/components/Tree/use-tree.mjs.map +1 -1
- package/esm/core/Box/Box.mjs +7 -3
- package/esm/core/Box/Box.mjs.map +1 -1
- package/esm/core/InlineStyles/InlineStyles.mjs +14 -2
- package/esm/core/InlineStyles/InlineStyles.mjs.map +1 -1
- package/esm/core/InlineStyles/hash-styles.mjs +15 -0
- package/esm/core/InlineStyles/hash-styles.mjs.map +1 -0
- package/esm/core/MantineProvider/Mantine.context.mjs +4 -1
- package/esm/core/MantineProvider/Mantine.context.mjs.map +1 -1
- package/esm/core/MantineProvider/MantineProvider.mjs +3 -2
- package/esm/core/MantineProvider/MantineProvider.mjs.map +1 -1
- package/esm/core/MantineProvider/color-functions/default-variant-colors-resolver/default-variant-colors-resolver.mjs +3 -4
- package/esm/core/MantineProvider/color-functions/default-variant-colors-resolver/default-variant-colors-resolver.mjs.map +1 -1
- package/esm/index.mjs +9 -2
- package/lib/components/MaskInput/MaskInput.d.ts +68 -0
- package/lib/components/MaskInput/index.d.ts +7 -0
- package/lib/components/MaskInput/use-mask-input-props.d.ts +428 -0
- package/lib/components/Slider/Marks/Marks.d.ts +2 -1
- package/lib/components/Slider/Marks/is-mark-filled.d.ts +2 -1
- package/lib/components/Slider/Slider/Slider.d.ts +2 -0
- package/lib/components/Slider/Track/Track.d.ts +2 -1
- package/lib/components/Tabs/Tabs.context.d.ts +1 -0
- package/lib/components/Tabs/Tabs.d.ts +2 -0
- package/lib/components/Tree/FlatTreeNode.d.ts +31 -0
- package/lib/components/Tree/Tree.d.ts +21 -1
- package/lib/components/Tree/TreeNode.d.ts +6 -2
- package/lib/components/Tree/filter-tree-data/filter-tree-data.d.ts +4 -0
- package/lib/components/Tree/flatten-tree-data/flatten-tree-data.d.ts +15 -0
- package/lib/components/Tree/index.d.ts +9 -0
- package/lib/components/Tree/merge-async-children/merge-async-children.d.ts +2 -0
- package/lib/components/Tree/move-tree-node/move-tree-node.d.ts +11 -0
- package/lib/components/Tree/use-tree-node-drag-drop.d.ts +18 -0
- package/lib/components/Tree/use-tree.d.ts +19 -1
- package/lib/components/index.d.ts +1 -0
- package/lib/core/InlineStyles/InlineStyles.d.ts +2 -1
- package/lib/core/InlineStyles/hash-styles.d.ts +2 -0
- package/lib/core/InlineStyles/index.d.ts +1 -0
- package/lib/core/MantineProvider/Mantine.context.d.ts +2 -0
- package/lib/core/MantineProvider/MantineProvider.d.ts +3 -1
- package/lib/core/MantineProvider/index.d.ts +1 -1
- package/package.json +5 -5
- package/styles/Tree.css +66 -0
- package/styles/Tree.layer.css +66 -0
- package/styles.css +66 -0
- package/styles.layer.css +66 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Autosize.mjs","names":[],"sources":["../../../src/components/Textarea/Autosize.tsx"],"sourcesContent":["import React, { useEffect, useLayoutEffect, useRef } from 'react';\nimport { useMergedRef } from '@mantine/hooks';\n\ntype TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nexport interface TextareaAutosizeProps extends Omit<TextareaProps, 'style'> {\n ref?: React.Ref<HTMLTextAreaElement>;\n maxRows?: number;\n minRows?: number;\n style?: Omit<NonNullable<TextareaProps['style']>, 'maxHeight' | 'minHeight'> & {\n height?: number;\n };\n}\n\nconst SIZING_STYLE_KEYS = [\n 'borderBottomWidth',\n 'borderLeftWidth',\n 'borderRightWidth',\n 'borderTopWidth',\n 'boxSizing',\n 'fontFamily',\n 'fontSize',\n 'fontStyle',\n 'fontWeight',\n 'letterSpacing',\n 'lineHeight',\n 'paddingBottom',\n 'paddingLeft',\n 'paddingRight',\n 'paddingTop',\n 'tabSize',\n 'textIndent',\n 'textRendering',\n 'textTransform',\n 'width',\n 'wordBreak',\n 'wordSpacing',\n 'scrollbarGutter',\n] as const;\n\ntype SizingStyleKey = (typeof SIZING_STYLE_KEYS)[number];\n\ninterface SizingData {\n sizingStyle: Pick<CSSStyleDeclaration, Extract<SizingStyleKey, keyof CSSStyleDeclaration>>;\n paddingSize: number;\n borderSize: number;\n}\n\nconst HIDDEN_TEXTAREA_STYLE: Record<string, string> = {\n 'min-height': '0',\n 'max-height': 'none',\n height: '0',\n visibility: 'hidden',\n overflow: 'hidden',\n position: 'absolute',\n 'z-index': '-1000',\n top: '0',\n right: '0',\n display: 'block',\n};\n\nfunction forceHiddenStyles(node: HTMLElement) {\n Object.keys(HIDDEN_TEXTAREA_STYLE).forEach((key) => {\n node.style.setProperty(key, HIDDEN_TEXTAREA_STYLE[key], 'important');\n });\n}\n\nfunction getSizingData(node: HTMLElement): SizingData | null {\n const style = window.getComputedStyle(node);\n\n if (style === null) {\n return null;\n }\n\n const sizingStyle = {} as SizingData['sizingStyle'];\n for (const key of SIZING_STYLE_KEYS) {\n (sizingStyle as any)[key] = style[key as keyof CSSStyleDeclaration];\n }\n\n if ((sizingStyle as any).boxSizing === '') {\n return null;\n }\n\n const paddingSize = parseFloat(sizingStyle.paddingBottom!) + parseFloat(sizingStyle.paddingTop!);\n\n const borderSize =\n parseFloat(sizingStyle.borderBottomWidth!) + parseFloat(sizingStyle.borderTopWidth!);\n\n return { sizingStyle, paddingSize, borderSize };\n}\n\nlet hiddenTextarea: HTMLTextAreaElement | null = null;\n\nfunction calculateNodeHeight(\n sizingData: SizingData,\n value: string,\n minRows = 1,\n maxRows = Infinity\n): [number, number] {\n if (!hiddenTextarea) {\n hiddenTextarea = document.createElement('textarea');\n hiddenTextarea.setAttribute('tabindex', '-1');\n hiddenTextarea.setAttribute('aria-hidden', 'true');\n hiddenTextarea.setAttribute('aria-label', 'autosize measurement');\n forceHiddenStyles(hiddenTextarea);\n }\n\n if (hiddenTextarea.parentNode === null) {\n document.body.appendChild(hiddenTextarea);\n }\n\n const { paddingSize, borderSize, sizingStyle } = sizingData;\n const { boxSizing } = sizingStyle;\n\n Object.keys(sizingStyle).forEach((key) => {\n (hiddenTextarea!.style as any)[key] = (sizingStyle as any)[key];\n });\n\n forceHiddenStyles(hiddenTextarea);\n\n hiddenTextarea.value = value;\n let height =\n boxSizing === 'border-box'\n ? hiddenTextarea.scrollHeight + borderSize\n : hiddenTextarea.scrollHeight - paddingSize;\n\n // Double set and calc due to Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1795904\n hiddenTextarea.value = value;\n height =\n boxSizing === 'border-box'\n ? hiddenTextarea.scrollHeight + borderSize\n : hiddenTextarea.scrollHeight - paddingSize;\n\n hiddenTextarea.value = 'x';\n const rowHeight = hiddenTextarea.scrollHeight - paddingSize;\n\n let minHeight = rowHeight * minRows;\n if (boxSizing === 'border-box') {\n minHeight = minHeight + paddingSize + borderSize;\n }\n height = Math.max(minHeight, height);\n\n let maxHeight = rowHeight * maxRows;\n if (boxSizing === 'border-box') {\n maxHeight = maxHeight + paddingSize + borderSize;\n }\n height = Math.min(maxHeight, height);\n\n return [height, rowHeight];\n}\n\nexport function TextareaAutosize({\n maxRows,\n minRows,\n onChange,\n ref: userRef,\n ...props\n}: TextareaAutosizeProps) {\n const isControlled = props.value !== undefined;\n const libRef = useRef<HTMLTextAreaElement | null>(null);\n const ref = useMergedRef(libRef, userRef);\n const heightRef = useRef(0);\n\n const resizeTextarea = () => {\n const node = libRef.current
|
|
1
|
+
{"version":3,"file":"Autosize.mjs","names":[],"sources":["../../../src/components/Textarea/Autosize.tsx"],"sourcesContent":["import React, { useEffect, useLayoutEffect, useRef } from 'react';\nimport { useMergedRef } from '@mantine/hooks';\n\ntype TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nexport interface TextareaAutosizeProps extends Omit<TextareaProps, 'style'> {\n ref?: React.Ref<HTMLTextAreaElement>;\n maxRows?: number;\n minRows?: number;\n style?: Omit<NonNullable<TextareaProps['style']>, 'maxHeight' | 'minHeight'> & {\n height?: number;\n };\n}\n\nconst SIZING_STYLE_KEYS = [\n 'borderBottomWidth',\n 'borderLeftWidth',\n 'borderRightWidth',\n 'borderTopWidth',\n 'boxSizing',\n 'fontFamily',\n 'fontSize',\n 'fontStyle',\n 'fontWeight',\n 'letterSpacing',\n 'lineHeight',\n 'paddingBottom',\n 'paddingLeft',\n 'paddingRight',\n 'paddingTop',\n 'tabSize',\n 'textIndent',\n 'textRendering',\n 'textTransform',\n 'width',\n 'wordBreak',\n 'wordSpacing',\n 'scrollbarGutter',\n] as const;\n\ntype SizingStyleKey = (typeof SIZING_STYLE_KEYS)[number];\n\ninterface SizingData {\n sizingStyle: Pick<CSSStyleDeclaration, Extract<SizingStyleKey, keyof CSSStyleDeclaration>>;\n paddingSize: number;\n borderSize: number;\n}\n\nconst HIDDEN_TEXTAREA_STYLE: Record<string, string> = {\n 'min-height': '0',\n 'max-height': 'none',\n height: '0',\n visibility: 'hidden',\n overflow: 'hidden',\n position: 'absolute',\n 'z-index': '-1000',\n top: '0',\n right: '0',\n display: 'block',\n};\n\nfunction forceHiddenStyles(node: HTMLElement) {\n Object.keys(HIDDEN_TEXTAREA_STYLE).forEach((key) => {\n node.style.setProperty(key, HIDDEN_TEXTAREA_STYLE[key], 'important');\n });\n}\n\nfunction getSizingData(node: HTMLElement): SizingData | null {\n const style = window.getComputedStyle(node);\n\n if (style === null) {\n return null;\n }\n\n const sizingStyle = {} as SizingData['sizingStyle'];\n for (const key of SIZING_STYLE_KEYS) {\n (sizingStyle as any)[key] = style[key as keyof CSSStyleDeclaration];\n }\n\n if ((sizingStyle as any).boxSizing === '') {\n return null;\n }\n\n const paddingSize = parseFloat(sizingStyle.paddingBottom!) + parseFloat(sizingStyle.paddingTop!);\n\n const borderSize =\n parseFloat(sizingStyle.borderBottomWidth!) + parseFloat(sizingStyle.borderTopWidth!);\n\n return { sizingStyle, paddingSize, borderSize };\n}\n\nlet hiddenTextarea: HTMLTextAreaElement | null = null;\n\nfunction calculateNodeHeight(\n sizingData: SizingData,\n value: string,\n minRows = 1,\n maxRows = Infinity\n): [number, number] {\n if (!hiddenTextarea) {\n hiddenTextarea = document.createElement('textarea');\n hiddenTextarea.setAttribute('tabindex', '-1');\n hiddenTextarea.setAttribute('aria-hidden', 'true');\n hiddenTextarea.setAttribute('aria-label', 'autosize measurement');\n forceHiddenStyles(hiddenTextarea);\n }\n\n if (hiddenTextarea.parentNode === null) {\n document.body.appendChild(hiddenTextarea);\n }\n\n const { paddingSize, borderSize, sizingStyle } = sizingData;\n const { boxSizing } = sizingStyle;\n\n Object.keys(sizingStyle).forEach((key) => {\n (hiddenTextarea!.style as any)[key] = (sizingStyle as any)[key];\n });\n\n forceHiddenStyles(hiddenTextarea);\n\n hiddenTextarea.value = value;\n let height =\n boxSizing === 'border-box'\n ? hiddenTextarea.scrollHeight + borderSize\n : hiddenTextarea.scrollHeight - paddingSize;\n\n // Double set and calc due to Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1795904\n hiddenTextarea.value = value;\n height =\n boxSizing === 'border-box'\n ? hiddenTextarea.scrollHeight + borderSize\n : hiddenTextarea.scrollHeight - paddingSize;\n\n hiddenTextarea.value = 'x';\n const rowHeight = hiddenTextarea.scrollHeight - paddingSize;\n\n let minHeight = rowHeight * minRows;\n if (boxSizing === 'border-box') {\n minHeight = minHeight + paddingSize + borderSize;\n }\n height = Math.max(minHeight, height);\n\n let maxHeight = rowHeight * maxRows;\n if (boxSizing === 'border-box') {\n maxHeight = maxHeight + paddingSize + borderSize;\n }\n height = Math.min(maxHeight, height);\n\n return [height, rowHeight];\n}\n\nexport function TextareaAutosize({\n maxRows,\n minRows,\n onChange,\n ref: userRef,\n ...props\n}: TextareaAutosizeProps) {\n const isControlled = props.value !== undefined;\n const libRef = useRef<HTMLTextAreaElement | null>(null);\n const ref = useMergedRef(libRef, userRef);\n const heightRef = useRef(0);\n\n const resizeTextarea = () => {\n const node = libRef.current;\n\n if (!node) {\n return;\n }\n\n const nodeSizingData = getSizingData(node);\n\n if (!nodeSizingData) {\n return;\n }\n\n const [height] = calculateNodeHeight(\n nodeSizingData,\n node.value || node.placeholder || 'x',\n minRows,\n maxRows\n );\n\n if (heightRef.current !== height) {\n heightRef.current = height;\n node.style.setProperty('height', `${height}px`, 'important');\n }\n };\n\n const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n if (!isControlled) {\n resizeTextarea();\n }\n onChange?.(event);\n };\n\n useLayoutEffect(resizeTextarea);\n\n useEffect(() => {\n const handleResize = () => resizeTextarea();\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n\n useEffect(() => {\n const handleFontsLoaded = () => resizeTextarea();\n document.fonts.addEventListener('loadingdone', handleFontsLoaded);\n return () => document.fonts.removeEventListener('loadingdone', handleFontsLoaded);\n }, []);\n\n useEffect(() => {\n const handleReset = (event: Event) => {\n if (libRef.current?.form === event.target && !isControlled) {\n const currentValue = libRef.current!.value;\n requestAnimationFrame(() => {\n if (libRef.current && currentValue !== libRef.current.value) {\n resizeTextarea();\n }\n });\n }\n };\n document.body.addEventListener('reset', handleReset);\n return () => document.body.removeEventListener('reset', handleReset);\n }, [isControlled]);\n\n return <textarea {...props} onChange={handleChange} ref={ref} />;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { findElementAncestor } from "../../core/utils/find-element-ancestor/find-element-ancestor.mjs";
|
|
3
|
+
import Tree_module_default from "./Tree.module.mjs";
|
|
4
|
+
import { memo, useRef } from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
//#region packages/@mantine/core/src/components/Tree/FlatTreeNode.tsx
|
|
7
|
+
const FlatTreeNode = memo(function FlatTreeNode({ node, level, parent, hasChildren, expanded, tree, expandOnClick = true, selectOnClick, expandOnSpace = true, checkOnSpace, renderNode, style, tabIndex = -1 }) {
|
|
8
|
+
const ref = useRef(null);
|
|
9
|
+
const isLoading = tree.isNodeLoading(node.value);
|
|
10
|
+
const loadError = tree.getNodeLoadError(node.value);
|
|
11
|
+
const selected = tree.selectedState.includes(node.value);
|
|
12
|
+
const handleClick = (event) => {
|
|
13
|
+
event.stopPropagation();
|
|
14
|
+
if (expandOnClick && hasChildren) tree.toggleExpanded(node.value);
|
|
15
|
+
if (selectOnClick) tree.select(node.value);
|
|
16
|
+
ref.current?.focus();
|
|
17
|
+
};
|
|
18
|
+
const handleKeyDown = (event) => {
|
|
19
|
+
if (event.nativeEvent.code === "ArrowRight") {
|
|
20
|
+
event.stopPropagation();
|
|
21
|
+
event.preventDefault();
|
|
22
|
+
if (expanded && hasChildren) {
|
|
23
|
+
const root = findElementAncestor(event.currentTarget, "[data-tree-root]");
|
|
24
|
+
const nodes = root ? Array.from(root.querySelectorAll("[role=treeitem]")).filter((treeNode) => treeNode.style.display !== "none") : [];
|
|
25
|
+
const index = nodes.indexOf(event.currentTarget);
|
|
26
|
+
if (index !== -1) nodes[index + 1]?.focus();
|
|
27
|
+
} else if (hasChildren) tree.expand(node.value);
|
|
28
|
+
}
|
|
29
|
+
if (event.nativeEvent.code === "ArrowLeft") {
|
|
30
|
+
event.stopPropagation();
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
if (expanded && hasChildren) tree.collapse(node.value);
|
|
33
|
+
else if (parent) (findElementAncestor(event.currentTarget, "[data-tree-root]")?.querySelector(`[role=treeitem][data-value="${CSS.escape(parent)}"]`))?.focus();
|
|
34
|
+
}
|
|
35
|
+
if (event.nativeEvent.code === "ArrowDown" || event.nativeEvent.code === "ArrowUp") {
|
|
36
|
+
const root = findElementAncestor(event.currentTarget, "[data-tree-root]");
|
|
37
|
+
if (!root) return;
|
|
38
|
+
event.stopPropagation();
|
|
39
|
+
event.preventDefault();
|
|
40
|
+
const nodes = Array.from(root.querySelectorAll("[role=treeitem]")).filter((treeNode) => treeNode.style.display !== "none");
|
|
41
|
+
const index = nodes.indexOf(event.currentTarget);
|
|
42
|
+
if (index === -1) return;
|
|
43
|
+
nodes[event.nativeEvent.code === "ArrowDown" ? index + 1 : index - 1]?.focus();
|
|
44
|
+
}
|
|
45
|
+
if (event.nativeEvent.code === "Space") {
|
|
46
|
+
if (expandOnSpace) {
|
|
47
|
+
event.stopPropagation();
|
|
48
|
+
event.preventDefault();
|
|
49
|
+
tree.toggleExpanded(node.value);
|
|
50
|
+
}
|
|
51
|
+
if (checkOnSpace) {
|
|
52
|
+
event.stopPropagation();
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
if (tree.isNodeChecked(node.value)) tree.uncheckNode(node.value);
|
|
55
|
+
else tree.checkNode(node.value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const elementProps = {
|
|
60
|
+
className: Tree_module_default.label,
|
|
61
|
+
style: {},
|
|
62
|
+
onClick: handleClick,
|
|
63
|
+
"data-selected": selected || void 0,
|
|
64
|
+
"data-value": node.value
|
|
65
|
+
};
|
|
66
|
+
return /* @__PURE__ */ jsx("div", {
|
|
67
|
+
ref,
|
|
68
|
+
className: Tree_module_default.node,
|
|
69
|
+
style: {
|
|
70
|
+
"--label-offset": `calc(var(--level-offset, var(--mantine-spacing-lg)) * ${level - 1})`,
|
|
71
|
+
...style
|
|
72
|
+
},
|
|
73
|
+
role: "treeitem",
|
|
74
|
+
"aria-selected": selected,
|
|
75
|
+
"aria-expanded": hasChildren ? expanded : void 0,
|
|
76
|
+
"data-value": node.value,
|
|
77
|
+
"data-selected": selected || void 0,
|
|
78
|
+
"data-level": level,
|
|
79
|
+
tabIndex,
|
|
80
|
+
onKeyDown: handleKeyDown,
|
|
81
|
+
children: typeof renderNode === "function" ? renderNode({
|
|
82
|
+
node,
|
|
83
|
+
level,
|
|
84
|
+
selected,
|
|
85
|
+
tree,
|
|
86
|
+
expanded,
|
|
87
|
+
hasChildren,
|
|
88
|
+
isLoading,
|
|
89
|
+
loadError,
|
|
90
|
+
elementProps
|
|
91
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
92
|
+
...elementProps,
|
|
93
|
+
children: node.label
|
|
94
|
+
})
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
FlatTreeNode.displayName = "@mantine/core/FlatTreeNode";
|
|
98
|
+
//#endregion
|
|
99
|
+
export { FlatTreeNode };
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=FlatTreeNode.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FlatTreeNode.mjs","names":["classes"],"sources":["../../../src/components/Tree/FlatTreeNode.tsx"],"sourcesContent":["import { memo, useRef } from 'react';\nimport { findElementAncestor } from '../../core';\nimport type { RenderNode, TreeNodeData } from './Tree';\nimport type { TreeController } from './use-tree';\nimport classes from './Tree.module.css';\n\nexport interface FlatTreeNodeProps {\n /** Node data from tree data */\n node: TreeNodeData;\n\n /** Nesting level of the node, starts at 1 */\n level: number;\n\n /** Value of the parent node, `null` for root nodes */\n parent: string | null;\n\n /** Whether the node has children */\n hasChildren: boolean;\n\n /** Whether the node is expanded */\n expanded: boolean;\n\n /** Tree controller instance, return value of `useTree` hook */\n tree: TreeController;\n\n /** If set, tree node with children is expanded on click @default true */\n expandOnClick?: boolean;\n\n /** If set, tree node is selected on click @default false */\n selectOnClick?: boolean;\n\n /** If set, tree node with children is expanded on space key press @default true */\n expandOnSpace?: boolean;\n\n /** If set, tree node is checked on space key press @default false */\n checkOnSpace?: boolean;\n\n /** A function to render tree node label */\n renderNode?: RenderNode;\n\n /** Style to apply to the root element, used for virtualizer positioning */\n style?: React.CSSProperties;\n\n /** Tab index for the node */\n tabIndex?: number;\n}\n\nexport const FlatTreeNode = memo(function FlatTreeNode({\n node,\n level,\n parent,\n hasChildren,\n expanded,\n tree,\n expandOnClick = true,\n selectOnClick,\n expandOnSpace = true,\n checkOnSpace,\n renderNode,\n style,\n tabIndex = -1,\n}: FlatTreeNodeProps) {\n const ref = useRef<HTMLDivElement>(null);\n const isLoading = tree.isNodeLoading(node.value);\n const loadError = tree.getNodeLoadError(node.value);\n const selected = tree.selectedState.includes(node.value);\n\n const handleClick = (event: React.MouseEvent) => {\n event.stopPropagation();\n\n if (expandOnClick && hasChildren) {\n tree.toggleExpanded(node.value);\n }\n\n if (selectOnClick) {\n tree.select(node.value);\n }\n\n ref.current?.focus();\n };\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.nativeEvent.code === 'ArrowRight') {\n event.stopPropagation();\n event.preventDefault();\n\n if (expanded && hasChildren) {\n const root = findElementAncestor(event.currentTarget as HTMLElement, '[data-tree-root]');\n const nodes = root\n ? Array.from(root.querySelectorAll<HTMLElement>('[role=treeitem]')).filter(\n (treeNode) => treeNode.style.display !== 'none'\n )\n : [];\n const index = nodes.indexOf(event.currentTarget as HTMLElement);\n if (index !== -1) {\n nodes[index + 1]?.focus();\n }\n } else if (hasChildren) {\n tree.expand(node.value);\n }\n }\n\n if (event.nativeEvent.code === 'ArrowLeft') {\n event.stopPropagation();\n event.preventDefault();\n\n if (expanded && hasChildren) {\n tree.collapse(node.value);\n } else if (parent) {\n const root = findElementAncestor(event.currentTarget as HTMLElement, '[data-tree-root]');\n const parentElement = root?.querySelector<HTMLElement>(\n `[role=treeitem][data-value=\"${CSS.escape(parent)}\"]`\n );\n parentElement?.focus();\n }\n }\n\n if (event.nativeEvent.code === 'ArrowDown' || event.nativeEvent.code === 'ArrowUp') {\n const root = findElementAncestor(event.currentTarget as HTMLElement, '[data-tree-root]');\n\n if (!root) {\n return;\n }\n\n event.stopPropagation();\n event.preventDefault();\n const nodes = Array.from(root.querySelectorAll<HTMLElement>('[role=treeitem]')).filter(\n (treeNode) => treeNode.style.display !== 'none'\n );\n const index = nodes.indexOf(event.currentTarget as HTMLElement);\n\n if (index === -1) {\n return;\n }\n\n const nextIndex = event.nativeEvent.code === 'ArrowDown' ? index + 1 : index - 1;\n nodes[nextIndex]?.focus();\n }\n\n if (event.nativeEvent.code === 'Space') {\n if (expandOnSpace) {\n event.stopPropagation();\n event.preventDefault();\n tree.toggleExpanded(node.value);\n }\n\n if (checkOnSpace) {\n event.stopPropagation();\n event.preventDefault();\n if (tree.isNodeChecked(node.value)) {\n tree.uncheckNode(node.value);\n } else {\n tree.checkNode(node.value);\n }\n }\n }\n };\n\n const elementProps = {\n className: classes.label,\n style: {} as React.CSSProperties,\n onClick: handleClick,\n 'data-selected': selected || undefined,\n 'data-value': node.value,\n };\n\n return (\n <div\n ref={ref}\n className={classes.node}\n style={{\n ...({\n '--label-offset': `calc(var(--level-offset, var(--mantine-spacing-lg)) * ${level - 1})`,\n } as React.CSSProperties),\n ...style,\n }}\n role=\"treeitem\"\n aria-selected={selected}\n aria-expanded={hasChildren ? expanded : undefined}\n data-value={node.value}\n data-selected={selected || undefined}\n data-level={level}\n tabIndex={tabIndex}\n onKeyDown={handleKeyDown}\n >\n {typeof renderNode === 'function' ? (\n renderNode({\n node,\n level,\n selected,\n tree,\n expanded,\n hasChildren,\n isLoading,\n loadError,\n elementProps,\n })\n ) : (\n <div {...elementProps}>{node.label}</div>\n )}\n </div>\n );\n});\n\nFlatTreeNode.displayName = '@mantine/core/FlatTreeNode';\n"],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ import { Box } from "../../core/Box/Box.mjs";
|
|
|
8
8
|
import { TreeNode } from "./TreeNode.mjs";
|
|
9
9
|
import { useTree } from "./use-tree.mjs";
|
|
10
10
|
import Tree_module_default from "./Tree.module.mjs";
|
|
11
|
-
import { useEffect, useMemo } from "react";
|
|
11
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
12
12
|
import { useClickOutside, useMergedRef } from "@mantine/hooks";
|
|
13
13
|
import { jsx } from "react/jsx-runtime";
|
|
14
14
|
//#region packages/@mantine/core/src/components/Tree/Tree.tsx
|
|
@@ -27,9 +27,13 @@ const defaultProps = {
|
|
|
27
27
|
const varsResolver = createVarsResolver((_theme, { levelOffset }) => ({ root: { "--level-offset": getSpacing(levelOffset) } }));
|
|
28
28
|
const Tree = factory((_props) => {
|
|
29
29
|
const props = useProps("Tree", defaultProps, _props);
|
|
30
|
-
const { classNames, className, style, styles, unstyled, vars, data, expandOnClick, tree, renderNode, selectOnClick, clearSelectionOnOutsideClick, allowRangeSelection, expandOnSpace, levelOffset, checkOnSpace, keepMounted, attributes, ref, ...others } = props;
|
|
30
|
+
const { classNames, className, style, styles, unstyled, vars, data, expandOnClick, tree, renderNode, selectOnClick, clearSelectionOnOutsideClick, allowRangeSelection, expandOnSpace, levelOffset, checkOnSpace, keepMounted, onDragDrop, withLines, attributes, ref, ...others } = props;
|
|
31
31
|
const defaultController = useTree();
|
|
32
32
|
const controller = tree || defaultController;
|
|
33
|
+
const dragStateRef = useRef({
|
|
34
|
+
draggedValue: null,
|
|
35
|
+
currentDropTarget: null
|
|
36
|
+
});
|
|
33
37
|
const getStyles = useStyles({
|
|
34
38
|
name: "Tree",
|
|
35
39
|
classes: Tree_module_default,
|
|
@@ -60,7 +64,10 @@ const Tree = factory((_props) => {
|
|
|
60
64
|
allowRangeSelection,
|
|
61
65
|
expandOnSpace,
|
|
62
66
|
checkOnSpace,
|
|
63
|
-
keepMounted
|
|
67
|
+
keepMounted,
|
|
68
|
+
onDragDrop,
|
|
69
|
+
dragStateRef,
|
|
70
|
+
data
|
|
64
71
|
}, node.value));
|
|
65
72
|
return /* @__PURE__ */ jsx(Box, {
|
|
66
73
|
component: "ul",
|
|
@@ -70,6 +77,7 @@ const Tree = factory((_props) => {
|
|
|
70
77
|
role: "tree",
|
|
71
78
|
"aria-multiselectable": controller.multiple,
|
|
72
79
|
"data-tree-root": true,
|
|
80
|
+
"data-with-lines": withLines || void 0,
|
|
73
81
|
children: nodes
|
|
74
82
|
});
|
|
75
83
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tree.mjs","names":["classes"],"sources":["../../../src/components/Tree/Tree.tsx"],"sourcesContent":["import { useEffect, useMemo } from 'react';\nimport { useClickOutside, useMergedRef } from '@mantine/hooks';\nimport {\n Box,\n BoxProps,\n createVarsResolver,\n ElementProps,\n factory,\n Factory,\n getSpacing,\n MantineSpacing,\n StylesApiProps,\n useProps,\n useStyles,\n} from '../../core';\nimport { TreeNode } from './TreeNode';\nimport { TreeController, useTree } from './use-tree';\nimport classes from './Tree.module.css';\n\nexport interface TreeNodeData {\n label: React.ReactNode;\n value: string;\n nodeProps?: Record<string, any>;\n children?: TreeNodeData[];\n}\n\nexport interface RenderTreeNodePayload {\n /** Node level in the tree */\n level: number;\n\n /** `true` if the node is expanded, applicable only for nodes with `children` */\n expanded: boolean;\n\n /** `true` if the node has non-empty `children` array */\n hasChildren: boolean;\n\n /** `true` if the node is selected */\n selected: boolean;\n\n /** Node data from the `data` prop of `Tree` */\n node: TreeNodeData;\n\n /** Tree controller instance, return value of `useTree` hook */\n tree: TreeController;\n\n /** Props to spread into the root node element */\n elementProps: {\n className: string;\n style: React.CSSProperties;\n onClick: (event: React.MouseEvent) => void;\n 'data-selected': boolean | undefined;\n 'data-value': string;\n };\n}\n\nexport type RenderNode = (payload: RenderTreeNodePayload) => React.ReactNode;\n\nexport type TreeStylesNames = 'root' | 'node' | 'subtree' | 'label';\nexport type TreeCssVariables = {\n root: '--level-offset';\n};\n\nexport interface TreeProps extends BoxProps, StylesApiProps<TreeFactory>, ElementProps<'ul'> {\n /** Data used to render nodes */\n data: TreeNodeData[];\n\n /** Horizontal padding of each subtree level, key of `theme.spacing` or any valid CSS value @default 'lg' */\n levelOffset?: MantineSpacing;\n\n /** If set, tree node with children is expanded on click @default true */\n expandOnClick?: boolean;\n\n /** If set, tree node with children is expanded on space key press @default true */\n expandOnSpace?: boolean;\n\n /** If set, tree node is checked on space key press @default false */\n checkOnSpace?: boolean;\n\n /** If set, tree node is selected on click @default false */\n selectOnClick?: boolean;\n\n /** Use-tree hook instance that can be used to manipulate component state */\n tree?: TreeController;\n\n /** A function to render tree node label */\n renderNode?: RenderNode;\n\n /** If set, selection is cleared when user clicks outside of the tree @default false */\n clearSelectionOnOutsideClick?: boolean;\n\n /** If set, tree nodes range can be selected with click when `Shift` key is pressed @default true */\n allowRangeSelection?: boolean;\n\n /** If set, subtree content is kept mounted when collapsed. React 19 `Activity` is used to preserve state. @default false */\n keepMounted?: boolean;\n}\n\nfunction getFlatValues(data: TreeNodeData[]): string[] {\n return data.reduce<string[]>((acc, item) => {\n acc.push(item.value);\n if (item.children) {\n acc.push(...getFlatValues(item.children));\n }\n return acc;\n }, []);\n}\n\nexport type TreeFactory = Factory<{\n props: TreeProps;\n ref: HTMLUListElement;\n stylesNames: TreeStylesNames;\n vars: TreeCssVariables;\n}>;\n\nconst defaultProps = {\n expandOnClick: true,\n allowRangeSelection: true,\n expandOnSpace: true,\n} satisfies Partial<TreeProps>;\n\nconst varsResolver = createVarsResolver<TreeFactory>((_theme, { levelOffset }) => ({\n root: {\n '--level-offset': getSpacing(levelOffset),\n },\n}));\n\nexport const Tree = factory<TreeFactory>((_props) => {\n const props = useProps('Tree', defaultProps, _props);\n const {\n classNames,\n className,\n style,\n styles,\n unstyled,\n vars,\n data,\n expandOnClick,\n tree,\n renderNode,\n selectOnClick,\n clearSelectionOnOutsideClick,\n allowRangeSelection,\n expandOnSpace,\n levelOffset,\n checkOnSpace,\n keepMounted,\n attributes,\n ref,\n ...others\n } = props;\n\n const defaultController = useTree();\n const controller = tree || defaultController;\n\n const getStyles = useStyles<TreeFactory>({\n name: 'Tree',\n classes,\n props,\n className,\n style,\n classNames,\n styles,\n unstyled,\n attributes,\n vars,\n varsResolver,\n });\n\n const clickOutsideRef = useClickOutside(\n () => clearSelectionOnOutsideClick && controller.clearSelected()\n );\n\n const mergedRef = useMergedRef(ref, clickOutsideRef);\n\n const flatValues = useMemo(() => getFlatValues(data), [data]);\n\n useEffect(() => {\n controller.initialize(data);\n }, [data]);\n\n const nodes = data.map((node, index) => (\n <TreeNode\n key={node.value}\n node={node}\n getStyles={getStyles}\n rootIndex={index}\n expandOnClick={expandOnClick}\n selectOnClick={selectOnClick}\n controller={controller}\n renderNode={renderNode}\n flatValues={flatValues}\n allowRangeSelection={allowRangeSelection}\n expandOnSpace={expandOnSpace}\n checkOnSpace={checkOnSpace}\n keepMounted={keepMounted}\n />\n ));\n\n return (\n <Box\n component=\"ul\"\n ref={mergedRef}\n {...getStyles('root')}\n {...others}\n role=\"tree\"\n aria-multiselectable={controller.multiple}\n data-tree-root\n >\n {nodes}\n </Box>\n );\n});\n\nTree.displayName = '@mantine/core/Tree';\nTree.classes = classes;\nTree.varsResolver = varsResolver;\n\nexport namespace Tree {\n export type Props = TreeProps;\n export type StylesNames = TreeStylesNames;\n export type Factory = TreeFactory;\n export type NodeData = TreeNodeData;\n export type RenderNodePayload = RenderTreeNodePayload;\n}\n"],"mappings":";;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"Tree.mjs","names":["classes"],"sources":["../../../src/components/Tree/Tree.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef } from 'react';\nimport { useClickOutside, useMergedRef } from '@mantine/hooks';\nimport {\n Box,\n BoxProps,\n createVarsResolver,\n ElementProps,\n factory,\n Factory,\n getSpacing,\n MantineSpacing,\n StylesApiProps,\n useProps,\n useStyles,\n} from '../../core';\nimport type { TreeDragDropPayload } from './move-tree-node/move-tree-node';\nimport { TreeNode } from './TreeNode';\nimport { TreeController, useTree } from './use-tree';\nimport classes from './Tree.module.css';\n\nexport interface TreeNodeData {\n label: React.ReactNode;\n value: string;\n nodeProps?: Record<string, any>;\n children?: TreeNodeData[];\n hasChildren?: boolean;\n}\n\nexport interface RenderTreeNodePayload {\n /** Node level in the tree */\n level: number;\n\n /** `true` if the node is expanded, applicable only for nodes with `children` */\n expanded: boolean;\n\n /** `true` if the node has non-empty `children` array or `hasChildren` is set to `true` in the data */\n hasChildren: boolean;\n\n /** `true` if the node is selected */\n selected: boolean;\n\n /** `true` if the node's children are currently being loaded */\n isLoading: boolean;\n\n /** Error from the last failed load attempt, or `null` */\n loadError: Error | null;\n\n /** Node data from the `data` prop of `Tree` */\n node: TreeNodeData;\n\n /** Tree controller instance, return value of `useTree` hook */\n tree: TreeController;\n\n /** Props to spread into the root node element */\n elementProps: {\n className: string;\n style: React.CSSProperties;\n onClick: (event: React.MouseEvent) => void;\n 'data-selected': boolean | undefined;\n 'data-value': string;\n draggable?: boolean;\n onDragStart?: (event: React.DragEvent) => void;\n onDragOver?: (event: React.DragEvent) => void;\n onDragLeave?: (event: React.DragEvent) => void;\n onDrop?: (event: React.DragEvent) => void;\n onDragEnd?: (event: React.DragEvent) => void;\n };\n}\n\nexport type RenderNode = (payload: RenderTreeNodePayload) => React.ReactNode;\n\nexport type TreeStylesNames = 'root' | 'node' | 'subtree' | 'label';\nexport type TreeCssVariables = {\n root: '--level-offset';\n};\n\nexport interface TreeDragState {\n draggedValue: string | null;\n currentDropTarget: HTMLElement | null;\n}\n\nexport interface TreeProps extends BoxProps, StylesApiProps<TreeFactory>, ElementProps<'ul'> {\n /** Data used to render nodes */\n data: TreeNodeData[];\n\n /** Horizontal padding of each subtree level, key of `theme.spacing` or any valid CSS value @default 'lg' */\n levelOffset?: MantineSpacing;\n\n /** If set, tree node with children is expanded on click @default true */\n expandOnClick?: boolean;\n\n /** If set, tree node with children is expanded on space key press @default true */\n expandOnSpace?: boolean;\n\n /** If set, tree node is checked on space key press @default false */\n checkOnSpace?: boolean;\n\n /** If set, tree node is selected on click @default false */\n selectOnClick?: boolean;\n\n /** Use-tree hook instance that can be used to manipulate component state */\n tree?: TreeController;\n\n /** A function to render tree node label */\n renderNode?: RenderNode;\n\n /** If set, selection is cleared when user clicks outside of the tree @default false */\n clearSelectionOnOutsideClick?: boolean;\n\n /** If set, tree nodes range can be selected with click when `Shift` key is pressed @default true */\n allowRangeSelection?: boolean;\n\n /** If set, subtree content is kept mounted when collapsed. React 19 `Activity` is used to preserve state. @default false */\n keepMounted?: boolean;\n\n /** Called when a node is dropped on another node, enables drag-and-drop when provided */\n onDragDrop?: (payload: TreeDragDropPayload) => void;\n\n /** If set, connecting lines are rendered showing parent-child relationships @default false */\n withLines?: boolean;\n}\n\nfunction getFlatValues(data: TreeNodeData[]): string[] {\n return data.reduce<string[]>((acc, item) => {\n acc.push(item.value);\n if (item.children) {\n acc.push(...getFlatValues(item.children));\n }\n return acc;\n }, []);\n}\n\nexport type TreeFactory = Factory<{\n props: TreeProps;\n ref: HTMLUListElement;\n stylesNames: TreeStylesNames;\n vars: TreeCssVariables;\n}>;\n\nconst defaultProps = {\n expandOnClick: true,\n allowRangeSelection: true,\n expandOnSpace: true,\n} satisfies Partial<TreeProps>;\n\nconst varsResolver = createVarsResolver<TreeFactory>((_theme, { levelOffset }) => ({\n root: {\n '--level-offset': getSpacing(levelOffset),\n },\n}));\n\nexport const Tree = factory<TreeFactory>((_props) => {\n const props = useProps('Tree', defaultProps, _props);\n const {\n classNames,\n className,\n style,\n styles,\n unstyled,\n vars,\n data,\n expandOnClick,\n tree,\n renderNode,\n selectOnClick,\n clearSelectionOnOutsideClick,\n allowRangeSelection,\n expandOnSpace,\n levelOffset,\n checkOnSpace,\n keepMounted,\n onDragDrop,\n withLines,\n attributes,\n ref,\n ...others\n } = props;\n\n const defaultController = useTree();\n const controller = tree || defaultController;\n\n const dragStateRef = useRef<TreeDragState>({ draggedValue: null, currentDropTarget: null });\n\n const getStyles = useStyles<TreeFactory>({\n name: 'Tree',\n classes,\n props,\n className,\n style,\n classNames,\n styles,\n unstyled,\n attributes,\n vars,\n varsResolver,\n });\n\n const clickOutsideRef = useClickOutside(\n () => clearSelectionOnOutsideClick && controller.clearSelected()\n );\n\n const mergedRef = useMergedRef(ref, clickOutsideRef);\n\n const flatValues = useMemo(() => getFlatValues(data), [data]);\n\n useEffect(() => {\n controller.initialize(data);\n }, [data]);\n\n const nodes = data.map((node, index) => (\n <TreeNode\n key={node.value}\n node={node}\n getStyles={getStyles}\n rootIndex={index}\n expandOnClick={expandOnClick}\n selectOnClick={selectOnClick}\n controller={controller}\n renderNode={renderNode}\n flatValues={flatValues}\n allowRangeSelection={allowRangeSelection}\n expandOnSpace={expandOnSpace}\n checkOnSpace={checkOnSpace}\n keepMounted={keepMounted}\n onDragDrop={onDragDrop}\n dragStateRef={dragStateRef}\n data={data}\n />\n ));\n\n return (\n <Box\n component=\"ul\"\n ref={mergedRef}\n {...getStyles('root')}\n {...others}\n role=\"tree\"\n aria-multiselectable={controller.multiple}\n data-tree-root\n data-with-lines={withLines || undefined}\n >\n {nodes}\n </Box>\n );\n});\n\nTree.displayName = '@mantine/core/Tree';\nTree.classes = classes;\nTree.varsResolver = varsResolver;\n\nexport namespace Tree {\n export type Props = TreeProps;\n export type StylesNames = TreeStylesNames;\n export type Factory = TreeFactory;\n export type NodeData = TreeNodeData;\n export type RenderNodePayload = RenderTreeNodePayload;\n}\n"],"mappings":";;;;;;;;;;;;;;AA0HA,SAAS,cAAc,MAAgC;AACrD,QAAO,KAAK,QAAkB,KAAK,SAAS;AAC1C,MAAI,KAAK,KAAK,MAAM;AACpB,MAAI,KAAK,SACP,KAAI,KAAK,GAAG,cAAc,KAAK,SAAS,CAAC;AAE3C,SAAO;IACN,EAAE,CAAC;;AAUR,MAAM,eAAe;CACnB,eAAe;CACf,qBAAqB;CACrB,eAAe;CAChB;AAED,MAAM,eAAe,oBAAiC,QAAQ,EAAE,mBAAmB,EACjF,MAAM,EACJ,kBAAkB,WAAW,YAAY,EAC1C,EACF,EAAE;AAEH,MAAa,OAAO,SAAsB,WAAW;CACnD,MAAM,QAAQ,SAAS,QAAQ,cAAc,OAAO;CACpD,MAAM,EACJ,YACA,WACA,OACA,QACA,UACA,MACA,MACA,eACA,MACA,YACA,eACA,8BACA,qBACA,eACA,aACA,cACA,aACA,YACA,WACA,YACA,KACA,GAAG,WACD;CAEJ,MAAM,oBAAoB,SAAS;CACnC,MAAM,aAAa,QAAQ;CAE3B,MAAM,eAAe,OAAsB;EAAE,cAAc;EAAM,mBAAmB;EAAM,CAAC;CAE3F,MAAM,YAAY,UAAuB;EACvC,MAAM;EACN,SAAA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CAMF,MAAM,YAAY,aAAa,KAJP,sBAChB,gCAAgC,WAAW,eAAe,CACjE,CAEmD;CAEpD,MAAM,aAAa,cAAc,cAAc,KAAK,EAAE,CAAC,KAAK,CAAC;AAE7D,iBAAgB;AACd,aAAW,WAAW,KAAK;IAC1B,CAAC,KAAK,CAAC;CAEV,MAAM,QAAQ,KAAK,KAAK,MAAM,UAC5B,oBAAC,UAAD;EAEQ;EACK;EACX,WAAW;EACI;EACA;EACH;EACA;EACA;EACS;EACN;EACD;EACD;EACD;EACE;EACR;EACN,EAhBK,KAAK,MAgBV,CACF;AAEF,QACE,oBAAC,KAAD;EACE,WAAU;EACV,KAAK;EACL,GAAI,UAAU,OAAO;EACrB,GAAI;EACJ,MAAK;EACL,wBAAsB,WAAW;EACjC,kBAAA;EACA,mBAAiB,aAAa,KAAA;YAE7B;EACG,CAAA;EAER;AAEF,KAAK,cAAc;AACnB,KAAK,UAAUA;AACf,KAAK,eAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tree.module.mjs","names":[],"sources":["../../../src/components/Tree/Tree.module.css"],"sourcesContent":[".root {\n --level-offset: var(--mantine-spacing-lg);\n margin: 0;\n padding: 0;\n user-select: none;\n}\n\n.subtree {\n margin: 0;\n padding: 0;\n}\n\n.node {\n cursor: pointer;\n list-style: none;\n margin: 0;\n padding: 0;\n outline: 0;\n\n &:focus-visible {\n > .label {\n outline: 2px solid var(--mantine-primary-color-filled);\n outline-offset: 2px;\n }\n }\n}\n\n.label {\n padding-inline-start: var(--label-offset);\n\n &:where([data-selected]) {\n @mixin where-light {\n background-color: var(--mantine-color-gray-1);\n }\n\n @mixin where-dark {\n background-color: var(--mantine-color-dark-5);\n }\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Tree.module.mjs","names":[],"sources":["../../../src/components/Tree/Tree.module.css"],"sourcesContent":[".root {\n --level-offset: var(--mantine-spacing-lg);\n --tree-line-width: rem(1px);\n --tree-line-color: var(--mantine-color-default-border);\n margin: 0;\n padding: 0;\n user-select: none;\n}\n\n.subtree {\n margin: 0;\n padding: 0;\n}\n\n.node {\n cursor: pointer;\n list-style: none;\n margin: 0;\n padding: 0;\n outline: 0;\n\n &:focus-visible {\n > .label {\n outline: 2px solid var(--mantine-primary-color-filled);\n outline-offset: 2px;\n }\n }\n}\n\n.label {\n position: relative;\n padding-inline-start: var(--label-offset);\n\n &:where([data-selected]) {\n @mixin where-light {\n background-color: var(--mantine-color-gray-1);\n }\n\n @mixin where-dark {\n background-color: var(--mantine-color-dark-5);\n }\n }\n\n &:where([data-dragging]) {\n opacity: 0.4;\n }\n\n &:where([data-drag-over='before'])::before {\n content: '';\n position: absolute;\n top: -1px;\n inset-inline-start: var(--label-offset, 0);\n inset-inline-end: 0;\n height: 2px;\n background-color: var(--mantine-primary-color-filled);\n pointer-events: none;\n z-index: 1;\n }\n\n &:where([data-drag-over='after'])::after {\n content: '';\n position: absolute;\n bottom: -1px;\n inset-inline-start: var(--label-offset, 0);\n inset-inline-end: 0;\n height: 2px;\n background-color: var(--mantine-primary-color-filled);\n pointer-events: none;\n z-index: 1;\n }\n\n &:where([data-drag-over='inside']) {\n background-color: var(--mantine-primary-color-light);\n }\n}\n\n:where([data-with-lines]) {\n .node {\n position: relative;\n }\n\n .subtree > .node {\n &::before {\n content: '';\n position: absolute;\n top: rem(12px);\n inset-inline-start: calc(var(--label-offset) - var(--level-offset) / 2);\n width: calc(var(--level-offset) / 2);\n height: 0;\n border-top: var(--tree-line-width) solid var(--tree-line-color);\n pointer-events: none;\n }\n\n &::after {\n content: '';\n position: absolute;\n top: 0;\n bottom: 0;\n inset-inline-start: calc(var(--label-offset) - var(--level-offset) / 2);\n width: 0;\n border-inline-start: var(--tree-line-width) solid var(--tree-line-color);\n pointer-events: none;\n }\n\n &:last-child::after {\n bottom: auto;\n height: rem(12px);\n }\n }\n}\n"],"mappings":""}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { findElementAncestor } from "../../core/utils/find-element-ancestor/find-element-ancestor.mjs";
|
|
3
3
|
import { Box } from "../../core/Box/Box.mjs";
|
|
4
|
+
import { Loader } from "../Loader/Loader.mjs";
|
|
5
|
+
import { useTreeNodeDragDrop } from "./use-tree-node-drag-drop.mjs";
|
|
4
6
|
import { Activity, useRef } from "react";
|
|
5
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
8
|
//#region packages/@mantine/core/src/components/Tree/TreeNode.tsx
|
|
@@ -12,8 +14,14 @@ function getValuesRange(anchor, value, flatValues) {
|
|
|
12
14
|
const end = Math.max(anchorIndex, valueIndex);
|
|
13
15
|
return flatValues.slice(start, end + 1);
|
|
14
16
|
}
|
|
15
|
-
function TreeNode({ node, getStyles, rootIndex, controller, expandOnClick, selectOnClick, isSubtree, level = 1, renderNode, flatValues, allowRangeSelection, expandOnSpace, checkOnSpace, keepMounted }) {
|
|
17
|
+
function TreeNode({ node, getStyles, rootIndex, controller, expandOnClick, selectOnClick, isSubtree, level = 1, renderNode, flatValues, allowRangeSelection, expandOnSpace, checkOnSpace, keepMounted, onDragDrop, dragStateRef, data }) {
|
|
16
18
|
const ref = useRef(null);
|
|
19
|
+
const hasLoadedChildren = Array.isArray(node.children);
|
|
20
|
+
const hasAsyncChildren = !!node.hasChildren && !hasLoadedChildren;
|
|
21
|
+
const hasChildren = hasLoadedChildren || hasAsyncChildren;
|
|
22
|
+
const isLoading = controller.isNodeLoading(node.value);
|
|
23
|
+
const loadError = controller.getNodeLoadError(node.value);
|
|
24
|
+
const isExpanded = controller.expandedState[node.value] || false;
|
|
17
25
|
const nested = (node.children || []).map((child) => /* @__PURE__ */ jsx(TreeNode, {
|
|
18
26
|
node: child,
|
|
19
27
|
flatValues,
|
|
@@ -28,19 +36,29 @@ function TreeNode({ node, getStyles, rootIndex, controller, expandOnClick, selec
|
|
|
28
36
|
allowRangeSelection,
|
|
29
37
|
expandOnSpace,
|
|
30
38
|
checkOnSpace,
|
|
31
|
-
keepMounted
|
|
39
|
+
keepMounted,
|
|
40
|
+
onDragDrop,
|
|
41
|
+
dragStateRef,
|
|
42
|
+
data
|
|
32
43
|
}, child.value));
|
|
44
|
+
const dragProps = useTreeNodeDragDrop({
|
|
45
|
+
nodeValue: node.value,
|
|
46
|
+
hasChildren,
|
|
47
|
+
data,
|
|
48
|
+
onDragDrop,
|
|
49
|
+
dragStateRef
|
|
50
|
+
});
|
|
33
51
|
const handleKeyDown = (event) => {
|
|
34
52
|
if (event.nativeEvent.code === "ArrowRight") {
|
|
35
53
|
event.stopPropagation();
|
|
36
54
|
event.preventDefault();
|
|
37
|
-
if (
|
|
55
|
+
if (isExpanded) event.currentTarget.querySelector("[role=treeitem]")?.focus();
|
|
38
56
|
else controller.expand(node.value);
|
|
39
57
|
}
|
|
40
58
|
if (event.nativeEvent.code === "ArrowLeft") {
|
|
41
59
|
event.stopPropagation();
|
|
42
60
|
event.preventDefault();
|
|
43
|
-
if (
|
|
61
|
+
if (isExpanded && hasChildren) controller.collapse(node.value);
|
|
44
62
|
else if (isSubtree) findElementAncestor(event.currentTarget, "[role=treeitem]")?.focus();
|
|
45
63
|
}
|
|
46
64
|
if (event.nativeEvent.code === "ArrowDown" || event.nativeEvent.code === "ArrowUp") {
|
|
@@ -77,7 +95,7 @@ function TreeNode({ node, getStyles, rootIndex, controller, expandOnClick, selec
|
|
|
77
95
|
controller.setSelectedState(getValuesRange(controller.anchorNode, node.value, flatValues));
|
|
78
96
|
ref.current?.focus();
|
|
79
97
|
} else {
|
|
80
|
-
expandOnClick
|
|
98
|
+
if (expandOnClick) controller.toggleExpanded(node.value);
|
|
81
99
|
selectOnClick && controller.select(node.value);
|
|
82
100
|
ref.current?.focus();
|
|
83
101
|
}
|
|
@@ -87,8 +105,10 @@ function TreeNode({ node, getStyles, rootIndex, controller, expandOnClick, selec
|
|
|
87
105
|
...getStyles("label"),
|
|
88
106
|
onClick: handleNodeClick,
|
|
89
107
|
"data-selected": selected || void 0,
|
|
90
|
-
"data-value": node.value
|
|
108
|
+
"data-value": node.value,
|
|
109
|
+
...dragProps
|
|
91
110
|
};
|
|
111
|
+
const withLoadingIndicator = isExpanded && isLoading && nested.length === 0;
|
|
92
112
|
return /* @__PURE__ */ jsxs("li", {
|
|
93
113
|
...getStyles("node", { style: { "--label-offset": `calc(var(--level-offset) * ${level - 1})` } }),
|
|
94
114
|
role: "treeitem",
|
|
@@ -99,33 +119,51 @@ function TreeNode({ node, getStyles, rootIndex, controller, expandOnClick, selec
|
|
|
99
119
|
tabIndex: rootIndex === 0 ? 0 : -1,
|
|
100
120
|
onKeyDown: handleKeyDown,
|
|
101
121
|
ref,
|
|
102
|
-
children: [
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
children: [
|
|
123
|
+
typeof renderNode === "function" ? renderNode({
|
|
124
|
+
node,
|
|
125
|
+
level,
|
|
126
|
+
selected,
|
|
127
|
+
tree: controller,
|
|
128
|
+
expanded: isExpanded,
|
|
129
|
+
hasChildren,
|
|
130
|
+
isLoading,
|
|
131
|
+
loadError,
|
|
132
|
+
elementProps
|
|
133
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
134
|
+
...elementProps,
|
|
135
|
+
children: node.label
|
|
136
|
+
}),
|
|
137
|
+
withLoadingIndicator && /* @__PURE__ */ jsx(Box, {
|
|
138
|
+
component: "ul",
|
|
139
|
+
role: "group",
|
|
140
|
+
...getStyles("subtree"),
|
|
141
|
+
"data-level": level,
|
|
142
|
+
children: /* @__PURE__ */ jsx("li", {
|
|
143
|
+
...getStyles("node", { style: { "--label-offset": `calc(var(--level-offset) * ${level})` } }),
|
|
144
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
145
|
+
...getStyles("label"),
|
|
146
|
+
children: /* @__PURE__ */ jsx(Loader, { size: 16 })
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
}),
|
|
150
|
+
keepMounted && nested.length > 0 ? /* @__PURE__ */ jsx(Activity, {
|
|
151
|
+
mode: isExpanded ? "visible" : "hidden",
|
|
152
|
+
children: /* @__PURE__ */ jsx(Box, {
|
|
153
|
+
component: "ul",
|
|
154
|
+
role: "group",
|
|
155
|
+
...getStyles("subtree"),
|
|
156
|
+
"data-level": level,
|
|
157
|
+
children: nested
|
|
158
|
+
})
|
|
159
|
+
}) : isExpanded && nested.length > 0 && /* @__PURE__ */ jsx(Box, {
|
|
116
160
|
component: "ul",
|
|
117
161
|
role: "group",
|
|
118
162
|
...getStyles("subtree"),
|
|
119
163
|
"data-level": level,
|
|
120
164
|
children: nested
|
|
121
165
|
})
|
|
122
|
-
|
|
123
|
-
component: "ul",
|
|
124
|
-
role: "group",
|
|
125
|
-
...getStyles("subtree"),
|
|
126
|
-
"data-level": level,
|
|
127
|
-
children: nested
|
|
128
|
-
})]
|
|
166
|
+
]
|
|
129
167
|
});
|
|
130
168
|
}
|
|
131
169
|
TreeNode.displayName = "@mantine/core/TreeNode";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeNode.mjs","names":[],"sources":["../../../src/components/Tree/TreeNode.tsx"],"sourcesContent":["import { Activity, useRef } from 'react';\nimport { Box, findElementAncestor, GetStylesApi } from '../../core';\nimport type { RenderNode, TreeFactory, TreeNodeData } from './Tree';\nimport type { TreeController } from './use-tree';\n\nfunction getValuesRange(anchor: string | null, value: string | undefined, flatValues: string[]) {\n if (!anchor || !value) {\n return [];\n }\n\n const anchorIndex = flatValues.indexOf(anchor);\n const valueIndex = flatValues.indexOf(value);\n const start = Math.min(anchorIndex, valueIndex);\n const end = Math.max(anchorIndex, valueIndex);\n\n return flatValues.slice(start, end + 1);\n}\n\ninterface TreeNodeProps {\n node: TreeNodeData;\n getStyles: GetStylesApi<TreeFactory>;\n rootIndex: number | undefined;\n controller: TreeController;\n expandOnClick: boolean | undefined;\n flatValues: string[];\n isSubtree?: boolean;\n level?: number;\n renderNode: RenderNode | undefined;\n selectOnClick: boolean | undefined;\n allowRangeSelection: boolean | undefined;\n expandOnSpace: boolean | undefined;\n checkOnSpace: boolean | undefined;\n keepMounted: boolean | undefined;\n}\n\nexport function TreeNode({\n node,\n getStyles,\n rootIndex,\n controller,\n expandOnClick,\n selectOnClick,\n isSubtree,\n level = 1,\n renderNode,\n flatValues,\n allowRangeSelection,\n expandOnSpace,\n checkOnSpace,\n keepMounted,\n}: TreeNodeProps) {\n const ref = useRef<HTMLLIElement>(null);\n const nested = (node.children || []).map((child) => (\n <TreeNode\n key={child.value}\n node={child}\n flatValues={flatValues}\n getStyles={getStyles}\n rootIndex={undefined}\n level={level + 1}\n controller={controller}\n expandOnClick={expandOnClick}\n isSubtree\n renderNode={renderNode}\n selectOnClick={selectOnClick}\n allowRangeSelection={allowRangeSelection}\n expandOnSpace={expandOnSpace}\n checkOnSpace={checkOnSpace}\n keepMounted={keepMounted}\n />\n ));\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.nativeEvent.code === 'ArrowRight') {\n event.stopPropagation();\n event.preventDefault();\n\n if (controller.expandedState[node.value]) {\n event.currentTarget.querySelector<HTMLLIElement>('[role=treeitem]')?.focus();\n } else {\n controller.expand(node.value);\n }\n }\n\n if (event.nativeEvent.code === 'ArrowLeft') {\n event.stopPropagation();\n event.preventDefault();\n if (controller.expandedState[node.value] && (node.children || []).length > 0) {\n controller.collapse(node.value);\n } else if (isSubtree) {\n findElementAncestor(event.currentTarget as HTMLElement, '[role=treeitem]')?.focus();\n }\n }\n\n if (event.nativeEvent.code === 'ArrowDown' || event.nativeEvent.code === 'ArrowUp') {\n const root = findElementAncestor(event.currentTarget as HTMLElement, '[data-tree-root]');\n\n if (!root) {\n return;\n }\n\n event.stopPropagation();\n event.preventDefault();\n const nodes = Array.from(root.querySelectorAll<HTMLLIElement>('[role=treeitem]')).filter(\n (treeNode) => treeNode.style.display !== 'none'\n );\n const index = nodes.indexOf(event.currentTarget as HTMLLIElement);\n\n if (index === -1) {\n return;\n }\n\n const nextIndex = event.nativeEvent.code === 'ArrowDown' ? index + 1 : index - 1;\n nodes[nextIndex]?.focus();\n\n if (event.shiftKey) {\n const selectNode = nodes[nextIndex];\n\n if (selectNode) {\n controller.setSelectedState(\n getValuesRange(controller.anchorNode, selectNode.dataset.value, flatValues)\n );\n }\n }\n }\n\n if (event.nativeEvent.code === 'Space') {\n if (expandOnSpace) {\n event.stopPropagation();\n event.preventDefault();\n controller.toggleExpanded(node.value);\n }\n\n if (checkOnSpace) {\n event.stopPropagation();\n event.preventDefault();\n controller.isNodeChecked(node.value)\n ? controller.uncheckNode(node.value)\n : controller.checkNode(node.value);\n }\n }\n };\n\n const handleNodeClick = (event: React.MouseEvent) => {\n event.stopPropagation();\n\n if (allowRangeSelection && event.shiftKey && controller.anchorNode) {\n controller.setSelectedState(getValuesRange(controller.anchorNode, node.value, flatValues));\n ref.current?.focus();\n } else {\n expandOnClick && controller.toggleExpanded(node.value);\n selectOnClick && controller.select(node.value);\n ref.current?.focus();\n }\n };\n\n const selected = controller.selectedState.includes(node.value);\n const elementProps = {\n ...getStyles('label'),\n onClick: handleNodeClick,\n 'data-selected': selected || undefined,\n 'data-value': node.value,\n };\n\n return (\n <li\n {...getStyles('node', {\n style: { '--label-offset': `calc(var(--level-offset) * ${level - 1})` },\n })}\n role=\"treeitem\"\n aria-selected={selected}\n data-value={node.value}\n data-selected={selected || undefined}\n data-level={level}\n tabIndex={rootIndex === 0 ? 0 : -1}\n onKeyDown={handleKeyDown}\n ref={ref}\n >\n {typeof renderNode === 'function' ? (\n renderNode({\n node,\n level,\n selected,\n tree: controller,\n expanded: controller.expandedState[node.value] || false,\n hasChildren: Array.isArray(node.children) && node.children.length > 0,\n elementProps,\n })\n ) : (\n <div {...elementProps}>{node.label}</div>\n )}\n\n {keepMounted && nested.length > 0 ? (\n <Activity mode={controller.expandedState[node.value] ? 'visible' : 'hidden'}>\n <Box component=\"ul\" role=\"group\" {...getStyles('subtree')} data-level={level}>\n {nested}\n </Box>\n </Activity>\n ) : (\n controller.expandedState[node.value] &&\n nested.length > 0 && (\n <Box component=\"ul\" role=\"group\" {...getStyles('subtree')} data-level={level}>\n {nested}\n </Box>\n )\n )}\n </li>\n );\n}\n\nTreeNode.displayName = '@mantine/core/TreeNode';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TreeNode.mjs","names":[],"sources":["../../../src/components/Tree/TreeNode.tsx"],"sourcesContent":["import { Activity, useRef } from 'react';\nimport { Box, findElementAncestor, GetStylesApi } from '../../core';\nimport { Loader } from '../Loader';\nimport type { TreeDragDropPayload } from './move-tree-node/move-tree-node';\nimport type { RenderNode, TreeDragState, TreeFactory, TreeNodeData } from './Tree';\nimport type { TreeController } from './use-tree';\nimport { useTreeNodeDragDrop } from './use-tree-node-drag-drop';\n\nfunction getValuesRange(anchor: string | null, value: string | undefined, flatValues: string[]) {\n if (!anchor || !value) {\n return [];\n }\n\n const anchorIndex = flatValues.indexOf(anchor);\n const valueIndex = flatValues.indexOf(value);\n const start = Math.min(anchorIndex, valueIndex);\n const end = Math.max(anchorIndex, valueIndex);\n\n return flatValues.slice(start, end + 1);\n}\n\ninterface TreeNodeProps {\n node: TreeNodeData;\n getStyles: GetStylesApi<TreeFactory>;\n rootIndex: number | undefined;\n controller: TreeController;\n expandOnClick: boolean | undefined;\n flatValues: string[];\n isSubtree?: boolean;\n level?: number;\n renderNode: RenderNode | undefined;\n selectOnClick: boolean | undefined;\n allowRangeSelection: boolean | undefined;\n expandOnSpace: boolean | undefined;\n checkOnSpace: boolean | undefined;\n keepMounted: boolean | undefined;\n onDragDrop: ((payload: TreeDragDropPayload) => void) | undefined;\n dragStateRef: React.RefObject<TreeDragState>;\n data: TreeNodeData[];\n}\n\nexport function TreeNode({\n node,\n getStyles,\n rootIndex,\n controller,\n expandOnClick,\n selectOnClick,\n isSubtree,\n level = 1,\n renderNode,\n flatValues,\n allowRangeSelection,\n expandOnSpace,\n checkOnSpace,\n keepMounted,\n onDragDrop,\n dragStateRef,\n data,\n}: TreeNodeProps) {\n const ref = useRef<HTMLLIElement>(null);\n const hasLoadedChildren = Array.isArray(node.children);\n const hasAsyncChildren = !!node.hasChildren && !hasLoadedChildren;\n const hasChildren = hasLoadedChildren || hasAsyncChildren;\n const isLoading = controller.isNodeLoading(node.value);\n const loadError = controller.getNodeLoadError(node.value);\n const isExpanded = controller.expandedState[node.value] || false;\n\n const nested = (node.children || []).map((child) => (\n <TreeNode\n key={child.value}\n node={child}\n flatValues={flatValues}\n getStyles={getStyles}\n rootIndex={undefined}\n level={level + 1}\n controller={controller}\n expandOnClick={expandOnClick}\n isSubtree\n renderNode={renderNode}\n selectOnClick={selectOnClick}\n allowRangeSelection={allowRangeSelection}\n expandOnSpace={expandOnSpace}\n checkOnSpace={checkOnSpace}\n keepMounted={keepMounted}\n onDragDrop={onDragDrop}\n dragStateRef={dragStateRef}\n data={data}\n />\n ));\n\n const dragProps = useTreeNodeDragDrop({\n nodeValue: node.value,\n hasChildren,\n data,\n onDragDrop,\n dragStateRef,\n });\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.nativeEvent.code === 'ArrowRight') {\n event.stopPropagation();\n event.preventDefault();\n\n if (isExpanded) {\n event.currentTarget.querySelector<HTMLLIElement>('[role=treeitem]')?.focus();\n } else {\n controller.expand(node.value);\n }\n }\n\n if (event.nativeEvent.code === 'ArrowLeft') {\n event.stopPropagation();\n event.preventDefault();\n if (isExpanded && hasChildren) {\n controller.collapse(node.value);\n } else if (isSubtree) {\n findElementAncestor(event.currentTarget as HTMLElement, '[role=treeitem]')?.focus();\n }\n }\n\n if (event.nativeEvent.code === 'ArrowDown' || event.nativeEvent.code === 'ArrowUp') {\n const root = findElementAncestor(event.currentTarget as HTMLElement, '[data-tree-root]');\n\n if (!root) {\n return;\n }\n\n event.stopPropagation();\n event.preventDefault();\n const nodes = Array.from(root.querySelectorAll<HTMLLIElement>('[role=treeitem]')).filter(\n (treeNode) => treeNode.style.display !== 'none'\n );\n const index = nodes.indexOf(event.currentTarget as HTMLLIElement);\n\n if (index === -1) {\n return;\n }\n\n const nextIndex = event.nativeEvent.code === 'ArrowDown' ? index + 1 : index - 1;\n nodes[nextIndex]?.focus();\n\n if (event.shiftKey) {\n const selectNode = nodes[nextIndex];\n\n if (selectNode) {\n controller.setSelectedState(\n getValuesRange(controller.anchorNode, selectNode.dataset.value, flatValues)\n );\n }\n }\n }\n\n if (event.nativeEvent.code === 'Space') {\n if (expandOnSpace) {\n event.stopPropagation();\n event.preventDefault();\n controller.toggleExpanded(node.value);\n }\n\n if (checkOnSpace) {\n event.stopPropagation();\n event.preventDefault();\n controller.isNodeChecked(node.value)\n ? controller.uncheckNode(node.value)\n : controller.checkNode(node.value);\n }\n }\n };\n\n const handleNodeClick = (event: React.MouseEvent) => {\n event.stopPropagation();\n\n if (allowRangeSelection && event.shiftKey && controller.anchorNode) {\n controller.setSelectedState(getValuesRange(controller.anchorNode, node.value, flatValues));\n ref.current?.focus();\n } else {\n if (expandOnClick) {\n controller.toggleExpanded(node.value);\n }\n\n selectOnClick && controller.select(node.value);\n ref.current?.focus();\n }\n };\n\n const selected = controller.selectedState.includes(node.value);\n const elementProps = {\n ...getStyles('label'),\n onClick: handleNodeClick,\n 'data-selected': selected || undefined,\n 'data-value': node.value,\n ...dragProps,\n };\n\n const withLoadingIndicator = isExpanded && isLoading && nested.length === 0;\n\n return (\n <li\n {...getStyles('node', {\n style: { '--label-offset': `calc(var(--level-offset) * ${level - 1})` },\n })}\n role=\"treeitem\"\n aria-selected={selected}\n data-value={node.value}\n data-selected={selected || undefined}\n data-level={level}\n tabIndex={rootIndex === 0 ? 0 : -1}\n onKeyDown={handleKeyDown}\n ref={ref}\n >\n {typeof renderNode === 'function' ? (\n renderNode({\n node,\n level,\n selected,\n tree: controller,\n expanded: isExpanded,\n hasChildren,\n isLoading,\n loadError,\n elementProps,\n })\n ) : (\n <div {...elementProps}>{node.label}</div>\n )}\n\n {withLoadingIndicator && (\n <Box component=\"ul\" role=\"group\" {...getStyles('subtree')} data-level={level}>\n <li\n {...getStyles('node', {\n style: { '--label-offset': `calc(var(--level-offset) * ${level})` },\n })}\n >\n <div {...getStyles('label')}>\n <Loader size={16} />\n </div>\n </li>\n </Box>\n )}\n\n {keepMounted && nested.length > 0 ? (\n <Activity mode={isExpanded ? 'visible' : 'hidden'}>\n <Box component=\"ul\" role=\"group\" {...getStyles('subtree')} data-level={level}>\n {nested}\n </Box>\n </Activity>\n ) : (\n isExpanded &&\n nested.length > 0 && (\n <Box component=\"ul\" role=\"group\" {...getStyles('subtree')} data-level={level}>\n {nested}\n </Box>\n )\n )}\n </li>\n );\n}\n\nTreeNode.displayName = '@mantine/core/TreeNode';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
//#region packages/@mantine/core/src/components/Tree/filter-tree-data/filter-tree-data.ts
|
|
3
|
+
function defaultTreeNodeFilter(query, node) {
|
|
4
|
+
return (typeof node.label === "string" ? node.label : node.value).toLowerCase().includes(query.toLowerCase().trim());
|
|
5
|
+
}
|
|
6
|
+
function filterTreeData(data, query, filter = defaultTreeNodeFilter) {
|
|
7
|
+
if (!query.trim()) return data;
|
|
8
|
+
const result = [];
|
|
9
|
+
for (const node of data) {
|
|
10
|
+
const nodeMatches = filter(query, node);
|
|
11
|
+
const filteredChildren = Array.isArray(node.children) && node.children.length > 0 ? filterTreeData(node.children, query, filter) : [];
|
|
12
|
+
if (nodeMatches || filteredChildren.length > 0) result.push(filteredChildren.length > 0 ? {
|
|
13
|
+
...node,
|
|
14
|
+
children: filteredChildren
|
|
15
|
+
} : { ...node });
|
|
16
|
+
}
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { defaultTreeNodeFilter, filterTreeData };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=filter-tree-data.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-tree-data.mjs","names":[],"sources":["../../../../src/components/Tree/filter-tree-data/filter-tree-data.ts"],"sourcesContent":["import type { TreeNodeData } from '../Tree';\n\nexport type TreeNodeFilter = (query: string, node: TreeNodeData) => boolean;\n\nexport function defaultTreeNodeFilter(query: string, node: TreeNodeData): boolean {\n const label = typeof node.label === 'string' ? node.label : node.value;\n return label.toLowerCase().includes(query.toLowerCase().trim());\n}\n\nexport function filterTreeData(\n data: TreeNodeData[],\n query: string,\n filter: TreeNodeFilter = defaultTreeNodeFilter\n): TreeNodeData[] {\n if (!query.trim()) {\n return data;\n }\n\n const result: TreeNodeData[] = [];\n\n for (const node of data) {\n const nodeMatches = filter(query, node);\n const filteredChildren =\n Array.isArray(node.children) && node.children.length > 0\n ? filterTreeData(node.children, query, filter)\n : [];\n\n if (nodeMatches || filteredChildren.length > 0) {\n result.push(\n filteredChildren.length > 0 ? { ...node, children: filteredChildren } : { ...node }\n );\n }\n }\n\n return result;\n}\n"],"mappings":";;AAIA,SAAgB,sBAAsB,OAAe,MAA6B;AAEhF,SADc,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAK,OACpD,aAAa,CAAC,SAAS,MAAM,aAAa,CAAC,MAAM,CAAC;;AAGjE,SAAgB,eACd,MACA,OACA,SAAyB,uBACT;AAChB,KAAI,CAAC,MAAM,MAAM,CACf,QAAO;CAGT,MAAM,SAAyB,EAAE;AAEjC,MAAK,MAAM,QAAQ,MAAM;EACvB,MAAM,cAAc,OAAO,OAAO,KAAK;EACvC,MAAM,mBACJ,MAAM,QAAQ,KAAK,SAAS,IAAI,KAAK,SAAS,SAAS,IACnD,eAAe,KAAK,UAAU,OAAO,OAAO,GAC5C,EAAE;AAER,MAAI,eAAe,iBAAiB,SAAS,EAC3C,QAAO,KACL,iBAAiB,SAAS,IAAI;GAAE,GAAG;GAAM,UAAU;GAAkB,GAAG,EAAE,GAAG,MAAM,CACpF;;AAIL,QAAO"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
//#region packages/@mantine/core/src/components/Tree/flatten-tree-data/flatten-tree-data.ts
|
|
3
|
+
function flattenTreeDataTo(acc, data, expandedState, parent, level) {
|
|
4
|
+
for (let i = 0; i < data.length; i++) {
|
|
5
|
+
const node = data[i];
|
|
6
|
+
const hasLoadedChildren = Array.isArray(node.children);
|
|
7
|
+
const hasAsyncChildren = !!node.hasChildren && !hasLoadedChildren;
|
|
8
|
+
const hasChildren = hasLoadedChildren || hasAsyncChildren;
|
|
9
|
+
const expanded = expandedState[node.value] || false;
|
|
10
|
+
acc.push({
|
|
11
|
+
node,
|
|
12
|
+
level,
|
|
13
|
+
parent,
|
|
14
|
+
hasChildren,
|
|
15
|
+
expanded
|
|
16
|
+
});
|
|
17
|
+
if (expanded && hasLoadedChildren) flattenTreeDataTo(acc, node.children, expandedState, node.value, level + 1);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function flattenTreeData(data, expandedState) {
|
|
21
|
+
const result = [];
|
|
22
|
+
flattenTreeDataTo(result, data, expandedState, null, 1);
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { flattenTreeData };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=flatten-tree-data.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flatten-tree-data.mjs","names":[],"sources":["../../../../src/components/Tree/flatten-tree-data/flatten-tree-data.ts"],"sourcesContent":["import type { TreeNodeData } from '../Tree';\nimport type { TreeExpandedState } from '../use-tree';\n\nexport interface FlattenedTreeNodeData {\n /** Node data from tree data */\n node: TreeNodeData;\n\n /** Nesting level of the node, starts at 1 */\n level: number;\n\n /** Value of the parent node, `null` for root nodes */\n parent: string | null;\n\n /** Whether the node has children */\n hasChildren: boolean;\n\n /** Whether the node is expanded */\n expanded: boolean;\n}\n\nfunction flattenTreeDataTo(\n acc: FlattenedTreeNodeData[],\n data: TreeNodeData[],\n expandedState: TreeExpandedState,\n parent: string | null,\n level: number\n): void {\n for (let i = 0; i < data.length; i++) {\n const node = data[i];\n const hasLoadedChildren = Array.isArray(node.children);\n const hasAsyncChildren = !!node.hasChildren && !hasLoadedChildren;\n const hasChildren = hasLoadedChildren || hasAsyncChildren;\n const expanded = expandedState[node.value] || false;\n\n acc.push({ node, level, parent, hasChildren, expanded });\n\n if (expanded && hasLoadedChildren) {\n flattenTreeDataTo(acc, node.children!, expandedState, node.value, level + 1);\n }\n }\n}\n\nexport function flattenTreeData(\n data: TreeNodeData[],\n expandedState: TreeExpandedState\n): FlattenedTreeNodeData[] {\n const result: FlattenedTreeNodeData[] = [];\n flattenTreeDataTo(result, data, expandedState, null, 1);\n return result;\n}\n"],"mappings":";;AAoBA,SAAS,kBACP,KACA,MACA,eACA,QACA,OACM;AACN,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,OAAO,KAAK;EAClB,MAAM,oBAAoB,MAAM,QAAQ,KAAK,SAAS;EACtD,MAAM,mBAAmB,CAAC,CAAC,KAAK,eAAe,CAAC;EAChD,MAAM,cAAc,qBAAqB;EACzC,MAAM,WAAW,cAAc,KAAK,UAAU;AAE9C,MAAI,KAAK;GAAE;GAAM;GAAO;GAAQ;GAAa;GAAU,CAAC;AAExD,MAAI,YAAY,kBACd,mBAAkB,KAAK,KAAK,UAAW,eAAe,KAAK,OAAO,QAAQ,EAAE;;;AAKlF,SAAgB,gBACd,MACA,eACyB;CACzB,MAAM,SAAkC,EAAE;AAC1C,mBAAkB,QAAQ,MAAM,eAAe,MAAM,EAAE;AACvD,QAAO"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
//#region packages/@mantine/core/src/components/Tree/merge-async-children/merge-async-children.ts
|
|
3
|
+
function mergeAsyncChildren(data, parentValue, children) {
|
|
4
|
+
let changed = false;
|
|
5
|
+
const result = data.map((node) => {
|
|
6
|
+
if (node.value === parentValue) {
|
|
7
|
+
changed = true;
|
|
8
|
+
const merged = {
|
|
9
|
+
...node,
|
|
10
|
+
children
|
|
11
|
+
};
|
|
12
|
+
delete merged.hasChildren;
|
|
13
|
+
return merged;
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(node.children)) {
|
|
16
|
+
const updatedChildren = mergeAsyncChildren(node.children, parentValue, children);
|
|
17
|
+
if (updatedChildren !== node.children) {
|
|
18
|
+
changed = true;
|
|
19
|
+
return {
|
|
20
|
+
...node,
|
|
21
|
+
children: updatedChildren
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return node;
|
|
26
|
+
});
|
|
27
|
+
return changed ? result : data;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { mergeAsyncChildren };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=merge-async-children.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-async-children.mjs","names":[],"sources":["../../../../src/components/Tree/merge-async-children/merge-async-children.ts"],"sourcesContent":["import type { TreeNodeData } from '../Tree';\n\nexport function mergeAsyncChildren(\n data: TreeNodeData[],\n parentValue: string,\n children: TreeNodeData[]\n): TreeNodeData[] {\n let changed = false;\n\n const result = data.map((node) => {\n if (node.value === parentValue) {\n changed = true;\n const merged: TreeNodeData = { ...node, children };\n delete merged.hasChildren;\n return merged;\n }\n\n if (Array.isArray(node.children)) {\n const updatedChildren = mergeAsyncChildren(node.children, parentValue, children);\n if (updatedChildren !== node.children) {\n changed = true;\n return { ...node, children: updatedChildren };\n }\n }\n\n return node;\n });\n\n return changed ? result : data;\n}\n"],"mappings":";;AAEA,SAAgB,mBACd,MACA,aACA,UACgB;CAChB,IAAI,UAAU;CAEd,MAAM,SAAS,KAAK,KAAK,SAAS;AAChC,MAAI,KAAK,UAAU,aAAa;AAC9B,aAAU;GACV,MAAM,SAAuB;IAAE,GAAG;IAAM;IAAU;AAClD,UAAO,OAAO;AACd,UAAO;;AAGT,MAAI,MAAM,QAAQ,KAAK,SAAS,EAAE;GAChC,MAAM,kBAAkB,mBAAmB,KAAK,UAAU,aAAa,SAAS;AAChF,OAAI,oBAAoB,KAAK,UAAU;AACrC,cAAU;AACV,WAAO;KAAE,GAAG;KAAM,UAAU;KAAiB;;;AAIjD,SAAO;GACP;AAEF,QAAO,UAAU,SAAS"}
|