forgeframe 1.0.0

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.
@@ -0,0 +1,215 @@
1
+ import type { Dimensions } from '../types';
2
+ /**
3
+ * Configuration options for opening a popup window.
4
+ *
5
+ * @public
6
+ */
7
+ export interface PopupOptions {
8
+ /**
9
+ * The URL to load in the popup window.
10
+ */
11
+ url: string;
12
+ /**
13
+ * The name/target for the popup window.
14
+ *
15
+ * @remarks
16
+ * This is used as the window name for `window.open()`. If a window with
17
+ * this name already exists, the URL will be loaded in that window.
18
+ */
19
+ name: string;
20
+ /**
21
+ * The dimensions for the popup window.
22
+ *
23
+ * @remarks
24
+ * String dimension values will be parsed as integers (e.g., `'500px'` becomes `500`).
25
+ * If a dimension cannot be parsed, a default of 500 pixels is used.
26
+ */
27
+ dimensions: Dimensions;
28
+ }
29
+ /**
30
+ * Error thrown when a popup window is blocked by the browser.
31
+ *
32
+ * @remarks
33
+ * Modern browsers block popup windows that are not triggered by direct user
34
+ * interaction (e.g., click events). This error is thrown by {@link openPopup}
35
+ * when the browser prevents the popup from opening.
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * try {
40
+ * const popup = openPopup({ ... });
41
+ * } catch (error) {
42
+ * if (error instanceof PopupOpenError) {
43
+ * alert('Please allow popups for this site');
44
+ * }
45
+ * }
46
+ * ```
47
+ *
48
+ * @public
49
+ */
50
+ export declare class PopupOpenError extends Error {
51
+ constructor(message?: string);
52
+ }
53
+ /**
54
+ * Opens a popup window centered on the screen with the specified options.
55
+ *
56
+ * @remarks
57
+ * This function creates a popup window using `window.open()` with sensible
58
+ * defaults for security and usability:
59
+ * - The popup is centered relative to the parent window
60
+ * - The location bar is always shown (required for security)
61
+ * - The popup is resizable and has scrollbars
62
+ * - Menu bar, toolbar, and status bar are hidden
63
+ *
64
+ * If the popup is blocked by the browser (e.g., due to popup blockers or
65
+ * lack of user interaction), a {@link PopupOpenError} is thrown.
66
+ *
67
+ * @param options - Configuration options for the popup
68
+ * @returns The opened Window object
69
+ * @throws {@link PopupOpenError} If the popup is blocked by the browser
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * // Open a popup for authentication
74
+ * try {
75
+ * const authPopup = openPopup({
76
+ * url: 'https://auth.example.com/login',
77
+ * name: 'auth-popup',
78
+ * dimensions: { width: 500, height: 600 }
79
+ * });
80
+ *
81
+ * // Watch for the popup to close
82
+ * watchPopupClose(authPopup, () => {
83
+ * console.log('Authentication completed');
84
+ * });
85
+ * } catch (error) {
86
+ * if (error instanceof PopupOpenError) {
87
+ * // Handle blocked popup
88
+ * }
89
+ * }
90
+ * ```
91
+ *
92
+ * @public
93
+ */
94
+ export declare function openPopup(options: PopupOptions): Window;
95
+ /**
96
+ * Closes a popup window if it is still open.
97
+ *
98
+ * @remarks
99
+ * This function safely closes a popup window by first checking if it is
100
+ * already closed. Any errors during the close operation (e.g., due to
101
+ * cross-origin restrictions) are silently ignored.
102
+ *
103
+ * @param win - The popup Window object to close
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * const popup = openPopup({ ... });
108
+ * // Later, when done:
109
+ * closePopup(popup);
110
+ * ```
111
+ *
112
+ * @public
113
+ */
114
+ export declare function closePopup(win: Window): void;
115
+ /**
116
+ * Brings a popup window to the foreground by focusing it.
117
+ *
118
+ * @remarks
119
+ * This function attempts to focus a popup window if it is still open.
120
+ * Any errors during the focus operation are silently ignored, as some
121
+ * browsers may restrict focusing windows in certain contexts.
122
+ *
123
+ * @param win - The popup Window object to focus
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * // Refocus the popup when user clicks a button
128
+ * button.addEventListener('click', () => {
129
+ * focusPopup(popup);
130
+ * });
131
+ * ```
132
+ *
133
+ * @public
134
+ */
135
+ export declare function focusPopup(win: Window): void;
136
+ /**
137
+ * Checks if a popup window was blocked by the browser.
138
+ *
139
+ * @remarks
140
+ * This function uses multiple heuristics to detect blocked popups:
141
+ * - `null` window reference indicates the popup was blocked
142
+ * - Attempting to access properties on a blocked popup throws an error
143
+ * - Some browsers return a window with zero dimensions when blocked
144
+ *
145
+ * @param win - The Window object to check, or `null` if the popup failed to open
146
+ * @returns `true` if the popup appears to be blocked, `false` otherwise
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * const win = window.open(url, name, features);
151
+ * if (isPopupBlocked(win)) {
152
+ * console.error('Popup was blocked by the browser');
153
+ * }
154
+ * ```
155
+ *
156
+ * @public
157
+ */
158
+ export declare function isPopupBlocked(win: Window | null): boolean;
159
+ /**
160
+ * Watches a popup window and invokes a callback when it closes.
161
+ *
162
+ * @remarks
163
+ * This function polls the popup window's `closed` property using exponential
164
+ * backoff - starting with fast checks and slowing down over time. This approach
165
+ * catches quick closes immediately while reducing CPU usage for long-running popups.
166
+ *
167
+ * If the window becomes inaccessible (e.g., due to navigation to a different
168
+ * origin), the callback is also invoked and polling stops.
169
+ *
170
+ * @param win - The popup Window object to watch
171
+ * @param callback - Function to call when the popup closes
172
+ * @param options - Optional configuration for polling intervals
173
+ * @returns A cleanup function that stops watching when called
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * const popup = openPopup({ ... });
178
+ *
179
+ * const stopWatching = watchPopupClose(popup, () => {
180
+ * console.log('Popup was closed');
181
+ * // Handle post-close logic (e.g., check authentication state)
182
+ * });
183
+ *
184
+ * // Optionally stop watching early
185
+ * stopWatching();
186
+ * ```
187
+ *
188
+ * @public
189
+ */
190
+ export declare function watchPopupClose(win: Window, callback: () => void, options?: {
191
+ initialInterval?: number;
192
+ maxInterval?: number;
193
+ multiplier?: number;
194
+ }): () => void;
195
+ /**
196
+ * Resizes a popup window to the specified dimensions.
197
+ *
198
+ * @remarks
199
+ * This function attempts to resize the popup window using `window.resizeTo()`.
200
+ * Some browsers may restrict window resizing for security reasons, in which
201
+ * case errors are silently ignored.
202
+ *
203
+ * If a dimension is not specified, the current window dimension is preserved.
204
+ *
205
+ * @param win - The popup Window object to resize
206
+ * @param dimensions - The new dimensions for the popup
207
+ *
208
+ * @example
209
+ * ```typescript
210
+ * resizePopup(popup, { width: 800, height: 600 });
211
+ * ```
212
+ *
213
+ * @public
214
+ */
215
+ export declare function resizePopup(win: Window, dimensions: Dimensions): void;
@@ -0,0 +1,202 @@
1
+ import type { TemplateContext, Dimensions } from '../types';
2
+ /**
3
+ * Creates the default container element for ForgeFrame components.
4
+ *
5
+ * @remarks
6
+ * This template creates a wrapper `<div>` element that holds the iframe or
7
+ * popup content. The container is styled as an inline-block with relative
8
+ * positioning to support absolute positioning of child elements like
9
+ * prerender overlays.
10
+ *
11
+ * The container includes:
12
+ * - A unique ID based on the component's UID
13
+ * - A `data-forgeframe-tag` attribute for identification
14
+ * - Base styles for dimensions and overflow handling
15
+ *
16
+ * @typeParam P - The props type for the component
17
+ * @param ctx - The template context containing document, dimensions, and metadata
18
+ * @returns The created container HTMLElement
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const container = defaultContainerTemplate({
23
+ * doc: document,
24
+ * dimensions: { width: 400, height: 300 },
25
+ * uid: 'abc123',
26
+ * tag: 'payment-button',
27
+ * props: {}
28
+ * });
29
+ * document.body.appendChild(container);
30
+ * ```
31
+ *
32
+ * @public
33
+ */
34
+ export declare function defaultContainerTemplate<P>(ctx: TemplateContext<P>): HTMLElement;
35
+ /**
36
+ * Creates the default prerender template showing a loading spinner.
37
+ *
38
+ * @remarks
39
+ * This template creates an overlay element displayed while the actual
40
+ * component content is loading. It includes:
41
+ * - A centered wrapper with a light gray background
42
+ * - An animated spinning loader
43
+ * - CSS keyframes for the spin animation
44
+ *
45
+ * The overlay uses absolute positioning to cover the container and
46
+ * a high z-index to appear above other content.
47
+ *
48
+ * If a CSP (Content Security Policy) nonce is provided, it will be
49
+ * applied to the inline style element to comply with security policies.
50
+ *
51
+ * @typeParam P - The props type for the component
52
+ * @param ctx - The template context with optional CSP nonce
53
+ * @returns The created prerender overlay HTMLElement
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const prerender = defaultPrerenderTemplate({
58
+ * doc: document,
59
+ * dimensions: { width: 400, height: 300 },
60
+ * uid: 'abc123',
61
+ * tag: 'payment-button',
62
+ * props: {},
63
+ * cspNonce: 'abc123xyz'
64
+ * });
65
+ * container.appendChild(prerender);
66
+ * ```
67
+ *
68
+ * @public
69
+ */
70
+ export declare function defaultPrerenderTemplate<P>(ctx: TemplateContext<P> & {
71
+ cspNonce?: string;
72
+ }): HTMLElement;
73
+ /**
74
+ * Applies width and height dimensions to an HTML element.
75
+ *
76
+ * @remarks
77
+ * Only dimensions that are defined will be applied. Numeric values are
78
+ * automatically converted to pixel strings. This function can be used
79
+ * to resize any HTML element, not just iframes.
80
+ *
81
+ * @param element - The HTML element to apply dimensions to
82
+ * @param dimensions - The dimensions object containing width and/or height
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const div = document.createElement('div');
87
+ * applyDimensions(div, { width: 400, height: 300 });
88
+ * applyDimensions(div, { width: '100%' }); // Only width, height unchanged
89
+ * ```
90
+ *
91
+ * @public
92
+ */
93
+ export declare function applyDimensions(element: HTMLElement, dimensions: Dimensions): void;
94
+ /**
95
+ * Creates a `<style>` element with the provided CSS content.
96
+ *
97
+ * @remarks
98
+ * This utility function creates an inline style element that can be appended
99
+ * to the document. If a CSP (Content Security Policy) nonce is provided,
100
+ * it will be set on the style element to allow the styles to be applied
101
+ * in environments with strict CSP rules.
102
+ *
103
+ * @param doc - The Document object to create the element in
104
+ * @param css - The CSS content to include in the style element
105
+ * @param nonce - Optional CSP nonce for security compliance
106
+ * @returns The created HTMLStyleElement
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * const style = createStyleElement(
111
+ * document,
112
+ * '.my-class { color: red; }',
113
+ * 'abc123xyz'
114
+ * );
115
+ * document.head.appendChild(style);
116
+ * ```
117
+ *
118
+ * @public
119
+ */
120
+ export declare function createStyleElement(doc: Document, css: string, nonce?: string): HTMLStyleElement;
121
+ /**
122
+ * Animates an element fading in from transparent to fully opaque.
123
+ *
124
+ * @remarks
125
+ * This function applies a CSS opacity transition to create a smooth fade-in
126
+ * effect. It sets the initial opacity to 0, triggers a reflow to ensure the
127
+ * transition applies, then sets opacity to 1.
128
+ *
129
+ * The returned Promise resolves after the animation duration completes.
130
+ * Note that the Promise uses `setTimeout` rather than `transitionend` events
131
+ * for more predictable behavior across browsers.
132
+ *
133
+ * @param element - The HTML element to fade in
134
+ * @param duration - Animation duration in milliseconds (default: 200)
135
+ * @returns A Promise that resolves when the animation completes
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * const element = document.getElementById('my-element')!;
140
+ * await fadeIn(element, 300);
141
+ * console.log('Fade in complete');
142
+ * ```
143
+ *
144
+ * @public
145
+ */
146
+ export declare function fadeIn(element: HTMLElement, duration?: number): Promise<void>;
147
+ /**
148
+ * Animates an element fading out from its current opacity to transparent.
149
+ *
150
+ * @remarks
151
+ * This function applies a CSS opacity transition to create a smooth fade-out
152
+ * effect. Unlike {@link fadeIn}, it does not force a reflow since the element
153
+ * is already visible and the transition can begin immediately.
154
+ *
155
+ * The returned Promise resolves after the animation duration completes.
156
+ * Note that this function only changes opacity; the element remains in the
157
+ * DOM and may need to be removed or hidden separately after fading out.
158
+ *
159
+ * @param element - The HTML element to fade out
160
+ * @param duration - Animation duration in milliseconds (default: 200)
161
+ * @returns A Promise that resolves when the animation completes
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * const element = document.getElementById('my-element')!;
166
+ * await fadeOut(element, 300);
167
+ * element.remove(); // Remove after fade completes
168
+ * ```
169
+ *
170
+ * @public
171
+ */
172
+ export declare function fadeOut(element: HTMLElement, duration?: number): Promise<void>;
173
+ /**
174
+ * Swaps the prerender placeholder with the actual content using fade animations.
175
+ *
176
+ * @remarks
177
+ * This function performs a smooth transition from the prerender loading state
178
+ * to the actual content. The process:
179
+ * 1. If a prerender element exists, fade it out and remove it from the DOM
180
+ * 2. Set the actual content's initial opacity to 0
181
+ * 3. Append the actual content to the container
182
+ * 4. Fade in the actual content
183
+ *
184
+ * Both fade animations use a 150ms duration for a quick but smooth transition.
185
+ *
186
+ * @param container - The parent container element
187
+ * @param prerenderElement - The prerender placeholder element, or `null` if none exists
188
+ * @param actualElement - The actual content element to display
189
+ * @returns A Promise that resolves when the swap animation completes
190
+ *
191
+ * @example
192
+ * ```typescript
193
+ * const container = document.getElementById('widget-container')!;
194
+ * const prerender = container.querySelector('.prerender');
195
+ * const iframe = createIframe({ ... });
196
+ *
197
+ * await swapPrerenderContent(container, prerender, iframe);
198
+ * ```
199
+ *
200
+ * @public
201
+ */
202
+ export declare function swapPrerenderContent(_container: HTMLElement, prerenderElement: HTMLElement | null, actualElement: HTMLElement): Promise<void>;