Skip to content

Commit 8c83e47

Browse files
authored
feat!: replace components by scoped slots for customization
BREAKING CHANGE: custom components have been replaced by scoped slots
2 parents 993f093 + 1cc52e9 commit 8c83e47

20 files changed

+457
-524
lines changed

.eslintrc.js

-8
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,7 @@ module.exports = {
55
root: true,
66
parserOptions: {
77
parser: "@babel/eslint-parser",
8-
babelOptions: {
9-
parserOpts: {
10-
plugins: ["jsx"],
11-
},
12-
},
138
ecmaVersion: 2017,
14-
ecmaFeatures: {
15-
jsx: true,
16-
},
179
sourceType: "module",
1810
},
1911
plugins: ["html", "vue"],

.storybook/main.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const path = require("path");
2-
const { loadConfigFromFile, mergeConfig } = require("vite");
3-
const vueJsx = require("@vitejs/plugin-vue-jsx");
2+
const { loadConfigFromFile } = require("vite");
43

54
module.exports = {
65
stories: [
@@ -32,7 +31,7 @@ module.exports = {
3231
"@": path.resolve("src"),
3332
},
3433
},
35-
plugins: [...config.plugins, vueJsx()],
34+
plugins: [...config.plugins],
3635
};
3736
},
3837

babel.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module.exports = {
1212
},
1313
],
1414
],
15-
plugins: ["transform-es2015-modules-commonjs", "@vue/babel-plugin-jsx"],
15+
plugins: ["transform-es2015-modules-commonjs"],
1616
},
1717
},
1818
};

docgen.config.js

-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ module.exports = {
77
componentsRoot: "src/components",
88
//getDestFile: (file: string, config: DocgenCLIConfig) => path.join(config.outDir, file).replace(/\.vue$/ ".doc.md"),
99
components: "**/Finder.vue", // the glob to define what files should be documented as components (relative to componentRoot)
10-
apiOptions: {
11-
jsx: true, // tell vue-docgen-api that your components are using JSX to avoid conflicts with TypeScript <type> syntax
12-
},
1310
getDestFile: (file, config) => path.join(config.outDir, "api.md"),
1411
templates: {
1512
component: (renderedUsage, doc) =>

docs/.vuepress/components/FinderExample.vue

+12-31
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
<template>
2-
<Finder
3-
:tree="tree"
4-
:item-component="itemComponent"
5-
:arrow-component="arrowComponent"
6-
v-bind="$props"
7-
/>
2+
<Finder :tree="tree" v-bind="$props">
3+
<template v-if="useCustomItemSlot" #item="{ item }">
4+
<div style="color: blue">
5+
<em>Name:</em> <strong>{{ item.label }}</strong>
6+
</div>
7+
</template>
8+
<template v-if="useCustomArrowSlot" #arrow="{ expanded }">
9+
<div>{{ expanded ? "↪" : "→" }}</div>
10+
</template>
11+
</Finder>
812
</template>
913
<script>
1014
import { Finder } from "../../../dist/vue-finder.es.js";
@@ -19,8 +23,8 @@ export default {
1923
"filter",
2024
"dragEnabled",
2125
"hasDragHandle",
22-
"useCustomItemComponent",
23-
"useCustomArrowComponent",
26+
"useCustomItemSlot",
27+
"useCustomArrowSlot",
2428
"defaultExpanded",
2529
],
2630
data() {
@@ -95,29 +99,6 @@ export default {
9599
},
96100
};
97101
},
98-
computed: {
99-
itemComponent() {
100-
if (this.useCustomItemComponent) {
101-
return {
102-
props: ["item"],
103-
template:
104-
'<div style="color: blue"><em>Name:</em> <strong>{{ item.label }}</strong></div>',
105-
};
106-
} else {
107-
return undefined;
108-
}
109-
},
110-
arrowComponent() {
111-
if (this.useCustomArrowComponent) {
112-
return {
113-
props: ["expanded"],
114-
template: "<div>{{ expanded ? '↪' : '→' }}</div>",
115-
};
116-
} else {
117-
return undefined;
118-
}
119-
},
120-
},
121102
};
122103
</script>
123104

docs/customization.md

+24-55
Original file line numberDiff line numberDiff line change
@@ -71,75 +71,44 @@ Here are the available properties:
7171
| `dropZoneBgColor` | Background color of drop zones (visible when Drag & Drop) |
7272
| `draggedItemBgColor` | Background color of dragged items (visible when Drag & Drop) |
7373

