@vobs/ui 0.3.0 → 1.0.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 (212) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +60 -0
  3. package/package.json +52 -110
  4. package/src/activity-rail.ts +125 -0
  5. package/src/alert.ts +65 -0
  6. package/src/assets/icons/alert-circle.svg +1 -0
  7. package/src/assets/icons/alert-triangle.svg +1 -0
  8. package/src/assets/icons/alert.d27e24.svg +1 -0
  9. package/src/assets/icons/alert.svg +1 -0
  10. package/src/assets/icons/apple.svg +1 -0
  11. package/src/assets/icons/arrow-down.svg +1 -0
  12. package/src/assets/icons/arrow-expand.svg +1 -0
  13. package/src/assets/icons/arrow-left.svg +1 -0
  14. package/src/assets/icons/arrow-minimize.svg +1 -0
  15. package/src/assets/icons/arrow-right-to-line.svg +1 -0
  16. package/src/assets/icons/arrow-right.svg +1 -0
  17. package/src/assets/icons/arrow-up-right.svg +1 -0
  18. package/src/assets/icons/arrow-up.0c0c0d.svg +1 -0
  19. package/src/assets/icons/arrow-up.svg +1 -0
  20. package/src/assets/icons/at.svg +1 -0
  21. package/src/assets/icons/atom.0c0c0d.svg +1 -0
  22. package/src/assets/icons/atom.svg +1 -0
  23. package/src/assets/icons/bar.svg +1 -0
  24. package/src/assets/icons/bell.svg +1 -0
  25. package/src/assets/icons/box.svg +1 -0
  26. package/src/assets/icons/bug.svg +1 -0
  27. package/src/assets/icons/calendar.svg +1 -0
  28. package/src/assets/icons/check-circle.33c192.svg +1 -0
  29. package/src/assets/icons/check-circle.svg +1 -0
  30. package/src/assets/icons/check.d1d3db.svg +1 -0
  31. package/src/assets/icons/check.svg +1 -0
  32. package/src/assets/icons/chevron-down.svg +1 -0
  33. package/src/assets/icons/chevron-right.svg +1 -0
  34. package/src/assets/icons/chevron-up.svg +1 -0
  35. package/src/assets/icons/circle.svg +1 -0
  36. package/src/assets/icons/clock.svg +1 -0
  37. package/src/assets/icons/cmd.svg +1 -0
  38. package/src/assets/icons/code.svg +1 -0
  39. package/src/assets/icons/columns.svg +1 -0
  40. package/src/assets/icons/copy.svg +1 -0
  41. package/src/assets/icons/cpu.svg +1 -0
  42. package/src/assets/icons/dashboard.0c0c0d.svg +1 -0
  43. package/src/assets/icons/dashboard.svg +1 -0
  44. package/src/assets/icons/dollar.svg +1 -0
  45. package/src/assets/icons/download.svg +1 -0
  46. package/src/assets/icons/edit.svg +1 -0
  47. package/src/assets/icons/extensions.svg +1 -0
  48. package/src/assets/icons/external.svg +1 -0
  49. package/src/assets/icons/eye.svg +1 -0
  50. package/src/assets/icons/file-text.svg +1 -0
  51. package/src/assets/icons/file.svg +1 -0
  52. package/src/assets/icons/files.svg +1 -0
  53. package/src/assets/icons/filter.svg +1 -0
  54. package/src/assets/icons/folder.svg +1 -0
  55. package/src/assets/icons/gear.svg +1 -0
  56. package/src/assets/icons/git.svg +1 -0
  57. package/src/assets/icons/github.svg +1 -0
  58. package/src/assets/icons/globe.svg +1 -0
  59. package/src/assets/icons/grid-2x2.svg +1 -0
  60. package/src/assets/icons/hash.svg +1 -0
  61. package/src/assets/icons/heart.svg +1 -0
  62. package/src/assets/icons/help.svg +1 -0
  63. package/src/assets/icons/home.svg +1 -0
  64. package/src/assets/icons/image.svg +1 -0
  65. package/src/assets/icons/info-circle.svg +1 -0
  66. package/src/assets/icons/info-square.svg +1 -0
  67. package/src/assets/icons/info.387bff.svg +1 -0
  68. package/src/assets/icons/info.svg +1 -0
  69. package/src/assets/icons/key.svg +1 -0
  70. package/src/assets/icons/layers.svg +1 -0
  71. package/src/assets/icons/layout.svg +1 -0
  72. package/src/assets/icons/link.svg +1 -0
  73. package/src/assets/icons/list.svg +1 -0
  74. package/src/assets/icons/lock.svg +1 -0
  75. package/src/assets/icons/log-out.svg +1 -0
  76. package/src/assets/icons/logo.svg +1 -0
  77. package/src/assets/icons/mail.svg +1 -0
  78. package/src/assets/icons/menu.svg +1 -0
  79. package/src/assets/icons/message-circle.svg +1 -0
  80. package/src/assets/icons/message-plus.svg +1 -0
  81. package/src/assets/icons/message-square.svg +1 -0
  82. package/src/assets/icons/mic.svg +1 -0
  83. package/src/assets/icons/minus.svg +1 -0
  84. package/src/assets/icons/moon.svg +1 -0
  85. package/src/assets/icons/more-h.svg +1 -0
  86. package/src/assets/icons/mouse.svg +1 -0
  87. package/src/assets/icons/palette.svg +1 -0
  88. package/src/assets/icons/panel-bottom.svg +1 -0
  89. package/src/assets/icons/pause.svg +1 -0
  90. package/src/assets/icons/play.svg +1 -0
  91. package/src/assets/icons/plug.svg +1 -0
  92. package/src/assets/icons/plus.0c0c0d.svg +1 -0
  93. package/src/assets/icons/plus.svg +1 -0
  94. package/src/assets/icons/refresh.svg +1 -0
  95. package/src/assets/icons/ruler.svg +1 -0
  96. package/src/assets/icons/scroll-text.svg +1 -0
  97. package/src/assets/icons/search-menu.svg +1 -0
  98. package/src/assets/icons/search.svg +1 -0
  99. package/src/assets/icons/send.0c0c0d.svg +1 -0
  100. package/src/assets/icons/send.svg +1 -0
  101. package/src/assets/icons/settings.0c0c0d.svg +1 -0
  102. package/src/assets/icons/settings.svg +1 -0
  103. package/src/assets/icons/shield.svg +1 -0
  104. package/src/assets/icons/sidebar-left.svg +1 -0
  105. package/src/assets/icons/sidebar-right.svg +1 -0
  106. package/src/assets/icons/sliders.svg +1 -0
  107. package/src/assets/icons/sparkles.32f08c.svg +1 -0
  108. package/src/assets/icons/sparkles.svg +1 -0
  109. package/src/assets/icons/square.svg +1 -0
  110. package/src/assets/icons/star.svg +1 -0
  111. package/src/assets/icons/sun.svg +1 -0
  112. package/src/assets/icons/terminal.svg +1 -0
  113. package/src/assets/icons/trash.svg +1 -0
  114. package/src/assets/icons/trending-down.svg +1 -0
  115. package/src/assets/icons/trending-up.svg +1 -0
  116. package/src/assets/icons/type.svg +1 -0
  117. package/src/assets/icons/upload.svg +1 -0
  118. package/src/assets/icons/user-circle.svg +1 -0
  119. package/src/assets/icons/user.svg +1 -0
  120. package/src/assets/icons/users.svg +1 -0
  121. package/src/assets/icons/wrench.svg +1 -0
  122. package/src/assets/icons/x-circle.svg +1 -0
  123. package/src/assets/icons/x.svg +1 -0
  124. package/src/assets/icons/zap.0c0c0d.svg +1 -0
  125. package/src/assets/icons/zap.svg +1 -0
  126. package/src/avatar.ts +64 -0
  127. package/src/button.ts +88 -0
  128. package/src/card.ts +59 -0
  129. package/src/chat-composer.ts +156 -0
  130. package/src/dialog.ts +127 -0
  131. package/src/drawer.ts +131 -0
  132. package/src/editor-tabs.ts +184 -0
  133. package/src/file-tree.ts +214 -0
  134. package/src/forms.ts +270 -0
  135. package/src/icon.ts +117 -0
  136. package/src/icons.js +165 -0
  137. package/src/index.test.ts +213 -0
  138. package/src/index.ts +94 -0
  139. package/src/kbd.ts +72 -0
  140. package/src/menu.ts +119 -0
  141. package/src/nav-list.ts +157 -0
  142. package/src/overlay.test.ts +66 -0
  143. package/src/overlay.ts +205 -0
  144. package/src/page-header.ts +97 -0
  145. package/src/pagination.ts +163 -0
  146. package/src/second-batch.test.ts +205 -0
  147. package/src/stat-card.ts +92 -0
  148. package/src/status-bar.ts +108 -0
  149. package/src/styles/base.css +240 -0
  150. package/src/styles/components.css +1234 -0
  151. package/{dist → src/styles}/styles.css +2 -0
  152. package/src/styles/toast.css +57 -0
  153. package/src/styles/tokens.css +438 -0
  154. package/src/styles/vui.css +47 -0
  155. package/src/table.ts +191 -0
  156. package/src/tabs.ts +100 -0
  157. package/src/tag.ts +33 -0
  158. package/src/third-batch.test.ts +137 -0
  159. package/src/toast.test.ts +55 -0
  160. package/src/toast.ts +79 -0
  161. package/src/types.ts +25 -0
  162. package/src/utils.ts +221 -0
  163. package/src/workbench-titlebar.ts +137 -0
  164. package/dist/app-shell-dom.d.ts +0 -30
  165. package/dist/app-shell-dom.js +0 -913
  166. package/dist/app-shell.d.ts +0 -235
  167. package/dist/app-shell.js +0 -415
  168. package/dist/base.css +0 -51
  169. package/dist/calendar-picker.d.ts +0 -45
  170. package/dist/calendar-picker.js +0 -217
  171. package/dist/calendar.d.ts +0 -95
  172. package/dist/calendar.js +0 -194
  173. package/dist/complex-inputs.d.ts +0 -300
  174. package/dist/complex-inputs.js +0 -866
  175. package/dist/components.css +0 -4756
  176. package/dist/data-display.d.ts +0 -1094
  177. package/dist/data-display.js +0 -2341
  178. package/dist/dialog.d.ts +0 -26
  179. package/dist/dialog.js +0 -94
  180. package/dist/feedback.d.ts +0 -88
  181. package/dist/feedback.js +0 -281
  182. package/dist/forms.d.ts +0 -378
  183. package/dist/forms.js +0 -1019
  184. package/dist/icons-config.d.ts +0 -25
  185. package/dist/icons-config.js +0 -14
  186. package/dist/icons.d.ts +0 -41
  187. package/dist/icons.js +0 -185
  188. package/dist/index.d.ts +0 -31
  189. package/dist/index.js +0 -40
  190. package/dist/locale/en-US.d.ts +0 -31
  191. package/dist/locale/en-US.js +0 -20
  192. package/dist/locale/zh-CN.d.ts +0 -31
  193. package/dist/locale/zh-CN.js +0 -20
  194. package/dist/navigation.d.ts +0 -609
  195. package/dist/navigation.js +0 -1707
  196. package/dist/overlay.d.ts +0 -308
  197. package/dist/overlay.js +0 -974
  198. package/dist/page-state.d.ts +0 -23
  199. package/dist/page-state.js +0 -96
  200. package/dist/primitives.d.ts +0 -268
  201. package/dist/primitives.js +0 -764
  202. package/dist/theme-data.d.ts +0 -394
  203. package/dist/theme-data.js +0 -417
  204. package/dist/theme.d.ts +0 -97
  205. package/dist/theme.js +0 -301
  206. package/dist/tokens.css +0 -570
  207. package/dist/tree.d.ts +0 -144
  208. package/dist/tree.js +0 -475
  209. package/dist/virtual-list.d.ts +0 -190
  210. package/dist/virtual-list.js +0 -538
  211. package/dist/workbench.d.ts +0 -136
  212. package/dist/workbench.js +0 -156
