Skip to content

Commit

Permalink
feat!: replace components by scoped slots for customization
Browse files Browse the repository at this point in the history
BREAKING CHANGE: previous custom components have been removed
  • Loading branch information
jledentu committed Jul 5, 2024
1 parent 8648d64 commit 1cc52e9
Show file tree
Hide file tree
Showing 20 changed files with 457 additions and 524 deletions.
8 changes: 0 additions & 8 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,7 @@ module.exports = {
root: true,
parserOptions: {
parser: "@babel/eslint-parser",
babelOptions: {
parserOpts: {
plugins: ["jsx"],
},
},
ecmaVersion: 2017,
ecmaFeatures: {
jsx: true,
},
sourceType: "module",
},
plugins: ["html", "vue"],
Expand Down
5 changes: 2 additions & 3 deletions .storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const path = require("path");
const { loadConfigFromFile, mergeConfig } = require("vite");
const vueJsx = require("@vitejs/plugin-vue-jsx");
const { loadConfigFromFile } = require("vite");

module.exports = {
stories: [
Expand Down Expand Up @@ -32,7 +31,7 @@ module.exports = {
"@": path.resolve("src"),
},
},
plugins: [...config.plugins, vueJsx()],
plugins: [...config.plugins],
};
},

Expand Down
2 changes: 1 addition & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = {
},
],
],
plugins: ["transform-es2015-modules-commonjs", "@vue/babel-plugin-jsx"],
plugins: ["transform-es2015-modules-commonjs"],
},
},
};
3 changes: 0 additions & 3 deletions docgen.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ module.exports = {
componentsRoot: "src/components",
//getDestFile: (file: string, config: DocgenCLIConfig) => path.join(config.outDir, file).replace(/\.vue$/ ".doc.md"),
components: "**/Finder.vue", // the glob to define what files should be documented as components (relative to componentRoot)
apiOptions: {
jsx: true, // tell vue-docgen-api that your components are using JSX to avoid conflicts with TypeScript <type> syntax
},
getDestFile: (file, config) => path.join(config.outDir, "api.md"),
templates: {
component: (renderedUsage, doc) =>
Expand Down
43 changes: 12 additions & 31 deletions docs/.vuepress/components/FinderExample.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
<template>
<Finder
:tree="tree"
:item-component="itemComponent"
:arrow-component="arrowComponent"
v-bind="$props"
/>
<Finder :tree="tree" v-bind="$props">
<template v-if="useCustomItemSlot" #item="{ item }">
<div style="color: blue">
<em>Name:</em> <strong>{{ item.label }}</strong>
</div>
</template>
<template v-if="useCustomArrowSlot" #arrow="{ expanded }">
<div>{{ expanded ? "↪" : "→" }}</div>
</template>
</Finder>
</template>
<script>
import { Finder } from "../../../dist/vue-finder.es.js";
Expand All @@ -19,8 +23,8 @@ export default {
"filter",
"dragEnabled",
"hasDragHandle",
"useCustomItemComponent",
"useCustomArrowComponent",
"useCustomItemSlot",
"useCustomArrowSlot",
"defaultExpanded",
],
data() {
Expand Down Expand Up @@ -95,29 +99,6 @@ export default {
},
};
},
computed: {
itemComponent() {
if (this.useCustomItemComponent) {
return {
props: ["item"],
template:
'<div style="color: blue"><em>Name:</em> <strong>{{ item.label }}</strong></div>',
};
} else {
return undefined;
}
},
arrowComponent() {
if (this.useCustomArrowComponent) {
return {
props: ["expanded"],
template: "<div>{{ expanded ? '↪' : '→' }}</div>",
};
} else {
return undefined;
}
},
},
};
</script>

Expand Down
79 changes: 24 additions & 55 deletions docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,75 +71,44 @@ Here are the available properties:
| `dropZoneBgColor` | Background color of drop zones (visible when Drag & Drop) |
| `draggedItemBgColor` | Background color of dragged items (visible when Drag & Drop) |

## Custom components
## Custom slots

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

### Item component
### Item

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

```html
<Finder :tree="tree" :item-component="itemComponent" />
```

```js
// ...
data() {
return {
itemComponent: {
props: ["item"],
template:
"<div style="color: blue"><em>Name:</em> <strong>{{ item.label }}</strong></div>"
}
}
}
```

<FinderExample :use-custom-item-component="true"/>

::: warning

The example above uses the `template` option to define the rendering of the component, so
the [runtime compiler](https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only) is needed.

You can also use a `render` function (in this case the runtime-only build is enough):
- `item`: the data of the item
- `expanded`: the expanded state of the item
- `dragged`: whether the item is currently dragged

