@finsweet/webflow-apps-utils 1.0.6 → 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/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,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
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { animations } from '../animations';
|
|
2
|
+
import { isVisible } from '../helpers';
|
|
3
|
+
import { Interaction } from './Interaction';
|
|
4
|
+
/**
|
|
5
|
+
* Controls showing/hiding an element.
|
|
6
|
+
* Works with Webflow interactions, built-in fade animations or no animations at all.
|
|
7
|
+
*/
|
|
8
|
+
export class DisplayController {
|
|
9
|
+
interaction;
|
|
10
|
+
animation;
|
|
11
|
+
animationEasing;
|
|
12
|
+
animationDuration;
|
|
13
|
+
visible;
|
|
14
|
+
element;
|
|
15
|
+
constructor({ element, interaction, animation, startsHidden, animationEasing, animationDuration }) {
|
|
16
|
+
// Store properties
|
|
17
|
+
this.element = element;
|
|
18
|
+
this.animation = animation;
|
|
19
|
+
this.animationEasing = animationEasing;
|
|
20
|
+
this.animationDuration = animationDuration;
|
|
21
|
+
// Visibility check
|
|
22
|
+
if (startsHidden) {
|
|
23
|
+
this.element.style.display = 'none';
|
|
24
|
+
this.visible = false;
|
|
25
|
+
}
|
|
26
|
+
else
|
|
27
|
+
this.visible = isVisible(this.element);
|
|
28
|
+
if (interaction) {
|
|
29
|
+
const { element, duration } = interaction;
|
|
30
|
+
this.interaction = new Interaction({ element, duration });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* @returns If the element is visible
|
|
35
|
+
*/
|
|
36
|
+
isVisible = () => this.visible;
|
|
37
|
+
/**
|
|
38
|
+
* Displays the element
|
|
39
|
+
* @returns An awaitable promise
|
|
40
|
+
*/
|
|
41
|
+
async show() {
|
|
42
|
+
if (this.visible)
|
|
43
|
+
return;
|
|
44
|
+
const { interaction, animation, element, animationDuration, animationEasing } = this;
|
|
45
|
+
const display = 'block';
|
|
46
|
+
// Interaction
|
|
47
|
+
if (interaction) {
|
|
48
|
+
await interaction.trigger('first');
|
|
49
|
+
}
|
|
50
|
+
// Animation
|
|
51
|
+
else if (animation) {
|
|
52
|
+
animations[animation].prepareIn(element, { display });
|
|
53
|
+
await animations[animation].animateIn(element, {
|
|
54
|
+
display,
|
|
55
|
+
duration: animationDuration,
|
|
56
|
+
easing: animationEasing
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// No interaction or animation
|
|
60
|
+
else {
|
|
61
|
+
element.style.display = display;
|
|
62
|
+
}
|
|
63
|
+
this.visible = true;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Hides the element
|
|
67
|
+
* @returns An awaitable promise
|
|
68
|
+
*/
|
|
69
|
+
async hide() {
|
|
70
|
+
if (!this.visible)
|
|
71
|
+
return;
|
|
72
|
+
const { interaction, animation, element, animationDuration, animationEasing } = this;
|
|
73
|
+
// Interaction
|
|
74
|
+
if (interaction) {
|
|
75
|
+
await interaction.trigger('second');
|
|
76
|
+
}
|
|
77
|
+
// Animation
|
|
78
|
+
else if (animation) {
|
|
79
|
+
await animations[animation].animateOut(element, {
|
|
80
|
+
display: 'none',
|
|
81
|
+
duration: animationDuration,
|
|
82
|
+
easing: animationEasing
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// No interaction or animation
|
|
86
|
+
else {
|
|
87
|
+
element.style.display = 'none';
|
|
88
|
+
}
|
|
89
|
+
this.visible = false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface InteractionParams {
|
|
2
|
+
/**
|
|
3
|
+
* The element that has a Webflow Ix2 Click interaction binded to it.
|
|
4
|
+
*/
|
|
5
|
+
element: HTMLElement | string;
|
|
6
|
+
/**
|
|
7
|
+
* The duration of the interaction.
|
|
8
|
+
* If a single number is passed, it will be used for both first and second interactions.
|
|
9
|
+
* If an object is passed, you can specify the duration for each interaction.
|
|
10
|
+
*/
|
|
11
|
+
duration?: number | Partial<Interaction['duration']>;
|
|
12
|
+
}
|
|
13
|
+
export declare class Interaction {
|
|
14
|
+
private readonly element;
|
|
15
|
+
private active;
|
|
16
|
+
private running;
|
|
17
|
+
private runningPromise?;
|
|
18
|
+
readonly duration: {
|
|
19
|
+
first: number;
|
|
20
|
+
second: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Acts as the controller for a Webflow Interaction.
|
|
24
|
+
* It accepts an element that will be clicked when required (firing a Mouse Click interaction).
|
|
25
|
+
* @param element Element that has the Mouse Click interaction.
|
|
26
|
+
* @param duration Optionally, the duration can be explicitly set so the trigger methods will return an awaitable Promise.
|
|
27
|
+
*/
|
|
28
|
+
constructor({ element, duration }: InteractionParams);
|
|
29
|
+
/**
|
|
30
|
+
* Trigger the interaction
|
|
31
|
+
* @param click Perform first or second click
|
|
32
|
+
* @returns True if the interaction was fired
|
|
33
|
+
*/
|
|
34
|
+
trigger(click?: 'first' | 'second'): Promise<boolean>;
|
|
35
|
+
/**
|
|
36
|
+
* @returns If the interaction is active
|
|
37
|
+
*/
|
|
38
|
+
isActive: () => boolean;
|
|
39
|
+
/**
|
|
40
|
+
* @returns If the interaction is running
|
|
41
|
+
*/
|
|
42
|
+
isRunning: () => boolean;
|
|
43
|
+
/**
|
|
44
|
+
* @returns A promise that fulfills when the current running interaction has finished
|
|
45
|
+
*/
|
|
46
|
+
untilFinished: () => Promise<unknown> | undefined;
|
|
47
|
+
}
|