@squeletteapp/widget-react 0.1.1 → 1.1.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,11 @@
1
+ export interface ChangelogBannerProps {
2
+ debug?: boolean;
3
+ }
4
+ /**
5
+ * ChangelogBanner - Renders a banner for the latest changelog entry
6
+ *
7
+ * This component automatically fetches the latest changelog entry,
8
+ * checks if it should be shown, and displays a banner at the bottom
9
+ * of the screen. Must be used within a ChangelogProvider.
10
+ */
11
+ export declare function ChangelogBanner({ debug }: ChangelogBannerProps): null;
@@ -0,0 +1,44 @@
1
+ 'use client';
2
+ import * as React from 'react';
3
+ import { useChangelogContext } from '../context';
4
+ /**
5
+ * ChangelogBanner - Renders a banner for the latest changelog entry
6
+ *
7
+ * This component automatically fetches the latest changelog entry,
8
+ * checks if it should be shown, and displays a banner at the bottom
9
+ * of the screen. Must be used within a ChangelogProvider.
10
+ */
11
+ export function ChangelogBanner({ debug = false }) {
12
+ const { store, module, theme, base, slug } = useChangelogContext();
13
+ const widgetRef = React.useRef(null);
14
+ // Store initial theme in ref to use in creation
15
+ const initialThemeRef = React.useRef(theme);
16
+ // Create widget once on mount (theme changes handled separately via setTheme)
17
+ React.useEffect(() => {
18
+ let mounted = true;
19
+ module
20
+ .createChangelogBannerWidget(store, {
21
+ base,
22
+ contentTheme: initialThemeRef.current,
23
+ slug,
24
+ debug,
25
+ })
26
+ .then((widget) => {
27
+ if (mounted && widget) {
28
+ widgetRef.current = widget;
29
+ }
30
+ });
31
+ return () => {
32
+ mounted = false;
33
+ if (widgetRef.current) {
34
+ widgetRef.current.destroy();
35
+ widgetRef.current = null;
36
+ }
37
+ };
38
+ }, [slug, store, module, base, debug]);
39
+ // Update theme when it changes (separate effect to avoid recreating widget)
40
+ React.useEffect(() => {
41
+ widgetRef.current?.setTheme(theme);
42
+ }, [theme]);
43
+ return null;
44
+ }
@@ -0,0 +1,14 @@
1
+ import * as React from 'react';
2
+ type Position = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw' | 'center';
3
+ export interface ChangelogEntriesListDropdownProps {
4
+ children: React.ReactElement;
5
+ position?: Position;
6
+ }
7
+ /**
8
+ * ChangelogEntriesListDropdown - Renders a dropdown list of changelog entries
9
+ *
10
+ * This component wraps a child element (trigger) and opens the dropdown
11
+ * when the child is clicked. Must be used within a ChangelogProvider.
12
+ */
13
+ export declare function ChangelogEntriesListDropdown({ children, position, }: ChangelogEntriesListDropdownProps): React.ReactElement<any, string | React.JSXElementConstructor<any>>;
14
+ export {};
@@ -0,0 +1,50 @@
1
+ 'use client';
2
+ import * as React from 'react';
3
+ import { useChangelogContext } from '../context';
4
+ /**
5
+ * ChangelogEntriesListDropdown - Renders a dropdown list of changelog entries
6
+ *
7
+ * This component wraps a child element (trigger) and opens the dropdown
8
+ * when the child is clicked. Must be used within a ChangelogProvider.
9
+ */
10
+ export function ChangelogEntriesListDropdown({ children, position, }) {
11
+ const { store, module, theme, base, slug } = useChangelogContext();
12
+ const widgetRef = React.useRef(null);
13
+ const anchorId = React.useId();
14
+ const cleanAnchorId = `sq-dropdown-${anchorId.replace(/:/g, '')}`;
15
+ // Store initial theme in ref to use in creation
16
+ const initialThemeRef = React.useRef(theme);
17
+ // Create widget once on mount (theme changes handled separately via setTheme)
18
+ React.useEffect(() => {
19
+ const widget = module.createChangelogEntriesListDropdownWidget(`#${cleanAnchorId}`, store, {
20
+ base,
21
+ contentTheme: initialThemeRef.current,
22
+ slug,
23
+ position,
24
+ });
25
+ widget.preload();
26
+ widgetRef.current = widget;
27
+ return () => {
28
+ widget.destroy();
29
+ widgetRef.current = null;
30
+ };
31
+ }, [slug, store, module, base, cleanAnchorId, position]);
32
+ // Update theme when it changes (separate effect to avoid recreating widget)
33
+ React.useEffect(() => {
34
+ widgetRef.current?.setTheme(theme);
35
+ }, [theme]);
36
+ const handleClick = React.useCallback(() => {
37
+ widgetRef.current?.open();
38
+ }, []);
39
+ // Clone the child and add the anchor id and click handler
40
+ return React.cloneElement(children, {
41
+ id: cleanAnchorId,
42
+ onClick: (e) => {
43
+ const originalOnClick = children.props.onClick;
44
+ if (originalOnClick) {
45
+ originalOnClick(e);
46
+ }
47
+ handleClick();
48
+ },
49
+ });
50
+ }
@@ -0,0 +1,11 @@
1
+ export interface ChangelogEntryModalProps {
2
+ ticketId: string;
3
+ onOpenChange?: (isOpen: boolean) => void;
4
+ }
5
+ /**
6
+ * ChangelogEntryModal - Renders a modal for a single changelog entry
7
+ *
8
+ * This component manages its own widget lifecycle and automatically
9
+ * cleans up on unmount. Must be used within a ChangelogProvider.
10
+ */
11
+ export declare function ChangelogEntryModal({ ticketId, onOpenChange, }: ChangelogEntryModalProps): null;
@@ -0,0 +1,34 @@
1
+ 'use client';
2
+ import * as React from 'react';
3
+ import { useChangelogContext } from '../context';
4
+ /**
5
+ * ChangelogEntryModal - Renders a modal for a single changelog entry
6
+ *
7
+ * This component manages its own widget lifecycle and automatically
8
+ * cleans up on unmount. Must be used within a ChangelogProvider.
9
+ */
10
+ export function ChangelogEntryModal({ ticketId, onOpenChange, }) {
11
+ const { store, module, theme, base, slug } = useChangelogContext();
12
+ const widgetRef = React.useRef(null);
13
+ React.useEffect(() => {
14
+ const widget = module.createChangelogEntryWidget(ticketId, {
15
+ base,
16
+ contentTheme: theme,
17
+ slug,
18
+ });
19
+ if (onOpenChange) {
20
+ widget.onOpenChange(onOpenChange);
21
+ }
22
+ widgetRef.current = widget;
23
+ store.mount(ticketId, widget);
24
+ return () => {
25
+ store.unmount(ticketId);
26
+ widgetRef.current = null;
27
+ };
28
+ }, [ticketId, slug, store, module, base, onOpenChange, theme]);
29
+ // Update theme when it changes
30
+ React.useEffect(() => {
31
+ widgetRef.current?.setTheme(theme);
32
+ }, [theme]);
33
+ return null;
34
+ }
@@ -0,0 +1,53 @@
1
+ import * as React from 'react';
2
+ import type { ContentTheme } from './types';
3
+ type WidgetStore = {
4
+ getState: () => Record<string, unknown>;
5
+ mount: (source: string, widget: unknown) => Promise<void>;
6
+ unmount: (source: string) => void;
7
+ open: (source: string) => Promise<void>;
8
+ setTheme: (theme: ContentTheme) => void;
9
+ };
10
+ type WidgetModule = {
11
+ createChangelogStore: () => WidgetStore;
12
+ createChangelogEntryWidget: (ticketId: string, options: {
13
+ base?: string;
14
+ contentTheme?: ContentTheme;
15
+ slug?: string;
16
+ }) => unknown;
17
+ createChangelogBannerWidget: (store: WidgetStore, options: {
18
+ base?: string;
19
+ contentTheme?: ContentTheme;
20
+ slug: string;
21
+ debug?: boolean;
22
+ }) => Promise<unknown>;
23
+ createChangelogEntriesListDropdownWidget: (anchor: string, store: WidgetStore, options: {
24
+ base?: string;
25
+ contentTheme?: ContentTheme;
26
+ slug?: string;
27
+ position?: 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw' | 'center';
28
+ }) => unknown;
29
+ };
30
+ type ChangelogContextValue = {
31
+ store: WidgetStore;
32
+ module: WidgetModule;
33
+ theme: ContentTheme;
34
+ base?: string;
35
+ slug: string;
36
+ };
37
+ export interface ChangelogProviderProps {
38
+ children: React.ReactNode;
39
+ slug: string;
40
+ theme?: ContentTheme;
41
+ base?: string;
42
+ }
43
+ /**
44
+ * ChangelogProvider - Provides changelog store and configuration to child components
45
+ *
46
+ * This provider handles:
47
+ * - Creating and managing the widget store (client-side only)
48
+ * - Syncing theme changes to all widgets
49
+ * - Providing base URL and slug to all child components
50
+ */
51
+ export declare function ChangelogProvider({ children, slug, theme, base, }: ChangelogProviderProps): import("react/jsx-runtime").JSX.Element | null;
52
+ export declare function useChangelogContext(): ChangelogContextValue;
53
+ export {};
@@ -0,0 +1,41 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from 'react';
4
+ const ChangelogContext = React.createContext(null);
5
+ /**
6
+ * ChangelogProvider - Provides changelog store and configuration to child components
7
+ *
8
+ * This provider handles:
9
+ * - Creating and managing the widget store (client-side only)
10
+ * - Syncing theme changes to all widgets
11
+ * - Providing base URL and slug to all child components
12
+ */
13
+ export function ChangelogProvider({ children, slug, theme = 'light', base, }) {
14
+ const [context, setContext] = React.useState(null);
15
+ // Initialize store on client side only
16
+ React.useEffect(() => {
17
+ import('@squeletteapp/widget').then((mod) => {
18
+ const widgetModule = mod;
19
+ setContext({
20
+ store: widgetModule.createChangelogStore(),
21
+ module: widgetModule,
22
+ });
23
+ });
24
+ }, []);
25
+ // Update theme when it changes
26
+ React.useEffect(() => {
27
+ context?.store.setTheme(theme);
28
+ }, [context, theme]);
29
+ // Don't render children until store is ready (client-side only)
30
+ if (!context) {
31
+ return null;
32
+ }
33
+ return (_jsx(ChangelogContext.Provider, { value: { store: context.store, module: context.module, theme, base, slug }, children: children }));
34
+ }
35
+ export function useChangelogContext() {
36
+ const context = React.useContext(ChangelogContext);
37
+ if (!context) {
38
+ throw new Error('useChangelogContext must be used within a ChangelogProvider');
39
+ }
40
+ return context;
41
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
- export { createChangelogWidget, createFeedbackWidget, createRoadmapWidget, createWidget, } from '@squeletteapp/widget';
2
- export { ChangelogWidget, type ChangelogWidgetProps, FeedbackWidget, type FeedbackWidgetProps, RoadmapWidget, type RoadmapWidgetProps, } from './components';
3
- export { useChangelogWidget, useFeedbackWidget, useRoadmapWidget, useWidget, type WidgetInstance, type WidgetOptions, } from './hooks';
1
+ export { ChangelogProvider, useChangelogContext, type ChangelogProviderProps, } from './context';
2
+ export { ChangelogEntryModal, type ChangelogEntryModalProps, } from './components/changelog-entry-modal';
3
+ export { ChangelogEntriesListDropdown, type ChangelogEntriesListDropdownProps, } from './components/changelog-entries-list-dropdown';
4
+ export { ChangelogBanner, type ChangelogBannerProps, } from './components/changelog-banner';
5
+ export type { ContentTheme } from './types';