From 1b1a3286e4e182b248ae4b98984ef57eca171a8d Mon Sep 17 00:00:00 2001 From: SimeonC <1085899+SimeonC@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:32:01 +0900 Subject: [PATCH] fix: correctly scope checkboxes and radios in classy to avoid conflicts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed `width` calculation that was ignored as `calc(var(…)+ 2)` is ignored due to `var(…)+` being invalid. A space is required between `)` and `+` --- system/core/scripts/generateComponents.ts | 50 ++++++++++++------- system/core/src/components/Checkbox.ts | 1 + system/core/src/components/InputWithIcons.ts | 4 -- system/core/src/components/InputWithPrefix.ts | 4 -- system/core/src/components/Radio.ts | 1 + .../core/src/components/TextAreaWithIcons.ts | 4 -- .../core/src/components/TextAreaWithPrefix.ts | 4 -- system/css/src/buildFile.ts | 7 ++- system/react-css/src/components/Badge.tsx | 6 +-- system/react-css/src/components/Banner.tsx | 6 +-- system/react-css/src/components/Button.tsx | 8 ++- system/react-css/src/components/Checkbox.tsx | 2 +- .../react-css/src/components/IconButton.tsx | 8 ++- system/react-css/src/components/Radio.tsx | 2 +- system/react-css/src/utils.tsx | 18 ++++--- 15 files changed, 70 insertions(+), 55 deletions(-) diff --git a/system/core/scripts/generateComponents.ts b/system/core/scripts/generateComponents.ts index ae4587a26..0c35e7585 100644 --- a/system/core/scripts/generateComponents.ts +++ b/system/core/scripts/generateComponents.ts @@ -259,7 +259,6 @@ class CssComponentBuilder extends ComponentBuilder { } hasValidSelectors() { - if (this.pascalImportKey === 'Spinner') return true; if (this.className) return true; if (!this.element) return false; return !!this.defaultProps.find(([key]) => key === 'type'); @@ -293,9 +292,10 @@ class CssComponentBuilder extends ComponentBuilder { '${this.element}' >({ variants: ${JSON.stringify(this.getVariants())}, - className: '${this.className}', - element: '${this.element}', - displayName: '${this.pascalImportKey}' + ${this.buildWithComponentProps({ + elementName: this.element, + displayName: this.pascalImportKey + })}, });` ); } @@ -306,17 +306,37 @@ class CssComponentBuilder extends ComponentBuilder { writeForwardRefComponent({ varName, elementName, - omitVariants = false, displayName = '', + omitVariants = false, fixedProps: fixedPropsArg = this.fixedProps || [], shouldExport = false }) { - const propsType = omitVariants ? 'Omit' : 'Props'; + const propsType = `${ + omitVariants ? 'Omit' : 'Props' + } & ${this.reactHtmlAttributesType}`; + return `${ + shouldExport ? 'export ' : '' + }const ${varName} = buildWithComponent<${ + this.elementType + }, ${propsType}>({ ${this.buildWithComponentProps({ + elementName, + displayName: displayName || varName, + fixedProps: fixedPropsArg + })}});`; + } + + // eslint-disable-next-line @typescript-eslint/naming-convention + private buildWithComponentProps({ + elementName, + displayName = '', + fixedProps: fixedPropsArg = this.fixedProps || [] + }) { const props = this.buildProps(fixedPropsArg); const classNameProp = props.find(({ key }) => key === 'className'); - const append: string[] = [ - `className: ${classNameProp ? `'${classNameProp.value}'` : 'undefined'}` - ]; + if (!classNameProp) { + throw new Error(`Missing className prop for ${displayName}`); + } + const append: string[] = [`className: '${classNameProp.value}'`]; const additionalProps = props.filter(({ key }) => key !== 'className'); if (additionalProps.length) { append.push( @@ -328,15 +348,9 @@ class CssComponentBuilder extends ComponentBuilder { .join(', ')} }` ); } - return `${ - shouldExport ? 'export ' : '' - }const ${varName} = buildWithComponent<${ - this.elementType - }, ${propsType} & ${ - this.reactHtmlAttributesType - }>({ tag: '${elementName}', displayName: '${ - displayName || varName - }', ${append.join(', ')}});`; + return `tag: '${elementName}', displayName: '${displayName}', ${append.join( + ', ' + )}`; } protected formatDefaultProp(key: string) { diff --git a/system/core/src/components/Checkbox.ts b/system/core/src/components/Checkbox.ts index c8ef1f6fb..a7ef5856a 100644 --- a/system/core/src/components/Checkbox.ts +++ b/system/core/src/components/Checkbox.ts @@ -2,6 +2,7 @@ import { OptionalKeys, css } from '../utils'; export const element = 'input'; export const selectors = ['input[type="checkbox"]:not(.toggle)']; +export const className = 'checkbox'; export interface Props { type: 'checkbox'; diff --git a/system/core/src/components/InputWithIcons.ts b/system/core/src/components/InputWithIcons.ts index 4a2001664..148778803 100644 --- a/system/core/src/components/InputWithIcons.ts +++ b/system/core/src/components/InputWithIcons.ts @@ -77,10 +77,6 @@ export const fullStyles = css` } & > [data-mode='input-append'] { height: calc(var(--tk-input-height) - var(--tk-input-border-width) * 2); - width: calc( - var(--tk-input-icon-size)+ var(--tk-input-icon-gap)+ - var(--tk-input-icon-end-padding) - ); --tk-icon-button-padding: 8px !important; margin-top: 0; margin-bottom: 0; diff --git a/system/core/src/components/InputWithPrefix.ts b/system/core/src/components/InputWithPrefix.ts index 96230f56c..198a88833 100644 --- a/system/core/src/components/InputWithPrefix.ts +++ b/system/core/src/components/InputWithPrefix.ts @@ -85,10 +85,6 @@ export const fullStyles = css` & > [data-mode='input-append'] { grid-area: 1/4/1/5; height: calc(var(--tk-input-height) - var(--tk-input-border-width) * 2); - width: calc( - var(--tk-input-icon-size)+ var(--tk-input-icon-gap)+ - var(--tk-input-icon-end-padding) - ); --tk-icon-button-padding: 8px !important; margin-top: 0; margin-bottom: 0; diff --git a/system/core/src/components/Radio.ts b/system/core/src/components/Radio.ts index 9e2ef7d71..d5b989b9a 100644 --- a/system/core/src/components/Radio.ts +++ b/system/core/src/components/Radio.ts @@ -2,6 +2,7 @@ import { OptionalKeys, css } from '../utils'; export const element = 'input'; export const selectors = ['input[type="radio"]:not(.toggle)']; +export const className = 'radio'; export interface Props { type: 'radio'; diff --git a/system/core/src/components/TextAreaWithIcons.ts b/system/core/src/components/TextAreaWithIcons.ts index 0a0515dbe..8d0d2256e 100644 --- a/system/core/src/components/TextAreaWithIcons.ts +++ b/system/core/src/components/TextAreaWithIcons.ts @@ -96,10 +96,6 @@ export const fullStyles = css` } & > [data-mode='input-append'] { height: calc(var(--tk-input-height) - var(--tk-input-border-width) * 2); - width: calc( - var(--tk-input-icon-size)+ var(--tk-input-icon-gap)+ - var(--tk-input-icon-end-padding) - ); --tk-icon-button-padding: 8px !important; margin-top: 0; margin-bottom: 0; diff --git a/system/core/src/components/TextAreaWithPrefix.ts b/system/core/src/components/TextAreaWithPrefix.ts index b67239761..872a5c461 100644 --- a/system/core/src/components/TextAreaWithPrefix.ts +++ b/system/core/src/components/TextAreaWithPrefix.ts @@ -101,10 +101,6 @@ export const fullStyles = css` & > [data-mode='input-append'] { grid-area: 1/4/1/5; height: calc(var(--tk-input-height) - var(--tk-input-border-width) * 2); - width: calc( - var(--tk-input-icon-size)+ var(--tk-input-icon-gap)+ - var(--tk-input-icon-end-padding) - ); --tk-icon-button-padding: 8px !important; margin-top: 0; margin-bottom: 0; diff --git a/system/css/src/buildFile.ts b/system/css/src/buildFile.ts index b07776dcc..4204be900 100644 --- a/system/css/src/buildFile.ts +++ b/system/css/src/buildFile.ts @@ -140,7 +140,12 @@ export class ComponentBuilder extends CssFileBuilder { getClassySelectors() { const { element, className, selectors = [] } = this.fileContent; - if (!className) return selectors; + if (!className) { + console.warn( + `className is missing in ${this.folderName}/${this.fileName}` + ); + return selectors; + } if (element === 'input') return [`input.${className}`]; return [`.${className}`]; } diff --git a/system/react-css/src/components/Badge.tsx b/system/react-css/src/components/Badge.tsx index ced8ca868..43596350c 100644 --- a/system/react-css/src/components/Badge.tsx +++ b/system/react-css/src/components/Badge.tsx @@ -40,7 +40,7 @@ export const VariantBadge = buildVariantComponents< 'orange', 'disabled' ], - className: 'badge', - element: 'span', - displayName: 'Badge' + tag: 'span', + displayName: 'Badge', + className: 'badge' }); diff --git a/system/react-css/src/components/Banner.tsx b/system/react-css/src/components/Banner.tsx index 4ede4f6fe..a7e77f01d 100644 --- a/system/react-css/src/components/Banner.tsx +++ b/system/react-css/src/components/Banner.tsx @@ -20,7 +20,7 @@ export const VariantBanner = buildVariantComponents< 'div' >({ variants: ['tertiary', 'ghost', 'success', 'warning', 'info', 'neutral'], - className: 'banner', - element: 'div', - displayName: 'Banner' + tag: 'div', + displayName: 'Banner', + className: 'banner' }); diff --git a/system/react-css/src/components/Button.tsx b/system/react-css/src/components/Button.tsx index a917d01f6..6d88899a8 100644 --- a/system/react-css/src/components/Button.tsx +++ b/system/react-css/src/components/Button.tsx @@ -44,7 +44,11 @@ export const VariantButton = buildVariantComponents< 'bare', 'danger' ], + tag: 'button', + displayName: 'Button', className: 'btn', - element: 'button', - displayName: 'Button' + additionalProps: { + type: button.defaultProps.type as never, + 'data-size': { toString: () => getConfigDefault('controlSize') } + } }); diff --git a/system/react-css/src/components/Checkbox.tsx b/system/react-css/src/components/Checkbox.tsx index 8b58ad399..c89bd5022 100644 --- a/system/react-css/src/components/Checkbox.tsx +++ b/system/react-css/src/components/Checkbox.tsx @@ -16,6 +16,6 @@ export const Checkbox = buildWithComponent< >({ tag: 'input', displayName: 'Checkbox', - className: undefined, + className: 'checkbox', additionalProps: { type: checkbox.defaultProps.type as never } }); diff --git a/system/react-css/src/components/IconButton.tsx b/system/react-css/src/components/IconButton.tsx index e031bd0a0..34009c9b2 100644 --- a/system/react-css/src/components/IconButton.tsx +++ b/system/react-css/src/components/IconButton.tsx @@ -46,7 +46,11 @@ export const VariantIconButton = buildVariantComponents< 'danger', 'danger-bare' ], + tag: 'button', + displayName: 'IconButton', className: 'icon-button', - element: 'button', - displayName: 'IconButton' + additionalProps: { + type: 'button', + 'data-size': { toString: () => getConfigDefault('controlSize') } + } }); diff --git a/system/react-css/src/components/Radio.tsx b/system/react-css/src/components/Radio.tsx index 1daab1055..9c2dfd4d6 100644 --- a/system/react-css/src/components/Radio.tsx +++ b/system/react-css/src/components/Radio.tsx @@ -16,6 +16,6 @@ export const Radio = buildWithComponent< >({ tag: 'input', displayName: 'Radio', - className: undefined, + className: 'radio', additionalProps: { type: radio.defaultProps.type as never } }); diff --git a/system/react-css/src/utils.tsx b/system/react-css/src/utils.tsx index 29e89f932..d6b6a2ad5 100644 --- a/system/react-css/src/utils.tsx +++ b/system/react-css/src/utils.tsx @@ -140,14 +140,13 @@ export function buildVariantComponents< >({ variants, className, - element, - displayName + tag, + displayName, + additionalProps, + style }: { variants: TVariant[]; - className: string; - displayName: string; - element: TElement; -}): Record< +} & DecorateOptions): Record< Capitalize, React.ForwardRefExoticComponent & WithComponentType > { @@ -161,10 +160,13 @@ export function buildVariantComponents< HTMLElementTagNameMap[TElement], Omit >({ - tag: element, + tag, className, + style, displayName: `${displayName}_${variantKey}`, - additionalProps: { 'data-variant': key } + additionalProps: additionalProps + ? { ...additionalProps, 'data-variant': key } + : { 'data-variant': key } }) }; }, {} as Record, React.ForwardRefExoticComponent & WithComponentType>);