package/dist/theme.js DELETED
@@ -1,301 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/ui
4
- */
5
- import { brandPresets, contrastRatio, DEFAULT_BRAND_ID, DEFAULT_THEME, deriveBrandTokens, deriveBrandTextColor, resolveBrandColor, themeTokenValues, } from './theme-data.js';
6
- export { brandPresets, contrastRatio, DEFAULT_BRAND_COLOR, DEFAULT_BRAND_ID, DEFAULT_THEME, deriveBrandTokens, deriveBrandTextColor, normalizeHexColor, resolveBrandColor, } from './theme-data.js';
7
- export const THEME_PREFERENCE_CHANGE_EVENT = 'vobs:theme-preference-change';
8
- export const THEME_STATE_CHANGE_EVENT = 'vobs:theme-state-change';
9
- const brandVariableNames = [
10
- '--bg-brand',
11
- '--bg-brand-hover',
12
- '--bg-brand-disabled',
13
- '--bg-brand-popup',
14
- '--bg-brand-overlay',
15
- '--text-brand',
16
- '--text-brand-hover',
17
- '--icon-brand',
18
- '--icon-brand-hover',
19
- '--border-brand',
20
- '--text-onbrand',
21
- '--icon-onbrand',
22
- '--color-primary',
23
- '--color-primary-hover',
24
- '--color-primary-disabled',
25
- '--color-primary-soft',
26
- '--color-accent',
27
- '--color-on-primary',
28
- ];
29
- export function createThemeController(options) {
30
- const listeners = new Set();
31
- const persistedPreference = readPersistedTheme(options.persistence);
32
- let preference = persistedPreference ??
33
- options.initialPreference ??
34
- (options.initialTheme === undefined && options.systemPreference !== undefined
35
- ? 'system'
36
- : (options.initialTheme ?? DEFAULT_THEME));
37
- let followsSystem = preference === 'system';
38
- let theme = resolveTheme(preference, options);
39
- let brand = readPersistedBrand(options.persistence, options.onWarning) ??
40
- readBrand(options.initialBrand ?? DEFAULT_BRAND_ID, options.onWarning);
41
- let stopSystemPreference;
42
- let destroyed = false;
43
- applyTheme(options.target, theme);
44
- applyBrand(options.target, brand, theme);
45
- subscribeToSystemPreference();
46
- function state() {
47
- return { theme, brand };
48
- }
49
- function notify() {
50
- const value = state();
51
- for (const listener of listeners)
52
- listener(value);
53
- }
54
- function setTheme(nextTheme) {
55
- setPreference(nextTheme);
56
- }
57
- function setPreference(nextPreference) {
58
- assertThemePreference(nextPreference);
59
- followsSystem = nextPreference === 'system';
60
- stopSystemPreference?.();
61
- stopSystemPreference = undefined;
62
- preference = nextPreference;
63
- theme = resolveTheme(preference, options);
64
- applyTheme(options.target, theme);
65
- applyBrand(options.target, brand, theme);
66
- if (preference === 'system')
67
- options.persistence?.writeSystemTheme?.();
68
- else
69
- options.persistence?.writeTheme?.(theme);
70
- subscribeToSystemPreference();
71
- notify();
72
- }
73
- function subscribeToSystemPreference() {
74
- if (!followsSystem || options.systemPreference?.subscribe === undefined)
75
- return;
76
- stopSystemPreference = options.systemPreference.subscribe((nextTheme) => {
77
- if (destroyed || !followsSystem)
78
- return;
79
- theme = nextTheme;
80
- applyTheme(options.target, theme);
81
- applyBrand(options.target, brand, theme);
82
- notify();
83
- });
84
- }
85
- return {
86
- get theme() {
87
- return theme;
88
- },
89
- get preference() {
90
- return preference;
91
- },
92
- get brand() {
93
- return brand;
94
- },
95
- get state() {
96
- return state();
97
- },
98
- setTheme,
99
- setPreference,
100
- toggleTheme() {
101
- const nextTheme = theme === 'dark' ? 'light' : 'dark';
102
- setTheme(nextTheme);
103
- return nextTheme;
104
- },
105
- setBrand(nextBrand) {
106
- brand = readBrand(nextBrand, options.onWarning);
107
- applyBrand(options.target, brand, theme);
108
- options.persistence?.writeBrand?.(brand);
109
- notify();
110
- return brand;
111
- },
112
- subscribe(listener) {
113
- listeners.add(listener);
114
- return () => listeners.delete(listener);
115
- },
116
- destroy() {
117
- if (destroyed)
118
- return;
119
- destroyed = true;
120
- followsSystem = false;
121
- stopSystemPreference?.();
122
- stopSystemPreference = undefined;
123
- listeners.clear();
124
- },
125
- };
126
- }
127
- export function createStorageThemePersistence(storage, keys = {}) {
128
- const themeKey = keys.theme ?? 'vobs-theme';
129
- const brandKey = keys.brand ?? 'vobs-brand-color';
130
- return {
131
- readTheme() {
132
- return storage.getItem(themeKey);
133
- },
134
- writeTheme(theme) {
135
- storage.setItem(themeKey, theme);
136
- },
137
- writeSystemTheme() {
138
- storage.setItem(themeKey, 'system');
139
- },
140
- readBrand() {
141
- const stored = storage.getItem(brandKey);
142
- if (stored === null)
143
- return undefined;
144
- try {
145
- return JSON.parse(stored);
146
- }
147
- catch {
148
- return stored;
149
- }
150
- },
151
- writeBrand(brand) {
152
- storage.setItem(brandKey, JSON.stringify(brand));
153
- },
154
- };
155
- }
156
- export function createMediaThemePreference(query) {
157
- return {
158
- read() {
159
- return query.matches ? 'light' : 'dark';
160
- },
161
- subscribe(listener) {
162
- const handleChange = (event) => {
163
- listener(event.matches ? 'light' : 'dark');
164
- };
165
- query.addEventListener('change', handleChange);
166
- return () => query.removeEventListener('change', handleChange);
167
- },
168
- };
169
- }
170
- export function createThemeState(theme = DEFAULT_THEME, brand = DEFAULT_BRAND_ID) {
171
- assertTheme(theme);
172
- return { theme, brand: resolveBrandColor(brand) };
173
- }
174
- export function createThemeAttributes(state) {
175
- const attributes = {
176
- 'data-theme': state.theme,
177
- 'data-brand': state.brand.id,
178
- ...(isPresetBrand(state.brand) ? {} : { style: serializeBrandStyle(state.brand, state.theme) }),
179
- };
180
- return attributes;
181
- }
182
- export function createThemeBootstrapScript(state) {
183
- const attributes = createThemeAttributes(state);
184
- const variables = isPresetBrand(state.brand) ? {} : brandCssVariables(state.brand, state.theme);
185
- return `(function(){var d=document.documentElement;d.setAttribute("data-theme",${JSON.stringify(attributes['data-theme'])});d.setAttribute("data-brand",${JSON.stringify(attributes['data-brand'])});var v=${JSON.stringify(variables)};for(var k in v){d.style.setProperty(k,v[k])}})()`;
186
- }
187
- function readPersistedTheme(persistence) {
188
- const value = persistence?.readTheme?.();
189
- return value === 'dark' || value === 'light' || value === 'system' ? value : undefined;
190
- }
191
- function resolveTheme(preference, options) {
192
- return preference === 'system'
193
- ? (options.systemPreference?.read() ?? options.initialTheme ?? DEFAULT_THEME)
194
- : preference;
195
- }
196
- function readPersistedBrand(persistence, onWarning) {
197
- const value = persistence?.readBrand?.();
198
- try {
199
- if (typeof value === 'string')
200
- return readBrand(value, onWarning);
201
- if (isBrandColorInput(value))
202
- return readBrand(value, onWarning);
203
- }
204
- catch {
205
- onWarning?.('Ignored invalid persisted brand color');
206
- return undefined;
207
- }
208
- if (value !== undefined && value !== null)
209
- onWarning?.('Ignored invalid persisted brand color');
210
- return undefined;
211
- }
212
- function readBrand(value, onWarning) {
213
- const brand = resolveBrandColor(value);
214
- if (!isPresetBrand(brand)) {
215
- const darkContrast = contrastRatio(brand.color, themeTokenValues.dark['--bg-base-default']);
216
- const lightContrast = contrastRatio(brand.color, themeTokenValues.light['--bg-base-default']);
217
- if (Math.min(darkContrast, lightContrast) < 3) {
218
- onWarning?.(`Custom brand ${brand.color} has low contrast against a theme background`);
219
- }
220
- }
221
- return brand;
222
- }
223
- function applyTheme(target, theme) {
224
- target.setAttribute('data-theme', theme);
225
- }
226
- function applyBrand(target, brand, theme) {
227
- target.setAttribute('data-brand', brand.id);
228
- if (isPresetBrand(brand)) {
229
- for (const name of brandVariableNames)
230
- target.style.removeProperty(name);
231
- return;
232
- }
233
- for (const [name, value] of Object.entries(brandCssVariables(brand, theme))) {
234
- target.style.setProperty(name, value);
235
- }
236
- }
237
- function brandCssVariables(brand, theme = DEFAULT_THEME) {
238
- const tokens = deriveBrandTokens(brand.color);
239
- const readable = theme === 'light' ? deriveBrandTextColor(brand.color) : tokens.background;
240
- const readableHover = theme === 'light' ? deriveBrandTextColor(tokens.hover) : tokens.hover;
241
- return {
242
- '--bg-brand': tokens.background,
243
- '--bg-brand-hover': tokens.hover,
244
- '--bg-brand-disabled': tokens.disabled,
245
- '--bg-brand-popup': tokens.soft,
246
- '--bg-brand-overlay': tokens.soft,
247
- '--text-brand': readable,
248
- '--text-brand-hover': readableHover,
249
- '--icon-brand': readable,
250
- '--icon-brand-hover': readableHover,
251
- '--border-brand': readable,
252
- '--text-onbrand': tokens.onBrand,
253
- '--icon-onbrand': tokens.onBrand,
254
- '--color-primary': tokens.background,
255
- '--color-primary-hover': tokens.hover,
256
- '--color-primary-disabled': tokens.disabled,
257
- '--color-primary-soft': tokens.soft,
258
- '--color-accent': tokens.background,
259
- '--color-on-primary': tokens.onBrand,
260
- };
261
- }
262
- function serializeBrandStyle(brand, theme) {
263
- return Object.entries(brandCssVariables(brand, theme))
264
- .map(([name, value]) => `${name}:${value}`)
265
- .join(';');
266
- }
267
- function isPresetBrand(brand) {
268
- return brandPresets.some((preset) => preset.id === brand.id && preset.color === brand.color);
269
- }
270
- function isBrandColorInput(value) {
271
- return (typeof value === 'object' &&
272
- value !== null &&
273
- 'color' in value &&
274
- typeof value.color === 'string' &&
275
- (!('id' in value) || value.id === undefined || typeof value.id === 'string') &&
276
- (!('label' in value) || value.label === undefined || typeof value.label === 'string'));
277
- }
278
- function assertTheme(theme) {
279
- if (theme !== 'dark' && theme !== 'light')
280
- throw new TypeError(`Invalid theme: ${theme}`);
281
- }
282
- function assertThemePreference(preference) {
283
- if (preference !== 'dark' && preference !== 'light' && preference !== 'system') {
284
- throw new TypeError(`Invalid theme preference: ${preference}`);
285
- }
286
- }
287
- /**
288
- * Reads a design-token value (CSS variable) for the active theme, for third-party adapters (contract ui-adapters.md §3.1).
289
- * Data source: tokens.css variables on html[data-theme] (getComputedStyle reads the latest effective value).
290
- * Returns undefined without a document (SSR/non-browser) or when the variable is undefined — adapters must degrade gracefully.
291
- */
292
- export function resolveUiToken(name) {
293
- const doc = globalThis.document;
294
- if (doc === undefined)
295
- return undefined;
296
- const value = doc.defaultView
297
- ?.getComputedStyle(doc.documentElement)
298
- .getPropertyValue(name)
299
- .trim();
300
- return value === undefined || value === '' ? undefined : value;
301
- }