@sxl-studio/storybook-addon 1.0.6 → 1.0.7

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/dist/index.d.ts CHANGED
@@ -13,6 +13,13 @@ type SxlRegistryMeta = {
13
13
  tokenStatus?: SxlTokenStatus;
14
14
  readiness?: SxlReadiness;
15
15
  };
16
+ /** File binding from Code Connect (per-framework). */
17
+ type SxlFileBinding = {
18
+ framework: string;
19
+ filePath: string;
20
+ componentName?: string;
21
+ importPath?: string;
22
+ };
16
23
  /** One component entry inside the registry. */
17
24
  type SxlRegistryEntry = {
18
25
  nodeId: string;
@@ -23,6 +30,14 @@ type SxlRegistryEntry = {
23
30
  designEmbed?: boolean;
24
31
  compositionJson?: boolean;
25
32
  metadata?: boolean;
33
+ /** ISO timestamp when the entry was last updated. */
34
+ updatedAt?: string;
35
+ /** Primary import path for the component. */
36
+ importPath?: string;
37
+ /** Snippet template for code generation. */
38
+ snippetTemplate?: string;
39
+ /** Per-framework file bindings. */
40
+ files?: SxlFileBinding[];
26
41
  meta?: SxlRegistryMeta;
27
42
  };
28
43
  /**
@@ -43,6 +58,8 @@ type SxlRegistry = {
43
58
  type SxlStoryParameters = {
44
59
  /** Explicit match by display name from the registry. */
45
60
  component?: string;
61
+ /** Alias for `component` (backward compat). */
62
+ componentName?: string;
46
63
  /** Explicit match by Figma node ID. */
47
64
  figmaNodeId?: string;
48
65
  /** Direct Figma design URL (overrides registry lookup). */
@@ -53,6 +70,12 @@ type SxlStoryParameters = {
53
70
  tokenStatus?: SxlTokenStatus;
54
71
  /** Override readiness per-story. */
55
72
  readiness?: SxlReadiness;
73
+ /** Override designEmbed per-story. */
74
+ designEmbed?: boolean;
75
+ /** Override compositionJson per-story. */
76
+ compositionJson?: boolean;
77
+ /** Override metadata per-story. */
78
+ metadata?: boolean;
56
79
  /** Registry data (typically set globally in preview.ts). */
57
80
  registry?: SxlRegistry;
58
81
  };
@@ -72,4 +95,4 @@ type SxlStoryParameters = {
72
95
  */
73
96
  declare function fromDiffCodeConnect(data: unknown): SxlRegistry;
74
97
 
75
- export { ADDON_ID, PANEL_ID, PARAM_KEY, type SxlReadiness, type SxlRegistry, type SxlRegistryEntry, type SxlRegistryMeta, type SxlStoryParameters, type SxlTokenStatus, fromDiffCodeConnect };
98
+ export { ADDON_ID, PANEL_ID, PARAM_KEY, type SxlFileBinding, type SxlReadiness, type SxlRegistry, type SxlRegistryEntry, type SxlRegistryMeta, type SxlStoryParameters, type SxlTokenStatus, fromDiffCodeConnect };
package/dist/index.js CHANGED
@@ -24,6 +24,13 @@ function fromDiffCodeConnect(data) {
24
24
  const tokenStatus = sb.tokensReady === true ? "assigned" : void 0;
25
25
  const statusRaw = typeof sb.status === "string" ? sb.status : void 0;
26
26
  const readiness = statusRaw === "complete" || statusRaw === "ready-for-dev" || statusRaw === "in-progress" || statusRaw === "backlog" ? statusRaw : void 0;
27
+ const rawFiles = Array.isArray(b.files) ? b.files : [];
28
+ const files = rawFiles.filter((f) => !!f && typeof f === "object").map((f) => ({
29
+ framework: String(f.framework ?? ""),
30
+ filePath: String(f.filePath ?? ""),
31
+ ...f.componentName ? { componentName: String(f.componentName) } : {},
32
+ ...f.importPath ? { importPath: String(f.importPath) } : {}
33
+ }));
27
34
  return {
28
35
  nodeId,
29
36
  displayName: String(b.displayName ?? e.nodeName ?? ""),
@@ -32,6 +39,10 @@ function fromDiffCodeConnect(data) {
32
39
  designEmbed: sb.designEmbed === true,
33
40
  compositionJson: sb.compositionJson === true,
34
41
  metadata: sb.metadata === true,
42
+ updatedAt: typeof e.updatedAt === "string" ? e.updatedAt : void 0,
43
+ importPath: typeof b.importPath === "string" ? b.importPath : void 0,
44
+ snippetTemplate: typeof b.snippetTemplate === "string" ? b.snippetTemplate : void 0,
45
+ files: files.length > 0 ? files : void 0,
35
46
  meta: {
36
47
  ...tokenStatus ? { tokenStatus } : {},
37
48
  ...readiness ? { readiness } : {}
package/dist/manager.js CHANGED
@@ -12,147 +12,230 @@ import React from "react";
12
12
  import { useParameter } from "@storybook/manager-api";
13
13
 
14
14
  // src/components/styles.ts
15
- var FONT_STACK = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
16
- var MONO_STACK = "'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace";
17
- var container = {
18
- padding: "16px",
19
- fontFamily: FONT_STACK,
15
+ var FONT = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
16
+ var MONO = "'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace";
17
+ var root = {
18
+ padding: "20px",
19
+ fontFamily: FONT,
20
20
  fontSize: "13px",
21
- lineHeight: 1.5,
22
- color: "var(--sxl-text, #333)",
21
+ lineHeight: 1.55,
22
+ color: "var(--sxl-text, #1a1a2e)",
23
23
  overflow: "auto",
24
- height: "100%"
24
+ height: "100%",
25
+ display: "flex",
26
+ flexDirection: "column",
27
+ gap: "16px"
25
28
  };
26
- var embedSection = {
27
- marginBottom: "16px",
28
- borderRadius: "8px",
29
- overflow: "hidden",
30
- border: "1px solid var(--sxl-border, #e6e6e6)",
29
+ var header = {
31
30
  display: "flex",
32
- justifyContent: "center"
31
+ alignItems: "flex-start",
32
+ justifyContent: "space-between",
33
+ gap: "12px"
33
34
  };
34
- var iframe = {
35
- width: "100%",
36
- height: "420px",
37
- border: "none"
35
+ var headerLeft = {
36
+ display: "flex",
37
+ flexDirection: "column",
38
+ gap: "4px",
39
+ flex: 1,
40
+ minWidth: 0
38
41
  };
39
- var section = {
40
- marginBottom: "12px",
41
- padding: "12px",
42
- borderRadius: "6px",
43
- backgroundColor: "var(--sxl-section-bg, #fafafa)",
44
- border: "1px solid var(--sxl-border, #eee)"
42
+ var componentName = {
43
+ fontSize: "18px",
44
+ fontWeight: 700,
45
+ color: "var(--sxl-text, #1a1a2e)",
46
+ margin: 0,
47
+ lineHeight: 1.3,
48
+ wordBreak: "break-word"
49
+ };
50
+ var updatedAt = {
51
+ fontSize: "11px",
52
+ color: "var(--sxl-muted, #8e8ea0)",
53
+ fontWeight: 400
54
+ };
55
+ var figmaButton = {
56
+ display: "inline-flex",
57
+ alignItems: "center",
58
+ gap: "6px",
59
+ padding: "6px 14px",
60
+ borderRadius: "8px",
61
+ border: "1px solid var(--sxl-border, #e0e0e8)",
62
+ backgroundColor: "var(--sxl-bg, #fff)",
63
+ color: "var(--sxl-link, #18a0fb)",
64
+ fontSize: "12px",
65
+ fontWeight: 600,
66
+ fontFamily: FONT,
67
+ textDecoration: "none",
68
+ cursor: "pointer",
69
+ whiteSpace: "nowrap",
70
+ transition: "all 120ms ease",
71
+ flexShrink: 0
72
+ };
73
+ var badgeRow = {
74
+ display: "flex",
75
+ flexWrap: "wrap",
76
+ gap: "8px"
45
77
  };
46
- var sectionTitle = {
78
+ var badge = {
79
+ display: "inline-flex",
80
+ alignItems: "center",
81
+ gap: "6px",
82
+ padding: "4px 10px",
83
+ borderRadius: "6px",
47
84
  fontSize: "11px",
48
85
  fontWeight: 600,
86
+ lineHeight: 1
87
+ };
88
+ var badgeDot = {
89
+ width: "7px",
90
+ height: "7px",
91
+ borderRadius: "50%",
92
+ flexShrink: 0
93
+ };
94
+ var card = {
95
+ padding: "14px 16px",
96
+ borderRadius: "10px",
97
+ backgroundColor: "var(--sxl-card-bg, #f8f8fb)",
98
+ border: "1px solid var(--sxl-border, #ebebf0)"
99
+ };
100
+ var cardTitle = {
101
+ fontSize: "10px",
102
+ fontWeight: 700,
49
103
  textTransform: "uppercase",
50
- letterSpacing: "0.5px",
51
- color: "var(--sxl-muted, #999)",
52
- marginBottom: "8px"
104
+ letterSpacing: "0.8px",
105
+ color: "var(--sxl-muted, #8e8ea0)",
106
+ marginBottom: "10px"
53
107
  };
54
- var infoRow = {
108
+ var row = {
55
109
  display: "flex",
56
110
  alignItems: "baseline",
57
111
  gap: "8px",
58
- marginBottom: "4px"
112
+ marginBottom: "6px"
59
113
  };
60
- var infoLabel = {
114
+ var rowLabel = {
61
115
  fontSize: "12px",
62
116
  fontWeight: 500,
63
- color: "var(--sxl-label, #666)",
64
- minWidth: "90px",
117
+ color: "var(--sxl-label, #6b6b80)",
118
+ minWidth: "80px",
65
119
  flexShrink: 0
66
120
  };
67
- var infoValue = {
121
+ var rowValue = {
68
122
  fontSize: "13px",
69
- color: "var(--sxl-text, #333)",
123
+ color: "var(--sxl-text, #1a1a2e)",
70
124
  wordBreak: "break-word"
71
125
  };
72
126
  var mono = {
73
- fontFamily: MONO_STACK,
127
+ fontFamily: MONO,
74
128
  fontSize: "12px"
75
129
  };
76
- var statusBadge = {
77
- display: "inline-flex",
78
- alignItems: "center",
79
- gap: "6px",
80
- fontSize: "12px",
81
- fontWeight: 500
130
+ var descriptionText = {
131
+ fontSize: "13px",
132
+ color: "var(--sxl-text, #3a3a4a)",
133
+ lineHeight: 1.6,
134
+ margin: 0
82
135
  };
83
- var statusDot = {
84
- width: "8px",
85
- height: "8px",
86
- borderRadius: "50%",
87
- display: "inline-block",
88
- flexShrink: 0
136
+ var embedWrap = {
137
+ borderRadius: "10px",
138
+ overflow: "hidden",
139
+ border: "1px solid var(--sxl-border, #ebebf0)"
140
+ };
141
+ var iframe = {
142
+ width: "100%",
143
+ height: "380px",
144
+ border: "none",
145
+ display: "block"
89
146
  };
90
- var propsList = {
147
+ var embedActions = {
148
+ display: "flex",
149
+ justifyContent: "flex-end",
150
+ padding: "8px 12px",
151
+ borderTop: "1px solid var(--sxl-border, #ebebf0)",
152
+ backgroundColor: "var(--sxl-card-bg, #f8f8fb)"
153
+ };
154
+ var embedLink = {
155
+ fontSize: "11px",
156
+ fontWeight: 600,
157
+ color: "var(--sxl-link, #18a0fb)",
158
+ textDecoration: "none"
159
+ };
160
+ var tagList = {
91
161
  display: "flex",
92
162
  flexWrap: "wrap",
93
- gap: "4px"
163
+ gap: "6px"
94
164
  };
95
- var propBadge = {
165
+ var tag = {
96
166
  fontSize: "11px",
97
- fontFamily: MONO_STACK,
98
- backgroundColor: "var(--sxl-badge-bg, #eef)",
99
- color: "var(--sxl-badge-text, #336)",
100
- padding: "2px 6px",
167
+ fontFamily: MONO,
168
+ backgroundColor: "var(--sxl-tag-bg, #eef0ff)",
169
+ color: "var(--sxl-tag-text, #3d4a8c)",
170
+ padding: "3px 8px",
171
+ borderRadius: "5px",
172
+ fontWeight: 500
173
+ };
174
+ var frameworkTag = {
175
+ fontSize: "10px",
176
+ fontFamily: FONT,
177
+ fontWeight: 700,
178
+ textTransform: "uppercase",
179
+ letterSpacing: "0.4px",
180
+ backgroundColor: "var(--sxl-fw-bg, #e8faf0)",
181
+ color: "var(--sxl-fw-text, #1a7a4c)",
182
+ padding: "2px 7px",
101
183
  borderRadius: "4px"
102
184
  };
103
- var emptyState = {
104
- textAlign: "center",
105
- padding: "32px 16px"
185
+ var codeBlock = {
186
+ fontFamily: MONO,
187
+ fontSize: "11px",
188
+ backgroundColor: "var(--sxl-code-bg, #f3f3f8)",
189
+ border: "1px solid var(--sxl-border, #ebebf0)",
190
+ borderRadius: "8px",
191
+ padding: "12px 14px",
192
+ overflow: "auto",
193
+ lineHeight: 1.65,
194
+ whiteSpace: "pre",
195
+ margin: 0
196
+ };
197
+ var emptyContainer = {
198
+ display: "flex",
199
+ flexDirection: "column",
200
+ alignItems: "center",
201
+ justifyContent: "center",
202
+ height: "100%",
203
+ padding: "40px 20px",
204
+ fontFamily: FONT,
205
+ textAlign: "center"
106
206
  };
107
207
  var emptyTitle = {
108
- fontSize: "14px",
208
+ fontSize: "15px",
109
209
  fontWeight: 600,
110
- color: "var(--sxl-muted, #666)",
111
- marginBottom: "16px",
210
+ color: "var(--sxl-text, #3a3a4a)",
211
+ marginBottom: "8px",
112
212
  marginTop: 0
113
213
  };
114
214
  var emptyHint = {
115
215
  fontSize: "12px",
116
- color: "var(--sxl-muted, #999)",
117
- marginBottom: "8px"
118
- };
119
- var code = {
120
- fontFamily: MONO_STACK,
121
- fontSize: "11px",
122
- backgroundColor: "var(--sxl-code-bg, #f0f0f0)",
123
- padding: "1px 4px",
124
- borderRadius: "3px"
125
- };
126
- var codeBlock = {
127
- fontFamily: MONO_STACK,
128
- fontSize: "11px",
129
- backgroundColor: "var(--sxl-code-bg, #f5f5f5)",
130
- border: "1px solid var(--sxl-border, #e6e6e6)",
131
- borderRadius: "6px",
132
- padding: "12px",
133
- textAlign: "left",
134
- overflow: "auto",
216
+ color: "var(--sxl-muted, #8e8ea0)",
135
217
  marginBottom: "12px",
136
- lineHeight: 1.6,
137
- whiteSpace: "pre"
218
+ marginTop: 0
138
219
  };
139
- var figmaLink = {
220
+ var emptyCode = {
221
+ fontFamily: MONO,
140
222
  fontSize: "11px",
141
- color: "var(--sxl-link, #18a0fb)",
142
- textDecoration: "none"
223
+ backgroundColor: "var(--sxl-code-bg, #f3f3f8)",
224
+ padding: "2px 5px",
225
+ borderRadius: "4px"
143
226
  };
144
227
 
145
228
  // src/components/SxlPanel.tsx
146
- var TOKEN_STATUS_MAP = {
147
- assigned: { label: "Assigned", color: "#1bc47d" },
148
- partial: { label: "Partial", color: "#f5a623" },
149
- none: { label: "None", color: "#b0b0b0" }
229
+ var TOKEN_MAP = {
230
+ assigned: { label: "Tokens", fg: "#166534", bg: "#dcfce7", dot: "#22c55e" },
231
+ partial: { label: "Tokens (partial)", fg: "#92400e", bg: "#fef3c7", dot: "#f59e0b" },
232
+ none: { label: "No tokens", fg: "#6b7280", bg: "#f3f4f6", dot: "#9ca3af" }
150
233
  };
151
234
  var READINESS_MAP = {
152
- "complete": { label: "Complete", color: "#1bc47d" },
153
- "ready-for-dev": { label: "Ready for Dev", color: "#18a0fb" },
154
- "in-progress": { label: "In Progress", color: "#f5a623" },
155
- "backlog": { label: "Backlog", color: "#b0b0b0" }
235
+ "complete": { label: "Complete", fg: "#166534", bg: "#dcfce7", dot: "#22c55e" },
236
+ "ready-for-dev": { label: "Ready for Dev", fg: "#1e40af", bg: "#dbeafe", dot: "#3b82f6" },
237
+ "in-progress": { label: "In Progress", fg: "#92400e", bg: "#fef3c7", dot: "#f59e0b" },
238
+ "backlog": { label: "Backlog", fg: "#6b7280", bg: "#f3f4f6", dot: "#9ca3af" }
156
239
  };
157
240
  function resolveEntry(params) {
158
241
  if (!params) return null;
@@ -160,11 +243,12 @@ function resolveEntry(params) {
160
243
  if (params.figmaUrl || params.description) {
161
244
  return {
162
245
  nodeId: params.figmaNodeId ?? "",
163
- displayName: params.component ?? "",
246
+ displayName: params.component ?? params.componentName ?? "",
164
247
  description: params.description,
165
248
  figmaUrl: params.figmaUrl,
166
- designEmbed: !!params.figmaUrl,
167
- metadata: !!params.description,
249
+ designEmbed: params.designEmbed ?? !!params.figmaUrl,
250
+ compositionJson: params.compositionJson,
251
+ metadata: params.metadata,
168
252
  meta: {
169
253
  tokenStatus: params.tokenStatus,
170
254
  readiness: params.readiness
@@ -176,17 +260,15 @@ function resolveEntry(params) {
176
260
  if (params.figmaNodeId) {
177
261
  found = registry.entries.find((e) => e.nodeId === params.figmaNodeId);
178
262
  }
179
- if (!found && params.component) {
180
- const name = params.component.toLowerCase();
181
- found = registry.entries.find((e) => e.displayName.toLowerCase() === name);
263
+ if (!found) {
264
+ const name = (params.component ?? params.componentName ?? "").toLowerCase();
265
+ if (name) {
266
+ found = registry.entries.find((e) => e.displayName.toLowerCase() === name);
267
+ }
268
+ }
269
+ if (!found && registry.entries.length === 1) {
270
+ found = registry.entries[0];
182
271
  }
183
- console.info("[SXL Storybook Addon] resolve-entry", {
184
- hasRegistry: !!registry,
185
- registryEntries: registry?.entries?.length ?? 0,
186
- figmaNodeId: params.figmaNodeId ?? null,
187
- component: params.component ?? null,
188
- found: found ? { nodeId: found.nodeId, displayName: found.displayName } : null
189
- });
190
272
  if (!found) return null;
191
273
  return {
192
274
  ...found,
@@ -195,57 +277,80 @@ function resolveEntry(params) {
195
277
  tokenStatus: params.tokenStatus ?? found.meta?.tokenStatus,
196
278
  readiness: params.readiness ?? found.meta?.readiness
197
279
  },
198
- description: params.description ?? found.description
280
+ description: params.description ?? found.description,
281
+ compositionJson: params.compositionJson ?? found.compositionJson,
282
+ metadata: params.metadata ?? found.metadata,
283
+ designEmbed: params.designEmbed ?? found.designEmbed
199
284
  };
200
285
  }
201
286
  function buildEmbedUrl(figmaUrl) {
202
287
  if (figmaUrl.includes("figma.com/embed")) return figmaUrl;
203
288
  return `https://www.figma.com/embed?embed_host=storybook&url=${encodeURIComponent(figmaUrl)}`;
204
289
  }
205
- function buildDesignUrl(figmaUrl) {
206
- if (figmaUrl.includes("figma.com/embed")) {
207
- try {
208
- const u = new URL(figmaUrl);
209
- return u.searchParams.get("url") ?? figmaUrl;
210
- } catch {
211
- return figmaUrl;
212
- }
290
+ function buildDevModeUrl(figmaUrl) {
291
+ try {
292
+ const u = new URL(figmaUrl.includes("figma.com/embed") ? new URL(figmaUrl).searchParams.get("url") ?? figmaUrl : figmaUrl);
293
+ u.searchParams.set("m", "dev");
294
+ return u.toString();
295
+ } catch {
296
+ return figmaUrl;
297
+ }
298
+ }
299
+ function formatDate(iso) {
300
+ if (!iso) return null;
301
+ try {
302
+ return new Intl.DateTimeFormat("en-US", {
303
+ month: "short",
304
+ day: "numeric",
305
+ year: "numeric",
306
+ hour: "2-digit",
307
+ minute: "2-digit"
308
+ }).format(new Date(iso));
309
+ } catch {
310
+ return iso;
213
311
  }
214
- return figmaUrl;
215
312
  }
216
- var EmptyState = () => /* @__PURE__ */ React.createElement("div", { style: container }, /* @__PURE__ */ React.createElement("div", { style: emptyState }, /* @__PURE__ */ React.createElement("p", { style: emptyTitle }, "No SXL data for this story"), /* @__PURE__ */ React.createElement("p", { style: emptyHint }, "Import the registry in\xA0", /* @__PURE__ */ React.createElement("code", { style: code }, ".storybook/preview.ts"), ":"), /* @__PURE__ */ React.createElement("pre", { style: codeBlock }, `import registry from '../sxl-codeconnect.json';
313
+ var Badge = ({
314
+ label,
315
+ fg,
316
+ bg,
317
+ dot
318
+ }) => /* @__PURE__ */ React.createElement("span", { style: { ...badge, color: fg, backgroundColor: bg } }, /* @__PURE__ */ React.createElement("span", { style: { ...badgeDot, backgroundColor: dot } }), label);
319
+ var EmptyState = () => /* @__PURE__ */ React.createElement("div", { style: emptyContainer }, /* @__PURE__ */ React.createElement("p", { style: emptyTitle }, "No SXL data for this story"), /* @__PURE__ */ React.createElement("p", { style: emptyHint }, "Import the registry in ", /* @__PURE__ */ React.createElement("code", { style: emptyCode }, ".storybook/preview.ts"), ":"), /* @__PURE__ */ React.createElement("pre", { style: codeBlock }, `import raw from '../diff-code-connect.YOUR_KEY.json';
320
+ import { fromDiffCodeConnect } from '@sxl-studio/storybook-addon';
217
321
 
218
322
  export default {
219
323
  parameters: {
220
- sxl: { registry },
324
+ sxl: { registry: fromDiffCodeConnect(raw) },
221
325
  },
222
326
  };`), /* @__PURE__ */ React.createElement("p", { style: emptyHint }, "Then match a story to a Figma component:"), /* @__PURE__ */ React.createElement("pre", { style: codeBlock }, `export const Default = {
223
327
  parameters: {
224
328
  sxl: { component: 'ButtonPrimary' },
225
329
  },
226
- };`)));
227
- var StatusRow = ({
228
- label,
229
- status,
230
- color
231
- }) => /* @__PURE__ */ React.createElement("div", { style: infoRow }, /* @__PURE__ */ React.createElement("span", { style: infoLabel }, label), /* @__PURE__ */ React.createElement("span", { style: statusBadge }, /* @__PURE__ */ React.createElement("span", { style: { ...statusDot, backgroundColor: color } }), status));
330
+ };`));
232
331
  var SxlPanel = () => {
233
332
  const params = useParameter(PARAM_KEY);
234
- console.info("[SXL Storybook Addon] panel-params", {
235
- hasParams: !!params,
236
- keys: params ? Object.keys(params) : [],
237
- hasRegistry: !!params?.registry,
238
- registryEntries: params?.registry?.entries?.length ?? 0
239
- });
240
333
  const entry = resolveEntry(params);
241
- if (!entry) return /* @__PURE__ */ React.createElement(EmptyState, null);
334
+ if (!entry) return React.createElement(EmptyState, null);
242
335
  const tokenStatus = entry.meta?.tokenStatus;
243
336
  const readiness = entry.meta?.readiness;
244
- const tokenInfo = tokenStatus ? TOKEN_STATUS_MAP[tokenStatus] : null;
337
+ const tokenInfo = tokenStatus ? TOKEN_MAP[tokenStatus] : null;
245
338
  const readinessInfo = readiness ? READINESS_MAP[readiness] : null;
339
+ const dateStr = formatDate(entry.updatedAt);
246
340
  const hasProps = !!entry.meta?.componentProperties?.length;
247
- const hasStatus = !!(tokenInfo || readinessInfo);
248
- return /* @__PURE__ */ React.createElement("div", { style: container }, entry.figmaUrl && entry.designEmbed !== false && /* @__PURE__ */ React.createElement("div", { style: embedSection }, /* @__PURE__ */ React.createElement(
341
+ const hasFiles = !!entry.files?.length;
342
+ const hasBadges = !!(tokenInfo || readinessInfo);
343
+ return /* @__PURE__ */ React.createElement("div", { style: root }, /* @__PURE__ */ React.createElement("div", { style: header }, /* @__PURE__ */ React.createElement("div", { style: headerLeft }, entry.displayName && /* @__PURE__ */ React.createElement("h2", { style: componentName }, entry.displayName), dateStr && /* @__PURE__ */ React.createElement("span", { style: updatedAt }, "Updated ", dateStr)), entry.figmaUrl && /* @__PURE__ */ React.createElement(
344
+ "a",
345
+ {
346
+ href: buildDevModeUrl(entry.figmaUrl),
347
+ target: "_blank",
348
+ rel: "noopener noreferrer",
349
+ style: figmaButton
350
+ },
351
+ /* @__PURE__ */ React.createElement(FigmaIcon, null),
352
+ "Open in Figma"
353
+ )), hasBadges && /* @__PURE__ */ React.createElement("div", { style: badgeRow }, tokenInfo && /* @__PURE__ */ React.createElement(Badge, { ...tokenInfo }), readinessInfo && /* @__PURE__ */ React.createElement(Badge, { ...readinessInfo })), entry.description && /* @__PURE__ */ React.createElement("div", { style: card }, /* @__PURE__ */ React.createElement("div", { style: cardTitle }, "Description"), /* @__PURE__ */ React.createElement("p", { style: descriptionText }, entry.description)), entry.figmaUrl && entry.designEmbed !== false && /* @__PURE__ */ React.createElement("div", { style: embedWrap }, /* @__PURE__ */ React.createElement(
249
354
  "iframe",
250
355
  {
251
356
  title: "Figma Design",
@@ -253,17 +358,18 @@ var SxlPanel = () => {
253
358
  style: iframe,
254
359
  allowFullScreen: true
255
360
  }
256
- )), (entry.displayName || entry.description || entry.nodeId) && /* @__PURE__ */ React.createElement("div", { style: section }, /* @__PURE__ */ React.createElement("div", { style: sectionTitle }, "Component"), entry.displayName && /* @__PURE__ */ React.createElement("div", { style: infoRow }, /* @__PURE__ */ React.createElement("span", { style: infoLabel }, "Name"), /* @__PURE__ */ React.createElement("span", { style: infoValue }, entry.displayName)), entry.description && /* @__PURE__ */ React.createElement("div", { style: infoRow }, /* @__PURE__ */ React.createElement("span", { style: infoLabel }, "Description"), /* @__PURE__ */ React.createElement("span", { style: infoValue }, entry.description)), entry.nodeId && /* @__PURE__ */ React.createElement("div", { style: infoRow }, /* @__PURE__ */ React.createElement("span", { style: infoLabel }, "Node ID"), /* @__PURE__ */ React.createElement("span", { style: { ...infoValue, ...mono } }, entry.nodeId)), entry.figmaUrl && /* @__PURE__ */ React.createElement("div", { style: infoRow }, /* @__PURE__ */ React.createElement("span", { style: infoLabel }, "Figma"), /* @__PURE__ */ React.createElement(
361
+ ), /* @__PURE__ */ React.createElement("div", { style: embedActions }, /* @__PURE__ */ React.createElement(
257
362
  "a",
258
363
  {
259
- href: buildDesignUrl(entry.figmaUrl),
364
+ href: buildDevModeUrl(entry.figmaUrl),
260
365
  target: "_blank",
261
366
  rel: "noopener noreferrer",
262
- style: figmaLink
367
+ style: embedLink
263
368
  },
264
- "Open in Figma \u2197"
265
- ))), hasProps && /* @__PURE__ */ React.createElement("div", { style: section }, /* @__PURE__ */ React.createElement("div", { style: sectionTitle }, "Contract"), /* @__PURE__ */ React.createElement("div", { style: infoRow }, /* @__PURE__ */ React.createElement("span", { style: infoLabel }, "Properties"), /* @__PURE__ */ React.createElement("span", { style: propsList }, entry.meta.componentProperties.map((p) => /* @__PURE__ */ React.createElement("span", { key: p, style: propBadge }, p)))), entry.meta.variantCount != null && /* @__PURE__ */ React.createElement("div", { style: infoRow }, /* @__PURE__ */ React.createElement("span", { style: infoLabel }, "Variants"), /* @__PURE__ */ React.createElement("span", { style: infoValue }, entry.meta.variantCount))), hasStatus && /* @__PURE__ */ React.createElement("div", { style: section }, /* @__PURE__ */ React.createElement("div", { style: sectionTitle }, "Status"), tokenInfo && /* @__PURE__ */ React.createElement(StatusRow, { label: "Tokens", status: tokenInfo.label, color: tokenInfo.color }), readinessInfo && /* @__PURE__ */ React.createElement(StatusRow, { label: "Readiness", status: readinessInfo.label, color: readinessInfo.color })));
369
+ "Open in Figma Dev Mode \u2192"
370
+ ))), (hasProps || entry.meta?.variantCount != null) && /* @__PURE__ */ React.createElement("div", { style: card }, /* @__PURE__ */ React.createElement("div", { style: cardTitle }, "API Contract"), hasProps && /* @__PURE__ */ React.createElement("div", { style: row }, /* @__PURE__ */ React.createElement("span", { style: rowLabel }, "Props"), /* @__PURE__ */ React.createElement("span", { style: tagList }, entry.meta.componentProperties.map((p) => /* @__PURE__ */ React.createElement("span", { key: p, style: tag }, p)))), entry.meta?.variantCount != null && /* @__PURE__ */ React.createElement("div", { style: row }, /* @__PURE__ */ React.createElement("span", { style: rowLabel }, "Variants"), /* @__PURE__ */ React.createElement("span", { style: rowValue }, entry.meta.variantCount))), (entry.importPath || hasFiles || entry.snippetTemplate) && /* @__PURE__ */ React.createElement("div", { style: card }, /* @__PURE__ */ React.createElement("div", { style: cardTitle }, "Code Connect"), entry.importPath && /* @__PURE__ */ React.createElement("div", { style: row }, /* @__PURE__ */ React.createElement("span", { style: rowLabel }, "Import"), /* @__PURE__ */ React.createElement("span", { style: { ...rowValue, ...mono } }, entry.importPath)), hasFiles && /* @__PURE__ */ React.createElement("div", { style: row }, /* @__PURE__ */ React.createElement("span", { style: rowLabel }, "Files"), /* @__PURE__ */ React.createElement("span", { style: tagList }, entry.files.map((f) => /* @__PURE__ */ React.createElement("span", { key: f.filePath, style: { display: "inline-flex", alignItems: "center", gap: "4px" } }, /* @__PURE__ */ React.createElement("span", { style: frameworkTag }, f.framework), /* @__PURE__ */ React.createElement("span", { style: { ...rowValue, ...mono, fontSize: "11px" } }, f.filePath))))), entry.snippetTemplate && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { style: { ...cardTitle, marginTop: "10px", marginBottom: "6px" } }, "Snippet Template"), /* @__PURE__ */ React.createElement("pre", { style: codeBlock }, entry.snippetTemplate))), entry.compositionJson && /* @__PURE__ */ React.createElement("div", { style: card }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: "8px" } }, /* @__PURE__ */ React.createElement("div", { style: cardTitle }, "Composition JSON"), /* @__PURE__ */ React.createElement(Badge, { label: "Enabled", fg: "#166534", bg: "#dcfce7", dot: "#22c55e" }))), entry.nodeId && /* @__PURE__ */ React.createElement("div", { style: { fontSize: "10px", color: "var(--sxl-muted, #b0b0b8)", textAlign: "right" } }, "Node: ", entry.nodeId));
266
371
  };
372
+ var FigmaIcon = () => /* @__PURE__ */ React.createElement("svg", { width: "14", height: "14", viewBox: "0 0 38 57", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ React.createElement("path", { d: "M19 28.5C19 23.2533 23.2533 19 28.5 19C33.7467 19 38 23.2533 38 28.5C38 33.7467 33.7467 38 28.5 38C23.2533 38 19 33.7467 19 28.5Z", fill: "#1ABCFE" }), /* @__PURE__ */ React.createElement("path", { d: "M0 47.5C0 42.2533 4.25329 38 9.5 38H19V47.5C19 52.7467 14.7467 57 9.5 57C4.25329 57 0 52.7467 0 47.5Z", fill: "#0ACF83" }), /* @__PURE__ */ React.createElement("path", { d: "M19 0V19H28.5C33.7467 19 38 14.7467 38 9.5C38 4.25329 33.7467 0 28.5 0H19Z", fill: "#FF7262" }), /* @__PURE__ */ React.createElement("path", { d: "M0 9.5C0 14.7467 4.25329 19 9.5 19H19V0H9.5C4.25329 0 0 4.25329 0 9.5Z", fill: "#F24E1E" }), /* @__PURE__ */ React.createElement("path", { d: "M0 28.5C0 33.7467 4.25329 38 9.5 38H19V19H9.5C4.25329 19 0 23.2533 0 28.5Z", fill: "#A259FF" }));
267
373
 
268
374
  // src/manager.tsx
269
375
  var REGISTRY_GUARD_KEY = "__sxlStudioAddonRegistered__";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sxl-studio/storybook-addon",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Storybook addon for SXL Studio — displays Figma Embed, component info and design token status for linked components",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",