snail.view 1.0.1 → 1.0.3

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.
@@ -203,6 +203,19 @@ type ElementSize = {
203
203
  height: number;
204
204
  };
205
205
 
206
+ /**
207
+ * 视图观察者
208
+ * 1、观察元素尺寸、位置变化
209
+ * 注意事项:
210
+ * 1、不提供全局【观察者】对象;这个涉到不少子scope的销毁,在全局挂着始终不好
211
+ */
212
+
213
+ /**
214
+ * 使用【观察者】
215
+ * @returns 全新的【观察者】+作用域
216
+ */
217
+ declare function useObserver(): IObserver & IScope;
218
+
206
219
  /**
207
220
  * css样式数据结构
208
221
  * 1、高度、宽度、边框、内外边距样式
@@ -418,15 +431,10 @@ type TransitionStyle = {
418
431
  * 2、【后续支持】构建style标签,并生成css样式插入到页面
419
432
  */
420
433
 
421
- /**
422
- * 使用【样式管理器】
423
- * @returns 全新的【样式管理器】
424
- */
425
- declare function useStyle(): IStyleManager;
426
434
  /**
427
435
  * 全局的【样式管理器】
428
436
  */
429
437
  declare const style: IStyleManager;
430
438
 
431
- export { configLink, link, linkMap, style, useAnimation, useLink, useStyle };
439
+ export { configLink, link, linkMap, style, useAnimation, useLink, useObserver };
432
440
  export type { AlignStyle, AllStyle, BorderStyle, ElementSize, IAnimationManager, ILinkManager, IObserver, IStyleManager, LinkElement, LinkFile, LinkOptions, MarginStyle, PaddingStyle, SizeOptions, SizeStyle, TransitionEffectOptions, TransitionStyle };
@@ -1,5 +1,5 @@
1
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';
2
+ import { throwIfFalse, checkScope, throwIfNullOrUndefined, throwIfTrue, useScope, useScopes, mountScope, extract, hasOwnProperty, tidyString, event, mustString, isArrayNotEmpty, isStringNotEmpty, version, run, mustFunction } from 'snail.core';
3
3
 
