@nubisco/ui 4.0.2 → 4.1.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.
@@ -3,7 +3,7 @@ import { existsSync } from 'node:fs'
3
3
  import path from 'node:path'
4
4
  import { fileURLToPath } from 'node:url'
5
5
  import MagicString from 'magic-string'
6
- import { parse } from 'vue/compiler-sfc'
6
+ import { parse, babelParse } from 'vue/compiler-sfc'
7
7
 
8
8
  /**
9
9
  * Resolves icon and flag artwork at compile time.
@@ -63,6 +63,15 @@ export interface IGlyphOptions {
63
63
  packageName?: string
64
64
  /** Log every rewrite. Useful when auditing what a page actually links. */
65
65
  verbose?: boolean
66
+ /**
67
+ * Warn when a glyph forwarded through another component (`<NbButton
68
+ * :icon="…">`) is a value this plugin cannot see through, so no artwork was
69
+ * linked for it. On by default, once per file, because the alternative is
70
+ * the silence that lets an icon reach `NbIcon` with nothing to resolve it
71
+ * against. Turn it off in a codebase where those bindings are deliberate
72
+ * pass-through props, resolved by whoever passes them in.
73
+ */
74
+ warnUnresolved?: boolean
66
75
  }
67
76
 
68
77
  type TKind = 'icon' | 'flag'
@@ -136,6 +145,99 @@ function staticWeight(element: any): string | undefined {
136
145
  return 'regular'
137
146
  }
138
147
 
