@squeletteapp/widget 0.1.0 → 0.3.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.
- package/README.md +112 -0
- package/dist/app-BpPatA6a.js +42 -0
- package/dist/index-B0eQqkb_.js +7951 -0
- package/dist/types/app/app.d.ts +15 -0
- package/dist/types/banner/banner-modal.d.ts +15 -0
- package/dist/types/banner/banner.d.ts +14 -0
- package/dist/types/banner/element.d.ts +7 -0
- package/dist/types/banner/index.d.ts +19 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/utils.d.ts +2 -0
- package/dist/types/widget/__tests__/widget.test.d.ts +1 -0
- package/dist/types/widget/components/widget-shell.d.ts +8 -0
- package/dist/types/widget/constants.d.ts +9 -0
- package/dist/types/widget/core/custom-element.d.ts +142 -0
- package/dist/types/widget/core/global-api.d.ts +97 -0
- package/dist/types/widget/core/identity.d.ts +73 -0
- package/dist/types/widget/core/panel-dimensions.d.ts +36 -0
- package/dist/types/widget/core/positioning.d.ts +63 -0
- package/dist/types/widget/core/scroll-lock.d.ts +28 -0
- package/dist/types/widget/element.d.ts +90 -0
- package/dist/types/widget/events.d.ts +13 -0
- package/dist/types/widget/factories.d.ts +41 -0
- package/dist/types/widget/styles.d.ts +8 -0
- package/dist/types/widget/types.d.ts +79 -0
- package/dist/types/widget/utils.d.ts +12 -0
- package/dist/widget.es.js +14 -0
- package/dist/widget.js +168 -15
- package/package.json +32 -18
- package/dist/button-component.d.ts +0 -2
- package/dist/button-component.js +0 -158
- package/dist/index.d.ts +0 -26
- package/dist/index.js +0 -230
- package/dist/styles.css +0 -567
- package/dist/widget.d.ts +0 -42
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Preact component responsible for rendering the sandboxed iframe. By
|
|
3
|
+
* keeping the widget UI in an isolated module we can lazy-load it only when the
|
|
4
|
+
* launcher opens, keeping the initial footprint tiny.
|
|
5
|
+
*/
|
|
6
|
+
import type { JSX } from "preact";
|
|
7
|
+
export interface WidgetFrameProps {
|
|
8
|
+
src: string;
|
|
9
|
+
title: string;
|
|
10
|
+
onLoaded?: () => void;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
}
|
|
13
|
+
export declare function WidgetFrame({ src, title, onLoaded, onClose, }: WidgetFrameProps): JSX.Element;
|
|
14
|
+
export declare const stylesText: string;
|
|
15
|
+
export default WidgetFrame;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type Ticket = {
|
|
2
|
+
title: string;
|
|
3
|
+
id: number;
|
|
4
|
+
workspace: {
|
|
5
|
+
slug: string;
|
|
6
|
+
};
|
|
7
|
+
created_at: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const showModal: import("@preact/signals").Signal<boolean>;
|
|
10
|
+
export declare const modalTicket: import("@preact/signals").Signal<Ticket | null>;
|
|
11
|
+
export declare function BannerModal({ workspaceSlug, theme, }: {
|
|
12
|
+
workspaceSlug: string;
|
|
13
|
+
theme: "light" | "dark";
|
|
14
|
+
}): import("preact").VNode<any> | null;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type SqueletteBannerWidgetProps = {
|
|
2
|
+
workspaceSlug: string;
|
|
3
|
+
theme: "light" | "dark";
|
|
4
|
+
};
|
|
5
|
+
export declare function Banner({ workspaceSlug, theme, }: SqueletteBannerWidgetProps): import("preact").JSX.Element | null;
|
|
6
|
+
type MarqueeSpanProps = {
|
|
7
|
+
children: string;
|
|
8
|
+
duration?: number;
|
|
9
|
+
gap?: number;
|
|
10
|
+
className?: string;
|
|
11
|
+
delay?: number;
|
|
12
|
+
};
|
|
13
|
+
export declare function MarqueeSpan({ children, duration, gap, className, delay, }: MarqueeSpanProps): import("preact").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SqueletteBannerElement } from "./element";
|
|
2
|
+
export { SqueletteBannerElement };
|
|
3
|
+
type BannerInitPayload = {
|
|
4
|
+
slug: string;
|
|
5
|
+
contentTheme?: "light" | "dark";
|
|
6
|
+
theme?: BannerTheme;
|
|
7
|
+
};
|
|
8
|
+
export type BannerTheme = {
|
|
9
|
+
bg?: string;
|
|
10
|
+
border?: string;
|
|
11
|
+
text?: string;
|
|
12
|
+
badgeBg?: string;
|
|
13
|
+
badgeText?: string;
|
|
14
|
+
buttonHover?: string | number;
|
|
15
|
+
};
|
|
16
|
+
export declare const SqueletteBanner: {
|
|
17
|
+
init({ slug, theme, contentTheme, }: BannerInitPayload): SqueletteBannerElement | null;
|
|
18
|
+
setTheme(theme: BannerTheme): void;
|
|
19
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry-point that re-exports the custom element and typings. Consumers
|
|
3
|
+
* importing via ESM or CommonJS land here after bundling.
|
|
4
|
+
*/
|
|
5
|
+
export * from "./widget/element";
|
|
6
|
+
export { type WidgetTheme, type WidgetEventName, type WidgetEventListener, type WidgetEventDetailMap, type WidgetSubmitPayload, type CreateWidgetOptions, type WidgetView, type WidgetIdentityPayload, type WidgetPosition, type WidgetFloatingPosition, type WidgetFixedPosition, } from "./widget/types";
|
|
7
|
+
export { identify, clearIdentity } from "./widget/element";
|
|
8
|
+
export { createWidget, createFeedbackWidget, createRoadmapWidget, createChangelogWidget, } from "./widget/factories";
|
|
9
|
+
export * from "./banner";
|
|
10
|
+
export type { BannerTheme } from "./banner";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presentational shell rendered inside the widget's shadow root. It hosts the
|
|
3
|
+
* launcher button, overlay, and the lazy-loaded iframe container while keeping
|
|
4
|
+
* the custom element class free of JSX and rendering concerns.
|
|
5
|
+
*/
|
|
6
|
+
import type { JSX } from "preact";
|
|
7
|
+
import type { WidgetShellProps } from "../types";
|
|
8
|
+
export declare function WidgetShell({ open, label, iframeSrc, FrameComponent, ensureFrame, onOpen, onClose, onFrameLoaded, }: WidgetShellProps): JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralised constants that define the public identity of the widget bundle.
|
|
3
|
+
* These values are relied upon across the element implementation and by the
|
|
4
|
+
* CDN embed snippet, so keep them in one place to avoid drift.
|
|
5
|
+
*/
|
|
6
|
+
export declare const TAG_NAME = "squelette-widget";
|
|
7
|
+
export declare const API_BASE: string;
|
|
8
|
+
export declare const CDN_BASE = "https://cdn.squelette.app/widget.js";
|
|
9
|
+
export declare const DEFAULT_LABEL = "Feedback";
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Element Implementation
|
|
3
|
+
*
|
|
4
|
+
* Defines the `<squelette-widget>` custom element that powers the widget system.
|
|
5
|
+
* This class extends HTMLElement to create a fully-featured web component with:
|
|
6
|
+
*
|
|
7
|
+
* **Core Features:**
|
|
8
|
+
* - Shadow DOM encapsulation for style isolation
|
|
9
|
+
* - Lazy loading of iframe renderer (loaded only when widget opens)
|
|
10
|
+
* - Reactive attribute system using observed attributes
|
|
11
|
+
* - Event emitter for widget lifecycle events (open, close, submit)
|
|
12
|
+
* - Theme management with auto/light/dark modes
|
|
13
|
+
* - Internationalization support
|
|
14
|
+
*
|
|
15
|
+
* **State Management:**
|
|
16
|
+
* - Tracks open/closed state
|
|
17
|
+
* - Manages iframe loading state
|
|
18
|
+
* - Handles user identity forwarding to iframe
|
|
19
|
+
* - Coordinates scroll locking when panel is open
|
|
20
|
+
*
|
|
21
|
+
* **Communication:**
|
|
22
|
+
* - PostMessage API for iframe communication
|
|
23
|
+
* - CustomEvent system for host application integration
|
|
24
|
+
* - Event emitter pattern for programmatic access
|
|
25
|
+
*
|
|
26
|
+
* The element is designed to be used both declaratively (HTML attributes)
|
|
27
|
+
* and programmatically (JavaScript API), making it flexible for different
|
|
28
|
+
* integration patterns.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```html
|
|
32
|
+
* <!-- Declarative usage -->
|
|
33
|
+
* <squelette-widget
|
|
34
|
+
* project="my-project"
|
|
35
|
+
* board="feedback"
|
|
36
|
+
* theme="auto"
|
|
37
|
+
* locale="en"
|
|
38
|
+
* ></squelette-widget>
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* // Programmatic usage
|
|
44
|
+
* const widget = document.querySelector('squelette-widget');
|
|
45
|
+
* await widget.open();
|
|
46
|
+
* widget.on('submit', (event) => {
|
|
47
|
+
* console.log('Feedback submitted:', event.payload);
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
import { type WidgetEventListener, type WidgetEventName } from "../types";
|
|
52
|
+
/**
|
|
53
|
+
* Custom element class for `<squelette-widget>`.
|
|
54
|
+
*
|
|
55
|
+
* This is the main widget component that handles all widget functionality
|
|
56
|
+
* including rendering, state management, event handling, and iframe coordination.
|
|
57
|
+
*/
|
|
58
|
+
export declare class SqueletteWidgetElement extends HTMLElement {
|
|
59
|
+
#private;
|
|
60
|
+
/**
|
|
61
|
+
* Attributes that trigger attributeChangedCallback when modified.
|
|
62
|
+
*/
|
|
63
|
+
static get observedAttributes(): string[];
|
|
64
|
+
constructor();
|
|
65
|
+
/**
|
|
66
|
+
* Called when element is inserted into the DOM.
|
|
67
|
+
* Initializes configuration from attributes and sets up event listeners.
|
|
68
|
+
*/
|
|
69
|
+
connectedCallback(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Called when element is removed from the DOM.
|
|
72
|
+
* Cleans up all event listeners and restores page state.
|
|
73
|
+
*/
|
|
74
|
+
disconnectedCallback(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Called when observed attributes change.
|
|
77
|
+
* Updates internal configuration and triggers re-render.
|
|
78
|
+
*/
|
|
79
|
+
attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
|
|
80
|
+
/**
|
|
81
|
+
* Opens the widget panel.
|
|
82
|
+
* @public
|
|
83
|
+
*/
|
|
84
|
+
open(): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Closes the widget panel.
|
|
87
|
+
* @public
|
|
88
|
+
*/
|
|
89
|
+
close(): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Toggles the widget panel open/closed state.
|
|
92
|
+
* @public
|
|
93
|
+
*/
|
|
94
|
+
toggle(): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Registers an event listener for widget events.
|
|
97
|
+
* @public
|
|
98
|
+
* @returns Cleanup function to remove the listener
|
|
99
|
+
*/
|
|
100
|
+
on<K extends WidgetEventName>(event: K, handler: WidgetEventListener<K>): () => void;
|
|
101
|
+
/**
|
|
102
|
+
* Destroys the widget and removes it from the DOM.
|
|
103
|
+
* Cleans up all resources and event listeners.
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
106
|
+
destroy(): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Renders the widget UI using Preact.
|
|
109
|
+
* @private
|
|
110
|
+
*/
|
|
111
|
+
private render;
|
|
112
|
+
/**
|
|
113
|
+
* Lazy loads the iframe frame module when needed.
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
private ensureFrameModule;
|
|
117
|
+
/**
|
|
118
|
+
* Called when iframe finishes loading.
|
|
119
|
+
* @private
|
|
120
|
+
*/
|
|
121
|
+
private handleFrameLoaded;
|
|
122
|
+
/**
|
|
123
|
+
* Updates the open/closed state and manages side effects.
|
|
124
|
+
* @private
|
|
125
|
+
*/
|
|
126
|
+
private setOpen;
|
|
127
|
+
/**
|
|
128
|
+
* Applies theme and sets up theme change listeners.
|
|
129
|
+
* @private
|
|
130
|
+
*/
|
|
131
|
+
private applyTheme;
|
|
132
|
+
/**
|
|
133
|
+
* Posts identity payload to iframe via postMessage.
|
|
134
|
+
* @private
|
|
135
|
+
*/
|
|
136
|
+
private postIdentityToFrame;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Registers the custom element if not already registered.
|
|
140
|
+
* @internal
|
|
141
|
+
*/
|
|
142
|
+
export declare function registerSqueletteWidget(): void;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global API Helper
|
|
3
|
+
*
|
|
4
|
+
* Creates and exposes the `window.SqueletteWidget` global API for widget integrations.
|
|
5
|
+
* This module provides convenient factory functions and utilities that make
|
|
6
|
+
* it easy to create and configure widgets without using the custom element directly.
|
|
7
|
+
*
|
|
8
|
+
* **Available API Methods:**
|
|
9
|
+
*
|
|
10
|
+
* 1. `create()` - Flexible widget factory
|
|
11
|
+
* 2. `createFeedbackWidget()` - Specialized feedback widget factory
|
|
12
|
+
* 3. `createRoadmapWidget()` - Specialized roadmap widget factory
|
|
13
|
+
* 4. `createChangelogWidget()` - Specialized changelog widget factory
|
|
14
|
+
* 5. `identify()` - Set user identity across all widgets
|
|
15
|
+
* 6. `clearIdentity()` - Clear user identity
|
|
16
|
+
*
|
|
17
|
+
* **Specialized Options:**
|
|
18
|
+
* The specialized factories support advanced positioning options including:
|
|
19
|
+
* - Button-anchored positioning with collision detection
|
|
20
|
+
* - Fixed viewport positioning (9 preset positions)
|
|
21
|
+
* - Overlay blur effects
|
|
22
|
+
* - Custom event callbacks
|
|
23
|
+
* - Click-outside-to-close behavior
|
|
24
|
+
*
|
|
25
|
+
* This API maintains backward compatibility with existing integrations while
|
|
26
|
+
* internally using the modern custom element system.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* // Modern API
|
|
31
|
+
* const widget = SqueletteWidget.create({
|
|
32
|
+
* project: 'my-project',
|
|
33
|
+
* board: 'feedback',
|
|
34
|
+
* view: 'feedback'
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* // Specialized API
|
|
38
|
+
* const widget = SqueletteWidget.createFeedbackWidget('my-project', 'feedback', {
|
|
39
|
+
* buttonSelector: '#feedback-btn',
|
|
40
|
+
* position: 'bottom'
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* // Identity management
|
|
44
|
+
* SqueletteWidget.identify({
|
|
45
|
+
* userId: '123',
|
|
46
|
+
* email: 'user@example.com',
|
|
47
|
+
* signature: 'hmac-sig'
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
import type { CreateWidgetOptions } from "../types";
|
|
52
|
+
import { SqueletteWidgetElement } from "./custom-element";
|
|
53
|
+
import { type PositioningOptions } from "./positioning";
|
|
54
|
+
import { identify as identityIdentify, clearIdentity as identityClearIdentity } from "./identity";
|
|
55
|
+
import { SqueletteBanner } from "../../banner";
|
|
56
|
+
/**
|
|
57
|
+
* Widget options that extend positioning options.
|
|
58
|
+
* Omits project/board/view as these are passed separately in some factory APIs.
|
|
59
|
+
*/
|
|
60
|
+
type WidgetFactoryOptions = Omit<CreateWidgetOptions, "project" | "board" | "view"> & PositioningOptions;
|
|
61
|
+
/**
|
|
62
|
+
* Global API interface exposed on window.SqueletteWidget
|
|
63
|
+
*/
|
|
64
|
+
export interface GlobalSqueletteWidget {
|
|
65
|
+
/** Modern widget factory */
|
|
66
|
+
create: (options: CreateWidgetOptions) => SqueletteWidgetElement;
|
|
67
|
+
/** Specialized feedback widget factory */
|
|
68
|
+
createFeedbackWidget: (project: string, board?: string | null, options?: WidgetFactoryOptions) => SqueletteWidgetElement;
|
|
69
|
+
/** Specialized roadmap widget factory */
|
|
70
|
+
createRoadmapWidget: (project: string, board?: string | null, options?: WidgetFactoryOptions) => SqueletteWidgetElement;
|
|
71
|
+
/** Specialized changelog widget factory */
|
|
72
|
+
createChangelogWidget: (project: string, options?: WidgetFactoryOptions) => SqueletteWidgetElement;
|
|
73
|
+
/** Set user identity */
|
|
74
|
+
identify: typeof identityIdentify;
|
|
75
|
+
/** Clear user identity */
|
|
76
|
+
clearIdentity: typeof identityClearIdentity;
|
|
77
|
+
/** Banner API */
|
|
78
|
+
banner: typeof SqueletteBanner;
|
|
79
|
+
/** Widget version */
|
|
80
|
+
version: string;
|
|
81
|
+
/** CDN base URL */
|
|
82
|
+
cdn: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Initializes and exposes the global SqueletteWidget API.
|
|
86
|
+
* This function is called once during module initialization.
|
|
87
|
+
*
|
|
88
|
+
* If the API already exists (e.g., from a previous script load),
|
|
89
|
+
* this function does nothing to avoid conflicts.
|
|
90
|
+
*/
|
|
91
|
+
export declare function ensureGlobalHelper(): void;
|
|
92
|
+
declare global {
|
|
93
|
+
interface Window {
|
|
94
|
+
SqueletteWidget?: GlobalSqueletteWidget;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity Management Module
|
|
3
|
+
*
|
|
4
|
+
* Handles user identification for the widget system. This module provides:
|
|
5
|
+
* - A global identity store accessible across all widget instances
|
|
6
|
+
* - Event-based identity updates using CustomEvents
|
|
7
|
+
* - Type-safe identity payload validation
|
|
8
|
+
* - Centralized identity state management
|
|
9
|
+
*
|
|
10
|
+
* The identity system works by:
|
|
11
|
+
* 1. Storing identity payload in module-level state
|
|
12
|
+
* 2. Broadcasting changes via 'squelette:identity' CustomEvent
|
|
13
|
+
* 3. Widget instances listen to this event and forward to iframes
|
|
14
|
+
*
|
|
15
|
+
* This allows multiple widget instances to share the same user identity
|
|
16
|
+
* without prop drilling or complex state management.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // Set user identity
|
|
21
|
+
* identify({
|
|
22
|
+
* userId: '123',
|
|
23
|
+
* email: 'user@example.com',
|
|
24
|
+
* signature: 'hmac-signature'
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // Clear identity
|
|
28
|
+
* clearIdentity();
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
import type { WidgetIdentityPayload } from '../types';
|
|
32
|
+
/**
|
|
33
|
+
* Sets the user identity for all widget instances.
|
|
34
|
+
*
|
|
35
|
+
* This function validates the payload and broadcasts the identity
|
|
36
|
+
* to all active widget instances via a CustomEvent. Each widget
|
|
37
|
+
* will then forward this information to its iframe.
|
|
38
|
+
*
|
|
39
|
+
* @param payload - User identification data including userId, email, and HMAC signature
|
|
40
|
+
* @throws {Error} Logs an error if payload is invalid (missing required fields)
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* identify({
|
|
45
|
+
* userId: 'user_123',
|
|
46
|
+
* email: 'john@example.com',
|
|
47
|
+
* signature: 'hmac_abc123',
|
|
48
|
+
* name: 'John Doe', // optional
|
|
49
|
+
* avatar: 'https://...', // optional
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function identify(payload: WidgetIdentityPayload): void;
|
|
54
|
+
/**
|
|
55
|
+
* Clears the current user identity for all widget instances.
|
|
56
|
+
*
|
|
57
|
+
* This removes the stored identity and notifies all widgets
|
|
58
|
+
* to clear their identity state, typically used on logout.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* // On user logout
|
|
63
|
+
* clearIdentity();
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function clearIdentity(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Gets the current identity payload.
|
|
69
|
+
*
|
|
70
|
+
* @internal This is used internally by widget instances
|
|
71
|
+
* @returns The current identity payload, or null if no user is identified
|
|
72
|
+
*/
|
|
73
|
+
export declare function getIdentityPayload(): WidgetIdentityPayload | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Panel Dimensions Configuration
|
|
3
|
+
*
|
|
4
|
+
* Defines the default dimensions for different widget views (feedback, roadmap, changelog).
|
|
5
|
+
* Each view has optimized width and height values based on its content requirements:
|
|
6
|
+
*
|
|
7
|
+
* - Feedback: Compact form for quick feedback submission
|
|
8
|
+
* - Roadmap: Medium height for displaying planned features
|
|
9
|
+
* - Changelog: Taller panel for scrolling through updates
|
|
10
|
+
*
|
|
11
|
+
* These dimensions are applied as CSS custom properties (--sq-panel-width, --sq-panel-height)
|
|
12
|
+
* to the custom element, allowing the widget to adapt its size based on the active view.
|
|
13
|
+
*/
|
|
14
|
+
import type { WidgetView } from "../types";
|
|
15
|
+
/**
|
|
16
|
+
* Default dimensions for each widget view type.
|
|
17
|
+
* Values are in pixels and represent the ideal size for each view's content.
|
|
18
|
+
*/
|
|
19
|
+
export declare const PANEL_DIMENSIONS: Record<WidgetView, {
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}>;
|
|
23
|
+
/**
|
|
24
|
+
* Fallback dimensions when view type is unknown or not specified.
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEFAULT_PANEL_DIMENSIONS: {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Applies panel dimensions to the widget element as CSS custom properties.
|
|
32
|
+
*
|
|
33
|
+
* @param element - The widget element to apply dimensions to
|
|
34
|
+
* @param view - The widget view type (feedback, roadmap, or changelog)
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyPanelDimensions(element: HTMLElement, view: WidgetView): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget Positioning System
|
|
3
|
+
*
|
|
4
|
+
* Handles advanced positioning logic for the widget.
|
|
5
|
+
* This module supports two positioning modes:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Button-anchored positioning**: Widget appears relative to a trigger button
|
|
8
|
+
* - Dynamically calculates optimal placement (top/bottom/left/right)
|
|
9
|
+
* - Automatically repositions on scroll/resize
|
|
10
|
+
* - Ensures widget stays within viewport bounds
|
|
11
|
+
* - Supports collision detection and smart fallback positioning
|
|
12
|
+
*
|
|
13
|
+
* 2. **Fixed positioning**: Widget appears at a fixed viewport location
|
|
14
|
+
* - Supports 9 preset positions (fixed-top-left, fixed-center-center, etc.)
|
|
15
|
+
* - Maintains position regardless of page scroll
|
|
16
|
+
* - Respects viewport margins and responsive layouts
|
|
17
|
+
*
|
|
18
|
+
* This module also handles:
|
|
19
|
+
* - Click-outside detection to close the widget
|
|
20
|
+
* - Overlay blur effects
|
|
21
|
+
* - Custom button selector binding
|
|
22
|
+
* - Lifecycle cleanup for event listeners
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const cleanup = applyPositioning(element, {
|
|
27
|
+
* buttonSelector: '#feedback-button',
|
|
28
|
+
* position: 'bottom',
|
|
29
|
+
* overlayBlur: true
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Later: cleanup all event listeners
|
|
33
|
+
* cleanup();
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
import type { SqueletteWidgetElement } from "./custom-element";
|
|
37
|
+
import type { WidgetPosition } from "../types";
|
|
38
|
+
/**
|
|
39
|
+
* Widget positioning and binding options.
|
|
40
|
+
*/
|
|
41
|
+
export interface PositioningOptions {
|
|
42
|
+
/** CSS selector for the button that triggers the widget */
|
|
43
|
+
buttonSelector?: string;
|
|
44
|
+
/** Preferred position relative to button or fixed viewport position */
|
|
45
|
+
position?: WidgetPosition;
|
|
46
|
+
/** Whether to apply blur effect to the overlay backdrop */
|
|
47
|
+
overlayBlur?: boolean;
|
|
48
|
+
/** Callback when widget open state changes */
|
|
49
|
+
onOpenChange?: (open: boolean) => void;
|
|
50
|
+
/** Callback when widget iframe finishes loading */
|
|
51
|
+
onLoad?: () => void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Applies positioning and event bindings to a widget element.
|
|
55
|
+
*
|
|
56
|
+
* This function sets up all the positioning logic, event listeners, and
|
|
57
|
+
* custom behaviors needed for the widget.
|
|
58
|
+
*
|
|
59
|
+
* @param element - The widget element to enhance
|
|
60
|
+
* @param options - Positioning and behavior options
|
|
61
|
+
* @returns Array of cleanup functions to remove all applied behaviors
|
|
62
|
+
*/
|
|
63
|
+
export declare function applyPositioning(element: SqueletteWidgetElement, options: PositioningOptions): Array<() => void>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Body Scroll Lock Utility
|
|
3
|
+
*
|
|
4
|
+
* Manages the locking and unlocking of body scroll when the widget panel is open.
|
|
5
|
+
* This prevents the underlying page from scrolling while the user interacts with
|
|
6
|
+
* the widget overlay.
|
|
7
|
+
*
|
|
8
|
+
* Key behaviors:
|
|
9
|
+
* - Locks body scroll by setting `overflow: hidden`
|
|
10
|
+
* - Calculates and compensates for scrollbar width to prevent layout shift
|
|
11
|
+
* - Returns a cleanup function to restore original scroll state
|
|
12
|
+
* - Preserves original overflow and padding-right values
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const restoreScroll = toggleBodyScroll(true);
|
|
17
|
+
* // ... widget is open, body cannot scroll
|
|
18
|
+
* restoreScroll(); // restore original scroll behavior
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Toggles body scroll lock and compensates for scrollbar width
|
|
23
|
+
* to prevent layout shift.
|
|
24
|
+
*
|
|
25
|
+
* @param lock - Whether to lock (true) or unlock (false) body scroll
|
|
26
|
+
* @returns A cleanup function that restores the original scroll state
|
|
27
|
+
*/
|
|
28
|
+
export declare function toggleBodyScroll(lock: boolean): () => void;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget Element Module
|
|
3
|
+
*
|
|
4
|
+
* This is the main entry point for the widget's custom element implementation.
|
|
5
|
+
* It has been refactored into smaller, focused modules for better maintainability:
|
|
6
|
+
*
|
|
7
|
+
* **Module Structure:**
|
|
8
|
+
*
|
|
9
|
+
* - `core/custom-element.ts` - The `<squelette-widget>` custom element class
|
|
10
|
+
* - Handles Shadow DOM, lifecycle methods, attribute observation
|
|
11
|
+
* - Manages widget state (open/closed, loading, theme)
|
|
12
|
+
* - Coordinates iframe loading and communication
|
|
13
|
+
*
|
|
14
|
+
* - `core/identity.ts` - User identity management
|
|
15
|
+
* - Global identity store for all widget instances
|
|
16
|
+
* - `identify()` and `clearIdentity()` functions
|
|
17
|
+
* - Event-based identity synchronization
|
|
18
|
+
*
|
|
19
|
+
* - `core/scroll-lock.ts` - Body scroll management
|
|
20
|
+
* - Locks page scroll when widget is open
|
|
21
|
+
* - Compensates for scrollbar width to prevent layout shift
|
|
22
|
+
*
|
|
23
|
+
* - `core/panel-dimensions.ts` - Widget panel dimensions
|
|
24
|
+
* - Default dimensions for each view type (feedback, roadmap, changelog)
|
|
25
|
+
* - CSS custom property application
|
|
26
|
+
*
|
|
27
|
+
* - `core/positioning.ts` - Advanced positioning system
|
|
28
|
+
* - Button-anchored positioning with collision detection
|
|
29
|
+
* - Fixed viewport positioning (9 preset positions)
|
|
30
|
+
* - Click-outside-to-close behavior
|
|
31
|
+
* - Responsive viewport tracking
|
|
32
|
+
*
|
|
33
|
+
* - `core/global-api.ts` - Global `window.SqueletteWidget` API
|
|
34
|
+
* - Factory functions for creating widgets
|
|
35
|
+
* - Convenient JavaScript API layer
|
|
36
|
+
* - Version and CDN information
|
|
37
|
+
*
|
|
38
|
+
* **Usage:**
|
|
39
|
+
*
|
|
40
|
+
* Declarative (HTML):
|
|
41
|
+
* ```html
|
|
42
|
+
* <squelette-widget
|
|
43
|
+
* project="my-project"
|
|
44
|
+
* board="feedback"
|
|
45
|
+
* theme="auto"
|
|
46
|
+
* locale="en"
|
|
47
|
+
* ></squelette-widget>
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* Programmatic (JavaScript):
|
|
51
|
+
* ```js
|
|
52
|
+
* const widget = SqueletteWidget.create({
|
|
53
|
+
* project: 'my-project',
|
|
54
|
+
* board: 'feedback',
|
|
55
|
+
* view: 'feedback'
|
|
56
|
+
* });
|
|
57
|
+
*
|
|
58
|
+
* await widget.open();
|
|
59
|
+
* widget.on('submit', (e) => console.log(e.payload));
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* Alternative API:
|
|
63
|
+
* ```js
|
|
64
|
+
* const widget = SqueletteWidget.createFeedbackWidget('my-project', 'feedback', {
|
|
65
|
+
* buttonSelector: '#feedback-button',
|
|
66
|
+
* position: 'bottom',
|
|
67
|
+
* overlayBlur: true
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* Identity Management:
|
|
72
|
+
* ```js
|
|
73
|
+
* SqueletteWidget.identify({
|
|
74
|
+
* userId: '123',
|
|
75
|
+
* email: 'user@example.com',
|
|
76
|
+
* signature: 'hmac-signature',
|
|
77
|
+
* name: 'John Doe' // optional
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* SqueletteWidget.clearIdentity(); // on logout
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export { SqueletteWidgetElement, registerSqueletteWidget, } from "./core/custom-element";
|
|
84
|
+
export { identify, clearIdentity } from "./core/identity";
|
|
85
|
+
export { ensureGlobalHelper, type GlobalSqueletteWidget, } from "./core/global-api";
|
|
86
|
+
declare global {
|
|
87
|
+
interface HTMLElementTagNameMap {
|
|
88
|
+
"squelette-widget": import("./core/custom-element").SqueletteWidgetElement;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight event emitter dedicated to the widget element. It keeps
|
|
3
|
+
* allocation pressure low while offering an ergonomic `.on()` API for clients
|
|
4
|
+
* embedding the widget and for internal coordination between the shell and the
|
|
5
|
+
* custom element lifecycle.
|
|
6
|
+
*/
|
|
7
|
+
import type { WidgetEventListener, WidgetEventName, WidgetEventDetailMap } from './types';
|
|
8
|
+
export declare class WidgetEventEmitter {
|
|
9
|
+
private listeners;
|
|
10
|
+
on<K extends WidgetEventName>(event: K, handler: WidgetEventListener<K>): () => void;
|
|
11
|
+
off<K extends WidgetEventName>(event: K, handler: WidgetEventListener<K>): void;
|
|
12
|
+
emit<K extends WidgetEventName>(event: K, payload: WidgetEventDetailMap[K]): void;
|
|
13
|
+
}
|