@squeletteapp/widget-react 0.1.0 → 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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/hooks.ts", "../src/components.tsx", "../src/index.ts"],
4
- "sourcesContent": ["import { useEffect, useRef, useCallback } from 'react';\nimport { \n createFeedbackWidget, \n createRoadmapWidget, \n createChangelogWidget,\n createWidget\n} from '@squeletteapp/widget';\n\nexport interface WidgetOptions {\n buttonSelector: string;\n position?: 'top' | 'bottom' | 'left' | 'right';\n theme?: string;\n onLoad?: () => void;\n onOpenChange?: (isOpen: boolean) => void;\n}\n\nexport interface WidgetInstance {\n destroy: () => void;\n}\n\nexport function useFeedbackWidget(\n workspaceSlug: string,\n boardSlug: string | undefined,\n options: WidgetOptions\n): WidgetInstance | null {\n const widgetRef = useRef<WidgetInstance | null>(null);\n\n const initWidget = useCallback(() => {\n if (widgetRef.current) {\n widgetRef.current.destroy();\n }\n \n widgetRef.current = createFeedbackWidget(workspaceSlug, boardSlug, options);\n return widgetRef.current;\n }, [workspaceSlug, boardSlug, options]);\n\n useEffect(() => {\n const widget = initWidget();\n \n return () => {\n if (widget) {\n widget.destroy();\n }\n };\n }, [initWidget]);\n\n return widgetRef.current;\n}\n\nexport function useRoadmapWidget(\n workspaceSlug: string,\n boardSlug: string,\n options: WidgetOptions\n): WidgetInstance | null {\n const widgetRef = useRef<WidgetInstance | null>(null);\n\n const initWidget = useCallback(() => {\n if (widgetRef.current) {\n widgetRef.current.destroy();\n }\n \n widgetRef.current = createRoadmapWidget(workspaceSlug, boardSlug, options);\n return widgetRef.current;\n }, [workspaceSlug, boardSlug, options]);\n\n useEffect(() => {\n const widget = initWidget();\n \n return () => {\n if (widget) {\n widget.destroy();\n }\n };\n }, [initWidget]);\n\n return widgetRef.current;\n}\n\nexport function useChangelogWidget(\n workspaceSlug: string,\n options: WidgetOptions\n): WidgetInstance | null {\n const widgetRef = useRef<WidgetInstance | null>(null);\n\n const initWidget = useCallback(() => {\n if (widgetRef.current) {\n widgetRef.current.destroy();\n }\n \n widgetRef.current = createChangelogWidget(workspaceSlug, options);\n return widgetRef.current;\n }, [workspaceSlug, options]);\n\n useEffect(() => {\n const widget = initWidget();\n \n return () => {\n if (widget) {\n widget.destroy();\n }\n };\n }, [initWidget]);\n\n return widgetRef.current;\n}\n\nexport function useWidget(options: {\n url: string;\n buttonSelector: string;\n position?: 'top' | 'bottom' | 'left' | 'right';\n onLoad?: () => void;\n onOpenChange?: (isOpen: boolean) => void;\n}): WidgetInstance | null {\n const widgetRef = useRef<WidgetInstance | null>(null);\n\n const initWidget = useCallback(() => {\n if (widgetRef.current) {\n widgetRef.current.destroy();\n }\n \n widgetRef.current = createWidget(options);\n return widgetRef.current;\n }, [options]);\n\n useEffect(() => {\n const widget = initWidget();\n \n return () => {\n if (widget) {\n widget.destroy();\n }\n };\n }, [initWidget]);\n\n return widgetRef.current;\n}", "import React, { useId } from 'react';\nimport { useFeedbackWidget, useRoadmapWidget, useChangelogWidget, WidgetOptions } from './hooks';\n\nexport interface FeedbackWidgetProps extends Omit<WidgetOptions, 'buttonSelector'> {\n workspaceSlug: string;\n boardSlug?: string;\n children: React.ReactNode;\n className?: string;\n}\n\nexport interface RoadmapWidgetProps extends Omit<WidgetOptions, 'buttonSelector'> {\n workspaceSlug: string;\n boardSlug: string;\n children: React.ReactNode;\n className?: string;\n}\n\nexport interface ChangelogWidgetProps extends Omit<WidgetOptions, 'buttonSelector'> {\n workspaceSlug: string;\n children: React.ReactNode;\n className?: string;\n}\n\nexport function FeedbackWidget({\n workspaceSlug,\n boardSlug,\n children,\n className,\n ...options\n}: FeedbackWidgetProps) {\n const buttonId = useId();\n\n const widget = useFeedbackWidget(workspaceSlug, boardSlug, {\n ...options,\n buttonSelector: `#${buttonId}`,\n });\n\n return (\n <button\n id={buttonId}\n className={className}\n type=\"button\"\n >\n {children}\n </button>\n );\n}\n\nexport function RoadmapWidget({\n workspaceSlug,\n boardSlug,\n children,\n className,\n ...options\n}: RoadmapWidgetProps) {\n const buttonId = useId();\n\n const widget = useRoadmapWidget(workspaceSlug, boardSlug, {\n ...options,\n buttonSelector: `#${buttonId}`,\n });\n\n return (\n <button\n id={buttonId}\n className={className}\n type=\"button\"\n >\n {children}\n </button>\n );\n}\n\nexport function ChangelogWidget({\n workspaceSlug,\n children,\n className,\n ...options\n}: ChangelogWidgetProps) {\n const buttonId = useId();\n\n const widget = useChangelogWidget(workspaceSlug, {\n ...options,\n buttonSelector: `#${buttonId}`,\n });\n\n return (\n <button\n id={buttonId}\n className={className}\n type=\"button\"\n >\n {children}\n </button>\n );\n}", "// Export hooks\nexport {\n useFeedbackWidget,\n useRoadmapWidget,\n useChangelogWidget,\n useWidget,\n type WidgetOptions,\n type WidgetInstance,\n} from './hooks';\n\n// Export components\nexport {\n FeedbackWidget,\n RoadmapWidget,\n ChangelogWidget,\n type FeedbackWidgetProps,\n type RoadmapWidgetProps,\n type ChangelogWidgetProps,\n} from './components';\n\n// Re-export functions from the base widget package\nexport { \n createFeedbackWidget,\n createRoadmapWidget,\n createChangelogWidget,\n createWidget,\n} from '@squeletteapp/widget';"],
5
- "mappings": "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",
6
- "names": ["createFeedbackWidget", "createRoadmapWidget", "createChangelogWidget", "createWidget"]
3
+ "sources": ["../src/context.tsx", "../src/components/changelog-entry-modal.tsx", "../src/components/changelog-entries-list-dropdown.tsx", "../src/components/changelog-banner.tsx"],
4
+ "sourcesContent": ["'use client';\n\nimport * as React from 'react';\nimport type { ContentTheme } from './types';\n\n// Lazy-loaded types - we don't import the actual module at the top level\ntype WidgetStore = {\n getState: () => Record<string, unknown>;\n mount: (source: string, widget: unknown) => Promise<void>;\n unmount: (source: string) => void;\n open: (source: string) => Promise<void>;\n setTheme: (theme: ContentTheme) => void;\n};\n\ntype WidgetModule = {\n createChangelogStore: () => WidgetStore;\n createChangelogEntryWidget: (\n ticketId: string,\n options: { base?: string; contentTheme?: ContentTheme; slug?: string }\n ) => unknown;\n createChangelogBannerWidget: (\n store: WidgetStore,\n options: { base?: string; contentTheme?: ContentTheme; slug: string; debug?: boolean }\n ) => Promise<unknown>;\n createChangelogEntriesListDropdownWidget: (\n anchor: string,\n store: WidgetStore,\n options: { base?: string; contentTheme?: ContentTheme; slug?: string; position?: 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw' | 'center' }\n ) => unknown;\n};\n\ntype ChangelogContextValue = {\n store: WidgetStore;\n module: WidgetModule;\n theme: ContentTheme;\n base?: string;\n slug: string;\n};\n\nconst ChangelogContext = React.createContext<ChangelogContextValue | null>(null);\n\nexport interface ChangelogProviderProps {\n children: React.ReactNode;\n slug: string;\n theme?: ContentTheme;\n base?: string;\n}\n\n/**\n * ChangelogProvider - Provides changelog store and configuration to child components\n *\n * This provider handles:\n * - Creating and managing the widget store (client-side only)\n * - Syncing theme changes to all widgets\n * - Providing base URL and slug to all child components\n */\nexport function ChangelogProvider({\n children,\n slug,\n theme = 'light',\n base,\n}: ChangelogProviderProps) {\n const [context, setContext] = React.useState<{\n store: WidgetStore;\n module: WidgetModule;\n } | null>(null);\n\n // Initialize store on client side only\n React.useEffect(() => {\n import('@squeletteapp/widget').then((mod) => {\n const widgetModule = mod as unknown as WidgetModule;\n setContext({\n store: widgetModule.createChangelogStore(),\n module: widgetModule,\n });\n });\n }, []);\n\n // Update theme when it changes\n React.useEffect(() => {\n context?.store.setTheme(theme);\n }, [context, theme]);\n\n // Don't render children until store is ready (client-side only)\n if (!context) {\n return null;\n }\n\n return (\n <ChangelogContext.Provider\n value={{ store: context.store, module: context.module, theme, base, slug }}\n >\n {children}\n </ChangelogContext.Provider>\n );\n}\n\nexport function useChangelogContext(): ChangelogContextValue {\n const context = React.useContext(ChangelogContext);\n if (!context) {\n throw new Error('useChangelogContext must be used within a ChangelogProvider');\n }\n return context;\n}\n", "'use client';\n\nimport * as React from 'react';\nimport { useChangelogContext } from '../context';\n\nexport interface ChangelogEntryModalProps {\n ticketId: string;\n onOpenChange?: (isOpen: boolean) => void;\n}\n\n/**\n * ChangelogEntryModal - Renders a modal for a single changelog entry\n *\n * This component manages its own widget lifecycle and automatically\n * cleans up on unmount. Must be used within a ChangelogProvider.\n */\nexport function ChangelogEntryModal({\n ticketId,\n onOpenChange,\n}: ChangelogEntryModalProps) {\n const { store, module, theme, base, slug } = useChangelogContext();\n const widgetRef = React.useRef<{ setTheme: (t: string) => void } | null>(null);\n\n React.useEffect(() => {\n const widget = module.createChangelogEntryWidget(ticketId, {\n base,\n contentTheme: theme,\n slug,\n }) as { onOpenChange: (cb: (isOpen: boolean) => void) => void; setTheme: (t: string) => void };\n\n if (onOpenChange) {\n widget.onOpenChange(onOpenChange);\n }\n\n widgetRef.current = widget;\n store.mount(ticketId, widget);\n\n return () => {\n store.unmount(ticketId);\n widgetRef.current = null;\n };\n }, [ticketId, slug, store, module, base, onOpenChange, theme]);\n\n // Update theme when it changes\n React.useEffect(() => {\n widgetRef.current?.setTheme(theme);\n }, [theme]);\n\n return null;\n}\n", "'use client';\n\nimport * as React from 'react';\nimport { useChangelogContext } from '../context';\n\ntype Position = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw' | 'center';\n\nexport interface ChangelogEntriesListDropdownProps {\n children: React.ReactElement;\n position?: Position;\n}\n\n/**\n * ChangelogEntriesListDropdown - Renders a dropdown list of changelog entries\n *\n * This component wraps a child element (trigger) and opens the dropdown\n * when the child is clicked. Must be used within a ChangelogProvider.\n */\nexport function ChangelogEntriesListDropdown({\n children,\n position,\n}: ChangelogEntriesListDropdownProps) {\n const { store, module, theme, base, slug } = useChangelogContext();\n const widgetRef = React.useRef<{\n preload: () => void;\n open: () => void;\n destroy: () => void;\n setTheme: (t: string) => void;\n } | null>(null);\n const anchorId = React.useId();\n const cleanAnchorId = `sq-dropdown-${anchorId.replace(/:/g, '')}`;\n\n // Store initial theme in ref to use in creation\n const initialThemeRef = React.useRef(theme);\n\n // Create widget once on mount (theme changes handled separately via setTheme)\n React.useEffect(() => {\n const widget = module.createChangelogEntriesListDropdownWidget(\n `#${cleanAnchorId}`,\n store,\n {\n base,\n contentTheme: initialThemeRef.current,\n slug,\n position,\n }\n ) as {\n preload: () => void;\n open: () => void;\n destroy: () => void;\n setTheme: (t: string) => void;\n };\n\n widget.preload();\n widgetRef.current = widget;\n\n return () => {\n widget.destroy();\n widgetRef.current = null;\n };\n }, [slug, store, module, base, cleanAnchorId, position]);\n\n // Update theme when it changes (separate effect to avoid recreating widget)\n React.useEffect(() => {\n widgetRef.current?.setTheme(theme);\n }, [theme]);\n\n const handleClick = React.useCallback(() => {\n widgetRef.current?.open();\n }, []);\n\n // Clone the child and add the anchor id and click handler\n return React.cloneElement(children, {\n id: cleanAnchorId,\n onClick: (e: React.MouseEvent) => {\n const originalOnClick = children.props.onClick;\n if (originalOnClick) {\n originalOnClick(e);\n }\n handleClick();\n },\n });\n}\n", "'use client';\n\nimport * as React from 'react';\nimport { useChangelogContext } from '../context';\n\nexport interface ChangelogBannerProps {\n debug?: boolean;\n}\n\n/**\n * ChangelogBanner - Renders a banner for the latest changelog entry\n *\n * This component automatically fetches the latest changelog entry,\n * checks if it should be shown, and displays a banner at the bottom\n * of the screen. Must be used within a ChangelogProvider.\n */\nexport function ChangelogBanner({ debug = false }: ChangelogBannerProps) {\n const { store, module, theme, base, slug } = useChangelogContext();\n const widgetRef = React.useRef<{\n destroy: () => void;\n setTheme: (t: string) => void;\n } | null>(null);\n\n // Store initial theme in ref to use in creation\n const initialThemeRef = React.useRef(theme);\n\n // Create widget once on mount (theme changes handled separately via setTheme)\n React.useEffect(() => {\n let mounted = true;\n\n module\n .createChangelogBannerWidget(store, {\n base,\n contentTheme: initialThemeRef.current,\n slug,\n debug,\n })\n .then((widget) => {\n if (mounted && widget) {\n widgetRef.current = widget as {\n destroy: () => void;\n setTheme: (t: string) => void;\n };\n }\n });\n\n return () => {\n mounted = false;\n if (widgetRef.current) {\n widgetRef.current.destroy();\n widgetRef.current = null;\n }\n };\n }, [slug, store, module, base, debug]);\n\n // Update theme when it changes (separate effect to avoid recreating widget)\n React.useEffect(() => {\n widgetRef.current?.setTheme(theme);\n }, [theme]);\n\n return null;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["React", "React", "React"]
7
7
  }
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,174 +17,175 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
23
- ChangelogWidget: () => ChangelogWidget,
24
- FeedbackWidget: () => FeedbackWidget,
25
- RoadmapWidget: () => RoadmapWidget,
26
- createChangelogWidget: () => import_widget2.createChangelogWidget,
27
- createFeedbackWidget: () => import_widget2.createFeedbackWidget,
28
- createRoadmapWidget: () => import_widget2.createRoadmapWidget,
29
- createWidget: () => import_widget2.createWidget,
30
- useChangelogWidget: () => useChangelogWidget,
31
- useFeedbackWidget: () => useFeedbackWidget,
32
- useRoadmapWidget: () => useRoadmapWidget,
33
- useWidget: () => useWidget
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ChangelogBanner: () => ChangelogBanner,
34
+ ChangelogEntriesListDropdown: () => ChangelogEntriesListDropdown,
35
+ ChangelogEntryModal: () => ChangelogEntryModal,
36
+ ChangelogProvider: () => ChangelogProvider,
37
+ useChangelogContext: () => useChangelogContext
34
38
  });
