@nubisco/ui 4.1.1 → 4.1.2

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.
@@ -0,0 +1,192 @@
1
+ import MagicString from 'magic-string'
2
+ import { parse, babelParse } from 'vue/compiler-sfc'
3
+
4
+ /**
5
+ * Makes a hand-written component import behave like an auto-imported one.
6
+ *
7
+ * The library ships one stylesheet per chunk, and the auto-import resolver
8
+ * declares each component's sheets as side effects so the bundler links them
9
+ * next to the component. That only happens for tags the resolver saw. An app
10
+ * that writes its imports by hand:
11
+ *
12
+ * ```ts
13
+ * import { NbButton, NbPanel } from '@nubisco/ui'
14
+ * ```
15
+ *
16
+ * never went through the resolver, so it got no stylesheets at all. With
17
+ * `styles: true` (the default) and the `@nubisco/ui/css` import dropped, as
18
+ * the upgrade guide said to, that shipped an app with no component CSS: every
19
+ * page rendered unstyled, and nothing failed. The CSS bundle still looked
20
+ * plausible, because the app's own styles and the design tokens were still in
21
+ * it.
22
+ *
23
+ * So this plugin gives the same treatment to imports the app wrote itself:
24
+ *
25
+ * 1. A named component imported from the barrel is rewritten to its own entry
26
+ * point, which is what the resolver would have emitted, and which also
27
+ * stops the barrel from pulling in every other component.
28
+ * 2. Either way, that component's stylesheets are imported alongside it.
29
+ *
30
+ * Names the manifest does not know (composables, types, `registerIcons`) stay
31
+ * on the barrel import untouched, and a namespace or default import is left
32
+ * alone entirely, since there is no way to tell from it which components the
33
+ * file actually uses.
34
+ */
35
+
36
+ interface INubiscoImportOptions {
37
+ /** `Nb*` name to entry file, from the component manifest. */
38
+ manifest: Map<string, string>
39
+ /** Which stylesheets each component entry needs. */
40
+ styleManifest: Record<string, string[]>
41
+ /** Inject stylesheets. When false this plugin only rewrites imports. */
42
+ styles: boolean
43
+ packageName: string
44
+ /** Called with the number of components resolved in a file. */
45
+ onResolve: (count: number) => void
46
+ }
47
+
48
+ interface IScriptBlock {
49
+ content: string
50
+ offset: number
51
+ }
52
+
53
+ /** The script of a `.vue` file, or the whole module for a plain script. */
54
+ function scriptBlocks(code: string, file: string): IScriptBlock[] {
55
+ if (!file.endsWith('.vue')) return [{ content: code, offset: 0 }]
56
+ const { descriptor, errors } = parse(code, { filename: file })
57
+ if (errors.length) return []
58
+ return [descriptor.script, descriptor.scriptSetup]
59
+ .filter((block): block is NonNullable<typeof block> => Boolean(block))
60
+ .map((block) => ({
61
+ content: block.content,
62
+ offset: block.loc.start.offset,
63
+ }))
64
+ }
65
+
66
+ interface ISpecifier {
67
+ imported: string
68
+ local: string
69
+ }
70
+
71
+ export function nubiscoImports(options: INubiscoImportOptions) {
72
+ const { manifest, styleManifest, styles, packageName, onResolve } = options
73
+ const componentPrefix = `${packageName}/components/`
74
+
75
+ return {
76
+ name: 'nubisco-ui:imports',
77
+ enforce: 'pre' as const,
78
+
79
+ transform(code: string, id: string) {
80
+ const file = id.split('?')[0]
81
+ if (file.includes('/node_modules/')) return
82
+ if (!/\.(vue|[cm]?[jt]sx?)$/.test(file)) return
83
+ if (!code.includes(packageName)) return
84
+
85
+ const magic = new MagicString(code)
86
+ const sheetsSeen = new Set<string>()
87
+ let resolved = 0
88
+ let changed = false
89
+
90
+ // Stylesheets are appended after the import they belong to, so they
91
+ // land in the consumer's module graph in the order the resolver would
92
+ // have produced.
93
+ const sheetsFor = (entry: string) => {
94
+ if (!styles) return ''
95
+ const sheets = (styleManifest[entry] ?? []).filter(
96
+ (sheet) => !sheetsSeen.has(sheet),
97
+ )
98
+ sheets.forEach((sheet) => sheetsSeen.add(sheet))
99
+ return sheets
100
+ .map((sheet) => `\nimport '${packageName}/dist/${sheet}'`)
101
+ .join('')
102
+ }
103
+
104
+ for (const block of scriptBlocks(code, file)) {
105
+ let program
106
+ try {
107
+ program = babelParse(block.content, {
108
+ sourceType: 'module',
109
+ plugins: ['typescript', 'jsx'],
110
+ }).program
111
+ } catch {
112
+ // Not parseable on its own: the Vue plugin will report it.
113
+ continue
114
+ }
115
+
116
+ for (const node of program.body as any[]) {
117
+ if (node.type !== 'ImportDeclaration') continue
118
+ // `import type { … }` links nothing at runtime, so it needs no
119
+ // stylesheet and must not be rewritten into a value import.
120
+ if (node.importKind === 'type') continue
121
+ const source: string = node.source.value
122
+ const start = block.offset + node.start
123
+ const end = block.offset + node.end
124
+
125
+ /* An entry point the app already named: it only needs its styles. */
126
+ if (source.startsWith(componentPrefix)) {
127
+ const entry = source.slice(componentPrefix.length)
128
+ const sheets = sheetsFor(entry)
129
+ resolved += 1
130
+ if (sheets) {
131
+ magic.appendRight(end, sheets)
132
+ changed = true
133
+ }
134
+ continue
135
+ }
136
+
137
+ if (source !== packageName) continue
138
+
139
+ const components: ISpecifier[] = []
140
+ const rest: string[] = []
141
+ let splittable = true
142
+
143
+ for (const specifier of node.specifiers as any[]) {
144
+ if (specifier.type !== 'ImportSpecifier') {
145
+ // A default or namespace import says nothing about which
146
+ // components the file uses, so it stays as it is.
147
+ splittable = false
148
+ break
149
+ }
150
+ const imported: string =
151
+ specifier.imported.name ?? specifier.imported.value
152
+ const local: string = specifier.local.name
153
+ if (specifier.importKind === 'type' || !manifest.has(imported)) {
154
+ rest.push(
155
+ block.content.slice(specifier.start, specifier.end).trim(),
156
+ )
157
+ continue
158
+ }
159
+ components.push({ imported, local })
160
+ }
161
+
162
+ if (!splittable || !components.length) continue
163
+
164
+ const lines = components.map(({ imported, local }) => {
165
+ const entry = manifest.get(imported) as string
166
+ const binding =
167
+ imported === local ? imported : `${imported} as ${local}`
168
+ return (
169
+ `import { ${binding} } from '${componentPrefix}${entry}'` +
170
+ sheetsFor(entry)
171
+ )
172
+ })
173
+ if (rest.length) {
174
+ lines.push(`import { ${rest.join(', ')} } from '${source}'`)
175
+ }
176
+
177
+ resolved += components.length
178
+ magic.overwrite(start, end, lines.join('\n'))
179
+ changed = true
180
+ }
181
+ }
182
+
183
+ onResolve(resolved)
184
+ if (!changed) return
185
+
186
+ return {
187
+ code: magic.toString(),
188
+ map: magic.generateMap({ hires: true, source: file }),
189
+ }
190
+ },
191
+ }
192
+ }
@@ -5,6 +5,7 @@ import type { Plugin } from 'vite'
5
5
  import Components from 'unplugin-vue-components/vite'
