@lovable-widgets/core 1.0.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 +27 -1
- package/dist/index.d.ts +19 -0
- package/dist/index.js +12 -0
- package/dist/index.mjs +29 -1
- package/dist/style.css +26 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1 +1,27 @@
|
|
|
1
|
-
#
|
|
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
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
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
CHANGED
|
@@ -1 +1,29 @@
|
|
|
1
|
-
|
|
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": "1.0.
|
|
4
|
-
"description": "Core 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",
|