@lovable-widgets/core 0.1.0 → 1.0.1

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 ADDED
@@ -0,0 +1,27 @@
1
+ # @lovable-widgets/core
2
+
3
+ The official SDK for building Lovable-compatible widgets.
4
+
5
+ ## Install
6
+ ```bash
7
+ npm install @lovable-widgets/core
8
+ ```
9
+
10
+ ## Usage
11
+ ```tsx
12
+ import { createWidget, WidgetCard, WidgetHeader, WidgetButton } from '@lovable-widgets/core';
13
+ import '@lovable-widgets/core/styles.css';
14
+
15
+ const MyWidgetInner = ({ title }) => (
16
+ <WidgetCard>
17
+ <WidgetHeader title={title} />
18
+ <WidgetButton>Click me</WidgetButton>
19
+ </WidgetCard>
20
+ );
21
+
22
+ export default createWidget({
23
+ meta: { name: 'my-widget', version: '1.0.0', description: '...', author: '...', category: 'ui', tags: [] },
24
+ component: MyWidgetInner,
25
+ propDefs: [{ name: 'title', type: 'string', required: true, description: 'Widget title' }],
26
+ }).component;
27
+ ```
package/dist/index.d.ts CHANGED
@@ -1,9 +1,19 @@
1
- export { createWidget } from './createWidget';
2
- export { useWidgetContext } from './context';
3
- export { useWidgetTheme, useWidgetId, useWidgetSecrets, useWidgetStatus, useWidgetEmit, useWidgetListener } from './hooks';
4
- export { registerWidget, getWidget, listWidgets, unregisterWidget, clearRegistry } from './registry';
5
- export { emitWidgetEvent, onWidgetEvent } from './events';
6
- export { WidgetErrorBoundary } from './errorBoundary';
7
- export { provideSecrets } from './provideSecrets';
8
- export { mountWidget, unmountWidget } from './mount';
9
- export type { WidgetSecretDef, WidgetMeta, WidgetConfig, WidgetPropDef, WidgetDefinition, CreateWidgetConfig, WidgetLifecycle, ThemeTokens, WidgetContextValue, WidgetEventType, WidgetEvent } from './types';
1
+ import { ComponentType, ForwardRefExoticComponent, ReactNode, HTMLAttributes, ButtonHTMLAttributes } from 'react';
2
+ export interface WidgetMeta { name: string; version: string; description: string; author: string; category: 'ui' | 'commerce' | 'navigation' | 'social-proof' | 'data' | 'forms' | 'media' | 'layout'; tags: string[]; icon?: string; }
3
+ export interface WidgetPropDef { name: string; type: string; required: boolean; default?: string; description: string; }
4
+ export interface WidgetDefinition<P = any> { component: ComponentType<P>; meta: WidgetMeta; propDefs: WidgetPropDef[]; __LOVABLE_WIDGET__: true; }
5
+ export interface CreateWidgetConfig<P> { meta: WidgetMeta; component: ComponentType<P>; propDefs: WidgetPropDef[]; }
6
+ export interface ThemeTokens { background: string; foreground: string; card: string; cardForeground: string; primary: string; primaryForeground: string; secondary: string; secondaryForeground: string; muted: string; mutedForeground: string; accent: string; accentForeground: string; destructive: string; destructiveForeground: string; border: string; ring: string; radius: string; }
7
+ export function createWidget<P extends Record<string, any>>(config: CreateWidgetConfig<P>): WidgetDefinition<P>;
8
+ export function useWidgetTheme(): ThemeTokens;
9
+ export function useWidgetId(prefix?: string): string;
10
+ export interface WidgetCardProps extends HTMLAttributes<HTMLDivElement> { children: ReactNode; noPadding?: boolean; }
11
+ export declare const WidgetCard: React.FC<WidgetCardProps>;
12
+ export interface WidgetHeaderProps extends HTMLAttributes<HTMLDivElement> { title: string; subtitle?: string; children?: ReactNode; }
13
+ export declare const WidgetHeader: React.FC<WidgetHeaderProps>;
14
+ export interface WidgetButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { variant?: 'primary' | 'secondary' | 'ghost' | 'destructive'; size?: 'sm' | 'md' | 'lg'; }
15
+ export declare const WidgetButton: React.FC<WidgetButtonProps>;
16
+ export interface WidgetBadgeProps extends HTMLAttributes<HTMLSpanElement> { variant?: 'default' | 'primary' | 'success' | 'warning' | 'destructive'; }
17
+ export declare const WidgetBadge: React.FC<WidgetBadgeProps>;
18
+ export interface WidgetDividerProps { className?: string; }
19
+ export declare const WidgetDivider: React.FC<WidgetDividerProps>;
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+ const react = require('react');
3
+ function createWidget(config) { const { meta, component: Component, propDefs } = config; const WrappedComponent = react.forwardRef((props, ref) => { const { className = "", ...rest } = props; return react.createElement("div", { ref, className: ("lw-widget lw-widget-" + meta.name + " " + className).trim(), "data-lw-widget": meta.name, "data-lw-version": meta.version }, react.createElement(Component, rest)); }); WrappedComponent.displayName = "LovableWidget(" + meta.name + ")"; return { component: WrappedComponent, meta, propDefs, __LOVABLE_WIDGET__: true }; }
4
+ function useWidgetTheme() { return react.useMemo(() => { const get = (name) => { if (typeof window === "undefined") return ""; return getComputedStyle(document.documentElement).getPropertyValue("--" + name).trim(); }; return { background: get("background"), foreground: get("foreground"), card: get("card"), cardForeground: get("card-foreground"), primary: get("primary"), primaryForeground: get("primary-foreground"), secondary: get("secondary"), secondaryForeground: get("secondary-foreground"), muted: get("muted"), mutedForeground: get("muted-foreground"), accent: get("accent"), accentForeground: get("accent-foreground"), destructive: get("destructive"), destructiveForeground: get("destructive-foreground"), border: get("border"), ring: get("ring"), radius: get("radius") }; }, []); }
5
+ let idCounter = 0;
6
+ function useWidgetId(prefix) { return react.useMemo(() => { idCounter += 1; return (prefix || "lw") + "-" + idCounter; }, [prefix]); }
7
+ function WidgetCard({ children, noPadding, className = "", ...props }) { return react.createElement("div", { className: ("lw-card " + (noPadding ? "lw-card--no-padding " : "") + className).trim(), ...props }, children); }
8
+ function WidgetHeader({ title, subtitle, children, className = "", ...props }) { return react.createElement("div", { className: ("lw-header " + className).trim(), ...props }, react.createElement("div", null, react.createElement("h3", { className: "lw-header__title" }, title), subtitle && react.createElement("p", { className: "lw-header__subtitle" }, subtitle)), children && react.createElement("div", { className: "lw-header__actions" }, children)); }
9
+ function WidgetButton({ children, variant = "primary", size = "md", className = "", ...props }) { return react.createElement("button", { className: ("lw-btn lw-btn--" + variant + " lw-btn--" + size + " " + className).trim(), ...props }, children); }
10
+ function WidgetBadge({ children, variant = "default", className = "", ...props }) { return react.createElement("span", { className: ("lw-badge lw-badge--" + variant + " " + className).trim(), ...props }, children); }
11
+ function WidgetDivider({ className = "" }) { return react.createElement("hr", { className: ("lw-divider " + className).trim() }); }
12
+ exports.createWidget = createWidget; exports.useWidgetTheme = useWidgetTheme; exports.useWidgetId = useWidgetId; exports.WidgetCard = WidgetCard; exports.WidgetHeader = WidgetHeader; exports.WidgetButton = WidgetButton; exports.WidgetBadge = WidgetBadge; exports.WidgetDivider = WidgetDivider;
package/dist/index.mjs ADDED
@@ -0,0 +1,29 @@
1
+ import { forwardRef, createElement, useMemo } from 'react';
2
+
3
+ function createWidget(config) {
4
+ const { meta, component: Component, propDefs } = config;
5
+ const WrappedComponent = forwardRef((props, ref) => {
6
+ const { className = "", ...rest } = props;
7
+ return createElement("div", { ref, className: ("lw-widget lw-widget-" + meta.name + " " + className).trim(), "data-lw-widget": meta.name, "data-lw-version": meta.version }, createElement(Component, rest));
8
+ });
9
+ WrappedComponent.displayName = "LovableWidget(" + meta.name + ")";
10
+ return { component: WrappedComponent, meta, propDefs, __LOVABLE_WIDGET__: true };
11
+ }
12
+
13
+ function useWidgetTheme() {
14
+ return useMemo(() => {
15
+ const get = (name) => { if (typeof window === "undefined") return ""; return getComputedStyle(document.documentElement).getPropertyValue("--" + name).trim(); };
16
+ return { background: get("background"), foreground: get("foreground"), card: get("card"), cardForeground: get("card-foreground"), primary: get("primary"), primaryForeground: get("primary-foreground"), secondary: get("secondary"), secondaryForeground: get("secondary-foreground"), muted: get("muted"), mutedForeground: get("muted-foreground"), accent: get("accent"), accentForeground: get("accent-foreground"), destructive: get("destructive"), destructiveForeground: get("destructive-foreground"), border: get("border"), ring: get("ring"), radius: get("radius") };
17
+ }, []);
18
+ }
19
+
20
+ let idCounter = 0;
21
+ function useWidgetId(prefix) { return useMemo(() => { idCounter += 1; return (prefix || "lw") + "-" + idCounter; }, [prefix]); }
22
+
23
+ function WidgetCard({ children, noPadding, className = "", ...props }) { return createElement("div", { className: ("lw-card " + (noPadding ? "lw-card--no-padding " : "") + className).trim(), ...props }, children); }
24
+ function WidgetHeader({ title, subtitle, children, className = "", ...props }) { return createElement("div", { className: ("lw-header " + className).trim(), ...props }, createElement("div", null, createElement("h3", { className: "lw-header__title" }, title), subtitle && createElement("p", { className: "lw-header__subtitle" }, subtitle)), children && createElement("div", { className: "lw-header__actions" }, children)); }
25
+ function WidgetButton({ children, variant = "primary", size = "md", className = "", ...props }) { return createElement("button", { className: ("lw-btn lw-btn--" + variant + " lw-btn--" + size + " " + className).trim(), ...props }, children); }
26
+ function WidgetBadge({ children, variant = "default", className = "", ...props }) { return createElement("span", { className: ("lw-badge lw-badge--" + variant + " " + className).trim(), ...props }, children); }
27
+ function WidgetDivider({ className = "" }) { return createElement("hr", { className: ("lw-divider " + className).trim() }); }
28
+
29
+ export { createWidget, useWidgetTheme, useWidgetId, WidgetCard, WidgetHeader, WidgetButton, WidgetBadge, WidgetDivider };
package/dist/style.css ADDED
@@ -0,0 +1,26 @@
1
+ .lw-widget { font-family: inherit; line-height: 1.5; color: hsl(var(--foreground, 222.2 84% 4.9%)); -webkit-font-smoothing: antialiased; }
2
+ .lw-card { border: 1px solid hsl(var(--border, 214.3 31.8% 91.4%)); border-radius: var(--radius, 0.75rem); background: hsl(var(--card, 0 0% 100%)); color: hsl(var(--card-foreground, 222.2 84% 4.9%)); padding: 1.5rem; transition: box-shadow 0.2s ease; }
3
+ .lw-card:hover { box-shadow: 0 4px 20px -4px hsl(var(--primary, 221.2 83.2% 53.3%) / 0.1); }
4
+ .lw-card--no-padding { padding: 0; }
5
+ .lw-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; padding: 1.5rem; }
6
+ .lw-header__title { font-size: 1.25rem; font-weight: 700; margin: 0; color: hsl(var(--foreground, 222.2 84% 4.9%)); }
7
+ .lw-header__subtitle { font-size: 0.875rem; margin: 0.25rem 0 0; color: hsl(var(--muted-foreground, 215.4 16.3% 46.9%)); }
8
+ .lw-header__actions { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
9
+ .lw-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; border-radius: var(--radius, 0.75rem); font-weight: 600; cursor: pointer; border: 1px solid transparent; transition: all 0.15s ease; white-space: nowrap; font-family: inherit; }
10
+ .lw-btn:disabled { opacity: 0.5; cursor: not-allowed; }
11
+ .lw-btn--sm { padding: 0.375rem 0.75rem; font-size: 0.8125rem; }
12
+ .lw-btn--md { padding: 0.5rem 1rem; font-size: 0.875rem; }
13
+ .lw-btn--lg { padding: 0.625rem 1.5rem; font-size: 1rem; }
14
+ .lw-btn--primary { background: hsl(var(--primary, 221.2 83.2% 53.3%)); color: hsl(var(--primary-foreground, 210 40% 98%)); }
15
+ .lw-btn--primary:hover:not(:disabled) { opacity: 0.9; }
16
+ .lw-btn--secondary { background: hsl(var(--secondary, 210 40% 96.1%)); color: hsl(var(--secondary-foreground, 222.2 47.4% 11.2%)); }
17
+ .lw-btn--ghost { background: transparent; color: hsl(var(--foreground, 222.2 84% 4.9%)); }
18
+ .lw-btn--ghost:hover:not(:disabled) { background: hsl(var(--accent, 210 40% 96.1%)); }
19
+ .lw-btn--destructive { background: hsl(var(--destructive, 0 84.2% 60.2%)); color: hsl(var(--destructive-foreground, 210 40% 98%)); }
20
+ .lw-badge { display: inline-flex; align-items: center; padding: 0.125rem 0.625rem; border-radius: 9999px; font-size: 0.75rem; font-weight: 600; line-height: 1.5; }
21
+ .lw-badge--default { background: hsl(var(--secondary, 210 40% 96.1%)); color: hsl(var(--secondary-foreground, 222.2 47.4% 11.2%)); }
22
+ .lw-badge--primary { background: hsl(var(--primary, 221.2 83.2% 53.3%) / 0.1); color: hsl(var(--primary, 221.2 83.2% 53.3%)); }
23
+ .lw-badge--success { background: hsl(142 76% 36% / 0.1); color: hsl(142 76% 36%); }
24
+ .lw-badge--warning { background: hsl(38 92% 50% / 0.1); color: hsl(38 92% 50%); }
25
+ .lw-badge--destructive { background: hsl(var(--destructive, 0 84.2% 60.2%) / 0.1); color: hsl(var(--destructive, 0 84.2% 60.2%)); }
26
+ .lw-divider { border: none; height: 1px; background: hsl(var(--border, 214.3 31.8% 91.4%)); margin: 1rem 0; }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lovable-widgets/core",
3
- "version": "0.1.0",
4
- "description": "Pure integration SDK for building Lovable-compatible widgets",
3
+ "version": "1.0.1",
4
+ "description": "Core SDK for building Lovable-compatible widgets. Every @lovable-widgets package must use this.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
package/dist/context.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import type { WidgetContextValue } from './types';
2
- export declare const WidgetContext: import("react").Context<WidgetContextValue | null>;
3
- export declare function useWidgetContext(): WidgetContextValue | null;
@@ -1,7 +0,0 @@
1
- import type { CreateWidgetConfig, WidgetDefinition } from './types';
2
- declare global {
3
- interface Window {
4
- __LOVABLE_WIDGET_SECRETS__?: Record<string, string>;
5
- }
6
- }
7
- export declare function createWidget<P extends Record<string, any>>(config: CreateWidgetConfig<P>): WidgetDefinition<P>;
@@ -1,19 +0,0 @@
1
- import React, { Component, ErrorInfo, ReactNode } from 'react';
2
- interface Props {
3
- widgetName: string;
4
- onError?: (error: Error, errorInfo?: {
5
- componentStack?: string;
6
- }) => void;
7
- children: ReactNode;
8
- }
9
- interface State {
10
- hasError: boolean;
11
- error: Error | null;
12
- }
13
- export declare class WidgetErrorBoundary extends Component<Props, State> {
14
- state: State;
15
- static getDerivedStateFromError(error: Error): State;
16
- componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
17
- render(): string | number | boolean | Iterable<React.ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
18
- }
19
- export {};
package/dist/events.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import type { WidgetEventType, WidgetEvent } from './types';
2
- export declare function emitWidgetEvent<T = any>(widgetName: string, type: WidgetEventType, payload?: T): void;
3
- export declare function onWidgetEvent<T = any>(type: WidgetEventType | '*', callback: (event: WidgetEvent<T>) => void): () => void;
package/dist/hooks.d.ts DELETED
@@ -1,7 +0,0 @@
1
- import type { ThemeTokens, WidgetEventType, WidgetEvent } from './types';
2
- export declare function useWidgetTheme(): ThemeTokens;
3
- export declare function useWidgetId(prefix?: string): string;
4
- export declare function useWidgetSecrets(): Record<string, string>;
5
- export declare function useWidgetStatus(): 'initializing' | 'ready' | 'missing-secrets' | 'unknown';
6
- export declare function useWidgetEmit(): (type: WidgetEventType, payload?: any) => void;
7
- export declare function useWidgetListener<T = any>(type: WidgetEventType | '*', callback: (event: WidgetEvent<T>) => void): void;
@@ -1 +0,0 @@
1
- var ie=Object.create;var p=Object.defineProperty;var de=Object.getOwnPropertyDescriptor;var se=Object.getOwnPropertyNames;var ae=Object.getPrototypeOf,ge=Object.prototype.hasOwnProperty;var ce=(e,t,r)=>t in e?p(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var ue=(e,t)=>{for(var r in t)p(e,r,{get:t[r],enumerable:!0})},b=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of se(t))!ge.call(e,o)&&o!==r&&p(e,o,{get:()=>t[o],enumerable:!(n=de(t,o))||n.enumerable});return e};var me=(e,t,r)=>(r=e!=null?ie(ae(e)):{},b(t||!e||!e.__esModule?p(r,"default",{value:e,enumerable:!0}):r,e)),fe=e=>b(p({},"__esModule",{value:!0}),e);var M=(e,t,r)=>ce(e,typeof t!="symbol"?t+"":t,r);var We={};ue(We,{WidgetErrorBoundary:()=>c,clearRegistry:()=>X,createWidget:()=>B,emitWidgetEvent:()=>d,getWidget:()=>w,listWidgets:()=>q,mountWidget:()=>Z,onWidgetEvent:()=>y,provideSecrets:()=>J,registerWidget:()=>K,unmountWidget:()=>h,unregisterWidget:()=>U,useWidgetContext:()=>g,useWidgetEmit:()=>H,useWidgetId:()=>$,useWidgetListener:()=>z,useWidgetSecrets:()=>G,useWidgetStatus:()=>O,useWidgetTheme:()=>A});module.exports=fe(We);var i=require("react");var v=require("react"),_=(0,v.createContext)(null);function g(){return(0,v.useContext)(_)}var I=require("react");var C="lovable-widget:";function d(e,t,r){if(typeof window>"u")return;let n={widget:e,type:t,payload:r,timestamp:Date.now()};window.dispatchEvent(new CustomEvent(`${C}${t}`,{detail:n})),window.dispatchEvent(new CustomEvent(`${C}*`,{detail:n}))}function y(e,t){if(typeof window>"u")return()=>{};let r=`${C}${e}`,n=o=>{t(o.detail)};return window.addEventListener(r,n),()=>window.removeEventListener(r,n)}var P=require("react/jsx-runtime"),c=class extends I.Component{constructor(){super(...arguments);M(this,"state",{hasError:!1,error:null})}static getDerivedStateFromError(r){return{hasError:!0,error:r}}componentDidCatch(r,n){let{widgetName:o,onError:l}=this.props;d(o,"error",{message:r.message,stack:r.stack,componentStack:n.componentStack}),l?.(r,{componentStack:n.componentStack??void 0})}render(){return this.state.hasError?(0,P.jsxs)("div",{"data-lw-error":this.props.widgetName,children:['Widget "',this.props.widgetName,'" encountered an error.']}):this.props.children}};var s=require("react/jsx-runtime");function pe({lifecycle:e,widgetName:t}){return(0,i.useEffect)(()=>(e.onMount?.(),d(t,"ready"),()=>{e.onUnmount?.()}),[]),null}function B(e){let{meta:t,component:r,propDefs:n,secrets:o=[],config:l={},lifecycle:x={}}=e,L=(0,i.forwardRef)((j,R)=>{let{className:D="",...ee}=j,[te,re]=(0,i.useState)(o.filter(()=>!1)),[T,ne]=(0,i.useState)({}),[E,k]=(0,i.useState)("initializing");(0,i.useEffect)(()=>{if(o.length===0){k("ready");return}let u=typeof window<"u"&&window.__LOVABLE_WIDGET_SECRETS__||{},m=[],N={};for(let f of o){let V=f.envKey||f.name;u[V]?N[f.name]=u[V]:f.required!==!1&&m.push(f)}ne(N),re(m),k(m.length>0?"missing-secrets":"ready"),m.length>0&&d(t.name,"missing-secrets",{secrets:m})},[]);let oe=(0,i.useMemo)(()=>({meta:t,secrets:T,config:l,status:E}),[T,E]);return E==="missing-secrets"?(0,s.jsxs)("div",{ref:R,className:D||void 0,"data-lw-widget":t.name,"data-lw-version":t.version,"data-lw-status":"missing-secrets",children:['Widget "',t.name,'" requires secrets: ',te.map(u=>u.envKey||u.name).join(", ")]}):(0,s.jsx)(_.Provider,{value:oe,children:(0,s.jsx)(c,{widgetName:t.name,onError:x.onError,children:(0,s.jsxs)("div",{ref:R,className:D||void 0,"data-lw-widget":t.name,"data-lw-version":t.version,"data-lw-status":E,children:[(0,s.jsx)(pe,{lifecycle:x,widgetName:t.name}),(0,s.jsx)(r,{...ee,__widgetSecrets:T})]})})})});return L.displayName=`LovableWidget(${t.name})`,{component:L,meta:t,propDefs:n,secrets:o,config:l,lifecycle:x,__LOVABLE_WIDGET__:!0}}var a=require("react");function A(){return(0,a.useMemo)(()=>{let e=t=>typeof window>"u"?"":getComputedStyle(document.documentElement).getPropertyValue("--"+t).trim();return{background:e("background"),foreground:e("foreground"),card:e("card"),cardForeground:e("card-foreground"),primary:e("primary"),primaryForeground:e("primary-foreground"),secondary:e("secondary"),secondaryForeground:e("secondary-foreground"),muted:e("muted"),mutedForeground:e("muted-foreground"),accent:e("accent"),accentForeground:e("accent-foreground"),destructive:e("destructive"),destructiveForeground:e("destructive-foreground"),border:e("border"),ring:e("ring"),radius:e("radius")}},[])}var F=0;function $(e){return(0,a.useMemo)(()=>(F+=1,(e||"lw")+"-"+F),[e])}function G(){let e=g();return e?e.secrets:{}}function O(){let e=g();return e?e.status:"unknown"}function H(){let t=g()?.meta.name??"unknown";return(0,a.useCallback)((r,n)=>{d(t,r,n)},[t])}function z(e,t){(0,a.useEffect)(()=>y(e,t),[e,t])}var W=new Map;function K(e){if(!e.__LOVABLE_WIDGET__)throw new Error("registerWidget: argument must be a WidgetDefinition created by createWidget()");W.set(e.meta.name,e)}function w(e){return W.get(e)}function q(){return Array.from(W.values())}function U(e){return W.delete(e)}function X(){W.clear()}function J(e){typeof window<"u"&&(window.__LOVABLE_WIDGET_SECRETS__={...window.__LOVABLE_WIDGET_SECRETS__||{},...e})}var Q=me(require("react"),1),Y=require("react-dom/client");var S=new WeakMap;function Z(e,t,r={}){let n=w(t);if(!n)throw new Error(`mountWidget: widget "${t}" is not registered.`);h(e);let o=(0,Y.createRoot)(e);o.render(Q.default.createElement(n.component,r)),S.set(e,o)}function h(e){let t=S.get(e);t&&(t.unmount(),S.delete(e))}
@@ -1 +0,0 @@
1
- var G=Object.defineProperty;var O=(e,t,r)=>t in e?G(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var D=(e,t,r)=>O(e,typeof t!="symbol"?t+"":t,r);import{forwardRef as U,useState as w,useEffect as N,useMemo as X}from"react";import{createContext as H,useContext as z}from"react";var E=H(null);function g(){return z(E)}import{Component as K}from"react";var v="lovable-widget:";function i(e,t,r){if(typeof window>"u")return;let n={widget:e,type:t,payload:r,timestamp:Date.now()};window.dispatchEvent(new CustomEvent(`${v}${t}`,{detail:n})),window.dispatchEvent(new CustomEvent(`${v}*`,{detail:n}))}function y(e,t){if(typeof window>"u")return()=>{};let r=`${v}${e}`,n=o=>{t(o.detail)};return window.addEventListener(r,n),()=>window.removeEventListener(r,n)}import{jsxs as q}from"react/jsx-runtime";var c=class extends K{constructor(){super(...arguments);D(this,"state",{hasError:!1,error:null})}static getDerivedStateFromError(r){return{hasError:!0,error:r}}componentDidCatch(r,n){let{widgetName:o,onError:m}=this.props;i(o,"error",{message:r.message,stack:r.stack,componentStack:n.componentStack}),m?.(r,{componentStack:n.componentStack??void 0})}render(){return this.state.hasError?q("div",{"data-lw-error":this.props.widgetName,children:['Widget "',this.props.widgetName,'" encountered an error.']}):this.props.children}};import{jsx as p,jsxs as k}from"react/jsx-runtime";function J({lifecycle:e,widgetName:t}){return N(()=>(e.onMount?.(),i(t,"ready"),()=>{e.onUnmount?.()}),[]),null}function Q(e){let{meta:t,component:r,propDefs:n,secrets:o=[],config:m={},lifecycle:W={}}=e,_=U((I,C)=>{let{className:S="",...P}=I,[B,F]=w(o.filter(()=>!1)),[l,A]=w({}),[f,h]=w("initializing");N(()=>{if(o.length===0){h("ready");return}let d=typeof window<"u"&&window.__LOVABLE_WIDGET_SECRETS__||{},s=[],L={};for(let a of o){let R=a.envKey||a.name;d[R]?L[a.name]=d[R]:a.required!==!1&&s.push(a)}A(L),F(s),h(s.length>0?"missing-secrets":"ready"),s.length>0&&i(t.name,"missing-secrets",{secrets:s})},[]);let $=X(()=>({meta:t,secrets:l,config:m,status:f}),[l,f]);return f==="missing-secrets"?k("div",{ref:C,className:S||void 0,"data-lw-widget":t.name,"data-lw-version":t.version,"data-lw-status":"missing-secrets",children:['Widget "',t.name,'" requires secrets: ',B.map(d=>d.envKey||d.name).join(", ")]}):p(E.Provider,{value:$,children:p(c,{widgetName:t.name,onError:W.onError,children:k("div",{ref:C,className:S||void 0,"data-lw-widget":t.name,"data-lw-version":t.version,"data-lw-status":f,children:[p(J,{lifecycle:W,widgetName:t.name}),p(r,{...P,__widgetSecrets:l})]})})})});return _.displayName=`LovableWidget(${t.name})`,{component:_,meta:t,propDefs:n,secrets:o,config:m,lifecycle:W,__LOVABLE_WIDGET__:!0}}import{useMemo as b,useEffect as Y,useCallback as Z}from"react";function j(){return b(()=>{let e=t=>typeof window>"u"?"":getComputedStyle(document.documentElement).getPropertyValue("--"+t).trim();return{background:e("background"),foreground:e("foreground"),card:e("card"),cardForeground:e("card-foreground"),primary:e("primary"),primaryForeground:e("primary-foreground"),secondary:e("secondary"),secondaryForeground:e("secondary-foreground"),muted:e("muted"),mutedForeground:e("muted-foreground"),accent:e("accent"),accentForeground:e("accent-foreground"),destructive:e("destructive"),destructiveForeground:e("destructive-foreground"),border:e("border"),ring:e("ring"),radius:e("radius")}},[])}var V=0;function ee(e){return b(()=>(V+=1,(e||"lw")+"-"+V),[e])}function te(){let e=g();return e?e.secrets:{}}function re(){let e=g();return e?e.status:"unknown"}function ne(){let t=g()?.meta.name??"unknown";return Z((r,n)=>{i(t,r,n)},[t])}function oe(e,t){Y(()=>y(e,t),[e,t])}var u=new Map;function ie(e){if(!e.__LOVABLE_WIDGET__)throw new Error("registerWidget: argument must be a WidgetDefinition created by createWidget()");u.set(e.meta.name,e)}function x(e){return u.get(e)}function de(){return Array.from(u.values())}function se(e){return u.delete(e)}function ae(){u.clear()}function ge(e){typeof window<"u"&&(window.__LOVABLE_WIDGET_SECRETS__={...window.__LOVABLE_WIDGET_SECRETS__||{},...e})}import ce from"react";import{createRoot as ue}from"react-dom/client";var T=new WeakMap;function me(e,t,r={}){let n=x(t);if(!n)throw new Error(`mountWidget: widget "${t}" is not registered.`);M(e);let o=ue(e);o.render(ce.createElement(n.component,r)),T.set(e,o)}function M(e){let t=T.get(e);t&&(t.unmount(),T.delete(e))}export{c as WidgetErrorBoundary,ae as clearRegistry,Q as createWidget,i as emitWidgetEvent,x as getWidget,de as listWidgets,me as mountWidget,y as onWidgetEvent,ge as provideSecrets,ie as registerWidget,M as unmountWidget,se as unregisterWidget,g as useWidgetContext,ne as useWidgetEmit,ee as useWidgetId,oe as useWidgetListener,te as useWidgetSecrets,re as useWidgetStatus,j as useWidgetTheme};
package/dist/mount.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export declare function mountWidget(container: HTMLElement, widgetName: string, props?: Record<string, any>): void;
2
- export declare function unmountWidget(container: HTMLElement): void;
@@ -1 +0,0 @@
1
- export declare function provideSecrets(secretMap: Record<string, string>): void;
@@ -1,6 +0,0 @@
1
- import type { WidgetDefinition } from './types';
2
- export declare function registerWidget(definition: WidgetDefinition): void;
3
- export declare function getWidget(name: string): WidgetDefinition | undefined;
4
- export declare function listWidgets(): WidgetDefinition[];
5
- export declare function unregisterWidget(name: string): boolean;
6
- export declare function clearRegistry(): void;
package/dist/types.d.ts DELETED
@@ -1,91 +0,0 @@
1
- import { ComponentType } from 'react';
2
- export interface WidgetSecretDef {
3
- name: string;
4
- envKey: string;
5
- description: string;
6
- required?: boolean;
7
- acquireUrl?: string;
8
- service?: string;
9
- }
10
- export interface WidgetMeta {
11
- name: string;
12
- version: string;
13
- description: string;
14
- author: string;
15
- category: 'ui' | 'commerce' | 'navigation' | 'social-proof' | 'data' | 'forms' | 'media' | 'layout' | 'ai' | 'analytics' | 'communication';
16
- tags: string[];
17
- icon?: string;
18
- license?: string;
19
- repository?: string;
20
- homepage?: string;
21
- }
22
- export interface WidgetConfig {
23
- ssr?: boolean;
24
- minCoreVersion?: string;
25
- sandbox?: 'strict' | 'permissive';
26
- cssPrefix?: string;
27
- }
28
- export interface WidgetPropDef {
29
- name: string;
30
- type: string;
31
- required: boolean;
32
- default?: string;
33
- description: string;
34
- options?: string[];
35
- }
36
- export interface WidgetLifecycle {
37
- onMount?: () => void;
38
- onUnmount?: () => void;
39
- onError?: (error: Error, errorInfo?: {
40
- componentStack?: string;
41
- }) => void;
42
- }
43
- export interface WidgetDefinition<P = any> {
44
- component: ComponentType<P>;
45
- meta: WidgetMeta;
46
- propDefs: WidgetPropDef[];
47
- secrets: WidgetSecretDef[];
48
- config: WidgetConfig;
49
- lifecycle: WidgetLifecycle;
50
- __LOVABLE_WIDGET__: true;
51
- }
52
- export interface CreateWidgetConfig<P> {
53
- meta: WidgetMeta;
54
- component: ComponentType<P>;
55
- propDefs: WidgetPropDef[];
56
- secrets?: WidgetSecretDef[];
57
- config?: WidgetConfig;
58
- lifecycle?: WidgetLifecycle;
59
- }
60
- export interface ThemeTokens {
61
- background: string;
62
- foreground: string;
63
- card: string;
64
- cardForeground: string;
65
- primary: string;
66
- primaryForeground: string;
67
- secondary: string;
68
- secondaryForeground: string;
69
- muted: string;
70
- mutedForeground: string;
71
- accent: string;
72
- accentForeground: string;
73
- destructive: string;
74
- destructiveForeground: string;
75
- border: string;
76
- ring: string;
77
- radius: string;
78
- }
79
- export interface WidgetContextValue {
80
- meta: WidgetMeta;
81
- secrets: Record<string, string>;
82
- config: WidgetConfig;
83
- status: 'initializing' | 'ready' | 'missing-secrets';
84
- }
85
- export type WidgetEventType = 'ready' | 'error' | 'state-change' | 'action' | 'missing-secrets' | 'resize';
86
- export interface WidgetEvent<T = any> {
87
- widget: string;
88
- type: WidgetEventType;
89
- payload: T;
90
- timestamp: number;
91
- }