74-
## Custom components
74+
## Custom slots
7575

76-
You can pass your own components in order to customize some parts of the UI.
76+
You can pass scoped slots in order to customize some parts of the UI.
7777

78-
### Item component
78+
### Item
7979

80-
You can define a component to render items with the `itemComponent` prop. This component requires a `item` prop, that will
81-
receive the data of the rendered item.
80+
You can use the `item` scoped slot to render items. This slot accepts the following props:
8281

83-
```html
84-
<Finder :tree="tree" :item-component="itemComponent" />
85-
```
86-
87-
```js
88-
// ...
89-
data() {
90-
return {
91-
itemComponent: {
92-
props: ["item"],
93-
template:
94-
"<div style="color: blue"><em>Name:</em> <strong>{{ item.label }}</strong></div>"
95-
}
96-
}
97-
}
98-
```
99-
100-
<FinderExample :use-custom-item-component="true"/>
101-
102-
::: warning
103-
104-
The example above uses the `template` option to define the rendering of the component, so
105-
the [runtime compiler](https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only) is needed.
106-
107-
You can also use a `render` function (in this case the runtime-only build is enough):
82+
- `item`: the data of the item
83+
- `expanded`: the expanded state of the item
84+
- `dragged`: whether the item is currently dragged
10885

109-
```js
110-
itemComponent: {
111-
props: ["item"],
112-
render(h) {
113-
return h("div", this.item)
114-
}
115-
}
86+
```html
87+
<Finder :tree="tree">
88+
<template #item="{ item }">
89+
<div style="color: blue">
90+
<em>Name:</em> <strong>{{ item.label }}</strong>
91+
</div>
92+
</template>
93+
</Finder>
11694
```
11795

118-
:::
96+
<FinderExample :use-custom-item-slot="true"/>
11997

120-
### Arrow component
98+
### Arrow
12199

122-
You can define a component to render arrows with the `arrowComponent` prop. This component accepts the following props:
100+
You can use the `arrow` scoped slot to render custom arrows. This slot accepts the following props:
123101

124102
- `expanded`: the expanded state of the item
125103
- `item`: the data of the item
126104
- `theme`: the theme applied on the `Finder`
127105

128106
```html
129-
<Finder :tree="tree" :arrow-component="arrowComponent" />
130-
```
131-
132-
```js
133-
// ...
134-
data() {
135-
return {
136-
arrowComponent: {
137-
props: ["expanded", "item", "theme"],
138-
template:
139-
"<div>{{ expanded ? '↪' : '→' }}</div>"
140-
}
141-
}
142-
}
107+
<Finder :tree="tree">
108+
<template #arrow="{ expanded }">
109+
<div>{{ expanded ? '↪' : '→' }}</div>
110+
</template>
111+
</Finder>
143112
```
144113

145-
<FinderExample :use-custom-arrow-component="true" />
114+
<FinderExample :use-custom-arrow-slot="true" />

package.json

-4
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
"devDependencies": {
5656
"@babel/core": "^7.8.4",
5757
"@babel/eslint-parser": "^7.17.0",
58-
"@babel/plugin-syntax-jsx": "^7.8.3",
5958
"@babel/preset-env": "^7.8.4",
6059
"@commitlint/cli": "^8.3.5",
6160
"@commitlint/config-conventional": "^8.3.4",
@@ -68,10 +67,7 @@
6867
"@storybook/builder-vite": "^7.5.3",
6968
"@storybook/vue3-vite": "^7.5.3",
7069
"@vitejs/plugin-vue": "^5.0.5",
71-
"@vitejs/plugin-vue-jsx": "^4.0.0",
7270
"@vitest/coverage-v8": "^1.6.0",
73-
"@vue/babel-plugin-jsx": "^1.2.2",
74-
"@vue/babel-preset-jsx": "^1.4.0",
7571
"@vue/compat": "^3.4.31",
7672
"@vue/test-utils": "2.4.6",
7773
"@vuepress/plugin-register-components": "^2.0.0-beta.61",

src/components/Finder.vue

+37-90
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,34 @@
1-
<script lang="jsx">
1+
<template>
2+
<div class="tree-container">
3+
<FinderList
4+
v-if="treeModel"
5+
ref="rootList"
6+
:tree-model="treeModel"
7+
:parent="treeModel.visibleTree"
8+
:selectable="selectable"
9+
:drag-enabled="dragEnabled"
10+
:options="options"
11+
>
12+
<template #item="itemProps">
13+
<slot name="item" v-bind="itemProps" />
14+
</template>
15+
<template #arrow="arrowProps">
16+
<slot name="arrow" v-bind="arrowProps" />
17+
</template>
18+
<template #drop-zone="dropZoneProps">
19+
<slot name="drop-zone" v-bind="dropZoneProps" />
20+
</template>
21+
<template #drag-image="dragImageProps">
22+
<slot name="drag-image" v-bind="dragImageProps" />
23+
</template>
24+
</FinderList>
25+
</div>
26+
</template>
27+
<script>
228
import { toRaw } from "vue";
329
import TreeModel from "@/utils/tree-model";
430
import FinderList from "./FinderList.vue";
531
6-
/**
7-
* Render the tree of an item and its selected children.
8-
*
9-
* @param {Object} h `createElement` object
10-
* @param {Object} context Context component
11-
* @param {Object} item Item to render
12-
* @return Rendering object
13-
*/
14-
function renderTree(h, context, item) {
15-
if (!item || !item.children || item.children.length === 0) {
16-
return null;
17-
}
18-
19-
const expandedChild = item.children.find((child) =>
20-
context.treeModel.isNodeExpanded(child.id),
21-
);
22-
23-
const options = {
24-
sortBy: context.sortBy,
25-
itemComponent: context.itemComponent,
26-
arrowComponent: context.arrowComponent,
27-
dragImageComponent: context.dragImageComponent,
28-
dropZoneComponent: context.dropZoneComponent,
29-
theme: context.theme,
30-
hasDragHandle: context.hasDragHandle,
31-
canDrop: context.canDrop,
32-
};
33-
34-
const itemList = (
35-
<FinderList
36-
ref="rootList"
37-
tree-model={context.treeModel}
38-
parent={item}
39-
items={item.children}
40-
selectable={context.selectable}
41-
drag-enabled={context.dragEnabled}
42-
options={options}
43-
has-expanded-item={!!expandedChild}
44-
/>
45-
);
46-
47-
return (
48-
<div class="list-container">
49-
{itemList}
50-
{expandedChild && renderTree(h, context, expandedChild)}
51-
</div>
52-
);
53-
}
54-
5532
/**
5633
* Get a value animated by a ease out Bezier curve.
5734
*/
@@ -185,34 +162,6 @@ export default {
185162
type: String,
186163
default: undefined,
187164
},
188-
/**
189-
* Custom component to render items.
190-
*/
191-
itemComponent: {
192-
type: [String, Object],
193-
default: undefined,
194-
},
195-
/**
196-
* Custom component to render arrows (on items with children).
197-
*/
198-
arrowComponent: {
199-
type: [String, Object],
200-
default: undefined,
201-
},
202-
/**
203-
* Custom component to render drag image.
204-
*/
205-
dragImageComponent: {
206-
type: [String, Object],
207-
default: undefined,
208-
},
209-
/**
210-
* Custom component to render drop zones.
211-
*/
212-
dropZoneComponent: {
213-
type: [String, Object],
214-
default: undefined,
215-
},
216165
/**
217166
* Styling options.
218167
*
@@ -249,6 +198,16 @@ export default {
249198
treeModel: {},
250199
};
251200
},
201+
computed: {
202+
options() {
203+
return {
204+
sortBy: this.sortBy,
205+
theme: this.theme,
206+
hasDragHandle: this.hasDragHandle,
207+
canDrop: this.canDrop,
208+
};
209+
},
210+
},
252211
watch: {
253212
tree(newTree) {
254213
this.treeModel.root = toRaw(newTree);
@@ -420,13 +379,6 @@ export default {
420379
window.requestAnimationFrame(step);
421380
},
422381
},
423-
render(h) {
424-
return (
425-
<div class="tree-container">
426-
{this.treeModel && renderTree(h, this, this.treeModel.visibleTree)}
427-
</div>
428-
);
429-
},
430382
};
431383
</script>
432384

@@ -436,10 +388,5 @@ export default {
436388
position: relative;
437389
display: flex;
438390
align-items: stretch;
439-
440-
.list-container {
441-
display: flex;
442-
align-items: stretch;
443-
}
444391
}
445392
</style>

0 commit comments

Comments
 (0)