@greypan/web-ui 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/components/back-top/index.js +15 -18
  2. package/dist/components/back-top/index.js.map +1 -1
  3. package/dist/components/button/index.js +14 -17
  4. package/dist/components/button/index.js.map +1 -1
  5. package/dist/components/layout/index.js +8 -11
  6. package/dist/components/layout/index.js.map +1 -1
  7. package/dist/components/svg-draw-lines/index.js +13 -16
  8. package/dist/components/svg-draw-lines/index.js.map +1 -1
  9. package/dist/node_modules/.pnpm/@lit_reactive-element@2.1.2/node_modules/@lit/reactive-element/reactive-element.js +25 -25
  10. package/dist/types/react.d.ts +4 -4
  11. package/dist/types/vue.d.ts +4 -4
  12. package/package.json +24 -5
  13. package/.turbo/turbo-build.log +0 -44
  14. package/.turbo/turbo-test.log +0 -14
  15. package/CHANGELOG.md +0 -28
  16. package/dist/node_modules/.pnpm/iconify-icon@3.0.2/node_modules/iconify-icon/dist/iconify-icon.js +0 -1219
  17. package/dist/node_modules/.pnpm/iconify-icon@3.0.2/node_modules/iconify-icon/dist/iconify-icon.js.map +0 -1
  18. package/dist/node_modules/.pnpm/lit-element@4.2.2/node_modules/lit-element/lit-element.js +0 -33
  19. package/dist/node_modules/.pnpm/lit-element@4.2.2/node_modules/lit-element/lit-element.js.map +0 -1
  20. package/dist/node_modules/.pnpm/lit-html@3.3.3/node_modules/lit-html/lit-html.js +0 -233
  21. package/dist/node_modules/.pnpm/lit-html@3.3.3/node_modules/lit-html/lit-html.js.map +0 -1
  22. package/dist/node_modules/.pnpm/lit@3.3.3/node_modules/lit/index.js +0 -5
  23. package/public/vite.svg +0 -1
  24. package/src/assets/common.css +0 -18
  25. package/src/components/back-top/index.ts +0 -124
  26. package/src/components/back-top/style.css +0 -25
  27. package/src/components/button/index.ts +0 -28
  28. package/src/components/button/style.css +0 -52
  29. package/src/components/layout/__tests__/layout.spec.ts +0 -7
  30. package/src/components/layout/index.ts +0 -26
  31. package/src/components/layout/style.css +0 -50
  32. package/src/components/svg-draw-lines/index.ts +0 -127
  33. package/src/components/svg-draw-lines/style.css +0 -21
  34. package/src/index.ts +0 -4
  35. package/src/types/react.ts +0 -30
  36. package/src/types/utils.ts +0 -14
  37. package/src/types/vue.ts +0 -27
  38. package/tsconfig.app.json +0 -14
  39. package/tsconfig.json +0 -8
  40. package/tsconfig.node.json +0 -18
  41. package/tsconfig.vitest.json +0 -10
  42. package/vite.config.ts +0 -40
