cbvirtua 1.0.10 → 1.0.12

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 (62) hide show
  1. package/package.json +1 -1
  2. package/smoothscroll.js +431 -0
  3. package/vant/style/README.md +79 -0
  4. package/vant/style/README.zh-CN.md +79 -0
  5. package/vant/style/animation.less +139 -0
  6. package/vant/style/base.less +10 -0
  7. package/vant/style/clearfix.less +5 -0
  8. package/vant/style/demo/index.vue +110 -0
  9. package/vant/style/ellipsis.less +13 -0
  10. package/vant/style/hairline.less +47 -0
  11. package/vant/style/mixins/clearfix.less +7 -0
  12. package/vant/style/mixins/ellipsis.less +15 -0
  13. package/vant/style/mixins/hairline.less +39 -0
  14. package/vant/style/normalize.less +38 -0
  15. package/vant/style/reset.less +171 -0
  16. package/vant/style/var.less +901 -0
  17. package/vant/tab/README.md +307 -0
  18. package/vant/tab/README.zh-CN.md +342 -0
  19. package/vant/tab/demo/index.vue +193 -0
  20. package/vant/tab/index.js +95 -0
  21. package/vant/tab/index.less +17 -0
  22. package/vant/tab/test/__snapshots__/demo.spec.js.snap +349 -0
  23. package/vant/tab/test/__snapshots__/index.spec.js.snap +352 -0
  24. package/vant/tab/test/__snapshots__/insert.spec.js.snap +63 -0
  25. package/vant/tab/test/demo.spec.js +4 -0
  26. package/vant/tab/test/index.spec.js +435 -0
  27. package/vant/tab/test/insert.spec.js +75 -0
  28. package/vant/tabs/Content.js +79 -0
  29. package/vant/tabs/Title.js +91 -0
  30. package/vant/tabs/index.js +453 -0
  31. package/vant/tabs/index.less +153 -0
  32. package/vant/tabs/utils.ts +53 -0
  33. package/vant/utils/constant.ts +11 -0
  34. package/vant/utils/create/bem.ts +45 -0
  35. package/vant/utils/create/component.ts +86 -0
  36. package/vant/utils/create/i18n.ts +16 -0
  37. package/vant/utils/create/index.ts +14 -0
  38. package/vant/utils/deep-assign.ts +27 -0
  39. package/vant/utils/deep-clone.ts +23 -0
  40. package/vant/utils/dom/event.ts +56 -0
  41. package/vant/utils/dom/node.ts +7 -0
  42. package/vant/utils/dom/raf.ts +40 -0
  43. package/vant/utils/dom/reset-scroll.ts +16 -0
  44. package/vant/utils/dom/scroll.ts +81 -0
  45. package/vant/utils/dom/style.ts +11 -0
  46. package/vant/utils/format/number.ts +52 -0
  47. package/vant/utils/format/string.ts +15 -0
  48. package/vant/utils/format/unit.ts +61 -0
  49. package/vant/utils/functional.ts +73 -0
  50. package/vant/utils/index.ts +79 -0
  51. package/vant/utils/interceptor.ts +27 -0
  52. package/vant/utils/router.ts +54 -0
  53. package/vant/utils/test/bem.spec.js +39 -0
  54. package/vant/utils/test/index.spec.js +152 -0
  55. package/vant/utils/test/interceptor.spec.js +50 -0
  56. package/vant/utils/types.ts +40 -0
  57. package/vant/utils/validate/date.ts +8 -0
  58. package/vant/utils/validate/email.ts +5 -0
  59. package/vant/utils/validate/mobile.ts +6 -0
  60. package/vant/utils/validate/number.ts +12 -0
  61. package/vant/utils/validate/system.ts +13 -0
  62. package/vant/utils/vnodes.ts +33 -0
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Create a basic component with common options
3
+ */
4
+ import '../../locale';
5
+ import { isFunction } from '..';
6
+ import { camelize } from '../format/string';
7
+ import { SlotsMixin } from '../../mixins/slots';
8
+ import Vue, {
9
+ VNode,
10
+ VueConstructor,
11
+ ComponentOptions,
12
+ RenderContext,
13
+ } from 'vue';
14
+ import { DefaultProps, FunctionComponent } from '../types';
15
+
16
+ export interface VantComponentOptions extends ComponentOptions<Vue> {
17
+ functional?: boolean;
18
+ install?: (Vue: VueConstructor) => void;
19
+ }
20
+
21
+ export type TsxBaseProps<Slots> = {
22
+ key: string | number;
23
+ // hack for jsx prop spread
24
+ props: any;
25
+ class: any;
26
+ style: string | object[] | object;
27
+ scopedSlots: Slots;
28
+ };
29
+
30
+ export type TsxComponent<Props, Events, Slots> = (
31
+ props: Partial<Props & Events & TsxBaseProps<Slots>>
32
+ ) => VNode;
33
+
34
+ function install(this: ComponentOptions<Vue>, Vue: VueConstructor) {
35
+ const { name } = this;
36
+ Vue.component(name as string, this);
37
+ Vue.component(camelize(`-${name}`), this);
38
+ }
39
+
40
+ // unify slots & scopedSlots
41
+ export function unifySlots(context: RenderContext) {
42
+ // use data.scopedSlots in lower Vue version
43
+ const scopedSlots = context.scopedSlots || context.data.scopedSlots || {};
44
+ const slots = context.slots();
45
+
46
+ Object.keys(slots).forEach((key) => {
47
+ if (!scopedSlots[key]) {
48
+ scopedSlots[key] = () => slots[key];
49
+ }
50
+ });
51
+
52
+ return scopedSlots;
53
+ }
54
+
55
+ // should be removed after Vue 3
56
+ function transformFunctionComponent(
57
+ pure: FunctionComponent
58
+ ): VantComponentOptions {
59
+ return {
60
+ functional: true,
61
+ props: pure.props,
62
+ model: pure.model,
63
+ render: (h, context): any =>
64
+ pure(h, context.props, unifySlots(context), context),
65
+ };
66
+ }
67
+
68
+ export function createComponent(name: string) {
69
+ return function <Props = DefaultProps, Events = {}, Slots = {}>(
70
+ sfc: VantComponentOptions | FunctionComponent
71
+ ): TsxComponent<Props, Events, Slots> {
72
+ if (isFunction(sfc)) {
73
+ sfc = transformFunctionComponent(sfc);
74
+ }
75
+
76
+ if (!sfc.functional) {
77
+ sfc.mixins = sfc.mixins || [];
78
+ sfc.mixins.push(SlotsMixin);
79
+ }
80
+
81
+ sfc.name = name;
82
+ sfc.install = install;
83
+
84
+ return sfc as TsxComponent<Props, Events, Slots>;
85
+ };
86
+ }
@@ -0,0 +1,16 @@
1
+ import { get, isFunction } from '..';
2
+ import { camelize } from '../format/string';
3
+ import locale from '../../locale';
4
+
5
+ export function createI18N(name: string) {
6
+ const prefix = camelize(name) + '.';
7
+
8
+ return function (path: string, ...args: any[]): string {
9
+ const messages = locale.messages();
10
+ const message = get(messages, prefix + path) || get(messages, path);
11
+
12
+ return isFunction(message) ? message(...args) : message;
13
+ };
14
+ }
15
+
16
+ export type Translate = ReturnType<typeof createI18N>;
@@ -0,0 +1,14 @@
1
+ import { createBEM, BEM } from './bem';
2
+ import { createComponent } from './component';
3
+ import { createI18N, Translate } from './i18n';
4
+
5
+ type CreateNamespaceReturn = [
6
+ ReturnType<typeof createComponent>,
7
+ BEM,
8
+ Translate
9
+ ];
10
+
11
+ export function createNamespace(name: string): CreateNamespaceReturn {
12
+ name = 'van-' + name;
13
+ return [createComponent(name), createBEM(name), createI18N(name)];
14
+ }
@@ -0,0 +1,27 @@
1
+ import { isDef, isObject } from '.';
2
+ import { ObjectIndex } from './types';
3
+
4
+ const { hasOwnProperty } = Object.prototype;
5
+
6
+ function assignKey(to: ObjectIndex, from: ObjectIndex, key: string) {
7
+ const val = from[key];
8
+
9
+ if (!isDef(val)) {
10
+ return;
11
+ }
12
+
13
+ if (!hasOwnProperty.call(to, key) || !isObject(val)) {
14
+ to[key] = val;
15
+ } else {
16
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
17
+ to[key] = deepAssign(Object(to[key]), from[key]);
18
+ }
19
+ }
20
+
21
+ export function deepAssign(to: ObjectIndex, from: ObjectIndex): ObjectIndex {
22
+ Object.keys(from).forEach((key) => {
23
+ assignKey(to, from, key);
24
+ });
25
+
26
+ return to;
27
+ }
@@ -0,0 +1,23 @@
1
+ import { isDef } from './index';
2
+ import { ObjectIndex } from './types';
3
+
4
+ export function deepClone(obj: ObjectIndex): object {
5
+ if (!isDef(obj)) {
6
+ return obj;
7
+ }
8
+
9
+ if (Array.isArray(obj)) {
10
+ return obj.map((item) => deepClone(item));
11
+ }
12
+
13
+ if (typeof obj === 'object') {
14
+ const to = {} as ObjectIndex;
15
+ Object.keys(obj).forEach((key) => {
16
+ to[key] = deepClone(obj[key]);
17
+ });
18
+
19
+ return to;
20
+ }
21
+
22
+ return obj;
23
+ }
@@ -0,0 +1,56 @@
1
+ import { isServer } from '..';
2
+ import { EventHandler } from '../types';
3
+
4
+ // eslint-disable-next-line import/no-mutable-exports
5
+ export let supportsPassive = false;
6
+
7
+ if (!isServer) {
8
+ try {
9
+ const opts = {};
10
+ Object.defineProperty(opts, 'passive', {
11
+ // eslint-disable-next-line getter-return
12
+ get() {
13
+ /* istanbul ignore next */
14
+ supportsPassive = true;
15
+ },
16
+ });
17
+ window.addEventListener('test-passive', null as any, opts);
18
+ // eslint-disable-next-line no-empty
19
+ } catch (e) {}
20
+ }
21
+
22
+ export function on(
23
+ target: EventTarget,
24
+ event: string,
25
+ handler: EventHandler,
26
+ passive = false
27
+ ) {
28
+ if (!isServer) {
29
+ target.addEventListener(
30
+ event,
31
+ handler,
32
+ supportsPassive ? { capture: false, passive } : false
33
+ );
34
+ }
35
+ }
36
+
37
+ export function off(target: EventTarget, event: string, handler: EventHandler) {
38
+ if (!isServer) {
39
+ target.removeEventListener(event, handler);
40
+ }
41
+ }
42
+
43
+ export function stopPropagation(event: Event) {
44
+ event.stopPropagation();
45
+ }
46
+
47
+ export function preventDefault(event: Event, isStopPropagation?: boolean) {
48
+ /* istanbul ignore else */
49
+ if (typeof event.cancelable !== 'boolean' || event.cancelable) {
50
+ event.preventDefault();
51
+ }
52
+
53
+ if (isStopPropagation) {
54
+ stopPropagation(event);
55
+ }
56
+ }
@@ -0,0 +1,7 @@
1
+ export function removeNode(el: Node) {
2
+ const parent = el.parentNode;
3
+
4
+ if (parent) {
5
+ parent.removeChild(el);
6
+ }
7
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * requestAnimationFrame polyfill
3
+ */
4
+
5
+ import { isServer } from '..';
6
+
7
+ let prev = Date.now();
8
+
9
+ /* istanbul ignore next */
10
+ function fallback(fn: FrameRequestCallback): number {
11
+ const curr = Date.now();
12
+ const ms = Math.max(0, 16 - (curr - prev));
13
+ const id = setTimeout(fn, ms);
14
+ prev = curr + ms;
15
+ return id;
16
+ }
17
+
18
+ /* istanbul ignore next */
19
+ const root = (isServer ? global : window) as Window;
20
+
21
+ /* istanbul ignore next */
22
+ const iRaf = root.requestAnimationFrame || fallback;
23
+
24
+ /* istanbul ignore next */
25
+ const iCancel = root.cancelAnimationFrame || root.clearTimeout;
26
+
27
+ export function raf(fn: FrameRequestCallback): number {
28
+ return iRaf.call(root, fn);
29
+ }
30
+
31
+ // double raf for animation
32
+ export function doubleRaf(fn: FrameRequestCallback): void {
33
+ raf(() => {
34
+ raf(fn);
35
+ });
36
+ }
37
+
38
+ export function cancelRaf(id: number) {
39
+ iCancel.call(root, id);
40
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Hack for iOS12 page scroll
3
+ * https://developers.weixin.qq.com/community/develop/doc/00044ae90742f8c82fb78fcae56800
4
+ */
5
+
6
+ import { isIOS as checkIsIOS } from '../validate/system';
7
+ import { getRootScrollTop, setRootScrollTop } from './scroll';
8
+
9
+ const isIOS = checkIsIOS();
10
+
11
+ /* istanbul ignore next */
12
+ export function resetScroll() {
13
+ if (isIOS) {
14
+ setRootScrollTop(getRootScrollTop());
15
+ }
16
+ }
@@ -0,0 +1,81 @@
1
+ type ScrollElement = HTMLElement | Window;
2
+
3
+ function isWindow(val: unknown): val is Window {
4
+ return val === window;
5
+ }
6
+
7
+ // get nearest scroll element
8
+ // https://github.com/vant-ui/vant/issues/3823
9
+ const overflowScrollReg = /scroll|auto|overlay/i;
10
+ export function getScroller(el: HTMLElement, root: ScrollElement = window) {
11
+ let node = el;
12
+
13
+ while (
14
+ node &&
15
+ node.tagName !== 'HTML' &&
16
+ node.tagName !== 'BODY' &&
17
+ node.nodeType === 1 &&
18
+ node !== root
19
+ ) {
20
+ const { overflowY } = window.getComputedStyle(node);
21
+ if (overflowScrollReg.test(overflowY)) {
22
+ return node;
23
+ }
24
+ node = node.parentNode as HTMLElement;
25
+ }
26
+
27
+ return root;
28
+ }
29
+
30
+ export function getScrollTop(el: ScrollElement): number {
31
+ const top = 'scrollTop' in el ? el.scrollTop : el.pageYOffset;
32
+
33
+ // iOS scroll bounce cause minus scrollTop
34
+ return Math.max(top, 0);
35
+ }
36
+
37
+ export function setScrollTop(el: ScrollElement, value: number) {
38
+ if ('scrollTop' in el) {
39
+ el.scrollTop = value;
40
+ } else {
41
+ el.scrollTo(el.scrollX, value);
42
+ }
43
+ }
44
+
45
+ export function getRootScrollTop(): number {
46
+ return (
47
+ window.pageYOffset ||
48
+ document.documentElement.scrollTop ||
49
+ document.body.scrollTop ||
50
+ 0
51
+ );
52
+ }
53
+
54
+ export function setRootScrollTop(value: number) {
55
+ setScrollTop(window, value);
56
+ setScrollTop(document.body, value);
57
+ }
58
+
59
+ // get distance from element top to page top or scroller top
60
+ export function getElementTop(el: ScrollElement, scroller?: HTMLElement) {
61
+ if (isWindow(el)) {
62
+ return 0;
63
+ }
64
+
65
+ const scrollTop = scroller ? getScrollTop(scroller) : getRootScrollTop();
66
+ return el.getBoundingClientRect().top + scrollTop;
67
+ }
68
+
69
+ export function getVisibleHeight(el: ScrollElement) {
70
+ if (isWindow(el)) {
71
+ return el.innerHeight;
72
+ }
73
+ return el.getBoundingClientRect().height;
74
+ }
75
+
76
+ export function getVisibleTop(el: ScrollElement) {
77
+ if (isWindow(el)) {
78
+ return 0;
79
+ }
80
+ return el.getBoundingClientRect().top;
81
+ }
@@ -0,0 +1,11 @@
1
+ export function isHidden(el: HTMLElement) {
2
+ const style = window.getComputedStyle(el);
3
+ const hidden = style.display === 'none';
4
+
5
+ // offsetParent returns null in the following situations:
6
+ // 1. The element or its parent element has the display property set to none.
7
+ // 2. The element has the position property set to fixed
8
+ const parentHidden = el.offsetParent === null && style.position !== 'fixed';
9
+
10
+ return hidden || parentHidden;
11
+ }
@@ -0,0 +1,52 @@
1
+ export function range(num: number, min: number, max: number): number {
2
+ return Math.min(Math.max(num, min), max);
3
+ }
4
+
5
+ function trimExtraChar(value: string, char: string, regExp: RegExp) {
6
+ const index = value.indexOf(char);
7
+ let prefix = '';
8
+
9
+ if (index === -1) {
10
+ return value;
11
+ }
12
+
13
+ if (char === '-' && index !== 0) {
14
+ return value.slice(0, index);
15
+ }
16
+
17
+ if (char === '.' && value.match(/^(\.|-\.)/)) {
18
+ prefix = index ? '-0' : '0';
19
+ }
20
+
21
+ return (
22
+ prefix + value.slice(0, index + 1) + value.slice(index).replace(regExp, '')
23
+ );
24
+ }
25
+
26
+ export function formatNumber(
27
+ value: string,
28
+ allowDot = true,
29
+ allowMinus = true
30
+ ) {
31
+ if (allowDot) {
32
+ value = trimExtraChar(value, '.', /\./g);
33
+ } else {
34
+ value = value.split('.')[0];
35
+ }
36
+
37
+ if (allowMinus) {
38
+ value = trimExtraChar(value, '-', /-/g);
39
+ } else {
40
+ value = value.replace(/-/, '');
41
+ }
42
+
43
+ const regExp = allowDot ? /[^-0-9.]/g : /[^-0-9]/g;
44
+
45
+ return value.replace(regExp, '');
46
+ }
47
+
48
+ // add num and avoid float number
49
+ export function addNumber(num1: number, num2: number) {
50
+ const cardinal = 10 ** 10;
51
+ return Math.round((num1 + num2) * cardinal) / cardinal;
52
+ }
@@ -0,0 +1,15 @@
1
+ const camelizeRE = /-(\w)/g;
2
+
3
+ export function camelize(str: string): string {
4
+ return str.replace(camelizeRE, (_, c) => c.toUpperCase());
5
+ }
6
+
7
+ export function padZero(num: number | string, targetLength = 2): string {
8
+ let str = num + '';
9
+
10
+ while (str.length < targetLength) {
11
+ str = '0' + str;
12
+ }
13
+
14
+ return str;
15
+ }
@@ -0,0 +1,61 @@
1
+ import { isDef, inBrowser } from '..';
2
+ import { isNumeric } from '../validate/number';
3
+
4
+ export function addUnit(value?: string | number): string | undefined {
5
+ if (!isDef(value)) {
6
+ return undefined;
7
+ }
8
+
9
+ value = String(value);
10
+ return isNumeric(value) ? `${value}px` : value;
11
+ }
12
+
13
+ // cache
14
+ let rootFontSize: number;
15
+
16
+ function getRootFontSize() {
17
+ if (!rootFontSize) {
18
+ const doc = document.documentElement;
19
+ const fontSize =
20
+ doc.style.fontSize || window.getComputedStyle(doc).fontSize;
21
+
22
+ rootFontSize = parseFloat(fontSize);
23
+ }
24
+
25
+ return rootFontSize;
26
+ }
27
+
28
+ function convertRem(value: string) {
29
+ value = value.replace(/rem/g, '');
30
+ return +value * getRootFontSize();
31
+ }
32
+
33
+ function convertVw(value: string) {
34
+ value = value.replace(/vw/g, '');
35
+ return (+value * window.innerWidth) / 100;
36
+ }
37
+
38
+ function convertVh(value: string) {
39
+ value = value.replace(/vh/g, '');
40
+ return (+value * window.innerHeight) / 100;
41
+ }
42
+
43
+ export function unitToPx(value: string | number): number {
44
+ if (typeof value === 'number') {
45
+ return value;
46
+ }
47
+
48
+ if (inBrowser) {
49
+ if (value.indexOf('rem') !== -1) {
50
+ return convertRem(value);
51
+ }
52
+ if (value.indexOf('vw') !== -1) {
53
+ return convertVw(value);
54
+ }
55
+ if (value.indexOf('vh') !== -1) {
56
+ return convertVh(value);
57
+ }
58
+ }
59
+
60
+ return parseFloat(value);
61
+ }
@@ -0,0 +1,73 @@
1
+ import Vue, { RenderContext, VNodeData } from 'vue';
2
+ import { ObjectIndex } from './types';
3
+
4
+ type Context = RenderContext & { data: VNodeData & ObjectIndex };
5
+
6
+ type InheritContext = Partial<VNodeData> & ObjectIndex;
7
+
8
+ const inheritKey = [
9
+ 'ref',
10
+ 'key',
11
+ 'style',
12
+ 'class',
13
+ 'attrs',
14
+ 'refInFor',
15
+ 'nativeOn',
16
+ 'directives',
17
+ 'staticClass',
18
+ 'staticStyle',
19
+ ];
20
+
21
+ const mapInheritKey: ObjectIndex = { nativeOn: 'on' };
22
+
23
+ // inherit partial context, map nativeOn to on
24
+ export function inherit(
25
+ context: Context,
26
+ inheritListeners?: boolean
27
+ ): InheritContext {
28
+ const result = inheritKey.reduce((obj, key) => {
29
+ if (context.data[key]) {
30
+ obj[mapInheritKey[key] || key] = context.data[key];
31
+ }
32
+ return obj;
33
+ }, {} as InheritContext);
34
+
35
+ if (inheritListeners) {
36
+ result.on = result.on || {};
37
+ Object.assign(result.on, context.data.on);
38
+ }
39
+
40
+ return result;
41
+ }
42
+
43
+ // emit event
44
+ export function emit(context: Context, eventName: string, ...args: any[]) {
45
+ const listeners = context.listeners[eventName];
46
+ if (listeners) {
47
+ if (Array.isArray(listeners)) {
48
+ listeners.forEach((listener) => {
49
+ listener(...args);
50
+ });
51
+ } else {
52
+ listeners(...args);
53
+ }
54
+ }
55
+ }
56
+
57
+ // mount functional component
58
+ export function mount(Component: any, data?: VNodeData) {
59
+ const instance = new Vue({
60
+ el: document.createElement('div'),
61
+ props: Component.props,
62
+ render(h) {
63
+ return h(Component, {
64
+ props: this.$props,
65
+ ...data,
66
+ });
67
+ },
68
+ });
69
+
70
+ document.body.appendChild(instance.$el);
71
+
72
+ return instance;
73
+ }
@@ -0,0 +1,79 @@
1
+ import Vue from 'vue';
2
+
3
+ export { createNamespace } from './create';
4
+ export { addUnit } from './format/unit';
5
+
6
+ export const inBrowser = typeof window !== 'undefined';
7
+ export const isServer: boolean = Vue.prototype.$isServer;
8
+
9
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
10
+ export function noop() {}
11
+
12
+ export function isDef<T>(val: T): val is NonNullable<T> {
13
+ return val !== undefined && val !== null;
14
+ }
15
+
16
+ export function isFunction(val: unknown): val is Function {
17
+ return typeof val === 'function';
18
+ }
19
+
20
+ export function isObject(val: unknown): val is Record<any, any> {
21
+ return val !== null && typeof val === 'object';
22
+ }
23
+
24
+ export function isPromise<T = any>(val: unknown): val is Promise<T> {
25
+ return isObject(val) && isFunction(val.then) && isFunction(val.catch);
26
+ }
27
+
28
+ export function get(object: any, path: string): any {
29
+ const keys = path.split('.');
30
+ let result = object;
31
+
32
+ keys.forEach((key) => {
33
+ result = isObject(result) ? result[key] ?? '' : '';
34
+ });
35
+
36
+ return result;
37
+ }
38
+
39
+ /**
40
+ * Checks if `value` is an empty object, collection, map, or set.
41
+ *
42
+ * Objects are considered empty if they have no own enumerable string keyed
43
+ * properties.
44
+ *
45
+ * Array-like values such as `arguments` objects, arrays, buffers, strings, or
46
+ * jQuery-like collections are considered empty if they have a `length` of `0`.
47
+ * Similarly, maps and sets are considered empty if they have a `size` of `0`.
48
+ *
49
+ * @function isEmpty
50
+ * @param {*} value The value to check.
51
+ * @returns {boolean} Returns `true` if `value` is empty, else `false`.
52
+ * @example
53
+ *
54
+ * _.isEmpty(null);
55
+ * // => true
56
+ *
57
+ * _.isEmpty(true);
58
+ * // => true
59
+ *
60
+ * _.isEmpty(1);
61
+ * // => true
62
+ *
63
+ * _.isEmpty([1, 2, 3]);
64
+ * // => false
65
+ *
66
+ * _.isEmpty({ 'a': 1 });
67
+ * // => false
68
+ */
69
+ export function isEmpty(value: any): boolean {
70
+ if (value == null) {
71
+ return true;
72
+ }
73
+
74
+ if (typeof value !== 'object') {
75
+ return true;
76
+ }
77
+
78
+ return Object.keys(value).length === 0;
79
+ }
@@ -0,0 +1,27 @@
1
+ import { isPromise, noop } from '.';
2
+
3
+ export function callInterceptor(options: {
4
+ interceptor?: (...args: any[]) => Promise<boolean> | boolean;
5
+ done: () => void;
6
+ args: any[];
7
+ }) {
8
+ const { interceptor, args, done } = options;
9
+
10
+ if (interceptor) {
11
+ const returnVal = interceptor(...args);
12
+
13
+ if (isPromise(returnVal)) {
14
+ returnVal
15
+ .then((value) => {
16
+ if (value) {
17
+ done();
18
+ }
19
+ })
20
+ .catch(noop);
21
+ } else if (returnVal) {
22
+ done();
23
+ }
24
+ } else {
25
+ done();
26
+ }
27
+ }