35
- module.exports = __toCommonJS(src_exports);
39
+ module.exports = __toCommonJS(index_exports);
36
40
 
37
- // src/hooks.ts
38
- var import_react = require("react");
39
- var import_widget = require("@squeletteapp/widget");
40
- function useFeedbackWidget(workspaceSlug, boardSlug, options) {
41
- const widgetRef = (0, import_react.useRef)(null);
42
- const initWidget = (0, import_react.useCallback)(() => {
43
- if (widgetRef.current) {
44
- widgetRef.current.destroy();
45
- }
46
- widgetRef.current = (0, import_widget.createFeedbackWidget)(workspaceSlug, boardSlug, options);
47
- return widgetRef.current;
48
- }, [workspaceSlug, boardSlug, options]);
49
- (0, import_react.useEffect)(() => {
50
- const widget = initWidget();
51
- return () => {
52
- if (widget) {
53
- widget.destroy();
54
- }
55
- };
56
- }, [initWidget]);
57
- return widgetRef.current;
58
- }
59
- function useRoadmapWidget(workspaceSlug, boardSlug, options) {
60
- const widgetRef = (0, import_react.useRef)(null);
61
- const initWidget = (0, import_react.useCallback)(() => {
62
- if (widgetRef.current) {
63
- widgetRef.current.destroy();
64
- }
65
- widgetRef.current = (0, import_widget.createRoadmapWidget)(workspaceSlug, boardSlug, options);
66
- return widgetRef.current;
67
- }, [workspaceSlug, boardSlug, options]);
68
- (0, import_react.useEffect)(() => {
69
- const widget = initWidget();
70
- return () => {
71
- if (widget) {
72
- widget.destroy();
73
- }
74
- };
75
- }, [initWidget]);
76
- return widgetRef.current;
77
- }
78
- function useChangelogWidget(workspaceSlug, options) {
79
- const widgetRef = (0, import_react.useRef)(null);
80
- const initWidget = (0, import_react.useCallback)(() => {
81
- if (widgetRef.current) {
82
- widgetRef.current.destroy();
83
- }
84
- widgetRef.current = (0, import_widget.createChangelogWidget)(workspaceSlug, options);
85
- return widgetRef.current;
86
- }, [workspaceSlug, options]);
87
- (0, import_react.useEffect)(() => {
88
- const widget = initWidget();
89
- return () => {
90
- if (widget) {
91
- widget.destroy();
92
- }
93
- };
94
- }, [initWidget]);
95
- return widgetRef.current;
96
- }
97
- function useWidget(options) {
98
- const widgetRef = (0, import_react.useRef)(null);
99
- const initWidget = (0, import_react.useCallback)(() => {
100
- if (widgetRef.current) {
101
- widgetRef.current.destroy();
102
- }
103
- widgetRef.current = (0, import_widget.createWidget)(options);
104
- return widgetRef.current;
105
- }, [options]);
106
- (0, import_react.useEffect)(() => {
107
- const widget = initWidget();
108
- return () => {
109
- if (widget) {
110
- widget.destroy();
111
- }
112
- };
113
- }, [initWidget]);
114
- return widgetRef.current;
115
- }
116
-
117
- // src/components.tsx
118
- var import_react2 = require("react");
41
+ // src/context.tsx
42
+ var React = __toESM(require("react"), 1);
119
43
  var import_jsx_runtime = require("react/jsx-runtime");
