@finsweet/webflow-apps-utils 1.0.5 → 1.0.7
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/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.js +1 -0
- package/dist/stores/isPreviewMode.d.ts +1 -0
- package/dist/stores/isPreviewMode.js +2 -0
- package/dist/types/dom.d.ts +1 -0
- package/dist/types/dom.js +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/webflow.d.ts +1 -1
- package/dist/ui/components/input/Input.svelte +18 -22
- package/dist/ui/components/layout/Layout.svelte +4 -2
- package/dist/ui/components/layout/Layout.svelte.d.ts +2 -0
- package/dist/ui/components/text/Text.svelte +4 -2
- package/dist/ui/components/text/types.d.ts +22 -0
- package/dist/ui/icons/ChevronIcon.svelte +1 -1
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/constants.js +11 -0
- package/dist/utils/helpers/dom.d.ts +37 -0
- package/dist/utils/helpers/dom.js +104 -0
- package/dist/utils/helpers/encodeDecodeConfigs.d.ts +13 -0
- package/dist/utils/helpers/encodeDecodeConfigs.js +20 -0
- package/dist/utils/helpers/events.d.ts +19 -0
- package/dist/utils/helpers/events.js +28 -0
- package/dist/utils/helpers/forms.d.ts +22 -0
- package/dist/utils/helpers/forms.js +82 -0
- package/dist/utils/helpers/guards.d.ts +124 -0
- package/dist/utils/helpers/guards.js +107 -0
- package/dist/utils/helpers/index.d.ts +8 -0
- package/dist/utils/helpers/index.js +8 -0
- package/dist/utils/helpers/parseCSV.d.ts +6 -0
- package/dist/utils/helpers/parseCSV.js +29 -0
- package/dist/utils/helpers/string.d.ts +23 -0
- package/dist/utils/helpers/string.js +33 -0
- package/dist/utils/helpers/wait.d.ts +13 -0
- package/dist/utils/helpers/wait.js +27 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/webflow/CopyJSONButton.d.ts +54 -0
- package/dist/utils/webflow/CopyJSONButton.js +117 -0
- package/dist/utils/webflow/DisplayController.d.ts +55 -0
- package/dist/utils/webflow/DisplayController.js +91 -0
- package/dist/utils/webflow/Interaction.d.ts +47 -0
- package/dist/utils/webflow/Interaction.js +52 -0
- package/dist/utils/webflow/index.d.ts +4 -0
- package/dist/utils/webflow/index.js +4 -0
- package/dist/utils/webflow/webflow.d.ts +32 -0
- package/dist/utils/webflow/webflow.js +90 -0
- package/package.json +5 -6
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { FormField } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Defines a typed object entry
|
|
4
|
+
*/
|
|
5
|
+
export type Entry<T> = {
|
|
6
|
+
[K in keyof T]: [K, T[K]];
|
|
7
|
+
}[keyof T];
|
|
8
|
+
/**
|
|
9
|
+
* Converts a `Map<K, V>` type to its equivalent when performing `[...map.entries()]`.
|
|
10
|
+
* @example ```typescript
|
|
11
|
+
* const map: MapType = new Map(['key', 'value']);
|
|
12
|
+
* const entries = [...map.entries()]; // Same type as MapEntries<MapType>
|
|
13
|
+
*
|
|
14
|
+
* typeof entries === MapEntries<MapType>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export type MapEntries<MapToConvert> = MapToConvert extends Map<infer Key, infer Value> ? [Key, Value][] : never;
|
|
18
|
+
/**
|
|
19
|
+
* Check if value is a string
|
|
20
|
+
*/
|
|
21
|
+
export declare const isString: (value: unknown) => value is string;
|
|
22
|
+
/**
|
|
23
|
+
* Check if value is a number
|
|
24
|
+
*/
|
|
25
|
+
export declare const isNumber: (value: unknown) => value is number;
|
|
26
|
+
/**
|
|
27
|
+
* Check if value is a boolean
|
|
28
|
+
*/
|
|
29
|
+
export declare const isBoolean: (value: unknown) => value is boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Check if value undefined
|
|
32
|
+
*/
|
|
33
|
+
export declare const isUndefined: (value: unknown) => value is undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Makes sure a value is not `null` or `undefined`.
|
|
36
|
+
* Useful for type safety when filtering empty elements from an array. Check out the example for more in-depth explanation.
|
|
37
|
+
* @param value The value to type-check.
|
|
38
|
+
* @example ```typescript
|
|
39
|
+
* const items = [1, null, 4, undefined, 8];
|
|
40
|
+
*
|
|
41
|
+
* const filteredItemsError: number[] = items.filter((item) => value !== undefined && value !== null); // Type '(number | null | undefined)[]' is not assignable to type 'number[]'.
|
|
42
|
+
*
|
|
43
|
+
* const filteredItemsSuccess: number[] = items.filter(isNotEmpty); // Success!
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare const isNotEmpty: <T>(value: T | null | undefined) => value is T;
|
|
47
|
+
/**
|
|
48
|
+
* Check if a key is included in a readonly array
|
|
49
|
+
* @param key
|
|
50
|
+
* @param source readonly array of strings
|
|
51
|
+
* @returns True/false
|
|
52
|
+
*/
|
|
53
|
+
export declare const isKeyOf: <T extends string>(key: string | null | undefined, source: readonly T[]) => key is (typeof source)[number];
|
|
54
|
+
/**
|
|
55
|
+
* Gets the keys of an object with inferred typing.
|
|
56
|
+
* @param object
|
|
57
|
+
* @returns
|
|
58
|
+
*/
|
|
59
|
+
export declare const getObjectKeys: <T extends Record<string, unknown>>(object: T) => (keyof T)[];
|
|
60
|
+
/**
|
|
61
|
+
* Gets type safe `Object.entries()`.
|
|
62
|
+
* @param object
|
|
63
|
+
*/
|
|
64
|
+
export declare const getObjectEntries: <T extends Readonly<Record<string, unknown>>>(object: T) => Entry<T>[];
|
|
65
|
+
/**
|
|
66
|
+
* @returns `true` if the target is an instance of Element type.
|
|
67
|
+
* @param target
|
|
68
|
+
*/
|
|
69
|
+
export declare const isElement: (target: unknown) => target is Element;
|
|
70
|
+
/**
|
|
71
|
+
* @returns `true` if the target is an instance of HTMLElement type.
|
|
72
|
+
* @param target
|
|
73
|
+
*/
|
|
74
|
+
export declare const isHTMLElement: (target: unknown) => target is HTMLElement;
|
|
75
|
+
/**
|
|
76
|
+
* @returns `true` if the target is an instance of HTMLVideoElement type.
|
|
77
|
+
* @param target
|
|
78
|
+
*/
|
|
79
|
+
export declare const isHTMLVideoElement: (target: unknown) => target is HTMLVideoElement;
|
|
80
|
+
/**
|
|
81
|
+
* @returns `true` if the target is an instance of HTMLInputElement type.
|
|
82
|
+
* @param target
|
|
83
|
+
*/
|
|
84
|
+
export declare const isHTMLInputElement: (target: unknown) => target is HTMLInputElement;
|
|
85
|
+
/**
|
|
86
|
+
* @returns `true` if the target is an instance of HTMLSelectElement type.
|
|
87
|
+
* @param target
|
|
88
|
+
*/
|
|
89
|
+
export declare const isHTMLSelectElement: (target: unknown) => target is HTMLSelectElement;
|
|
90
|
+
/**
|
|
91
|
+
* @returns `true` if the target is an instance of HTMLTextAreaElement type.
|
|
92
|
+
* @param target
|
|
93
|
+
*/
|
|
94
|
+
export declare const isHTMLTextAreaElement: (target: unknown) => target is HTMLTextAreaElement;
|
|
95
|
+
/**
|
|
96
|
+
* Checks if an element is a form field element
|
|
97
|
+
* @param element
|
|
98
|
+
*/
|
|
99
|
+
export declare const isFormField: (element: Element | EventTarget | null) => element is FormField;
|
|
100
|
+
/**
|
|
101
|
+
* @returns `true` if the target is an instance of HTMLAnchorElement type.
|
|
102
|
+
* @param target
|
|
103
|
+
*/
|
|
104
|
+
export declare const isHTMLAnchorElement: (target: unknown) => target is HTMLAnchorElement;
|
|
105
|
+
/**
|
|
106
|
+
* @returns `true` if the target is an instance of HTMLOptionElement type.
|
|
107
|
+
* @param target
|
|
108
|
+
*/
|
|
109
|
+
export declare const isHTMLOptionElement: (target: unknown) => target is HTMLOptionElement;
|
|
110
|
+
/**
|
|
111
|
+
* @returns `true` if the target is an instance of HTMLImageElement type.
|
|
112
|
+
* @param target
|
|
113
|
+
*/
|
|
114
|
+
export declare const isHTMLImageElement: (target: unknown) => target is HTMLImageElement;
|
|
115
|
+
/**
|
|
116
|
+
* @returns `true` if the target is an instance of HTMLButtonElement type.
|
|
117
|
+
* @param target
|
|
118
|
+
*/
|
|
119
|
+
export declare const isHTMLButtonElement: (target: unknown) => target is HTMLButtonElement;
|
|
120
|
+
/**
|
|
121
|
+
* @returns `true` if the target is an instance of File type.
|
|
122
|
+
* @param target
|
|
123
|
+
*/
|
|
124
|
+
export declare const isFile: (target: unknown) => target is File;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if value is a string
|
|
3
|
+
*/
|
|
4
|
+
export const isString = (value) => typeof value === 'string';
|
|
5
|
+
/**
|
|
6
|
+
* Check if value is a number
|
|
7
|
+
*/
|
|
8
|
+
export const isNumber = (value) => typeof value === 'number';
|
|
9
|
+
/**
|
|
10
|
+
* Check if value is a boolean
|
|
11
|
+
*/
|
|
12
|
+
export const isBoolean = (value) => typeof value === 'boolean';
|
|
13
|
+
/**
|
|
14
|
+
* Check if value undefined
|
|
15
|
+
*/
|
|
16
|
+
export const isUndefined = (value) => value === undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Makes sure a value is not `null` or `undefined`.
|
|
19
|
+
* Useful for type safety when filtering empty elements from an array. Check out the example for more in-depth explanation.
|
|
20
|
+
* @param value The value to type-check.
|
|
21
|
+
* @example ```typescript
|
|
22
|
+
* const items = [1, null, 4, undefined, 8];
|
|
23
|
+
*
|
|
24
|
+
* const filteredItemsError: number[] = items.filter((item) => value !== undefined && value !== null); // Type '(number | null | undefined)[]' is not assignable to type 'number[]'.
|
|
25
|
+
*
|
|
26
|
+
* const filteredItemsSuccess: number[] = items.filter(isNotEmpty); // Success!
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export const isNotEmpty = (value) => value !== undefined && value !== null;
|
|
30
|
+
/**
|
|
31
|
+
* Check if a key is included in a readonly array
|
|
32
|
+
* @param key
|
|
33
|
+
* @param source readonly array of strings
|
|
34
|
+
* @returns True/false
|
|
35
|
+
*/
|
|
36
|
+
export const isKeyOf = (key, source) => !!key && source.includes(key);
|
|
37
|
+
/**
|
|
38
|
+
* Gets the keys of an object with inferred typing.
|
|
39
|
+
* @param object
|
|
40
|
+
* @returns
|
|
41
|
+
*/
|
|
42
|
+
export const getObjectKeys = (object) => Object.keys(object);
|
|
43
|
+
/**
|
|
44
|
+
* Gets type safe `Object.entries()`.
|
|
45
|
+
* @param object
|
|
46
|
+
*/
|
|
47
|
+
export const getObjectEntries = (object) => Object.entries(object);
|
|
48
|
+
/**
|
|
49
|
+
* @returns `true` if the target is an instance of Element type.
|
|
50
|
+
* @param target
|
|
51
|
+
*/
|
|
52
|
+
export const isElement = (target) => target instanceof Element;
|
|
53
|
+
/**
|
|
54
|
+
* @returns `true` if the target is an instance of HTMLElement type.
|
|
55
|
+
* @param target
|
|
56
|
+
*/
|
|
57
|
+
export const isHTMLElement = (target) => target instanceof HTMLElement;
|
|
58
|
+
/**
|
|
59
|
+
* @returns `true` if the target is an instance of HTMLVideoElement type.
|
|
60
|
+
* @param target
|
|
61
|
+
*/
|
|
62
|
+
export const isHTMLVideoElement = (target) => target instanceof HTMLVideoElement;
|
|
63
|
+
/**
|
|
64
|
+
* @returns `true` if the target is an instance of HTMLInputElement type.
|
|
65
|
+
* @param target
|
|
66
|
+
*/
|
|
67
|
+
export const isHTMLInputElement = (target) => target instanceof HTMLInputElement;
|
|
68
|
+
/**
|
|
69
|
+
* @returns `true` if the target is an instance of HTMLSelectElement type.
|
|
70
|
+
* @param target
|
|
71
|
+
*/
|
|
72
|
+
export const isHTMLSelectElement = (target) => target instanceof HTMLSelectElement;
|
|
73
|
+
/**
|
|
74
|
+
* @returns `true` if the target is an instance of HTMLTextAreaElement type.
|
|
75
|
+
* @param target
|
|
76
|
+
*/
|
|
77
|
+
export const isHTMLTextAreaElement = (target) => target instanceof HTMLTextAreaElement;
|
|
78
|
+
/**
|
|
79
|
+
* Checks if an element is a form field element
|
|
80
|
+
* @param element
|
|
81
|
+
*/
|
|
82
|
+
export const isFormField = (element) => isHTMLInputElement(element) || isHTMLSelectElement(element) || isHTMLTextAreaElement(element);
|
|
83
|
+
/**
|
|
84
|
+
* @returns `true` if the target is an instance of HTMLAnchorElement type.
|
|
85
|
+
* @param target
|
|
86
|
+
*/
|
|
87
|
+
export const isHTMLAnchorElement = (target) => target instanceof HTMLAnchorElement;
|
|
88
|
+
/**
|
|
89
|
+
* @returns `true` if the target is an instance of HTMLOptionElement type.
|
|
90
|
+
* @param target
|
|
91
|
+
*/
|
|
92
|
+
export const isHTMLOptionElement = (target) => target instanceof HTMLOptionElement;
|
|
93
|
+
/**
|
|
94
|
+
* @returns `true` if the target is an instance of HTMLImageElement type.
|
|
95
|
+
* @param target
|
|
96
|
+
*/
|
|
97
|
+
export const isHTMLImageElement = (target) => target instanceof HTMLImageElement;
|
|
98
|
+
/**
|
|
99
|
+
* @returns `true` if the target is an instance of HTMLButtonElement type.
|
|
100
|
+
* @param target
|
|
101
|
+
*/
|
|
102
|
+
export const isHTMLButtonElement = (target) => target instanceof HTMLButtonElement;
|
|
103
|
+
/**
|
|
104
|
+
* @returns `true` if the target is an instance of File type.
|
|
105
|
+
* @param target
|
|
106
|
+
*/
|
|
107
|
+
export const isFile = (target) => target instanceof File;
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
export * from './capitalizeFirstLetter';
|
|
2
2
|
export * from './cleanupTooltipMessage';
|
|
3
|
+
export * from './encodeDecodeConfigs';
|
|
3
4
|
export * from './goto';
|
|
5
|
+
export * from './dom';
|
|
6
|
+
export * from './events';
|
|
7
|
+
export * from './forms';
|
|
4
8
|
export * from './getTimeNow';
|
|
5
9
|
export * from './minifyCode';
|
|
6
10
|
export * from './noop';
|
|
11
|
+
export * from './guards';
|
|
7
12
|
export * from './numbers';
|
|
13
|
+
export * from './parseCSV';
|
|
14
|
+
export * from './string';
|
|
8
15
|
export * from './objectsToModuleExports';
|
|
9
16
|
export * from './trimText';
|
|
10
17
|
export * from './toHumanReadableList';
|
|
18
|
+
export * from './wait';
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
export * from './capitalizeFirstLetter';
|
|
2
2
|
export * from './cleanupTooltipMessage';
|
|
3
|
+
export * from './encodeDecodeConfigs';
|
|
3
4
|
export * from './goto';
|
|
5
|
+
export * from './dom';
|
|
6
|
+
export * from './events';
|
|
7
|
+
export * from './forms';
|
|
4
8
|
export * from './getTimeNow';
|
|
5
9
|
export * from './minifyCode';
|
|
6
10
|
export * from './noop';
|
|
11
|
+
export * from './guards';
|
|
7
12
|
export * from './numbers';
|
|
13
|
+
export * from './parseCSV';
|
|
14
|
+
export * from './string';
|
|
8
15
|
export * from './objectsToModuleExports';
|
|
9
16
|
export * from './trimText';
|
|
10
17
|
export * from './toHumanReadableList';
|
|
18
|
+
export * from './wait';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { parse } from 'csv-parse/browser/esm';
|
|
2
|
+
/**
|
|
3
|
+
* Parse CSV data
|
|
4
|
+
* @param csvText CSV data as string
|
|
5
|
+
* @returns Parsed CSV data as an array of objects
|
|
6
|
+
*/
|
|
7
|
+
export const parseCSV = async (csvText) => {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const results = [];
|
|
10
|
+
parse(csvText, {
|
|
11
|
+
columns: true,
|
|
12
|
+
skip_empty_lines: true,
|
|
13
|
+
trim: true
|
|
14
|
+
})
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
.on('readable', function () {
|
|
17
|
+
let record;
|
|
18
|
+
while ((record = this.read()) !== null) {
|
|
19
|
+
results.push(record);
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
.on('error', (error) => {
|
|
23
|
+
reject(error);
|
|
24
|
+
})
|
|
25
|
+
.on('end', () => {
|
|
26
|
+
resolve(results);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes the trailing slash from a URL string.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```
|
|
6
|
+
* This:
|
|
7
|
+
* https://www.finsweet.com/attributes/attractions/capri-island/
|
|
8
|
+
*
|
|
9
|
+
* Becomes:
|
|
10
|
+
* https://www.finsweet.com/attributes/attractions/capri-island
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @param value The value to mutate.
|
|
14
|
+
* @returns A new string without a trailing slash.
|
|
15
|
+
*/
|
|
16
|
+
export declare const removeTrailingSlash: (value: string) => string;
|
|
17
|
+
/**
|
|
18
|
+
* Convert a string of comma separated values to an array of values.
|
|
19
|
+
*
|
|
20
|
+
* @param string Comma separated string.
|
|
21
|
+
* @param filterEmpty Defines if empty values should be filtered out of the returned array. Defaults to `true`.
|
|
22
|
+
*/
|
|
23
|
+
export declare const extractCommaSeparatedValues: (string: string | null | undefined, filterEmpty?: boolean) => string[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes the trailing slash from a URL string.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```
|
|
6
|
+
* This:
|
|
7
|
+
* https://www.finsweet.com/attributes/attractions/capri-island/
|
|
8
|
+
*
|
|
9
|
+
* Becomes:
|
|
10
|
+
* https://www.finsweet.com/attributes/attractions/capri-island
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @param value The value to mutate.
|
|
14
|
+
* @returns A new string without a trailing slash.
|
|
15
|
+
*/
|
|
16
|
+
export const removeTrailingSlash = (value) => value.replace(/\/+$/, '');
|
|
17
|
+
/**
|
|
18
|
+
* Convert a string of comma separated values to an array of values.
|
|
19
|
+
*
|
|
20
|
+
* @param string Comma separated string.
|
|
21
|
+
* @param filterEmpty Defines if empty values should be filtered out of the returned array. Defaults to `true`.
|
|
22
|
+
*/
|
|
23
|
+
export const extractCommaSeparatedValues = (string, filterEmpty = true) => {
|
|
24
|
+
if (!string)
|
|
25
|
+
return [];
|
|
26
|
+
const items = string.split(',').reduce((accumulatedValue, currentValue) => {
|
|
27
|
+
const value = currentValue.trim();
|
|
28
|
+
if (!filterEmpty || value)
|
|
29
|
+
accumulatedValue.push(value);
|
|
30
|
+
return accumulatedValue;
|
|
31
|
+
}, []);
|
|
32
|
+
return items;
|
|
33
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @returns Awaitable promise for waiting X time.
|
|
3
|
+
* @param time
|
|
4
|
+
*/
|
|
5
|
+
export declare const wait: (time: number) => Promise<unknown>;
|
|
6
|
+
/**
|
|
7
|
+
* @returns A promise that resolves once Webflow has fully loaded.
|
|
8
|
+
*/
|
|
9
|
+
export declare const waitWebflowReady: () => Promise<unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* @returns A promise that resolves once the DOM is ready.
|
|
12
|
+
*/
|
|
13
|
+
export declare const waitDOMReady: () => Promise<unknown>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @returns Awaitable promise for waiting X time.
|
|
3
|
+
* @param time
|
|
4
|
+
*/
|
|
5
|
+
export const wait = (time) => new Promise((resolve) => setTimeout(resolve, time));
|
|
6
|
+
/**
|
|
7
|
+
* @returns A promise that resolves once Webflow has fully loaded.
|
|
8
|
+
*/
|
|
9
|
+
export const waitWebflowReady = async () => {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
window.Webflow ||= [];
|
|
12
|
+
window.Webflow.push(resolve);
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* @returns A promise that resolves once the DOM is ready.
|
|
17
|
+
*/
|
|
18
|
+
export const waitDOMReady = async () => {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
if (document.readyState === 'loading') {
|
|
21
|
+
document.addEventListener('DOMContentLoaded', resolve);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
resolve(undefined);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
};
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export declare class CopyJSONButton {
|
|
2
|
+
private readonly element;
|
|
3
|
+
private readonly hiddenTrigger;
|
|
4
|
+
private readonly successCSSClass?;
|
|
5
|
+
private readonly textNode;
|
|
6
|
+
private copyData;
|
|
7
|
+
private successText;
|
|
8
|
+
private errorText;
|
|
9
|
+
private notificationDuration;
|
|
10
|
+
private notificationActive;
|
|
11
|
+
private originalText;
|
|
12
|
+
constructor({ element, copyData, successText, errorText, notificationDuration, successCSSClass }: {
|
|
13
|
+
element: HTMLElement;
|
|
14
|
+
copyData: Record<string, unknown>;
|
|
15
|
+
successText?: string;
|
|
16
|
+
errorText?: string;
|
|
17
|
+
notificationDuration?: number;
|
|
18
|
+
successCSSClass?: string;
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Inits the component.
|
|
22
|
+
*/
|
|
23
|
+
private init;
|
|
24
|
+
/**
|
|
25
|
+
* Creates a hidden button that will serve as the copy trigger.
|
|
26
|
+
* @returns The new button element.
|
|
27
|
+
*/
|
|
28
|
+
private createHiddenTrigger;
|
|
29
|
+
/**
|
|
30
|
+
* Handles click events: triggers a copy command on the element.
|
|
31
|
+
*/
|
|
32
|
+
private handleClick;
|
|
33
|
+
/**
|
|
34
|
+
* Handles the copy event, transfers the JSON data to the user's clipboard.
|
|
35
|
+
* @param e
|
|
36
|
+
*/
|
|
37
|
+
private handleCopy;
|
|
38
|
+
/**
|
|
39
|
+
* Triggers a `success`/`error` notification on the button.
|
|
40
|
+
* If the `successCSSClass` is specific, it adds/removes on the button.
|
|
41
|
+
* @param state `success` or `error`
|
|
42
|
+
*/
|
|
43
|
+
private triggerNotification;
|
|
44
|
+
/**
|
|
45
|
+
* Updates the JSON data to be copied.
|
|
46
|
+
* @param newCopyData
|
|
47
|
+
*/
|
|
48
|
+
updateCopyData(newCopyData: Record<string, unknown>): void;
|
|
49
|
+
/**
|
|
50
|
+
* Updates the button's text content.
|
|
51
|
+
* @param newText The new text to be displayed.
|
|
52
|
+
*/
|
|
53
|
+
updateTextContent(newText: string): void;
|
|
54
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { findTextNode } from '../helpers';
|
|
2
|
+
export class CopyJSONButton {
|
|
3
|
+
element;
|
|
4
|
+
hiddenTrigger;
|
|
5
|
+
successCSSClass;
|
|
6
|
+
textNode;
|
|
7
|
+
copyData;
|
|
8
|
+
successText = 'Copied!';
|
|
9
|
+
errorText = 'Something went wrong';
|
|
10
|
+
notificationDuration = 500;
|
|
11
|
+
notificationActive = false;
|
|
12
|
+
originalText;
|
|
13
|
+
constructor({ element, copyData, successText, errorText, notificationDuration, successCSSClass }) {
|
|
14
|
+
this.element = element;
|
|
15
|
+
this.copyData = copyData;
|
|
16
|
+
if (successText)
|
|
17
|
+
this.successText = successText;
|
|
18
|
+
if (errorText)
|
|
19
|
+
this.errorText = errorText;
|
|
20
|
+
if (notificationDuration)
|
|
21
|
+
this.notificationDuration = notificationDuration;
|
|
22
|
+
if (successCSSClass)
|
|
23
|
+
this.successCSSClass = successCSSClass;
|
|
24
|
+
this.textNode = findTextNode(element) || element;
|
|
25
|
+
this.originalText = this.textNode.textContent || '';
|
|
26
|
+
this.hiddenTrigger = this.createHiddenTrigger();
|
|
27
|
+
this.init();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Inits the component.
|
|
31
|
+
*/
|
|
32
|
+
init() {
|
|
33
|
+
const { element, hiddenTrigger } = this;
|
|
34
|
+
element.addEventListener('click', (e) => this.handleClick(e));
|
|
35
|
+
hiddenTrigger.addEventListener('copy', (e) => this.handleCopy(e));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Creates a hidden button that will serve as the copy trigger.
|
|
39
|
+
* @returns The new button element.
|
|
40
|
+
*/
|
|
41
|
+
createHiddenTrigger() {
|
|
42
|
+
const { element } = this;
|
|
43
|
+
const button = document.createElement('button');
|
|
44
|
+
button.contentEditable = 'true';
|
|
45
|
+
Object.assign(button.style, {
|
|
46
|
+
position: 'absolute',
|
|
47
|
+
clip: 'rect(1px, 1px, 1px, 1px)',
|
|
48
|
+
clipPath: 'inset(0px 0px 99.9% 99.9%)',
|
|
49
|
+
overflow: 'hidden',
|
|
50
|
+
height: '1px',
|
|
51
|
+
width: '1px',
|
|
52
|
+
padding: '0',
|
|
53
|
+
border: '0'
|
|
54
|
+
});
|
|
55
|
+
(element.parentElement || document.body).appendChild(button);
|
|
56
|
+
return button;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Handles click events: triggers a copy command on the element.
|
|
60
|
+
*/
|
|
61
|
+
handleClick(e) {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
this.hiddenTrigger.focus();
|
|
64
|
+
document.execCommand('copy');
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Handles the copy event, transfers the JSON data to the user's clipboard.
|
|
68
|
+
* @param e
|
|
69
|
+
*/
|
|
70
|
+
handleCopy(e) {
|
|
71
|
+
try {
|
|
72
|
+
// Copy starter form JSON to clipboard
|
|
73
|
+
e.clipboardData?.setData('application/json', JSON.stringify(this.copyData).trim());
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
// Trigger notification
|
|
76
|
+
this.triggerNotification('success');
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
this.triggerNotification('error');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Triggers a `success`/`error` notification on the button.
|
|
84
|
+
* If the `successCSSClass` is specific, it adds/removes on the button.
|
|
85
|
+
* @param state `success` or `error`
|
|
86
|
+
*/
|
|
87
|
+
triggerNotification(state) {
|
|
88
|
+
const { notificationActive, notificationDuration, originalText, element, successCSSClass, successText, errorText } = this;
|
|
89
|
+
if (notificationActive)
|
|
90
|
+
return;
|
|
91
|
+
this.notificationActive = true;
|
|
92
|
+
this.textNode.textContent = state === 'success' ? successText : errorText;
|
|
93
|
+
if (successCSSClass)
|
|
94
|
+
element.classList.add(successCSSClass);
|
|
95
|
+
window.setTimeout(() => {
|
|
96
|
+
this.textNode.textContent = originalText;
|
|
97
|
+
if (successCSSClass)
|
|
98
|
+
element.classList.remove(successCSSClass);
|
|
99
|
+
this.notificationActive = false;
|
|
100
|
+
}, notificationDuration);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Updates the JSON data to be copied.
|
|
104
|
+
* @param newCopyData
|
|
105
|
+
*/
|
|
106
|
+
updateCopyData(newCopyData) {
|
|
107
|
+
this.copyData = newCopyData;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Updates the button's text content.
|
|
111
|
+
* @param newText The new text to be displayed.
|
|
112
|
+
*/
|
|
113
|
+
updateTextContent(newText) {
|
|
114
|
+
this.textNode.textContent = newText;
|
|
115
|
+
this.originalText = newText;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { animations, type Easings } from '../animations';
|
|
2
|
+
import { type InteractionParams } from './Interaction';
|
|
3
|
+
export interface DisplayControllerParams {
|
|
4
|
+
/**
|
|
5
|
+
* The main element. Accepts both an HTMLElement or a string selector.
|
|
6
|
+
*/
|
|
7
|
+
element: HTMLElement;
|
|
8
|
+
/**
|
|
9
|
+
* If the display must be controlled through a Webflow interaction.
|
|
10
|
+
*/
|
|
11
|
+
interaction?: InteractionParams;
|
|
12
|
+
/**
|
|
13
|
+
* Defines a custom animation to be used when showing/hiding the element.
|
|
14
|
+
*/
|
|
15
|
+
animation?: keyof typeof animations;
|
|
16
|
+
/**
|
|
17
|
+
* If set to true, the element will be set to `display: none`.
|
|
18
|
+
*/
|
|
19
|
+
startsHidden?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The duration of the animation in milliseconds.
|
|
22
|
+
*/
|
|
23
|
+
animationDuration?: number;
|
|
24
|
+
/**
|
|
25
|
+
* The easing of the animation.
|
|
26
|
+
*/
|
|
27
|
+
animationEasing: Easings[number];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Controls showing/hiding an element.
|
|
31
|
+
* Works with Webflow interactions, built-in fade animations or no animations at all.
|
|
32
|
+
*/
|
|
33
|
+
export declare class DisplayController {
|
|
34
|
+
private readonly interaction;
|
|
35
|
+
private readonly animation;
|
|
36
|
+
private readonly animationEasing;
|
|
37
|
+
private readonly animationDuration;
|
|
38
|
+
private visible;
|
|
39
|
+
readonly element: HTMLElement;
|
|
40
|
+
constructor({ element, interaction, animation, startsHidden, animationEasing, animationDuration }: DisplayControllerParams);
|
|
41
|
+
/**
|
|
42
|
+
* @returns If the element is visible
|
|
43
|
+
*/
|
|
44
|
+
isVisible: () => boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Displays the element
|
|
47
|
+
* @returns An awaitable promise
|
|
48
|
+
*/
|
|
49
|
+
show(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Hides the element
|
|
52
|
+
* @returns An awaitable promise
|
|
53
|
+
*/
|
|
54
|
+
hide(): Promise<void>;
|
|
55
|
+
}
|