镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Commit b8901ce

Browse files
committed
fix(components): draw a built-in on the web, not the native primitive of its name
The native primitives are a web page's components of last resort, but the check for a user override of a built-in searched them too. So in a dev server every <Icon> rendered the primitive's empty span in place of the built-in's SVG.
1 parent d187c11 commit b8901ce

2 files changed

Lines changed: 23 additions & 1 deletion

File tree

‎packages/stx/src/component-renderer.ts‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1184,9 +1184,16 @@ async function processCustomElementTags(
11841184
// A project-authored component file of the same name takes precedence so
11851185
// users can override built-ins (e.g. a custom `components/Icon.stx`
11861186
// shadowing the built-in Lucide `Icon`).
1187+
//
1188+
// The native primitives are components of last resort and nobody's
1189+
// override: a built-in is the web's own implementation of its name.
1190+
// Counted as a user file, the primitive `Icon` took every `<Icon>` on a
1191+
// web page from the built-in's SVG and drew an empty
1192+
// `<span data-native="Icon">`. A render target that owns the name (a
1193+
// native screen's `_targetComponentDirs`) still takes it.
11871194
const builtinDef = registry.getBuiltin(tag.tagName)
11881195
const overriddenByUser = builtinDef
1189-
? await userComponentFileExists(tag.tagName, componentsDir, context, filePath, options)
1196+
? await userComponentFileExists(tag.tagName, componentsDir, context, filePath, { ...options, _nativePrimitivesFallback: undefined })
11901197
: false
11911198
const sharedImage = tag.tagName === 'Image'
11921199
&& usesSharedImageApi([

‎packages/stx/test/native-primitives-on-web.test.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ it('an app component of the same name wins over the primitive', async () => {
4646
finally { clearComponentCache(); await rm(root, { recursive: true, force: true }) }
4747
})
4848

49+
it('a built-in of the same name is the web page\'s, not the primitive', async () => {
50+
const root = await realpath(createTempDir('stx-web-primitives-builtin-'))
51+
try {
52+
await Bun.write(path.join(root, 'stx.config.ts'), 'export default {}')
53+
clearComponentCache()
54+
const config = await loadStxConfig(root)
55+
const html = await render(root, '<button><Icon name="plus" size="15" /> New plan</button>', config)
56+
// The built-in Icon draws the picture; the primitive of last resort left an empty span.
57+
expect(html).toContain('<svg')
58+
expect(html).toContain('width="15"')
59+
expect(html).not.toContain('data-native="Icon"')
60+
}
61+
finally { clearComponentCache(); await rm(root, { recursive: true, force: true }) }
62+
})
63+
4964
it('leaves ordinary HTML elements of the same spelling alone', async () => {
5065
const root = await realpath(createTempDir('stx-web-primitives-html-'))
5166
try {

0 commit comments

Comments
 (0)