From 1072bc6226e1ba0fe554c655c821571ead9626da Mon Sep 17 00:00:00 2001 From: maro Date: Fri, 6 Dec 2024 03:44:29 +0900 Subject: [PATCH] feat: dynamic JSX interface inheritance (#71) - Added `ReactHTMLProps` utility type to dynamically handle React HTML element type definitions. - Fixed incorrect type generation for some elements (e.g., `input`), ensuring appropriate attribute types are used. --- src/html.ts | 115 ------------------------------------------------- src/index.ts | 14 +++--- test/mist.d.ts | 14 ++++-- 3 files changed, 16 insertions(+), 127 deletions(-) delete mode 100644 src/html.ts diff --git a/src/html.ts b/src/html.ts deleted file mode 100644 index 747aa44..0000000 --- a/src/html.ts +++ /dev/null @@ -1,115 +0,0 @@ -// Ref: lib.dom.d.ts -module.exports = { - a: 'HTMLAnchorElement', - abbr: 'HTMLElement', - address: 'HTMLElement', - area: 'HTMLAreaElement', - article: 'HTMLElement', - aside: 'HTMLElement', - audio: 'HTMLAudioElement', - b: 'HTMLElement', - base: 'HTMLBaseElement', - bdi: 'HTMLElement', - bdo: 'HTMLElement', - blockquote: 'HTMLQuoteElement', - body: 'HTMLBodyElement', - br: 'HTMLBRElement', - button: 'HTMLButtonElement', - canvas: 'HTMLCanvasElement', - caption: 'HTMLTableCaptionElement', - cite: 'HTMLElement', - code: 'HTMLElement', - col: 'HTMLTableColElement', - colgroup: 'HTMLTableColElement', - data: 'HTMLDataElement', - datalist: 'HTMLDataListElement', - dd: 'HTMLElement', - del: 'HTMLModElement', - details: 'HTMLDetailsElement', - dfn: 'HTMLElement', - dialog: 'HTMLDialogElement', - div: 'HTMLDivElement', - dl: 'HTMLDListElement', - dt: 'HTMLElement', - em: 'HTMLElement', - embed: 'HTMLEmbedElement', - fieldset: 'HTMLFieldSetElement', - figcaption: 'HTMLElement', - figure: 'HTMLElement', - footer: 'HTMLElement', - form: 'HTMLFormElement', - h1: 'HTMLHeadingElement', - h2: 'HTMLHeadingElement', - h3: 'HTMLHeadingElement', - h4: 'HTMLHeadingElement', - h5: 'HTMLHeadingElement', - h6: 'HTMLHeadingElement', - head: 'HTMLHeadElement', - header: 'HTMLElement', - hgroup: 'HTMLElement', - hr: 'HTMLHRElement', - html: 'HTMLHtmlElement', - i: 'HTMLElement', - iframe: 'HTMLIFrameElement', - img: 'HTMLImageElement', - input: 'HTMLInputElement', - ins: 'HTMLModElement', - kbd: 'HTMLElement', - label: 'HTMLLabelElement', - legend: 'HTMLLegendElement', - li: 'HTMLLIElement', - link: 'HTMLLinkElement', - main: 'HTMLElement', - map: 'HTMLMapElement', - mark: 'HTMLElement', - menu: 'HTMLMenuElement', - meta: 'HTMLMetaElement', - meter: 'HTMLMeterElement', - nav: 'HTMLElement', - noscript: 'HTMLElement', - object: 'HTMLObjectElement', - ol: 'HTMLOListElement', - optgroup: 'HTMLOptGroupElement', - option: 'HTMLOptionElement', - output: 'HTMLOutputElement', - p: 'HTMLParagraphElement', - picture: 'HTMLPictureElement', - pre: 'HTMLPreElement', - progress: 'HTMLProgressElement', - q: 'HTMLQuoteElement', - rp: 'HTMLElement', - rt: 'HTMLElement', - ruby: 'HTMLElement', - s: 'HTMLElement', - samp: 'HTMLElement', - script: 'HTMLScriptElement', - search: 'HTMLElement', - section: 'HTMLElement', - select: 'HTMLSelectElement', - slot: 'HTMLSlotElement', - small: 'HTMLElement', - source: 'HTMLSourceElement', - span: 'HTMLSpanElement', - strong: 'HTMLElement', - style: 'HTMLStyleElement', - sub: 'HTMLElement', - summary: 'HTMLElement', - sup: 'HTMLElement', - table: 'HTMLTableElement', - tbody: 'HTMLTableSectionElement', - td: 'HTMLTableCellElement', - template: 'HTMLTemplateElement', - textarea: 'HTMLTextAreaElement', - tfoot: 'HTMLTableSectionElement', - th: 'HTMLTableCellElement', - thead: 'HTMLTableSectionElement', - time: 'HTMLTimeElement', - title: 'HTMLTitleElement', - tr: 'HTMLTableRowElement', - track: 'HTMLTrackElement', - u: 'HTMLElement', - ul: 'HTMLUListElement', - var: 'HTMLElement', - video: 'HTMLVideoElement', - wbr: 'HTMLElement', -} diff --git a/src/index.ts b/src/index.ts index 621f19b..d6ab7f1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,6 @@ import { type PluginCreator } from 'postcss' import selectorParser = require('postcss-selector-parser') import atImport = require('postcss-import') import path = require('node:path') -const html = require('./html') const key = require('./key') declare module 'postcss-selector-parser' { @@ -27,7 +26,11 @@ type Parsed = Record< > function render(parsed: Parsed): string { - let interfaceDefinitions = '' + let interfaceDefinitions = `type ReactHTMLProps< + Tag extends keyof React.ReactHTML +> = React.ReactHTML[Tag] extends React.DetailedHTMLFactory + ? React.DetailedHTMLProps + : React.DetailedHTMLProps, HTMLElement>\n\n` const jsxElements: Record = {} // Normalize @@ -101,12 +104,7 @@ function render(parsed: Parsed): string { const attributeEntries = Object.entries(attributes) - let htmlElement = 'HTMLElement' - if (tag in html) { - htmlElement = html[tag as keyof typeof html] - } - - let interfaceDefinition = `interface ${interfaceName} extends React.DetailedHTMLProps, ${htmlElement}> {\n` + let interfaceDefinition = `interface ${interfaceName} extends ReactHTMLProps<'${tag}'> {\n` discriminatorAttributes.forEach((attr) => { interfaceDefinition += ` '${attr}'?: never\n` diff --git a/test/mist.d.ts b/test/mist.d.ts index 047696c..ab4144f 100644 --- a/test/mist.d.ts +++ b/test/mist.d.ts @@ -1,18 +1,24 @@ -interface Mist_button extends React.DetailedHTMLProps, HTMLButtonElement> { +type ReactHTMLProps< + Tag extends keyof React.ReactHTML +> = React.ReactHTML[Tag] extends React.DetailedHTMLFactory + ? React.DetailedHTMLProps + : React.DetailedHTMLProps, HTMLElement> + +interface Mist_button extends ReactHTMLProps<'button'> { 'data-variant'?: 'primary' | 'secondary' style?: { '--highlightColor'?: string } & React.CSSProperties } -interface Mist_div extends React.DetailedHTMLProps, HTMLDivElement> { +interface Mist_div extends ReactHTMLProps<'div'> { 'data-component'?: never } -interface Mist_div_data_component_card extends React.DetailedHTMLProps, HTMLDivElement> { +interface Mist_div_data_component_card extends ReactHTMLProps<'div'> { 'data-component': 'card' 'data-size'?: 'sm' | 'xl' } -interface Mist_div_data_component_card_title extends React.DetailedHTMLProps, HTMLDivElement> { +interface Mist_div_data_component_card_title extends ReactHTMLProps<'div'> { 'data-component': 'card-title' }