vanilla-jui 1.3.10 → 1.4.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 (90) hide show
  1. package/dist/index.d.ts +2927 -0
  2. package/dist/index.js +1 -1
  3. package/dist/index.umd.js +1 -1
  4. package/dist/style.css +1 -1
  5. package/package.json +4 -3
  6. package/src/components/accordion.ts +522 -0
  7. package/src/components/drop.ts +497 -0
  8. package/src/components/flow.ts +1579 -0
  9. package/src/components/form.ts +953 -0
  10. package/src/components/{icons.js → icons.ts} +24 -11
  11. package/src/components/menu.ts +615 -0
  12. package/src/components/{modal.js → modal.ts} +560 -237
  13. package/src/components/offcanvas.ts +496 -0
  14. package/src/components/{pagination.js → pagination.ts} +251 -76
  15. package/src/components/parabola.ts +335 -0
  16. package/src/components/{sticky.js → sticky.ts} +123 -98
  17. package/src/components/{swiper.js → swiper.ts} +510 -232
  18. package/src/components/tabs.ts +984 -0
  19. package/src/components/theme.ts +437 -0
  20. package/src/components/toast.ts +371 -0
  21. package/src/components/toc.ts +385 -0
  22. package/src/components/tooltip.ts +179 -0
  23. package/src/components/validator.ts +596 -0
  24. package/src/core/{Component.js → Component.ts} +134 -27
  25. package/src/css/accordion.css +2 -2
  26. package/src/css/animation.css +31 -1
  27. package/src/css/breadcrumb.css +1 -1
  28. package/src/css/button.css +5 -5
  29. package/src/css/card.css +7 -7
  30. package/src/css/color.css +865 -1028
  31. package/src/css/color_p3.css +871 -1036
  32. package/src/css/components.css +1 -0
  33. package/src/css/drop.css +1 -1
  34. package/src/css/flow.css +1 -1
  35. package/src/css/form.css +21 -21
  36. package/src/css/gradient.css +17 -4
  37. package/src/css/icon.css +17 -1
  38. package/src/css/index.css +3 -3
  39. package/src/css/layout.css +1 -1
  40. package/src/css/menu.css +27 -27
  41. package/src/css/modal.css +10 -27
  42. package/src/css/offcanvas.css +2 -2
  43. package/src/css/pagination.css +1 -1
  44. package/src/css/popup.css +2 -2
  45. package/src/css/swiper.css +12 -12
  46. package/src/css/tabs.css +3 -2
  47. package/src/css/tag.css +3 -4
  48. package/src/css/theme-palette.css +6 -6
  49. package/src/css/tip.css +1 -1
  50. package/src/css/toast.css +8 -8
  51. package/src/css/tokens.css +197 -226
  52. package/src/css/toolbar.css +3 -3
  53. package/src/css/tooltip.css +1 -1
  54. package/src/index.ts +37 -0
  55. package/src/locales/{index.js → index.ts} +1 -2
  56. package/src/types.d.ts +1 -0
  57. package/src/utilities/browser.ts +131 -0
  58. package/src/utilities/cache.ts +57 -0
  59. package/src/utilities/core.ts +614 -0
  60. package/src/utilities/dom.ts +468 -0
  61. package/src/utilities/events.ts +106 -0
  62. package/src/utilities/http.ts +35 -0
  63. package/src/utilities/storage.ts +46 -0
  64. package/src/components/accordion.js +0 -373
  65. package/src/components/drop.js +0 -437
  66. package/src/components/flow.js +0 -1133
  67. package/src/components/form.js +0 -585
  68. package/src/components/menu.js +0 -422
  69. package/src/components/offcanvas.js +0 -332
  70. package/src/components/parabola.js +0 -295
  71. package/src/components/tabs.js +0 -746
  72. package/src/components/theme.js +0 -353
  73. package/src/components/toast.js +0 -329
  74. package/src/components/toc.js +0 -226
  75. package/src/components/tooltip.js +0 -86
  76. package/src/components/validator.js +0 -586
  77. package/src/css/toast.min.css +0 -1
  78. package/src/index.js +0 -45
  79. package/src/locales/index.min.js +0 -1
  80. package/src/utilities/browser.js +0 -111
  81. package/src/utilities/cache.js +0 -159
  82. package/src/utilities/core.js +0 -502
  83. package/src/utilities/debug.js +0 -103
  84. package/src/utilities/dom.js +0 -313
  85. package/src/utilities/events.js +0 -69
  86. package/src/utilities/http.js +0 -30
  87. package/src/utilities/legacy-dom.js +0 -179
  88. package/src/utilities/storage.js +0 -46
  89. /package/src/{components/components.js → css/themes/index.css} +0 -0
  90. /package/src/icons/{index.js → index.ts} +0 -0
