@bigplay/tree-view-vue2 0.3.0 → 0.3.1

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.
@@ -9,11 +9,13 @@ declare const _default: import('vue/types/vue').ExtendedVue<Vue<Record<string, a
9
9
  unwatch: null | (() => void);
10
10
  }, {
11
11
  /**
12
- * Подводит сетку к матчам раунда.
12
+ * Подводит сетку к матчам раунда — только по горизонтали.
13
13
  *
14
- * Сначала пробуем по самим карточкам: браузер сам подвинет и страницу, и блок
15
- * с прокруткой, поэтому финал оказывается на экране целиком, а не только
16
- * «где-то справа». Карточек не нашли (виртуализация) — считаем по колонкам.
14
+ * Меряем по самой карточке: так раунд встаёт по центру экрана точно, а у финала
15
+ * прокрутка упирается в правый край и он виден целиком. Карточек не нашли
16
+ * (виртуализация) — считаем по колонке, она той же ширины и на том же месте.
17
+ *
18
+ * Вертикаль не трогаем: страница остаётся там, где была.
17
19
  */
18
20
  scrollToRound(column: BracketRoundColumn): void;
19
21
  /** Нажатие — только на узком экране: на широком колонка раунда это просто подпись. */
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
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;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const l=require("vue"),i=require("@bigplay/tree-view-core"),c=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:r=>{r.stopPropagation(),this.$emit("toggle")}}},this.collapsed?"+":"−")),e("div",{class:"tree-view-card"},t)}}),s=new WeakMap,h=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: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,n=r.links.map(o=>a?a({link:o})??[]:e("path",{key:o.id,class:"tree-view__link",attrs:{d:o.path}})),d=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}},n),...d])])}}),u=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 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=l.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.$el,r=i.findScrollParent(t);if(!t||!r)return;const a=this.$refs.content,n=a?i.nodesInColumn(a,e.index,e.width,this.model.offset)[0]:void 0,d=n?i.horizontalBox(n,r):{left:i.offsetWithin(t,r)+e.index*e.width,width:e.width};i.smoothScrollLeft(r,i.roundScrollLeft({...d,viewport:r.clientWidth,scrollWidth:r.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
@@ -1 +1 @@
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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"}
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 horizontalBox,\n nodesInColumn,\n offsetWithin,\n roundScrollLeft,\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 * Вертикаль не трогаем: страница остаётся там, где была.\n */\n scrollToRound(column: BracketRoundColumn): void {\n const element = this.$el as HTMLElement | null\n const container = findScrollParent(element)\n if (!element || !container) return\n\n const content = this.$refs.content as HTMLElement | undefined\n // Карточки раунда стоят друг под другом, поэтому по горизонтали годится любая.\n const card = content\n ? nodesInColumn(content, column.index, column.width, this.model.offset)[0]\n : undefined\n\n const box = card\n ? horizontalBox(card, container)\n : {\n left: offsetWithin(element, container) + column.index * column.width,\n width: column.width,\n }\n\n smoothScrollLeft(\n container,\n roundScrollLeft({\n ...box,\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","element","container","findScrollParent","nodesInColumn","box","horizontalBox","offsetWithin","smoothScrollLeft","roundScrollLeft","injectStyles","styles","TreeViewPlugin"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
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";
1
+ import n 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, findScrollParent as _, nodesInColumn as C, horizontalBox as S, offsetWithin as T, smoothScrollLeft as $, roundScrollLeft as z, watchMedia as R, buildBracketRounds as B, injectStyles as I } from "@bigplay/tree-view-core";
3
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({
4
+ const d = n.extend({
5
5
  name: "TreeNodeCard",
6
6
  props: {
7
7
  label: { type: String, required: !0 },
@@ -30,7 +30,7 @@ const d = l.extend({
30
30
  )
31
31
  ), t("div", { class: "tree-view-card" }, e);
32
32
  }
33
- }), r = /* @__PURE__ */ new WeakMap(), I = l.extend({
33
+ }), r = /* @__PURE__ */ new WeakMap(), N = n.extend({
34
34
  name: "TreeView",
35
35
  props: {
36
36
  /** Объект, массив объектов или плоский список (вместе с `getParentId`). */
@@ -202,9 +202,9 @@ const d = l.extend({
202
202
  }
203
203
  },
204
204
  render(t) {
205
- const e = this.layout, i = this.drawn, s = this.$scopedSlots.link, n = i.links.map(
205
+ const e = this.layout, i = this.drawn, s = this.$scopedSlots.link, a = i.links.map(
206
206
  (o) => s ? s({ link: o }) ?? [] : t("path", { key: o.id, class: "tree-view__link", attrs: { d: o.path } })
207
- ), a = i.nodes.map(
207
+ ), l = i.nodes.map(
208
208
  (o) => t(
209
209
  "div",
210
210
  {
@@ -233,14 +233,14 @@ const d = l.extend({
233
233
  class: "tree-view__links",
234
234
  attrs: { width: e.width, height: e.height }
235
235
  },
236
- n
236
+ a
237
237
  ),
238
- ...a
238
+ ...l
239
239
  ])
240
240
  ]
241
241
  );
242
242
  }
243
- }), O = l.extend({
243
+ }), O = n.extend({
244
244
  name: "BracketCard",
245
245
  props: {
246
246
  /** Матч: нужны только команды. */
@@ -301,7 +301,7 @@ const d = l.extend({
301
301
  for (const s of e.rows) i.push(this.renderRow(t, s));
302
302
  return t("div", { class: ["tv-bracket", { "tv-bracket--my-team": e.hasMyTeam }] }, i);
303
303
  }
304
- }), L = l.extend({
304
+ }), L = n.extend({
305
305
  name: "BracketRounds",
306
306
  props: {
307
307
  /** Раунды по порядку — от первого к финалу. */
@@ -346,25 +346,27 @@ const d = l.extend({
346
346
  },
347
347
  methods: {
348
348
  /**
349
- * Подводит сетку к матчам раунда.
349
+ * Подводит сетку к матчам раунда — только по горизонтали.
350
350
  *
351
- * Сначала пробуем по самим карточкам: браузер сам подвинет и страницу, и блок
352
- * с прокруткой, поэтому финал оказывается на экране целиком, а не только
353
- * «где-то справа». Карточек не нашли (виртуализация) — считаем по колонкам.
351
+ * Меряем по самой карточке: так раунд встаёт по центру экрана точно, а у финала
352
+ * прокрутка упирается в правый край и он виден целиком. Карточек не нашли
353
+ * (виртуализация) — считаем по колонке, она той же ширины и на том же месте.
354
+ *
355
+ * Вертикаль не трогаем: страница остаётся там, где была.
354
356
  */
355
357
  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;
358
+ const e = this.$el, i = _(e);
359
+ if (!e || !i) return;
360
+ const s = this.$refs.content, a = s ? C(s, t.index, t.width, this.model.offset)[0] : void 0, l = a ? S(a, i) : {
361
+ left: T(e, i) + t.index * t.width,
362
+ width: t.width
363
+ };
361
364
  $(
362
- a,
365
+ i,
363
366
  z({
364
- left: o,
365
- width: t.width,
366
- viewport: a.clientWidth,
367
- scrollWidth: a.scrollWidth
367
+ ...l,
368
+ viewport: i.clientWidth,
369
+ scrollWidth: i.scrollWidth
368
370
  })
369
371
  );
370
372
  },
@@ -407,10 +409,10 @@ const d = l.extend({
407
409
  ), t("div", { class: "tv-rounds" }, e);
408
410
  }
409
411
  }), 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
+ I(E);
413
+ const M = {
412
414
  install(t) {
413
- t.component("TreeView", I), t.component("TreeNodeCard", d), t.component("BracketCard", O), t.component("BracketRounds", L);
415
+ t.component("TreeView", N), t.component("TreeNodeCard", d), t.component("BracketCard", O), t.component("BracketRounds", L);
414
416
  }
415
417
  };
416
418
  export {
@@ -419,11 +421,11 @@ export {
419
421
  A as DEFAULT_OPTIONS,
420
422
  P as MOBILE_MEDIA_QUERY,
421
423
  d as TreeNodeCard,
422
- I as TreeView,
423
- D as TreeViewPlugin,
424
+ N as TreeView,
425
+ M as TreeViewPlugin,
424
426
  F as bracketCardHeight,
425
427
  H as buildBracketCard,
426
428
  K as buildBracketRounds,
427
- D as default
429
+ M as default
428
430
  };
429
431
  //# 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/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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"}
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 horizontalBox,\n nodesInColumn,\n offsetWithin,\n roundScrollLeft,\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 * Вертикаль не трогаем: страница остаётся там, где была.\n */\n scrollToRound(column: BracketRoundColumn): void {\n const element = this.$el as HTMLElement | null\n const container = findScrollParent(element)\n if (!element || !container) return\n\n const content = this.$refs.content as HTMLElement | undefined\n // Карточки раунда стоят друг под другом, поэтому по горизонтали годится любая.\n const card = content\n ? nodesInColumn(content, column.index, column.width, this.model.offset)[0]\n : undefined\n\n const box = card\n ? horizontalBox(card, container)\n : {\n left: offsetWithin(element, container) + column.index * column.width,\n width: column.width,\n }\n\n smoothScrollLeft(\n container,\n roundScrollLeft({\n ...box,\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","element","container","findScrollParent","nodesInColumn","box","horizontalBox","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.0",
3
+ "version": "0.3.1",
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.3.0"
38
+ "@bigplay/tree-view-core": "^0.3.1"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "vue": "^2.6.0 || ^2.7.0"