snail.view 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025-present, Snai <snail_dev@163.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,427 @@
1
+ import { IScope, IVersionManager } from 'snail.core';
2
+
3
+ /**
4
+ * 动画管理器
5
+ */
6
+ interface IAnimationManager {
7
+ /**
8
+ * 【卷起】动画
9
+ * - 水平方向 卷动 时,设置target的宽度
10
+ * - 垂直方向 卷动 时,设置target的高度
11
+ * @param target 要执行动画的目标元素
12
+ * @param direction 卷起方法:水平、垂直
13
+ * @param options 动画效果配置
14
+ * @returns 动画作用域
15
+ */
16
+ roll(target: HTMLElement, direction: "horizontal" | "vertical", options: TransitionEffectOptions): IScope;
17
+ }
18
+ /**
19
+ * 过渡动画效果配置选项
20
+ * - 约束动画过程中样式值:样式名随着动画类型自动适配,如roll动画则为 height
21
+ */
22
+ type TransitionEffectOptions = {
23
+ /**
24
+ * 样式过渡的初始值
25
+ * - 如 roll 动画时,设置过渡动画的初始高度值
26
+ */
27
+ start: string;
28
+ /**
29
+ * 样式过渡到的目标值
30
+ * - 如 roll 动画时,设置过渡动画的最终高度值
31
+ */
32
+ target: string;
33
+ /**
34
+ * 动画时间,单位ms
35
+ * - 默认 200ms
36
+ */
37
+ time?: number;
38
+ /**
39
+ * 动画结束后,是否清理过渡动画的target值
40
+ */
41
+ clear?: boolean;
42
+ };
43
+
44
+ /**
45
+ * 动画管理器
46
+ * 1、对一些常用动画做封装,结合IScope作用域实现生命周期管理
47
+ * 2、【后续支持】配置一些常用动画属性,如动画时长
48
+ * 3、【后续支持】全新作用域,隔离配置
49
+ * 注意事项:
50
+ * 1、不提供全局【观察者】对象;这个涉到不少子scope的销毁,在全局挂着始终不好
51
+ */
52
+
53
+ /**
54
+ * 使用【动画管理器】
55
+ * @returns 全新的【动画管理器】+作用域
56
+ */
57
+ declare function useAnimation(): IAnimationManager & IScope;
58
+
59
+ /**
60
+ * 接口:link标签管理器
61
+ */
62
+ interface ILinkManager {
63
+ /**
64
+ * 注册link文件
65
+ * - 基于配置origin组装link文件全路径;未配置origin则使用location.origin
66
+ * - 自动基于version追加版本到querystring中
67
+ * @param files link文件;可通过theme指定link,不指定则是公共link
68
+ * @returns link句柄,支持切换主题,销毁link等操作
69
+ */
70
+ register(...files: Array<LinkFile | string>): IScope;
71
+ /**
72
+ * 切换主题;自动将非当前主题的link禁用掉(公共link除外)
73
+ * @param code 主题编码字符串
74
+ * @returns 管理器自身
75
+ */
76
+ theme(code: string): ILinkManager;
77
+ }
78
+ /**
79
+ * link配置选项
80
+ */
81
+ type LinkOptions = {
82
+ /**
83
+ * 默认主题;未指定或不支持指定主题时,以此主题为准
84
+ */
85
+ theme: string;
86
+ /**
87
+ * link注入的容器元素
88
+ * - 不传入则采用默认的
89
+ * - 传入则需外部确保存在性,且在元素销毁时执行link的destroy方法同步销毁管理器
90
+ */
91
+ container: HTMLElement;
92
+ /**
93
+ * link文件的所在的服务器
94
+ * - 优先级: scope -> global-> location
95
+ * @see https://developer.mozilla.org/zh-CN/docs/Web/API/URL/URL#base
96
+ */
97
+ origin: string;
98
+ /**
99
+ * link版本管理器
100
+ * - 用于注册link时,格式化link文件url地址
101
+ */
102
+ version: IVersionManager;
103
+ };
104
+ /**
105
+ * link文件
106
+ */
107
+ type LinkFile = {
108
+ /**
109
+ * link文件路径
110
+ */
111
+ file: string;
112
+ /**
113
+ * 匹配的主题code,若为undefined表示为公共link
114
+ */
115
+ theme: string | undefined;
116
+ };
117
+ /**
118
+ * link标签元素对象
119
+ */
120
+ type LinkElement = LinkFile & {
121
+ /**
122
+ * 此元素的引用次数:为0时强制禁用掉
123
+ */
124
+ ref: number;
125
+ /**
126
+ * link元素信息
127
+ */
128
+ element?: HTMLLinkElement;
129
+ };
130
+
131
+ /**
132
+ * link 标签管理
133
+ * 1、csslink标签管理,自动追加版本号,维护生命周期
134
+ */
135
+
136
+ /**
137
+ * 使用【link标签管理器】
138
+ * - 全新作用域,和其他【link标签管理器】实例隔离
139
+ * @param options
140
+ * @returns 新的管理器+作用域
141
+ */
142
+ declare function useLink(options?: Partial<LinkOptions>): ILinkManager & IScope;
143
+ /** 全局的link映射表
144
+ * - 将指定的link文件映射为新的link文件
145
+ * - key为源link文件地址,value为新的link文件地址
146
+ * - 注意:key区分大小写,外部使用时做好控制
147
+ */
148
+ declare const linkMap: Map<string, string>;
149
+ /**
150
+ * 全局【link管理器】
151
+ */
152
+ declare const link: ILinkManager;
153
+ /**
154
+ * Link标签 全局配置
155
+ * @param options 配置选项
156
+ * @returns 全局link管理器
157
+ */
158
+ declare function configLink(options: Partial<LinkOptions>): ILinkManager;
159
+
160
+ /**
161
+ * 接口
162
+ */
163
+ interface IObserver {
164
+ /**
165
+ * 监听指定事件
166
+ * - scope销毁时自动移除监听
167
+ * - 内部使用addEventListener 方法监听事件,销毁时自动执行removeEventListener
168
+ * @param target 监听元素
169
+ * @param name 事件名称
170
+ * @param fn 事件处理方法
171
+ * @returns 作用域,可销毁监听
172
+ */
173
+ onEvent(target: Element | Window, name: string, fn: EventListenerOrEventListenerObject): IScope;
174
+ /**
175
+ * 监听元素尺寸变化
176
+ * - scope销毁时自动移除监听
177
+ * @param el 监听元素
178
+ * @param fn 变化时的回调方法
179
+ * @returns 作用域,可销毁监听
180
+ */
181
+ onSize(el: Element, fn: (size: Readonly<ElementSize>) => void): IScope;
182
+ /**
183
+ * 监听元素客户端位置、大小变化
184
+ * - 位置计算规则:相对window屏幕
185
+ * - scope销毁时自动移除监听
186
+ * @param el 监听元素
187
+ * @param fn 变化时的回调方法
188
+ * @returns 作用域,可销毁监听
189
+ */
190
+ onClient(el: Element, fn: (rect: DOMRectReadOnly) => void): IScope;
191
+ }
192
+ /**
193
+ * 元素尺寸
194
+ */
195
+ type ElementSize = {
196
+ /**
197
+ * 宽度
198
+ */
199
+ width: number;
200
+ /**
201
+ * 高度
202
+ */
203
+ height: number;
204
+ };
205
+
206
+ /**
207
+ * css样式数据结构
208
+ * 1、高度、宽度、边框、内外边距样式
209
+ * 2、文本、布局对齐方式
210
+ */
211
+ /**
212
+ * 样式管理器
213
+ */
214
+ interface IStyleManager {
215
+ /**
216
+ * 构建样式
217
+ * @param options 样式配置
218
+ * @param isFlex 是否是flex布局
219
+ * @returns 计算出来的组件样式信息
220
+ */
221
+ build(options: AllStyle | undefined, isFlex?: boolean): Partial<CSSStyleDeclaration>;
222
+ /**
223
+ * 获取元素样式
224
+ * - 仅限style属性中获取
225
+ * @param target 目标元素
226
+ * @param keys 需要获取样式信息
227
+ * @returns 样式信息
228
+ */
229
+ getStyle(target: HTMLElement, ...keys: Extract<keyof CSSStyleDeclaration, string>[]): Record<string, string>;
230
+ /**
231
+ * 为元素设置样式
232
+ * @param target 目标元素
233
+ * @param options 样式配置
234
+ */
235
+ setStyle(target: HTMLElement, options: AllStyle): void;
236
+ }
237
+ /**
238
+ * 所有的样式属性
239
+ * - 尺寸、对齐、边框、内边距等合集
240
+ * - 对齐方式、、、
241
+ */
242
+ type AllStyle = AlignStyle & SizeStyle & MarginStyle & BorderStyle & PaddingStyle & TransitionStyle;
243
+ /**
244
+ * 组件对齐样式
245
+ * - flex布局时约束 align-items和 justify-content
246
+ * - 非flex布局时约束 text-align和 vertical-align
247
+ */
248
+ type AlignStyle = {
249
+ /**
250
+ * 对齐方式
251
+ * - left: 左对齐
252
+ * - center: 居中对齐
253
+ * - right: 右对齐
254
+ */
255
+ align?: "left" | "center" | "right";
256
+ /**
257
+ * 垂直对齐方式
258
+ * - top: 顶部对齐
259
+ * - middle: 居中对齐
260
+ * - bottom: 底部对齐
261
+ */
262
+ valign?: "top" | "middle" | "bottom";
263
+ };
264
+ /**
265
+ * 尺寸配置选项
266
+ */
267
+ type SizeOptions = {
268
+ /**
269
+ * 弹性尺寸
270
+ * - 在flex布局时生效
271
+ * - 存在时,size属性无效
272
+ */
273
+ flex?: number;
274
+ /**
275
+ * 固定尺寸大小
276
+ * -对应 width 或者 height 属性
277
+ */
278
+ size?: string;
279
+ /**
280
+ * 最小值
281
+ * - 对应 min-width 或者 min-height 属性
282
+ * - size 属性未指定、或者无效时生效;
283
+ */
284
+ min?: string;
285
+ /**
286
+ * 最大值
287
+ * - 对应 max-width 或者 max-height 属性
288
+ * - size 属性未指定、或者无效时生效;
289
+ */
290
+ max?: string;
291
+ };
292
+ /**
293
+ * 尺寸样式:宽度+高度
294
+ */
295
+ type SizeStyle = {
296
+ /**
297
+ * 宽度样式
298
+ */
299
+ width?: SizeOptions;
300
+ /**
301
+ * 高度样式
302
+ */
303
+ height?: SizeOptions;
304
+ };
305
+ /**
306
+ * 组件外边距样式
307
+ * - margin < marginXXX
308
+ */
309
+ type MarginStyle = {
310
+ /**
311
+ * 外边距样式
312
+ */
313
+ margin?: string;
314
+ /**
315
+ * 上外边距样式
316
+ */
317
+ marginTop?: string;
318
+ /**
319
+ * 右外边距样式
320
+ */
321
+ marginRight?: string;
322
+ /**
323
+ * 下外边距样式
324
+ */
325
+ marginBottom?: string;
326
+ /**
327
+ * 左外边距样式
328
+ */
329
+ marginLeft?: string;
330
+ };
331
+ /**
332
+ * 组件边框样式
333
+ * - border < borderXXX
334
+ */
335
+ type BorderStyle = {
336
+ /**
337
+ * 边框圆角
338
+ */
339
+ borderRadius?: string;
340
+ /**
341
+ * 边框样式
342
+ */
343
+ border?: string;
344
+ /**
345
+ * 上边框样式
346
+ */
347
+ borderTop?: string;
348
+ /**
349
+ * 右边框样式
350
+ */
351
+ borderRight?: string;
352
+ /**
353
+ * 下边框样式
354
+ */
355
+ borderBottom?: string;
356
+ /**
357
+ * 左边框样式
358
+ */
359
+ borderLeft?: string;
360
+ };
361
+ /**
362
+ * 内边距样式
363
+ * - 优先级:padding < paddingXXX
364
+ */
365
+ type PaddingStyle = {
366
+ /**
367
+ * 内边距
368
+ */
369
+ padding?: string;
370
+ /**
371
+ * 上内边距
372
+ */
373
+ paddingTop?: string;
374
+ /**
375
+ * 右内边距
376
+ */
377
+ paddingRight?: string;
378
+ /**
379
+ * 下内边距
380
+ */
381
+ paddingBottom?: string;
382
+ /**
383
+ * 左内边距
384
+ */
385
+ paddingLeft?: string;
386
+ };
387
+ /**
388
+ * 过渡效果 样式
389
+ */
390
+ type TransitionStyle = {
391
+ /**
392
+ * 过渡效果
393
+ */
394
+ transition?: string;
395
+ /**
396
+ * 过渡效果属性
397
+ * - 如height、width、left、、、
398
+ */
399
+ transitionProperty?: string;
400
+ /**
401
+ * 过渡效果持续时间
402
+ */
403
+ transitionDuration?: string;
404
+ /**
405
+ * 过渡效果延迟时间
406
+ */
407
+ transitionDelay?: string;
408
+ /**
409
+ * 过渡效果函数
410
+ * - 暂时固定效果,后期支持自定义
411
+ */
412
+ transitionTimingFunction?: ("ease" | "ease-in" | "ease-out" | "ease-in-out" | "linear" | "step-start" | "step-end");
413
+ };
414
+
415
+ /**
416
+ * 样式管理模块
417
+ * 1、基于配置构建css样式数据
418
+ * 2、【后续支持】构建style标签,并生成css样式插入到页面
419
+ */
420
+
421
+ /**
422
+ * 全局的【样式管理器】
423
+ */
424
+ declare const style: IStyleManager;
425
+
426
+ export { configLink, link, linkMap, style, useAnimation, useLink };
427
+ export type { AlignStyle, AllStyle, BorderStyle, ElementSize, IAnimationManager, ILinkManager, IObserver, IStyleManager, LinkElement, LinkFile, LinkOptions, MarginStyle, PaddingStyle, SizeOptions, SizeStyle, TransitionEffectOptions, TransitionStyle };
@@ -0,0 +1,281 @@
1
+ //@ sourceURL=/snail.view.js
2
+ import { throwIfFalse, checkScope, throwIfNullOrUndefined, throwIfTrue, useScope, useScopes, mountScope, extract, hasOwnProperty, tidyString, event, mustString, isArrayNotEmpty, isStringNotEmpty, version } from 'snail.core';
3
+
4
+ function buildAlign(style, align, isFlex) {
5
+ if (isFlex == true) {
6
+ const map = {
7
+ "left": "start",
8
+ "center": "center",
9
+ "right": "end",
10
+ "top": "start",
11
+ "middle": "center",
12
+ "bottom": "end"
13
+ };
14
+ const aV = map[align.align],
15
+ vaV = map[align.valign];
16
+ aV && (style.justifyContent = aV);
17
+ vaV && (style.alignItems = vaV);
18
+ } else {
19
+ align.align && (style.textAlign = align.align);
20
+ align.valign && (style.verticalAlign = align.valign);
21
+ }
22
+ }
23
+ function buildSize(style, size, styleName, isFlex) {
24
+ if (size) {
25
+ var fixed = size.size;
26
+ if (isFlex && size.flex != void 0) {
27
+ fixed = void 0;
28
+ style.flex = String(size.flex);
29
+ }
30
+ if (fixed != void 0) {
31
+ style[styleName] = fixed;
32
+ } else {
33
+ size.min != void 0 && (style[`min-${styleName}`] = size.min);
34
+ size.max != void 0 && (style[`max-${styleName}`] = size.max);
35
+ }
36
+ }
37
+ }
38
+ function buildMargin(style, margin) {
39
+ if (margin) {
40
+ margin.margin && (style.margin = margin.margin);
41
+ margin.marginTop && (style.marginTop = margin.marginTop);
42
+ margin.marginRight && (style.marginRight = margin.marginRight);
43
+ margin.marginBottom && (style.marginBottom = margin.marginBottom);
44
+ margin.marginLeft && (style.marginLeft = margin.marginLeft);
45
+ }
46
+ }
47
+ function buildBorder(style, border) {
48
+ if (border) {
49
+ border.borderRadius && (style.borderRadius = border.borderRadius);
50
+ border.border && (style.border = border.border);
51
+ border.borderTop && (style.borderTop = border.borderTop);
52
+ border.borderRight && (style.borderRight = border.borderRight);
53
+ border.borderBottom && (style.borderBottom = border.borderBottom);
54
+ border.borderLeft && (style.borderLeft = border.borderLeft);
55
+ }
56
+ }
57
+ function buildPadding(style, padding) {
58
+ if (padding) {
59
+ padding.padding && (style.padding = padding.padding);
60
+ padding.paddingTop && (style.paddingTop = padding.paddingTop);
61
+ padding.paddingRight && (style.paddingRight = padding.paddingRight);
62
+ padding.paddingBottom && (style.paddingBottom = padding.paddingBottom);
63
+ padding.paddingLeft && (style.paddingLeft = padding.paddingLeft);
64
+ }
65
+ }
66
+ function buildTransition(style, transition) {
67
+ if (transition) {
68
+ transition.transition && (style.transition = transition.transition);
69
+ transition.transitionProperty && (style.transitionProperty = transition.transitionProperty);
70
+ transition.transitionDuration && (style.transitionDuration = transition.transitionDuration);
71
+ transition.transitionDelay && (style.transitionDelay = transition.transitionDelay);
72
+ transition.transitionTimingFunction && (style.transitionTimingFunction = transition.transitionTimingFunction);
73
+ }
74
+ }
75
+
76
+ function useStyle() {
77
+ function build(options, isFlex) {
78
+ const style2 = Object.create(null);
79
+ if (options) {
80
+ buildAlign(style2, options, isFlex);
81
+ buildSize(style2, options.width, "width", isFlex);
82
+ buildSize(style2, options.height, "height", isFlex);
83
+ buildMargin(style2, options);
84
+ buildBorder(style2, options);
85
+ buildPadding(style2, options);
86
+ buildTransition(style2, options);
87
+ }
88
+ return style2;
89
+ }
90
+ function getStyle(target) {
91
+ throwIfFalse(target instanceof HTMLElement, "getStyle: target must be an HTMLElement.");
92
+ const ret = Object.create(null);
93
+ for (var _len = arguments.length, keys = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
94
+ keys[_key - 1] = arguments[_key];
95
+ }
96
+ keys.forEach(key => ret[key] = target.style[key]);
97
+ return Object.freeze(ret);
98
+ }
99
+ function setStyle(target, options) {
100
+ throwIfFalse(target instanceof HTMLElement, "setStyle: target must be an HTMLElement.");
101
+ const style2 = build(options);
102
+ Object.assign(target.style, style2);
103
+ }
104
+ return Object.freeze({
105
+ build,
106
+ getStyle,
107
+ setStyle
108
+ });
109
+ }
110
+ const style = useStyle();
111
+
112
+ const ERROR_SAMEVALUE = "value cannot be the same";
113
+ function checkTransition(scope, target, options) {
114
+ checkScope(scope, "checkTransition: scope destroyed.");
115
+ throwIfFalse(target instanceof HTMLElement, "checkTransition: target must be an HTMLElement.");
116
+ throwIfNullOrUndefined(options, "checkTransition: options must be an Object.");
117
+ throwIfTrue(options.start == options.target, `checkTransition: options.start and end ${ERROR_SAMEVALUE}. value: ${options.start}`);
118
+ options.time = options.time > 0 ? options.time : 200;
119
+ options.start = options.start || "";
120
+ options.target = options.target || "";
121
+ }
122
+ function startTransition(target, init, styleName, options) {
123
+ const backStyle = style.getStyle(target, ...Object.keys(init), styleName);
124
+ const scope = useScope();
125
+ const setTarget = () => target.style[styleName] = options.target;
126
+ Object.assign(target.style, init, {
127
+ [styleName]: options.start
128
+ });
129
+ setTimeout(setTarget, 1);
130
+ setTimeout(scope.destroy, options.time);
131
+ return scope.onDestroy(() => {
132
+ Object.assign(target.style, backStyle);
133
+ options.clear != true && setTarget();
134
+ });
135
+ }
136
+
137
+ function useAnimation() {
138
+ const scopes = useScopes();
139
+ function roll(target, direction, options) {
140
+ checkTransition(manager, target, options);
141
+ const styleName = direction === "horizontal" ? "width" : "height";
142
+ const scope = startTransition(target, {
143
+ overflow: "hidden !important",
144
+ transition: `${styleName} ${options.time || 200}ms ease !important`
145
+ }, styleName, options);
146
+ return scopes.add(scope);
147
+ }
148
+ const manager = mountScope({
149
+ roll
150
+ });
151
+ manager.onDestroy(scopes.destroy);
152
+ return Object.freeze(manager);
153
+ }
154
+
155
+ const LINK_CONFIG = {
156
+ theme: void 0,
157
+ container: void 0,
158
+ origin: void 0,
159
+ version: void 0
160
+ };
161
+ const EVENT_ChangeTheme = "Snail.ChangeTheme";
162
+ const LINK_CONTAINER_ID = "snail_link_container";
163
+ function checkLinkOptions(options) {
164
+ options = extract(Object.keys(LINK_CONFIG), options);
165
+ hasOwnProperty(options, "theme") && (options.theme = tidyString(options.theme));
166
+ hasOwnProperty(options, "origin") && (options.origin = tidyString(options.origin));
167
+ return options;
168
+ }
169
+ function getLinkDefaultContainer() {
170
+ var container = document.getElementById(LINK_CONTAINER_ID);
171
+ if (!container) {
172
+ container = document.createElement("div");
173
+ container.id = LINK_CONTAINER_ID;
174
+ container.style.display = "none !important";
175
+ container.style.height = "0px";
176
+ container.style.width = "0px";
177
+ document.body.appendChild(container);
178
+ }
179
+ return container;
180
+ }
181
+ function setlinkByTheme(links, code, options) {
182
+ let hasMatchTheme = false;
183
+ links.forEach(link => {
184
+ code && link.theme == code && (hasMatchTheme = true);
185
+ link.element.disabled = link.ref == 0 || link.theme != void 0 && link.theme != code;
186
+ });
187
+ let defaultTheme = hasMatchTheme ? void 0 : options.theme || LINK_CONFIG.theme;
188
+ defaultTheme && links.forEach(link => {
189
+ link.theme == defaultTheme && (link.element.disabled = link.ref == 0);
190
+ });
191
+ }
192
+ function destroylink(links, isDel) {
193
+ links.forEach(link => {
194
+ link.ref = isDel ? 0 : Math.max(0, link.ref - 1);
195
+ link.element.setAttribute("data-ref", link.ref.toString());
196
+ link.element.disabled = link.ref == 0;
197
+ if (isDel == true) {
198
+ link.element.parentNode && link.element.parentNode.removeChild(link.element);
199
+ link.element = void 0;
200
+ }
201
+ });
202
+ links.splice(0);
203
+ }
204
+
205
+ function useLink(options) {
206
+ options = Object.freeze(checkLinkOptions(options));
207
+ var scopeTheme = void 0;
208
+ const scopeLinks = [];
209
+ function register() {
210
+ const funclinks = [];
211
+ for (var _len = arguments.length, files = new Array(_len), _key = 0; _key < _len; _key++) {
212
+ files[_key] = arguments[_key];
213
+ }
214
+ isArrayNotEmpty(files) && files.forEach(file => {
215
+ const link2 = typeof file == "string" ? {
216
+ file,
217
+ theme: void 0
218
+ } : file;
219
+ let href = linkMap.get(link2.file);
220
+ href && console.log(`map to new link file. link: ${link2.file}, new link: ${href}`);
221
+ href = href || link2.file;
222
+ mustString(href, "href");
223
+ let tmpStr = options.origin || LINK_CONFIG.origin;
224
+ isStringNotEmpty(tmpStr) && (href = new URL(href, tmpStr).toString());
225
+ tmpStr = href.toLowerCase();
226
+ let linkEle = scopeLinks.find(s => s.theme == link2.theme && s.file.toLowerCase() == tmpStr);
227
+ if (!linkEle) {
228
+ linkEle = {
229
+ file: href,
230
+ theme: link2.theme,
231
+ ref: 0
232
+ };
233
+ scopeLinks.push(linkEle);
234
+ }
235
+ linkEle.ref += 1;
236
+ funclinks.push(linkEle);
237
+ if (!linkEle.element) {
238
+ linkEle.element = document.createElement("link");
239
+ linkEle.element.href = (options.version || LINK_CONFIG.version || version).formart(linkEle.file);
240
+ linkEle.element.rel = "linksheet";
241
+ linkEle.element.disabled = true;
242
+ link2.theme && linkEle.element.setAttribute("data-theme", link2.theme);
243
+ const container = options.container || LINK_CONFIG.container || getLinkDefaultContainer();
244
+ container.appendChild(linkEle.element);
245
+ }
246
+ linkEle.element.setAttribute("data-ref", linkEle.ref.toString());
247
+ });
248
+ funclinks.length > 0 && setlinkByTheme(funclinks, scopeTheme, options);
249
+ return useScope().onDestroy(() => destroylink(funclinks, false));
250
+ }
251
+ function theme(code) {
252
+ mustString(code, "code");
253
+ if (scopeTheme != code) {
254
+ setlinkByTheme(scopeLinks, scopeTheme = code, options);
255
+ manager === link && event.trigger(EVENT_ChangeTheme, code, true);
256
+ }
257
+ return manager;
258
+ }
259
+ const manager = mountScope({
260
+ register,
261
+ theme
262
+ });
263
+ {
264
+ manager.onDestroy(() => {
265
+ event.off(EVENT_ChangeTheme, theme);
266
+ destroylink(scopeLinks, true);
267
+ });
268
+ event.on(EVENT_ChangeTheme, theme);
269
+ }
270
+ return Object.freeze(manager);
271
+ }
272
+ const linkMap = new Map();
273
+ const link = useLink();
274
+ event.off(EVENT_ChangeTheme, link.theme);
275
+ function configLink(options) {
276
+ options = checkLinkOptions(options);
277
+ Object.assign(LINK_CONFIG, options);
278
+ return link;
279
+ }
280
+
281
+ export { configLink, link, linkMap, style, useAnimation, useLink };
@@ -0,0 +1,10 @@
1
+ // 基础样式 混入集
2
+ // 命名规则: .样式信息(如w代表width)-属性(如fill表示填充)()
3
+ // 混入集中的样式统一采用()结尾,避免直接输出;仅作为【定义混入】,不直接参与less样式编译输出
4
+
5
+ // ***************************************** 👉 盒子模型 *****************************************
6
+ // 高度、宽度填充满,全100%
7
+ .wh-fill() {
8
+ width: 100%;
9
+ height: 100%;
10
+ }
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "snail.view",
3
+ "description": "对视图界面做的一些封装。如样式计算助手方法,常用样式less混入、变量等;dom相关助手类",
4
+ "author": "snail_dev@163.com",
5
+ "license": "MIT",
6
+ "version": "1.0.0",
7
+ "type": "module",
8
+ "main": "dist/snail.view.js",
9
+ "module": "dist/snail.view.js",
10
+ "types": "dist/snail.view.d.ts",
11
+ "private": false,
12
+ "scripts": {
13
+ "build": "rollup -c ./rollup.config.js",
14
+ "types": "tsc -p ./tsconfig.dts.json --declarationDir ./dist/_types"
15
+ },
16
+ "dependencies": {
17
+ "snail.core": ">=2.0.3"
18
+ },
19
+ "devDependencies": {
20
+ "rollup": ">=4.39.0",
21
+ "snail.rollup": ">=1.2.8",
22
+ "snail.rollup-asset": ">=1.2.1",
23
+ "snail.rollup-script": ">=1.2.4"
24
+ }
25
+ }