@bigplay/tree-view-vue2 0.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/README.md +30 -0
- package/dist/TreeNodeCard.d.ts +11 -0
- package/dist/TreeView.d.ts +46 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +230 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @bigplay/tree-view-vue2
|
|
2
|
+
|
|
3
|
+
Дерево и турнирные сетки для Vue 2.6 / 2.7. Тот же компонент, что и
|
|
4
|
+
[`@bigplay/tree-view`](https://www.npmjs.com/package/@bigplay/tree-view) для Vue 3:
|
|
5
|
+
общий core, одинаковые пропы, события и классы стилей.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @bigplay/tree-view-vue2
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import Vue from 'vue'
|
|
13
|
+
import { TreeView } from '@bigplay/tree-view-vue2'
|
|
14
|
+
|
|
15
|
+
Vue.component('TreeView', TreeView)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<tree-view :data="data" :options="{ direction: 'right-to-left' }" collapsible>
|
|
20
|
+
<template #node="{ data, toggle }">
|
|
21
|
+
<div class="my-card" @click="toggle">{{ data.name }}</div>
|
|
22
|
+
</template>
|
|
23
|
+
</tree-view>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Стили подключать не нужно — они внутри пакета и вставляются сами.
|
|
27
|
+
|
|
28
|
+
Полная документация — в [корневом README](https://github.com/dadashi44/tree-view#readme).
|
|
29
|
+
|
|
30
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { default as Vue } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Карточка узла по умолчанию для Vue 2.
|
|
4
|
+
* Разметка и классы один в один как в Vue 3 — стили общие.
|
|
5
|
+
*/
|
|
6
|
+
declare const _default: import('vue/types/vue').ExtendedVue<Vue<Record<string, any>, Record<string, any>, never, never, (event: string, ...args: any[]) => Vue>, unknown, unknown, unknown, {
|
|
7
|
+
label: string;
|
|
8
|
+
hasChildren: boolean;
|
|
9
|
+
collapsed: boolean;
|
|
10
|
+
}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin>;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { default as Vue, VNode } from 'vue';
|
|
2
|
+
import { Layout, LayoutNode, ScaleLimits, Transform, TreeViewOptions } from '@bigplay/tree-view-core';
|
|
3
|
+
/** Данные узла могут быть какими угодно — библиотека читает их только аксессорами. */
|
|
4
|
+
type NodeData = any;
|
|
5
|
+
declare const _default: import('vue/types/vue').ExtendedVue<Vue<Record<string, any>, Record<string, any>, never, never, (event: string, ...args: any[]) => Vue>, {
|
|
6
|
+
/** Массив, а не Set: Vue 2 не умеет наблюдать за Set. */
|
|
7
|
+
collapsedIds: string[];
|
|
8
|
+
transform: Transform;
|
|
9
|
+
}, {
|
|
10
|
+
/** Вписывает дерево в видимую область. */
|
|
11
|
+
fit(padding?: number): void;
|
|
12
|
+
zoomIn(): void;
|
|
13
|
+
zoomOut(): void;
|
|
14
|
+
resetTransform(): void;
|
|
15
|
+
setTransform(transform: Transform): void;
|
|
16
|
+
/** Развернуть все свёрнутые ветки. */
|
|
17
|
+
expandAll(): void;
|
|
18
|
+
/** Свернуть или развернуть узел по id. */
|
|
19
|
+
toggle(id: string): void;
|
|
20
|
+
toggleNode(node: LayoutNode<NodeData>): void;
|
|
21
|
+
onNodeClick(node: LayoutNode<NodeData>, event: MouseEvent): void;
|
|
22
|
+
nodeStyle(node: LayoutNode<NodeData>): Record<string, string>;
|
|
23
|
+
nodeClassOf(node: LayoutNode<NodeData>): string | undefined;
|
|
24
|
+
/** Подпись карточки по умолчанию: name → title → label → id. */
|
|
25
|
+
labelOf(node: LayoutNode<NodeData>): string;
|
|
26
|
+
/** Своя карточка из scoped-слота или карточка по умолчанию. */
|
|
27
|
+
renderNodeContent(h: typeof Vue.prototype.$createElement, node: LayoutNode<NodeData>): VNode | VNode[];
|
|
28
|
+
}, {
|
|
29
|
+
layout: Layout<any>;
|
|
30
|
+
canvasStyle: Record<string, string>;
|
|
31
|
+
rootStyle: Record<string, string> | undefined;
|
|
32
|
+
}, {
|
|
33
|
+
data: any;
|
|
34
|
+
options: Partial<TreeViewOptions>;
|
|
35
|
+
getId: ((item: any) => string | number | null | undefined) | undefined;
|
|
36
|
+
getChildren: ((item: any) => any[] | null | undefined) | undefined;
|
|
37
|
+
getParentId: ((item: any) => string | number | null | undefined) | undefined;
|
|
38
|
+
collapsible: boolean;
|
|
39
|
+
pannable: boolean;
|
|
40
|
+
zoomable: boolean;
|
|
41
|
+
fitOnMount: boolean;
|
|
42
|
+
size: string;
|
|
43
|
+
scaleLimits: ScaleLimits;
|
|
44
|
+
nodeClass: string | ((node: LayoutNode<NodeData>) => string);
|
|
45
|
+
}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin>;
|
|
46
|
+
export default _default;
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const n=require("vue"),s=require("@bigplay/tree-view-core"),a=n.extend({name:"TreeNodeCard",props:{label:{type:String,required:!0},hasChildren:{type:Boolean,default:!1},collapsed:{type:Boolean,default:!1}},render(e){const t=[e("span",{class:"tree-view-card__label"},this.label)];return this.hasChildren&&t.push(e("button",{class:"tree-view-card__toggle",attrs:{type:"button","data-tv-no-pan":"","aria-label":this.collapsed?"Развернуть":"Свернуть"},on:{click:l=>{l.stopPropagation(),this.$emit("toggle")}}},this.collapsed?"+":"−")),e("div",{class:"tree-view-card"},t)}}),o=new WeakMap,r=n.extend({name:"TreeView",props:{data:{type:[Object,Array],default:null},options:{type:Object,default:void 0},getId:{type:Function,default:void 0},getChildren:{type:Function,default:void 0},getParentId:{type:Function,default:void 0},collapsible:{type:Boolean,default:!1},pannable:{type:Boolean,default:!0},zoomable:{type:Boolean,default:!0},fitOnMount:{type:Boolean,default:!0},size:{type:String,default:"fill"},scaleLimits:{type:Object,default:void 0},nodeClass:{type:[String,Function],default:void 0}},data(){return{collapsedIds:[],transform:{x:0,y:0,scale:1}}},computed:{layout(){const e=s.toTree(this.data,{getId:this.getId,getChildren:this.getChildren,getParentId:this.getParentId});return s.layoutTree(s.applyCollapsed(e,new Set(this.collapsedIds)),this.options)},canvasStyle(){return{width:`${this.layout.width}px`,height:`${this.layout.height}px`,transform:s.toCssTransform(this.transform)}},rootStyle(){if(this.size==="content")return{width:`${this.layout.width*this.transform.scale}px`,height:`${this.layout.height*this.transform.scale}px`,overflow:"visible"}}},mounted(){const e=new s.PanZoomController({pannable:()=>this.pannable,zoomable:()=>this.zoomable,limits:this.scaleLimits?()=>this.scaleLimits:void 0,onChange:t=>{this.transform=t,this.$emit("transform",t)}});e.attach(this.$el),o.set(this,e),this.fitOnMount&&this.$nextTick(()=>this.fit())},beforeDestroy(){o.get(this)?.detach(),o.delete(this)},methods:{fit(e){o.get(this)?.fit({width:this.layout.width,height:this.layout.height},e)},zoomIn(){o.get(this)?.zoomIn()},zoomOut(){o.get(this)?.zoomOut()},resetTransform(){o.get(this)?.reset()},setTransform(e){o.get(this)?.set(e)},expandAll(){this.collapsedIds=[]},toggle(e){this.collapsedIds=[...s.toggleCollapsed(new Set(this.collapsedIds),e)]},toggleNode(e){this.toggle(e.id),this.$emit("toggle",e,this.collapsedIds.includes(e.id))},onNodeClick(e,t){this.$emit("node-click",e,t),this.collapsible&&e.hasChildren&&this.toggleNode(e)},nodeStyle(e){return{left:`${e.x}px`,top:`${e.y}px`,width:`${e.width}px`,height:`${e.height}px`}},nodeClassOf(e){return typeof this.nodeClass=="function"?this.nodeClass(e):this.nodeClass},labelOf(e){const t=e.data;return t?.name??t?.title??t?.label??e.id},renderNodeContent(e,t){const l=this.$scopedSlots.node;return l?l({node:t,data:t.data,depth:t.depth,collapsed:t.collapsed,hasChildren:t.hasChildren,toggle:()=>this.toggleNode(t)})??[]:e(a,{props:{label:this.labelOf(t),hasChildren:t.hasChildren,collapsed:t.collapsed},on:{toggle:()=>this.toggleNode(t)}})}},render(e){const t=this.layout,l=this.$scopedSlots.link,h=t.links.map(i=>l?l({link:i})??[]:e("path",{key:i.id,class:"tree-view__link",attrs:{d:i.path}})),c=t.nodes.map(i=>e("div",{key:i.id,class:["tree-view__node",this.nodeClassOf(i)],style:this.nodeStyle(i),on:{click:p=>this.onNodeClick(i,p)}},[].concat(this.renderNodeContent(e,i))));return e("div",{class:["tree-view",{"tree-view--pannable":this.pannable,"tree-view--content":this.size==="content"}],style:this.rootStyle},[e("div",{class:"tree-view__canvas",style:this.canvasStyle},[e("svg",{class:"tree-view__links",attrs:{width:t.width,height:t.height}},h),...c])])}}),u=".tree-view{--tv-link-color: #cbd5e1;--tv-link-width: 2px;--tv-node-bg: #ffffff;--tv-node-color: #0f172a;--tv-node-border: 1px solid #e2e8f0;--tv-node-radius: 10px;--tv-node-shadow: 0 1px 2px rgb(15 23 42 / 8%);--tv-node-padding: 8px 12px;--tv-accent: #2563eb;position:relative;width:100%;height:100%;overflow:hidden;touch-action:none}.tree-view--pannable{cursor:grab}.tree-view--content{width:auto;height:auto;overflow:visible}.tree-view__canvas{position:absolute;top:0;left:0;transform-origin:0 0}.tree-view__links{position:absolute;top:0;left:0;overflow:visible;pointer-events:none}.tree-view__link{fill:none;stroke:var(--tv-link-color);stroke-width:var(--tv-link-width)}.tree-view__node{position:absolute;box-sizing:border-box;display:flex;align-items:stretch;justify-content:stretch}.tree-view-card{box-sizing:border-box;display:flex;gap:8px;align-items:center;justify-content:space-between;width:100%;height:100%;padding:var(--tv-node-padding);overflow:hidden;color:var(--tv-node-color);background:var(--tv-node-bg);border:var(--tv-node-border);border-radius:var(--tv-node-radius);box-shadow:var(--tv-node-shadow)}.tree-view-card__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-view-card__toggle{flex:none;width:20px;height:20px;padding:0;font:inherit;line-height:1;color:var(--tv-accent);cursor:pointer;background:none;border:none}";s.injectStyles(u);const d={install(e){e.component("TreeView",r),e.component("TreeNodeCard",a)}};Object.defineProperty(exports,"DEFAULT_OPTIONS",{enumerable:!0,get:()=>s.DEFAULT_OPTIONS});exports.TreeNodeCard=a;exports.TreeView=r;exports.TreeViewPlugin=d;exports.default=d;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/TreeNodeCard.ts","../src/TreeView.ts","../src/index.ts"],"sourcesContent":["import Vue from 'vue'\n\n/**\n * Карточка узла по умолчанию для Vue 2.\n * Разметка и классы один в один как в Vue 3 — стили общие.\n */\nexport default Vue.extend({\n name: 'TreeNodeCard',\n props: {\n label: { type: String, required: true },\n hasChildren: { type: Boolean, default: false },\n collapsed: { type: Boolean, default: false },\n },\n render(h) {\n const children = [h('span', { class: 'tree-view-card__label' }, this.label)]\n\n if (this.hasChildren) {\n children.push(\n h(\n 'button',\n {\n class: 'tree-view-card__toggle',\n attrs: {\n type: 'button',\n 'data-tv-no-pan': '',\n 'aria-label': this.collapsed ? 'Развернуть' : 'Свернуть',\n },\n on: {\n click: (event: MouseEvent) => {\n event.stopPropagation()\n this.$emit('toggle')\n },\n },\n },\n this.collapsed ? '+' : '−',\n ),\n )\n }\n\n return h('div', { class: 'tree-view-card' }, children)\n },\n})\n","import Vue, { type PropType, type VNode } from 'vue'\nimport {\n applyCollapsed,\n layoutTree,\n PanZoomController,\n toCssTransform,\n toggleCollapsed,\n toTree,\n type Accessors,\n type Layout,\n type LayoutNode,\n type ScaleLimits,\n type Transform,\n type TreeViewOptions,\n} from '@bigplay/tree-view-core'\nimport TreeNodeCard from './TreeNodeCard'\n\n/** Данные узла могут быть какими угодно — библиотека читает их только аксессорами. */\ntype NodeData = any\n\n/**\n * Контроллеры держим здесь, а не в data(): Vue 2 сделал бы объект реактивным,\n * а внутри него DOM-элемент и Map — наблюдать за ними незачем.\n */\nconst controllers = new WeakMap<Vue, PanZoomController>()\n\nexport default Vue.extend({\n name: 'TreeView',\n props: {\n /** Объект, массив объектов или плоский список (вместе с `getParentId`). */\n data: { type: [Object, Array] as PropType<NodeData>, default: null },\n /** Размеры и направление. Можно передать только часть полей. */\n options: { type: Object as PropType<Partial<TreeViewOptions>>, default: undefined },\n /** Как достать id узла. По умолчанию — поле `id`. */\n getId: { type: Function as PropType<Accessors<NodeData>['getId']>, default: undefined },\n /** Как достать детей. По умолчанию — поле `children`. */\n getChildren: { type: Function as PropType<Accessors<NodeData>['getChildren']>, default: undefined },\n /** Как достать id родителя. Передан — значит данные плоские. */\n getParentId: { type: Function as PropType<Accessors<NodeData>['getParentId']>, default: undefined },\n /** Клик по узлу сворачивает/разворачивает ветку. */\n collapsible: { type: Boolean, default: false },\n /** Разрешить перетаскивание холста. */\n pannable: { type: Boolean, default: true },\n /** Разрешить зум колесом и «щипком». */\n zoomable: { type: Boolean, default: true },\n /** Вписать дерево в контейнер при первом отображении. */\n fitOnMount: { type: Boolean, default: true },\n /**\n * Как компонент занимает место:\n * - `'fill'` (по умолчанию) — растягивается на родителя, лишнее обрезается;\n * - `'content'` — контейнер принимает размер дерева и ничего не обрезает.\n */\n size: { type: String as PropType<'fill' | 'content'>, default: 'fill' },\n /** Пределы масштаба. */\n scaleLimits: { type: Object as PropType<ScaleLimits>, default: undefined },\n /** Дополнительный класс на обёртке узла — строкой или функцией. */\n nodeClass: {\n type: [String, Function] as PropType<string | ((node: LayoutNode<NodeData>) => string)>,\n default: undefined,\n },\n },\n\n data() {\n return {\n /** Массив, а не Set: Vue 2 не умеет наблюдать за Set. */\n collapsedIds: [] as string[],\n transform: { x: 0, y: 0, scale: 1 } as Transform,\n }\n },\n\n computed: {\n layout(): Layout<NodeData> {\n const tree = toTree<NodeData>(this.data, {\n getId: this.getId,\n getChildren: this.getChildren,\n getParentId: this.getParentId,\n })\n\n return layoutTree(applyCollapsed(tree, new Set(this.collapsedIds)), this.options)\n },\n\n canvasStyle(): Record<string, string> {\n return {\n width: `${this.layout.width}px`,\n height: `${this.layout.height}px`,\n transform: toCssTransform(this.transform),\n }\n },\n\n rootStyle(): Record<string, string> | undefined {\n if (this.size !== 'content') return undefined\n\n return {\n width: `${this.layout.width * this.transform.scale}px`,\n height: `${this.layout.height * this.transform.scale}px`,\n overflow: 'visible',\n }\n },\n },\n\n mounted() {\n const controller = new PanZoomController({\n pannable: () => this.pannable,\n zoomable: () => this.zoomable,\n limits: this.scaleLimits ? () => this.scaleLimits : undefined,\n onChange: (transform) => {\n this.transform = transform\n this.$emit('transform', transform)\n },\n })\n\n controller.attach(this.$el as HTMLElement)\n controllers.set(this, controller)\n\n if (this.fitOnMount) this.$nextTick(() => this.fit())\n },\n\n beforeDestroy() {\n controllers.get(this)?.detach()\n controllers.delete(this)\n },\n\n methods: {\n /** Вписывает дерево в видимую область. */\n fit(padding?: number): void {\n controllers.get(this)?.fit({ width: this.layout.width, height: this.layout.height }, padding)\n },\n zoomIn(): void {\n controllers.get(this)?.zoomIn()\n },\n zoomOut(): void {\n controllers.get(this)?.zoomOut()\n },\n resetTransform(): void {\n controllers.get(this)?.reset()\n },\n setTransform(transform: Transform): void {\n controllers.get(this)?.set(transform)\n },\n /** Развернуть все свёрнутые ветки. */\n expandAll(): void {\n this.collapsedIds = []\n },\n /** Свернуть или развернуть узел по id. */\n toggle(id: string): void {\n this.collapsedIds = [...toggleCollapsed(new Set(this.collapsedIds), id)]\n },\n\n toggleNode(node: LayoutNode<NodeData>): void {\n this.toggle(node.id)\n this.$emit('toggle', node, this.collapsedIds.includes(node.id))\n },\n\n onNodeClick(node: LayoutNode<NodeData>, event: MouseEvent): void {\n this.$emit('node-click', node, event)\n if (this.collapsible && node.hasChildren) this.toggleNode(node)\n },\n\n nodeStyle(node: LayoutNode<NodeData>): Record<string, string> {\n return {\n left: `${node.x}px`,\n top: `${node.y}px`,\n width: `${node.width}px`,\n height: `${node.height}px`,\n }\n },\n\n nodeClassOf(node: LayoutNode<NodeData>): string | undefined {\n return typeof this.nodeClass === 'function' ? this.nodeClass(node) : this.nodeClass\n },\n\n /** Подпись карточки по умолчанию: name → title → label → id. */\n labelOf(node: LayoutNode<NodeData>): string {\n const data = node.data as { name?: string; title?: string; label?: string } | null\n return data?.name ?? data?.title ?? data?.label ?? node.id\n },\n\n /** Своя карточка из scoped-слота или карточка по умолчанию. */\n renderNodeContent(h: typeof Vue.prototype.$createElement, node: LayoutNode<NodeData>): VNode | VNode[] {\n const slot = this.$scopedSlots.node\n\n if (slot) {\n return (slot({\n node,\n data: node.data,\n depth: node.depth,\n collapsed: node.collapsed,\n hasChildren: node.hasChildren,\n toggle: () => this.toggleNode(node),\n }) ?? []) as VNode[]\n }\n\n return h(TreeNodeCard, {\n props: { label: this.labelOf(node), hasChildren: node.hasChildren, collapsed: node.collapsed },\n on: { toggle: () => this.toggleNode(node) },\n })\n },\n },\n\n render(h): VNode {\n const layout = this.layout\n const linkSlot = this.$scopedSlots.link\n\n const links = layout.links.map((link) =>\n linkSlot\n ? ((linkSlot({ link }) ?? []) as VNode[])\n : h('path', { key: link.id, class: 'tree-view__link', attrs: { d: link.path } }),\n )\n\n const nodes = layout.nodes.map((node) =>\n h(\n 'div',\n {\n key: node.id,\n class: ['tree-view__node', this.nodeClassOf(node)],\n style: this.nodeStyle(node),\n on: { click: (event: MouseEvent) => this.onNodeClick(node, event) },\n },\n ([] as VNode[]).concat(this.renderNodeContent(h, node)),\n ),\n )\n\n return h(\n 'div',\n {\n class: [\n 'tree-view',\n { 'tree-view--pannable': this.pannable, 'tree-view--content': this.size === 'content' },\n ],\n style: this.rootStyle,\n },\n [\n h('div', { class: 'tree-view__canvas', style: this.canvasStyle }, [\n h(\n 'svg',\n {\n class: 'tree-view__links',\n attrs: { width: layout.width, height: layout.height },\n },\n links as VNode[],\n ),\n ...nodes,\n ]),\n ],\n )\n },\n})\n","import type { VueConstructor } from 'vue'\nimport TreeView from './TreeView'\nimport TreeNodeCard from './TreeNodeCard'\n// Стили общие для Vue 2 и Vue 3 — лежат в core, чтобы не расходились.\n// Они попадают прямо в бандл и подключаются сами: отдельный импорт в проекте не нужен.\nimport { injectStyles } from '@bigplay/tree-view-core'\nimport styles from '@bigplay/tree-view-core/style.css?inline'\n\ninjectStyles(styles)\n\nexport { TreeView, TreeNodeCard }\n\nexport type {\n Accessors,\n Direction,\n Layout,\n LayoutLink,\n LayoutNode,\n LinkStyle,\n ScaleLimits,\n Transform,\n TreeNode,\n TreeViewOptions,\n} from '@bigplay/tree-view-core'\nexport { DEFAULT_OPTIONS } from '@bigplay/tree-view-core'\n\n/** Плагин: `Vue.use(TreeViewPlugin)` регистрирует компоненты глобально. */\nexport const TreeViewPlugin = {\n install(Vue: VueConstructor) {\n Vue.component('TreeView', TreeView)\n Vue.component('TreeNodeCard', TreeNodeCard)\n },\n}\n\nexport default TreeViewPlugin\n"],"names":["TreeNodeCard","Vue","h","children","event","controllers","TreeView","tree","toTree","layoutTree","applyCollapsed","toCssTransform","controller","PanZoomController","transform","padding","id","toggleCollapsed","node","data","slot","layout","linkSlot","links","link","nodes","injectStyles","styles","TreeViewPlugin"],"mappings":"wKAMAA,EAAeC,EAAI,OAAO,CACxB,KAAM,eACN,MAAO,CACL,MAAO,CAAE,KAAM,OAAQ,SAAU,EAAA,EACjC,YAAa,CAAE,KAAM,QAAS,QAAS,EAAA,EACvC,UAAW,CAAE,KAAM,QAAS,QAAS,EAAA,CAAM,EAE7C,OAAOC,EAAG,CACR,MAAMC,EAAW,CAACD,EAAE,OAAQ,CAAE,MAAO,uBAAA,EAA2B,KAAK,KAAK,CAAC,EAE3E,OAAI,KAAK,aACPC,EAAS,KACPD,EACE,SACA,CACE,MAAO,yBACP,MAAO,CACL,KAAM,SACN,iBAAkB,GAClB,aAAc,KAAK,UAAY,aAAe,UAAA,EAEhD,GAAI,CACF,MAAQE,GAAsB,CAC5BA,EAAM,gBAAA,EACN,KAAK,MAAM,QAAQ,CACrB,CAAA,CACF,EAEF,KAAK,UAAY,IAAM,GAAA,CACzB,EAIGF,EAAE,MAAO,CAAE,MAAO,gBAAA,EAAoBC,CAAQ,CACvD,CACF,CAAC,ECjBKE,MAAkB,QAExBC,EAAeL,EAAI,OAAO,CACxB,KAAM,WACN,MAAO,CAEL,KAAM,CAAE,KAAM,CAAC,OAAQ,KAAK,EAAyB,QAAS,IAAA,EAE9D,QAAS,CAAE,KAAM,OAA8C,QAAS,MAAA,EAExE,MAAO,CAAE,KAAM,SAAoD,QAAS,MAAA,EAE5E,YAAa,CAAE,KAAM,SAA0D,QAAS,MAAA,EAExF,YAAa,CAAE,KAAM,SAA0D,QAAS,MAAA,EAExF,YAAa,CAAE,KAAM,QAAS,QAAS,EAAA,EAEvC,SAAU,CAAE,KAAM,QAAS,QAAS,EAAA,EAEpC,SAAU,CAAE,KAAM,QAAS,QAAS,EAAA,EAEpC,WAAY,CAAE,KAAM,QAAS,QAAS,EAAA,EAMtC,KAAM,CAAE,KAAM,OAAwC,QAAS,MAAA,EAE/D,YAAa,CAAE,KAAM,OAAiC,QAAS,MAAA,EAE/D,UAAW,CACT,KAAM,CAAC,OAAQ,QAAQ,EACvB,QAAS,MAAA,CACX,EAGF,MAAO,CACL,MAAO,CAEL,aAAc,CAAA,EACd,UAAW,CAAE,EAAG,EAAG,EAAG,EAAG,MAAO,CAAA,CAAE,CAEtC,EAEA,SAAU,CACR,QAA2B,CACzB,MAAMM,EAAOC,EAAAA,OAAiB,KAAK,KAAM,CACvC,MAAO,KAAK,MACZ,YAAa,KAAK,YAClB,YAAa,KAAK,WAAA,CACnB,EAED,OAAOC,EAAAA,WAAWC,iBAAeH,EAAM,IAAI,IAAI,KAAK,YAAY,CAAC,EAAG,KAAK,OAAO,CAClF,EAEA,aAAsC,CACpC,MAAO,CACL,MAAO,GAAG,KAAK,OAAO,KAAK,KAC3B,OAAQ,GAAG,KAAK,OAAO,MAAM,KAC7B,UAAWI,EAAAA,eAAe,KAAK,SAAS,CAAA,CAE5C,EAEA,WAAgD,CAC9C,GAAI,KAAK,OAAS,UAElB,MAAO,CACL,MAAO,GAAG,KAAK,OAAO,MAAQ,KAAK,UAAU,KAAK,KAClD,OAAQ,GAAG,KAAK,OAAO,OAAS,KAAK,UAAU,KAAK,KACpD,SAAU,SAAA,CAEd,CAAA,EAGF,SAAU,CACR,MAAMC,EAAa,IAAIC,oBAAkB,CACvC,SAAU,IAAM,KAAK,SACrB,SAAU,IAAM,KAAK,SACrB,OAAQ,KAAK,YAAc,IAAM,KAAK,YAAc,OACpD,SAAWC,GAAc,CACvB,KAAK,UAAYA,EACjB,KAAK,MAAM,YAAaA,CAAS,CACnC,CAAA,CACD,EAEDF,EAAW,OAAO,KAAK,GAAkB,EACzCP,EAAY,IAAI,KAAMO,CAAU,EAE5B,KAAK,YAAY,KAAK,UAAU,IAAM,KAAK,KAAK,CACtD,EAEA,eAAgB,CACdP,EAAY,IAAI,IAAI,GAAG,OAAA,EACvBA,EAAY,OAAO,IAAI,CACzB,EAEA,QAAS,CAEP,IAAIU,EAAwB,CAC1BV,EAAY,IAAI,IAAI,GAAG,IAAI,CAAE,MAAO,KAAK,OAAO,MAAO,OAAQ,KAAK,OAAO,MAAA,EAAUU,CAAO,CAC9F,EACA,QAAe,CACbV,EAAY,IAAI,IAAI,GAAG,OAAA,CACzB,EACA,SAAgB,CACdA,EAAY,IAAI,IAAI,GAAG,QAAA,CACzB,EACA,gBAAuB,CACrBA,EAAY,IAAI,IAAI,GAAG,MAAA,CACzB,EACA,aAAaS,EAA4B,CACvCT,EAAY,IAAI,IAAI,GAAG,IAAIS,CAAS,CACtC,EAEA,WAAkB,CAChB,KAAK,aAAe,CAAA,CACtB,EAEA,OAAOE,EAAkB,CACvB,KAAK,aAAe,CAAC,GAAGC,kBAAgB,IAAI,IAAI,KAAK,YAAY,EAAGD,CAAE,CAAC,CACzE,EAEA,WAAWE,EAAkC,CAC3C,KAAK,OAAOA,EAAK,EAAE,EACnB,KAAK,MAAM,SAAUA,EAAM,KAAK,aAAa,SAASA,EAAK,EAAE,CAAC,CAChE,EAEA,YAAYA,EAA4Bd,EAAyB,CAC/D,KAAK,MAAM,aAAcc,EAAMd,CAAK,EAChC,KAAK,aAAec,EAAK,aAAa,KAAK,WAAWA,CAAI,CAChE,EAEA,UAAUA,EAAoD,CAC5D,MAAO,CACL,KAAM,GAAGA,EAAK,CAAC,KACf,IAAK,GAAGA,EAAK,CAAC,KACd,MAAO,GAAGA,EAAK,KAAK,KACpB,OAAQ,GAAGA,EAAK,MAAM,IAAA,CAE1B,EAEA,YAAYA,EAAgD,CAC1D,OAAO,OAAO,KAAK,WAAc,WAAa,KAAK,UAAUA,CAAI,EAAI,KAAK,SAC5E,EAGA,QAAQA,EAAoC,CAC1C,MAAMC,EAAOD,EAAK,KAClB,OAAOC,GAAM,MAAQA,GAAM,OAASA,GAAM,OAASD,EAAK,EAC1D,EAGA,kBAAkBhB,EAAwCgB,EAA6C,CACrG,MAAME,EAAO,KAAK,aAAa,KAE/B,OAAIA,EACMA,EAAK,CACX,KAAAF,EACA,KAAMA,EAAK,KACX,MAAOA,EAAK,MACZ,UAAWA,EAAK,UAChB,YAAaA,EAAK,YAClB,OAAQ,IAAM,KAAK,WAAWA,CAAI,CAAA,CACnC,GAAK,CAAA,EAGDhB,EAAEF,EAAc,CACrB,MAAO,CAAE,MAAO,KAAK,QAAQkB,CAAI,EAAG,YAAaA,EAAK,YAAa,UAAWA,EAAK,SAAA,EACnF,GAAI,CAAE,OAAQ,IAAM,KAAK,WAAWA,CAAI,CAAA,CAAE,CAC3C,CACH,CAAA,EAGF,OAAOhB,EAAU,CACf,MAAMmB,EAAS,KAAK,OACdC,EAAW,KAAK,aAAa,KAE7BC,EAAQF,EAAO,MAAM,IAAKG,GAC9BF,EACMA,EAAS,CAAE,KAAAE,EAAM,GAAK,CAAA,EACxBtB,EAAE,OAAQ,CAAE,IAAKsB,EAAK,GAAI,MAAO,kBAAmB,MAAO,CAAE,EAAGA,EAAK,KAAK,CAAG,CAAA,EAG7EC,EAAQJ,EAAO,MAAM,IAAKH,GAC9BhB,EACE,MACA,CACE,IAAKgB,EAAK,GACV,MAAO,CAAC,kBAAmB,KAAK,YAAYA,CAAI,CAAC,EACjD,MAAO,KAAK,UAAUA,CAAI,EAC1B,GAAI,CAAE,MAAQd,GAAsB,KAAK,YAAYc,EAAMd,CAAK,CAAA,CAAE,EAEnE,CAAA,EAAe,OAAO,KAAK,kBAAkBF,EAAGgB,CAAI,CAAC,CAAA,CACxD,EAGF,OAAOhB,EACL,MACA,CACE,MAAO,CACL,YACA,CAAE,sBAAuB,KAAK,SAAU,qBAAsB,KAAK,OAAS,SAAA,CAAU,EAExF,MAAO,KAAK,SAAA,EAEd,CACEA,EAAE,MAAO,CAAE,MAAO,oBAAqB,MAAO,KAAK,aAAe,CAChEA,EACE,MACA,CACE,MAAO,mBACP,MAAO,CAAE,MAAOmB,EAAO,MAAO,OAAQA,EAAO,MAAA,CAAO,EAEtDE,CAAA,EAEF,GAAGE,CAAA,CACJ,CAAA,CACH,CAEJ,CACF,CAAC,u1CC9ODC,EAAAA,aAAaC,CAAM,EAmBZ,MAAMC,EAAiB,CAC5B,QAAQ3B,EAAqB,CAC3BA,EAAI,UAAU,WAAYK,CAAQ,EAClCL,EAAI,UAAU,eAAgBD,CAAY,CAC5C,CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { VueConstructor } from 'vue';
|
|
2
|
+
import { default as TreeView } from './TreeView';
|
|
3
|
+
import { default as TreeNodeCard } from './TreeNodeCard';
|
|
4
|
+
export { TreeView, TreeNodeCard };
|
|
5
|
+
export type { Accessors, Direction, Layout, LayoutLink, LayoutNode, LinkStyle, ScaleLimits, Transform, TreeNode, TreeViewOptions, } from '@bigplay/tree-view-core';
|
|
6
|
+
export { DEFAULT_OPTIONS } from '@bigplay/tree-view-core';
|
|
7
|
+
/** Плагин: `Vue.use(TreeViewPlugin)` регистрирует компоненты глобально. */
|
|
8
|
+
export declare const TreeViewPlugin: {
|
|
9
|
+
install(Vue: VueConstructor): void;
|
|
10
|
+
};
|
|
11
|
+
export default TreeViewPlugin;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import l from "vue";
|
|
2
|
+
import { toggleCollapsed as h, PanZoomController as c, toCssTransform as p, toTree as g, layoutTree as v, applyCollapsed as f, injectStyles as u } from "@bigplay/tree-view-core";
|
|
3
|
+
import { DEFAULT_OPTIONS as k } from "@bigplay/tree-view-core";
|
|
4
|
+
const a = l.extend({
|
|
5
|
+
name: "TreeNodeCard",
|
|
6
|
+
props: {
|
|
7
|
+
label: { type: String, required: !0 },
|
|
8
|
+
hasChildren: { type: Boolean, default: !1 },
|
|
9
|
+
collapsed: { type: Boolean, default: !1 }
|
|
10
|
+
},
|
|
11
|
+
render(e) {
|
|
12
|
+
const t = [e("span", { class: "tree-view-card__label" }, this.label)];
|
|
13
|
+
return this.hasChildren && t.push(
|
|
14
|
+
e(
|
|
15
|
+
"button",
|
|
16
|
+
{
|
|
17
|
+
class: "tree-view-card__toggle",
|
|
18
|
+
attrs: {
|
|
19
|
+
type: "button",
|
|
20
|
+
"data-tv-no-pan": "",
|
|
21
|
+
"aria-label": this.collapsed ? "Развернуть" : "Свернуть"
|
|
22
|
+
},
|
|
23
|
+
on: {
|
|
24
|
+
click: (s) => {
|
|
25
|
+
s.stopPropagation(), this.$emit("toggle");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
this.collapsed ? "+" : "−"
|
|
30
|
+
)
|
|
31
|
+
), e("div", { class: "tree-view-card" }, t);
|
|
32
|
+
}
|
|
33
|
+
}), o = /* @__PURE__ */ new WeakMap(), w = l.extend({
|
|
34
|
+
name: "TreeView",
|
|
35
|
+
props: {
|
|
36
|
+
/** Объект, массив объектов или плоский список (вместе с `getParentId`). */
|
|
37
|
+
data: { type: [Object, Array], default: null },
|
|
38
|
+
/** Размеры и направление. Можно передать только часть полей. */
|
|
39
|
+
options: { type: Object, default: void 0 },
|
|
40
|
+
/** Как достать id узла. По умолчанию — поле `id`. */
|
|
41
|
+
getId: { type: Function, default: void 0 },
|
|
42
|
+
/** Как достать детей. По умолчанию — поле `children`. */
|
|
43
|
+
getChildren: { type: Function, default: void 0 },
|
|
44
|
+
/** Как достать id родителя. Передан — значит данные плоские. */
|
|
45
|
+
getParentId: { type: Function, default: void 0 },
|
|
46
|
+
/** Клик по узлу сворачивает/разворачивает ветку. */
|
|
47
|
+
collapsible: { type: Boolean, default: !1 },
|
|
48
|
+
/** Разрешить перетаскивание холста. */
|
|
49
|
+
pannable: { type: Boolean, default: !0 },
|
|
50
|
+
/** Разрешить зум колесом и «щипком». */
|
|
51
|
+
zoomable: { type: Boolean, default: !0 },
|
|
52
|
+
/** Вписать дерево в контейнер при первом отображении. */
|
|
53
|
+
fitOnMount: { type: Boolean, default: !0 },
|
|
54
|
+
/**
|
|
55
|
+
* Как компонент занимает место:
|
|
56
|
+
* - `'fill'` (по умолчанию) — растягивается на родителя, лишнее обрезается;
|
|
57
|
+
* - `'content'` — контейнер принимает размер дерева и ничего не обрезает.
|
|
58
|
+
*/
|
|
59
|
+
size: { type: String, default: "fill" },
|
|
60
|
+
/** Пределы масштаба. */
|
|
61
|
+
scaleLimits: { type: Object, default: void 0 },
|
|
62
|
+
/** Дополнительный класс на обёртке узла — строкой или функцией. */
|
|
63
|
+
nodeClass: {
|
|
64
|
+
type: [String, Function],
|
|
65
|
+
default: void 0
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
data() {
|
|
69
|
+
return {
|
|
70
|
+
/** Массив, а не Set: Vue 2 не умеет наблюдать за Set. */
|
|
71
|
+
collapsedIds: [],
|
|
72
|
+
transform: { x: 0, y: 0, scale: 1 }
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
computed: {
|
|
76
|
+
layout() {
|
|
77
|
+
const e = g(this.data, {
|
|
78
|
+
getId: this.getId,
|
|
79
|
+
getChildren: this.getChildren,
|
|
80
|
+
getParentId: this.getParentId
|
|
81
|
+
});
|
|
82
|
+
return v(f(e, new Set(this.collapsedIds)), this.options);
|
|
83
|
+
},
|
|
84
|
+
canvasStyle() {
|
|
85
|
+
return {
|
|
86
|
+
width: `${this.layout.width}px`,
|
|
87
|
+
height: `${this.layout.height}px`,
|
|
88
|
+
transform: p(this.transform)
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
rootStyle() {
|
|
92
|
+
if (this.size === "content")
|
|
93
|
+
return {
|
|
94
|
+
width: `${this.layout.width * this.transform.scale}px`,
|
|
95
|
+
height: `${this.layout.height * this.transform.scale}px`,
|
|
96
|
+
overflow: "visible"
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
mounted() {
|
|
101
|
+
const e = new c({
|
|
102
|
+
pannable: () => this.pannable,
|
|
103
|
+
zoomable: () => this.zoomable,
|
|
104
|
+
limits: this.scaleLimits ? () => this.scaleLimits : void 0,
|
|
105
|
+
onChange: (t) => {
|
|
106
|
+
this.transform = t, this.$emit("transform", t);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
e.attach(this.$el), o.set(this, e), this.fitOnMount && this.$nextTick(() => this.fit());
|
|
110
|
+
},
|
|
111
|
+
beforeDestroy() {
|
|
112
|
+
o.get(this)?.detach(), o.delete(this);
|
|
113
|
+
},
|
|
114
|
+
methods: {
|
|
115
|
+
/** Вписывает дерево в видимую область. */
|
|
116
|
+
fit(e) {
|
|
117
|
+
o.get(this)?.fit({ width: this.layout.width, height: this.layout.height }, e);
|
|
118
|
+
},
|
|
119
|
+
zoomIn() {
|
|
120
|
+
o.get(this)?.zoomIn();
|
|
121
|
+
},
|
|
122
|
+
zoomOut() {
|
|
123
|
+
o.get(this)?.zoomOut();
|
|
124
|
+
},
|
|
125
|
+
resetTransform() {
|
|
126
|
+
o.get(this)?.reset();
|
|
127
|
+
},
|
|
128
|
+
setTransform(e) {
|
|
129
|
+
o.get(this)?.set(e);
|
|
130
|
+
},
|
|
131
|
+
/** Развернуть все свёрнутые ветки. */
|
|
132
|
+
expandAll() {
|
|
133
|
+
this.collapsedIds = [];
|
|
134
|
+
},
|
|
135
|
+
/** Свернуть или развернуть узел по id. */
|
|
136
|
+
toggle(e) {
|
|
137
|
+
this.collapsedIds = [...h(new Set(this.collapsedIds), e)];
|
|
138
|
+
},
|
|
139
|
+
toggleNode(e) {
|
|
140
|
+
this.toggle(e.id), this.$emit("toggle", e, this.collapsedIds.includes(e.id));
|
|
141
|
+
},
|
|
142
|
+
onNodeClick(e, t) {
|
|
143
|
+
this.$emit("node-click", e, t), this.collapsible && e.hasChildren && this.toggleNode(e);
|
|
144
|
+
},
|
|
145
|
+
nodeStyle(e) {
|
|
146
|
+
return {
|
|
147
|
+
left: `${e.x}px`,
|
|
148
|
+
top: `${e.y}px`,
|
|
149
|
+
width: `${e.width}px`,
|
|
150
|
+
height: `${e.height}px`
|
|
151
|
+
};
|
|
152
|
+
},
|
|
153
|
+
nodeClassOf(e) {
|
|
154
|
+
return typeof this.nodeClass == "function" ? this.nodeClass(e) : this.nodeClass;
|
|
155
|
+
},
|
|
156
|
+
/** Подпись карточки по умолчанию: name → title → label → id. */
|
|
157
|
+
labelOf(e) {
|
|
158
|
+
const t = e.data;
|
|
159
|
+
return t?.name ?? t?.title ?? t?.label ?? e.id;
|
|
160
|
+
},
|
|
161
|
+
/** Своя карточка из scoped-слота или карточка по умолчанию. */
|
|
162
|
+
renderNodeContent(e, t) {
|
|
163
|
+
const s = this.$scopedSlots.node;
|
|
164
|
+
return s ? s({
|
|
165
|
+
node: t,
|
|
166
|
+
data: t.data,
|
|
167
|
+
depth: t.depth,
|
|
168
|
+
collapsed: t.collapsed,
|
|
169
|
+
hasChildren: t.hasChildren,
|
|
170
|
+
toggle: () => this.toggleNode(t)
|
|
171
|
+
}) ?? [] : e(a, {
|
|
172
|
+
props: { label: this.labelOf(t), hasChildren: t.hasChildren, collapsed: t.collapsed },
|
|
173
|
+
on: { toggle: () => this.toggleNode(t) }
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
render(e) {
|
|
178
|
+
const t = this.layout, s = this.$scopedSlots.link, n = t.links.map(
|
|
179
|
+
(i) => s ? s({ link: i }) ?? [] : e("path", { key: i.id, class: "tree-view__link", attrs: { d: i.path } })
|
|
180
|
+
), r = t.nodes.map(
|
|
181
|
+
(i) => e(
|
|
182
|
+
"div",
|
|
183
|
+
{
|
|
184
|
+
key: i.id,
|
|
185
|
+
class: ["tree-view__node", this.nodeClassOf(i)],
|
|
186
|
+
style: this.nodeStyle(i),
|
|
187
|
+
on: { click: (d) => this.onNodeClick(i, d) }
|
|
188
|
+
},
|
|
189
|
+
[].concat(this.renderNodeContent(e, i))
|
|
190
|
+
)
|
|
191
|
+
);
|
|
192
|
+
return e(
|
|
193
|
+
"div",
|
|
194
|
+
{
|
|
195
|
+
class: [
|
|
196
|
+
"tree-view",
|
|
197
|
+
{ "tree-view--pannable": this.pannable, "tree-view--content": this.size === "content" }
|
|
198
|
+
],
|
|
199
|
+
style: this.rootStyle
|
|
200
|
+
},
|
|
201
|
+
[
|
|
202
|
+
e("div", { class: "tree-view__canvas", style: this.canvasStyle }, [
|
|
203
|
+
e(
|
|
204
|
+
"svg",
|
|
205
|
+
{
|
|
206
|
+
class: "tree-view__links",
|
|
207
|
+
attrs: { width: t.width, height: t.height }
|
|
208
|
+
},
|
|
209
|
+
n
|
|
210
|
+
),
|
|
211
|
+
...r
|
|
212
|
+
])
|
|
213
|
+
]
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}), b = ".tree-view{--tv-link-color: #cbd5e1;--tv-link-width: 2px;--tv-node-bg: #ffffff;--tv-node-color: #0f172a;--tv-node-border: 1px solid #e2e8f0;--tv-node-radius: 10px;--tv-node-shadow: 0 1px 2px rgb(15 23 42 / 8%);--tv-node-padding: 8px 12px;--tv-accent: #2563eb;position:relative;width:100%;height:100%;overflow:hidden;touch-action:none}.tree-view--pannable{cursor:grab}.tree-view--content{width:auto;height:auto;overflow:visible}.tree-view__canvas{position:absolute;top:0;left:0;transform-origin:0 0}.tree-view__links{position:absolute;top:0;left:0;overflow:visible;pointer-events:none}.tree-view__link{fill:none;stroke:var(--tv-link-color);stroke-width:var(--tv-link-width)}.tree-view__node{position:absolute;box-sizing:border-box;display:flex;align-items:stretch;justify-content:stretch}.tree-view-card{box-sizing:border-box;display:flex;gap:8px;align-items:center;justify-content:space-between;width:100%;height:100%;padding:var(--tv-node-padding);overflow:hidden;color:var(--tv-node-color);background:var(--tv-node-bg);border:var(--tv-node-border);border-radius:var(--tv-node-radius);box-shadow:var(--tv-node-shadow)}.tree-view-card__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-view-card__toggle{flex:none;width:20px;height:20px;padding:0;font:inherit;line-height:1;color:var(--tv-accent);cursor:pointer;background:none;border:none}";
|
|
217
|
+
u(b);
|
|
218
|
+
const x = {
|
|
219
|
+
install(e) {
|
|
220
|
+
e.component("TreeView", w), e.component("TreeNodeCard", a);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
export {
|
|
224
|
+
k as DEFAULT_OPTIONS,
|
|
225
|
+
a as TreeNodeCard,
|
|
226
|
+
w as TreeView,
|
|
227
|
+
x as TreeViewPlugin,
|
|
228
|
+
x as default
|
|
229
|
+
};
|
|
230
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/TreeNodeCard.ts","../src/TreeView.ts","../src/index.ts"],"sourcesContent":["import Vue from 'vue'\n\n/**\n * Карточка узла по умолчанию для Vue 2.\n * Разметка и классы один в один как в Vue 3 — стили общие.\n */\nexport default Vue.extend({\n name: 'TreeNodeCard',\n props: {\n label: { type: String, required: true },\n hasChildren: { type: Boolean, default: false },\n collapsed: { type: Boolean, default: false },\n },\n render(h) {\n const children = [h('span', { class: 'tree-view-card__label' }, this.label)]\n\n if (this.hasChildren) {\n children.push(\n h(\n 'button',\n {\n class: 'tree-view-card__toggle',\n attrs: {\n type: 'button',\n 'data-tv-no-pan': '',\n 'aria-label': this.collapsed ? 'Развернуть' : 'Свернуть',\n },\n on: {\n click: (event: MouseEvent) => {\n event.stopPropagation()\n this.$emit('toggle')\n },\n },\n },\n this.collapsed ? '+' : '−',\n ),\n )\n }\n\n return h('div', { class: 'tree-view-card' }, children)\n },\n})\n","import Vue, { type PropType, type VNode } from 'vue'\nimport {\n applyCollapsed,\n layoutTree,\n PanZoomController,\n toCssTransform,\n toggleCollapsed,\n toTree,\n type Accessors,\n type Layout,\n type LayoutNode,\n type ScaleLimits,\n type Transform,\n type TreeViewOptions,\n} from '@bigplay/tree-view-core'\nimport TreeNodeCard from './TreeNodeCard'\n\n/** Данные узла могут быть какими угодно — библиотека читает их только аксессорами. */\ntype NodeData = any\n\n/**\n * Контроллеры держим здесь, а не в data(): Vue 2 сделал бы объект реактивным,\n * а внутри него DOM-элемент и Map — наблюдать за ними незачем.\n */\nconst controllers = new WeakMap<Vue, PanZoomController>()\n\nexport default Vue.extend({\n name: 'TreeView',\n props: {\n /** Объект, массив объектов или плоский список (вместе с `getParentId`). */\n data: { type: [Object, Array] as PropType<NodeData>, default: null },\n /** Размеры и направление. Можно передать только часть полей. */\n options: { type: Object as PropType<Partial<TreeViewOptions>>, default: undefined },\n /** Как достать id узла. По умолчанию — поле `id`. */\n getId: { type: Function as PropType<Accessors<NodeData>['getId']>, default: undefined },\n /** Как достать детей. По умолчанию — поле `children`. */\n getChildren: { type: Function as PropType<Accessors<NodeData>['getChildren']>, default: undefined },\n /** Как достать id родителя. Передан — значит данные плоские. */\n getParentId: { type: Function as PropType<Accessors<NodeData>['getParentId']>, default: undefined },\n /** Клик по узлу сворачивает/разворачивает ветку. */\n collapsible: { type: Boolean, default: false },\n /** Разрешить перетаскивание холста. */\n pannable: { type: Boolean, default: true },\n /** Разрешить зум колесом и «щипком». */\n zoomable: { type: Boolean, default: true },\n /** Вписать дерево в контейнер при первом отображении. */\n fitOnMount: { type: Boolean, default: true },\n /**\n * Как компонент занимает место:\n * - `'fill'` (по умолчанию) — растягивается на родителя, лишнее обрезается;\n * - `'content'` — контейнер принимает размер дерева и ничего не обрезает.\n */\n size: { type: String as PropType<'fill' | 'content'>, default: 'fill' },\n /** Пределы масштаба. */\n scaleLimits: { type: Object as PropType<ScaleLimits>, default: undefined },\n /** Дополнительный класс на обёртке узла — строкой или функцией. */\n nodeClass: {\n type: [String, Function] as PropType<string | ((node: LayoutNode<NodeData>) => string)>,\n default: undefined,\n },\n },\n\n data() {\n return {\n /** Массив, а не Set: Vue 2 не умеет наблюдать за Set. */\n collapsedIds: [] as string[],\n transform: { x: 0, y: 0, scale: 1 } as Transform,\n }\n },\n\n computed: {\n layout(): Layout<NodeData> {\n const tree = toTree<NodeData>(this.data, {\n getId: this.getId,\n getChildren: this.getChildren,\n getParentId: this.getParentId,\n })\n\n return layoutTree(applyCollapsed(tree, new Set(this.collapsedIds)), this.options)\n },\n\n canvasStyle(): Record<string, string> {\n return {\n width: `${this.layout.width}px`,\n height: `${this.layout.height}px`,\n transform: toCssTransform(this.transform),\n }\n },\n\n rootStyle(): Record<string, string> | undefined {\n if (this.size !== 'content') return undefined\n\n return {\n width: `${this.layout.width * this.transform.scale}px`,\n height: `${this.layout.height * this.transform.scale}px`,\n overflow: 'visible',\n }\n },\n },\n\n mounted() {\n const controller = new PanZoomController({\n pannable: () => this.pannable,\n zoomable: () => this.zoomable,\n limits: this.scaleLimits ? () => this.scaleLimits : undefined,\n onChange: (transform) => {\n this.transform = transform\n this.$emit('transform', transform)\n },\n })\n\n controller.attach(this.$el as HTMLElement)\n controllers.set(this, controller)\n\n if (this.fitOnMount) this.$nextTick(() => this.fit())\n },\n\n beforeDestroy() {\n controllers.get(this)?.detach()\n controllers.delete(this)\n },\n\n methods: {\n /** Вписывает дерево в видимую область. */\n fit(padding?: number): void {\n controllers.get(this)?.fit({ width: this.layout.width, height: this.layout.height }, padding)\n },\n zoomIn(): void {\n controllers.get(this)?.zoomIn()\n },\n zoomOut(): void {\n controllers.get(this)?.zoomOut()\n },\n resetTransform(): void {\n controllers.get(this)?.reset()\n },\n setTransform(transform: Transform): void {\n controllers.get(this)?.set(transform)\n },\n /** Развернуть все свёрнутые ветки. */\n expandAll(): void {\n this.collapsedIds = []\n },\n /** Свернуть или развернуть узел по id. */\n toggle(id: string): void {\n this.collapsedIds = [...toggleCollapsed(new Set(this.collapsedIds), id)]\n },\n\n toggleNode(node: LayoutNode<NodeData>): void {\n this.toggle(node.id)\n this.$emit('toggle', node, this.collapsedIds.includes(node.id))\n },\n\n onNodeClick(node: LayoutNode<NodeData>, event: MouseEvent): void {\n this.$emit('node-click', node, event)\n if (this.collapsible && node.hasChildren) this.toggleNode(node)\n },\n\n nodeStyle(node: LayoutNode<NodeData>): Record<string, string> {\n return {\n left: `${node.x}px`,\n top: `${node.y}px`,\n width: `${node.width}px`,\n height: `${node.height}px`,\n }\n },\n\n nodeClassOf(node: LayoutNode<NodeData>): string | undefined {\n return typeof this.nodeClass === 'function' ? this.nodeClass(node) : this.nodeClass\n },\n\n /** Подпись карточки по умолчанию: name → title → label → id. */\n labelOf(node: LayoutNode<NodeData>): string {\n const data = node.data as { name?: string; title?: string; label?: string } | null\n return data?.name ?? data?.title ?? data?.label ?? node.id\n },\n\n /** Своя карточка из scoped-слота или карточка по умолчанию. */\n renderNodeContent(h: typeof Vue.prototype.$createElement, node: LayoutNode<NodeData>): VNode | VNode[] {\n const slot = this.$scopedSlots.node\n\n if (slot) {\n return (slot({\n node,\n data: node.data,\n depth: node.depth,\n collapsed: node.collapsed,\n hasChildren: node.hasChildren,\n toggle: () => this.toggleNode(node),\n }) ?? []) as VNode[]\n }\n\n return h(TreeNodeCard, {\n props: { label: this.labelOf(node), hasChildren: node.hasChildren, collapsed: node.collapsed },\n on: { toggle: () => this.toggleNode(node) },\n })\n },\n },\n\n render(h): VNode {\n const layout = this.layout\n const linkSlot = this.$scopedSlots.link\n\n const links = layout.links.map((link) =>\n linkSlot\n ? ((linkSlot({ link }) ?? []) as VNode[])\n : h('path', { key: link.id, class: 'tree-view__link', attrs: { d: link.path } }),\n )\n\n const nodes = layout.nodes.map((node) =>\n h(\n 'div',\n {\n key: node.id,\n class: ['tree-view__node', this.nodeClassOf(node)],\n style: this.nodeStyle(node),\n on: { click: (event: MouseEvent) => this.onNodeClick(node, event) },\n },\n ([] as VNode[]).concat(this.renderNodeContent(h, node)),\n ),\n )\n\n return h(\n 'div',\n {\n class: [\n 'tree-view',\n { 'tree-view--pannable': this.pannable, 'tree-view--content': this.size === 'content' },\n ],\n style: this.rootStyle,\n },\n [\n h('div', { class: 'tree-view__canvas', style: this.canvasStyle }, [\n h(\n 'svg',\n {\n class: 'tree-view__links',\n attrs: { width: layout.width, height: layout.height },\n },\n links as VNode[],\n ),\n ...nodes,\n ]),\n ],\n )\n },\n})\n","import type { VueConstructor } from 'vue'\nimport TreeView from './TreeView'\nimport TreeNodeCard from './TreeNodeCard'\n// Стили общие для Vue 2 и Vue 3 — лежат в core, чтобы не расходились.\n// Они попадают прямо в бандл и подключаются сами: отдельный импорт в проекте не нужен.\nimport { injectStyles } from '@bigplay/tree-view-core'\nimport styles from '@bigplay/tree-view-core/style.css?inline'\n\ninjectStyles(styles)\n\nexport { TreeView, TreeNodeCard }\n\nexport type {\n Accessors,\n Direction,\n Layout,\n LayoutLink,\n LayoutNode,\n LinkStyle,\n ScaleLimits,\n Transform,\n TreeNode,\n TreeViewOptions,\n} from '@bigplay/tree-view-core'\nexport { DEFAULT_OPTIONS } from '@bigplay/tree-view-core'\n\n/** Плагин: `Vue.use(TreeViewPlugin)` регистрирует компоненты глобально. */\nexport const TreeViewPlugin = {\n install(Vue: VueConstructor) {\n Vue.component('TreeView', TreeView)\n Vue.component('TreeNodeCard', TreeNodeCard)\n },\n}\n\nexport default TreeViewPlugin\n"],"names":["TreeNodeCard","Vue","h","children","event","controllers","TreeView","tree","toTree","layoutTree","applyCollapsed","toCssTransform","controller","PanZoomController","transform","padding","id","toggleCollapsed","node","data","slot","layout","linkSlot","links","link","nodes","injectStyles","styles","TreeViewPlugin"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bigplay/tree-view-vue2",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Компонент дерева и турнирных сеток для Vue 2.6 / 2.7",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": [
|
|
8
|
+
"*.css"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"main": "./dist/index.cjs",
|
|
14
|
+
"module": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js",
|
|
20
|
+
"require": "./dist/index.cjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"vue",
|
|
25
|
+
"vue2",
|
|
26
|
+
"tree",
|
|
27
|
+
"bracket",
|
|
28
|
+
"tournament",
|
|
29
|
+
"diagram"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "vite build",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"test:watch": "vitest",
|
|
35
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@bigplay/tree-view-core": "^0.1.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"vue": "^2.6.0 || ^2.7.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^20.19.0",
|
|
45
|
+
"@vue/test-utils": "^1.3.6",
|
|
46
|
+
"happy-dom": "^15.11.7",
|
|
47
|
+
"typescript": "^5.8.3",
|
|
48
|
+
"vite": "^7.1.2",
|
|
49
|
+
"vite-plugin-dts": "^4.5.4",
|
|
50
|
+
"vitest": "^3.2.4",
|
|
51
|
+
"vue": "^2.7.16",
|
|
52
|
+
"vue-template-compiler": "^2.7.16"
|
|
53
|
+
},
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "git+https://github.com/dadashi44/tree-view.git",
|
|
57
|
+
"directory": "packages/vue2"
|
|
58
|
+
},
|
|
59
|
+
"homepage": "https://github.com/dadashi44/tree-view#readme",
|
|
60
|
+
"bugs": {
|
|
61
|
+
"url": "https://github.com/dadashi44/tree-view/issues"
|
|
62
|
+
},
|
|
63
|
+
"author": "Daniyar Kudaibergenev",
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"access": "public"
|
|
66
|
+
}
|
|
67
|
+
}
|