|
1 |
| -<script lang="ts"> |
| 1 | +<script lang="ts" module> |
2 | 2 | import type { FileTreeNode, FolderNode } from "$lib/tree.svelte.js";
|
| 3 | + import { DEV } from "esm-env"; |
| 4 | + import { getContext, hasContext, setContext } from "svelte"; |
3 | 5 | import TreeItemProvider from "./TreeItemProvider.svelte";
|
4 |
| - import { TreeContext } from "./context.js"; |
5 |
| - import { createTreeState } from "./state.svelte.js"; |
6 |
| - import type { TreeItemSnippetProps, TreeProps } from "./types.js"; |
| 6 | + import { TreeContext } from "./state.svelte.js"; |
| 7 | + import type { TreeItemProviderContext, TreeProps } from "./types.js"; |
| 8 | +
|
| 9 | + const CONTEXT_KEY = Symbol("Tree"); |
| 10 | +
|
| 11 | + export function getTreeContext(): TreeContext { |
| 12 | + if (DEV && !hasContext(CONTEXT_KEY)) { |
| 13 | + throw new Error("No parent <Tree> found"); |
| 14 | + } |
| 15 | + return getContext(CONTEXT_KEY); |
| 16 | + } |
| 17 | +</script> |
7 | 18 |
|
| 19 | +<script lang="ts"> |
| 20 | + const defaultId = $props.id(); |
8 | 21 | let {
|
9 | 22 | tree,
|
10 | 23 | item,
|
11 | 24 | pasteOperation = $bindable(),
|
12 |
| - id = crypto.randomUUID(), |
| 25 | + id = defaultId, |
13 | 26 | element = $bindable(null),
|
14 | 27 | generateCopyId = () => crypto.randomUUID(),
|
15 |
| - onRenameItem = ({ target, name }) => { |
16 |
| - target.name = name; |
| 28 | + onRenameItem = (args) => { |
| 29 | + args.target.name = args.name; |
17 | 30 | return true;
|
18 | 31 | },
|
19 | 32 | onRenameError,
|
20 |
| - onMoveItems = ({ updates }) => { |
21 |
| - for (const { target, children } of updates) { |
| 33 | + onMoveItems = (args) => { |
| 34 | + for (const { target, children } of args.updates) { |
22 | 35 | target.children = children;
|
23 | 36 | }
|
24 | 37 | return true;
|
25 | 38 | },
|
26 | 39 | onMoveError,
|
27 |
| - onInsertItems = ({ target, start, inserted }) => { |
28 |
| - target.children.splice(start, 0, ...inserted); |
| 40 | + onInsertItems = (args) => { |
| 41 | + args.target.children.splice(args.start, 0, ...args.inserted); |
29 | 42 | return true;
|
30 | 43 | },
|
31 | 44 | onNameConflict = () => "cancel",
|
32 |
| - onDeleteItems = ({ updates }) => { |
33 |
| - for (const { target, children } of updates) { |
| 45 | + onDeleteItems = (args) => { |
| 46 | + for (const { target, children } of args.updates) { |
34 | 47 | target.children = children;
|
35 | 48 | }
|
36 | 49 | return true;
|
37 | 50 | },
|
38 |
| - ...attributes |
| 51 | + ...rest |
39 | 52 | }: TreeProps = $props();
|
40 | 53 |
|
41 |
| - const treeState = createTreeState({ |
| 54 | + const treeContext = new TreeContext({ |
42 | 55 | tree: () => tree,
|
43 | 56 | pasteOperation: () => pasteOperation,
|
44 | 57 | setPasteOperation: (value) => {
|
45 | 58 | pasteOperation = value;
|
46 | 59 | },
|
47 |
| - treeId: () => id, |
| 60 | + id: () => id, |
48 | 61 | generateCopyId: () => generateCopyId(),
|
49 |
| - onRenameItem: (event) => onRenameItem(event), |
50 |
| - onRenameError: (event) => onRenameError?.(event), |
51 |
| - onMoveItems: (event) => onMoveItems(event), |
52 |
| - onMoveError: (event) => onMoveError?.(event), |
53 |
| - onInsertItems: (event) => onInsertItems(event), |
54 |
| - onNameConflict: (event) => onNameConflict(event), |
55 |
| - onDeleteItems: (event) => onDeleteItems(event), |
| 62 | + onRenameItem: (args) => onRenameItem(args), |
| 63 | + onRenameError: (args) => onRenameError?.(args), |
| 64 | + onMoveItems: (args) => onMoveItems(args), |
| 65 | + onMoveError: (args) => onMoveError?.(args), |
| 66 | + onInsertItems: (args) => onInsertItems(args), |
| 67 | + onNameConflict: (args) => onNameConflict(args), |
| 68 | + onDeleteItems: (args) => onDeleteItems(args), |
56 | 69 | });
|
57 |
| -
|
58 |
| - TreeContext.set({ treeState }); |
| 70 | + setContext(CONTEXT_KEY, treeContext); |
59 | 71 | </script>
|
60 | 72 |
|
61 | 73 | {#snippet items(
|
62 | 74 | nodes: Array<FileTreeNode> = tree.children,
|
63 |
| - depth: number = 0, |
64 |
| - parent?: TreeItemSnippetProps<FolderNode>, |
| 75 | + parent?: TreeItemProviderContext<FolderNode>, |
65 | 76 | )}
|
66 | 77 | {#each nodes as node, index (node.id)}
|
67 |
| - {@const props = { node, index, depth, parent }} |
68 |
| - <TreeItemProvider {node} {index} {depth} {parent}> |
69 |
| - {@render item(props)} |
70 |
| - </TreeItemProvider> |
| 78 | + <TreeItemProvider {node} {index} {parent}> |
| 79 | + {#snippet children(context)} |
| 80 | + {@render item(context)} |
71 | 81 |
|
72 |
| - {#if node.type === "folder" && node.expanded} |
73 |
| - {@render items(node.children, depth + 1, props as TreeItemSnippetProps<FolderNode>)} |
74 |
| - {/if} |
| 82 | + {#if node.type === "folder" && node.expanded} |
| 83 | + {@render items(node.children, context as TreeItemProviderContext<FolderNode>)} |
| 84 | + {/if} |
| 85 | + {/snippet} |
| 86 | + </TreeItemProvider> |
75 | 87 | {/each}
|
76 | 88 | {/snippet}
|
77 | 89 |
|
78 |
| -<div bind:this={element} {...attributes} {id} role="tree" aria-multiselectable="true"> |
| 90 | +<div bind:this={element} {...rest} {id} role="tree" aria-multiselectable="true"> |
79 | 91 | {@render items()}
|
80 | 92 | </div>
|
0 commit comments