148
+ /**
149
+ * Parse one template expression on its own. `babelParse` wants a program, so
150
+ * the expression is wrapped; a binding Vue accepts but Babel cannot read is
151
+ * simply unknown, which the caller treats as unresolved.
152
+ */
153
+ function parseExpression(expression: string): any {
154
+ try {
155
+ const { program } = babelParse(`(${expression})`, {
156
+ sourceType: 'module',
157
+ plugins: ['typescript'],
158
+ })
159
+ const statement: any = program.body[0]
160
+ return statement?.type === 'ExpressionStatement'
161
+ ? statement.expression
162
+ : undefined
163
+ } catch {
164
+ return undefined
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Whether every value this expression can hand to the component is artwork the
170
+ * bundle already links: a literal this plugin just rewrote, or a glyph module
171
+ * the file imported itself.
172
+ *
173
+ * The point is what it refuses. `open ? 'caret-up' : 'caret-down'` produces one
174
+ * of two rewritten literals and nothing else, so it is resolved. `block?.icon
175
+ * || 'cube'` also contains a rewritten literal, but it can just as easily
176
+ * produce `block.icon`, which is a runtime value and needs the catalogue.
177
+ * Judging by "a rewritten literal appears and no quoted string survives" called
178
+ * that second one resolved, which meant adding a literal fallback silently
179
+ * removed the coverage the same expression had without one.
180
+ */
181
+ function producesOnlyLinkedGlyphs(
182
+ node: any,
183
+ isLinked: (name: string) => boolean,
184
+ ): boolean {
185
+ if (!node) return false
186
+ const recurse = (child: any) => producesOnlyLinkedGlyphs(child, isLinked)
187
+ switch (node.type) {
188
+ case 'Identifier':
189
+ return isLinked(node.name)
190
+ // The test is not a value the prop receives; the two arms are.
191
+ case 'ConditionalExpression':
192
+ return recurse(node.consequent) && recurse(node.alternate)
193
+ // `a || b`, `a ?? b` and `a && b` can all produce either side.
194
+ case 'LogicalExpression':
195
+ return recurse(node.left) && recurse(node.right)
196
+ case 'SequenceExpression':
197
+ return recurse(node.expressions[node.expressions.length - 1])
198
+ case 'TSAsExpression':
199
+ case 'TSNonNullExpression':
200
+ case 'TSSatisfiesExpression':
201
+ case 'ParenthesizedExpression':
202
+ return recurse(node.expression)
203
+ default:
204
+ return false
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Local names bound to glyph modules by the file's own imports, so that
210
+ * `<NbIcon :name="GithubLogo" />` is understood as already-linked artwork
211
+ * rather than as a runtime name needing the whole catalogue.
212
+ */
213
+ function glyphImportLocals(script: string, packageName: string): Set<string> {
214
+ const locals = new Set<string>()
215
+ const from = packageName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
216
+ const pattern = new RegExp(
217
+ `import\\s+([^;'"\n]+?)\\s+from\\s*['"]${from}/(?:icons|flags)/[^'"]+['"]`,
218
+ 'g',
219
+ )
220
+ for (const match of script.matchAll(pattern)) {
221
+ const clause = match[1]
222
+ const namespace = clause.match(/\*\s+as\s+(\w+)/)
223
+ if (namespace) locals.add(namespace[1])
224
+ const defaultImport = clause.match(/^\s*(\w+)/)
225
+ if (defaultImport) locals.add(defaultImport[1])
226
+ const named = clause.match(/\{([^}]*)\}/)
227
+ if (named) {
228
+ for (const part of named[1].split(',')) {
229
+ const local = part
230
+ .trim()
231
+ .split(/\s+as\s+/)
232
+ .pop()
233
+ ?.trim()
234
+ if (local) locals.add(local)
235
+ }
236
+ }
237
+ }
238
+ return locals
239
+ }
240
+
139
241
  function staticPropKind(
140
242
  name: string,
141
243
  isIcon: boolean,
@@ -157,6 +259,7 @@ export function nubiscoGlyphs(options: IGlyphOptions = {}) {
157
259
  flags = true,
158
260
  packageName = '@nubisco/ui',
159
261
  verbose = false,
262
+ warnUnresolved = true,
160
263
  } = options
161
264
 
162
265
  const glyphRoot = options.glyphRoot ?? defaultGlyphRoot()
@@ -186,6 +289,16 @@ export function nubiscoGlyphs(options: IGlyphOptions = {}) {
186
289
  const edits: IEdit[] = []
187
290
  const used = new Map<string, IGlyphImport>()
188
291
  const catalogsNeeded = new Set<TKind>()
292
+ const unresolvedForwards: { tag: string; prop: string; exp: string }[] =
293
+ []
294
+
295
+ // Artwork the file already imports by hand counts as linked: binding an
296
+ // imported module is the documented no-plugin path, and pulling a
297
+ // catalogue in on top of it would be pure waste.
298
+ const glyphLocals = glyphImportLocals(
299
+ `${descriptor.scriptSetup?.content ?? ''}\n${descriptor.script?.content ?? ''}`,
300
+ packageName,
301
+ )
189
302
 
190
303
  const use = (glyph: IGlyphImport) => {
191
304
  const variable = identifierFor(glyph)
@@ -229,17 +342,18 @@ export function nubiscoGlyphs(options: IGlyphOptions = {}) {
229
342
  continue
230
343
  }
231
344
 
232
- /* ---- bound: :name="…" on NbIcon / NbFlag --------------------- */
345
+ /* ---- bound: :name="…", :icon="…", :flag="…" ------------------ */
233
346
  if (
234
347
  prop.type === NODE_DIRECTIVE &&
235
348
  prop.name === 'bind' &&
236
349
  prop.arg?.type === EXPR_SIMPLE &&
237
- prop.exp?.type === EXPR_SIMPLE &&
238
- (isIcon || isFlag)
350
+ prop.exp?.type === EXPR_SIMPLE
239
351
  ) {
240
- const kind: TKind = isIcon ? 'icon' : 'flag'
241
- if (!enabled(kind)) continue
242
- if (!['name', 'icon', 'flag'].includes(prop.arg.content)) continue
352
+ // Same rule as the static branch, so `:icon="a ? 'check' : 'copy'"`
353
+ // links the two icons whether it is written on NbIcon or forwarded
354
+ // through NbButton. Only the tag decides the kind.
355
+ const kind = staticPropKind(prop.arg.content, isIcon, isFlag)
356
+ if (!kind || !enabled(kind)) continue
243
357
 
244
358
  const expression: string = prop.exp.content
245
359
  const rewritten = expression.replace(
@@ -262,16 +376,52 @@ export function nubiscoGlyphs(options: IGlyphOptions = {}) {
262
376
  })
263
377
  }
264
378
 
265
- // Considered resolved when every value the expression can produce
266
- // is one of the modules just imported: at least one appears, and
267
- // no string literal survived that could not be accounted for.
268
- const resolved =
269
- rewritten.includes('__nb_') && !/['"]/.test(rewritten)
270
- if (!resolved) catalogsNeeded.add(kind)
379
+ const resolved = producesOnlyLinkedGlyphs(
380
+ parseExpression(rewritten),
381
+ (identifier) =>
382
+ used.has(identifier) || glyphLocals.has(identifier),
383
+ )
384
+ if (resolved) continue
385
+
386
+ // On NbIcon or NbFlag an unresolvable name is fatal at first
387
+ // render, so the catalogue is the only thing that can save it. On
388
+ // a forwarding component the same expression may just as well be
389
+ // a module arriving as a prop, and linking 1,500 icons on that
390
+ // guess would make the common wrapper the most expensive file in
391
+ // the bundle. So that case is reported rather than paid for.
392
+ if (isIcon || isFlag) catalogsNeeded.add(kind)
393
+ else
394
+ unresolvedForwards.push({
395
+ tag,
396
+ prop: prop.arg.content,
397
+ exp: expression,
398
+ })
271
399
  }
272
400
  }
273
401
  })
274
402
 
403
+ // One line per file, however many bindings it has: this is a note about
404
+ // the file, and repeating the same advice per expression would train
405
+ // people to skip it.
406
+ if (warnUnresolved && unresolvedForwards.length) {
407
+ const kinds = new Set(unresolvedForwards.map((f) => f.prop))
408
+ const register = kinds.has('flag')
409
+ ? 'registerFlags()'
410
+ : 'registerIcons()'
411
+ const catalogue = `${packageName}/${kinds.has('flag') ? 'flags' : 'icons'}/all`
412
+ console.warn(
413
+ `[nubisco-ui] ${path.relative(process.cwd(), file)}: no artwork ` +
414
+ `linked for ` +
415
+ unresolvedForwards
416
+ .map((f) => `<${f.tag} :${f.prop}="${f.exp}">`)
417
+ .join(', ') +
418
+ `. The value is only known at runtime, so it will throw on first ` +
419
+ `render unless something resolves it: ${register} for a known ` +
420
+ `set, or import '${catalogue}' in this file. Nothing to do if ` +
421
+ `these are pass-through props (set warnUnresolved: false).`,
422
+ )
423
+ }
424
+
275
425
  if (!used.size && !catalogsNeeded.size) return
276
426
 
277
427
  const imports: string[] = []
@@ -1 +0,0 @@
1
- require(`./chunk-D-qHiVGv.cjs`);const e=require(`./_plugin-vue_export-helper-tagjRzOz.cjs`),t=require(`./palette-73dy8s3C.cjs`),n=require(`./ChartLegend-CkL6V-U_.cjs`),r=require(`./scales-Bzt05iAE.cjs`),i=require(`./useChartSize-xKPzLmex.cjs`);let a=require(`vue`);var o=[`width`,`height`,`aria-label`],s={key:0},c=[`x1`,`x2`,`y1`,`y2`],l={class:`nb-chart__axis`},u=[`x`,`y`],d={class:`nb-chart__axis`},f=[`x`,`y`],p=[`x1`,`x2`,`y1`,`y2`],m=[`x`,`y`,`width`,`height`,`fill`],h={class:`nb-chart__hover-layer`},g=[`x`,`y`,`width`,`height`,`onMouseenter`,`onMousemove`],_=(0,a.defineComponent)({__name:`BarChart`,props:{series:{default:()=>[]},orientation:{default:`vertical`},stacked:{type:Boolean,default:!1},title:{default:void 0},subtitle:{default:void 0},height:{default:280},showLegend:{type:Boolean,default:!0},showTooltip:{type:Boolean,default:!0},showGrid:{type:Boolean,default:!0},colors:{default:()=>t.n}},setup(e){let _=e,v={top:12,right:16,bottom:28,left:44},y=(0,a.ref)(null),b=i.t(y,{width:480,height:240}),x=(0,a.computed)(()=>_.series.map((e,n)=>({name:e.name,data:e.data,color:e.color??t.i(n,_.colors)}))),S=(0,a.computed)(()=>(_.series[0]?.data??[]).map(e=>e.x)),C=(0,a.computed)(()=>{let e=_.series.flatMap(e=>e.data.map(e=>e.y));return e.length?r.i(Math.min(0,...e),Math.max(0,...e),.05):[0,1]}),w=(0,a.computed)(()=>r.t(S.value.map(e=>String(e)),[v.left,Math.max(v.left,b.value.width-v.right)],.2)),T=(0,a.computed)(()=>r.r(C.value,[Math.max(v.top,b.value.height-v.bottom),v.top])),E=(0,a.computed)(()=>T.value.ticks(5)),D=(0,a.computed)(()=>x.value.length?w.value.bandwidth/x.value.length:w.value.bandwidth),O=e=>e>=0?T.value(e):T.value(0),k=e=>e>=0?Math.max(0,T.value(0)-T.value(e)):Math.max(0,T.value(e)-T.value(0)),A=e=>Math.abs(e)>=1e3?`${(e/1e3).toFixed(1)}k`:String(e),j=(0,a.ref)(null),M=(0,a.ref)({x:0,y:0}),N=(e,t)=>{let n=e.currentTarget.ownerSVGElement;if(!n)return;let r=n.getBoundingClientRect();M.value={x:e.clientX-r.left+12,y:e.clientY-r.top+12},j.value=t},P=(0,a.computed)(()=>j.value===null?[]:x.value.map(e=>({label:e.name,value:A(e.data[j.value]?.y??0),color:e.color})));return(r,i)=>((0,a.openBlock)(),(0,a.createBlock)(t.u,{title:e.title,subtitle:e.subtitle,height:e.height,"show-legend":e.showLegend&&x.value.length>0},{legend:(0,a.withCtx)(()=>[(0,a.createVNode)(n.t,{items:x.value.map(e=>({label:e.name,color:e.color}))},null,8,[`items`])]),default:(0,a.withCtx)(()=>[(0,a.createElementVNode)(`div`,{ref_key:`root`,ref:y,class:`nb-bar-chart`},[((0,a.openBlock)(),(0,a.createElementBlock)(`svg`,{width:(0,a.unref)(b).width,height:(0,a.unref)(b).height,class:`nb-chart__svg`,role:`img`,"aria-label":e.title||`Bar chart`,onMouseleave:i[0]||=e=>j.value=null},[e.showGrid&&(0,a.unref)(b).width>0?((0,a.openBlock)(),(0,a.createElementBlock)(`g`,s,[((0,a.openBlock)(!0),(0,a.createElementBlock)(a.Fragment,null,(0,a.renderList)(E.value,e=>((0,a.openBlock)(),(0,a.createElementBlock)(`line`,{key:`grid-${e}`,class:`nb-chart__gridline`,x1:v.left,x2:(0,a.unref)(b).width-v.right,y1:T.value(e),y2:T.value(e)},null,8,c))),128))])):(0,a.createCommentVNode)(``,!0),(0,a.createElementVNode)(`g`,l,[((0,a.openBlock)(!0),(0,a.createElementBlock)(a.Fragment,null,(0,a.renderList)(E.value,e=>((0,a.openBlock)(),(0,a.createElementBlock)(`text`,{key:`yt-${e}`,x:v.left-6,y:T.value(e),"text-anchor":`end`,"dominant-baseline":`middle`},(0,a.toDisplayString)(A(e)),9,u))),128))]),(0,a.createElementVNode)(`g`,d,[((0,a.openBlock)(!0),(0,a.createElementBlock)(a.Fragment,null,(0,a.renderList)(S.value,(e,t)=>((0,a.openBlock)(),(0,a.createElementBlock)(`text`,{key:`xt-${t}`,x:w.value(String(e))+w.value.bandwidth/2,y:(0,a.unref)(b).height-v.bottom+14,"text-anchor":`middle`},(0,a.toDisplayString)(e),9,f))),128))]),(0,a.createElementVNode)(`line`,{class:`nb-chart__axis-line`,x1:v.left,x2:(0,a.unref)(b).width-v.right,y1:T.value(0),y2:T.value(0)},null,8,p),((0,a.openBlock)(!0),(0,a.createElementBlock)(a.Fragment,null,(0,a.renderList)(S.value,(e,t)=>((0,a.openBlock)(),(0,a.createElementBlock)(`g`,{key:`g-${t}`},[((0,a.openBlock)(!0),(0,a.createElementBlock)(a.Fragment,null,(0,a.renderList)(x.value,(n,r)=>((0,a.openBlock)(),(0,a.createElementBlock)(`rect`,{key:`${t}-${r}`,class:(0,a.normalizeClass)([`nb-chart__bar`,{"is-dim":j.value!==null&&j.value!==t}]),x:w.value(String(e))+r*D.value,y:O(n.data[t]?.y??0),width:Math.max(0,D.value-2),height:k(n.data[t]?.y??0),fill:n.color},null,10,m))),128))]))),128)),(0,a.createElementVNode)(`g`,h,[((0,a.openBlock)(!0),(0,a.createElementBlock)(a.Fragment,null,(0,a.renderList)(S.value,(e,t)=>((0,a.openBlock)(),(0,a.createElementBlock)(`rect`,{key:`hover-${t}`,x:w.value(String(e)),y:v.top,width:w.value.bandwidth,height:Math.max(0,(0,a.unref)(b).height-v.top-v.bottom),fill:`transparent`,onMouseenter:e=>j.value=t,onMousemove:e=>N(e,t)},null,40,g))),128))])],40,o)),(0,a.createVNode)(t.l,{visible:e.showTooltip&&j.value!==null,x:M.value.x,y:M.value.y,title:j.value===null?``:String(S.value[j.value]),rows:P.value},null,8,[`visible`,`x`,`y`,`title`,`rows`])],512)]),_:1},8,[`title`,`subtitle`,`height`,`show-legend`]))}}),v=e.t(_,[[`__scopeId`,`data-v-452a9823`]]);Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return v}});
@@ -1,185 +0,0 @@
1
- import { t as e } from "./_plugin-vue_export-helper-O4QQSku4.js";
2
- import { i as t, l as n, n as r, u as i } from "./palette-DpTb1uUD.js";
3
- import { t as a } from "./ChartLegend-DvjSe_3l.js";
4
- import { i as o, r as s, t as c } from "./scales-DzXsYt4Z.js";
5
- import { t as l } from "./useChartSize-B6TdJSnI.js";
6
- import { Fragment as u, computed as d, createBlock as f, createCommentVNode as p, createElementBlock as m, createElementVNode as h, createVNode as g, defineComponent as _, normalizeClass as v, openBlock as y, ref as b, renderList as x, toDisplayString as S, unref as C, withCtx as w } from "vue";
7
- //#region src/components/Charts/BarChart.vue?vue&type=script&setup=true&lang.ts
8
- var T = [
9
- "width",
10
- "height",
11
- "aria-label"
12
- ], E = { key: 0 }, D = [
13
- "x1",
14
- "x2",
15
- "y1",
16
- "y2"
17
- ], O = { class: "nb-chart__axis" }, k = ["x", "y"], A = { class: "nb-chart__axis" }, j = ["x", "y"], M = [
18
- "x1",
19
- "x2",
20
- "y1",
21
- "y2"
22
- ], N = [
23
- "x",
24
- "y",
25
- "width",
26
- "height",
27
- "fill"
28
- ], P = { class: "nb-chart__hover-layer" }, F = [
29
- "x",
30
- "y",
31
- "width",
32
- "height",
33
- "onMouseenter",
34
- "onMousemove"
35
- ], I = /* @__PURE__ */ e(/* @__PURE__ */ _({
36
- __name: "BarChart",
37
- props: {
38
- series: { default: () => [] },
39
- orientation: { default: "vertical" },
40
- stacked: {
41
- type: Boolean,
42
- default: !1
43
- },
44
- title: { default: void 0 },
45
- subtitle: { default: void 0 },
46
- height: { default: 280 },
47
- showLegend: {
48
- type: Boolean,
49
- default: !0
50
- },
51
- showTooltip: {
52
- type: Boolean,
53
- default: !0
54
- },
55
- showGrid: {
56
- type: Boolean,
57
- default: !0
58
- },
59
- colors: { default: () => r }
60
- },
61
- setup(e) {
62
- let r = e, _ = {
63
- top: 12,
64
- right: 16,
65
- bottom: 28,
66
- left: 44
67
- }, I = b(null), L = l(I, {
68
- width: 480,
69
- height: 240
70
- }), R = d(() => r.series.map((e, n) => ({
71
- name: e.name,
72
- data: e.data,
73
- color: e.color ?? t(n, r.colors)
74
- }))), z = d(() => (r.series[0]?.data ?? []).map((e) => e.x)), B = d(() => {
75
- let e = r.series.flatMap((e) => e.data.map((e) => e.y));
76
- return e.length ? o(Math.min(0, ...e), Math.max(0, ...e), .05) : [0, 1];
77
- }), V = d(() => c(z.value.map((e) => String(e)), [_.left, Math.max(_.left, L.value.width - _.right)], .2)), H = d(() => s(B.value, [Math.max(_.top, L.value.height - _.bottom), _.top])), U = d(() => H.value.ticks(5)), W = d(() => R.value.length ? V.value.bandwidth / R.value.length : V.value.bandwidth), G = (e) => e >= 0 ? H.value(e) : H.value(0), K = (e) => e >= 0 ? Math.max(0, H.value(0) - H.value(e)) : Math.max(0, H.value(e) - H.value(0)), q = (e) => Math.abs(e) >= 1e3 ? `${(e / 1e3).toFixed(1)}k` : String(e), J = b(null), Y = b({
78
- x: 0,
79
- y: 0
80
- }), X = (e, t) => {
81
- let n = e.currentTarget.ownerSVGElement;
82
- if (!n) return;
83
- let r = n.getBoundingClientRect();
84
- Y.value = {
85
- x: e.clientX - r.left + 12,
86
- y: e.clientY - r.top + 12
87
- }, J.value = t;
88
- }, Z = d(() => J.value === null ? [] : R.value.map((e) => ({
89
- label: e.name,
90
- value: q(e.data[J.value]?.y ?? 0),
91
- color: e.color
92
- })));
93
- return (t, r) => (y(), f(i, {
94
- title: e.title,
95
- subtitle: e.subtitle,
96
- height: e.height,
97
- "show-legend": e.showLegend && R.value.length > 0
98
- }, {
99
- legend: w(() => [g(a, { items: R.value.map((e) => ({
100
- label: e.name,
101
- color: e.color
102
- })) }, null, 8, ["items"])]),
103
- default: w(() => [h("div", {
104
- ref_key: "root",
105
- ref: I,
106
- class: "nb-bar-chart"
107
- }, [(y(), m("svg", {
108
- width: C(L).width,
109
- height: C(L).height,
110
- class: "nb-chart__svg",
111
- role: "img",
112
- "aria-label": e.title || "Bar chart",
113
- onMouseleave: r[0] ||= (e) => J.value = null
114
- }, [
115
- e.showGrid && C(L).width > 0 ? (y(), m("g", E, [(y(!0), m(u, null, x(U.value, (e) => (y(), m("line", {
116
- key: `grid-${e}`,
117
- class: "nb-chart__gridline",
118
- x1: _.left,
119
- x2: C(L).width - _.right,
120
- y1: H.value(e),
121
- y2: H.value(e)
122
- }, null, 8, D))), 128))])) : p("", !0),
123
- h("g", O, [(y(!0), m(u, null, x(U.value, (e) => (y(), m("text", {
124
- key: `yt-${e}`,
125
- x: _.left - 6,
126
- y: H.value(e),
127
- "text-anchor": "end",
128
- "dominant-baseline": "middle"
129
- }, S(q(e)), 9, k))), 128))]),
130
- h("g", A, [(y(!0), m(u, null, x(z.value, (e, t) => (y(), m("text", {
131
- key: `xt-${t}`,
132
- x: V.value(String(e)) + V.value.bandwidth / 2,
133
- y: C(L).height - _.bottom + 14,
134
- "text-anchor": "middle"
135
- }, S(e), 9, j))), 128))]),
136
- h("line", {
137
- class: "nb-chart__axis-line",
138
- x1: _.left,
139
- x2: C(L).width - _.right,
140
- y1: H.value(0),
141
- y2: H.value(0)
142
- }, null, 8, M),
143
- (y(!0), m(u, null, x(z.value, (e, t) => (y(), m("g", { key: `g-${t}` }, [(y(!0), m(u, null, x(R.value, (n, r) => (y(), m("rect", {
144
- key: `${t}-${r}`,
145
- class: v(["nb-chart__bar", { "is-dim": J.value !== null && J.value !== t }]),
146
- x: V.value(String(e)) + r * W.value,
147
- y: G(n.data[t]?.y ?? 0),
148
- width: Math.max(0, W.value - 2),
149
- height: K(n.data[t]?.y ?? 0),
150
- fill: n.color
151
- }, null, 10, N))), 128))]))), 128)),
152
- h("g", P, [(y(!0), m(u, null, x(z.value, (e, t) => (y(), m("rect", {
153
- key: `hover-${t}`,
154
- x: V.value(String(e)),
155
- y: _.top,
156
- width: V.value.bandwidth,
157
- height: Math.max(0, C(L).height - _.top - _.bottom),
158
- fill: "transparent",
159
- onMouseenter: (e) => J.value = t,
160
- onMousemove: (e) => X(e, t)
161
- }, null, 40, F))), 128))])
162
- ], 40, T)), g(n, {
163
- visible: e.showTooltip && J.value !== null,
164
- x: Y.value.x,
165
- y: Y.value.y,
166
- title: J.value === null ? "" : String(z.value[J.value]),
167
- rows: Z.value
168
- }, null, 8, [
169
- "visible",
170
- "x",
171
- "y",
172
- "title",
173
- "rows"
174
- ])], 512)]),
175
- _: 1
176
- }, 8, [
177
- "title",
178
- "subtitle",
179
- "height",
180
- "show-legend"
181
- ]));
182
- }
183
- }), [["__scopeId", "data-v-452a9823"]]);
184
- //#endregion
185
- export { I as t };
@@ -1 +0,0 @@
1
- require(`./chunk-D-qHiVGv.cjs`);const e=require(`./_plugin-vue_export-helper-tagjRzOz.cjs`),t=require(`./palette-73dy8s3C.cjs`),n=require(`./ChartLegend-CkL6V-U_.cjs`),r=require(`./useChartSize-xKPzLmex.cjs`);let i=require(`vue`);var a=[`width`,`height`,`aria-label`],o=[`transform`],s=[`d`,`fill`,`onMouseenter`],c=[`x`,`y`],l=(0,i.defineComponent)({__name:`PieChart`,props:{data:{default:()=>[]},innerRadius:{default:0},labels:{default:`percent`},title:{default:void 0},subtitle:{default:void 0},height:{default:280},showLegend:{type:Boolean,default:!0},showTooltip:{type:Boolean,default:!0},colors:{default:()=>t.n}},setup(e){let l=e,u=(0,i.ref)(null),d=r.t(u,{width:280,height:240}),f=(0,i.computed)(()=>l.data.map((e,n)=>({label:e.label,value:e.value,color:e.color??t.i(n,l.colors)}))),p=(0,i.computed)(()=>f.value.reduce((e,t)=>e+Math.max(0,t.value),0)),m=(0,i.computed)(()=>d.value.width/2),h=(0,i.computed)(()=>d.value.height/2),g=(0,i.computed)(()=>Math.max(0,Math.min(d.value.width,d.value.height)/2-8)),_=(0,i.computed)(()=>Math.max(0,Math.min(.95,l.innerRadius))*g.value),v=(0,i.computed)(()=>{if(!p.value)return[];let e=-Math.PI/2,t=[];for(let n=0;n<f.value.length;n++){let r=f.value[n],i=Math.max(0,r.value)/p.value,a=e,o=e+i*Math.PI*2;e=o;let s=y(a,o,_.value,g.value),c=(a+o)/2,u=_.value>0?(_.value+g.value)/2:g.value*.65,d=Math.cos(c)*u,m=Math.sin(c)*u,h=l.labels===`percent`?`${Math.round(i*100)}%`:l.labels===`value`?String(r.value):``;t.push({path:s,color:r.color,labelX:d,labelY:m,labelText:h,labelColor:`var(--nb-c-white)`,startAngle:a,endAngle:o,value:r.value,label:r.label})}return t}),y=(e,t,n,r)=>{if(Math.abs(t-e)>=Math.PI*2-1e-6){let e=`M ${r} 0 A ${r} ${r} 0 1 1 ${-r} 0 A ${r} ${r} 0 1 1 ${r} 0 Z`;return n<=0?e:`${e} ${`M ${n} 0 A ${n} ${n} 0 1 0 ${-n} 0 A ${n} ${n} 0 1 0 ${n} 0 Z`}`}let i=Math.cos(e)*r,a=Math.sin(e)*r,o=Math.cos(t)*r,s=Math.sin(t)*r,c=t-e>Math.PI?1:0;if(n<=0)return`M 0 0 L ${i} ${a} A ${r} ${r} 0 ${c} 1 ${o} ${s} Z`;let l=Math.cos(t)*n,u=Math.sin(t)*n,d=Math.cos(e)*n,f=Math.sin(e)*n;return[`M ${i} ${a}`,`A ${r} ${r} 0 ${c} 1 ${o} ${s}`,`L ${l} ${u}`,`A ${n} ${n} 0 ${c} 0 ${d} ${f}`,`Z`].join(` `)},b=(0,i.ref)(null),x=(0,i.ref)({x:0,y:0}),S=e=>{let t=e.currentTarget.ownerSVGElement;if(!t)return;let n=t.getBoundingClientRect();x.value={x:e.clientX-n.left+12,y:e.clientY-n.top+12}},C=(0,i.computed)(()=>{if(b.value===null)return[];let e=v.value[b.value];if(!e)return[];let t=p.value?Math.round(e.value/p.value*100):0;return[{label:e.label,value:`${e.value} (${t}%)`,color:e.color}]});return(r,l)=>((0,i.openBlock)(),(0,i.createBlock)(t.u,{title:e.title,subtitle:e.subtitle,height:e.height,"show-legend":e.showLegend&&f.value.length>0},{legend:(0,i.withCtx)(()=>[(0,i.createVNode)(n.t,{items:f.value.map(e=>({label:e.label,color:e.color}))},null,8,[`items`])]),default:(0,i.withCtx)(()=>[(0,i.createElementVNode)(`div`,{ref_key:`root`,ref:u,class:`nb-pie-chart`},[((0,i.openBlock)(),(0,i.createElementBlock)(`svg`,{width:(0,i.unref)(d).width,height:(0,i.unref)(d).height,class:`nb-chart__svg`,role:`img`,"aria-label":e.title||`Pie chart`,onMouseleave:l[1]||=e=>b.value=null},[(0,i.createElementVNode)(`g`,{transform:`translate(${m.value}, ${h.value})`},[((0,i.openBlock)(!0),(0,i.createElementBlock)(i.Fragment,null,(0,i.renderList)(v.value,(e,t)=>((0,i.openBlock)(),(0,i.createElementBlock)(`path`,{key:`slice-${t}`,class:(0,i.normalizeClass)([`nb-chart__slice`,{"is-dim":b.value!==null&&b.value!==t}]),d:e.path,fill:e.color,onMouseenter:e=>b.value=t,onMousemove:l[0]||=e=>S(e)},null,42,s))),128)),e.labels===`none`?(0,i.createCommentVNode)(``,!0):((0,i.openBlock)(!0),(0,i.createElementBlock)(i.Fragment,{key:0},(0,i.renderList)(v.value,(e,t)=>((0,i.openBlock)(),(0,i.createElementBlock)(`text`,{key:`lab-${t}`,class:`nb-chart__slice-label`,x:e.labelX,y:e.labelY,"text-anchor":`middle`,"dominant-baseline":`middle`,style:(0,i.normalizeStyle)({fill:e.labelColor})},(0,i.toDisplayString)(e.labelText),13,c))),128))],8,o)],40,a)),(0,i.createVNode)(t.l,{visible:e.showTooltip&&b.value!==null,x:x.value.x,y:x.value.y,rows:C.value},null,8,[`visible`,`x`,`y`,`rows`])],512)]),_:1},8,[`title`,`subtitle`,`height`,`show-legend`]))}}),u=e.t(l,[[`__scopeId`,`data-v-26bfcb67`]]);Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return u}});
@@ -1,157 +0,0 @@
1
- import { t as e } from "./_plugin-vue_export-helper-O4QQSku4.js";
2
- import { i as t, l as n, n as r, u as i } from "./palette-DpTb1uUD.js";
3
- import { t as a } from "./ChartLegend-DvjSe_3l.js";
4
- import { t as o } from "./useChartSize-B6TdJSnI.js";
5
- import { Fragment as s, computed as c, createBlock as l, createCommentVNode as u, createElementBlock as d, createElementVNode as f, createVNode as p, defineComponent as m, normalizeClass as h, normalizeStyle as g, openBlock as _, ref as v, renderList as y, toDisplayString as b, unref as x, withCtx as S } from "vue";
6
- //#region src/components/Charts/PieChart.vue?vue&type=script&setup=true&lang.ts
7
- var C = [
8
- "width",
9
- "height",
10
- "aria-label"
11
- ], w = ["transform"], T = [
12
- "d",
13
- "fill",
14
- "onMouseenter"
15
- ], E = ["x", "y"], D = /* @__PURE__ */ e(/* @__PURE__ */ m({
16
- __name: "PieChart",
17
- props: {
18
- data: { default: () => [] },
19
- innerRadius: { default: 0 },
20
- labels: { default: "percent" },
21
- title: { default: void 0 },
22
- subtitle: { default: void 0 },
23
- height: { default: 280 },
24
- showLegend: {
25
- type: Boolean,
26
- default: !0
27
- },
28
- showTooltip: {
29
- type: Boolean,
30
- default: !0
31
- },
32
- colors: { default: () => r }
33
- },
34
- setup(e) {
35
- let r = e, m = v(null), D = o(m, {
36
- width: 280,
37
- height: 240
38
- }), O = c(() => r.data.map((e, n) => ({
39
- label: e.label,
40
- value: e.value,
41
- color: e.color ?? t(n, r.colors)
42
- }))), k = c(() => O.value.reduce((e, t) => e + Math.max(0, t.value), 0)), A = c(() => D.value.width / 2), j = c(() => D.value.height / 2), M = c(() => Math.max(0, Math.min(D.value.width, D.value.height) / 2 - 8)), N = c(() => Math.max(0, Math.min(.95, r.innerRadius)) * M.value), P = c(() => {
43
- if (!k.value) return [];
44
- let e = -Math.PI / 2, t = [];
45
- for (let n = 0; n < O.value.length; n++) {
46
- let i = O.value[n], a = Math.max(0, i.value) / k.value, o = e, s = e + a * Math.PI * 2;
47
- e = s;
48
- let c = F(o, s, N.value, M.value), l = (o + s) / 2, u = N.value > 0 ? (N.value + M.value) / 2 : M.value * .65, d = Math.cos(l) * u, f = Math.sin(l) * u, p = r.labels === "percent" ? `${Math.round(a * 100)}%` : r.labels === "value" ? String(i.value) : "";
49
- t.push({
50
- path: c,
51
- color: i.color,
52
- labelX: d,
53
- labelY: f,
54
- labelText: p,
55
- labelColor: "var(--nb-c-white)",
56
- startAngle: o,
57
- endAngle: s,
58
- value: i.value,
59
- label: i.label
60
- });
61
- }
62
- return t;
63
- }), F = (e, t, n, r) => {
64
- if (Math.abs(t - e) >= Math.PI * 2 - 1e-6) {
65
- let e = `M ${r} 0 A ${r} ${r} 0 1 1 ${-r} 0 A ${r} ${r} 0 1 1 ${r} 0 Z`;
66
- return n <= 0 ? e : `${e} ${`M ${n} 0 A ${n} ${n} 0 1 0 ${-n} 0 A ${n} ${n} 0 1 0 ${n} 0 Z`}`;
67
- }
68
- let i = Math.cos(e) * r, a = Math.sin(e) * r, o = Math.cos(t) * r, s = Math.sin(t) * r, c = t - e > Math.PI ? 1 : 0;
69
- if (n <= 0) return `M 0 0 L ${i} ${a} A ${r} ${r} 0 ${c} 1 ${o} ${s} Z`;
70
- let l = Math.cos(t) * n, u = Math.sin(t) * n, d = Math.cos(e) * n, f = Math.sin(e) * n;
71
- return [
72
- `M ${i} ${a}`,
73
- `A ${r} ${r} 0 ${c} 1 ${o} ${s}`,
74
- `L ${l} ${u}`,
75
- `A ${n} ${n} 0 ${c} 0 ${d} ${f}`,
76
- "Z"
77
- ].join(" ");
78
- }, I = v(null), L = v({
79
- x: 0,
80
- y: 0
81
- }), R = (e) => {
82
- let t = e.currentTarget.ownerSVGElement;
83
- if (!t) return;
84
- let n = t.getBoundingClientRect();
85
- L.value = {
86
- x: e.clientX - n.left + 12,
87
- y: e.clientY - n.top + 12
88
- };
89
- }, z = c(() => {
90
- if (I.value === null) return [];
91
- let e = P.value[I.value];
92
- if (!e) return [];
93
- let t = k.value ? Math.round(e.value / k.value * 100) : 0;
94
- return [{
95
- label: e.label,
96
- value: `${e.value} (${t}%)`,
97
- color: e.color
98
- }];
99
- });
100
- return (t, r) => (_(), l(i, {
101
- title: e.title,
102
- subtitle: e.subtitle,
103
- height: e.height,
104
- "show-legend": e.showLegend && O.value.length > 0
105
- }, {
106
- legend: S(() => [p(a, { items: O.value.map((e) => ({
107
- label: e.label,
108
- color: e.color
109
- })) }, null, 8, ["items"])]),
110
- default: S(() => [f("div", {
111
- ref_key: "root",
112
- ref: m,
113
- class: "nb-pie-chart"
114
- }, [(_(), d("svg", {
115
- width: x(D).width,
116
- height: x(D).height,
117
- class: "nb-chart__svg",
118
- role: "img",
119
- "aria-label": e.title || "Pie chart",
120
- onMouseleave: r[1] ||= (e) => I.value = null
121
- }, [f("g", { transform: `translate(${A.value}, ${j.value})` }, [(_(!0), d(s, null, y(P.value, (e, t) => (_(), d("path", {
122
- key: `slice-${t}`,
123
- class: h(["nb-chart__slice", { "is-dim": I.value !== null && I.value !== t }]),
124
- d: e.path,
125
- fill: e.color,
126
- onMouseenter: (e) => I.value = t,
127
- onMousemove: r[0] ||= (e) => R(e)
128
- }, null, 42, T))), 128)), e.labels === "none" ? u("", !0) : (_(!0), d(s, { key: 0 }, y(P.value, (e, t) => (_(), d("text", {
129
- key: `lab-${t}`,
130
- class: "nb-chart__slice-label",
131
- x: e.labelX,
132
- y: e.labelY,
133
- "text-anchor": "middle",
134
- "dominant-baseline": "middle",
135
- style: g({ fill: e.labelColor })
136
- }, b(e.labelText), 13, E))), 128))], 8, w)], 40, C)), p(n, {
137
- visible: e.showTooltip && I.value !== null,
138
- x: L.value.x,
139
- y: L.value.y,
140
- rows: z.value
141
- }, null, 8, [
142
- "visible",
143
- "x",
144
- "y",
145
- "rows"
146
- ])], 512)]),
147
- _: 1
148
- }, 8, [
149
- "title",
150
- "subtitle",
151
- "height",
152
- "show-legend"
153
- ]));
154
- }
155
- }), [["__scopeId", "data-v-26bfcb67"]]);
156
- //#endregion
157
- export { D as t };