4
4
  function buildAlign(style, align, isFlex) {
5
5
  if (isFlex == true) {
@@ -237,7 +237,7 @@ function useLink(options) {
237
237
  if (!linkEle.element) {
238
238
  linkEle.element = document.createElement("link");
239
239
  linkEle.element.href = (options.version || LINK_CONFIG.version || version).formart(linkEle.file);
240
- linkEle.element.rel = "linksheet";
240
+ linkEle.element.rel = "stylesheet";
241
241
  linkEle.element.disabled = true;
242
242
  link2.theme && linkEle.element.setAttribute("data-theme", link2.theme);
243
243
  const container = options.container || LINK_CONFIG.container || getLinkDefaultContainer();
@@ -278,4 +278,66 @@ function configLink(options) {
278
278
  return link;
279
279
  }
280
280
 
281
- export { configLink, link, linkMap, style, useAnimation, useLink, useStyle };
281
+ function useObserver() {
282
+ const scopes = useScopes();
283
+ function onEvent(target, name, fn) {
284
+ checkScope(manager, "onEvent: observer destroyed.");
285
+ throwIfFalse(target instanceof Element || target === window, "onEvent: target must be a Element or Window");
286
+ mustString(name, "onEvent: name");
287
+ mustFunction(fn, "onEvent: fn");
288
+ target.addEventListener(name, fn);
289
+ return scopes.get().onDestroy(() => target.removeEventListener(name, fn));
290
+ }
291
+ function onSize(el, fn) {
292
+ checkScope(manager, "onSize: observer destroyed.");
293
+ throwIfFalse(el instanceof Element, "onSize: el must be a Element.");
294
+ const scope = scopes.get();
295
+ var preSize = void 0;
296
+ function calcSize() {
297
+ if (scope.destroyed == false) {
298
+ const rect = el.getBoundingClientRect();
299
+ const isChange = preSize == void 0 || preSize.width != rect.width || preSize.height != rect.height;
300
+ if (isChange == true) {
301
+ preSize = Object.freeze({
302
+ width: rect.width,
303
+ height: rect.height
304
+ });
305
+ run(fn, preSize);
306
+ }
307
+ }
308
+ }
309
+ const resizeObserver = "ResizeObserver" in window ? new ResizeObserver(calcSize) : void 0;
310
+ const timer = resizeObserver ? resizeObserver.observe(el) : setInterval(calcSize, 100);
311
+ setTimeout(calcSize);
312
+ return scope.onDestroy(() => {
313
+ resizeObserver && resizeObserver.disconnect();
314
+ timer && clearInterval(timer);
315
+ });
316
+ }
317
+ function onClient(el, fn) {
318
+ checkScope(manager, "onClient: observer destroyed.");
319
+ throwIfFalse(el instanceof Element, "onClient: el must be a Element.");
320
+ const scope = scopes.get();
321
+ var preRect = void 0;
322
+ const timer = setInterval(function () {
323
+ if (scope.destroyed == false) {
324
+ const rect = el.getBoundingClientRect();
325
+ const isChange = preRect == void 0 || rect.x != preRect.x || rect.y != preRect.y || rect.width != preRect.width || rect.height != preRect.height;
326
+ if (isChange == true) {
327
+ preRect = DOMRectReadOnly.fromRect(rect);
328
+ run(fn, preRect);
329
+ }
330
+ }
331
+ }, 100);
332
+ return scope.onDestroy(() => clearInterval(timer));
333
+ }
334
+ const manager = mountScope({
335
+ onEvent,
336
+ onSize,
337
+ onClient
338
+ });
339
+ manager.onDestroy(scopes.destroy);
340
+ return Object.freeze(manager);
341
+ }
342
+
343
+ export { configLink, link, linkMap, style, useAnimation, useLink, useObserver };
@@ -0,0 +1,355 @@
1
+ //@ sourceURL=/snail.view.js
2
+ (function (global, factory) {
3
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('snail.core')) :
4
+ typeof define === 'function' && define.amd ? define(['exports', 'snail.core'], factory) :
5
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.SnailView = global.SnailView || {}, global.Snail));
6
+ })(this, (function (exports, snail_core) { 'use strict';
7
+
8
+ function buildAlign(style, align, isFlex) {
9
+ if (isFlex == true) {
10
+ const map = {
11
+ "left": "start",
12
+ "center": "center",
13
+ "right": "end",
14
+ "top": "start",
15
+ "middle": "center",
16
+ "bottom": "end"
17
+ };
18
+ const aV = map[align.align],
19
+ vaV = map[align.valign];
20
+ aV && (style.justifyContent = aV);
21
+ vaV && (style.alignItems = vaV);
22
+ } else {
23
+ align.align && (style.textAlign = align.align);
24
+ align.valign && (style.verticalAlign = align.valign);
25
+ }
26
+ }
27
+ function buildSize(style, size, styleName, isFlex) {
28
+ if (size) {
29
+ var fixed = size.size;
30
+ if (isFlex && size.flex != void 0) {
31
+ fixed = void 0;
32
+ style.flex = String(size.flex);
33
+ }
34
+ if (fixed != void 0) {
35
+ style[styleName] = fixed;
36
+ } else {
37
+ size.min != void 0 && (style[`min-${styleName}`] = size.min);
38
+ size.max != void 0 && (style[`max-${styleName}`] = size.max);
39
+ }
40
+ }
41
+ }
42
+ function buildMargin(style, margin) {
43
+ if (margin) {
44
+ margin.margin && (style.margin = margin.margin);
45
+ margin.marginTop && (style.marginTop = margin.marginTop);
46
+ margin.marginRight && (style.marginRight = margin.marginRight);
47
+ margin.marginBottom && (style.marginBottom = margin.marginBottom);
48
+ margin.marginLeft && (style.marginLeft = margin.marginLeft);
49
+ }
50
+ }
51
+ function buildBorder(style, border) {
52
+ if (border) {
53
+ border.borderRadius && (style.borderRadius = border.borderRadius);
54
+ border.border && (style.border = border.border);
55
+ border.borderTop && (style.borderTop = border.borderTop);
56
+ border.borderRight && (style.borderRight = border.borderRight);
57
+ border.borderBottom && (style.borderBottom = border.borderBottom);
58
+ border.borderLeft && (style.borderLeft = border.borderLeft);
59
+ }
60
+ }
61
+ function buildPadding(style, padding) {
62
+ if (padding) {
63
+ padding.padding && (style.padding = padding.padding);
64
+ padding.paddingTop && (style.paddingTop = padding.paddingTop);
65
+ padding.paddingRight && (style.paddingRight = padding.paddingRight);
66
+ padding.paddingBottom && (style.paddingBottom = padding.paddingBottom);
67
+ padding.paddingLeft && (style.paddingLeft = padding.paddingLeft);
68
+ }
69
+ }
70
+ function buildTransition(style, transition) {
71
+ if (transition) {
72
+ transition.transition && (style.transition = transition.transition);
73
+ transition.transitionProperty && (style.transitionProperty = transition.transitionProperty);
74
+ transition.transitionDuration && (style.transitionDuration = transition.transitionDuration);
75
+ transition.transitionDelay && (style.transitionDelay = transition.transitionDelay);
76
+ transition.transitionTimingFunction && (style.transitionTimingFunction = transition.transitionTimingFunction);
77
+ }
78
+ }
79
+
80
+ function useStyle() {
81
+ function build(options, isFlex) {
82
+ const style2 = Object.create(null);
83
+ if (options) {
84
+ buildAlign(style2, options, isFlex);
85
+ buildSize(style2, options.width, "width", isFlex);
86
+ buildSize(style2, options.height, "height", isFlex);
87
+ buildMargin(style2, options);
88
+ buildBorder(style2, options);
89
+ buildPadding(style2, options);
90
+ buildTransition(style2, options);
91
+ }
92
+ return style2;
93
+ }
94
+ function getStyle(target) {
95
+ snail_core.throwIfFalse(target instanceof HTMLElement, "getStyle: target must be an HTMLElement.");
96
+ const ret = Object.create(null);
97
+ for (var _len = arguments.length, keys = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
98
+ keys[_key - 1] = arguments[_key];
99
+ }
100
+ keys.forEach(key => ret[key] = target.style[key]);
101
+ return Object.freeze(ret);
102
+ }
103
+ function setStyle(target, options) {
104
+ snail_core.throwIfFalse(target instanceof HTMLElement, "setStyle: target must be an HTMLElement.");
105
+ const style2 = build(options);
106
+ Object.assign(target.style, style2);
107
+ }
108
+ return Object.freeze({
109
+ build,
110
+ getStyle,
111
+ setStyle
112
+ });
113
+ }
114
+ const style = useStyle();
115
+
116
+ const ERROR_SAMEVALUE = "value cannot be the same";
117
+ function checkTransition(scope, target, options) {
118
+ snail_core.checkScope(scope, "checkTransition: scope destroyed.");
119
+ snail_core.throwIfFalse(target instanceof HTMLElement, "checkTransition: target must be an HTMLElement.");
120
+ snail_core.throwIfNullOrUndefined(options, "checkTransition: options must be an Object.");
121
+ snail_core.throwIfTrue(options.start == options.target, `checkTransition: options.start and end ${ERROR_SAMEVALUE}. value: ${options.start}`);
122
+ options.time = options.time > 0 ? options.time : 200;
123
+ options.start = options.start || "";
124
+ options.target = options.target || "";
125
+ }
126
+ function startTransition(target, init, styleName, options) {
127
+ const backStyle = style.getStyle(target, ...Object.keys(init), styleName);
128
+ const scope = snail_core.useScope();
129
+ const setTarget = () => target.style[styleName] = options.target;
130
+ Object.assign(target.style, init, {
131
+ [styleName]: options.start
132
+ });
133
+ setTimeout(setTarget, 1);
134
+ setTimeout(scope.destroy, options.time);
135
+ return scope.onDestroy(() => {
136
+ Object.assign(target.style, backStyle);
137
+ options.clear != true && setTarget();
138
+ });
139
+ }
140
+
141
+ function useAnimation() {
142
+ const scopes = snail_core.useScopes();
143
+ function roll(target, direction, options) {
144
+ checkTransition(manager, target, options);
145
+ const styleName = direction === "horizontal" ? "width" : "height";
146
+ const scope = startTransition(target, {
147
+ overflow: "hidden !important",
148
+ transition: `${styleName} ${options.time || 200}ms ease !important`
149
+ }, styleName, options);
150
+ return scopes.add(scope);
151
+ }
152
+ const manager = snail_core.mountScope({
153
+ roll
154
+ });
155
+ manager.onDestroy(scopes.destroy);
156
+ return Object.freeze(manager);
157
+ }
158
+
159
+ const LINK_CONFIG = {
160
+ theme: void 0,
161
+ container: void 0,
162
+ origin: void 0,
163
+ version: void 0
164
+ };
165
+ const EVENT_ChangeTheme = "Snail.ChangeTheme";
166
+ const LINK_CONTAINER_ID = "snail_link_container";
167
+ function checkLinkOptions(options) {
168
+ options = snail_core.extract(Object.keys(LINK_CONFIG), options);
169
+ snail_core.hasOwnProperty(options, "theme") && (options.theme = snail_core.tidyString(options.theme));
170
+ snail_core.hasOwnProperty(options, "origin") && (options.origin = snail_core.tidyString(options.origin));
171
+ return options;
172
+ }
173
+ function getLinkDefaultContainer() {
174
+ var container = document.getElementById(LINK_CONTAINER_ID);
175
+ if (!container) {
176
+ container = document.createElement("div");
177
+ container.id = LINK_CONTAINER_ID;
178
+ container.style.display = "none !important";
179
+ container.style.height = "0px";
180
+ container.style.width = "0px";
181
+ document.body.appendChild(container);
182
+ }
183
+ return container;
184
+ }
185
+ function setlinkByTheme(links, code, options) {
186
+ let hasMatchTheme = false;
187
+ links.forEach(link => {
188
+ code && link.theme == code && (hasMatchTheme = true);
189
+ link.element.disabled = link.ref == 0 || link.theme != void 0 && link.theme != code;
190
+ });
191
+ let defaultTheme = hasMatchTheme ? void 0 : options.theme || LINK_CONFIG.theme;
192
+ defaultTheme && links.forEach(link => {
193
+ link.theme == defaultTheme && (link.element.disabled = link.ref == 0);
194
+ });
195
+ }
196
+ function destroylink(links, isDel) {
197
+ links.forEach(link => {
198
+ link.ref = isDel ? 0 : Math.max(0, link.ref - 1);
199
+ link.element.setAttribute("data-ref", link.ref.toString());
200
+ link.element.disabled = link.ref == 0;
201
+ if (isDel == true) {
202
+ link.element.parentNode && link.element.parentNode.removeChild(link.element);
203
+ link.element = void 0;
204
+ }
205
+ });
206
+ links.splice(0);
207
+ }
208
+
209
+ function useLink(options) {
210
+ options = Object.freeze(checkLinkOptions(options));
211
+ var scopeTheme = void 0;
212
+ const scopeLinks = [];
213
+ function register() {
214
+ const funclinks = [];
215
+ for (var _len = arguments.length, files = new Array(_len), _key = 0; _key < _len; _key++) {
216
+ files[_key] = arguments[_key];
217
+ }
218
+ snail_core.isArrayNotEmpty(files) && files.forEach(file => {
219
+ const link2 = typeof file == "string" ? {
220
+ file,
221
+ theme: void 0
222
+ } : file;
223
+ let href = linkMap.get(link2.file);
224
+ href && console.log(`map to new link file. link: ${link2.file}, new link: ${href}`);
225
+ href = href || link2.file;
226
+ snail_core.mustString(href, "href");
227
+ let tmpStr = options.origin || LINK_CONFIG.origin;
228
+ snail_core.isStringNotEmpty(tmpStr) && (href = new URL(href, tmpStr).toString());
229
+ tmpStr = href.toLowerCase();
230
+ let linkEle = scopeLinks.find(s => s.theme == link2.theme && s.file.toLowerCase() == tmpStr);
231
+ if (!linkEle) {
232
+ linkEle = {
233
+ file: href,
234
+ theme: link2.theme,
235
+ ref: 0
236
+ };
237
+ scopeLinks.push(linkEle);
238
+ }
239
+ linkEle.ref += 1;
240
+ funclinks.push(linkEle);
241
+ if (!linkEle.element) {
242
+ linkEle.element = document.createElement("link");
243
+ linkEle.element.href = (options.version || LINK_CONFIG.version || snail_core.version).formart(linkEle.file);
244
+ linkEle.element.rel = "stylesheet";
245
+ linkEle.element.disabled = true;
246
+ link2.theme && linkEle.element.setAttribute("data-theme", link2.theme);
247
+ const container = options.container || LINK_CONFIG.container || getLinkDefaultContainer();
248
+ container.appendChild(linkEle.element);
249
+ }
250
+ linkEle.element.setAttribute("data-ref", linkEle.ref.toString());
251
+ });
252
+ funclinks.length > 0 && setlinkByTheme(funclinks, scopeTheme, options);
253
+ return snail_core.useScope().onDestroy(() => destroylink(funclinks, false));
254
+ }
255
+ function theme(code) {
256
+ snail_core.mustString(code, "code");
257
+ if (scopeTheme != code) {
258
+ setlinkByTheme(scopeLinks, scopeTheme = code, options);
259
+ manager === link && snail_core.event.trigger(EVENT_ChangeTheme, code, true);
260
+ }
261
+ return manager;
262
+ }
263
+ const manager = snail_core.mountScope({
264
+ register,
265
+ theme
266
+ });
267
+ {
268
+ manager.onDestroy(() => {
269
+ snail_core.event.off(EVENT_ChangeTheme, theme);
270
+ destroylink(scopeLinks, true);
271
+ });
272
+ snail_core.event.on(EVENT_ChangeTheme, theme);
273
+ }
274
+ return Object.freeze(manager);
275
+ }
276
+ const linkMap = new Map();
277
+ const link = useLink();
278
+ snail_core.event.off(EVENT_ChangeTheme, link.theme);
279
+ function configLink(options) {
280
+ options = checkLinkOptions(options);
281
+ Object.assign(LINK_CONFIG, options);
282
+ return link;
283
+ }
284
+
285
+ function useObserver() {
286
+ const scopes = snail_core.useScopes();
287
+ function onEvent(target, name, fn) {
288
+ snail_core.checkScope(manager, "onEvent: observer destroyed.");
289
+ snail_core.throwIfFalse(target instanceof Element || target === window, "onEvent: target must be a Element or Window");
290
+ snail_core.mustString(name, "onEvent: name");
291
+ snail_core.mustFunction(fn, "onEvent: fn");
292
+ target.addEventListener(name, fn);
293
+ return scopes.get().onDestroy(() => target.removeEventListener(name, fn));
294
+ }
295
+ function onSize(el, fn) {
296
+ snail_core.checkScope(manager, "onSize: observer destroyed.");
297
+ snail_core.throwIfFalse(el instanceof Element, "onSize: el must be a Element.");
298
+ const scope = scopes.get();
299
+ var preSize = void 0;
300
+ function calcSize() {
301
+ if (scope.destroyed == false) {
302
+ const rect = el.getBoundingClientRect();
303
+ const isChange = preSize == void 0 || preSize.width != rect.width || preSize.height != rect.height;
304
+ if (isChange == true) {
305
+ preSize = Object.freeze({
306
+ width: rect.width,
307
+ height: rect.height
308
+ });
309
+ snail_core.run(fn, preSize);
310
+ }
311
+ }
312
+ }
313
+ const resizeObserver = "ResizeObserver" in window ? new ResizeObserver(calcSize) : void 0;
314
+ const timer = resizeObserver ? resizeObserver.observe(el) : setInterval(calcSize, 100);
315
+ setTimeout(calcSize);
316
+ return scope.onDestroy(() => {
317
+ resizeObserver && resizeObserver.disconnect();
318
+ timer && clearInterval(timer);
319
+ });
320
+ }
321
+ function onClient(el, fn) {
322
+ snail_core.checkScope(manager, "onClient: observer destroyed.");
323
+ snail_core.throwIfFalse(el instanceof Element, "onClient: el must be a Element.");
324
+ const scope = scopes.get();
325
+ var preRect = void 0;
326
+ const timer = setInterval(function () {
327
+ if (scope.destroyed == false) {
328
+ const rect = el.getBoundingClientRect();
329
+ const isChange = preRect == void 0 || rect.x != preRect.x || rect.y != preRect.y || rect.width != preRect.width || rect.height != preRect.height;
330
+ if (isChange == true) {
331
+ preRect = DOMRectReadOnly.fromRect(rect);
332
+ snail_core.run(fn, preRect);
333
+ }
334
+ }
335
+ }, 100);
336
+ return scope.onDestroy(() => clearInterval(timer));
337
+ }
338
+ const manager = snail_core.mountScope({
339
+ onEvent,
340
+ onSize,
341
+ onClient
342
+ });
343
+ manager.onDestroy(scopes.destroy);
344
+ return Object.freeze(manager);
345
+ }
346
+
347
+ exports.configLink = configLink;
348
+ exports.link = link;
349
+ exports.linkMap = linkMap;
350
+ exports.style = style;
351
+ exports.useAnimation = useAnimation;
352
+ exports.useLink = useLink;
353
+ exports.useObserver = useObserver;
354
+
355
+ }));
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "对视图界面做的一些封装。如样式计算助手方法,常用样式less混入、变量等;dom相关助手类",
4
4
  "author": "snail_dev@163.com",
5
5
  "license": "MIT",
6
- "version": "1.0.1",
6
+ "version": "1.0.3",
7
7
  "type": "module",
8
8
  "main": "dist/snail.view.js",
9
9
  "module": "dist/snail.view.js",