@widgetic/canvas 0.5.4
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 +45 -0
- package/dist/canvas/Canvas.svelte +10678 -0
- package/dist/canvas/Canvas.svelte.d.ts +147 -0
- package/dist/canvas/CanvasToolbar.svelte +1422 -0
- package/dist/canvas/CanvasToolbar.svelte.d.ts +54 -0
- package/dist/canvas/ContextMenu.svelte +279 -0
- package/dist/canvas/ContextMenu.svelte.d.ts +36 -0
- package/dist/canvas/PanZoomPanel.svelte +315 -0
- package/dist/canvas/PanZoomPanel.svelte.d.ts +32 -0
- package/dist/canvas/canvasLogger.d.ts +5 -0
- package/dist/canvas/canvasLogger.js +19 -0
- package/dist/canvas/index.d.ts +13 -0
- package/dist/canvas/index.js +12 -0
- package/dist/canvas/props-panel/PropsPanel.svelte +1902 -0
- package/dist/canvas/props-panel/PropsPanel.svelte.d.ts +73 -0
- package/dist/canvas/props-panel/TextPropsICSection.svelte +238 -0
- package/dist/canvas/props-panel/TextPropsICSection.svelte.d.ts +36 -0
- package/dist/canvas/shapes/FrameShape.d.ts +97 -0
- package/dist/canvas/shapes/FrameShape.js +951 -0
- package/dist/canvas/shapes/ImageShape.d.ts +38 -0
- package/dist/canvas/shapes/ImageShape.js +245 -0
- package/dist/canvas/shapes/ShapeLibrary.d.ts +64 -0
- package/dist/canvas/shapes/ShapeLibrary.js +526 -0
- package/dist/canvas/shapes/WidgetShape.d.ts +21 -0
- package/dist/canvas/shapes/WidgetShape.js +132 -0
- package/dist/canvas/types.d.ts +26 -0
- package/dist/canvas/types.js +5 -0
- package/dist/components/Tooltip.svelte +179 -0
- package/dist/components/Tooltip.svelte.d.ts +21 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.js +13 -0
- package/dist/components/input-controls/ColorIC.svelte +388 -0
- package/dist/components/input-controls/ColorIC.svelte.d.ts +22 -0
- package/dist/components/input-controls/FontSelectorIC.svelte +69 -0
- package/dist/components/input-controls/FontSelectorIC.svelte.d.ts +17 -0
- package/dist/components/input-controls/SliderUnitIC.svelte +217 -0
- package/dist/components/input-controls/SliderUnitIC.svelte.d.ts +24 -0
- package/dist/components/input-controls/TextAlignIC.svelte +84 -0
- package/dist/components/input-controls/TextAlignIC.svelte.d.ts +17 -0
- package/dist/components/input-controls/TextStyleIC.svelte +85 -0
- package/dist/components/input-controls/TextStyleIC.svelte.d.ts +21 -0
- package/dist/icons/arrow.svg +3 -0
- package/dist/icons/checkmark.svg +3 -0
- package/dist/icons/draw.svg +22 -0
- package/dist/icons/eraser.svg +23 -0
- package/dist/icons/hand.svg +6 -0
- package/dist/icons/select.svg +3 -0
- package/dist/icons/text.svg +5 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +12 -0
- package/package.json +101 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WidgetShape — extends ImageShape with widget-specific properties.
|
|
3
|
+
*
|
|
4
|
+
* Adds _isWidgetImage and _widgetId to link an image placeholder to a
|
|
5
|
+
* generated widget in the Widgetic platform.
|
|
6
|
+
*
|
|
7
|
+
* When an ImageShape is "converted to widget", its prototype is swapped
|
|
8
|
+
* to WidgetShape via upgradeToWidgetShape(), and the serialized type
|
|
9
|
+
* becomes 'WidgetShape'.
|
|
10
|
+
*
|
|
11
|
+
* Backward-compat: old saves that stored widget links directly on ImageShape
|
|
12
|
+
* (with type:'ImageShape' + _isWidgetImage:true) are handled by the
|
|
13
|
+
* classRegistry alias and the reviver in Canvas.svelte.
|
|
14
|
+
*/
|
|
15
|
+
import { Rect, classRegistry } from 'fabric';
|
|
16
|
+
import { ImageShape, IMAGE_SHAPE_CUSTOM_PROPS } from './ImageShape';
|
|
17
|
+
import { canvasLog, canvasWarn } from '../canvasLogger';
|
|
18
|
+
// Widget-specific custom properties (on top of IMAGE_SHAPE_CUSTOM_PROPS)
|
|
19
|
+
export const WIDGET_SHAPE_EXTRA_PROPS = [
|
|
20
|
+
'_isWidgetImage',
|
|
21
|
+
'_widgetId',
|
|
22
|
+
'_widgetName',
|
|
23
|
+
'_widgetOrphaned',
|
|
24
|
+
];
|
|
25
|
+
// Full list: base image props + widget props
|
|
26
|
+
export const WIDGET_SHAPE_CUSTOM_PROPS = [
|
|
27
|
+
...IMAGE_SHAPE_CUSTOM_PROPS,
|
|
28
|
+
...WIDGET_SHAPE_EXTRA_PROPS,
|
|
29
|
+
];
|
|
30
|
+
export class WidgetShape extends ImageShape {
|
|
31
|
+
static type = 'WidgetShape';
|
|
32
|
+
_isWidgetImage = false;
|
|
33
|
+
_widgetId = null;
|
|
34
|
+
_widgetName = null;
|
|
35
|
+
/** True when _widgetId no longer exists in the host widget list (deleted or moved). */
|
|
36
|
+
_widgetOrphaned = false;
|
|
37
|
+
/** Custom placeholder overlay: replace generic "Drop image" text with the widget name. */
|
|
38
|
+
_render(ctx) {
|
|
39
|
+
const hasImage = this._hasImage && this._imageElement;
|
|
40
|
+
if (hasImage) {
|
|
41
|
+
super._render(ctx);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Draw the underlying rect background (dashed border stays via stroke).
|
|
45
|
+
Rect.prototype._render.call(this, ctx);
|
|
46
|
+
this._renderWidgetPlaceholder(ctx);
|
|
47
|
+
}
|
|
48
|
+
_renderWidgetPlaceholder(ctx) {
|
|
49
|
+
const availableW = this.width || 100;
|
|
50
|
+
const availableH = this.height || 100;
|
|
51
|
+
ctx.save();
|
|
52
|
+
ctx.fillStyle = '#475569';
|
|
53
|
+
ctx.textAlign = 'center';
|
|
54
|
+
ctx.textBaseline = 'middle';
|
|
55
|
+
const isOrphaned = !!this._widgetOrphaned;
|
|
56
|
+
// Widget icon
|
|
57
|
+
const iconSize = Math.min(48, availableH * 0.28);
|
|
58
|
+
ctx.font = `${iconSize}px Arial`;
|
|
59
|
+
ctx.fillText(isOrphaned ? '⚠️' : '🧩', 0, -availableH * 0.18);
|
|
60
|
+
// Widget name
|
|
61
|
+
const name = isOrphaned
|
|
62
|
+
? 'Unlinked widget'
|
|
63
|
+
: (this._widgetName || 'Widget');
|
|
64
|
+
const maxTextWidth = availableW - 24;
|
|
65
|
+
let fontSize = Math.max(11, Math.min(18, availableW * 0.06));
|
|
66
|
+
ctx.font = `600 ${fontSize}px system-ui, -apple-system, sans-serif`;
|
|
67
|
+
let displayName = name;
|
|
68
|
+
// Truncate with ellipsis if too wide
|
|
69
|
+
while (ctx.measureText(displayName).width > maxTextWidth && displayName.length > 4) {
|
|
70
|
+
displayName = displayName.slice(0, -1);
|
|
71
|
+
}
|
|
72
|
+
if (displayName.length < name.length)
|
|
73
|
+
displayName = displayName.slice(0, -1) + '…';
|
|
74
|
+
ctx.fillStyle = '#1e293b';
|
|
75
|
+
ctx.fillText(displayName, 0, availableH * 0.06);
|
|
76
|
+
// Subtitle
|
|
77
|
+
ctx.font = `400 ${Math.max(10, fontSize - 3)}px system-ui, -apple-system, sans-serif`;
|
|
78
|
+
ctx.fillStyle = '#64748b';
|
|
79
|
+
ctx.fillText(isOrphaned ? 'Remove from canvas' : 'Widget preview', 0, availableH * 0.06 + fontSize + 6);
|
|
80
|
+
ctx.restore();
|
|
81
|
+
}
|
|
82
|
+
// ── Serialisation ─────────────────────────────────────────────────────────
|
|
83
|
+
toObject(propertiesToInclude) {
|
|
84
|
+
const extras = WIDGET_SHAPE_CUSTOM_PROPS.concat(propertiesToInclude ?? []);
|
|
85
|
+
const base = super.toObject(extras);
|
|
86
|
+
return {
|
|
87
|
+
...base,
|
|
88
|
+
type: WidgetShape.type,
|
|
89
|
+
_imageElement: undefined,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
// ── Deserialisation ───────────────────────────────────────────────────────
|
|
93
|
+
static fromObject(object, options) {
|
|
94
|
+
return Rect.fromObject({ ...object, type: 'rect' }, options).then((rect) => {
|
|
95
|
+
Object.setPrototypeOf(rect, WidgetShape.prototype);
|
|
96
|
+
const shape = rect;
|
|
97
|
+
for (const prop of WIDGET_SHAPE_CUSTOM_PROPS) {
|
|
98
|
+
if (prop in object && shape[prop] === undefined || shape[prop] !== object[prop]) {
|
|
99
|
+
shape[prop] = object[prop];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (shape._imageUrl) {
|
|
103
|
+
ImageShape.reloadImage(shape);
|
|
104
|
+
}
|
|
105
|
+
canvasLog('WidgetShape: fromObject — restored', shape._objectId || 'shape', 'hasImage:', shape._hasImage, 'isWidget:', shape._isWidgetImage, 'widgetId:', shape._widgetId);
|
|
106
|
+
return shape;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Register so loadFromJSON can resolve type:'WidgetShape'
|
|
111
|
+
classRegistry.setClass(WidgetShape);
|
|
112
|
+
/**
|
|
113
|
+
* Upgrades an ImageShape to a WidgetShape by swapping the prototype chain.
|
|
114
|
+
* Called when user clicks "Convert to Widget".
|
|
115
|
+
*/
|
|
116
|
+
export function upgradeToWidgetShape(obj) {
|
|
117
|
+
if (!obj)
|
|
118
|
+
return null;
|
|
119
|
+
if (obj instanceof WidgetShape)
|
|
120
|
+
return obj;
|
|
121
|
+
try {
|
|
122
|
+
Object.setPrototypeOf(obj, WidgetShape.prototype);
|
|
123
|
+
const shape = obj;
|
|
124
|
+
shape._isWidgetImage = true;
|
|
125
|
+
canvasLog('WidgetShape: upgraded ImageShape → WidgetShape for', shape._objectId || 'shape');
|
|
126
|
+
return shape;
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
canvasWarn('WidgetShape: upgradeToWidgetShape failed', err);
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas component shared types.
|
|
3
|
+
* Importable by both the canvas project and consuming apps (e.g. widget-creator).
|
|
4
|
+
*/
|
|
5
|
+
/** Payload emitted when a frame is converted to a widget via onConvertToWidget callback. */
|
|
6
|
+
export interface WidgetConversionPayload {
|
|
7
|
+
frameName: string;
|
|
8
|
+
frameId: string;
|
|
9
|
+
screenshot: string;
|
|
10
|
+
canvasData: {
|
|
11
|
+
frame: Record<string, any>;
|
|
12
|
+
children: Record<string, any>[];
|
|
13
|
+
bounds: {
|
|
14
|
+
left: number;
|
|
15
|
+
top: number;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
metadata: {
|
|
21
|
+
childCount: number;
|
|
22
|
+
shapeTypes: string[];
|
|
23
|
+
hasImages: boolean;
|
|
24
|
+
hasText: boolean;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Tooltip — reusable canvas tooltip component
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* <Tooltip text="Draw D">
|
|
7
|
+
* <button>Draw</button>
|
|
8
|
+
* </Tooltip>
|
|
9
|
+
*
|
|
10
|
+
* The tooltip element is appended directly to <body> so it always appears
|
|
11
|
+
* above overflow containers and CSS transform ancestors (transformed
|
|
12
|
+
* ancestors would otherwise create a new containing-block for position:fixed,
|
|
13
|
+
* causing mis-positioning).
|
|
14
|
+
*/
|
|
15
|
+
import { onDestroy } from 'svelte';
|
|
16
|
+
|
|
17
|
+
// Tooltip label
|
|
18
|
+
export let text: string = '';
|
|
19
|
+
// Preferred position: 'above' appears above the trigger, 'below' below it
|
|
20
|
+
export let position: 'above' | 'below' = 'above';
|
|
21
|
+
// Set to true to suppress the tooltip
|
|
22
|
+
export let disabled: boolean = false;
|
|
23
|
+
// Extra vertical offset (px) — positive moves tooltip further from trigger
|
|
24
|
+
export let offsetY: number = 0;
|
|
25
|
+
|
|
26
|
+
let triggerEl: HTMLElement | null = null;
|
|
27
|
+
|
|
28
|
+
// Lazily-created body-level elements
|
|
29
|
+
let tooltipBodyEl: HTMLElement | null = null;
|
|
30
|
+
let arrowBodyEl: HTMLElement | null = null;
|
|
31
|
+
|
|
32
|
+
function ensureBodyEl() {
|
|
33
|
+
if (tooltipBodyEl) return;
|
|
34
|
+
|
|
35
|
+
tooltipBodyEl = document.createElement('div');
|
|
36
|
+
arrowBodyEl = document.createElement('div');
|
|
37
|
+
document.body.appendChild(tooltipBodyEl);
|
|
38
|
+
|
|
39
|
+
// Base tooltip styles
|
|
40
|
+
Object.assign(tooltipBodyEl.style, {
|
|
41
|
+
position: 'fixed',
|
|
42
|
+
zIndex: '99999',
|
|
43
|
+
pointerEvents: 'none',
|
|
44
|
+
display: 'none',
|
|
45
|
+
background: '#1f2937',
|
|
46
|
+
color: '#f9fafb',
|
|
47
|
+
fontSize: '12px',
|
|
48
|
+
lineHeight: '1.4',
|
|
49
|
+
padding: '5px 10px',
|
|
50
|
+
borderRadius: '6px',
|
|
51
|
+
whiteSpace: 'normal',
|
|
52
|
+
maxWidth: '200px',
|
|
53
|
+
textAlign: 'center',
|
|
54
|
+
boxShadow: '0 2px 8px rgba(0,0,0,0.25)',
|
|
55
|
+
userSelect: 'none',
|
|
56
|
+
WebkitUserSelect: 'none',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Arrow base styles — final border values set in show()
|
|
60
|
+
Object.assign(arrowBodyEl.style, {
|
|
61
|
+
position: 'absolute',
|
|
62
|
+
left: '50%',
|
|
63
|
+
transform: 'translateX(-50%)',
|
|
64
|
+
width: '0',
|
|
65
|
+
height: '0',
|
|
66
|
+
borderLeft: '5px solid transparent',
|
|
67
|
+
borderRight: '5px solid transparent',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const VIEWPORT_PADDING = 6;
|
|
72
|
+
const GAP = 8;
|
|
73
|
+
const ARROW_SIZE = 5;
|
|
74
|
+
|
|
75
|
+
function show() {
|
|
76
|
+
if (disabled || !text || !triggerEl) return;
|
|
77
|
+
ensureBodyEl();
|
|
78
|
+
|
|
79
|
+
// For display:contents wrappers, getBoundingClientRect() returns a zero rect;
|
|
80
|
+
// fall back to the first visual child in that case.
|
|
81
|
+
const triggerRect = triggerEl.getBoundingClientRect();
|
|
82
|
+
const anchor = (triggerRect.width === 0 && triggerRect.height === 0)
|
|
83
|
+
? ((triggerEl.firstElementChild as HTMLElement) ?? triggerEl)
|
|
84
|
+
: triggerEl;
|
|
85
|
+
const rect = anchor.getBoundingClientRect();
|
|
86
|
+
|
|
87
|
+
tooltipBodyEl!.textContent = text;
|
|
88
|
+
tooltipBodyEl!.appendChild(arrowBodyEl!);
|
|
89
|
+
|
|
90
|
+
// Temporarily show off-screen to measure natural size
|
|
91
|
+
Object.assign(tooltipBodyEl!.style, {
|
|
92
|
+
display: 'block',
|
|
93
|
+
left: '-9999px',
|
|
94
|
+
top: '-9999px',
|
|
95
|
+
transform: 'none',
|
|
96
|
+
});
|
|
97
|
+
const tipW = tooltipBodyEl!.offsetWidth;
|
|
98
|
+
const tipH = tooltipBodyEl!.offsetHeight;
|
|
99
|
+
|
|
100
|
+
const vw = window.innerWidth;
|
|
101
|
+
const vh = window.innerHeight;
|
|
102
|
+
const cx = rect.left + rect.width / 2;
|
|
103
|
+
|
|
104
|
+
// Decide vertical placement: prefer the requested position, flip if no room
|
|
105
|
+
let placeAbove = position === 'above';
|
|
106
|
+
const spaceAbove = rect.top - GAP - offsetY;
|
|
107
|
+
const spaceBelow = vh - rect.bottom - GAP - offsetY;
|
|
108
|
+
|
|
109
|
+
if (placeAbove && tipH > spaceAbove && spaceBelow > spaceAbove) {
|
|
110
|
+
placeAbove = false;
|
|
111
|
+
} else if (!placeAbove && tipH > spaceBelow && spaceAbove > spaceBelow) {
|
|
112
|
+
placeAbove = true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Vertical position
|
|
116
|
+
let top: number;
|
|
117
|
+
if (placeAbove) {
|
|
118
|
+
top = rect.top - GAP - offsetY - tipH;
|
|
119
|
+
} else {
|
|
120
|
+
top = rect.bottom + GAP + offsetY;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Horizontal position: center on trigger, then clamp to viewport
|
|
124
|
+
let left = cx - tipW / 2;
|
|
125
|
+
left = Math.max(VIEWPORT_PADDING, Math.min(left, vw - tipW - VIEWPORT_PADDING));
|
|
126
|
+
|
|
127
|
+
Object.assign(tooltipBodyEl!.style, {
|
|
128
|
+
left: `${left}px`,
|
|
129
|
+
top: `${top}px`,
|
|
130
|
+
transform: 'none',
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Position arrow relative to the trigger center
|
|
134
|
+
const arrowLeft = Math.max(ARROW_SIZE + 2, Math.min(cx - left, tipW - ARROW_SIZE - 2));
|
|
135
|
+
if (placeAbove) {
|
|
136
|
+
Object.assign(arrowBodyEl!.style, {
|
|
137
|
+
bottom: `${-ARROW_SIZE}px`,
|
|
138
|
+
top: 'auto',
|
|
139
|
+
left: `${arrowLeft}px`,
|
|
140
|
+
transform: 'translateX(-50%)',
|
|
141
|
+
borderTop: `${ARROW_SIZE}px solid #1f2937`,
|
|
142
|
+
borderBottom: 'none',
|
|
143
|
+
});
|
|
144
|
+
} else {
|
|
145
|
+
Object.assign(arrowBodyEl!.style, {
|
|
146
|
+
top: `${-ARROW_SIZE}px`,
|
|
147
|
+
bottom: 'auto',
|
|
148
|
+
left: `${arrowLeft}px`,
|
|
149
|
+
transform: 'translateX(-50%)',
|
|
150
|
+
borderBottom: `${ARROW_SIZE}px solid #1f2937`,
|
|
151
|
+
borderTop: 'none',
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function hide() {
|
|
157
|
+
if (tooltipBodyEl) tooltipBodyEl.style.display = 'none';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Clean up body element when component is destroyed
|
|
161
|
+
onDestroy(() => {
|
|
162
|
+
hide();
|
|
163
|
+
if (tooltipBodyEl) {
|
|
164
|
+
tooltipBodyEl.remove();
|
|
165
|
+
tooltipBodyEl = null;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
</script>
|
|
169
|
+
|
|
170
|
+
<!-- display:contents makes this wrapper invisible to layout while still receiving events -->
|
|
171
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
172
|
+
<div
|
|
173
|
+
bind:this={triggerEl}
|
|
174
|
+
onmouseenter={show}
|
|
175
|
+
onmouseleave={hide}
|
|
176
|
+
style="display:contents"
|
|
177
|
+
>
|
|
178
|
+
<slot />
|
|
179
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
text?: string;
|
|
5
|
+
position?: "above" | "below";
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
offsetY?: number;
|
|
8
|
+
};
|
|
9
|
+
events: {
|
|
10
|
+
[evt: string]: CustomEvent<any>;
|
|
11
|
+
};
|
|
12
|
+
slots: {
|
|
13
|
+
default: {};
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export type TooltipProps = typeof __propDef.props;
|
|
17
|
+
export type TooltipEvents = typeof __propDef.events;
|
|
18
|
+
export type TooltipSlots = typeof __propDef.slots;
|
|
19
|
+
export default class Tooltip extends SvelteComponentTyped<TooltipProps, TooltipEvents, TooltipSlots> {
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight components barrel — general-purpose, safe for static import.
|
|
3
|
+
*
|
|
4
|
+
* Import: import { Tooltip, ColorIC } from '@widgetic/canvas/components';
|
|
5
|
+
*/
|
|
6
|
+
export { default as Tooltip } from './Tooltip.svelte';
|
|
7
|
+
export { default as ColorIC } from './input-controls/ColorIC.svelte';
|
|
8
|
+
export { default as FontSelectorIC } from './input-controls/FontSelectorIC.svelte';
|
|
9
|
+
export { default as SliderUnitIC } from './input-controls/SliderUnitIC.svelte';
|
|
10
|
+
export { default as TextAlignIC } from './input-controls/TextAlignIC.svelte';
|
|
11
|
+
export { default as TextStyleIC } from './input-controls/TextStyleIC.svelte';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight components barrel — general-purpose, safe for static import.
|
|
3
|
+
*
|
|
4
|
+
* Import: import { Tooltip, ColorIC } from '@widgetic/canvas/components';
|
|
5
|
+
*/
|
|
6
|
+
// General Components
|
|
7
|
+
export { default as Tooltip } from './Tooltip.svelte';
|
|
8
|
+
// Input Controllers
|
|
9
|
+
export { default as ColorIC } from './input-controls/ColorIC.svelte';
|
|
10
|
+
export { default as FontSelectorIC } from './input-controls/FontSelectorIC.svelte';
|
|
11
|
+
export { default as SliderUnitIC } from './input-controls/SliderUnitIC.svelte';
|
|
12
|
+
export { default as TextAlignIC } from './input-controls/TextAlignIC.svelte';
|
|
13
|
+
export { default as TextStyleIC } from './input-controls/TextStyleIC.svelte';
|