@bigplay/tree-view-vue2 0.2.0 → 0.3.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/dist/BracketRounds.d.ts +33 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +200 -92
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { default as Vue, VNode } from 'vue';
|
|
2
|
+
import { BracketRound, BracketRoundColumn, BracketRoundsModel } from '@bigplay/tree-view-core';
|
|
3
|
+
/**
|
|
4
|
+
* Полоса раундов для Vue 2. Разметка и классы один в один как в Vue 3 —
|
|
5
|
+
* колонки считает та же функция из core, стили общие.
|
|
6
|
+
*/
|
|
7
|
+
declare const _default: import('vue/types/vue').ExtendedVue<Vue<Record<string, any>, Record<string, any>, never, never, (event: string, ...args: any[]) => Vue>, {
|
|
8
|
+
isNarrow: boolean;
|
|
9
|
+
unwatch: null | (() => void);
|
|
10
|
+
}, {
|
|
11
|
+
/**
|
|
12
|
+
* Подводит сетку к матчам раунда.
|
|
13
|
+
*
|
|
14
|
+
* Сначала пробуем по самим карточкам: браузер сам подвинет и страницу, и блок
|
|
15
|
+
* с прокруткой, поэтому финал оказывается на экране целиком, а не только
|
|
16
|
+
* «где-то справа». Карточек не нашли (виртуализация) — считаем по колонкам.
|
|
17
|
+
*/
|
|
18
|
+
scrollToRound(column: BracketRoundColumn): void;
|
|
19
|
+
/** Нажатие — только на узком экране: на широком колонка раунда это просто подпись. */
|
|
20
|
+
onSelect(column: BracketRoundColumn): void;
|
|
21
|
+
renderColumn(h: typeof Vue.prototype.$createElement, column: BracketRoundColumn): VNode;
|
|
22
|
+
}, {
|
|
23
|
+
isClickable: boolean;
|
|
24
|
+
model: BracketRoundsModel;
|
|
25
|
+
}, {
|
|
26
|
+
rounds: BracketRound[];
|
|
27
|
+
nodeWidth: number;
|
|
28
|
+
levelGap: number;
|
|
29
|
+
isShow: boolean;
|
|
30
|
+
scrollOnClick: boolean;
|
|
31
|
+
mobileQuery: string;
|
|
32
|
+
}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin>;
|
|
33
|
+
export default _default;
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const l=require("vue"),r=require("@bigplay/tree-view-core"),n=l.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:i=>{i.stopPropagation(),this.$emit("toggle")}}},this.collapsed?"+":"−")),e("div",{class:"tree-view-card"},t)}}),o=new WeakMap,d=l.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},virtualize:{type:Boolean,default:!0},overscan:{type:Number,default:r.DEFAULT_OVERSCAN}},data(){return{collapsedIds:[],transform:{x:0,y:0,scale:1},visibleRect:this.virtualize?r.estimateVisibleRect():null}},computed:{layout(){const e=r.toTree(this.data,{getId:this.getId,getChildren:this.getChildren,getParentId:this.getParentId});return r.layoutTree(r.applyCollapsed(e,new Set(this.collapsedIds)),this.options)},drawn(){return this.virtualize?r.visibleLayout(this.layout,this.visibleRect,this.overscan):this.layout},canvasStyle(){return{width:`${this.layout.width}px`,height:`${this.layout.height}px`,transform:r.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"}}},watch:{layout(){this.$nextTick(()=>this.updateVisibleRect())}},mounted(){const e=new r.PanZoomController({pannable:()=>this.pannable,zoomable:()=>this.zoomable,limits:this.scaleLimits?()=>this.scaleLimits:void 0,onChange:t=>{this.transform=t,this.updateVisibleRect(),this.$emit("transform",t)}});e.attach(this.$el),o.set(this,e),this.updateVisibleRect(),window.addEventListener("scroll",this.updateVisibleRect,{passive:!0,capture:!0}),window.addEventListener("resize",this.updateVisibleRect,{passive:!0}),this.fitOnMount&&this.$nextTick(()=>this.fit())},beforeDestroy(){o.get(this)?.detach(),o.delete(this),window.removeEventListener("scroll",this.updateVisibleRect,{capture:!0}),window.removeEventListener("resize",this.updateVisibleRect)},methods:{updateVisibleRect(){this.visibleRect=this.virtualize?r.measureVisibleRect(this.$refs.canvas,this.transform.scale):null},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=[...r.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 i=this.$scopedSlots.node;return i?i({node:t,data:t.data,depth:t.depth,collapsed:t.collapsed,hasChildren:t.hasChildren,toggle:()=>this.toggleNode(t)})??[]:e(n,{props:{label:this.labelOf(t),hasChildren:t.hasChildren,collapsed:t.collapsed},on:{toggle:()=>this.toggleNode(t)}})}},render(e){const t=this.layout,i=this.drawn,s=this.$scopedSlots.link,p=i.links.map(a=>s?s({link:a})??[]:e("path",{key:a.id,class:"tree-view__link",attrs:{d:a.path}})),v=i.nodes.map(a=>e("div",{key:a.id,class:["tree-view__node",this.nodeClassOf(a)],style:this.nodeStyle(a),on:{click:u=>this.onNodeClick(a,u)}},[].concat(this.renderNodeContent(e,a))));return e("div",{class:["tree-view",{"tree-view--pannable":this.pannable,"tree-view--content":this.size==="content"}],style:this.rootStyle},[e("div",{ref:"canvas",class:"tree-view__canvas",style:this.canvasStyle},[e("svg",{class:"tree-view__links",attrs:{width:t.width,height:t.height}},p),...v])])}}),c=l.extend({name:"BracketCard",props:{match:{type:Object,default:null},rows:{type:Number,default:void 0},myTeamHint:{type:String,default:"Нажми для перехода в матч 👇"},techDefeatLabel:{type:String,default:"ТП"},techDefeatHint:{type:String,default:"Техническое поражение"}},data(){return{hoveredKey:null}},computed:{card(){return r.buildBracketCard(this.match,{rows:this.rows,techDefeatLabel:this.techDefeatLabel})}},methods:{renderRow(e,t){const i=[];return t.team&&(t.isTechDefeat&&this.hoveredKey===t.key&&i.push(e("span",{class:"tv-bracket__tooltip"},this.techDefeatHint)),i.push(e("span",{class:"tv-bracket__name"},t.team.name)),i.push(e("span",{class:"tv-bracket__score"},t.score))),e("div",{key:t.key,class:["tv-bracket__row",{"tv-bracket__row--winner":t.isWinner,"tv-bracket__row--loser":t.isLoser&&!t.isEmpty,"tv-bracket__row--my":t.isMyTeam,"tv-bracket__row--empty":t.isEmpty}],attrs:t.isMyTeam?{title:"Моя команда"}:{},on:{click:()=>{t.team&&this.$emit("select",t.team,t)},mouseenter:()=>{this.hoveredKey=t.key},mouseleave:()=>{this.hoveredKey=null}}},i)}},render(e){const t=this.card,i=[];t.hasMyTeam&&this.myTeamHint&&i.push(e("div",{class:"tv-bracket__hint"},this.myTeamHint));for(const s of t.rows)i.push(this.renderRow(e,s));return e("div",{class:["tv-bracket",{"tv-bracket--my-team":t.hasMyTeam}]},i)}}),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}.tv-bracket{--tv-bracket-winner-bg: #0427c4;--tv-bracket-winner-color: #ffffff;--tv-bracket-loser-bg: #e5e5e5;--tv-bracket-loser-color: #7d7d8d;--tv-bracket-my-bg: #00146c;--tv-bracket-my-color: #ffffff;--tv-bracket-radius: 6px;position:relative;box-sizing:border-box;display:flex;flex-direction:column;width:100%;height:100%;font-size:12px}.tv-bracket--my-team{border-radius:var(--tv-bracket-radius);outline:2px solid var(--tv-bracket-my-bg)}.tv-bracket__hint{position:absolute;right:0;bottom:100%;left:0;padding:3px 8px;overflow:hidden;font-size:11px;font-weight:600;line-height:1.2;color:var(--tv-bracket-my-color);text-align:center;text-overflow:ellipsis;white-space:nowrap;background:var(--tv-bracket-my-bg);border-radius:var(--tv-bracket-radius) var(--tv-bracket-radius) 0 0}.tv-bracket__row{position:relative;box-sizing:border-box;display:flex;flex:1 1 0;align-items:center;justify-content:space-between;min-height:0;padding:4px 8px;cursor:pointer;transition:all 75ms}.tv-bracket__row--winner{font-weight:700;color:var(--tv-bracket-winner-color);background:var(--tv-bracket-winner-bg)}.tv-bracket__row--loser{color:var(--tv-bracket-loser-color);background:var(--tv-bracket-loser-bg)}.tv-bracket__row--my{color:var(--tv-bracket-my-color);background:var(--tv-bracket-my-bg)}.tv-bracket__row--empty{cursor:default;background:var(--tv-bracket-loser-bg)}.tv-bracket__name{max-width:120px;overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.tv-bracket__score{display:flex;flex:none;align-items:center;justify-content:center;width:20px;height:20px;font-weight:700;font-variant-numeric:tabular-nums}.tv-bracket__tooltip{position:absolute;top:-26px;left:6px;z-index:5000;padding:4px 8px;font-weight:400;color:var(--tv-bracket-loser-color);white-space:nowrap;background:#fff;border:1px solid #d1d5db;border-radius:4px;box-shadow:0 4px 10px #0f172a26}";r.injectStyles(b);const h={install(e){e.component("TreeView",d),e.component("TreeNodeCard",n),e.component("BracketCard",c)}};Object.defineProperty(exports,"DEFAULT_OPTIONS",{enumerable:!0,get:()=>r.DEFAULT_OPTIONS});Object.defineProperty(exports,"bracketCardHeight",{enumerable:!0,get:()=>r.bracketCardHeight});Object.defineProperty(exports,"buildBracketCard",{enumerable:!0,get:()=>r.buildBracketCard});exports.BracketCard=c;exports.TreeNodeCard=n;exports.TreeView=d;exports.TreeViewPlugin=h;exports.default=h;
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const d=require("vue"),i=require("@bigplay/tree-view-core"),c=d.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:r=>{r.stopPropagation(),this.$emit("toggle")}}},this.collapsed?"+":"−")),e("div",{class:"tree-view-card"},t)}}),s=new WeakMap,h=d.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},virtualize:{type:Boolean,default:!0},overscan:{type:Number,default:i.DEFAULT_OVERSCAN}},data(){return{collapsedIds:[],transform:{x:0,y:0,scale:1},visibleRect:this.virtualize?i.estimateVisibleRect():null}},computed:{layout(){const e=i.toTree(this.data,{getId:this.getId,getChildren:this.getChildren,getParentId:this.getParentId});return i.layoutTree(i.applyCollapsed(e,new Set(this.collapsedIds)),this.options)},drawn(){return this.virtualize?i.visibleLayout(this.layout,this.visibleRect,this.overscan):this.layout},canvasStyle(){return{width:`${this.layout.width}px`,height:`${this.layout.height}px`,transform:i.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"}}},watch:{layout(){this.$nextTick(()=>this.updateVisibleRect())}},mounted(){const e=new i.PanZoomController({pannable:()=>this.pannable,zoomable:()=>this.zoomable,limits:this.scaleLimits?()=>this.scaleLimits:void 0,onChange:t=>{this.transform=t,this.updateVisibleRect(),this.$emit("transform",t)}});e.attach(this.$el),s.set(this,e),this.updateVisibleRect(),window.addEventListener("scroll",this.updateVisibleRect,{passive:!0,capture:!0}),window.addEventListener("resize",this.updateVisibleRect,{passive:!0}),this.fitOnMount&&this.$nextTick(()=>this.fit())},beforeDestroy(){s.get(this)?.detach(),s.delete(this),window.removeEventListener("scroll",this.updateVisibleRect,{capture:!0}),window.removeEventListener("resize",this.updateVisibleRect)},methods:{updateVisibleRect(){this.visibleRect=this.virtualize?i.measureVisibleRect(this.$refs.canvas,this.transform.scale):null},fit(e){s.get(this)?.fit({width:this.layout.width,height:this.layout.height},e)},zoomIn(){s.get(this)?.zoomIn()},zoomOut(){s.get(this)?.zoomOut()},resetTransform(){s.get(this)?.reset()},setTransform(e){s.get(this)?.set(e)},expandAll(){this.collapsedIds=[]},toggle(e){this.collapsedIds=[...i.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 r=this.$scopedSlots.node;return r?r({node:t,data:t.data,depth:t.depth,collapsed:t.collapsed,hasChildren:t.hasChildren,toggle:()=>this.toggleNode(t)})??[]:e(c,{props:{label:this.labelOf(t),hasChildren:t.hasChildren,collapsed:t.collapsed},on:{toggle:()=>this.toggleNode(t)}})}},render(e){const t=this.layout,r=this.drawn,a=this.$scopedSlots.link,l=r.links.map(o=>a?a({link:o})??[]:e("path",{key:o.id,class:"tree-view__link",attrs:{d:o.path}})),n=r.nodes.map(o=>e("div",{key:o.id,class:["tree-view__node",this.nodeClassOf(o)],style:this.nodeStyle(o),on:{click:b=>this.onNodeClick(o,b)}},[].concat(this.renderNodeContent(e,o))));return e("div",{class:["tree-view",{"tree-view--pannable":this.pannable,"tree-view--content":this.size==="content"}],style:this.rootStyle},[e("div",{ref:"canvas",class:"tree-view__canvas",style:this.canvasStyle},[e("svg",{class:"tree-view__links",attrs:{width:t.width,height:t.height}},l),...n])])}}),u=d.extend({name:"BracketCard",props:{match:{type:Object,default:null},rows:{type:Number,default:void 0},myTeamHint:{type:String,default:"Нажми для перехода в матч 👇"},techDefeatLabel:{type:String,default:"ТП"},techDefeatHint:{type:String,default:"Техническое поражение"}},data(){return{hoveredKey:null}},computed:{card(){return i.buildBracketCard(this.match,{rows:this.rows,techDefeatLabel:this.techDefeatLabel})}},methods:{renderRow(e,t){const r=[];return t.team&&(t.isTechDefeat&&this.hoveredKey===t.key&&r.push(e("span",{class:"tv-bracket__tooltip"},this.techDefeatHint)),r.push(e("span",{class:"tv-bracket__name"},t.team.name)),r.push(e("span",{class:"tv-bracket__score"},t.score))),e("div",{key:t.key,class:["tv-bracket__row",{"tv-bracket__row--winner":t.isWinner,"tv-bracket__row--loser":t.isLoser&&!t.isEmpty,"tv-bracket__row--my":t.isMyTeam,"tv-bracket__row--empty":t.isEmpty}],attrs:t.isMyTeam?{title:"Моя команда"}:{},on:{click:()=>{t.team&&this.$emit("select",t.team,t)},mouseenter:()=>{this.hoveredKey=t.key},mouseleave:()=>{this.hoveredKey=null}}},r)}},render(e){const t=this.card,r=[];t.hasMyTeam&&this.myTeamHint&&r.push(e("div",{class:"tv-bracket__hint"},this.myTeamHint));for(const a of t.rows)r.push(this.renderRow(e,a));return e("div",{class:["tv-bracket",{"tv-bracket--my-team":t.hasMyTeam}]},r)}}),p=d.extend({name:"BracketRounds",props:{rounds:{type:Array,default:()=>[]},nodeWidth:{type:Number,default:180},levelGap:{type:Number,default:60},isShow:{type:Boolean,default:!0},scrollOnClick:{type:Boolean,default:void 0},mobileQuery:{type:String,default:i.MOBILE_MEDIA_QUERY}},data(){return{isNarrow:!1,unwatch:null}},computed:{isClickable(){return this.isShow&&(this.scrollOnClick===void 0?this.isNarrow:this.scrollOnClick)},model(){return i.buildBracketRounds(this.rounds,{nodeWidth:this.nodeWidth,levelGap:this.levelGap})}},mounted(){this.unwatch=i.watchMedia(this.mobileQuery,e=>{this.isNarrow=e})},beforeDestroy(){this.unwatch?.()},methods:{scrollToRound(e){const t=this.$refs.content,r=t?i.nodesInColumn(t,e.index,e.width,this.model.offset):[],a=r[Math.floor(r.length/2)];if(a&&i.scrollToNode(a))return;const l=this.$el,n=i.findScrollParent(l);if(!l||!n)return;const o=i.offsetWithin(l,n)+e.index*e.width;i.smoothScrollLeft(n,i.roundScrollLeft({left:o,width:e.width,viewport:n.clientWidth,scrollWidth:n.scrollWidth}))},onSelect(e){this.isClickable&&(this.$emit("select",e),this.scrollToRound(e))},renderColumn(e,t){return e("div",{key:t.key,class:"tv-rounds__item",style:{width:`${t.width}px`},on:{click:()=>this.onSelect(t)}},this.$scopedSlots.round?.({round:t})??t.name)}},render(e){const t=[];return this.isShow&&t.push(e("div",{class:"tv-rounds__bar",style:{width:`${this.model.width}px`}},this.model.columns.map(r=>this.renderColumn(e,r)))),t.push(e("div",{ref:"content",class:"tv-rounds__content",style:this.isShow?{paddingLeft:`${this.model.offset}px`}:{}},this.$slots.default)),e("div",{class:"tv-rounds"},t)}}),f=".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}.tv-bracket{--tv-bracket-winner-bg: #0427c4;--tv-bracket-winner-color: #ffffff;--tv-bracket-loser-bg: #e5e5e5;--tv-bracket-loser-color: #7d7d8d;--tv-bracket-my-bg: #00146c;--tv-bracket-my-color: #ffffff;--tv-bracket-radius: 6px;position:relative;box-sizing:border-box;display:flex;flex-direction:column;width:100%;height:100%;font-size:12px}.tv-bracket--my-team{border-radius:var(--tv-bracket-radius);outline:2px solid var(--tv-bracket-my-bg)}.tv-bracket__hint{position:absolute;right:0;bottom:100%;left:0;padding:3px 8px;overflow:hidden;font-size:11px;font-weight:600;line-height:1.2;color:var(--tv-bracket-my-color);text-align:center;text-overflow:ellipsis;white-space:nowrap;background:var(--tv-bracket-my-bg);border-radius:var(--tv-bracket-radius) var(--tv-bracket-radius) 0 0}.tv-bracket__row{position:relative;box-sizing:border-box;display:flex;flex:1 1 0;align-items:center;justify-content:space-between;min-height:0;padding:4px 8px;cursor:pointer;transition:all 75ms}.tv-bracket__row--winner{font-weight:700;color:var(--tv-bracket-winner-color);background:var(--tv-bracket-winner-bg)}.tv-bracket__row--loser{color:var(--tv-bracket-loser-color);background:var(--tv-bracket-loser-bg)}.tv-bracket__row--my{color:var(--tv-bracket-my-color);background:var(--tv-bracket-my-bg)}.tv-bracket__row--empty{cursor:default;background:var(--tv-bracket-loser-bg)}.tv-bracket__name{max-width:120px;overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.tv-bracket__score{display:flex;flex:none;align-items:center;justify-content:center;width:20px;height:20px;font-weight:700;font-variant-numeric:tabular-nums}.tv-bracket__tooltip{position:absolute;top:-26px;left:6px;z-index:5000;padding:4px 8px;font-weight:400;color:var(--tv-bracket-loser-color);white-space:nowrap;background:#fff;border:1px solid #d1d5db;border-radius:4px;box-shadow:0 4px 10px #0f172a26}.tv-rounds{--tv-rounds-bg: #f5f5f7;--tv-rounds-color: #9ca3af;--tv-rounds-border: 2px solid #e5e7eb;--tv-rounds-gap: 20px;display:flex;flex-direction:column;width:max-content;min-width:100%}.tv-rounds__bar{display:flex;min-width:100%;margin-bottom:var(--tv-rounds-gap);background:var(--tv-rounds-bg);border-bottom:var(--tv-rounds-border)}.tv-rounds__item{flex:none;box-sizing:border-box;padding:10px 20px;font:inherit;font-size:14px;font-weight:600;color:var(--tv-rounds-color);text-align:center;text-transform:uppercase;white-space:nowrap;background:none;border:none;border-right:var(--tv-rounds-border)}";i.injectStyles(f);const v={install(e){e.component("TreeView",h),e.component("TreeNodeCard",c),e.component("BracketCard",u),e.component("BracketRounds",p)}};Object.defineProperty(exports,"DEFAULT_OPTIONS",{enumerable:!0,get:()=>i.DEFAULT_OPTIONS});Object.defineProperty(exports,"MOBILE_MEDIA_QUERY",{enumerable:!0,get:()=>i.MOBILE_MEDIA_QUERY});Object.defineProperty(exports,"bracketCardHeight",{enumerable:!0,get:()=>i.bracketCardHeight});Object.defineProperty(exports,"buildBracketCard",{enumerable:!0,get:()=>i.buildBracketCard});Object.defineProperty(exports,"buildBracketRounds",{enumerable:!0,get:()=>i.buildBracketRounds});exports.BracketCard=u;exports.BracketRounds=p;exports.TreeNodeCard=c;exports.TreeView=h;exports.TreeViewPlugin=v;exports.default=v;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/TreeNodeCard.ts","../src/TreeView.ts","../src/BracketCard.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 DEFAULT_OVERSCAN,\n estimateVisibleRect,\n layoutTree,\n measureVisibleRect,\n PanZoomController,\n toCssTransform,\n toggleCollapsed,\n toTree,\n visibleLayout,\n type Accessors,\n type Layout,\n type LayoutNode,\n type Rect,\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 * Рисовать только то, что видно на экране. На больших сетках в DOM\n * попадает несколько десятков карточек вместо тысячи.\n */\n virtualize: { type: Boolean, default: true },\n /** Запас вокруг видимой области в пикселях. */\n overscan: { type: Number, default: DEFAULT_OVERSCAN },\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 * Видимая часть холста; `null` — рисуем всё.\n * До первого измерения берём размер окна: иначе первый кадр\n * нарисует дерево целиком и тут же выбросит лишнее.\n */\n visibleRect: (this.virtualize ? estimateVisibleRect() : null) as Rect | null,\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 /** То, что реально попадёт в DOM: при `virtualize` — только видимая часть. */\n drawn(): Layout<NodeData> {\n return this.virtualize ? visibleLayout(this.layout, this.visibleRect, this.overscan) : this.layout\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 watch: {\n // Новые данные — видимую часть надо пересчитать уже по ним.\n layout() {\n this.$nextTick(() => this.updateVisibleRect())\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 // Холст поехал — видимая часть стала другой.\n this.updateVisibleRect()\n this.$emit('transform', transform)\n },\n })\n\n controller.attach(this.$el as HTMLElement)\n controllers.set(this, controller)\n\n this.updateVisibleRect()\n window.addEventListener('scroll', this.updateVisibleRect, { passive: true, capture: true })\n window.addEventListener('resize', this.updateVisibleRect, { passive: true })\n\n if (this.fitOnMount) this.$nextTick(() => this.fit())\n },\n\n beforeDestroy() {\n controllers.get(this)?.detach()\n controllers.delete(this)\n window.removeEventListener('scroll', this.updateVisibleRect, { capture: true } as EventListenerOptions)\n window.removeEventListener('resize', this.updateVisibleRect)\n },\n\n methods: {\n /** Пересчитывает, какая часть холста сейчас видна на экране. */\n updateVisibleRect(): void {\n this.visibleRect = this.virtualize\n ? measureVisibleRect(this.$refs.canvas as Element | undefined, this.transform.scale)\n : null\n },\n\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 drawn = this.drawn\n const linkSlot = this.$scopedSlots.link\n\n const links = drawn.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 = drawn.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', { ref: 'canvas', 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 Vue, { type PropType, type VNode } from 'vue'\nimport {\n buildBracketCard,\n type BracketCardMatch,\n type BracketCardRow,\n} from '@bigplay/tree-view-core'\n\n/**\n * Карточка матча для Vue 2. Разметка и классы один в один как в Vue 3 —\n * строки считает та же функция из core, стили общие.\n */\nexport default Vue.extend({\n name: 'BracketCard',\n props: {\n /** Матч: нужны только команды. */\n match: { type: Object as PropType<BracketCardMatch | null>, default: null },\n /** Сколько строк рисовать. У финала — одна. */\n rows: { type: Number, default: undefined },\n /** Подсказка над карточкой с моей командой. Пустая строка — не показывать. */\n myTeamHint: { type: String, default: 'Нажми для перехода в матч 👇' },\n /** Текст в ячейке счёта при техническом поражении. */\n techDefeatLabel: { type: String, default: 'ТП' },\n /** Подсказка по наведению на техническое поражение. */\n techDefeatHint: { type: String, default: 'Техническое поражение' },\n },\n\n data() {\n return { hoveredKey: null as string | null }\n },\n\n computed: {\n card(): ReturnType<typeof buildBracketCard> {\n return buildBracketCard(this.match, { rows: this.rows, techDefeatLabel: this.techDefeatLabel })\n },\n },\n\n methods: {\n renderRow(h: typeof Vue.prototype.$createElement, row: BracketCardRow): VNode {\n const content: VNode[] = []\n\n if (row.team) {\n if (row.isTechDefeat && this.hoveredKey === row.key) {\n content.push(h('span', { class: 'tv-bracket__tooltip' }, this.techDefeatHint))\n }\n content.push(h('span', { class: 'tv-bracket__name' }, row.team.name))\n content.push(h('span', { class: 'tv-bracket__score' }, row.score))\n }\n\n return h(\n 'div',\n {\n key: row.key,\n class: [\n 'tv-bracket__row',\n {\n 'tv-bracket__row--winner': row.isWinner,\n 'tv-bracket__row--loser': row.isLoser && !row.isEmpty,\n 'tv-bracket__row--my': row.isMyTeam,\n 'tv-bracket__row--empty': row.isEmpty,\n },\n ],\n attrs: row.isMyTeam ? { title: 'Моя команда' } : {},\n on: {\n click: () => {\n if (row.team) this.$emit('select', row.team, row)\n },\n mouseenter: () => {\n this.hoveredKey = row.key\n },\n mouseleave: () => {\n this.hoveredKey = null\n },\n },\n },\n content,\n )\n },\n },\n\n render(h): VNode {\n const card = this.card\n const children: VNode[] = []\n\n if (card.hasMyTeam && this.myTeamHint) {\n children.push(h('div', { class: 'tv-bracket__hint' }, this.myTeamHint))\n }\n\n for (const row of card.rows) children.push(this.renderRow(h, row))\n\n return h('div', { class: ['tv-bracket', { 'tv-bracket--my-team': card.hasMyTeam }] }, children)\n },\n})\n","import type { VueConstructor } from 'vue'\nimport TreeView from './TreeView'\nimport TreeNodeCard from './TreeNodeCard'\nimport BracketCard from './BracketCard'\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, BracketCard }\n\nexport type {\n Accessors,\n BracketCardMatch,\n BracketCardModel,\n BracketCardOptions,\n BracketCardRow,\n BracketCardTeam,\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, buildBracketCard, bracketCardHeight } 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 Vue.component('BracketCard', BracketCard)\n },\n}\n\nexport default TreeViewPlugin\n"],"names":["TreeNodeCard","Vue","h","children","event","controllers","TreeView","DEFAULT_OVERSCAN","estimateVisibleRect","tree","toTree","layoutTree","applyCollapsed","visibleLayout","toCssTransform","controller","PanZoomController","transform","measureVisibleRect","padding","id","toggleCollapsed","node","data","slot","layout","drawn","linkSlot","links","link","nodes","BracketCard","buildBracketCard","row","content","card","injectStyles","styles","TreeViewPlugin"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/TreeNodeCard.ts","../src/TreeView.ts","../src/BracketCard.ts","../src/BracketRounds.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 DEFAULT_OVERSCAN,\n estimateVisibleRect,\n layoutTree,\n measureVisibleRect,\n PanZoomController,\n toCssTransform,\n toggleCollapsed,\n toTree,\n visibleLayout,\n type Accessors,\n type Layout,\n type LayoutNode,\n type Rect,\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 * Рисовать только то, что видно на экране. На больших сетках в DOM\n * попадает несколько десятков карточек вместо тысячи.\n */\n virtualize: { type: Boolean, default: true },\n /** Запас вокруг видимой области в пикселях. */\n overscan: { type: Number, default: DEFAULT_OVERSCAN },\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 * Видимая часть холста; `null` — рисуем всё.\n * До первого измерения берём размер окна: иначе первый кадр\n * нарисует дерево целиком и тут же выбросит лишнее.\n */\n visibleRect: (this.virtualize ? estimateVisibleRect() : null) as Rect | null,\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 /** То, что реально попадёт в DOM: при `virtualize` — только видимая часть. */\n drawn(): Layout<NodeData> {\n return this.virtualize ? visibleLayout(this.layout, this.visibleRect, this.overscan) : this.layout\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 watch: {\n // Новые данные — видимую часть надо пересчитать уже по ним.\n layout() {\n this.$nextTick(() => this.updateVisibleRect())\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 // Холст поехал — видимая часть стала другой.\n this.updateVisibleRect()\n this.$emit('transform', transform)\n },\n })\n\n controller.attach(this.$el as HTMLElement)\n controllers.set(this, controller)\n\n this.updateVisibleRect()\n window.addEventListener('scroll', this.updateVisibleRect, { passive: true, capture: true })\n window.addEventListener('resize', this.updateVisibleRect, { passive: true })\n\n if (this.fitOnMount) this.$nextTick(() => this.fit())\n },\n\n beforeDestroy() {\n controllers.get(this)?.detach()\n controllers.delete(this)\n window.removeEventListener('scroll', this.updateVisibleRect, { capture: true } as EventListenerOptions)\n window.removeEventListener('resize', this.updateVisibleRect)\n },\n\n methods: {\n /** Пересчитывает, какая часть холста сейчас видна на экране. */\n updateVisibleRect(): void {\n this.visibleRect = this.virtualize\n ? measureVisibleRect(this.$refs.canvas as Element | undefined, this.transform.scale)\n : null\n },\n\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 drawn = this.drawn\n const linkSlot = this.$scopedSlots.link\n\n const links = drawn.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 = drawn.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', { ref: 'canvas', 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 Vue, { type PropType, type VNode } from 'vue'\nimport {\n buildBracketCard,\n type BracketCardMatch,\n type BracketCardRow,\n} from '@bigplay/tree-view-core'\n\n/**\n * Карточка матча для Vue 2. Разметка и классы один в один как в Vue 3 —\n * строки считает та же функция из core, стили общие.\n */\nexport default Vue.extend({\n name: 'BracketCard',\n props: {\n /** Матч: нужны только команды. */\n match: { type: Object as PropType<BracketCardMatch | null>, default: null },\n /** Сколько строк рисовать. У финала — одна. */\n rows: { type: Number, default: undefined },\n /** Подсказка над карточкой с моей командой. Пустая строка — не показывать. */\n myTeamHint: { type: String, default: 'Нажми для перехода в матч 👇' },\n /** Текст в ячейке счёта при техническом поражении. */\n techDefeatLabel: { type: String, default: 'ТП' },\n /** Подсказка по наведению на техническое поражение. */\n techDefeatHint: { type: String, default: 'Техническое поражение' },\n },\n\n data() {\n return { hoveredKey: null as string | null }\n },\n\n computed: {\n card(): ReturnType<typeof buildBracketCard> {\n return buildBracketCard(this.match, { rows: this.rows, techDefeatLabel: this.techDefeatLabel })\n },\n },\n\n methods: {\n renderRow(h: typeof Vue.prototype.$createElement, row: BracketCardRow): VNode {\n const content: VNode[] = []\n\n if (row.team) {\n if (row.isTechDefeat && this.hoveredKey === row.key) {\n content.push(h('span', { class: 'tv-bracket__tooltip' }, this.techDefeatHint))\n }\n content.push(h('span', { class: 'tv-bracket__name' }, row.team.name))\n content.push(h('span', { class: 'tv-bracket__score' }, row.score))\n }\n\n return h(\n 'div',\n {\n key: row.key,\n class: [\n 'tv-bracket__row',\n {\n 'tv-bracket__row--winner': row.isWinner,\n 'tv-bracket__row--loser': row.isLoser && !row.isEmpty,\n 'tv-bracket__row--my': row.isMyTeam,\n 'tv-bracket__row--empty': row.isEmpty,\n },\n ],\n attrs: row.isMyTeam ? { title: 'Моя команда' } : {},\n on: {\n click: () => {\n if (row.team) this.$emit('select', row.team, row)\n },\n mouseenter: () => {\n this.hoveredKey = row.key\n },\n mouseleave: () => {\n this.hoveredKey = null\n },\n },\n },\n content,\n )\n },\n },\n\n render(h): VNode {\n const card = this.card\n const children: VNode[] = []\n\n if (card.hasMyTeam && this.myTeamHint) {\n children.push(h('div', { class: 'tv-bracket__hint' }, this.myTeamHint))\n }\n\n for (const row of card.rows) children.push(this.renderRow(h, row))\n\n return h('div', { class: ['tv-bracket', { 'tv-bracket--my-team': card.hasMyTeam }] }, children)\n },\n})\n","import Vue, { type PropType, type VNode } from 'vue'\nimport {\n MOBILE_MEDIA_QUERY,\n buildBracketRounds,\n findScrollParent,\n nodesInColumn,\n offsetWithin,\n roundScrollLeft,\n scrollToNode,\n smoothScrollLeft,\n watchMedia,\n type BracketRound,\n type BracketRoundColumn,\n type BracketRoundsModel,\n} from '@bigplay/tree-view-core'\n\n/**\n * Полоса раундов для Vue 2. Разметка и классы один в один как в Vue 3 —\n * колонки считает та же функция из core, стили общие.\n */\nexport default Vue.extend({\n name: 'BracketRounds',\n props: {\n /** Раунды по порядку — от первого к финалу. */\n rounds: { type: Array as PropType<BracketRound[]>, default: () => [] },\n /** Ширина карточки матча — то же число, что в `nodeWidth` у сетки. */\n nodeWidth: { type: Number, default: 180 },\n /** Промежуток между раундами — то же число, что в `levelGap` у сетки. */\n levelGap: { type: Number, default: 60 },\n /** Показывать полосу. Содержимое слота рисуется в любом случае. */\n isShow: { type: Boolean, default: true },\n /** Нажатие на раунд подводит к нему сетку. Не передан — решает ширина экрана. */\n scrollOnClick: { type: Boolean, default: undefined },\n /** Медиавыражение «узкий экран», при котором нажатие включается. */\n mobileQuery: { type: String, default: MOBILE_MEDIA_QUERY },\n },\n\n data() {\n return {\n // Узкий ли экран. До монтирования — нет: на сервере ширину знать неоткуда.\n isNarrow: false,\n unwatch: null as null | (() => void),\n }\n },\n\n computed: {\n /** Полосы нет — нажимать не на что. */\n isClickable(): boolean {\n return this.isShow && (this.scrollOnClick === undefined ? this.isNarrow : this.scrollOnClick)\n },\n\n model(): BracketRoundsModel {\n return buildBracketRounds(this.rounds, {\n nodeWidth: this.nodeWidth,\n levelGap: this.levelGap,\n })\n },\n },\n\n mounted() {\n this.unwatch = watchMedia(this.mobileQuery, (matches) => {\n this.isNarrow = matches\n })\n },\n\n beforeDestroy() {\n this.unwatch?.()\n },\n\n methods: {\n /**\n * Подводит сетку к матчам раунда.\n *\n * Сначала пробуем по самим карточкам: браузер сам подвинет и страницу, и блок\n * с прокруткой, поэтому финал оказывается на экране целиком, а не только\n * «где-то справа». Карточек не нашли (виртуализация) — считаем по колонкам.\n */\n scrollToRound(column: BracketRoundColumn): void {\n const content = this.$refs.content as HTMLElement | undefined\n const matches = content\n ? nodesInColumn(content, column.index, column.width, this.model.offset)\n : []\n const middle = matches[Math.floor(matches.length / 2)]\n\n if (middle && scrollToNode(middle)) return\n\n const element = this.$el as HTMLElement | null\n const container = findScrollParent(element)\n if (!element || !container) return\n\n const left = offsetWithin(element, container) + column.index * column.width\n\n smoothScrollLeft(\n container,\n roundScrollLeft({\n left,\n width: column.width,\n viewport: container.clientWidth,\n scrollWidth: container.scrollWidth,\n }),\n )\n },\n\n /** Нажатие — только на узком экране: на широком колонка раунда это просто подпись. */\n onSelect(column: BracketRoundColumn): void {\n if (!this.isClickable) return\n\n this.$emit('select', column)\n this.scrollToRound(column)\n },\n\n renderColumn(h: typeof Vue.prototype.$createElement, column: BracketRoundColumn): VNode {\n return h(\n 'div',\n {\n key: column.key,\n class: 'tv-rounds__item',\n style: { width: `${column.width}px` },\n on: { click: () => this.onSelect(column) },\n },\n this.$scopedSlots.round?.({ round: column }) ?? column.name,\n )\n },\n },\n\n render(h): VNode {\n const children: VNode[] = []\n\n if (this.isShow) {\n children.push(\n h(\n 'div',\n { class: 'tv-rounds__bar', style: { width: `${this.model.width}px` } },\n this.model.columns.map((column) => this.renderColumn(h, column)),\n ),\n )\n }\n\n children.push(\n h(\n 'div',\n {\n ref: 'content',\n class: 'tv-rounds__content',\n // Сюда кладут саму сетку: ей достаётся отступ, центрующий матчи.\n style: this.isShow ? { paddingLeft: `${this.model.offset}px` } : {},\n },\n this.$slots.default,\n ),\n )\n\n return h('div', { class: 'tv-rounds' }, children)\n },\n})\n","import type { VueConstructor } from 'vue'\nimport TreeView from './TreeView'\nimport TreeNodeCard from './TreeNodeCard'\nimport BracketCard from './BracketCard'\nimport BracketRounds from './BracketRounds'\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, BracketCard, BracketRounds }\n\nexport type {\n Accessors,\n BracketCardMatch,\n BracketCardModel,\n BracketCardOptions,\n BracketCardRow,\n BracketCardTeam,\n BracketRound,\n BracketRoundColumn,\n BracketRoundsModel,\n BracketRoundsOptions,\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 {\n DEFAULT_OPTIONS,\n MOBILE_MEDIA_QUERY,\n buildBracketCard,\n bracketCardHeight,\n buildBracketRounds,\n} 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 Vue.component('BracketCard', BracketCard)\n Vue.component('BracketRounds', BracketRounds)\n },\n}\n\nexport default TreeViewPlugin\n"],"names":["TreeNodeCard","Vue","h","children","event","controllers","TreeView","DEFAULT_OVERSCAN","estimateVisibleRect","tree","toTree","layoutTree","applyCollapsed","visibleLayout","toCssTransform","controller","PanZoomController","transform","measureVisibleRect","padding","id","toggleCollapsed","node","data","slot","layout","drawn","linkSlot","links","link","nodes","BracketCard","buildBracketCard","row","content","card","BracketRounds","MOBILE_MEDIA_QUERY","buildBracketRounds","watchMedia","matches","column","nodesInColumn","middle","scrollToNode","element","container","findScrollParent","left","offsetWithin","smoothScrollLeft","roundScrollLeft","injectStyles","styles","TreeViewPlugin"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,9 +2,10 @@ import { VueConstructor } from 'vue';
|
|
|
2
2
|
import { default as TreeView } from './TreeView';
|
|
3
3
|
import { default as TreeNodeCard } from './TreeNodeCard';
|
|
4
4
|
import { default as BracketCard } from './BracketCard';
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
export {
|
|
5
|
+
import { default as BracketRounds } from './BracketRounds';
|
|
6
|
+
export { TreeView, TreeNodeCard, BracketCard, BracketRounds };
|
|
7
|
+
export type { Accessors, BracketCardMatch, BracketCardModel, BracketCardOptions, BracketCardRow, BracketCardTeam, BracketRound, BracketRoundColumn, BracketRoundsModel, BracketRoundsOptions, Direction, Layout, LayoutLink, LayoutNode, LinkStyle, ScaleLimits, Transform, TreeNode, TreeViewOptions, } from '@bigplay/tree-view-core';
|
|
8
|
+
export { DEFAULT_OPTIONS, MOBILE_MEDIA_QUERY, buildBracketCard, bracketCardHeight, buildBracketRounds, } from '@bigplay/tree-view-core';
|
|
8
9
|
/** Плагин: `Vue.use(TreeViewPlugin)` регистрирует компоненты глобально. */
|
|
9
10
|
export declare const TreeViewPlugin: {
|
|
10
11
|
install(Vue: VueConstructor): void;
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { DEFAULT_OVERSCAN as h, toggleCollapsed as p, measureVisibleRect as
|
|
3
|
-
import { DEFAULT_OPTIONS as
|
|
4
|
-
const
|
|
1
|
+
import l from "vue";
|
|
2
|
+
import { DEFAULT_OVERSCAN as h, toggleCollapsed as p, measureVisibleRect as u, PanZoomController as v, toCssTransform as b, visibleLayout as f, toTree as g, layoutTree as m, applyCollapsed as w, estimateVisibleRect as y, buildBracketCard as k, MOBILE_MEDIA_QUERY as x, nodesInColumn as _, scrollToNode as C, findScrollParent as S, offsetWithin as T, smoothScrollLeft as $, roundScrollLeft as z, watchMedia as R, buildBracketRounds as B, injectStyles as N } from "@bigplay/tree-view-core";
|
|
3
|
+
import { DEFAULT_OPTIONS as A, MOBILE_MEDIA_QUERY as P, bracketCardHeight as F, buildBracketCard as H, buildBracketRounds as K } from "@bigplay/tree-view-core";
|
|
4
|
+
const d = l.extend({
|
|
5
5
|
name: "TreeNodeCard",
|
|
6
6
|
props: {
|
|
7
7
|
label: { type: String, required: !0 },
|
|
8
8
|
hasChildren: { type: Boolean, default: !1 },
|
|
9
9
|
collapsed: { type: Boolean, default: !1 }
|
|
10
10
|
},
|
|
11
|
-
render(
|
|
12
|
-
const
|
|
13
|
-
return this.hasChildren &&
|
|
14
|
-
|
|
11
|
+
render(t) {
|
|
12
|
+
const e = [t("span", { class: "tree-view-card__label" }, this.label)];
|
|
13
|
+
return this.hasChildren && e.push(
|
|
14
|
+
t(
|
|
15
15
|
"button",
|
|
16
16
|
{
|
|
17
17
|
class: "tree-view-card__toggle",
|
|
@@ -28,9 +28,9 @@ const l = s.extend({
|
|
|
28
28
|
},
|
|
29
29
|
this.collapsed ? "+" : "−"
|
|
30
30
|
)
|
|
31
|
-
),
|
|
31
|
+
), t("div", { class: "tree-view-card" }, e);
|
|
32
32
|
}
|
|
33
|
-
}), r = /* @__PURE__ */ new WeakMap(),
|
|
33
|
+
}), r = /* @__PURE__ */ new WeakMap(), I = l.extend({
|
|
34
34
|
name: "TreeView",
|
|
35
35
|
props: {
|
|
36
36
|
/** Объект, массив объектов или плоский список (вместе с `getParentId`). */
|
|
@@ -87,12 +87,12 @@ const l = s.extend({
|
|
|
87
87
|
},
|
|
88
88
|
computed: {
|
|
89
89
|
layout() {
|
|
90
|
-
const
|
|
90
|
+
const t = g(this.data, {
|
|
91
91
|
getId: this.getId,
|
|
92
92
|
getChildren: this.getChildren,
|
|
93
93
|
getParentId: this.getParentId
|
|
94
94
|
});
|
|
95
|
-
return m(w(
|
|
95
|
+
return m(w(t, new Set(this.collapsedIds)), this.options);
|
|
96
96
|
},
|
|
97
97
|
/** То, что реально попадёт в DOM: при `virtualize` — только видимая часть. */
|
|
98
98
|
drawn() {
|
|
@@ -102,7 +102,7 @@ const l = s.extend({
|
|
|
102
102
|
return {
|
|
103
103
|
width: `${this.layout.width}px`,
|
|
104
104
|
height: `${this.layout.height}px`,
|
|
105
|
-
transform:
|
|
105
|
+
transform: b(this.transform)
|
|
106
106
|
};
|
|
107
107
|
},
|
|
108
108
|
rootStyle() {
|
|
@@ -121,15 +121,15 @@ const l = s.extend({
|
|
|
121
121
|
}
|
|
122
122
|
},
|
|
123
123
|
mounted() {
|
|
124
|
-
const
|
|
124
|
+
const t = new v({
|
|
125
125
|
pannable: () => this.pannable,
|
|
126
126
|
zoomable: () => this.zoomable,
|
|
127
127
|
limits: this.scaleLimits ? () => this.scaleLimits : void 0,
|
|
128
|
-
onChange: (
|
|
129
|
-
this.transform =
|
|
128
|
+
onChange: (e) => {
|
|
129
|
+
this.transform = e, this.updateVisibleRect(), this.$emit("transform", e);
|
|
130
130
|
}
|
|
131
131
|
});
|
|
132
|
-
|
|
132
|
+
t.attach(this.$el), r.set(this, t), this.updateVisibleRect(), window.addEventListener("scroll", this.updateVisibleRect, { passive: !0, capture: !0 }), window.addEventListener("resize", this.updateVisibleRect, { passive: !0 }), this.fitOnMount && this.$nextTick(() => this.fit());
|
|
133
133
|
},
|
|
134
134
|
beforeDestroy() {
|
|
135
135
|
r.get(this)?.detach(), r.delete(this), window.removeEventListener("scroll", this.updateVisibleRect, { capture: !0 }), window.removeEventListener("resize", this.updateVisibleRect);
|
|
@@ -137,11 +137,11 @@ const l = s.extend({
|
|
|
137
137
|
methods: {
|
|
138
138
|
/** Пересчитывает, какая часть холста сейчас видна на экране. */
|
|
139
139
|
updateVisibleRect() {
|
|
140
|
-
this.visibleRect = this.virtualize ?
|
|
140
|
+
this.visibleRect = this.virtualize ? u(this.$refs.canvas, this.transform.scale) : null;
|
|
141
141
|
},
|
|
142
142
|
/** Вписывает дерево в видимую область. */
|
|
143
|
-
fit(
|
|
144
|
-
r.get(this)?.fit({ width: this.layout.width, height: this.layout.height },
|
|
143
|
+
fit(t) {
|
|
144
|
+
r.get(this)?.fit({ width: this.layout.width, height: this.layout.height }, t);
|
|
145
145
|
},
|
|
146
146
|
zoomIn() {
|
|
147
147
|
r.get(this)?.zoomIn();
|
|
@@ -152,71 +152,71 @@ const l = s.extend({
|
|
|
152
152
|
resetTransform() {
|
|
153
153
|
r.get(this)?.reset();
|
|
154
154
|
},
|
|
155
|
-
setTransform(
|
|
156
|
-
r.get(this)?.set(
|
|
155
|
+
setTransform(t) {
|
|
156
|
+
r.get(this)?.set(t);
|
|
157
157
|
},
|
|
158
158
|
/** Развернуть все свёрнутые ветки. */
|
|
159
159
|
expandAll() {
|
|
160
160
|
this.collapsedIds = [];
|
|
161
161
|
},
|
|
162
162
|
/** Свернуть или развернуть узел по id. */
|
|
163
|
-
toggle(
|
|
164
|
-
this.collapsedIds = [...p(new Set(this.collapsedIds),
|
|
163
|
+
toggle(t) {
|
|
164
|
+
this.collapsedIds = [...p(new Set(this.collapsedIds), t)];
|
|
165
165
|
},
|
|
166
|
-
toggleNode(
|
|
167
|
-
this.toggle(
|
|
166
|
+
toggleNode(t) {
|
|
167
|
+
this.toggle(t.id), this.$emit("toggle", t, this.collapsedIds.includes(t.id));
|
|
168
168
|
},
|
|
169
|
-
onNodeClick(
|
|
170
|
-
this.$emit("node-click",
|
|
169
|
+
onNodeClick(t, e) {
|
|
170
|
+
this.$emit("node-click", t, e), this.collapsible && t.hasChildren && this.toggleNode(t);
|
|
171
171
|
},
|
|
172
|
-
nodeStyle(
|
|
172
|
+
nodeStyle(t) {
|
|
173
173
|
return {
|
|
174
|
-
left: `${
|
|
175
|
-
top: `${
|
|
176
|
-
width: `${
|
|
177
|
-
height: `${
|
|
174
|
+
left: `${t.x}px`,
|
|
175
|
+
top: `${t.y}px`,
|
|
176
|
+
width: `${t.width}px`,
|
|
177
|
+
height: `${t.height}px`
|
|
178
178
|
};
|
|
179
179
|
},
|
|
180
|
-
nodeClassOf(
|
|
181
|
-
return typeof this.nodeClass == "function" ? this.nodeClass(
|
|
180
|
+
nodeClassOf(t) {
|
|
181
|
+
return typeof this.nodeClass == "function" ? this.nodeClass(t) : this.nodeClass;
|
|
182
182
|
},
|
|
183
183
|
/** Подпись карточки по умолчанию: name → title → label → id. */
|
|
184
|
-
labelOf(
|
|
185
|
-
const
|
|
186
|
-
return
|
|
184
|
+
labelOf(t) {
|
|
185
|
+
const e = t.data;
|
|
186
|
+
return e?.name ?? e?.title ?? e?.label ?? t.id;
|
|
187
187
|
},
|
|
188
188
|
/** Своя карточка из scoped-слота или карточка по умолчанию. */
|
|
189
|
-
renderNodeContent(
|
|
189
|
+
renderNodeContent(t, e) {
|
|
190
190
|
const i = this.$scopedSlots.node;
|
|
191
191
|
return i ? i({
|
|
192
|
-
node:
|
|
193
|
-
data:
|
|
194
|
-
depth:
|
|
195
|
-
collapsed:
|
|
196
|
-
hasChildren:
|
|
197
|
-
toggle: () => this.toggleNode(
|
|
198
|
-
}) ?? [] :
|
|
199
|
-
props: { label: this.labelOf(
|
|
200
|
-
on: { toggle: () => this.toggleNode(
|
|
192
|
+
node: e,
|
|
193
|
+
data: e.data,
|
|
194
|
+
depth: e.depth,
|
|
195
|
+
collapsed: e.collapsed,
|
|
196
|
+
hasChildren: e.hasChildren,
|
|
197
|
+
toggle: () => this.toggleNode(e)
|
|
198
|
+
}) ?? [] : t(d, {
|
|
199
|
+
props: { label: this.labelOf(e), hasChildren: e.hasChildren, collapsed: e.collapsed },
|
|
200
|
+
on: { toggle: () => this.toggleNode(e) }
|
|
201
201
|
});
|
|
202
202
|
}
|
|
203
203
|
},
|
|
204
|
-
render(
|
|
205
|
-
const
|
|
206
|
-
(
|
|
207
|
-
),
|
|
208
|
-
(
|
|
204
|
+
render(t) {
|
|
205
|
+
const e = this.layout, i = this.drawn, s = this.$scopedSlots.link, n = i.links.map(
|
|
206
|
+
(o) => s ? s({ link: o }) ?? [] : t("path", { key: o.id, class: "tree-view__link", attrs: { d: o.path } })
|
|
207
|
+
), a = i.nodes.map(
|
|
208
|
+
(o) => t(
|
|
209
209
|
"div",
|
|
210
210
|
{
|
|
211
|
-
key:
|
|
212
|
-
class: ["tree-view__node", this.nodeClassOf(
|
|
213
|
-
style: this.nodeStyle(
|
|
214
|
-
on: { click: (c) => this.onNodeClick(
|
|
211
|
+
key: o.id,
|
|
212
|
+
class: ["tree-view__node", this.nodeClassOf(o)],
|
|
213
|
+
style: this.nodeStyle(o),
|
|
214
|
+
on: { click: (c) => this.onNodeClick(o, c) }
|
|
215
215
|
},
|
|
216
|
-
[].concat(this.renderNodeContent(
|
|
216
|
+
[].concat(this.renderNodeContent(t, o))
|
|
217
217
|
)
|
|
218
218
|
);
|
|
219
|
-
return
|
|
219
|
+
return t(
|
|
220
220
|
"div",
|
|
221
221
|
{
|
|
222
222
|
class: [
|
|
@@ -226,21 +226,21 @@ const l = s.extend({
|
|
|
226
226
|
style: this.rootStyle
|
|
227
227
|
},
|
|
228
228
|
[
|
|
229
|
-
|
|
230
|
-
|
|
229
|
+
t("div", { ref: "canvas", class: "tree-view__canvas", style: this.canvasStyle }, [
|
|
230
|
+
t(
|
|
231
231
|
"svg",
|
|
232
232
|
{
|
|
233
233
|
class: "tree-view__links",
|
|
234
|
-
attrs: { width:
|
|
234
|
+
attrs: { width: e.width, height: e.height }
|
|
235
235
|
},
|
|
236
236
|
n
|
|
237
237
|
),
|
|
238
|
-
...
|
|
238
|
+
...a
|
|
239
239
|
])
|
|
240
240
|
]
|
|
241
241
|
);
|
|
242
242
|
}
|
|
243
|
-
}),
|
|
243
|
+
}), O = l.extend({
|
|
244
244
|
name: "BracketCard",
|
|
245
245
|
props: {
|
|
246
246
|
/** Матч: нужны только команды. */
|
|
@@ -263,28 +263,28 @@ const l = s.extend({
|
|
|
263
263
|
}
|
|
264
264
|
},
|
|
265
265
|
methods: {
|
|
266
|
-
renderRow(
|
|
266
|
+
renderRow(t, e) {
|
|
267
267
|
const i = [];
|
|
268
|
-
return
|
|
268
|
+
return e.team && (e.isTechDefeat && this.hoveredKey === e.key && i.push(t("span", { class: "tv-bracket__tooltip" }, this.techDefeatHint)), i.push(t("span", { class: "tv-bracket__name" }, e.team.name)), i.push(t("span", { class: "tv-bracket__score" }, e.score))), t(
|
|
269
269
|
"div",
|
|
270
270
|
{
|
|
271
|
-
key:
|
|
271
|
+
key: e.key,
|
|
272
272
|
class: [
|
|
273
273
|
"tv-bracket__row",
|
|
274
274
|
{
|
|
275
|
-
"tv-bracket__row--winner":
|
|
276
|
-
"tv-bracket__row--loser":
|
|
277
|
-
"tv-bracket__row--my":
|
|
278
|
-
"tv-bracket__row--empty":
|
|
275
|
+
"tv-bracket__row--winner": e.isWinner,
|
|
276
|
+
"tv-bracket__row--loser": e.isLoser && !e.isEmpty,
|
|
277
|
+
"tv-bracket__row--my": e.isMyTeam,
|
|
278
|
+
"tv-bracket__row--empty": e.isEmpty
|
|
279
279
|
}
|
|
280
280
|
],
|
|
281
|
-
attrs:
|
|
281
|
+
attrs: e.isMyTeam ? { title: "Моя команда" } : {},
|
|
282
282
|
on: {
|
|
283
283
|
click: () => {
|
|
284
|
-
|
|
284
|
+
e.team && this.$emit("select", e.team, e);
|
|
285
285
|
},
|
|
286
286
|
mouseenter: () => {
|
|
287
|
-
this.hoveredKey =
|
|
287
|
+
this.hoveredKey = e.key;
|
|
288
288
|
},
|
|
289
289
|
mouseleave: () => {
|
|
290
290
|
this.hoveredKey = null;
|
|
@@ -295,27 +295,135 @@ const l = s.extend({
|
|
|
295
295
|
);
|
|
296
296
|
}
|
|
297
297
|
},
|
|
298
|
-
render(
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
for (const
|
|
302
|
-
return
|
|
298
|
+
render(t) {
|
|
299
|
+
const e = this.card, i = [];
|
|
300
|
+
e.hasMyTeam && this.myTeamHint && i.push(t("div", { class: "tv-bracket__hint" }, this.myTeamHint));
|
|
301
|
+
for (const s of e.rows) i.push(this.renderRow(t, s));
|
|
302
|
+
return t("div", { class: ["tv-bracket", { "tv-bracket--my-team": e.hasMyTeam }] }, i);
|
|
303
303
|
}
|
|
304
|
-
}),
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
304
|
+
}), L = l.extend({
|
|
305
|
+
name: "BracketRounds",
|
|
306
|
+
props: {
|
|
307
|
+
/** Раунды по порядку — от первого к финалу. */
|
|
308
|
+
rounds: { type: Array, default: () => [] },
|
|
309
|
+
/** Ширина карточки матча — то же число, что в `nodeWidth` у сетки. */
|
|
310
|
+
nodeWidth: { type: Number, default: 180 },
|
|
311
|
+
/** Промежуток между раундами — то же число, что в `levelGap` у сетки. */
|
|
312
|
+
levelGap: { type: Number, default: 60 },
|
|
313
|
+
/** Показывать полосу. Содержимое слота рисуется в любом случае. */
|
|
314
|
+
isShow: { type: Boolean, default: !0 },
|
|
315
|
+
/** Нажатие на раунд подводит к нему сетку. Не передан — решает ширина экрана. */
|
|
316
|
+
scrollOnClick: { type: Boolean, default: void 0 },
|
|
317
|
+
/** Медиавыражение «узкий экран», при котором нажатие включается. */
|
|
318
|
+
mobileQuery: { type: String, default: x }
|
|
319
|
+
},
|
|
320
|
+
data() {
|
|
321
|
+
return {
|
|
322
|
+
// Узкий ли экран. До монтирования — нет: на сервере ширину знать неоткуда.
|
|
323
|
+
isNarrow: !1,
|
|
324
|
+
unwatch: null
|
|
325
|
+
};
|
|
326
|
+
},
|
|
327
|
+
computed: {
|
|
328
|
+
/** Полосы нет — нажимать не на что. */
|
|
329
|
+
isClickable() {
|
|
330
|
+
return this.isShow && (this.scrollOnClick === void 0 ? this.isNarrow : this.scrollOnClick);
|
|
331
|
+
},
|
|
332
|
+
model() {
|
|
333
|
+
return B(this.rounds, {
|
|
334
|
+
nodeWidth: this.nodeWidth,
|
|
335
|
+
levelGap: this.levelGap
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
mounted() {
|
|
340
|
+
this.unwatch = R(this.mobileQuery, (t) => {
|
|
341
|
+
this.isNarrow = t;
|
|
342
|
+
});
|
|
343
|
+
},
|
|
344
|
+
beforeDestroy() {
|
|
345
|
+
this.unwatch?.();
|
|
346
|
+
},
|
|
347
|
+
methods: {
|
|
348
|
+
/**
|
|
349
|
+
* Подводит сетку к матчам раунда.
|
|
350
|
+
*
|
|
351
|
+
* Сначала пробуем по самим карточкам: браузер сам подвинет и страницу, и блок
|
|
352
|
+
* с прокруткой, поэтому финал оказывается на экране целиком, а не только
|
|
353
|
+
* «где-то справа». Карточек не нашли (виртуализация) — считаем по колонкам.
|
|
354
|
+
*/
|
|
355
|
+
scrollToRound(t) {
|
|
356
|
+
const e = this.$refs.content, i = e ? _(e, t.index, t.width, this.model.offset) : [], s = i[Math.floor(i.length / 2)];
|
|
357
|
+
if (s && C(s)) return;
|
|
358
|
+
const n = this.$el, a = S(n);
|
|
359
|
+
if (!n || !a) return;
|
|
360
|
+
const o = T(n, a) + t.index * t.width;
|
|
361
|
+
$(
|
|
362
|
+
a,
|
|
363
|
+
z({
|
|
364
|
+
left: o,
|
|
365
|
+
width: t.width,
|
|
366
|
+
viewport: a.clientWidth,
|
|
367
|
+
scrollWidth: a.scrollWidth
|
|
368
|
+
})
|
|
369
|
+
);
|
|
370
|
+
},
|
|
371
|
+
/** Нажатие — только на узком экране: на широком колонка раунда это просто подпись. */
|
|
372
|
+
onSelect(t) {
|
|
373
|
+
this.isClickable && (this.$emit("select", t), this.scrollToRound(t));
|
|
374
|
+
},
|
|
375
|
+
renderColumn(t, e) {
|
|
376
|
+
return t(
|
|
377
|
+
"div",
|
|
378
|
+
{
|
|
379
|
+
key: e.key,
|
|
380
|
+
class: "tv-rounds__item",
|
|
381
|
+
style: { width: `${e.width}px` },
|
|
382
|
+
on: { click: () => this.onSelect(e) }
|
|
383
|
+
},
|
|
384
|
+
this.$scopedSlots.round?.({ round: e }) ?? e.name
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
render(t) {
|
|
389
|
+
const e = [];
|
|
390
|
+
return this.isShow && e.push(
|
|
391
|
+
t(
|
|
392
|
+
"div",
|
|
393
|
+
{ class: "tv-rounds__bar", style: { width: `${this.model.width}px` } },
|
|
394
|
+
this.model.columns.map((i) => this.renderColumn(t, i))
|
|
395
|
+
)
|
|
396
|
+
), e.push(
|
|
397
|
+
t(
|
|
398
|
+
"div",
|
|
399
|
+
{
|
|
400
|
+
ref: "content",
|
|
401
|
+
class: "tv-rounds__content",
|
|
402
|
+
// Сюда кладут саму сетку: ей достаётся отступ, центрующий матчи.
|
|
403
|
+
style: this.isShow ? { paddingLeft: `${this.model.offset}px` } : {}
|
|
404
|
+
},
|
|
405
|
+
this.$slots.default
|
|
406
|
+
)
|
|
407
|
+
), t("div", { class: "tv-rounds" }, e);
|
|
408
|
+
}
|
|
409
|
+
}), E = ".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}.tv-bracket{--tv-bracket-winner-bg: #0427c4;--tv-bracket-winner-color: #ffffff;--tv-bracket-loser-bg: #e5e5e5;--tv-bracket-loser-color: #7d7d8d;--tv-bracket-my-bg: #00146c;--tv-bracket-my-color: #ffffff;--tv-bracket-radius: 6px;position:relative;box-sizing:border-box;display:flex;flex-direction:column;width:100%;height:100%;font-size:12px}.tv-bracket--my-team{border-radius:var(--tv-bracket-radius);outline:2px solid var(--tv-bracket-my-bg)}.tv-bracket__hint{position:absolute;right:0;bottom:100%;left:0;padding:3px 8px;overflow:hidden;font-size:11px;font-weight:600;line-height:1.2;color:var(--tv-bracket-my-color);text-align:center;text-overflow:ellipsis;white-space:nowrap;background:var(--tv-bracket-my-bg);border-radius:var(--tv-bracket-radius) var(--tv-bracket-radius) 0 0}.tv-bracket__row{position:relative;box-sizing:border-box;display:flex;flex:1 1 0;align-items:center;justify-content:space-between;min-height:0;padding:4px 8px;cursor:pointer;transition:all 75ms}.tv-bracket__row--winner{font-weight:700;color:var(--tv-bracket-winner-color);background:var(--tv-bracket-winner-bg)}.tv-bracket__row--loser{color:var(--tv-bracket-loser-color);background:var(--tv-bracket-loser-bg)}.tv-bracket__row--my{color:var(--tv-bracket-my-color);background:var(--tv-bracket-my-bg)}.tv-bracket__row--empty{cursor:default;background:var(--tv-bracket-loser-bg)}.tv-bracket__name{max-width:120px;overflow:hidden;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.tv-bracket__score{display:flex;flex:none;align-items:center;justify-content:center;width:20px;height:20px;font-weight:700;font-variant-numeric:tabular-nums}.tv-bracket__tooltip{position:absolute;top:-26px;left:6px;z-index:5000;padding:4px 8px;font-weight:400;color:var(--tv-bracket-loser-color);white-space:nowrap;background:#fff;border:1px solid #d1d5db;border-radius:4px;box-shadow:0 4px 10px #0f172a26}.tv-rounds{--tv-rounds-bg: #f5f5f7;--tv-rounds-color: #9ca3af;--tv-rounds-border: 2px solid #e5e7eb;--tv-rounds-gap: 20px;display:flex;flex-direction:column;width:max-content;min-width:100%}.tv-rounds__bar{display:flex;min-width:100%;margin-bottom:var(--tv-rounds-gap);background:var(--tv-rounds-bg);border-bottom:var(--tv-rounds-border)}.tv-rounds__item{flex:none;box-sizing:border-box;padding:10px 20px;font:inherit;font-size:14px;font-weight:600;color:var(--tv-rounds-color);text-align:center;text-transform:uppercase;white-space:nowrap;background:none;border:none;border-right:var(--tv-rounds-border)}";
|
|
410
|
+
N(E);
|
|
411
|
+
const D = {
|
|
412
|
+
install(t) {
|
|
413
|
+
t.component("TreeView", I), t.component("TreeNodeCard", d), t.component("BracketCard", O), t.component("BracketRounds", L);
|
|
309
414
|
}
|
|
310
415
|
};
|
|
311
416
|
export {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
417
|
+
O as BracketCard,
|
|
418
|
+
L as BracketRounds,
|
|
419
|
+
A as DEFAULT_OPTIONS,
|
|
420
|
+
P as MOBILE_MEDIA_QUERY,
|
|
421
|
+
d as TreeNodeCard,
|
|
422
|
+
I as TreeView,
|
|
423
|
+
D as TreeViewPlugin,
|
|
424
|
+
F as bracketCardHeight,
|
|
425
|
+
H as buildBracketCard,
|
|
426
|
+
K as buildBracketRounds,
|
|
427
|
+
D as default
|
|
320
428
|
};
|
|
321
429
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/TreeNodeCard.ts","../src/TreeView.ts","../src/BracketCard.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 DEFAULT_OVERSCAN,\n estimateVisibleRect,\n layoutTree,\n measureVisibleRect,\n PanZoomController,\n toCssTransform,\n toggleCollapsed,\n toTree,\n visibleLayout,\n type Accessors,\n type Layout,\n type LayoutNode,\n type Rect,\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 * Рисовать только то, что видно на экране. На больших сетках в DOM\n * попадает несколько десятков карточек вместо тысячи.\n */\n virtualize: { type: Boolean, default: true },\n /** Запас вокруг видимой области в пикселях. */\n overscan: { type: Number, default: DEFAULT_OVERSCAN },\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 * Видимая часть холста; `null` — рисуем всё.\n * До первого измерения берём размер окна: иначе первый кадр\n * нарисует дерево целиком и тут же выбросит лишнее.\n */\n visibleRect: (this.virtualize ? estimateVisibleRect() : null) as Rect | null,\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 /** То, что реально попадёт в DOM: при `virtualize` — только видимая часть. */\n drawn(): Layout<NodeData> {\n return this.virtualize ? visibleLayout(this.layout, this.visibleRect, this.overscan) : this.layout\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 watch: {\n // Новые данные — видимую часть надо пересчитать уже по ним.\n layout() {\n this.$nextTick(() => this.updateVisibleRect())\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 // Холст поехал — видимая часть стала другой.\n this.updateVisibleRect()\n this.$emit('transform', transform)\n },\n })\n\n controller.attach(this.$el as HTMLElement)\n controllers.set(this, controller)\n\n this.updateVisibleRect()\n window.addEventListener('scroll', this.updateVisibleRect, { passive: true, capture: true })\n window.addEventListener('resize', this.updateVisibleRect, { passive: true })\n\n if (this.fitOnMount) this.$nextTick(() => this.fit())\n },\n\n beforeDestroy() {\n controllers.get(this)?.detach()\n controllers.delete(this)\n window.removeEventListener('scroll', this.updateVisibleRect, { capture: true } as EventListenerOptions)\n window.removeEventListener('resize', this.updateVisibleRect)\n },\n\n methods: {\n /** Пересчитывает, какая часть холста сейчас видна на экране. */\n updateVisibleRect(): void {\n this.visibleRect = this.virtualize\n ? measureVisibleRect(this.$refs.canvas as Element | undefined, this.transform.scale)\n : null\n },\n\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 drawn = this.drawn\n const linkSlot = this.$scopedSlots.link\n\n const links = drawn.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 = drawn.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', { ref: 'canvas', 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 Vue, { type PropType, type VNode } from 'vue'\nimport {\n buildBracketCard,\n type BracketCardMatch,\n type BracketCardRow,\n} from '@bigplay/tree-view-core'\n\n/**\n * Карточка матча для Vue 2. Разметка и классы один в один как в Vue 3 —\n * строки считает та же функция из core, стили общие.\n */\nexport default Vue.extend({\n name: 'BracketCard',\n props: {\n /** Матч: нужны только команды. */\n match: { type: Object as PropType<BracketCardMatch | null>, default: null },\n /** Сколько строк рисовать. У финала — одна. */\n rows: { type: Number, default: undefined },\n /** Подсказка над карточкой с моей командой. Пустая строка — не показывать. */\n myTeamHint: { type: String, default: 'Нажми для перехода в матч 👇' },\n /** Текст в ячейке счёта при техническом поражении. */\n techDefeatLabel: { type: String, default: 'ТП' },\n /** Подсказка по наведению на техническое поражение. */\n techDefeatHint: { type: String, default: 'Техническое поражение' },\n },\n\n data() {\n return { hoveredKey: null as string | null }\n },\n\n computed: {\n card(): ReturnType<typeof buildBracketCard> {\n return buildBracketCard(this.match, { rows: this.rows, techDefeatLabel: this.techDefeatLabel })\n },\n },\n\n methods: {\n renderRow(h: typeof Vue.prototype.$createElement, row: BracketCardRow): VNode {\n const content: VNode[] = []\n\n if (row.team) {\n if (row.isTechDefeat && this.hoveredKey === row.key) {\n content.push(h('span', { class: 'tv-bracket__tooltip' }, this.techDefeatHint))\n }\n content.push(h('span', { class: 'tv-bracket__name' }, row.team.name))\n content.push(h('span', { class: 'tv-bracket__score' }, row.score))\n }\n\n return h(\n 'div',\n {\n key: row.key,\n class: [\n 'tv-bracket__row',\n {\n 'tv-bracket__row--winner': row.isWinner,\n 'tv-bracket__row--loser': row.isLoser && !row.isEmpty,\n 'tv-bracket__row--my': row.isMyTeam,\n 'tv-bracket__row--empty': row.isEmpty,\n },\n ],\n attrs: row.isMyTeam ? { title: 'Моя команда' } : {},\n on: {\n click: () => {\n if (row.team) this.$emit('select', row.team, row)\n },\n mouseenter: () => {\n this.hoveredKey = row.key\n },\n mouseleave: () => {\n this.hoveredKey = null\n },\n },\n },\n content,\n )\n },\n },\n\n render(h): VNode {\n const card = this.card\n const children: VNode[] = []\n\n if (card.hasMyTeam && this.myTeamHint) {\n children.push(h('div', { class: 'tv-bracket__hint' }, this.myTeamHint))\n }\n\n for (const row of card.rows) children.push(this.renderRow(h, row))\n\n return h('div', { class: ['tv-bracket', { 'tv-bracket--my-team': card.hasMyTeam }] }, children)\n },\n})\n","import type { VueConstructor } from 'vue'\nimport TreeView from './TreeView'\nimport TreeNodeCard from './TreeNodeCard'\nimport BracketCard from './BracketCard'\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, BracketCard }\n\nexport type {\n Accessors,\n BracketCardMatch,\n BracketCardModel,\n BracketCardOptions,\n BracketCardRow,\n BracketCardTeam,\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, buildBracketCard, bracketCardHeight } 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 Vue.component('BracketCard', BracketCard)\n },\n}\n\nexport default TreeViewPlugin\n"],"names":["TreeNodeCard","Vue","h","children","event","controllers","TreeView","DEFAULT_OVERSCAN","estimateVisibleRect","tree","toTree","layoutTree","applyCollapsed","visibleLayout","toCssTransform","controller","PanZoomController","transform","measureVisibleRect","padding","id","toggleCollapsed","node","data","slot","layout","drawn","linkSlot","links","link","nodes","BracketCard","buildBracketCard","row","content","card","injectStyles","styles","TreeViewPlugin"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/TreeNodeCard.ts","../src/TreeView.ts","../src/BracketCard.ts","../src/BracketRounds.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 DEFAULT_OVERSCAN,\n estimateVisibleRect,\n layoutTree,\n measureVisibleRect,\n PanZoomController,\n toCssTransform,\n toggleCollapsed,\n toTree,\n visibleLayout,\n type Accessors,\n type Layout,\n type LayoutNode,\n type Rect,\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 * Рисовать только то, что видно на экране. На больших сетках в DOM\n * попадает несколько десятков карточек вместо тысячи.\n */\n virtualize: { type: Boolean, default: true },\n /** Запас вокруг видимой области в пикселях. */\n overscan: { type: Number, default: DEFAULT_OVERSCAN },\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 * Видимая часть холста; `null` — рисуем всё.\n * До первого измерения берём размер окна: иначе первый кадр\n * нарисует дерево целиком и тут же выбросит лишнее.\n */\n visibleRect: (this.virtualize ? estimateVisibleRect() : null) as Rect | null,\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 /** То, что реально попадёт в DOM: при `virtualize` — только видимая часть. */\n drawn(): Layout<NodeData> {\n return this.virtualize ? visibleLayout(this.layout, this.visibleRect, this.overscan) : this.layout\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 watch: {\n // Новые данные — видимую часть надо пересчитать уже по ним.\n layout() {\n this.$nextTick(() => this.updateVisibleRect())\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 // Холст поехал — видимая часть стала другой.\n this.updateVisibleRect()\n this.$emit('transform', transform)\n },\n })\n\n controller.attach(this.$el as HTMLElement)\n controllers.set(this, controller)\n\n this.updateVisibleRect()\n window.addEventListener('scroll', this.updateVisibleRect, { passive: true, capture: true })\n window.addEventListener('resize', this.updateVisibleRect, { passive: true })\n\n if (this.fitOnMount) this.$nextTick(() => this.fit())\n },\n\n beforeDestroy() {\n controllers.get(this)?.detach()\n controllers.delete(this)\n window.removeEventListener('scroll', this.updateVisibleRect, { capture: true } as EventListenerOptions)\n window.removeEventListener('resize', this.updateVisibleRect)\n },\n\n methods: {\n /** Пересчитывает, какая часть холста сейчас видна на экране. */\n updateVisibleRect(): void {\n this.visibleRect = this.virtualize\n ? measureVisibleRect(this.$refs.canvas as Element | undefined, this.transform.scale)\n : null\n },\n\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 drawn = this.drawn\n const linkSlot = this.$scopedSlots.link\n\n const links = drawn.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 = drawn.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', { ref: 'canvas', 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 Vue, { type PropType, type VNode } from 'vue'\nimport {\n buildBracketCard,\n type BracketCardMatch,\n type BracketCardRow,\n} from '@bigplay/tree-view-core'\n\n/**\n * Карточка матча для Vue 2. Разметка и классы один в один как в Vue 3 —\n * строки считает та же функция из core, стили общие.\n */\nexport default Vue.extend({\n name: 'BracketCard',\n props: {\n /** Матч: нужны только команды. */\n match: { type: Object as PropType<BracketCardMatch | null>, default: null },\n /** Сколько строк рисовать. У финала — одна. */\n rows: { type: Number, default: undefined },\n /** Подсказка над карточкой с моей командой. Пустая строка — не показывать. */\n myTeamHint: { type: String, default: 'Нажми для перехода в матч 👇' },\n /** Текст в ячейке счёта при техническом поражении. */\n techDefeatLabel: { type: String, default: 'ТП' },\n /** Подсказка по наведению на техническое поражение. */\n techDefeatHint: { type: String, default: 'Техническое поражение' },\n },\n\n data() {\n return { hoveredKey: null as string | null }\n },\n\n computed: {\n card(): ReturnType<typeof buildBracketCard> {\n return buildBracketCard(this.match, { rows: this.rows, techDefeatLabel: this.techDefeatLabel })\n },\n },\n\n methods: {\n renderRow(h: typeof Vue.prototype.$createElement, row: BracketCardRow): VNode {\n const content: VNode[] = []\n\n if (row.team) {\n if (row.isTechDefeat && this.hoveredKey === row.key) {\n content.push(h('span', { class: 'tv-bracket__tooltip' }, this.techDefeatHint))\n }\n content.push(h('span', { class: 'tv-bracket__name' }, row.team.name))\n content.push(h('span', { class: 'tv-bracket__score' }, row.score))\n }\n\n return h(\n 'div',\n {\n key: row.key,\n class: [\n 'tv-bracket__row',\n {\n 'tv-bracket__row--winner': row.isWinner,\n 'tv-bracket__row--loser': row.isLoser && !row.isEmpty,\n 'tv-bracket__row--my': row.isMyTeam,\n 'tv-bracket__row--empty': row.isEmpty,\n },\n ],\n attrs: row.isMyTeam ? { title: 'Моя команда' } : {},\n on: {\n click: () => {\n if (row.team) this.$emit('select', row.team, row)\n },\n mouseenter: () => {\n this.hoveredKey = row.key\n },\n mouseleave: () => {\n this.hoveredKey = null\n },\n },\n },\n content,\n )\n },\n },\n\n render(h): VNode {\n const card = this.card\n const children: VNode[] = []\n\n if (card.hasMyTeam && this.myTeamHint) {\n children.push(h('div', { class: 'tv-bracket__hint' }, this.myTeamHint))\n }\n\n for (const row of card.rows) children.push(this.renderRow(h, row))\n\n return h('div', { class: ['tv-bracket', { 'tv-bracket--my-team': card.hasMyTeam }] }, children)\n },\n})\n","import Vue, { type PropType, type VNode } from 'vue'\nimport {\n MOBILE_MEDIA_QUERY,\n buildBracketRounds,\n findScrollParent,\n nodesInColumn,\n offsetWithin,\n roundScrollLeft,\n scrollToNode,\n smoothScrollLeft,\n watchMedia,\n type BracketRound,\n type BracketRoundColumn,\n type BracketRoundsModel,\n} from '@bigplay/tree-view-core'\n\n/**\n * Полоса раундов для Vue 2. Разметка и классы один в один как в Vue 3 —\n * колонки считает та же функция из core, стили общие.\n */\nexport default Vue.extend({\n name: 'BracketRounds',\n props: {\n /** Раунды по порядку — от первого к финалу. */\n rounds: { type: Array as PropType<BracketRound[]>, default: () => [] },\n /** Ширина карточки матча — то же число, что в `nodeWidth` у сетки. */\n nodeWidth: { type: Number, default: 180 },\n /** Промежуток между раундами — то же число, что в `levelGap` у сетки. */\n levelGap: { type: Number, default: 60 },\n /** Показывать полосу. Содержимое слота рисуется в любом случае. */\n isShow: { type: Boolean, default: true },\n /** Нажатие на раунд подводит к нему сетку. Не передан — решает ширина экрана. */\n scrollOnClick: { type: Boolean, default: undefined },\n /** Медиавыражение «узкий экран», при котором нажатие включается. */\n mobileQuery: { type: String, default: MOBILE_MEDIA_QUERY },\n },\n\n data() {\n return {\n // Узкий ли экран. До монтирования — нет: на сервере ширину знать неоткуда.\n isNarrow: false,\n unwatch: null as null | (() => void),\n }\n },\n\n computed: {\n /** Полосы нет — нажимать не на что. */\n isClickable(): boolean {\n return this.isShow && (this.scrollOnClick === undefined ? this.isNarrow : this.scrollOnClick)\n },\n\n model(): BracketRoundsModel {\n return buildBracketRounds(this.rounds, {\n nodeWidth: this.nodeWidth,\n levelGap: this.levelGap,\n })\n },\n },\n\n mounted() {\n this.unwatch = watchMedia(this.mobileQuery, (matches) => {\n this.isNarrow = matches\n })\n },\n\n beforeDestroy() {\n this.unwatch?.()\n },\n\n methods: {\n /**\n * Подводит сетку к матчам раунда.\n *\n * Сначала пробуем по самим карточкам: браузер сам подвинет и страницу, и блок\n * с прокруткой, поэтому финал оказывается на экране целиком, а не только\n * «где-то справа». Карточек не нашли (виртуализация) — считаем по колонкам.\n */\n scrollToRound(column: BracketRoundColumn): void {\n const content = this.$refs.content as HTMLElement | undefined\n const matches = content\n ? nodesInColumn(content, column.index, column.width, this.model.offset)\n : []\n const middle = matches[Math.floor(matches.length / 2)]\n\n if (middle && scrollToNode(middle)) return\n\n const element = this.$el as HTMLElement | null\n const container = findScrollParent(element)\n if (!element || !container) return\n\n const left = offsetWithin(element, container) + column.index * column.width\n\n smoothScrollLeft(\n container,\n roundScrollLeft({\n left,\n width: column.width,\n viewport: container.clientWidth,\n scrollWidth: container.scrollWidth,\n }),\n )\n },\n\n /** Нажатие — только на узком экране: на широком колонка раунда это просто подпись. */\n onSelect(column: BracketRoundColumn): void {\n if (!this.isClickable) return\n\n this.$emit('select', column)\n this.scrollToRound(column)\n },\n\n renderColumn(h: typeof Vue.prototype.$createElement, column: BracketRoundColumn): VNode {\n return h(\n 'div',\n {\n key: column.key,\n class: 'tv-rounds__item',\n style: { width: `${column.width}px` },\n on: { click: () => this.onSelect(column) },\n },\n this.$scopedSlots.round?.({ round: column }) ?? column.name,\n )\n },\n },\n\n render(h): VNode {\n const children: VNode[] = []\n\n if (this.isShow) {\n children.push(\n h(\n 'div',\n { class: 'tv-rounds__bar', style: { width: `${this.model.width}px` } },\n this.model.columns.map((column) => this.renderColumn(h, column)),\n ),\n )\n }\n\n children.push(\n h(\n 'div',\n {\n ref: 'content',\n class: 'tv-rounds__content',\n // Сюда кладут саму сетку: ей достаётся отступ, центрующий матчи.\n style: this.isShow ? { paddingLeft: `${this.model.offset}px` } : {},\n },\n this.$slots.default,\n ),\n )\n\n return h('div', { class: 'tv-rounds' }, children)\n },\n})\n","import type { VueConstructor } from 'vue'\nimport TreeView from './TreeView'\nimport TreeNodeCard from './TreeNodeCard'\nimport BracketCard from './BracketCard'\nimport BracketRounds from './BracketRounds'\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, BracketCard, BracketRounds }\n\nexport type {\n Accessors,\n BracketCardMatch,\n BracketCardModel,\n BracketCardOptions,\n BracketCardRow,\n BracketCardTeam,\n BracketRound,\n BracketRoundColumn,\n BracketRoundsModel,\n BracketRoundsOptions,\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 {\n DEFAULT_OPTIONS,\n MOBILE_MEDIA_QUERY,\n buildBracketCard,\n bracketCardHeight,\n buildBracketRounds,\n} 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 Vue.component('BracketCard', BracketCard)\n Vue.component('BracketRounds', BracketRounds)\n },\n}\n\nexport default TreeViewPlugin\n"],"names":["TreeNodeCard","Vue","h","children","event","controllers","TreeView","DEFAULT_OVERSCAN","estimateVisibleRect","tree","toTree","layoutTree","applyCollapsed","visibleLayout","toCssTransform","controller","PanZoomController","transform","measureVisibleRect","padding","id","toggleCollapsed","node","data","slot","layout","drawn","linkSlot","links","link","nodes","BracketCard","buildBracketCard","row","content","card","BracketRounds","MOBILE_MEDIA_QUERY","buildBracketRounds","watchMedia","matches","column","nodesInColumn","middle","scrollToNode","element","container","findScrollParent","left","offsetWithin","smoothScrollLeft","roundScrollLeft","injectStyles","styles","TreeViewPlugin"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bigplay/tree-view-vue2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Компонент дерева и турнирных сеток для Vue 2.6 / 2.7",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@bigplay/tree-view-core": "^0.
|
|
38
|
+
"@bigplay/tree-view-core": "^0.3.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"vue": "^2.6.0 || ^2.7.0"
|