@@ -1,124 +0,0 @@
1
- import 'iconify-icon'
2
- import '@/components/button'
3
- import { getRootScrollTop } from '@greypan/browser-kit'
4
- import { html, LitElement, type PropertyValues, unsafeCSS } from 'lit'
5
- import { customElement, property, state } from 'lit/decorators.js'
6
-
7
- import style from './style.css?inline'
8
-
9
- @customElement('web-ui-back-top')
10
- export class WebUiBackTop extends LitElement {
11
- static styles = unsafeCSS(style)
12
-
13
- @property({ type: Boolean, reflect: true }) smooth = true
14
- @property({ type: Number, reflect: true }) threshold: number = 200
15
- @property({ type: Boolean, reflect: true }) visible = false
16
- @property({ type: Object, attribute: false }) scrollTarget: HTMLElement | Window = window
17
-
18
- @state() private eventController?: AbortController
19
-
20
- override connectedCallback() {
21
- super.connectedCallback()
22
- this.computeVisible()
23
- this.onScrollTarget()
24
- }
25
-
26
- override disconnectedCallback() {
27
- super.disconnectedCallback()
28
- this.eventController?.abort()
29
- }
30
-
31
- protected override willUpdate(props: PropertyValues) {
32
- super.willUpdate(props)
33
-
34
- if (props.has('threshold') || props.has('scrollTarget')) {
35
- this.computeVisible()
36
- }
37
- //避免首次与 connectedCallback 重复触发
38
- if (props.has('scrollTarget') && this.hasUpdated) {
39
- this.onScrollTarget()
40
- }
41
- }
42
-
43
- private get target() {
44
- if (!this.scrollTarget) {
45
- return window
46
- }
47
- const isRoot =
48
- this.scrollTarget === window ||
49
- this.scrollTarget === document.documentElement ||
50
- this.scrollTarget === document.body
51
- return isRoot ? window : this.scrollTarget
52
- }
53
-
54
- private onScrollTarget() {
55
- this.eventController?.abort()
56
- this.eventController = new AbortController()
57
-
58
- this.target.addEventListener(
59
- 'scroll',
60
- () => {
61
- this.computeVisible()
62
- },
63
- {
64
- signal: this.eventController.signal,
65
- passive: true
66
- }
67
- )
68
- }
69
-
70
- private computeVisible() {
71
- const { target } = this
72
- let nextVisible: boolean
73
- if (target === window) {
74
- nextVisible = getRootScrollTop() >= this.threshold
75
- } else if (target instanceof HTMLElement) {
76
- nextVisible = target.scrollTop >= this.threshold
77
- } else {
78
- throw new Error('Prop scrollTarget must be HTMLElement or Window.')
79
- }
80
- if (nextVisible !== this.visible) {
81
- this.visible = nextVisible
82
- this.dispatchEvent(
83
- new CustomEvent('visible-change', {
84
- detail: { visible: nextVisible },
85
- bubbles: true,
86
- composed: true
87
- })
88
- )
89
- }
90
- }
91
-
92
- toTop() {
93
- this.target.scrollTo({
94
- top: 0,
95
- behavior: this.smooth ? 'smooth' : 'auto'
96
- })
97
- }
98
-
99
- private onEnter(e: KeyboardEvent) {
100
- if ((e as KeyboardEvent).key == 'Enter') {
101
- e.preventDefault()
102
- this.toTop()
103
- }
104
- }
105
-
106
- render() {
107
- return html`
108
- <div role="button" tabindex="0" @click=${this.toTop} @keydown=${this.onEnter}>
109
- <slot>
110
- <!-- 默认 slot 加上 tabindex="-1",防止双重 focus -->
111
- <web-ui-button tabindex="-1" icon>
112
- <iconify-icon icon="octicon:move-to-top-16" width="16" height="16"></iconify-icon>
113
- </web-ui-button>
114
- </slot>
115
- </div>
116
- `
117
- }
118
- }
119
-
120
- export interface WebUiBackTop {
121
- readonly $events: {
122
- 'visible-change': CustomEvent<{ visible: boolean }>
123
- }
124
- }
@@ -1,25 +0,0 @@
1
- :host {
2
- pointer-events: none;
3
-
4
- position: fixed;
5
- z-index: var(--web-ui-back-top-z-index, auto);
6
- top: var(--web-ui-back-top-top, auto);
7
- right: var(--web-ui-back-top-right, 20px);
8
- bottom: var(--web-ui-back-top-bottom, 20px);
9
- left: var(--web-ui-back-top-left, auto);
10
- transform: scale(0);
11
-
12
- display: inline-block;
13
-
14
- visibility: hidden;
15
- opacity: 0;
16
-
17
- transition: all 0.3s ease-out;
18
- }
19
-
20
- :host([visible]) {
21
- pointer-events: auto;
22
- transform: scale(1);
23
- visibility: visible;
24
- opacity: 1;
25
- }
@@ -1,28 +0,0 @@
1
- import { html, LitElement, unsafeCSS } from 'lit'
2
- import { customElement, property } from 'lit/decorators.js'
3
-
4
- import style from './style.css?inline'
5
-
6
- @customElement('web-ui-button')
7
- export class WebUiButton extends LitElement {
8
- static styles = unsafeCSS(style)
9
-
10
- @property({ type: Boolean, reflect: true }) full = false
11
- @property({ type: Boolean, reflect: true }) primary = false
12
- @property({ type: Boolean, reflect: true }) text = false
13
- @property({ type: Boolean, reflect: true }) icon = false
14
-
15
- render() {
16
- return html`
17
- <button>
18
- ${this.icon
19
- ? html`<slot></slot>`
20
- : html`
21
- <slot name="prefix"></slot>
22
- <slot></slot>
23
- <slot name="suffix"></slot>
24
- `}
25
- </button>
26
- `
27
- }
28
- }
@@ -1,52 +0,0 @@
1
- :host {
2
- button {
3
- cursor: pointer;
4
-
5
- display: inline-flex;
6
- gap: var(--web-ui-button-gap, 8px);
7
- align-items: center;
8
- justify-content: center;
9
-
10
- width: max-content;
11
- min-height: var(--web-ui-button-h, 32px);
12
- padding: var(--web-ui-button-p-y, 4px) var(--web-ui-button-p-x, 16px);
13
- border: none;
14
- border-radius: 999vmax;
15
-
16
- font-size: var(--web-ui-button-font-size, 14px);
17
- font-weight: var(--web-ui-button-bold, 500);
18
- color: var(--web-ui-button-color, #006cf9);
19
-
20
- background: none;
21
- background-color: var(--web-ui-button-bg, #f0f0f6);
22
- }
23
- }
24
-
25
- :host([full]) {
26
- button {
27
- display: flex;
28
- width: 100%;
29
- }
30
- }
31
-
32
- :host([primary]) {
33
- button {
34
- color: var(--web-ui-button-primary-color, #fff);
35
- background-color: var(--web-ui-button-primary-bg, #006cf9);
36
- }
37
- }
38
-
39
- :host([text]) {
40
- button {
41
- color: var(--web-ui-button-primary-color, #006cf9);
42
- background-color: transparent;
43
- }
44
- }
45
-
46
- :host([icon]) {
47
- button {
48
- width: var(--web-ui-button-h, 32px);
49
- height: var(--web-ui-button-h, 32px);
50
- padding: var(--web-ui-button-p-y, 4px);
51
- }
52
- }
@@ -1,7 +0,0 @@
1
- import { describe, expect, it } from 'vite-plus/test'
2
-
3
- describe('test', () => {
4
- it('1 + 1 = 2', () => {
5
- expect(1 + 1).toBe(2)
6
- })
7
- })
@@ -1,26 +0,0 @@
1
- import { html, LitElement, unsafeCSS } from 'lit'
2
- import { customElement } from 'lit/decorators.js'
3
-
4
- import style from './style.css?inline'
5
-
6
- @customElement('web-ui-layout')
7
- export class WebUiLayout extends LitElement {
8
- static styles = unsafeCSS(style)
9
-
10
- render() {
11
- return html`
12
- <header>
13
- <slot name="header"></slot>
14
- </header>
15
- <main>
16
- <slot></slot>
17
- </main>
18
- <aside>
19
- <div class="menu"><slot name="sidebar"></slot></div>
20
- </aside>
21
- <footer>
22
- <slot name="tabbar"></slot>
23
- </footer>
24
- `
25
- }
26
- }
@@ -1,50 +0,0 @@
1
- :host {
2
- display: grid;
3
- grid-template-areas:
4
- 'sidebar header'
5
- 'sidebar content';
6
- grid-template-columns: var(--web-ui-base-layout-sidebar-width, 240px) 1fr;
7
- grid-template-rows: var(--web-ui-base-layout-header-height, 64px) 1fr;
8
-
9
- box-sizing: border-box;
10
- min-height: 100dvh;
11
- min-height: 100vh;
12
-
13
- * {
14
- box-sizing: inherit;
15
- }
16
- }
17
-
18
- header {
19
- position: sticky;
20
- top: 0;
21
- right: 0;
22
- grid-area: header;
23
- }
24
-
25
- main {
26
- grid-area: content;
27
- }
28
-
29
- aside {
30
- position: sticky;
31
- top: 0;
32
- left: 0;
33
-
34
- grid-area: sidebar;
35
-
36
- height: 100dvh;
37
- height: 100vh;
38
- padding: 8px;
39
-
40
- .menu {
41
- height: 100%;
42
- border-radius: 16px;
43
- background-color: var(--web-ui-base-layout-bg, #f5f5f5);
44
- box-shadow: 2px 4px 32px rgb(0 0 0 / 0.2);
45
- }
46
- }
47
-
48
- footer {
49
- grid-area: footer;
50
- }
@@ -1,127 +0,0 @@
1
- import { html, LitElement, unsafeCSS } from 'lit'
2
- import { customElement, property, query, state } from 'lit/decorators.js'
3
-
4
- import style from './style.css?inline'
5
-
6
- @customElement('web-ui-svg-draw-lines')
7
- export class WebUiSvgDrawLines extends LitElement {
8
- static styles = unsafeCSS(style)
9
-
10
- @property({ type: Number, reflect: true }) duration = 1000
11
- @property({ type: String, reflect: true }) easing = 'linear'
12
-
13
- @state() private isAnimating = false
14
- @state() private svgClone: SVGSVGElement | null = null
15
- @query('slot') private slotEl!: HTMLSlotElement
16
-
17
- private handleSlotChange() {
18
- if (this.isAnimating) return
19
-
20
- this.cloneOriginalSvg()
21
-
22
- this.isAnimating = true
23
- void this.startAnimation()
24
- }
25
-
26
- private cloneOriginalSvg() {
27
- const original = this.slotEl.assignedElements({ flatten: true })[0]
28
- if (!(original instanceof SVGSVGElement)) return
29
-
30
- const svgClone = original.cloneNode(true) as SVGSVGElement
31
- svgClone.classList.add('svg-clone')
32
- this.svgClone = svgClone
33
- }
34
-
35
- private async startAnimation() {
36
- if (!this.svgClone) return
37
- await this.updateComplete
38
-
39
- const selectors = 'path, rect, circle, line, polyline, polygon, ellipse'
40
- const elements = Array.from(this.svgClone.querySelectorAll(selectors)) as SVGGeometryElement[]
41
-
42
- const animTasks: SVGGeometryElement[] = []
43
- let cursor = { x: 0, y: 0 }
44
-
45
- // 除 path 外其余几何图形无需额外处理
46
- // 将绘制多段路径的单 path 先拆分为多 path 并重新插入 dom
47
- // 再分别计算每个 path 的 total length
48
- elements.forEach(el => {
49
- if (el instanceof SVGPathElement) {
50
- const d = el.getAttribute('d') || ''
51
- const segments = d.split(/(?=[Mm])/).filter(s => s.trim())
52
-
53
- // 无论是一段还是多段,统一处理
54
- segments.forEach(seg => {
55
- const pathPart = segments.length > 1 ? (el.cloneNode() as SVGPathElement) : el
56
- let finalD = seg.startsWith('m') ? `M${cursor.x} ${cursor.y}${seg}` : seg
57
-
58
- finalD = this.fixPathGap(pathPart, finalD)
59
- pathPart.setAttribute('d', finalD)
60
-
61
- if (segments.length > 1) el.parentNode?.insertBefore(pathPart, el)
62
-
63
- animTasks.push(pathPart)
64
-
65
- const end = pathPart.getPointAtLength(pathPart.getTotalLength())
66
- cursor = { x: end.x, y: end.y }
67
- })
68
-
69
- if (segments.length > 1) el.remove()
70
- } else {
71
- animTasks.push(el)
72
- }
73
- })
74
-
75
- if (animTasks.length === 0) return this.stopAnimation()
76
-
77
- const promises = animTasks.map((el, i) => {
78
- return new Promise<void>(resolve => {
79
- this.drawLine(el, i, resolve)
80
- })
81
- })
82
-
83
- await Promise.all(promises)
84
- this.stopAnimation()
85
- }
86
-
87
- // 缺口修复逻辑
88
- // 多走 0.1px 触发渲染闭合和确定起始矢量方向
89
- private fixPathGap(pathEl: SVGPathElement, d: string): string {
90
- if (/[Zz]\s*$/.test(d)) {
91
- pathEl.setAttribute('d', d)
92
- const p0 = pathEl.getPointAtLength(0)
93
- const p1 = pathEl.getPointAtLength(0.1)
94
-
95
- // 将 Z 替换为回到起点并多走 0.1px 的路径
96
- return d.replace(/[Zz]\s*$/, `L${p0.x.toFixed(3)} ${p0.y.toFixed(3)} L${p1.x.toFixed(3)} ${p1.y.toFixed(3)}`)
97
- }
98
- return d
99
- }
100
-
101
- private drawLine(el: SVGGeometryElement, index: number, onFinish: () => void) {
102
- const strokeWidth = parseFloat(getComputedStyle(el).strokeWidth) || 0
103
- const len = el.getTotalLength() + strokeWidth
104
-
105
- el.style.strokeDasharray = `${len}`
106
- el.style.strokeDashoffset = `${len}`
107
-
108
- const anim = el.animate([{ strokeDashoffset: `${len}` }, { strokeDashoffset: '0' }], {
109
- duration: this.duration,
110
- easing: this.easing,
111
- fill: 'forwards'
112
- })
113
- anim.onfinish = onFinish
114
- }
115
-
116
- private stopAnimation() {
117
- this.isAnimating = false
118
- this.svgClone = null
119
- }
120
-
121
- render() {
122
- return html`
123
- <slot ?hidden="${this.isAnimating}" @slotchange="${this.handleSlotChange}"></slot>
124
- ${this.isAnimating ? this.svgClone : ''}
125
- `
126
- }
127
- }
@@ -1,21 +0,0 @@
1
- :host {
2
- position: relative;
3
- display: inline-block;
4
- vertical-align: middle;
5
-
6
- .svg-clone {
7
- pointer-events: none;
8
-
9
- position: absolute;
10
- top: 0;
11
- left: 0;
12
-
13
- width: 100%;
14
- height: 100%;
15
- }
16
-
17
- slot[hidden] {
18
- display: contents;
19
- visibility: hidden;
20
- }
21
- }
package/src/index.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from '@/components/back-top'
2
- export * from '@/components/button'
3
- export * from '@/components/layout'
4
- export * from '@/components/svg-draw-lines'
@@ -1,30 +0,0 @@
1
- import type { DetailedHTMLProps, HTMLAttributes } from 'react'
2
-
3
- import type { WebUiBackTop, WebUiButton, WebUiLayout } from '..'
4
-
5
- import type { ExtractProps, OmitLitBase } from './utils'
6
- // 提取 $events 并转化为 React 的 on 事件
7
- type ExtractReactEvents<T> = T extends { readonly $events: infer E }
8
- ? {
9
- [K in keyof E as `on${string & K}`]?: (e: E[K]) => void
10
- }
11
- : object
12
-
13
- export type ReactWrapper<T> = DetailedHTMLProps<
14
- ExtractProps<OmitLitBase<T>> & ExtractReactEvents<T> & HTMLAttributes<HTMLElement>,
15
- HTMLElement
16
- >
17
-
18
- export interface WebUiComponents {
19
- 'web-ui-button': ReactWrapper<WebUiButton>
20
- 'web-ui-back-top': ReactWrapper<WebUiBackTop>
21
- 'web-ui-layout': ReactWrapper<WebUiLayout>
22
- }
23
-
24
- declare module 'react' {
25
- // oxlint-disable-next-line typescript/no-namespace
26
- namespace JSX {
27
- // oxlint-disable-next-line typescript/no-empty-object-type
28
- interface IntrinsicElements extends WebUiComponents {}
29
- }
30
- }
@@ -1,14 +0,0 @@
1
- import type { LitElement } from 'lit'
2
-
3
- type Fn = (...args: unknown[]) => unknown
4
-
5
- /**
6
- * 1. 移除属性中的函数
7
- * 2. 移除 $events 虚拟属性
8
- * 3. 属性全部设为可选(符合 web component 标准)
9
- */
10
- export type ExtractProps<T> = {
11
- [K in keyof T as T[K] extends Fn ? never : K extends '$events' ? never : K]?: T[K]
12
- }
13
-
14
- export type OmitLitBase<T> = Omit<T, keyof HTMLElement | keyof LitElement>
package/src/types/vue.ts DELETED
@@ -1,27 +0,0 @@
1
- import type { DefineComponent } from 'vue'
2
-
3
- import type { WebUiBackTop, WebUiButton, WebUiLayout } from '..'
4
-
5
- import type { ExtractProps, OmitLitBase } from './utils'
6
-
7
- // 提取 $events 并转化为 Vue on 事件
8
- // 使用 Capitalize 让事件在 Vue 模板中获得更好的驼峰/短横线兼容支持
9
- // 例如:识别 onVisibleChange 或 onVisible-change 格式
10
- type ExtractVueEvents<T> = T extends { readonly $events: infer E }
11
- ? {
12
- [K in keyof E as `on${Capitalize<string & K>}`]?: (e: E[K]) => void
13
- }
14
- : object
15
-
16
- export type VueWrapper<T> = DefineComponent<ExtractProps<OmitLitBase<T>> & ExtractVueEvents<T>>
17
-
18
- export interface WebUiComponents {
19
- 'web-ui-button': VueWrapper<WebUiButton>
20
- 'web-ui-back-top': VueWrapper<WebUiBackTop>
21
- 'web-ui-layout': VueWrapper<WebUiLayout>
22
- }
23
-
24
- declare module 'vue' {
25
- // oxlint-disable-next-line typescript/no-empty-object-type
26
- export interface GlobalComponents extends WebUiComponents {}
27
- }
package/tsconfig.app.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "experimentalDecorators": true, // Lit 必备
4
- "paths": {
5
- "@/*": ["./src/*"]
6
- },
7
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
8
- "types": ["vite/client"],
9
- "useDefineForClassFields": false // Lit 必备
10
- },
11
- "exclude": ["src/**/__tests__"],
12
- "extends": "@vue/tsconfig/tsconfig.dom.json",
13
- "include": ["src/**/*"]
14
- }
package/tsconfig.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "files": [],
3
- "references": [
4
- { "path": "./tsconfig.node.json" },
5
- { "path": "./tsconfig.app.json" },
6
- { "path": "./tsconfig.vitest.json" }
7
- ]
8
- }
@@ -1,18 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "module": "ESNext",
4
- "moduleResolution": "Bundler",
5
- "noEmit": true,
6
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
7
- "types": ["node"]
8
- },
9
- "extends": "@tsconfig/node24/tsconfig.json",
10
- "include": [
11
- "vite.config.*",
12
- "vitest.config.*",
13
- "cypress.config.*",
14
- "nightwatch.conf.*",
15
- "playwright.config.*",
16
- "eslint.config.*"
17
- ]
18
- }
@@ -1,10 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "lib": [],
4
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
5
- "types": ["node", "jsdom"]
6
- },
7
- "exclude": [],
8
- "extends": "./tsconfig.app.json",
9
- "include": ["src/**/__tests__"]
10
- }
package/vite.config.ts DELETED
@@ -1,40 +0,0 @@
1
- import { resolve } from 'node:path'
2
-
3
- import dts from 'vite-plugin-dts'
4
- import { type UserConfig } from 'vite-plus'
5
-
6
- export default {
7
- resolve: {
8
- tsconfigPaths: true
9
- },
10
- plugins: [
11
- dts({
12
- tsconfigPath: './tsconfig.app.json'
13
- })
14
- ],
15
- test: {
16
- environment: 'jsdom'
17
- },
18
- css: {
19
- transformer: 'lightningcss'
20
- },
21
- build: {
22
- cssMinify: 'lightningcss',
23
- sourcemap: true,
24
- lib: {
25
- entry: resolve(import.meta.dirname, 'src/index.ts'),
26
- name: 'WebUi',
27
- formats: ['es']
28
- },
29
- rollupOptions: {
30
- external: ['@greypan/browser-kit', '@greypan/js-kit'],
31
- output: {
32
- preserveModules: true,
33
- // 指定源码根目录,这样 dist 下就不会多出一层 'src' 目录
34
- preserveModulesRoot: 'src',
35
- dir: 'dist',
36
- entryFileNames: '[name].js'
37
- }
38
- }
39
- }
40
- } satisfies UserConfig