6
6
  import { COMPONENT_MANIFEST } from '../../components/manifest.js'
7
7
  import { nubiscoGlyphs, type IGlyphOptions } from './glyphs.js'
8
+ import { nubiscoImports } from './imports.js'
8
9
 
9
10
  /**
10
11
  * Compile-time resolution for `@nubisco/ui`.
@@ -35,6 +36,10 @@ import { nubiscoGlyphs, type IGlyphOptions } from './glyphs.js'
35
36
  * what it renders and nothing else. Consumers who do not run this plugin
36
37
  * import `@nubisco/ui/css`, the whole sheet, as before.
37
38
  *
39
+ * A third plugin gives hand-written imports the same treatment, because an app
40
+ * that writes `import { NbButton } from '@nubisco/ui'` never reaches the
41
+ * resolver and so used to get no stylesheets at all.
42
+ *
38
43
  * Nothing is deferred to runtime, so SSR, prerendering and hydration behave
39
44
  * exactly as they would with hand-written imports.
40
45
  */
@@ -90,6 +95,7 @@ export function nubiscoUI(options: INubiscoUIOptions = {}): Plugin[] {
90
95
  const { components = true, glyphs = true, styles = true } = options
91
96
  const componentOptions = typeof components === 'object' ? components : {}
92
97
  const plugins: Plugin[] = []
98
+ let resolvedComponents = 0
93
99
 
94
100
  if (glyphs !== false) {
95
101
  plugins.push(nubiscoGlyphs(typeof glyphs === 'object' ? glyphs : {}))
@@ -101,6 +107,18 @@ export function nubiscoUI(options: INubiscoUIOptions = {}): Plugin[] {
101
107
  ? loadStyleManifest(options.distRoot ?? defaultDistRoot())
102
108
  : {}
103
109
 
110
+ plugins.push(
111
+ nubiscoImports({
112
+ manifest: lookup,
113
+ styleManifest,
114
+ styles,
115
+ packageName: '@nubisco/ui',
116
+ onResolve: (count) => {
117
+ resolvedComponents += count
118
+ },
119
+ }) as Plugin,
120
+ )
121
+
104
122
  plugins.push(
105
123
  Components({
106
124
  dirs: componentOptions.dirs ?? [],
@@ -109,6 +127,7 @@ export function nubiscoUI(options: INubiscoUIOptions = {}): Plugin[] {
109
127
  (name: string) => {
110
128
  const file = lookup.get(name)
111
129
  if (!file) return
130
+ resolvedComponents += 1
112
131
  const sheets = styleManifest[file] ?? []
113
132
  return {
114
133
  name,
@@ -119,6 +138,31 @@ export function nubiscoUI(options: INubiscoUIOptions = {}): Plugin[] {
119
138
  ],
120
139
  }),
121
140
  )
141
+
142
+ // A build that linked no component at all cannot have linked any component
143
+ // CSS either, and `styles: true` says the app is relying on this plugin
144
+ // for it. That combination ships an unstyled app and fails nothing, so it
145
+ // is worth a line. It is reachable when every usage goes through a
146
+ // namespace import (`import * as UI from '@nubisco/ui'`), or a dynamic
147
+ // one, neither of which names the components it uses.
148
+ if (styles) {
149
+ plugins.push({
150
+ name: 'nubisco-ui:styles-check',
151
+ apply: 'build',
152
+ closeBundle() {
153
+ if (resolvedComponents) return
154
+ console.warn(
155
+ `[nubisco-ui] no components were linked in this build, so none of ` +
156
+ `the component stylesheets were either. If this app renders ` +
157
+ `Nubisco components, it will render unstyled. Import them by ` +
158
+ `name (\`import { NbButton } from '@nubisco/ui'\`) or use the ` +
159
+ `tags directly so they can be resolved; or pass ` +
160
+ `\`nubiscoUI({ styles: false })\` and import ` +
161
+ `'@nubisco/ui/css' yourself.`,
162
+ )
163
+ },
164
+ })
165
+ }
122
166
  }
123
167
 
124
168
  return plugins
@@ -1 +0,0 @@
1
- require(`./chunk-D-qHiVGv.cjs`);const e=require(`./_plugin-vue_export-helper-tagjRzOz.cjs`),t=require(`./Icon-C8R_r_In.cjs`),n=require(`./composables/useStableId.composable.cjs`),r=require(`./composables/useSurfaceLayer.composable.cjs`),i=require(`./utils/anchorPosition.helper.cjs`);let a=require(`vue`);var o=[`data-term`],s=[`aria-label`,`aria-expanded`,`aria-describedby`,`disabled`],c={key:0,class:`nb-info-hint--title`},l={class:`nb-info-hint--body`},u=(0,a.defineComponent)({__name:`InfoHint`,props:{text:{default:void 0},title:{default:void 0},term:{default:void 0},placement:{default:`top`},size:{default:14},icon:{default:`info`},label:{default:void 0},openDelay:{default:120},closeDelay:{default:140},teleportTo:{default:`body`},disabled:{type:Boolean,default:!1}},emits:[`open`,`close`,`activate`],setup(e,{expose:u,emit:d}){let f=e,p=d,m=`${n.useStableId({})}-popover`,{layerProps:h}=r.useSurfaceLayer({overlay:!0}),g=(0,a.ref)(null),_=(0,a.ref)(null),v=(0,a.ref)(!1),y=(0,a.ref)(!1),b=(0,a.ref)(f.placement),x=(0,a.ref)({top:0,left:0,arrowOffset:50}),S,C,w=(0,a.computed)(()=>({top:`${x.value.top}px`,left:`${x.value.left}px`,"--nb-info-hint-arrow-offset":`${x.value.arrowOffset}%`}));function T(){clearTimeout(S),clearTimeout(C),S=void 0,C=void 0}function E(){let e=g.value,t=_.value;if(!e||!t)return;let n=e.getBoundingClientRect(),r=t.getBoundingClientRect(),a=i.placeAnchored(n,{width:r.width,height:r.height},{side:f.placement,viewport:i.viewportSize()});b.value=a.side,x.value={top:a.top,left:a.left,arrowOffset:a.arrowOffset}}function D(){f.disabled||v.value||(T(),v.value=!0,p(`open`),(0,a.nextTick)(()=>{E(),requestAnimationFrame(E)}))}function O(){v.value&&(T(),v.value=!1,y.value=!1,p(`close`))}function k(){f.disabled||(clearTimeout(C),C=void 0,!v.value&&(S=setTimeout(D,f.openDelay)))}function A(){clearTimeout(S),S=void 0,!y.value&&(C=setTimeout(O,f.closeDelay))}function j(){if(!f.disabled){if(y.value){O();return}y.value=!0,D(),p(`activate`,f.term)}}function M(e){if(e.key===`Escape`){v.value&&(e.preventDefault(),O());return}}function N(){f.disabled||(clearTimeout(C),C=void 0,D())}function P(e){if(y.value)return;let t=e.relatedTarget;t&&_.value?.contains(t)||O()}function F(e){let t=e.target;t&&(g.value?.contains(t)||_.value?.contains(t)||O())}function I(e){e.key===`Escape`&&O()}return(0,a.watch)(v,e=>{typeof document>`u`||(e?(document.addEventListener(`pointerdown`,F,!0),document.addEventListener(`keydown`,I),window.addEventListener(`resize`,E),window.addEventListener(`scroll`,E,!0)):(document.removeEventListener(`pointerdown`,F,!0),document.removeEventListener(`keydown`,I),window.removeEventListener(`resize`,E),window.removeEventListener(`scroll`,E,!0)))}),(0,a.watch)(()=>f.disabled,e=>{e&&O()}),(0,a.onBeforeUnmount)(()=>{T(),!(typeof document>`u`)&&(document.removeEventListener(`pointerdown`,F,!0),document.removeEventListener(`keydown`,I),window.removeEventListener(`resize`,E),window.removeEventListener(`scroll`,E,!0))}),u({open:D,close:O,isOpen:v}),(n,r)=>((0,a.openBlock)(),(0,a.createElementBlock)(`span`,{class:`nb-info-hint`,"data-term":e.term||void 0},[(0,a.createElementVNode)(`button`,{ref_key:`triggerRef`,ref:g,type:`button`,class:(0,a.normalizeClass)([`nb-info-hint--trigger`,{"nb-info-hint--trigger-open":v.value}]),"aria-label":e.label??`More information`,"aria-expanded":v.value,"aria-describedby":v.value?m:void 0,disabled:e.disabled,onClick:(0,a.withModifiers)(j,[`stop`]),onMousedown:r[0]||=(0,a.withModifiers)(()=>{},[`stop`]),onPointerdown:r[1]||=(0,a.withModifiers)(()=>{},[`stop`]),onKeydown:(0,a.withModifiers)(M,[`stop`]),onMouseenter:k,onMouseleave:A,onFocus:N,onBlur:P},[(0,a.createVNode)(t.t,{name:e.icon,size:e.size,weight:`regular`},null,8,[`name`,`size`])],42,s),((0,a.openBlock)(),(0,a.createBlock)(a.Teleport,{to:e.teleportTo},[v.value?((0,a.openBlock)(),(0,a.createElementBlock)(`div`,(0,a.mergeProps)({key:0,id:m,ref_key:`popoverRef`,ref:_,class:[`nb-info-hint--popover`,`nb-info-hint--popover-${b.value}`]},(0,a.unref)(h),{role:`tooltip`,style:w.value,onClick:r[2]||=(0,a.withModifiers)(()=>{},[`stop`]),onMousedown:r[3]||=(0,a.withModifiers)(()=>{},[`stop`]),onPointerdown:r[4]||=(0,a.withModifiers)(()=>{},[`stop`]),onMouseenter:k,onMouseleave:A}),[e.title?((0,a.openBlock)(),(0,a.createElementBlock)(`p`,c,(0,a.toDisplayString)(e.title),1)):(0,a.createCommentVNode)(``,!0),(0,a.createElementVNode)(`div`,l,[(0,a.renderSlot)(n.$slots,`default`,{},()=>[(0,a.createTextVNode)((0,a.toDisplayString)(e.text),1)],!0)])],16)):(0,a.createCommentVNode)(``,!0)],8,[`to`]))],8,o))}}),d=e.t(u,[[`__scopeId`,`data-v-f6f2eaf3`]]);Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return d}});
@@ -1,164 +0,0 @@
1
- import { t as e } from "./_plugin-vue_export-helper-O4QQSku4.js";
2
- import { t } from "./Icon-rREAqsu0.js";
3
- import { useStableId as n } from "./composables/useStableId.composable.mjs";
4
- import { useSurfaceLayer as r } from "./composables/useSurfaceLayer.composable.mjs";
5
- import { placeAnchored as i, viewportSize as a } from "./utils/anchorPosition.helper.mjs";
6
- import { Teleport as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createTextVNode as f, createVNode as p, defineComponent as m, mergeProps as h, nextTick as g, normalizeClass as _, onBeforeUnmount as v, openBlock as y, ref as b, renderSlot as x, toDisplayString as S, unref as ee, watch as C, withModifiers as w } from "vue";
7
- //#region src/components/InfoHint.vue?vue&type=script&setup=true&lang.ts
8
- var T = ["data-term"], E = [
9
- "aria-label",
10
- "aria-expanded",
11
- "aria-describedby",
12
- "disabled"
13
- ], D = {
14
- key: 0,
15
- class: "nb-info-hint--title"
16
- }, O = { class: "nb-info-hint--body" }, k = /* @__PURE__ */ e(/* @__PURE__ */ m({
17
- __name: "InfoHint",
18
- props: {
19
- text: { default: void 0 },
20
- title: { default: void 0 },
21
- term: { default: void 0 },
22
- placement: { default: "top" },
23
- size: { default: 14 },
24
- icon: { default: "info" },
25
- label: { default: void 0 },
26
- openDelay: { default: 120 },
27
- closeDelay: { default: 140 },
28
- teleportTo: { default: "body" },
29
- disabled: {
30
- type: Boolean,
31
- default: !1
32
- }
33
- },
34
- emits: [
35
- "open",
36
- "close",
37
- "activate"
38
- ],
39
- setup(e, { expose: m, emit: k }) {
40
- let A = e, j = k, M = `${n({})}-popover`, { layerProps: N } = r({ overlay: !0 }), P = b(null), F = b(null), I = b(!1), L = b(!1), R = b(A.placement), z = b({
41
- top: 0,
42
- left: 0,
43
- arrowOffset: 50
44
- }), B, V, H = s(() => ({
45
- top: `${z.value.top}px`,
46
- left: `${z.value.left}px`,
47
- "--nb-info-hint-arrow-offset": `${z.value.arrowOffset}%`
48
- }));
49
- function U() {
50
- clearTimeout(B), clearTimeout(V), B = void 0, V = void 0;
51
- }
52
- function W() {
53
- let e = P.value, t = F.value;
54
- if (!e || !t) return;
55
- let n = e.getBoundingClientRect(), r = t.getBoundingClientRect(), o = i(n, {
56
- width: r.width,
57
- height: r.height
58
- }, {
59
- side: A.placement,
60
- viewport: a()
61
- });
62
- R.value = o.side, z.value = {
63
- top: o.top,
64
- left: o.left,
65
- arrowOffset: o.arrowOffset
66
- };
67
- }
68
- function G() {
69
- A.disabled || I.value || (U(), I.value = !0, j("open"), g(() => {
70
- W(), requestAnimationFrame(W);
71
- }));
72
- }
73
- function K() {
74
- I.value && (U(), I.value = !1, L.value = !1, j("close"));
75
- }
76
- function q() {
77
- A.disabled || (clearTimeout(V), V = void 0, !I.value && (B = setTimeout(G, A.openDelay)));
78
- }
79
- function J() {
80
- clearTimeout(B), B = void 0, !L.value && (V = setTimeout(K, A.closeDelay));
81
- }
82
- function Y() {
83
- if (!A.disabled) {
84
- if (L.value) {
85
- K();
86
- return;
87
- }
88
- L.value = !0, G(), j("activate", A.term);
89
- }
90
- }
91
- function X(e) {
92
- if (e.key === "Escape") {
93
- I.value && (e.preventDefault(), K());
94
- return;
95
- }
96
- }
97
- function Z() {
98
- A.disabled || (clearTimeout(V), V = void 0, G());
99
- }
100
- function te(e) {
101
- if (L.value) return;
102
- let t = e.relatedTarget;
103
- t && F.value?.contains(t) || K();
104
- }
105
- function Q(e) {
106
- let t = e.target;
107
- t && (P.value?.contains(t) || F.value?.contains(t) || K());
108
- }
109
- function $(e) {
110
- e.key === "Escape" && K();
111
- }
112
- return C(I, (e) => {
113
- typeof document > "u" || (e ? (document.addEventListener("pointerdown", Q, !0), document.addEventListener("keydown", $), window.addEventListener("resize", W), window.addEventListener("scroll", W, !0)) : (document.removeEventListener("pointerdown", Q, !0), document.removeEventListener("keydown", $), window.removeEventListener("resize", W), window.removeEventListener("scroll", W, !0)));
114
- }), C(() => A.disabled, (e) => {
115
- e && K();
116
- }), v(() => {
117
- U(), !(typeof document > "u") && (document.removeEventListener("pointerdown", Q, !0), document.removeEventListener("keydown", $), window.removeEventListener("resize", W), window.removeEventListener("scroll", W, !0));
118
- }), m({
119
- open: G,
120
- close: K,
121
- isOpen: I
122
- }), (n, r) => (y(), u("span", {
123
- class: "nb-info-hint",
124
- "data-term": e.term || void 0
125
- }, [d("button", {
126
- ref_key: "triggerRef",
127
- ref: P,
128
- type: "button",
129
- class: _(["nb-info-hint--trigger", { "nb-info-hint--trigger-open": I.value }]),
130
- "aria-label": e.label ?? "More information",
131
- "aria-expanded": I.value,
132
- "aria-describedby": I.value ? M : void 0,
133
- disabled: e.disabled,
134
- onClick: w(Y, ["stop"]),
135
- onMousedown: r[0] ||= w(() => {}, ["stop"]),
136
- onPointerdown: r[1] ||= w(() => {}, ["stop"]),
137
- onKeydown: w(X, ["stop"]),
138
- onMouseenter: q,
139
- onMouseleave: J,
140
- onFocus: Z,
141
- onBlur: te
142
- }, [p(t, {
143
- name: e.icon,
144
- size: e.size,
145
- weight: "regular"
146
- }, null, 8, ["name", "size"])], 42, E), (y(), c(o, { to: e.teleportTo }, [I.value ? (y(), u("div", h({
147
- key: 0,
148
- id: M,
149
- ref_key: "popoverRef",
150
- ref: F,
151
- class: ["nb-info-hint--popover", `nb-info-hint--popover-${R.value}`]
152
- }, ee(N), {
153
- role: "tooltip",
154
- style: H.value,
155
- onClick: r[2] ||= w(() => {}, ["stop"]),
156
- onMousedown: r[3] ||= w(() => {}, ["stop"]),
157
- onPointerdown: r[4] ||= w(() => {}, ["stop"]),
158
- onMouseenter: q,
159
- onMouseleave: J
160
- }), [e.title ? (y(), u("p", D, S(e.title), 1)) : l("", !0), d("div", O, [x(n.$slots, "default", {}, () => [f(S(e.text), 1)], !0)])], 16)) : l("", !0)], 8, ["to"]))], 8, T));
161
- }
162
- }), [["__scopeId", "data-v-f6f2eaf3"]]);
163
- //#endregion
164
- export { k as t };
@@ -1 +0,0 @@
1
- require(`./chunk-D-qHiVGv.cjs`);const e=require(`./Icon-C8R_r_In.cjs`),t=require(`./EmptyState-henL7JH6.cjs`),n=require(`./Button-Dqtcr4i0.cjs`),r=require(`./Spinner-CqSN2vaR.cjs`),i=require(`./Skeleton-D8CHd_4p.cjs`),a=require(`./NotificationCenterItem-Clhhma6H.cjs`);let o=require(`vue`),s=require(`@nubisco/ui/icons/warning-circle`);var c={key:0,class:`nb-notification-center__badge`,"aria-hidden":`true`},l=[`aria-describedby`,`aria-busy`],u={class:`nb-notification-center__header`},d={class:`nb-notification-center__sr`,role:`status`},f={class:`nb-notification-center__stale-text`},ee={class:`nb-notification-center__sr`},te=[`tabindex`],ne={key:4,class:`nb-notification-center__empty`},re={key:5,class:`nb-notification-center__footer`},p=new Set,m=8,h=8,g=96,_=88,v=200;function ie(e,{align:t,width:n,maxHeight:r,viewport:i}){let a=t===`start`?e.left:e.left+e.width-n,o=Math.min(Math.max(a,h),Math.max(h,i.width-n-h)),s=e.top+e.height,c=i.height-s-m-h,l=e.top-m-h,u=c<v&&l>c?`top`:`bottom`,d=Math.max(_,u===`top`?l:c),f=Math.max(_,Math.min(r,d-g)),ee=Math.min(r+g,d);return{top:u===`top`?Math.max(h,e.top-m-ee):s+m,left:o,side:u,maxListHeight:f}}function ae(e,t){return e.left<=t.width&&e.left+e.width>=0&&e.top<=t.height&&e.top+e.height>=0}var y=(0,o.defineComponent)({__name:`NotificationCenter`,props:{items:{default:()=>[]},unreadCount:{default:void 0},itemCount:{default:void 0},open:{type:Boolean,default:void 0},label:{default:`Notifications`},markAllLabel:{default:`Mark all as read`},markAllPendingLabel:{default:`Marking all as read`},markAllPending:{type:Boolean,default:!1},emptyTitle:{default:`No notifications`},emptyDescription:{default:`New activity shows up here.`},loadingLabel:{default:`Loading notifications`},loading:{type:Boolean,default:!1},error:{type:Boolean,default:!1},errorTitle:{default:`Could not load notifications`},errorDescription:{default:`The request failed. Nothing has been lost.`},errorStaleLabel:{default:`These may be out of date.`},retryLabel:{default:`Try again`},showRetry:{type:Boolean,default:!0},maxCount:{default:99},width:{default:360},maxHeight:{default:384},align:{default:`end`},showMarkAll:{type:Boolean,default:!0},interactive:{type:Boolean,default:!0},closeOnSelect:{type:Boolean,default:!0},closeOnNavigate:{type:Boolean,default:!0},disabled:{type:Boolean,default:!1},icon:{default:`bell`},locale:{default:void 0},unreadLabel:{default:`Unread`},readLabel:{default:`Read`},formatUnread:{type:Function,default:e=>e===1?`1 unread`:`${e} unread`}},emits:[`update:open`,`open`,`close`,`select`,`mark-all-read`,`retry`],setup(m,{expose:h,emit:g}){let _=m,v=g,y=(0,o.useSlots)(),b=`nb-notification-center-${(0,o.useId)()}`,oe=`${b}-title`,se=`${b}-trigger`,x=`${b}-error`,S=(0,o.ref)(null),C=(0,o.ref)(null),w=(0,o.ref)(null),T=(0,o.ref)(null),E=(0,o.ref)(!1),D=(0,o.computed)(()=>_.open===void 0?E.value:_.open),O=(0,o.computed)(()=>typeof _.unreadCount==`number`?Math.max(0,_.unreadCount):_.items.filter(e=>!e.read).length),ce=(0,o.computed)(()=>O.value>_.maxCount?`${_.maxCount}+`:String(O.value)),le=(0,o.computed)(()=>O.value>0?`${_.label}, ${_.formatUnread(O.value)}`:_.label),ue=(0,o.computed)(()=>{if(typeof _.itemCount==`number`)return Math.max(0,_.itemCount);if(!y.default)return _.items.length}),de=(0,o.computed)(()=>(ue.value??0)>0),k=(0,o.computed)(()=>{if(_.loading)return`loading`;let e=ue.value;return _.error&&(e===void 0||e===0)?`error`:e===void 0||e>0?`list`:`empty`}),fe=(0,o.computed)(()=>_.error&&!_.loading&&k.value===`list`&&de.value);(0,o.ref)(!1),(0,o.watch)(()=>[D.value,!!y.default,_.itemCount],([e,t,n])=>{},{immediate:!0});function A(){v(`retry`)}let j=(0,o.computed)(()=>({id:se,"aria-haspopup":`dialog`,"aria-expanded":D.value?`true`:`false`,"aria-controls":D.value?b:void 0,"aria-label":le.value,disabled:_.disabled||void 0})),M=(0,o.computed)(()=>({type:`button`,disabled:O.value===0&&!_.markAllPending,"aria-disabled":_.markAllPending?`true`:void 0,"aria-busy":_.markAllPending?`true`:void 0,onClick:De})),pe=(0,o.computed)(()=>fe.value||k.value===`error`?x:void 0);function N(e){if(!e){w.value=null;return}let t=e instanceof HTMLElement?e:e.$el;w.value=t instanceof HTMLElement?t:null}let P=(0,o.ref)({top:0,left:0,side:`bottom`,maxListHeight:_.maxHeight});function F(){return{width:window.innerWidth,height:window.innerHeight}}function I(){let e=S.value?.getBoundingClientRect();e&&(P.value=ie(e,{align:_.align,width:_.width,maxHeight:_.maxHeight,viewport:F()}))}let me=(0,o.computed)(()=>({top:`${Math.round(P.value.top)}px`,left:`${Math.round(P.value.left)}px`,width:`${_.width}px`})),L=(0,o.computed)(()=>({maxHeight:`${Math.round(P.value.maxListHeight)}px`})),he=(0,o.computed)(()=>({"nb-notification-center__panel--start":_.align===`start`,"nb-notification-center__panel--above":P.value.side===`top`}));function R(e){_.open===void 0&&(E.value=e),v(`update:open`,e)}function z(){_.disabled||D.value||(I(),R(!0),v(`open`))}function B(e={}){if(!D.value)return;let t=T.value?.contains(document.activeElement);R(!1),v(`close`),(e.restoreFocus??t)&&(0,o.nextTick)(V)}function V(){let e=w.value;if(e?.isConnected){e.focus();return}(S.value?.querySelector(J))?.focus()}function H(){D.value?B({restoreFocus:!0}):z()}let U=(0,o.ref)(0),ge=new Set([`button`,`link`,`menuitem`,`option`]);function W(e){if(e.tagName===`BUTTON`)return!e.hasAttribute(`disabled`);if(e.tagName===`A`)return e.hasAttribute(`href`);let t=e.getAttribute(`role`);return t!==null&&ge.has(t)}function G(){return T.value?Array.from(T.value.querySelectorAll(`[data-nb-notification-item]`)).filter(e=>!!W(e)):[]}let _e=(0,o.ref)(void 0);function ve(e){let t=C.value;_e.value=t&&t.childElementCount>0&&e.length===0?0:void 0}function K(e){let t=G();ve(t),t.length&&(U.value=Math.min(Math.max(e,0),t.length-1),t.forEach((e,t)=>{e.setAttribute(`tabindex`,t===U.value?`0`:`-1`)}))}function q(e){let t=G();if(!t.length)return!1;let n=Math.min(Math.max(e,0),t.length-1);return K(n),t[n]?.focus(),!0}function ye(e){let t=e.target?.closest(`[data-nb-notification-item]`);if(!t)return;let n=G().indexOf(t);n>=0&&K(n)}let J=`a[href]:not([tabindex="-1"]), button:not([disabled]):not([tabindex="-1"]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex="0"]`;function be(e){return!!e?.closest?.(`input, textarea, select, [contenteditable=""], [contenteditable="true"]`)}function xe(e){let t=G(),n=e.target?.closest(`[data-nb-notification-item]`),r=n?t.indexOf(n):-1;if(e.key===`Escape`){if(!Se(e))return;e.preventDefault(),e.stopPropagation(),B({restoreFocus:!0});return}if(e.key===`Tab`){Ce(e);return}if(!be(e.target))switch(e.key){case`ArrowDown`:q(r<0?0:r+1)&&e.preventDefault();break;case`ArrowUp`:q(r<0?t.length-1:r-1)&&e.preventDefault();break;case`Home`:r>=0&&(e.preventDefault(),q(0));break;case`End`:r>=0&&(e.preventDefault(),q(t.length-1));break;default:break}}function Se(e){if(e.defaultPrevented)return!1;let t=(e.target??document.activeElement)?.closest?.(`[aria-modal="true"]`);return!(t&&t!==T.value)}function Ce(e){let t=T.value;if(!t)return;let n=Array.from(t.querySelectorAll(J)),r=document.activeElement,i=n[0],a=n[n.length-1],s=!n.length||r===i||!t.contains(r),c=!n.length||r===a;if(e.shiftKey?!s:!c)return;e.preventDefault();let l=e.shiftKey?w.value:we();B({restoreFocus:!1}),(0,o.nextTick)(()=>{l?.isConnected?l.focus():V()})}function we(){let e=w.value;if(!e)return null;let t=Array.from(document.querySelectorAll(J)).filter(e=>!T.value?.contains(e)).filter(e=>e.tabIndex>=0),n=t.indexOf(e);return n<0?null:t[n+1]??null}function Te(e,t){v(`select`,e,t),_.closeOnSelect&&B({restoreFocus:!1})}function Ee(e){if(!y.default)return;let t=e.target?.closest(`[data-nb-notification-item]`);if(t&&W(t)){if(e.type===`keydown`){let n=e.key;if(n!==`Enter`&&n!==` `||t.tagName===`BUTTON`||t.tagName===`A`)return;e.preventDefault()}v(`select`,null,e),_.closeOnSelect&&B({restoreFocus:!1})}}function De(){_.markAllPending||v(`mark-all-read`)}function Y(e){let t=e.target;S.value?.contains(t)||T.value?.contains(t)||B({restoreFocus:!1})}function Oe(e){e.key===`Escape`&&(T.value?.contains(document.activeElement)||Se(e)&&B({restoreFocus:S.value?.contains(document.activeElement)??!1}))}let X=0;function Z(){!D.value||X||(X=requestAnimationFrame(()=>{X=0,Ae()}))}function ke(){X&&=(cancelAnimationFrame(X),0)}function Ae(){if(!D.value)return;let e=S.value?.getBoundingClientRect();if(e&&!ae(e,F())){B({restoreFocus:!1});return}I()}function Q(){_.closeOnNavigate&&B({restoreFocus:!1})}function je(){return window.navigation}function Me(){document.addEventListener(`mousedown`,Y),document.addEventListener(`keydown`,Oe),window.addEventListener(`resize`,Z),window.addEventListener(`scroll`,Z,!0),window.addEventListener(`popstate`,Q),window.addEventListener(`hashchange`,Q),je()?.addEventListener(`navigate`,Q)}function Ne(){ke(),document.removeEventListener(`mousedown`,Y),document.removeEventListener(`keydown`,Oe),window.removeEventListener(`resize`,Z),window.removeEventListener(`scroll`,Z,!0),window.removeEventListener(`popstate`,Q),window.removeEventListener(`hashchange`,Q),je()?.removeEventListener(`navigate`,Q)}let $=()=>B({restoreFocus:!1});return(0,o.watch)(D,e=>{if(e){for(let e of[...p])e!==$&&e();p.add($),Me(),(0,o.nextTick)(()=>{I(),K(0),q(0)||T.value?.focus()})}else p.delete($),Ne(),U.value=0}),(0,o.watch)(()=>[_.items.length,k.value],()=>{D.value&&(0,o.nextTick)(()=>K(U.value))}),(0,o.onBeforeUnmount)(()=>{Ne(),p.delete($);let e=T.value;e?.isConnected&&e.remove()}),h({show:z,close:B,toggle:H,isOpen:D,unreadCount:O}),(p,h)=>((0,o.openBlock)(),(0,o.createElementBlock)(`div`,{ref_key:`rootRef`,ref:S,class:`nb-notification-center`},[(0,o.renderSlot)(p.$slots,`trigger`,{open:D.value,toggle:H,show:z,close:B,unreadCount:O.value,badge:ce.value,panelId:b,triggerProps:j.value,setTriggerRef:N},()=>[(0,o.createElementVNode)(`button`,(0,o.mergeProps)({ref:N,type:`button`,class:[`nb-notification-center__trigger`,{"nb-notification-center__trigger--active":D.value}]},j.value,{onClick:H}),[(0,o.createVNode)(e.t,{name:m.icon,size:18},null,8,[`name`]),O.value>0?((0,o.openBlock)(),(0,o.createElementBlock)(`span`,c,(0,o.toDisplayString)(ce.value),1)):(0,o.createCommentVNode)(``,!0)],16)]),((0,o.openBlock)(),(0,o.createBlock)(o.Teleport,{to:`body`},[(0,o.createVNode)(o.Transition,{name:`nb-notification-center-pop`},{default:(0,o.withCtx)(()=>[D.value?((0,o.openBlock)(),(0,o.createElementBlock)(`div`,{key:0,id:b,ref_key:`panelRef`,ref:T,class:(0,o.normalizeClass)([`nb-notification-center__panel`,he.value]),style:(0,o.normalizeStyle)(me.value),role:`dialog`,tabindex:`-1`,"aria-labelledby":oe,"aria-describedby":pe.value,"aria-busy":m.loading?`true`:void 0,onKeydown:xe,onFocusin:ye},[(0,o.createElementVNode)(`div`,u,[(0,o.createElementVNode)(`h2`,{id:oe,class:`nb-notification-center__title`},(0,o.toDisplayString)(m.label),1),(0,o.renderSlot)(p.$slots,`header-start`,{close:B,unreadCount:O.value}),(0,o.renderSlot)(p.$slots,`header-actions`,{close:B,unreadCount:O.value,markAllRead:De,markAllPending:m.markAllPending,markAllProps:M.value,markAllText:m.markAllPending?m.markAllPendingLabel:m.markAllLabel},()=>[m.showMarkAll?((0,o.openBlock)(),(0,o.createElementBlock)(`button`,(0,o.mergeProps)({key:0,class:`nb-notification-center__mark-all`},M.value),[m.markAllPending?((0,o.openBlock)(),(0,o.createBlock)(r.t,{key:0,size:`xs`,tone:`inherit`,decorative:``})):(0,o.createCommentVNode)(``,!0),(0,o.createTextVNode)(` `+(0,o.toDisplayString)(m.markAllPending?m.markAllPendingLabel:m.markAllLabel),1)],16)):(0,o.createCommentVNode)(``,!0)])]),(0,o.createElementVNode)(`span`,d,(0,o.toDisplayString)(m.markAllPending?m.markAllPendingLabel:``),1),fe.value?((0,o.openBlock)(),(0,o.createElementBlock)(`div`,{key:0,id:x,class:`nb-notification-center__stale`,role:`status`},[(0,o.createVNode)(e.t,{name:(0,o.unref)(s.regular),size:14,"aria-hidden":`true`},null,8,[`name`]),(0,o.createElementVNode)(`span`,f,(0,o.toDisplayString)(m.errorStaleLabel),1),m.showRetry?((0,o.openBlock)(),(0,o.createElementBlock)(`button`,{key:0,type:`button`,class:`nb-notification-center__retry`,onClick:A},(0,o.toDisplayString)(m.retryLabel),1)):(0,o.createCommentVNode)(``,!0)])):(0,o.createCommentVNode)(``,!0),k.value===`loading`?((0,o.openBlock)(),(0,o.createElementBlock)(`div`,{key:1,class:`nb-notification-center__loading`,role:`status`,style:(0,o.normalizeStyle)(L.value)},[(0,o.createElementVNode)(`span`,ee,(0,o.toDisplayString)(m.loadingLabel),1),((0,o.openBlock)(),(0,o.createElementBlock)(o.Fragment,null,(0,o.renderList)(3,e=>(0,o.createVNode)(i.t,{key:e,variant:`text`,type:`body-sm`,lines:2,"last-line-width":`60%`})),64))],4)):k.value===`error`?((0,o.openBlock)(),(0,o.createElementBlock)(`div`,{key:2,id:x,class:`nb-notification-center__error`,role:`alert`},[(0,o.renderSlot)(p.$slots,`error`,{retry:A},()=>[(0,o.createVNode)(t.t,{size:`sm`,kind:`error`,title:m.errorTitle,description:m.errorDescription},(0,o.createSlots)({_:2},[m.showRetry?{name:`actions`,fn:(0,o.withCtx)(()=>[(0,o.createVNode)(n.t,{size:`sm`,variant:`secondary`,onClick:A},{default:(0,o.withCtx)(()=>[(0,o.createTextVNode)((0,o.toDisplayString)(m.retryLabel),1)]),_:1})]),key:`0`}:void 0]),1032,[`title`,`description`])])])):k.value===`list`?((0,o.openBlock)(),(0,o.createElementBlock)(`ul`,{key:3,ref_key:`listRef`,ref:C,class:`nb-notification-center__list`,role:`list`,tabindex:_e.value,style:(0,o.normalizeStyle)(L.value),onClick:Ee,onKeydown:Ee},[(0,o.renderSlot)(p.$slots,`default`,{close:B,items:m.items},()=>[((0,o.openBlock)(!0),(0,o.createElementBlock)(o.Fragment,null,(0,o.renderList)(m.items,e=>((0,o.openBlock)(),(0,o.createBlock)(a.t,{key:e.id,title:e.title,body:e.body,time:e.time,"time-label":e.timeLabel,read:e.read,variant:e.variant??`neutral`,icon:e.icon,href:e.href,interactive:e.interactive??m.interactive,locale:m.locale,"unread-label":m.unreadLabel,"read-label":m.readLabel,onSelect:t=>Te(e,t)},null,8,[`title`,`body`,`time`,`time-label`,`read`,`variant`,`icon`,`href`,`interactive`,`locale`,`unread-label`,`read-label`,`onSelect`]))),128))])],44,te)):k.value===`empty`?((0,o.openBlock)(),(0,o.createElementBlock)(`div`,ne,[(0,o.renderSlot)(p.$slots,`empty`,{},()=>[(0,o.createVNode)(t.t,{size:`sm`,icon:m.icon,title:m.emptyTitle,description:m.emptyDescription},null,8,[`icon`,`title`,`description`])])])):(0,o.createCommentVNode)(``,!0),p.$slots.footer?((0,o.openBlock)(),(0,o.createElementBlock)(`div`,re,[(0,o.renderSlot)(p.$slots,`footer`,{close:B})])):(0,o.createCommentVNode)(``,!0)],46,l)):(0,o.createCommentVNode)(``,!0)]),_:3})]))],512))}});Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return y}});