@@ -1,111 +0,0 @@
1
- /**
2
- * 判断当前环境是否为移动设备。
3
- * @returns {boolean}
4
- */
5
- export function isMobile() {
6
- // 1. 优先使用现代 Client Hints API (如果浏览器支持)
7
- // 这是目前最准确、最符合隐私规范的方式
8
- if (
9
- navigator.userAgentData &&
10
- typeof navigator.userAgentData.mobile === 'boolean'
11
- ) {
12
- return navigator.userAgentData.mobile;
13
- }
14
-
15
- const ua = navigator.userAgent || navigator.vendor || window.opera;
16
-
17
- // 2. 核心 UA 正则匹配 (覆盖主流手机及移动端浏览器)
18
- // 注意:这里包含了 Mobile, iPhone, Android 等,但排除了明确标识为 Tablet 的安卓设备
19
- const mobileUaRegex =
20
- /Android|iPhone|iPad|iPod|Mobile|Windows Phone|webOS|BlackBerry|IEMobile|Opera Mini/i;
21
- const isMobileUa = mobileUaRegex.test(ua);
22
-
23
- // 3. 排除平板设备 (Tablet)
24
- // 安卓平板通常包含 "Android" 但不包含 "Mobile",或者明确包含 "Tablet"
25
- const isTabletUa = /iPad|Android(?!.*Mobile)|Tablet/i.test(ua);
26
-
27
- // 4. 触摸能力检测 (作为兜底和验证)
28
- // 现代 PC 也可能有触摸屏,因此触摸仅作为辅助验证,不能单独作为判定标准
29
- const hasTouchSupport =
30
- 'maxTouchPoints' in navigator
31
- ? navigator.maxTouchPoints > 0
32
- : 'ontouchstart' in window;
33
-
34
- // 5. 屏幕尺寸检测 (CSS 像素)
35
- // 取宽高中较小的一边,防止横屏状态下宽度超过常规手机阈值
36
- const screenWidth = Math.min(window.screen.width, window.screen.height);
37
- const isSmallScreen = screenWidth <= 768;
38
-
39
- // 6. 综合判定逻辑
40
- // 必须是移动端 UA,且不是平板,并且具备小屏幕或触摸特征
41
- // 这样能有效防止桌面浏览器修改 UA 导致的误判,以及 iPad 伪装成 Mac 的问题
42
- if (isMobileUa && !isTabletUa) {
43
- // 对于 iOS 设备,UA 匹配通常足够;对于 Android,需要屏幕尺寸辅助确认
44
- if (
45
- /iPhone|iPod|Windows Phone|webOS|BlackBerry|IEMobile|Opera Mini/i.test(ua)
46
- ) {
47
- return true;
48
- }
49
- // Android 设备需结合屏幕尺寸或触摸能力,避免大屏安卓平板被误判
50
- if (/Android/i.test(ua)) {
51
- return isSmallScreen || hasTouchSupport;
52
- }
53
- }
54
-
55
- // 7. 针对 iOS 13+ iPad 伪装成 Mac 的特殊兜底
56
- // 如果 UA 显示为 Mac,但支持多点触控且屏幕较小,极大概率是 iPad
57
- const isLikelyIPad =
58
- /Macintosh|MacIntel/i.test(ua) && hasTouchSupport && isSmallScreen;
59
-
60
- return isLikelyIPad;
61
- }
62
-
63
- /**
64
- * 复制文本到剪贴板。
65
- *
66
- * 优先使用 Clipboard API,不可用时降级到 textarea + execCommand。
67
- * @param {*} text 需要复制的文本。
68
- * @returns {Promise<boolean>} 是否复制成功。
69
- */
70
- export async function copy(text) {
71
- if (typeof window === 'undefined' || typeof document === 'undefined') {
72
- return Promise.resolve(false);
73
- }
74
-
75
- const value = typeof text === 'string' ? text : String(text);
76
-
77
- if (
78
- navigator.clipboard &&
79
- typeof navigator.clipboard.writeText === 'function'
80
- ) {
81
- return navigator.clipboard
82
- .writeText(value)
83
- .then(() => true)
84
- .catch(() => fallbackCopy(value));
85
- }
86
-
87
- return Promise.resolve(fallbackCopy(value));
88
- }
89
-
90
- function fallbackCopy(text) {
91
- let textarea = null;
92
-
93
- try {
94
- textarea = document.createElement('textarea');
95
- textarea.value = text;
96
- textarea.setAttribute('readonly', '');
97
- textarea.style.position = 'absolute';
98
- textarea.style.left = '-9999px';
99
- textarea.style.opacity = '0';
100
- document.body.appendChild(textarea);
101
- textarea.select();
102
- textarea.setSelectionRange(0, text.length);
103
- return !!document.execCommand('copy');
104
- } catch {
105
- return false;
106
- } finally {
107
- if (textarea && textarea.parentNode) {
108
- textarea.parentNode.removeChild(textarea);
109
- }
110
- }
111
- }
@@ -1,159 +0,0 @@
1
- import { isFunction, randomId } from './core.js';
2
-
3
- const instances = new Map();
4
- const timers = new Map();
5
-
6
- /**
7
- * 创建或获取带缓存的类实例。
8
- *
9
- * 支持按 cacheKey 缓存实例,并可通过 ttl 设置空闲释放时间。
10
- * @template T
11
- * @param {new (...args:any[])=>T} Class 构造函数。
12
- * @param {any[]} [args=[]] 构造参数。
13
- * @param {string} [cacheKey=""] 缓存键;为空时自动生成。
14
- * @param {boolean} [isReset=false] 是否忽略已有缓存并重新创建。
15
- * @param {number|null} [ttl=null] 空闲释放时间,单位毫秒。
16
- * @returns {T} 实例代理。
17
- */
18
- export const singleton = (
19
- Class,
20
- args = [],
21
- cacheKey = '',
22
- isReset = false,
23
- ttl = null
24
- ) => {
25
- if (!isFunction(Class)) {
26
- throw new Error('First argument expects a class/constructor function.');
27
- }
28
- if (!Array.isArray(args)) {
29
- throw new Error('Second argument must be an array of arguments.');
30
- }
31
- if (typeof cacheKey !== 'string') {
32
- throw new Error('Third argument expects a string.');
33
- }
34
- if (typeof isReset !== 'boolean') {
35
- throw new Error('Fourth argument expects a boolean.');
36
- }
37
- if (typeof ttl !== 'number' && ttl !== null) {
38
- throw new Error('Fifth argument expects a number or null.');
39
- }
40
-
41
- const key = cacheKey.trim() === '' ? randomId() : cacheKey;
42
-
43
- if (instances.has(key) && !isReset) {
44
- return instances.get(key).proxy;
45
- }
46
-
47
- const instance = new Class(...args);
48
- const proxy = new Proxy(instance, {
49
- get(target, name, receiver) {
50
- if (ttl) refreshTimer(key, ttl);
51
- return Reflect.get(target, name, receiver);
52
- },
53
- set(target, name, value, receiver) {
54
- return Reflect.set(target, name, value, receiver);
55
- },
56
- });
57
-
58
- instances.set(key, { instance, proxy });
59
- return proxy;
60
- };
61
-
62
- function refreshTimer(key, ttl) {
63
- if (timers.has(key)) {
64
- clearTimeout(timers.get(key));
65
- }
66
-
67
- const timeId = setTimeout(() => {
68
- release(key);
69
- }, ttl);
70
-
71
- timers.set(key, timeId);
72
- }
73
-
74
- /**
75
- * 释放指定缓存实例。
76
- *
77
- * 若实例存在 destroy 方法,会先调用 destroy。
78
- * @param {string} key 缓存键。
79
- * @returns {void}
80
- */
81
- export function release(key) {
82
- if (instances.has(key)) {
83
- const { instance } = instances.get(key);
84
-
85
- if (typeof instance.destroy === 'function') {
86
- try {
87
- instance.destroy();
88
- } catch {
89
- throw new Error(
90
- `release(): destroy() failed on instance with key "${key}".`
91
- );
92
- }
93
- }
94
-
95
- instances.delete(key);
96
- }
97
-
98
- if (timers.has(key)) {
99
- clearTimeout(timers.get(key));
100
- timers.delete(key);
101
- }
102
- }
103
-
104
- /**
105
- * 释放 singleton 管理的全部实例。
106
- * @returns {void}
107
- */
108
- export function destroyAll() {
109
- for (const { instance } of instances.values()) {
110
- if (typeof instance.destroy === 'function') {
111
- try {
112
- instance.destroy();
113
- } catch {}
114
- }
115
- }
116
-
117
- instances.clear();
118
-
119
- for (const timerId of timers.values()) {
120
- clearTimeout(timerId);
121
- }
122
-
123
- timers.clear();
124
- }
125
-
126
- /**
127
- * 简易服务缓存容器。
128
- *
129
- * 用于按 key 缓存工厂创建的服务实例,并提供销毁能力。
130
- */
131
- export const service = {
132
- instances: new Map(),
133
-
134
- get(key, factory) {
135
- if (!this.instances.has(key)) {
136
- this.instances.set(key, factory());
137
- }
138
- return this.instances.get(key);
139
- },
140
-
141
- destroy(key) {
142
- if (this.instances.has(key)) {
143
- const instance = this.instances.get(key);
144
- if (instance.destroy) {
145
- instance.destroy();
146
- }
147
- this.instances.delete(key);
148
- }
149
- },
150
-
151
- destroyAll() {
152
- for (const instance of this.instances.values()) {
153
- if (instance.destroy) {
154
- instance.destroy();
155
- }
156
- }
157
- this.instances.clear();
158
- },
159
- };