@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
package/dist/stores/index.d.ts
CHANGED
package/dist/stores/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isPreviewMode: import("svelte/store").Writable<boolean>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type FormField = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/index.js
CHANGED
package/dist/types/webflow.d.ts
CHANGED
|
@@ -41,6 +41,8 @@
|
|
|
41
41
|
containerMode?: boolean;
|
|
42
42
|
/** Size variant for the footer */
|
|
43
43
|
footerSize?: 'normal' | 'large';
|
|
44
|
+
/** Padding for the main content container (CSS value) */
|
|
45
|
+
mainContentPadding?: string;
|
|
44
46
|
/** Array of notification objects for tab status indicators */
|
|
45
47
|
notifications?: Array<{
|
|
46
48
|
/** Tab path this notification applies to */
|
|
@@ -76,6 +78,7 @@
|
|
|
76
78
|
sidebarWidth = '274px',
|
|
77
79
|
containerMode = false,
|
|
78
80
|
footerSize = 'normal',
|
|
81
|
+
mainContentPadding = 'var(--Spacing-24, 24px)',
|
|
79
82
|
notifications = [],
|
|
80
83
|
sidebar,
|
|
81
84
|
main,
|
|
@@ -240,7 +243,7 @@
|
|
|
240
243
|
<!-- Main Content -->
|
|
241
244
|
<div class="main-content" data-area="main">
|
|
242
245
|
{#if main}
|
|
243
|
-
<div class="main-content-container">
|
|
246
|
+
<div class="main-content-container" style="padding: {mainContentPadding}">
|
|
244
247
|
{#if showEditModeMessage}
|
|
245
248
|
<EditModeMessage />
|
|
246
249
|
{/if}
|
|
@@ -462,7 +465,6 @@
|
|
|
462
465
|
flex-direction: column;
|
|
463
466
|
align-items: flex-start;
|
|
464
467
|
align-self: stretch;
|
|
465
|
-
padding: var(--Spacing-24, 24px);
|
|
466
468
|
gap: var(--Spacing-16, 16px);
|
|
467
469
|
}
|
|
468
470
|
|
|
@@ -28,6 +28,8 @@ interface LayoutProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
28
28
|
containerMode?: boolean;
|
|
29
29
|
/** Size variant for the footer */
|
|
30
30
|
footerSize?: 'normal' | 'large';
|
|
31
|
+
/** Padding for the main content container (CSS value) */
|
|
32
|
+
mainContentPadding?: string;
|
|
31
33
|
/** Array of notification objects for tab status indicators */
|
|
32
34
|
notifications?: Array<{
|
|
33
35
|
/** Tab path this notification applies to */
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
// Link behavior
|
|
45
45
|
link = false,
|
|
46
|
+
linkHover = true,
|
|
46
47
|
|
|
47
48
|
// Event handlers
|
|
48
49
|
onclick,
|
|
@@ -211,6 +212,7 @@
|
|
|
211
212
|
const classes = ['labels'];
|
|
212
213
|
if (disabled) classes.push('disabled');
|
|
213
214
|
if (link) classes.push('link');
|
|
215
|
+
if (link && linkHover) classes.push('link-hover');
|
|
214
216
|
if (loading) classes.push('is-busy');
|
|
215
217
|
if (hasPopup && popupConfig.active) classes.push('active');
|
|
216
218
|
classes.push(className);
|
|
@@ -839,8 +841,8 @@
|
|
|
839
841
|
border-radius: 4px;
|
|
840
842
|
}
|
|
841
843
|
|
|
842
|
-
.labels.link:hover:not(.disabled),
|
|
843
|
-
.labels.link.is-busy {
|
|
844
|
+
.labels.link-hover:hover:not(.disabled),
|
|
845
|
+
.labels.link-hover.is-busy {
|
|
844
846
|
background-color: var(--defaultLightHover);
|
|
845
847
|
border-radius: 4px;
|
|
846
848
|
}
|
|
@@ -25,26 +25,48 @@ export interface PopupConfig {
|
|
|
25
25
|
onclick?: () => void;
|
|
26
26
|
}
|
|
27
27
|
export interface TextProps {
|
|
28
|
+
/** The text content to display */
|
|
28
29
|
label?: string;
|
|
30
|
+
/** Additional CSS classes to apply to the component */
|
|
29
31
|
class?: string;
|
|
32
|
+
/** Whether to render the label as HTML instead of plain text */
|
|
30
33
|
raw?: boolean;
|
|
34
|
+
/** Whether to capitalize the first letter of the text */
|
|
31
35
|
capitalize?: boolean;
|
|
36
|
+
/** Whether the component is disabled and non-interactive */
|
|
32
37
|
disabled?: boolean;
|
|
38
|
+
/** HTML title attribute for accessibility and hover tooltip */
|
|
33
39
|
title?: string;
|
|
40
|
+
/** Text wrapping behavior - 'nowrap' prevents wrapping, 'normal' allows wrapping */
|
|
34
41
|
wrap?: 'nowrap' | 'normal';
|
|
42
|
+
/** Horizontal alignment of the text content */
|
|
35
43
|
textAlign?: 'left' | 'center' | 'right';
|
|
44
|
+
/** Font size - use predefined sizes or custom CSS value */
|
|
36
45
|
fontSize?: TEXT_SIZES | string;
|
|
46
|
+
/** Font weight - use predefined weights or custom CSS value */
|
|
37
47
|
fontWeight?: TEXT_WEIGHTS | string;
|
|
48
|
+
/** Text color as any valid CSS color value */
|
|
38
49
|
fontColor?: string;
|
|
50
|
+
/** Fixed height for the component container */
|
|
39
51
|
height?: string;
|
|
52
|
+
/** Width at which text will be truncated with ellipsis */
|
|
40
53
|
ellipsisOnWidth?: string;
|
|
54
|
+
/** Tooltip configuration object with all tooltip-related settings */
|
|
41
55
|
tooltip?: Partial<TooltipProps>;
|
|
42
56
|
/** Specifies whether to show tooltip on the text or icon. Requires icon prop when set to 'icon' */
|
|
43
57
|
tooltipTarget?: 'text' | 'icon';
|
|
58
|
+
/** Configuration for action popup functionality (delete, reset, etc.) */
|
|
44
59
|
popup?: PopupConfig;
|
|
60
|
+
/** Icon component to display alongside the text */
|
|
45
61
|
icon?: Component | null;
|
|
62
|
+
/** Whether to show loading spinner instead of icon */
|
|
46
63
|
loading?: boolean;
|
|
64
|
+
/** Whether to style the text as a clickable link with pointer cursor */
|
|
47
65
|
link?: boolean;
|
|
66
|
+
/** Whether to show hover background effect when link is true (default: true) */
|
|
67
|
+
linkHover?: boolean;
|
|
68
|
+
/** Custom content snippet to render instead of the label text */
|
|
48
69
|
children?: Snippet;
|
|
70
|
+
/** Additional pill/badge content snippet to display */
|
|
49
71
|
pill?: Snippet;
|
|
50
72
|
}
|
|
@@ -59,3 +59,8 @@ export declare const BRAND: {
|
|
|
59
59
|
*/
|
|
60
60
|
export declare const FINSWEET_COMPONENTS_WEBFLOW_APP_ORIGINS: string[];
|
|
61
61
|
export declare const ACCEPTED_WEBFLOW_ELEMENTS_FOR_INSERTION: string[];
|
|
62
|
+
/**
|
|
63
|
+
* List of domains that are considered staging.
|
|
64
|
+
*/
|
|
65
|
+
export declare const STAGING_DOMAINS: string[];
|
|
66
|
+
export declare const FINSWEET_LOGO_URL = "https://cdn.prod.website-files.com/61819aaca0e7ac73f85a2d54/6865d68f194e84da9c6452e5_Components%20White%20Logo.svg";
|
package/dist/utils/constants.js
CHANGED
|
@@ -71,3 +71,14 @@ export const ACCEPTED_WEBFLOW_ELEMENTS_FOR_INSERTION = [
|
|
|
71
71
|
'Container',
|
|
72
72
|
'BlockContainer'
|
|
73
73
|
];
|
|
74
|
+
/**
|
|
75
|
+
* List of domains that are considered staging.
|
|
76
|
+
*/
|
|
77
|
+
export const STAGING_DOMAINS = [
|
|
78
|
+
'webflow.io',
|
|
79
|
+
'webflow-ext.com',
|
|
80
|
+
'localhost',
|
|
81
|
+
'canvas.webflow.com',
|
|
82
|
+
'server.wized.com'
|
|
83
|
+
];
|
|
84
|
+
export const FINSWEET_LOGO_URL = 'https://cdn.prod.website-files.com/61819aaca0e7ac73f85a2d54/6865d68f194e84da9c6452e5_Components%20White%20Logo.svg';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if an element is scrollable
|
|
3
|
+
* @param element
|
|
4
|
+
* @returns True or false
|
|
5
|
+
*/
|
|
6
|
+
export declare const isScrollable: (element: Element) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Finds the first child text node of an element
|
|
9
|
+
* @param element The element to search into.
|
|
10
|
+
*/
|
|
11
|
+
export declare const findTextNode: (element: HTMLElement) => ChildNode | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Function to fetch the Document of a specified URL.
|
|
14
|
+
*
|
|
15
|
+
* @param url - The URL of the page.
|
|
16
|
+
* @param slug - [optional] The slug of the page.
|
|
17
|
+
* @returns
|
|
18
|
+
*/
|
|
19
|
+
export declare const fetchDocument: (url: string, slug?: string) => Promise<Document>;
|
|
20
|
+
/**
|
|
21
|
+
* Function to fetch the Elements of a specified URL.
|
|
22
|
+
*
|
|
23
|
+
* @param url - The URL of the page.
|
|
24
|
+
* @param tagName - The tag name of the elements to fetch. If not provided, returns the whole page as a string.
|
|
25
|
+
* @param asElement - [optional] If true, returns the element as an object.
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
export declare const fetchElements: (url: URL, tagName?: string, asElement?: boolean) => Promise<string[] | HTMLElement[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Fetch elements by attribute
|
|
31
|
+
*/
|
|
32
|
+
export declare const fetchElementsByAttribute: (url: URL, attribute: string) => Promise<string[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Checks if an element is visible
|
|
35
|
+
* @param element
|
|
36
|
+
*/
|
|
37
|
+
export declare const isVisible: (element: HTMLElement) => boolean;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { load } from 'cheerio';
|
|
2
|
+
import { FINSWEET_REVERSE_PROXY_URL } from '../constants';
|
|
3
|
+
import { isHTMLElement } from './guards';
|
|
4
|
+
/**
|
|
5
|
+
* Check if an element is scrollable
|
|
6
|
+
* @param element
|
|
7
|
+
* @returns True or false
|
|
8
|
+
*/
|
|
9
|
+
export const isScrollable = (element) => {
|
|
10
|
+
const { overflow } = getComputedStyle(element);
|
|
11
|
+
return overflow === 'auto' || overflow === 'scroll';
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Finds the first child text node of an element
|
|
15
|
+
* @param element The element to search into.
|
|
16
|
+
*/
|
|
17
|
+
export const findTextNode = (element) => {
|
|
18
|
+
let textNode;
|
|
19
|
+
for (const node of Array.from(element.childNodes)) {
|
|
20
|
+
if (isHTMLElement(node) && node.childNodes.length)
|
|
21
|
+
textNode = findTextNode(node);
|
|
22
|
+
else if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim())
|
|
23
|
+
textNode = node;
|
|
24
|
+
if (textNode)
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
return textNode;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Function to fetch the Document of a specified URL.
|
|
31
|
+
*
|
|
32
|
+
* @param url - The URL of the page.
|
|
33
|
+
* @param slug - [optional] The slug of the page.
|
|
34
|
+
* @returns
|
|
35
|
+
*/
|
|
36
|
+
export const fetchDocument = async (url, slug) => {
|
|
37
|
+
const pageUrl = new URL(url);
|
|
38
|
+
if (slug)
|
|
39
|
+
pageUrl.pathname = slug;
|
|
40
|
+
const target = `${FINSWEET_REVERSE_PROXY_URL}${pageUrl}`;
|
|
41
|
+
const response = await fetch(target);
|
|
42
|
+
const pageContent = await response.text();
|
|
43
|
+
const parser = new DOMParser();
|
|
44
|
+
return parser.parseFromString(pageContent, 'text/html');
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Function to fetch the Elements of a specified URL.
|
|
48
|
+
*
|
|
49
|
+
* @param url - The URL of the page.
|
|
50
|
+
* @param tagName - The tag name of the elements to fetch. If not provided, returns the whole page as a string.
|
|
51
|
+
* @param asElement - [optional] If true, returns the element as an object.
|
|
52
|
+
* @returns
|
|
53
|
+
*/
|
|
54
|
+
export const fetchElements = async (url, tagName, asElement) => {
|
|
55
|
+
const target = `${FINSWEET_REVERSE_PROXY_URL}${url.href}`;
|
|
56
|
+
const response = await fetch(target);
|
|
57
|
+
const html = await response.text();
|
|
58
|
+
const $ = load(html);
|
|
59
|
+
// return the whole page if no tag name is provided
|
|
60
|
+
if (!tagName)
|
|
61
|
+
return [$.html()];
|
|
62
|
+
// crawl page and get elements
|
|
63
|
+
if (asElement && tagName) {
|
|
64
|
+
const elements = $(tagName)
|
|
65
|
+
.map((_, el) => {
|
|
66
|
+
const outerHTML = $.html(el); // Get the outer HTML of each element
|
|
67
|
+
const parser = new DOMParser();
|
|
68
|
+
const parsedDoc = parser.parseFromString(outerHTML, 'text/html');
|
|
69
|
+
const element = parsedDoc.querySelector(tagName);
|
|
70
|
+
return element;
|
|
71
|
+
})
|
|
72
|
+
.get();
|
|
73
|
+
return elements;
|
|
74
|
+
}
|
|
75
|
+
// crawl page and get elements as strings
|
|
76
|
+
const elements = $(tagName)
|
|
77
|
+
.map((_, el) => {
|
|
78
|
+
const outerHTML = $.html(el);
|
|
79
|
+
return outerHTML;
|
|
80
|
+
})
|
|
81
|
+
.get();
|
|
82
|
+
return elements;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Fetch elements by attribute
|
|
86
|
+
*/
|
|
87
|
+
export const fetchElementsByAttribute = async (url, attribute) => {
|
|
88
|
+
const target = `${FINSWEET_REVERSE_PROXY_URL}${url.href}`;
|
|
89
|
+
const response = await fetch(target);
|
|
90
|
+
const html = await response.text();
|
|
91
|
+
const $ = load(html);
|
|
92
|
+
const elements = $(attribute)
|
|
93
|
+
.map((_, el) => {
|
|
94
|
+
const outerHTML = $.html(el);
|
|
95
|
+
return outerHTML;
|
|
96
|
+
})
|
|
97
|
+
.get();
|
|
98
|
+
return elements;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Checks if an element is visible
|
|
102
|
+
* @param element
|
|
103
|
+
*/
|
|
104
|
+
export const isVisible = (element) => !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a configuration object to a base64-encoded string.
|
|
3
|
+
* @param {object} configs
|
|
4
|
+
* @returns
|
|
5
|
+
*/
|
|
6
|
+
export declare const encodeComponentConfigs: (configs: object) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Decodes a base64-encoded configuration string to a configuration object.
|
|
9
|
+
* @param configsString
|
|
10
|
+
* @param component
|
|
11
|
+
* @returns
|
|
12
|
+
*/
|
|
13
|
+
export declare const decodeComponentConfigs: <T>(configsString: string) => T;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a configuration object to a base64-encoded string.
|
|
3
|
+
* @param {object} configs
|
|
4
|
+
* @returns
|
|
5
|
+
*/
|
|
6
|
+
export const encodeComponentConfigs = (configs) => {
|
|
7
|
+
const previewModeConfigs = btoa(JSON.stringify(configs));
|
|
8
|
+
return previewModeConfigs;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Decodes a base64-encoded configuration string to a configuration object.
|
|
12
|
+
* @param configsString
|
|
13
|
+
* @param component
|
|
14
|
+
* @returns
|
|
15
|
+
*/
|
|
16
|
+
export const decodeComponentConfigs = (configsString) => {
|
|
17
|
+
const jsonString = atob(configsString);
|
|
18
|
+
const configParsed = JSON.parse(jsonString);
|
|
19
|
+
return configParsed;
|
|
20
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adds an event listener to an element.
|
|
3
|
+
* @returns A callback to remove the event listener from the element.
|
|
4
|
+
*
|
|
5
|
+
* @param target
|
|
6
|
+
* @param type
|
|
7
|
+
* @param listener
|
|
8
|
+
* @param options
|
|
9
|
+
*/
|
|
10
|
+
export declare function addListener<TargetInterface extends EventTarget, Type extends TargetInterface extends Window ? keyof WindowEventMap | string : TargetInterface extends Document ? keyof DocumentEventMap | string : TargetInterface extends HTMLElement ? keyof HTMLElementEventMap | string : keyof ElementEventMap | string, Listener extends Type extends keyof WindowEventMap ? (this: Document, ev: WindowEventMap[Type]) => unknown : Type extends keyof DocumentEventMap ? (this: Document, ev: DocumentEventMap[Type]) => unknown : Type extends keyof HTMLElementEventMap ? (this: HTMLElement, ev: HTMLElementEventMap[Type]) => unknown : Type extends keyof ElementEventMap ? (this: Element, ev: ElementEventMap[Type]) => unknown : EventListenerOrEventListenerObject>(target: TargetInterface | null | undefined, type: Type, listener: Listener, options?: boolean | AddEventListenerOptions): () => void;
|
|
11
|
+
type AllowedEvent = keyof DocumentEventMap | 'w-close';
|
|
12
|
+
/**
|
|
13
|
+
* Dispatches a custom event that bubbles from the target.
|
|
14
|
+
* @param target The element where the event will originate.
|
|
15
|
+
* @param events The event name or an array of event names.
|
|
16
|
+
* @returns True if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise.
|
|
17
|
+
*/
|
|
18
|
+
export declare const simulateEvent: (target: EventTarget, events: AllowedEvent | Array<AllowedEvent>) => boolean;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { noop } from './noop';
|
|
2
|
+
/**
|
|
3
|
+
* Adds an event listener to an element.
|
|
4
|
+
* @returns A callback to remove the event listener from the element.
|
|
5
|
+
*
|
|
6
|
+
* @param target
|
|
7
|
+
* @param type
|
|
8
|
+
* @param listener
|
|
9
|
+
* @param options
|
|
10
|
+
*/
|
|
11
|
+
export function addListener(target, type, listener, options) {
|
|
12
|
+
if (!target)
|
|
13
|
+
return noop;
|
|
14
|
+
target.addEventListener(type, listener, options);
|
|
15
|
+
return () => target.removeEventListener(type, listener, options);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Dispatches a custom event that bubbles from the target.
|
|
19
|
+
* @param target The element where the event will originate.
|
|
20
|
+
* @param events The event name or an array of event names.
|
|
21
|
+
* @returns True if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise.
|
|
22
|
+
*/
|
|
23
|
+
export const simulateEvent = (target, events) => {
|
|
24
|
+
if (!Array.isArray(events))
|
|
25
|
+
events = [events];
|
|
26
|
+
const eventsSuccess = events.map((event) => target.dispatchEvent(new Event(event, { bubbles: true })));
|
|
27
|
+
return eventsSuccess.every((success) => success);
|
|
28
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { FormField } from '../../types';
|
|
2
|
+
import { simulateEvent } from './events';
|
|
3
|
+
/**
|
|
4
|
+
* Clears the form field's value and emits an input and changed event.
|
|
5
|
+
* If the field is a checkbox or a radio, it will unselect it.
|
|
6
|
+
* @param field The `FormField` to clear.
|
|
7
|
+
* @param omitEvents By default, events are dispatched from the `FormField`. In some cases, these events might collide with other logic of the system.
|
|
8
|
+
* You can omit certain events from being dispatched by passing them in an array.
|
|
9
|
+
*/
|
|
10
|
+
export declare const clearFormField: (field: FormField, omitEvents?: Parameters<typeof simulateEvent>["1"]) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Gets the value of a given input element.
|
|
13
|
+
* @param {FormField} input
|
|
14
|
+
*/
|
|
15
|
+
export declare const getFormFieldValue: (input: FormField) => string;
|
|
16
|
+
/**
|
|
17
|
+
* Sets a value to a FormField element and emits `click`, `input` and `change` Events.
|
|
18
|
+
*
|
|
19
|
+
* @param element The FormField to update.
|
|
20
|
+
* @param value `boolean` for Checkboxes and Radios, `string` for the rest.
|
|
21
|
+
*/
|
|
22
|
+
export declare const setFormFieldValue: (element: FormField, value: string | boolean) => void;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { FORM_CSS_CLASSES } from '../webflow';
|
|
2
|
+
import { simulateEvent } from './events';
|
|
3
|
+
import { isHTMLInputElement } from './guards';
|
|
4
|
+
/**
|
|
5
|
+
* Clears the form field's value and emits an input and changed event.
|
|
6
|
+
* If the field is a checkbox or a radio, it will unselect it.
|
|
7
|
+
* @param field The `FormField` to clear.
|
|
8
|
+
* @param omitEvents By default, events are dispatched from the `FormField`. In some cases, these events might collide with other logic of the system.
|
|
9
|
+
* You can omit certain events from being dispatched by passing them in an array.
|
|
10
|
+
*/
|
|
11
|
+
export const clearFormField = (field, omitEvents = []) => {
|
|
12
|
+
const { type } = field;
|
|
13
|
+
if (isHTMLInputElement(field) && ['checkbox', 'radio'].includes(type)) {
|
|
14
|
+
if (!field.checked)
|
|
15
|
+
return;
|
|
16
|
+
// Reset the field's value
|
|
17
|
+
field.checked = false;
|
|
18
|
+
// Emit DOM events
|
|
19
|
+
simulateEvent(field, ['click', 'input', 'change'].filter((event) => !omitEvents.includes(event)));
|
|
20
|
+
if (type === 'checkbox')
|
|
21
|
+
return;
|
|
22
|
+
// Clear custom radio button classes
|
|
23
|
+
const { parentElement } = field;
|
|
24
|
+
if (!parentElement)
|
|
25
|
+
return;
|
|
26
|
+
const radioInput = parentElement.querySelector(`.${FORM_CSS_CLASSES.radioInput}`);
|
|
27
|
+
if (!radioInput)
|
|
28
|
+
return;
|
|
29
|
+
radioInput.classList.remove(FORM_CSS_CLASSES.checkboxOrRadioFocus, FORM_CSS_CLASSES.checkboxOrRadioChecked);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Reset the field's value
|
|
33
|
+
field.value = '';
|
|
34
|
+
// Emit DOM events
|
|
35
|
+
simulateEvent(field, ['input', 'change'].filter((eventKey) => !omitEvents.includes(eventKey)));
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Gets the value of a given input element.
|
|
39
|
+
* @param {FormField} input
|
|
40
|
+
*/
|
|
41
|
+
export const getFormFieldValue = (input) => {
|
|
42
|
+
let { value } = input;
|
|
43
|
+
// Perform actions depending on input type
|
|
44
|
+
if (input.type === 'checkbox')
|
|
45
|
+
value = input.checked.toString();
|
|
46
|
+
if (input.type === 'radio') {
|
|
47
|
+
// Get the checked radio
|
|
48
|
+
const checkedOption = input
|
|
49
|
+
.closest('form')
|
|
50
|
+
?.querySelector(`input[name="${input.name}"]:checked`);
|
|
51
|
+
// If exists, set its value
|
|
52
|
+
value = isHTMLInputElement(checkedOption) ? checkedOption.value : '';
|
|
53
|
+
}
|
|
54
|
+
return value.toString();
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Sets a value to a FormField element and emits `click`, `input` and `change` Events.
|
|
58
|
+
*
|
|
59
|
+
* @param element The FormField to update.
|
|
60
|
+
* @param value `boolean` for Checkboxes and Radios, `string` for the rest.
|
|
61
|
+
*/
|
|
62
|
+
export const setFormFieldValue = (element, value) => {
|
|
63
|
+
const { type } = element;
|
|
64
|
+
const isRadio = type === 'radio';
|
|
65
|
+
const isCheckbox = type === 'checkbox';
|
|
66
|
+
if (isRadio || isCheckbox) {
|
|
67
|
+
if (!isHTMLInputElement(element) ||
|
|
68
|
+
typeof value !== 'boolean' ||
|
|
69
|
+
value === element.checked ||
|
|
70
|
+
(isRadio && value === false)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
element.checked = value;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
if (element.value === value)
|
|
77
|
+
return;
|
|
78
|
+
element.value = value.toString();
|
|
79
|
+
}
|
|
80
|
+
// Emit DOM events
|
|
81
|
+
simulateEvent(element, ['click', 'input', 'change']);
|
|
82
|
+
};
|
|
@@ -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;
|