```js
itemComponent: {
props: ["item"],
render(h) {
return h("div", this.item)
}
}
```html
<Finder :tree="tree">
<template #item="{ item }">
<div style="color: blue">
<em>Name:</em> <strong>{{ item.label }}</strong>
</div>
</template>
</Finder>
```

:::
<FinderExample :use-custom-item-slot="true"/>

### Arrow component
### Arrow

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

- `expanded`: the expanded state of the item
- `item`: the data of the item
- `theme`: the theme applied on the `Finder`

```html
<Finder :tree="tree" :arrow-component="arrowComponent" />
```

```js
// ...
data() {
return {
arrowComponent: {
props: ["expanded", "item", "theme"],
template:
"<div>{{ expanded ? '↪' : '→' }}</div>"
}
}
}
<Finder :tree="tree">
<template #arrow="{ expanded }">
<div>{{ expanded ? '↪' : '→' }}</div>
</template>
</Finder>
```

<FinderExample :use-custom-arrow-component="true" />
<FinderExample :use-custom-arrow-slot="true" />
4 changes: 0 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/eslint-parser": "^7.17.0",
"@babel/plugin-syntax-jsx": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"@commitlint/cli": "^8.3.5",
"@commitlint/config-conventional": "^8.3.4",
Expand All @@ -72,10 +71,7 @@
"@storybook/builder-vite": "^7.5.3",
"@storybook/vue3-vite": "^7.5.3",
"@vitejs/plugin-vue": "^5.0.5",
"@vitejs/plugin-vue-jsx": "^4.0.0",
"@vitest/coverage-v8": "^1.6.0",
"@vue/babel-plugin-jsx": "^1.2.2",
"@vue/babel-preset-jsx": "^1.4.0",
"@vue/compat": "^3.4.31",
"@vue/test-utils": "2.4.6",
"@vuepress/plugin-register-components": "^2.0.0-beta.61",
Expand Down
127 changes: 37 additions & 90 deletions src/components/Finder.vue
Original file line number Diff line number Diff line change
@@ -1,57 +1,34 @@
<script lang="jsx">
<template>
<div class="tree-container">
<FinderList
v-if="treeModel"
ref="rootList"
:tree-model="treeModel"
:parent="treeModel.visibleTree"
:selectable="selectable"
:drag-enabled="dragEnabled"
:options="options"
>
<template #item="itemProps">
<slot name="item" v-bind="itemProps" />
</template>
<template #arrow="arrowProps">
<slot name="arrow" v-bind="arrowProps" />
</template>
<template #drop-zone="dropZoneProps">
<slot name="drop-zone" v-bind="dropZoneProps" />
</template>
<template #drag-image="dragImageProps">
<slot name="drag-image" v-bind="dragImageProps" />
</template>
</FinderList>
</div>
</template>
<script>
import { toRaw } from "vue";
import TreeModel from "@/utils/tree-model";
import FinderList from "./FinderList.vue";
/**
* Render the tree of an item and its selected children.
*
* @param {Object} h `createElement` object
* @param {Object} context Context component
* @param {Object} item Item to render
* @return Rendering object
*/
function renderTree(h, context, item) {
if (!item || !item.children || item.children.length === 0) {
return null;
}
const expandedChild = item.children.find((child) =>
context.treeModel.isNodeExpanded(child.id),
);
const options = {
sortBy: context.sortBy,
itemComponent: context.itemComponent,
arrowComponent: context.arrowComponent,
dragImageComponent: context.dragImageComponent,
dropZoneComponent: context.dropZoneComponent,
theme: context.theme,
hasDragHandle: context.hasDragHandle,
canDrop: context.canDrop,
};
const itemList = (
<FinderList
ref="rootList"
tree-model={context.treeModel}
parent={item}
items={item.children}
selectable={context.selectable}
drag-enabled={context.dragEnabled}
options={options}
has-expanded-item={!!expandedChild}
/>
);
return (
<div class="list-container">
{itemList}
{expandedChild && renderTree(h, context, expandedChild)}
</div>
);
}
/**
* Get a value animated by a ease out Bezier curve.
*/
Expand Down Expand Up @@ -185,34 +162,6 @@ export default {
type: String,
default: undefined,
},
/**
* Custom component to render items.
*/
itemComponent: {
type: [String, Object],
default: undefined,
},
/**
* Custom component to render arrows (on items with children).
*/
arrowComponent: {
type: [String, Object],
default: undefined,
},
/**
* Custom component to render drag image.
*/
dragImageComponent: {
type: [String, Object],
default: undefined,
},
/**
* Custom component to render drop zones.
*/
dropZoneComponent: {
type: [String, Object],
default: undefined,
},
/**
* Styling options.
*
Expand Down Expand Up @@ -249,6 +198,16 @@ export default {
treeModel: {},
};
},
computed: {
options() {
return {
sortBy: this.sortBy,
theme: this.theme,
hasDragHandle: this.hasDragHandle,
canDrop: this.canDrop,
};
},
},
watch: {
tree(newTree) {
this.treeModel.root = toRaw(newTree);
Expand Down Expand Up @@ -420,13 +379,6 @@ export default {
window.requestAnimationFrame(step);
},
},
render(h) {
return (
<div class="tree-container">
{this.treeModel && renderTree(h, this, this.treeModel.visibleTree)}
</div>
);
},
};
</script>

Expand All @@ -436,10 +388,5 @@ export default {
position: relative;
display: flex;
align-items: stretch;
.list-container {
display: flex;
align-items: stretch;
}
}
</style>
Loading

0 comments on commit 1cc52e9

Please sign in to comment.