120
- function FeedbackWidget({
121
- workspaceSlug,
122
- boardSlug,
44
+ var ChangelogContext = React.createContext(null);
45
+ function ChangelogProvider({
123
46
  children,
124
- className,
125
- ...options
47
+ slug,
48
+ theme = "light",
49
+ base
126
50
  }) {
127
- const buttonId = (0, import_react2.useId)();
128
- const widget = useFeedbackWidget(workspaceSlug, boardSlug, {
129
- ...options,
130
- buttonSelector: `#${buttonId}`
131
- });
51
+ const [context, setContext] = React.useState(null);
52
+ React.useEffect(() => {
53
+ import("@squeletteapp/widget").then((mod) => {
54
+ const widgetModule = mod;
55
+ setContext({
56
+ store: widgetModule.createChangelogStore(),
57
+ module: widgetModule
58
+ });
59
+ });
60
+ }, []);
61
+ React.useEffect(() => {
62
+ context?.store.setTheme(theme);
63
+ }, [context, theme]);
64
+ if (!context) {
65
+ return null;
66
+ }
132
67
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
133
- "button",
68
+ ChangelogContext.Provider,
134
69
  {
135
- id: buttonId,
136
- className,
137
- type: "button",
70
+ value: { store: context.store, module: context.module, theme, base, slug },
138
71
  children
139
72
  }
140
73
  );
141
74
  }
142
- function RoadmapWidget({
143
- workspaceSlug,
144
- boardSlug,
145
- children,
146
- className,
147
- ...options
75
+ function useChangelogContext() {
76
+ const context = React.useContext(ChangelogContext);
77
+ if (!context) {
78
+ throw new Error("useChangelogContext must be used within a ChangelogProvider");
79
+ }
80
+ return context;
81
+ }
82
+
83
+ // src/components/changelog-entry-modal.tsx
84
+ var React2 = __toESM(require("react"), 1);
85
+ function ChangelogEntryModal({
86
+ ticketId,
87
+ onOpenChange
148
88
  }) {
149
- const buttonId = (0, import_react2.useId)();
150
- const widget = useRoadmapWidget(workspaceSlug, boardSlug, {
151
- ...options,
152
- buttonSelector: `#${buttonId}`
153
- });
154
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
155
- "button",
156
- {
157
- id: buttonId,
158
- className,
159
- type: "button",
160
- children
89
+ const { store, module: module2, theme, base, slug } = useChangelogContext();
90
+ const widgetRef = React2.useRef(null);
91
+ React2.useEffect(() => {
92
+ const widget = module2.createChangelogEntryWidget(ticketId, {
93
+ base,
94
+ contentTheme: theme,
95
+ slug
96
+ });
97
+ if (onOpenChange) {
98
+ widget.onOpenChange(onOpenChange);
161
99
  }
162
- );
100
+ widgetRef.current = widget;
101
+ store.mount(ticketId, widget);
102
+ return () => {
103
+ store.unmount(ticketId);
104
+ widgetRef.current = null;
105
+ };
106
+ }, [ticketId, slug, store, module2, base, onOpenChange, theme]);
107
+ React2.useEffect(() => {
108
+ widgetRef.current?.setTheme(theme);
109
+ }, [theme]);
110
+ return null;
163
111
  }
164
- function ChangelogWidget({
165
- workspaceSlug,
112
+
113
+ // src/components/changelog-entries-list-dropdown.tsx
114
+ var React3 = __toESM(require("react"), 1);
115
+ function ChangelogEntriesListDropdown({
166
116
  children,
167
- className,
168
- ...options
117
+ position
169
118
  }) {
170
- const buttonId = (0, import_react2.useId)();
171
- const widget = useChangelogWidget(workspaceSlug, {
172
- ...options,
173
- buttonSelector: `#${buttonId}`
174
- });
175
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
176
- "button",
177
- {
178
- id: buttonId,
179
- className,
180
- type: "button",
181
- children
119
+ const { store, module: module2, theme, base, slug } = useChangelogContext();
120
+ const widgetRef = React3.useRef(null);
121
+ const anchorId = React3.useId();
122
+ const cleanAnchorId = `sq-dropdown-${anchorId.replace(/:/g, "")}`;
123
+ const initialThemeRef = React3.useRef(theme);
124
+ React3.useEffect(() => {
125
+ const widget = module2.createChangelogEntriesListDropdownWidget(
126
+ `#${cleanAnchorId}`,
127
+ store,
128
+ {
129
+ base,
130
+ contentTheme: initialThemeRef.current,
131
+ slug,
132
+ position
133
+ }
134
+ );
135
+ widget.preload();
136
+ widgetRef.current = widget;
137
+ return () => {
138
+ widget.destroy();
139
+ widgetRef.current = null;
140
+ };
141
+ }, [slug, store, module2, base, cleanAnchorId, position]);
142
+ React3.useEffect(() => {
143
+ widgetRef.current?.setTheme(theme);
144
+ }, [theme]);
145
+ const handleClick = React3.useCallback(() => {
146
+ widgetRef.current?.open();
147
+ }, []);
148
+ return React3.cloneElement(children, {
149
+ id: cleanAnchorId,
150
+ onClick: (e) => {
151
+ const originalOnClick = children.props.onClick;
152
+ if (originalOnClick) {
153
+ originalOnClick(e);
154
+ }
155
+ handleClick();
182
156
  }
183
- );
157
+ });
184
158
  }
185
159
 
186
- // src/index.ts
187
- var import_widget2 = require("@squeletteapp/widget");
160
+ // src/components/changelog-banner.tsx
161
+ var React4 = __toESM(require("react"), 1);
162
+ function ChangelogBanner({ debug = false }) {
163
+ const { store, module: module2, theme, base, slug } = useChangelogContext();
164
+ const widgetRef = React4.useRef(null);
165
+ const initialThemeRef = React4.useRef(theme);
166
+ React4.useEffect(() => {
167
+ let mounted = true;
168
+ module2.createChangelogBannerWidget(store, {
169
+ base,
170
+ contentTheme: initialThemeRef.current,
171
+ slug,
172
+ debug
173
+ }).then((widget) => {
174
+ if (mounted && widget) {
175
+ widgetRef.current = widget;
176
+ }
177
+ });
178
+ return () => {
179
+ mounted = false;
180
+ if (widgetRef.current) {
181
+ widgetRef.current.destroy();
182
+ widgetRef.current = null;
183
+ }
184
+ };
185
+ }, [slug, store, module2, base, debug]);
186
+ React4.useEffect(() => {
187
+ widgetRef.current?.setTheme(theme);
188
+ }, [theme]);
189
+ return null;
190
+ }
188
191
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/index.ts", "../src/hooks.ts", "../src/components.tsx"],
4
- "sourcesContent": ["// Export hooks\nexport {\n useFeedbackWidget,\n useRoadmapWidget,\n useChangelogWidget,\n useWidget,\n type WidgetOptions,\n type WidgetInstance,\n} from './hooks';\n\n// Export components\nexport {\n FeedbackWidget,\n RoadmapWidget,\n ChangelogWidget,\n type FeedbackWidgetProps,\n type RoadmapWidgetProps,\n type ChangelogWidgetProps,\n} from './components';\n\n// Re-export functions from the base widget package\nexport { \n createFeedbackWidget,\n createRoadmapWidget,\n createChangelogWidget,\n createWidget,\n} from '@squeletteapp/widget';", "import { useEffect, useRef, useCallback } from 'react';\nimport { \n createFeedbackWidget, \n createRoadmapWidget, \n createChangelogWidget,\n createWidget\n} from '@squeletteapp/widget';\n\nexport interface WidgetOptions {\n buttonSelector: string;\n position?: 'top' | 'bottom' | 'left' | 'right';\n theme?: string;\n onLoad?: () => void;\n onOpenChange?: (isOpen: boolean) => void;\n}\n\nexport interface WidgetInstance {\n destroy: () => void;\n}\n\nexport function useFeedbackWidget(\n workspaceSlug: string,\n boardSlug: string | undefined,\n options: WidgetOptions\n): WidgetInstance | null {\n const widgetRef = useRef<WidgetInstance | null>(null);\n\n const initWidget = useCallback(() => {\n if (widgetRef.current) {\n widgetRef.current.destroy();\n }\n \n widgetRef.current = createFeedbackWidget(workspaceSlug, boardSlug, options);\n return widgetRef.current;\n }, [workspaceSlug, boardSlug, options]);\n\n useEffect(() => {\n const widget = initWidget();\n \n return () => {\n if (widget) {\n widget.destroy();\n }\n };\n }, [initWidget]);\n\n return widgetRef.current;\n}\n\nexport function useRoadmapWidget(\n workspaceSlug: string,\n boardSlug: string,\n options: WidgetOptions\n): WidgetInstance | null {\n const widgetRef = useRef<WidgetInstance | null>(null);\n\n const initWidget = useCallback(() => {\n if (widgetRef.current) {\n widgetRef.current.destroy();\n }\n \n widgetRef.current = createRoadmapWidget(workspaceSlug, boardSlug, options);\n return widgetRef.current;\n }, [workspaceSlug, boardSlug, options]);\n\n useEffect(() => {\n const widget = initWidget();\n \n return () => {\n if (widget) {\n widget.destroy();\n }\n };\n }, [initWidget]);\n\n return widgetRef.current;\n}\n\nexport function useChangelogWidget(\n workspaceSlug: string,\n options: WidgetOptions\n): WidgetInstance | null {\n const widgetRef = useRef<WidgetInstance | null>(null);\n\n const initWidget = useCallback(() => {\n if (widgetRef.current) {\n widgetRef.current.destroy();\n }\n \n widgetRef.current = createChangelogWidget(workspaceSlug, options);\n return widgetRef.current;\n }, [workspaceSlug, options]);\n\n useEffect(() => {\n const widget = initWidget();\n \n return () => {\n if (widget) {\n widget.destroy();\n }\n };\n }, [initWidget]);\n\n return widgetRef.current;\n}\n\nexport function useWidget(options: {\n url: string;\n buttonSelector: string;\n position?: 'top' | 'bottom' | 'left' | 'right';\n onLoad?: () => void;\n onOpenChange?: (isOpen: boolean) => void;\n}): WidgetInstance | null {\n const widgetRef = useRef<WidgetInstance | null>(null);\n\n const initWidget = useCallback(() => {\n if (widgetRef.current) {\n widgetRef.current.destroy();\n }\n \n widgetRef.current = createWidget(options);\n return widgetRef.current;\n }, [options]);\n\n useEffect(() => {\n const widget = initWidget();\n \n return () => {\n if (widget) {\n widget.destroy();\n }\n };\n }, [initWidget]);\n\n return widgetRef.current;\n}", "import React, { useId } from 'react';\nimport { useFeedbackWidget, useRoadmapWidget, useChangelogWidget, WidgetOptions } from './hooks';\n\nexport interface FeedbackWidgetProps extends Omit<WidgetOptions, 'buttonSelector'> {\n workspaceSlug: string;\n boardSlug?: string;\n children: React.ReactNode;\n className?: string;\n}\n\nexport interface RoadmapWidgetProps extends Omit<WidgetOptions, 'buttonSelector'> {\n workspaceSlug: string;\n boardSlug: string;\n children: React.ReactNode;\n className?: string;\n}\n\nexport interface ChangelogWidgetProps extends Omit<WidgetOptions, 'buttonSelector'> {\n workspaceSlug: string;\n children: React.ReactNode;\n className?: string;\n}\n\nexport function FeedbackWidget({\n workspaceSlug,\n boardSlug,\n children,\n className,\n ...options\n}: FeedbackWidgetProps) {\n const buttonId = useId();\n\n const widget = useFeedbackWidget(workspaceSlug, boardSlug, {\n ...options,\n buttonSelector: `#${buttonId}`,\n });\n\n return (\n <button\n id={buttonId}\n className={className}\n type=\"button\"\n >\n {children}\n </button>\n );\n}\n\nexport function RoadmapWidget({\n workspaceSlug,\n boardSlug,\n children,\n className,\n ...options\n}: RoadmapWidgetProps) {\n const buttonId = useId();\n\n const widget = useRoadmapWidget(workspaceSlug, boardSlug, {\n ...options,\n buttonSelector: `#${buttonId}`,\n });\n\n return (\n <button\n id={buttonId}\n className={className}\n type=\"button\"\n >\n {children}\n </button>\n );\n}\n\nexport function ChangelogWidget({\n workspaceSlug,\n children,\n className,\n ...options\n}: ChangelogWidgetProps) {\n const buttonId = useId();\n\n const widget = useChangelogWidget(workspaceSlug, {\n ...options,\n buttonSelector: `#${buttonId}`,\n });\n\n return (\n <button\n id={buttonId}\n className={className}\n type=\"button\"\n >\n {children}\n </button>\n );\n}"],
5
- "mappings": "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",
6
- "names": ["import_react", "import_widget"]
3
+ "sources": ["../src/index.ts", "../src/context.tsx", "../src/components/changelog-entry-modal.tsx", "../src/components/changelog-entries-list-dropdown.tsx", "../src/components/changelog-banner.tsx"],
4
+ "sourcesContent": ["// Export Provider and context hook\nexport {\n ChangelogProvider,\n useChangelogContext,\n type ChangelogProviderProps,\n} from './context';\n\n// Export React components\nexport {\n ChangelogEntryModal,\n type ChangelogEntryModalProps,\n} from './components/changelog-entry-modal';\n\nexport {\n ChangelogEntriesListDropdown,\n type ChangelogEntriesListDropdownProps,\n} from './components/changelog-entries-list-dropdown';\n\nexport {\n ChangelogBanner,\n type ChangelogBannerProps,\n} from './components/changelog-banner';\n\n// Export types\nexport type { ContentTheme } from './types';\n", "'use client';\n\nimport * as React from 'react';\nimport type { ContentTheme } from './types';\n\n// Lazy-loaded types - we don't import the actual module at the top level\ntype WidgetStore = {\n getState: () => Record<string, unknown>;\n mount: (source: string, widget: unknown) => Promise<void>;\n unmount: (source: string) => void;\n open: (source: string) => Promise<void>;\n setTheme: (theme: ContentTheme) => void;\n};\n\ntype WidgetModule = {\n createChangelogStore: () => WidgetStore;\n createChangelogEntryWidget: (\n ticketId: string,\n options: { base?: string; contentTheme?: ContentTheme; slug?: string }\n ) => unknown;\n createChangelogBannerWidget: (\n store: WidgetStore,\n options: { base?: string; contentTheme?: ContentTheme; slug: string; debug?: boolean }\n ) => Promise<unknown>;\n createChangelogEntriesListDropdownWidget: (\n anchor: string,\n store: WidgetStore,\n options: { base?: string; contentTheme?: ContentTheme; slug?: string; position?: 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw' | 'center' }\n ) => unknown;\n};\n\ntype ChangelogContextValue = {\n store: WidgetStore;\n module: WidgetModule;\n theme: ContentTheme;\n base?: string;\n slug: string;\n};\n\nconst ChangelogContext = React.createContext<ChangelogContextValue | null>(null);\n\nexport interface ChangelogProviderProps {\n children: React.ReactNode;\n slug: string;\n theme?: ContentTheme;\n base?: string;\n}\n\n/**\n * ChangelogProvider - Provides changelog store and configuration to child components\n *\n * This provider handles:\n * - Creating and managing the widget store (client-side only)\n * - Syncing theme changes to all widgets\n * - Providing base URL and slug to all child components\n */\nexport function ChangelogProvider({\n children,\n slug,\n theme = 'light',\n base,\n}: ChangelogProviderProps) {\n const [context, setContext] = React.useState<{\n store: WidgetStore;\n module: WidgetModule;\n } | null>(null);\n\n // Initialize store on client side only\n React.useEffect(() => {\n import('@squeletteapp/widget').then((mod) => {\n const widgetModule = mod as unknown as WidgetModule;\n setContext({\n store: widgetModule.createChangelogStore(),\n module: widgetModule,\n });\n });\n }, []);\n\n // Update theme when it changes\n React.useEffect(() => {\n context?.store.setTheme(theme);\n }, [context, theme]);\n\n // Don't render children until store is ready (client-side only)\n if (!context) {\n return null;\n }\n\n return (\n <ChangelogContext.Provider\n value={{ store: context.store, module: context.module, theme, base, slug }}\n >\n {children}\n </ChangelogContext.Provider>\n );\n}\n\nexport function useChangelogContext(): ChangelogContextValue {\n const context = React.useContext(ChangelogContext);\n if (!context) {\n throw new Error('useChangelogContext must be used within a ChangelogProvider');\n }\n return context;\n}\n", "'use client';\n\nimport * as React from 'react';\nimport { useChangelogContext } from '../context';\n\nexport interface ChangelogEntryModalProps {\n ticketId: string;\n onOpenChange?: (isOpen: boolean) => void;\n}\n\n/**\n * ChangelogEntryModal - Renders a modal for a single changelog entry\n *\n * This component manages its own widget lifecycle and automatically\n * cleans up on unmount. Must be used within a ChangelogProvider.\n */\nexport function ChangelogEntryModal({\n ticketId,\n onOpenChange,\n}: ChangelogEntryModalProps) {\n const { store, module, theme, base, slug } = useChangelogContext();\n const widgetRef = React.useRef<{ setTheme: (t: string) => void } | null>(null);\n\n React.useEffect(() => {\n const widget = module.createChangelogEntryWidget(ticketId, {\n base,\n contentTheme: theme,\n slug,\n }) as { onOpenChange: (cb: (isOpen: boolean) => void) => void; setTheme: (t: string) => void };\n\n if (onOpenChange) {\n widget.onOpenChange(onOpenChange);\n }\n\n widgetRef.current = widget;\n store.mount(ticketId, widget);\n\n return () => {\n store.unmount(ticketId);\n widgetRef.current = null;\n };\n }, [ticketId, slug, store, module, base, onOpenChange, theme]);\n\n // Update theme when it changes\n React.useEffect(() => {\n widgetRef.current?.setTheme(theme);\n }, [theme]);\n\n return null;\n}\n", "'use client';\n\nimport * as React from 'react';\nimport { useChangelogContext } from '../context';\n\ntype Position = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw' | 'center';\n\nexport interface ChangelogEntriesListDropdownProps {\n children: React.ReactElement;\n position?: Position;\n}\n\n/**\n * ChangelogEntriesListDropdown - Renders a dropdown list of changelog entries\n *\n * This component wraps a child element (trigger) and opens the dropdown\n * when the child is clicked. Must be used within a ChangelogProvider.\n */\nexport function ChangelogEntriesListDropdown({\n children,\n position,\n}: ChangelogEntriesListDropdownProps) {\n const { store, module, theme, base, slug } = useChangelogContext();\n const widgetRef = React.useRef<{\n preload: () => void;\n open: () => void;\n destroy: () => void;\n setTheme: (t: string) => void;\n } | null>(null);\n const anchorId = React.useId();\n const cleanAnchorId = `sq-dropdown-${anchorId.replace(/:/g, '')}`;\n\n // Store initial theme in ref to use in creation\n const initialThemeRef = React.useRef(theme);\n\n // Create widget once on mount (theme changes handled separately via setTheme)\n React.useEffect(() => {\n const widget = module.createChangelogEntriesListDropdownWidget(\n `#${cleanAnchorId}`,\n store,\n {\n base,\n contentTheme: initialThemeRef.current,\n slug,\n position,\n }\n ) as {\n preload: () => void;\n open: () => void;\n destroy: () => void;\n setTheme: (t: string) => void;\n };\n\n widget.preload();\n widgetRef.current = widget;\n\n return () => {\n widget.destroy();\n widgetRef.current = null;\n };\n }, [slug, store, module, base, cleanAnchorId, position]);\n\n // Update theme when it changes (separate effect to avoid recreating widget)\n React.useEffect(() => {\n widgetRef.current?.setTheme(theme);\n }, [theme]);\n\n const handleClick = React.useCallback(() => {\n widgetRef.current?.open();\n }, []);\n\n // Clone the child and add the anchor id and click handler\n return React.cloneElement(children, {\n id: cleanAnchorId,\n onClick: (e: React.MouseEvent) => {\n const originalOnClick = children.props.onClick;\n if (originalOnClick) {\n originalOnClick(e);\n }\n handleClick();\n },\n });\n}\n", "'use client';\n\nimport * as React from 'react';\nimport { useChangelogContext } from '../context';\n\nexport interface ChangelogBannerProps {\n debug?: boolean;\n}\n\n/**\n * ChangelogBanner - Renders a banner for the latest changelog entry\n *\n * This component automatically fetches the latest changelog entry,\n * checks if it should be shown, and displays a banner at the bottom\n * of the screen. Must be used within a ChangelogProvider.\n */\nexport function ChangelogBanner({ debug = false }: ChangelogBannerProps) {\n const { store, module, theme, base, slug } = useChangelogContext();\n const widgetRef = React.useRef<{\n destroy: () => void;\n setTheme: (t: string) => void;\n } | null>(null);\n\n // Store initial theme in ref to use in creation\n const initialThemeRef = React.useRef(theme);\n\n // Create widget once on mount (theme changes handled separately via setTheme)\n React.useEffect(() => {\n let mounted = true;\n\n module\n .createChangelogBannerWidget(store, {\n base,\n contentTheme: initialThemeRef.current,\n slug,\n debug,\n })\n .then((widget) => {\n if (mounted && widget) {\n widgetRef.current = widget as {\n destroy: () => void;\n setTheme: (t: string) => void;\n };\n }\n });\n\n return () => {\n mounted = false;\n if (widgetRef.current) {\n widgetRef.current.destroy();\n widgetRef.current = null;\n }\n };\n }, [slug, store, module, base, debug]);\n\n // Update theme when it changes (separate effect to avoid recreating widget)\n React.useEffect(() => {\n widgetRef.current?.setTheme(theme);\n }, [theme]);\n\n return null;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["React", "module", "React", "module", "React", "module"]
7
7
  }
@@ -0,0 +1 @@
1
+ export type ContentTheme = 'light' | 'dark';
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@squeletteapp/widget-react",
3
3
  "type": "module",
4
- "version": "0.1.0",
5
- "description": "React components and hooks for Squelette widgets",
4
+ "version": "1.0.0",
5
+ "description": "React components for Squelette changelog widgets",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "exports": {
@@ -17,28 +17,31 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "build": "tsc && node build.js",
20
- "dev": "tsc --watch",
20
+ "dev": "node dev.js",
21
21
  "prepublishOnly": "npm run build",
22
+ "publish": "npm publish --access public",
22
23
  "publish:widget-react": "npm publish --access public"
23
24
  },
24
25
  "peerDependencies": {
25
26
  "react": ">=16.8.0"
26
27
  },
27
28
  "dependencies": {
28
- "@squeletteapp/widget": "^0.1.0"
29
+ "@squeletteapp/widget": "1.0.0"
29
30
  },
30
31
  "devDependencies": {
31
32
  "@types/react": "^18.0.0",
32
33
  "react": "^18.0.0",
33
- "esbuild": "^0.21.5",
34
+ "esbuild": "^0.25.8",
34
35
  "typescript": "^5.8.3"
35
36
  },
36
37
  "keywords": [
37
38
  "react",
38
39
  "widget",
39
- "feedback",
40
+ "changelog",
40
41
  "squelette"
41
42
  ],
42
43
  "author": "Squelette",
43
- "license": "MIT"
44
+ "publishConfig": {
45
+ "access": "public"
46
+ }
44
47
  }
@@ -1,22 +0,0 @@
1
- import React from 'react';
2
- import { WidgetOptions } from './hooks';
3
- export interface FeedbackWidgetProps extends Omit<WidgetOptions, 'buttonSelector'> {
4
- workspaceSlug: string;
5
- boardSlug?: string;
6
- children: React.ReactNode;
7
- className?: string;
8
- }
9
- export interface RoadmapWidgetProps extends Omit<WidgetOptions, 'buttonSelector'> {
10
- workspaceSlug: string;
11
- boardSlug: string;
12
- children: React.ReactNode;
13
- className?: string;
14
- }
15
- export interface ChangelogWidgetProps extends Omit<WidgetOptions, 'buttonSelector'> {
16
- workspaceSlug: string;
17
- children: React.ReactNode;
18
- className?: string;
19
- }
20
- export declare function FeedbackWidget({ workspaceSlug, boardSlug, children, className, ...options }: FeedbackWidgetProps): import("react/jsx-runtime").JSX.Element;
21
- export declare function RoadmapWidget({ workspaceSlug, boardSlug, children, className, ...options }: RoadmapWidgetProps): import("react/jsx-runtime").JSX.Element;
22
- export declare function ChangelogWidget({ workspaceSlug, children, className, ...options }: ChangelogWidgetProps): import("react/jsx-runtime").JSX.Element;
@@ -1,27 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useId } from 'react';
3
- import { useFeedbackWidget, useRoadmapWidget, useChangelogWidget } from './hooks';
4
- export function FeedbackWidget({ workspaceSlug, boardSlug, children, className, ...options }) {
5
- const buttonId = useId();
6
- const widget = useFeedbackWidget(workspaceSlug, boardSlug, {
7
- ...options,
8
- buttonSelector: `#${buttonId}`,
9
- });
10
- return (_jsx("button", { id: buttonId, className: className, type: "button", children: children }));
11
- }
12
- export function RoadmapWidget({ workspaceSlug, boardSlug, children, className, ...options }) {
13
- const buttonId = useId();
14
- const widget = useRoadmapWidget(workspaceSlug, boardSlug, {
15
- ...options,
16
- buttonSelector: `#${buttonId}`,
17
- });
18
- return (_jsx("button", { id: buttonId, className: className, type: "button", children: children }));
19
- }
20
- export function ChangelogWidget({ workspaceSlug, children, className, ...options }) {
21
- const buttonId = useId();
22
- const widget = useChangelogWidget(workspaceSlug, {
23
- ...options,
24
- buttonSelector: `#${buttonId}`,
25
- });
26
- return (_jsx("button", { id: buttonId, className: className, type: "button", children: children }));
27
- }