@vobs/ui 0.3.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +60 -0
- package/package.json +52 -110
- package/src/activity-rail.ts +125 -0
- package/src/alert.ts +65 -0
- package/src/assets/icons/alert-circle.svg +1 -0
- package/src/assets/icons/alert-triangle.svg +1 -0
- package/src/assets/icons/alert.d27e24.svg +1 -0
- package/src/assets/icons/alert.svg +1 -0
- package/src/assets/icons/apple.svg +1 -0
- package/src/assets/icons/arrow-down.svg +1 -0
- package/src/assets/icons/arrow-expand.svg +1 -0
- package/src/assets/icons/arrow-left.svg +1 -0
- package/src/assets/icons/arrow-minimize.svg +1 -0
- package/src/assets/icons/arrow-right-to-line.svg +1 -0
- package/src/assets/icons/arrow-right.svg +1 -0
- package/src/assets/icons/arrow-up-right.svg +1 -0
- package/src/assets/icons/arrow-up.0c0c0d.svg +1 -0
- package/src/assets/icons/arrow-up.svg +1 -0
- package/src/assets/icons/at.svg +1 -0
- package/src/assets/icons/atom.0c0c0d.svg +1 -0
- package/src/assets/icons/atom.svg +1 -0
- package/src/assets/icons/bar.svg +1 -0
- package/src/assets/icons/bell.svg +1 -0
- package/src/assets/icons/box.svg +1 -0
- package/src/assets/icons/bug.svg +1 -0
- package/src/assets/icons/calendar.svg +1 -0
- package/src/assets/icons/check-circle.33c192.svg +1 -0
- package/src/assets/icons/check-circle.svg +1 -0
- package/src/assets/icons/check.d1d3db.svg +1 -0
- package/src/assets/icons/check.svg +1 -0
- package/src/assets/icons/chevron-down.svg +1 -0
- package/src/assets/icons/chevron-right.svg +1 -0
- package/src/assets/icons/chevron-up.svg +1 -0
- package/src/assets/icons/circle.svg +1 -0
- package/src/assets/icons/clock.svg +1 -0
- package/src/assets/icons/cmd.svg +1 -0
- package/src/assets/icons/code.svg +1 -0
- package/src/assets/icons/columns.svg +1 -0
- package/src/assets/icons/copy.svg +1 -0
- package/src/assets/icons/cpu.svg +1 -0
- package/src/assets/icons/dashboard.0c0c0d.svg +1 -0
- package/src/assets/icons/dashboard.svg +1 -0
- package/src/assets/icons/dollar.svg +1 -0
- package/src/assets/icons/download.svg +1 -0
- package/src/assets/icons/edit.svg +1 -0
- package/src/assets/icons/extensions.svg +1 -0
- package/src/assets/icons/external.svg +1 -0
- package/src/assets/icons/eye.svg +1 -0
- package/src/assets/icons/file-text.svg +1 -0
- package/src/assets/icons/file.svg +1 -0
- package/src/assets/icons/files.svg +1 -0
- package/src/assets/icons/filter.svg +1 -0
- package/src/assets/icons/folder.svg +1 -0
- package/src/assets/icons/gear.svg +1 -0
- package/src/assets/icons/git.svg +1 -0
- package/src/assets/icons/github.svg +1 -0
- package/src/assets/icons/globe.svg +1 -0
- package/src/assets/icons/grid-2x2.svg +1 -0
- package/src/assets/icons/hash.svg +1 -0
- package/src/assets/icons/heart.svg +1 -0
- package/src/assets/icons/help.svg +1 -0
- package/src/assets/icons/home.svg +1 -0
- package/src/assets/icons/image.svg +1 -0
- package/src/assets/icons/info-circle.svg +1 -0
- package/src/assets/icons/info-square.svg +1 -0
- package/src/assets/icons/info.387bff.svg +1 -0
- package/src/assets/icons/info.svg +1 -0
- package/src/assets/icons/key.svg +1 -0
- package/src/assets/icons/layers.svg +1 -0
- package/src/assets/icons/layout.svg +1 -0
- package/src/assets/icons/link.svg +1 -0
- package/src/assets/icons/list.svg +1 -0
- package/src/assets/icons/lock.svg +1 -0
- package/src/assets/icons/log-out.svg +1 -0
- package/src/assets/icons/logo.svg +1 -0
- package/src/assets/icons/mail.svg +1 -0
- package/src/assets/icons/menu.svg +1 -0
- package/src/assets/icons/message-circle.svg +1 -0
- package/src/assets/icons/message-plus.svg +1 -0
- package/src/assets/icons/message-square.svg +1 -0
- package/src/assets/icons/mic.svg +1 -0
- package/src/assets/icons/minus.svg +1 -0
- package/src/assets/icons/moon.svg +1 -0
- package/src/assets/icons/more-h.svg +1 -0
- package/src/assets/icons/mouse.svg +1 -0
- package/src/assets/icons/palette.svg +1 -0
- package/src/assets/icons/panel-bottom.svg +1 -0
- package/src/assets/icons/pause.svg +1 -0
- package/src/assets/icons/play.svg +1 -0
- package/src/assets/icons/plug.svg +1 -0
- package/src/assets/icons/plus.0c0c0d.svg +1 -0
- package/src/assets/icons/plus.svg +1 -0
- package/src/assets/icons/refresh.svg +1 -0
- package/src/assets/icons/ruler.svg +1 -0
- package/src/assets/icons/scroll-text.svg +1 -0
- package/src/assets/icons/search-menu.svg +1 -0
- package/src/assets/icons/search.svg +1 -0
- package/src/assets/icons/send.0c0c0d.svg +1 -0
- package/src/assets/icons/send.svg +1 -0
- package/src/assets/icons/settings.0c0c0d.svg +1 -0
- package/src/assets/icons/settings.svg +1 -0
- package/src/assets/icons/shield.svg +1 -0
- package/src/assets/icons/sidebar-left.svg +1 -0
- package/src/assets/icons/sidebar-right.svg +1 -0
- package/src/assets/icons/sliders.svg +1 -0
- package/src/assets/icons/sparkles.32f08c.svg +1 -0
- package/src/assets/icons/sparkles.svg +1 -0
- package/src/assets/icons/square.svg +1 -0
- package/src/assets/icons/star.svg +1 -0
- package/src/assets/icons/sun.svg +1 -0
- package/src/assets/icons/terminal.svg +1 -0
- package/src/assets/icons/trash.svg +1 -0
- package/src/assets/icons/trending-down.svg +1 -0
- package/src/assets/icons/trending-up.svg +1 -0
- package/src/assets/icons/type.svg +1 -0
- package/src/assets/icons/upload.svg +1 -0
- package/src/assets/icons/user-circle.svg +1 -0
- package/src/assets/icons/user.svg +1 -0
- package/src/assets/icons/users.svg +1 -0
- package/src/assets/icons/wrench.svg +1 -0
- package/src/assets/icons/x-circle.svg +1 -0
- package/src/assets/icons/x.svg +1 -0
- package/src/assets/icons/zap.0c0c0d.svg +1 -0
- package/src/assets/icons/zap.svg +1 -0
- package/src/avatar.ts +64 -0
- package/src/button.ts +88 -0
- package/src/card.ts +59 -0
- package/src/chat-composer.ts +156 -0
- package/src/dialog.ts +127 -0
- package/src/drawer.ts +131 -0
- package/src/editor-tabs.ts +184 -0
- package/src/file-tree.ts +214 -0
- package/src/forms.ts +270 -0
- package/src/icon.ts +118 -0
- package/src/icons.js +165 -0
- package/src/index.test.ts +213 -0
- package/src/index.ts +94 -0
- package/src/kbd.ts +72 -0
- package/src/menu.ts +119 -0
- package/src/nav-list.ts +157 -0
- package/src/overlay.test.ts +66 -0
- package/src/overlay.ts +205 -0
- package/src/page-header.ts +97 -0
- package/src/pagination.ts +163 -0
- package/src/second-batch.test.ts +205 -0
- package/src/stat-card.ts +92 -0
- package/src/status-bar.ts +108 -0
- package/src/styles/base.css +240 -0
- package/src/styles/components.css +1234 -0
- package/{dist → src/styles}/styles.css +2 -0
- package/src/styles/toast.css +57 -0
- package/src/styles/tokens.css +438 -0
- package/src/styles/vui.css +47 -0
- package/src/table.ts +191 -0
- package/src/tabs.ts +100 -0
- package/src/tag.ts +33 -0
- package/src/third-batch.test.ts +137 -0
- package/src/toast.test.ts +55 -0
- package/src/toast.ts +79 -0
- package/src/types.ts +25 -0
- package/src/utils.ts +221 -0
- package/src/workbench-titlebar.ts +137 -0
- package/dist/app-shell-dom.d.ts +0 -30
- package/dist/app-shell-dom.js +0 -913
- package/dist/app-shell.d.ts +0 -235
- package/dist/app-shell.js +0 -415
- package/dist/base.css +0 -51
- package/dist/calendar-picker.d.ts +0 -45
- package/dist/calendar-picker.js +0 -217
- package/dist/calendar.d.ts +0 -95
- package/dist/calendar.js +0 -194
- package/dist/complex-inputs.d.ts +0 -300
- package/dist/complex-inputs.js +0 -866
- package/dist/components.css +0 -4756
- package/dist/data-display.d.ts +0 -1094
- package/dist/data-display.js +0 -2341
- package/dist/dialog.d.ts +0 -26
- package/dist/dialog.js +0 -94
- package/dist/feedback.d.ts +0 -88
- package/dist/feedback.js +0 -281
- package/dist/forms.d.ts +0 -378
- package/dist/forms.js +0 -1019
- package/dist/icons-config.d.ts +0 -25
- package/dist/icons-config.js +0 -14
- package/dist/icons.d.ts +0 -41
- package/dist/icons.js +0 -185
- package/dist/index.d.ts +0 -31
- package/dist/index.js +0 -40
- package/dist/locale/en-US.d.ts +0 -31
- package/dist/locale/en-US.js +0 -20
- package/dist/locale/zh-CN.d.ts +0 -31
- package/dist/locale/zh-CN.js +0 -20
- package/dist/navigation.d.ts +0 -609
- package/dist/navigation.js +0 -1707
- package/dist/overlay.d.ts +0 -308
- package/dist/overlay.js +0 -974
- package/dist/page-state.d.ts +0 -23
- package/dist/page-state.js +0 -96
- package/dist/primitives.d.ts +0 -268
- package/dist/primitives.js +0 -764
- package/dist/theme-data.d.ts +0 -394
- package/dist/theme-data.js +0 -417
- package/dist/theme.d.ts +0 -97
- package/dist/theme.js +0 -301
- package/dist/tokens.css +0 -570
- package/dist/tree.d.ts +0 -144
- package/dist/tree.js +0 -475
- package/dist/virtual-list.d.ts +0 -190
- package/dist/virtual-list.js +0 -538
- package/dist/workbench.d.ts +0 -136
- package/dist/workbench.js +0 -156
package/src/utils.ts
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { effect } from '@vobs/reactivity'
|
|
2
|
+
import {
|
|
3
|
+
addEventListener,
|
|
4
|
+
createFragment,
|
|
5
|
+
createText,
|
|
6
|
+
insertBefore,
|
|
7
|
+
insertDynamic,
|
|
8
|
+
setAttribute,
|
|
9
|
+
setProperty,
|
|
10
|
+
setTextContent,
|
|
11
|
+
type VobsNode
|
|
12
|
+
} from '@vobs/vobs'
|
|
13
|
+
import type { VuiCommonProps } from './types'
|
|
14
|
+
|
|
15
|
+
type VuiProps = VuiCommonProps | object
|
|
16
|
+
|
|
17
|
+
export function classNames(...values: readonly (string | false | null | undefined)[]): string {
|
|
18
|
+
return values
|
|
19
|
+
.flatMap(value => typeof value === 'string' ? value.trim().split(/\s+/u) : [])
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
.join(' ')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function readProp<T>(props: object, name: string, fallback: T): T {
|
|
25
|
+
const value = Reflect.get(props, name)
|
|
26
|
+
return (value === undefined ? fallback : value) as T
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function hasProp(props: object, name: string): boolean {
|
|
30
|
+
return name in props
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function bindClass(
|
|
34
|
+
root: Element,
|
|
35
|
+
props: VuiProps,
|
|
36
|
+
...baseClasses: readonly (string | undefined)[]
|
|
37
|
+
): void {
|
|
38
|
+
effect(() => {
|
|
39
|
+
setAttribute(root, 'class', classNames(
|
|
40
|
+
...baseClasses,
|
|
41
|
+
readString(props, 'class'),
|
|
42
|
+
readString(props, 'className')
|
|
43
|
+
))
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function bindClassList(
|
|
48
|
+
root: Element,
|
|
49
|
+
props: VuiProps,
|
|
50
|
+
readBaseClasses: () => readonly (string | undefined)[]
|
|
51
|
+
): void {
|
|
52
|
+
effect(() => {
|
|
53
|
+
setAttribute(root, 'class', classNames(
|
|
54
|
+
...readBaseClasses(),
|
|
55
|
+
readString(props, 'class'),
|
|
56
|
+
readString(props, 'className')
|
|
57
|
+
))
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function bindCommonAttributes(
|
|
62
|
+
root: Element,
|
|
63
|
+
props: VuiProps,
|
|
64
|
+
skip: readonly string[] = [],
|
|
65
|
+
options: { readonly includeDataAria?: boolean } = {}
|
|
66
|
+
): void {
|
|
67
|
+
const ignored = new Set(skip)
|
|
68
|
+
ignored.add('class')
|
|
69
|
+
ignored.add('className')
|
|
70
|
+
ignored.add('children')
|
|
71
|
+
ignored.add('style')
|
|
72
|
+
|
|
73
|
+
effect(() => {
|
|
74
|
+
const next = new Map<string, string>()
|
|
75
|
+
for (const name of Object.keys(props)) {
|
|
76
|
+
if (ignored.has(name) || name.startsWith('on')) continue
|
|
77
|
+
if (!isCommonAttribute(name)) continue
|
|
78
|
+
if (options.includeDataAria === false && (name.startsWith('aria-') || name.startsWith('data-'))) continue
|
|
79
|
+
|
|
80
|
+
const value = Reflect.get(props, name)
|
|
81
|
+
const normalized = normalizeAttribute(name, value)
|
|
82
|
+
if (normalized !== undefined) next.set(normalized.name, normalized.value)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const managed = getManagedAttributes(root)
|
|
86
|
+
for (const name of managed) {
|
|
87
|
+
if (!next.has(name)) removeAttribute(root, name)
|
|
88
|
+
}
|
|
89
|
+
for (const [name, value] of next) setAttribute(root, name, value)
|
|
90
|
+
setManagedAttributes(root, next.keys())
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function bindUserStyle(root: Element, props: VuiProps): void {
|
|
95
|
+
bindStyle(root, props, () => '')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function bindStyle(root: Element, props: VuiProps, createStyle: () => string): void {
|
|
99
|
+
effect(() => {
|
|
100
|
+
const userStyle = readString(props, 'style')
|
|
101
|
+
const internalStyle = createStyle()
|
|
102
|
+
const style = [internalStyle, userStyle].filter(Boolean).join('; ')
|
|
103
|
+
if (style) setAttribute(root, 'style', style)
|
|
104
|
+
else removeAttribute(root, 'style')
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function bindTextContent(
|
|
109
|
+
node: Text,
|
|
110
|
+
read: () => unknown
|
|
111
|
+
): void {
|
|
112
|
+
effect(() => {
|
|
113
|
+
setTextContent(node, String(read() ?? ''))
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function bindPropertyValue(
|
|
118
|
+
node: Element,
|
|
119
|
+
name: string,
|
|
120
|
+
read: () => unknown
|
|
121
|
+
): void {
|
|
122
|
+
effect(() => setProperty(node, name, read()))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function bindAttributeValue(
|
|
126
|
+
node: Element,
|
|
127
|
+
name: string,
|
|
128
|
+
read: () => unknown
|
|
129
|
+
): void {
|
|
130
|
+
effect(() => {
|
|
131
|
+
const value = read()
|
|
132
|
+
if (value === undefined || value === null || value === false) removeAttribute(node, name)
|
|
133
|
+
else setAttribute(node, name, String(value))
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function listen(
|
|
138
|
+
root: Element,
|
|
139
|
+
event: string,
|
|
140
|
+
props: object,
|
|
141
|
+
propName: string,
|
|
142
|
+
disabled?: () => boolean
|
|
143
|
+
): void {
|
|
144
|
+
addEventListener(root, event, (reason: Event) => {
|
|
145
|
+
if (disabled?.()) return
|
|
146
|
+
const handler = Reflect.get(props, propName)
|
|
147
|
+
if (typeof handler === 'function') handler(reason)
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function mountSlot(
|
|
152
|
+
parent: Node,
|
|
153
|
+
props: object,
|
|
154
|
+
propName: string
|
|
155
|
+
): void {
|
|
156
|
+
insertDynamic(parent, null, () => resolveSlot(Reflect.get(props, propName)))
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function resolveSlot(value: unknown): VobsNode | null {
|
|
160
|
+
const resolved = typeof value === 'function' ? value() : value
|
|
161
|
+
if (resolved === undefined || resolved === null || resolved === false) return null
|
|
162
|
+
if (typeof resolved === 'string' || typeof resolved === 'number') return createText(String(resolved))
|
|
163
|
+
if (Array.isArray(resolved)) {
|
|
164
|
+
const children = resolved
|
|
165
|
+
return createFragment((parent, anchor) => {
|
|
166
|
+
for (const child of children) {
|
|
167
|
+
const node = resolveSlot(child)
|
|
168
|
+
if (node) insertBefore(parent, node, anchor)
|
|
169
|
+
}
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
return resolved as VobsNode
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function setOptionalAttribute(node: Element, name: string, value: unknown): void {
|
|
176
|
+
if (value === undefined || value === null || value === false || value === '') {
|
|
177
|
+
removeAttribute(node, name)
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
setAttribute(node, name, String(value))
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function setOptionalProperty(node: Element, name: string, value: unknown): void {
|
|
184
|
+
if (value === undefined || value === null) return
|
|
185
|
+
setProperty(node, name, value)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function readString(props: object, name: string): string | undefined {
|
|
189
|
+
const value = Reflect.get(props, name)
|
|
190
|
+
return typeof value === 'string' ? value : undefined
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function isCommonAttribute(name: string): boolean {
|
|
194
|
+
return name === 'id'
|
|
195
|
+
|| name === 'title'
|
|
196
|
+
|| name === 'role'
|
|
197
|
+
|| name === 'tabIndex'
|
|
198
|
+
|| name.startsWith('aria-')
|
|
199
|
+
|| name.startsWith('data-')
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function normalizeAttribute(name: string, value: unknown): { name: string; value: string } | undefined {
|
|
203
|
+
if (value === undefined || value === null) return undefined
|
|
204
|
+
if (value === false && !name.startsWith('aria-') && !name.startsWith('data-')) return undefined
|
|
205
|
+
return { name: name === 'tabIndex' ? 'tabindex' : name, value: String(value) }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const managedAttributes = new WeakMap<object, Set<string>>()
|
|
209
|
+
|
|
210
|
+
function getManagedAttributes(node: Element): Set<string> {
|
|
211
|
+
return managedAttributes.get(node) ?? new Set<string>()
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function setManagedAttributes(node: Element, names: IterableIterator<string>): void {
|
|
215
|
+
managedAttributes.set(node, new Set(names))
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function removeAttribute(node: Element, name: string): void {
|
|
219
|
+
const candidate = node as Element & { removeAttribute?: (attribute: string) => void }
|
|
220
|
+
candidate.removeAttribute?.(name)
|
|
221
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addEventListener,
|
|
3
|
+
createElement,
|
|
4
|
+
createFragment,
|
|
5
|
+
createText,
|
|
6
|
+
insertBefore,
|
|
7
|
+
insertDynamic,
|
|
8
|
+
setAttribute,
|
|
9
|
+
type VobsNode
|
|
10
|
+
} from '@vobs/vobs'
|
|
11
|
+
import {
|
|
12
|
+
bindClassList,
|
|
13
|
+
bindCommonAttributes,
|
|
14
|
+
bindTextContent,
|
|
15
|
+
bindUserStyle,
|
|
16
|
+
hasProp,
|
|
17
|
+
mountSlot,
|
|
18
|
+
readProp,
|
|
19
|
+
setOptionalAttribute
|
|
20
|
+
} from './utils'
|
|
21
|
+
import type { VuiChildren, VuiCommonProps } from './types'
|
|
22
|
+
|
|
23
|
+
export interface WorkbenchTitlebarProps extends VuiCommonProps {
|
|
24
|
+
readonly mode?: string
|
|
25
|
+
readonly modeIcon?: VuiChildren
|
|
26
|
+
readonly project?: string
|
|
27
|
+
readonly projectIcon?: VuiChildren
|
|
28
|
+
readonly projectChevron?: VuiChildren
|
|
29
|
+
readonly actions?: VuiChildren
|
|
30
|
+
readonly windowControls?: boolean
|
|
31
|
+
readonly onWindowClose?: (event: MouseEvent) => void
|
|
32
|
+
readonly onWindowMinimize?: (event: MouseEvent) => void
|
|
33
|
+
readonly onWindowMaximize?: (event: MouseEvent) => void
|
|
34
|
+
readonly onProjectClick?: (event: MouseEvent) => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function WorkbenchTitlebar(props: WorkbenchTitlebarProps = {}): VobsNode {
|
|
38
|
+
const root = createElement('header')
|
|
39
|
+
const left = createElement('div')
|
|
40
|
+
const right = createElement('div')
|
|
41
|
+
bindClassList(root, props, () => ['vui-wbtitlebar'])
|
|
42
|
+
bindCommonAttributes(root, props, [
|
|
43
|
+
'mode',
|
|
44
|
+
'modeIcon',
|
|
45
|
+
'project',
|
|
46
|
+
'projectIcon',
|
|
47
|
+
'projectChevron',
|
|
48
|
+
'actions',
|
|
49
|
+
'windowControls',
|
|
50
|
+
'onWindowClose',
|
|
51
|
+
'onWindowMinimize',
|
|
52
|
+
'onWindowMaximize',
|
|
53
|
+
'onProjectClick'
|
|
54
|
+
])
|
|
55
|
+
bindUserStyle(root, props)
|
|
56
|
+
setAttribute(left, 'class', 'vui-wbtitlebar__left')
|
|
57
|
+
setAttribute(right, 'class', 'vui-wbtitlebar__right')
|
|
58
|
+
insertDynamic(left, null, () => createTitlebarLeft(props))
|
|
59
|
+
if (hasProp(props, 'actions')) mountSlot(right, props, 'actions')
|
|
60
|
+
if (hasProp(props, 'children')) mountSlot(right, props, 'children')
|
|
61
|
+
insertBefore(root, left, null)
|
|
62
|
+
insertBefore(root, right, null)
|
|
63
|
+
return root
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function createTitlebarLeft(props: WorkbenchTitlebarProps): VobsNode {
|
|
67
|
+
return createFragment((parent, anchor) => {
|
|
68
|
+
if (readProp(props, 'windowControls', true)) {
|
|
69
|
+
const lights = createElement('div')
|
|
70
|
+
setAttribute(lights, 'class', 'vui-wbtitlebar__lights')
|
|
71
|
+
insertBefore(lights, createWindowLight('close', props, 'onWindowClose'), null)
|
|
72
|
+
insertBefore(lights, createWindowLight('min', props, 'onWindowMinimize'), null)
|
|
73
|
+
insertBefore(lights, createWindowLight('max', props, 'onWindowMaximize'), null)
|
|
74
|
+
insertBefore(parent, lights, anchor)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (hasProp(props, 'mode')) {
|
|
78
|
+
const mode = createElement('span')
|
|
79
|
+
setAttribute(mode, 'class', 'vui-wbtitlebar__mode-chip')
|
|
80
|
+
if (hasProp(props, 'modeIcon')) {
|
|
81
|
+
const icon = createElement('span')
|
|
82
|
+
setAttribute(icon, 'class', 'vui-wbtitlebar__mode-icon')
|
|
83
|
+
mountSlot(icon, props, 'modeIcon')
|
|
84
|
+
insertBefore(mode, icon, null)
|
|
85
|
+
}
|
|
86
|
+
const text = createText('')
|
|
87
|
+
bindTextContent(text, () => readProp(props, 'mode', ''))
|
|
88
|
+
insertBefore(mode, text, null)
|
|
89
|
+
insertBefore(parent, mode, anchor)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (hasProp(props, 'project')) insertBefore(parent, createProjectSelector(props), anchor)
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function createWindowLight(
|
|
97
|
+
kind: 'close' | 'min' | 'max',
|
|
98
|
+
props: WorkbenchTitlebarProps,
|
|
99
|
+
handlerName: 'onWindowClose' | 'onWindowMinimize' | 'onWindowMaximize'
|
|
100
|
+
): VobsNode {
|
|
101
|
+
const light = createElement('button')
|
|
102
|
+
setAttribute(light, 'class', `vui-wbtitlebar__light vui-wbtitlebar__light--${kind}`)
|
|
103
|
+
setAttribute(light, 'type', 'button')
|
|
104
|
+
setAttribute(light, 'aria-label', kind === 'close' ? 'Close window' : kind === 'min' ? 'Minimize window' : 'Maximize window')
|
|
105
|
+
addEventListener(light, 'click', event => {
|
|
106
|
+
const handler = readProp<unknown>(props, handlerName, undefined)
|
|
107
|
+
if (typeof handler === 'function') (handler as WorkbenchTitlebarProps[typeof handlerName])!(event as MouseEvent)
|
|
108
|
+
})
|
|
109
|
+
return light
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function createProjectSelector(props: WorkbenchTitlebarProps): VobsNode {
|
|
113
|
+
const button = createElement('button')
|
|
114
|
+
setAttribute(button, 'class', 'vui-wbtitlebar__project-selector')
|
|
115
|
+
setAttribute(button, 'type', 'button')
|
|
116
|
+
setOptionalAttribute(button, 'aria-label', readProp(props, 'project', 'Project'))
|
|
117
|
+
if (hasProp(props, 'projectIcon')) {
|
|
118
|
+
const icon = createElement('span')
|
|
119
|
+
setAttribute(icon, 'class', 'vui-wbtitlebar__project-icon')
|
|
120
|
+
mountSlot(icon, props, 'projectIcon')
|
|
121
|
+
insertBefore(button, icon, null)
|
|
122
|
+
}
|
|
123
|
+
const project = createText('')
|
|
124
|
+
bindTextContent(project, () => readProp(props, 'project', ''))
|
|
125
|
+
insertBefore(button, project, null)
|
|
126
|
+
if (hasProp(props, 'projectChevron')) {
|
|
127
|
+
const chevron = createElement('span')
|
|
128
|
+
setAttribute(chevron, 'class', 'vui-wbtitlebar__project-chevron')
|
|
129
|
+
mountSlot(chevron, props, 'projectChevron')
|
|
130
|
+
insertBefore(button, chevron, null)
|
|
131
|
+
}
|
|
132
|
+
addEventListener(button, 'click', event => {
|
|
133
|
+
const handler = readProp<unknown>(props, 'onProjectClick', undefined)
|
|
134
|
+
if (typeof handler === 'function') (handler as WorkbenchTitlebarProps['onProjectClick'])!(event as MouseEvent)
|
|
135
|
+
})
|
|
136
|
+
return button
|
|
137
|
+
}
|
package/dist/app-shell-dom.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/** @license MIT
|
|
2
|
-
* Copyright (c) 2026 vobsjs
|
|
3
|
-
* @vobs/ui
|
|
4
|
-
*/
|
|
5
|
-
import { type Owner, type TemplateEnvironment } from '@vobs/runtime-dom';
|
|
6
|
-
import type { AppShellDefinition, AppShellComponentScope, ResolvedAppShellState, ResolvedAppShellStatus } from './app-shell.js';
|
|
7
|
-
export interface AppShellFrame {
|
|
8
|
-
readonly root: HTMLDivElement;
|
|
9
|
-
readonly brand: HTMLAnchorElement;
|
|
10
|
-
readonly sidebar: HTMLElement;
|
|
11
|
-
readonly main: HTMLElement;
|
|
12
|
-
readonly primaryNav: HTMLElement;
|
|
13
|
-
readonly utilityNav: HTMLElement;
|
|
14
|
-
readonly pageFrame: HTMLElement;
|
|
15
|
-
readonly pageHeader: HTMLElement;
|
|
16
|
-
readonly pageToolbar: HTMLElement;
|
|
17
|
-
readonly statusbar: HTMLElement;
|
|
18
|
-
readonly statusIcon: HTMLElement;
|
|
19
|
-
readonly statusText: HTMLSpanElement;
|
|
20
|
-
readonly pageKicker: HTMLParagraphElement;
|
|
21
|
-
readonly pageTitle: HTMLHeadingElement;
|
|
22
|
-
readonly pageDescription: HTMLParagraphElement;
|
|
23
|
-
readonly version: HTMLSpanElement;
|
|
24
|
-
}
|
|
25
|
-
export declare function createAppShellFrame(shell: AppShellDefinition, scope: AppShellComponentScope, environment: TemplateEnvironment): AppShellFrame;
|
|
26
|
-
export declare function bindAppShellThemeControls(owner: Owner, frame: AppShellFrame, shell: AppShellDefinition, scope: AppShellComponentScope, environment: TemplateEnvironment): void;
|
|
27
|
-
export declare function bindAppShellAccountMenu(owner: Owner, frame: AppShellFrame, shell: AppShellDefinition): void;
|
|
28
|
-
export declare function bindAppShellActions(owner: Owner, frame: AppShellFrame, shell: AppShellDefinition): void;
|
|
29
|
-
export declare function syncAppShellFrame(frame: AppShellFrame, shell: AppShellDefinition, state: ResolvedAppShellState, status: ResolvedAppShellStatus, scope: AppShellComponentScope, environment: TemplateEnvironment): void;
|
|
30
|
-
export declare function bindAppShellLanguageMenu(owner: Owner, frame: AppShellFrame, shell: AppShellDefinition, scope: AppShellComponentScope, environment: TemplateEnvironment): void;
|