@@ -748,6 +748,24 @@ function propsFingerprint(props: Record<string, unknown>): string {
748748 return JSON . stringify ( meaningful , Object . keys ( meaningful ) . sort ( ) )
749749}
750750
751+ /** Suggest a story name based on meaningful prop values */
752+ function suggestStoryName ( props : Record < string , unknown > ) : string {
753+ const meaningfulProps = [ 'variant' , 'type' , 'size' , 'mode' , 'status' , 'kind' , 'color' , 'intent' , 'appearance' ]
754+ for ( const propName of meaningfulProps ) {
755+ const value = props [ propName ]
756+ if ( typeof value === 'string' && value . length > 0 && value . length < 30 ) {
757+ return value . charAt ( 0 ) . toUpperCase ( ) + value . slice ( 1 )
758+ }
759+ }
760+ for ( const [ , value ] of Object . entries ( props ) ) {
761+ if ( typeof value === 'boolean' && value ) continue
762+ if ( typeof value === 'string' && value . length > 0 && value . length < 30 ) {
763+ return value . charAt ( 0 ) . toUpperCase ( ) + value . slice ( 1 )
764+ }
765+ }
766+ return 'Default'
767+ }
768+
751769/** Fetch the registry snapshot from the server (RPC) */
752770/** Read the registry from shared state (synced automatically from client) */
753771function fetchRegistry ( ) : RegistryInstance [ ] {
@@ -1294,7 +1312,10 @@ async function buildHighlighterPanel() {
12941312 root . appendChild ( hdr )
12951313
12961314 // ── Properties section ──
1297- const propsEntries = Object . entries ( comp . props || { } )
1315+ // Use serializedProps when available (React) for __isJSX / __isFunction markers;
1316+ // fall back to raw props (Vue / Svelte where props are already serialized).
1317+ const displayProps = comp . serializedProps || comp . props || { }
1318+ const propsEntries = Object . entries ( displayProps )
12981319 if ( propsEntries . length > 0 ) {
12991320 const propsSection = document . createElement ( 'div' )
13001321 propsSection . className = 'hl-section'
@@ -1318,9 +1339,29 @@ async function buildHighlighterPanel() {
13181339 const val = document . createElement ( 'div' )
13191340 val . className = 'hl-prop-val'
13201341
1321- // Create an editable input for primitive values
13221342 const valType = typeof value
1323- if ( valType === 'string' || valType === 'number' || valType === 'boolean' ) {
1343+ const isObj = value && typeof value === 'object'
1344+ const isFunction = isObj && ( value as Record < string , unknown > ) . __isFunction
1345+ const isJSX = isObj && ( value as Record < string , unknown > ) . __isJSX
1346+
1347+ if ( isFunction ) {
1348+ // Handler / function prop
1349+ const fn = value as { __isFunction : true ; name : string }
1350+ val . innerHTML = `<span class="hl-prop-fn">${ fn . name ? fn . name : '() => {}' } </span>`
1351+ } else if ( isJSX ) {
1352+ // JSX prop — show source in a collapsible code block
1353+ const jsx = value as { __isJSX : true ; source : string }
1354+ const wrapper = document . createElement ( 'details' )
1355+ wrapper . className = 'hl-prop-details'
1356+ const summary = document . createElement ( 'summary' )
1357+ summary . innerHTML = `<span class="hl-prop-jsx-badge">JSX</span>`
1358+ wrapper . appendChild ( summary )
1359+ const code = document . createElement ( 'pre' )
1360+ code . className = 'hl-prop-code'
1361+ code . textContent = jsx . source
1362+ wrapper . appendChild ( code )
1363+ val . appendChild ( wrapper )
1364+ } else if ( valType === 'string' || valType === 'number' || valType === 'boolean' ) {
13241365 const input = document . createElement ( 'input' )
13251366 input . className = 'hl-prop-input'
13261367 input . type = valType === 'boolean' ? 'checkbox' : valType === 'number' ? 'number' : 'text'
@@ -1330,7 +1371,6 @@ async function buildHighlighterPanel() {
13301371 input . value = String ( value )
13311372 }
13321373 input . addEventListener ( 'change' , ( ) => {
1333- // Update the local props for story creation
13341374 if ( valType === 'boolean' ) {
13351375 comp . props [ key ] = input . checked
13361376 } else if ( valType === 'number' ) {
@@ -1343,8 +1383,21 @@ async function buildHighlighterPanel() {
13431383 } else if ( value === null || value === undefined ) {
13441384 val . innerHTML = `<span class="hl-prop-null">${ String ( value ) } </span>`
13451385 } else {
1346- // Complex objects — show a collapsed badge
1347- val . innerHTML = `<span class="hl-prop-obj">${ Array . isArray ( value ) ? 'Array' : 'Object' } </span>`
1386+ // Complex objects/arrays — show collapsible JSON
1387+ const wrapper = document . createElement ( 'details' )
1388+ wrapper . className = 'hl-prop-details'
1389+ const summary = document . createElement ( 'summary' )
1390+ summary . innerHTML = `<span class="hl-prop-obj">${ Array . isArray ( value ) ? `Array(${ ( value as unknown [ ] ) . length } )` : 'Object' } </span>`
1391+ wrapper . appendChild ( summary )
1392+ const code = document . createElement ( 'pre' )
1393+ code . className = 'hl-prop-code'
1394+ try {
1395+ code . textContent = JSON . stringify ( value , null , 2 )
1396+ } catch {
1397+ code . textContent = String ( value )
1398+ }
1399+ wrapper . appendChild ( code )
1400+ val . appendChild ( wrapper )
13481401 }
13491402
13501403 row . appendChild ( label )
@@ -1364,6 +1417,19 @@ async function buildHighlighterPanel() {
13641417 createHdr . className = 'hl-section-hdr'
13651418 createHdr . innerHTML = `<span class="hl-section-title">Create Story</span>`
13661419
1420+ createSection . appendChild ( createHdr )
1421+
1422+ // Story name input
1423+ const storyNameRow = document . createElement ( 'div' )
1424+ storyNameRow . className = 'hl-story-name-row'
1425+ const storyNameInput = document . createElement ( 'input' )
1426+ storyNameInput . className = 'hl-prop-input'
1427+ storyNameInput . type = 'text'
1428+ storyNameInput . placeholder = 'Story name\u2026'
1429+ storyNameInput . value = suggestStoryName ( comp . props )
1430+ storyNameInput . addEventListener ( 'focus' , ( ) => storyNameInput . select ( ) )
1431+ storyNameRow . appendChild ( storyNameInput )
1432+
13671433 const addBtn = document . createElement ( 'button' )
13681434 addBtn . className = 'create-all-btn'
13691435 addBtn . textContent = 'Add'
@@ -1375,6 +1441,7 @@ async function buildHighlighterPanel() {
13751441 meta : comp . meta ,
13761442 props : comp . props ,
13771443 serializedProps : comp . serializedProps ,
1444+ storyName : storyNameInput . value . trim ( ) || undefined ,
13781445 } )
13791446 // Bust the storybook index cache and retry until the new story appears
13801447 const refreshAfterCreate = async ( ) => {
@@ -1401,9 +1468,9 @@ async function buildHighlighterPanel() {
14011468 addBtn . textContent = 'Add'
14021469 }
14031470 } )
1404- createHdr . appendChild ( addBtn )
1471+ storyNameRow . appendChild ( addBtn )
14051472
1406- createSection . appendChild ( createHdr )
1473+ createSection . appendChild ( storyNameRow )
14071474 root . appendChild ( createSection )
14081475
14091476 // ── Stories section ──
0 commit comments