Use HTMLElementTagNameMap to unify both rendering and typing.master
@@ -2,10 +2,14 @@ import * as React from 'react'; | |||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
import { Button } from '@tesseract-design/web-base'; | import { Button } from '@tesseract-design/web-base'; | ||||
const ActionButtonDerivedElementComponent = 'button' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link ActionButton} component. | * Derived HTML element of the {@link ActionButton} component. | ||||
*/ | */ | ||||
export type ActionButtonDerivedElement = HTMLButtonElement; | |||||
export type ActionButtonDerivedElement = HTMLElementTagNameMap[ | |||||
typeof ActionButtonDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link ActionButton} component. | * Props of the {@link ActionButton} component. | ||||
@@ -76,7 +80,7 @@ export const ActionButton = React.forwardRef<ActionButtonDerivedElement, ActionB | |||||
}, | }, | ||||
forwardedRef, | forwardedRef, | ||||
) => ( | ) => ( | ||||
<button | |||||
<ActionButtonDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
data-testid="button" | data-testid="button" | ||||
type={type} | type={type} | ||||
@@ -184,7 +188,7 @@ export const ActionButton = React.forwardRef<ActionButtonDerivedElement, ActionB | |||||
</svg> | </svg> | ||||
</span> | </span> | ||||
)} | )} | ||||
</button> | |||||
</ActionButtonDerivedElementComponent> | |||||
)); | )); | ||||
ActionButton.displayName = 'ActionButton' as const; | ActionButton.displayName = 'ActionButton' as const; | ||||
@@ -2,9 +2,7 @@ import * as React from 'react'; | |||||
import { useClientSide, useFallbackId, useProxyInput } from '@modal-sh/react-utils'; | import { useClientSide, useFallbackId, useProxyInput } from '@modal-sh/react-utils'; | ||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
const DEFAULT_ENHANCED_HEIGHT_PX = 64 as const; | |||||
const DEFAULT_NON_ENHANCED_SIDE_HEIGHT_PX = 256 as const; | |||||
const FileSelectBoxDefaultPreviewComponentDerivedElementComponent = 'div' as const; | |||||
/** | /** | ||||
* Common props for the {@link FileSelectBoxProps.previewComponent|previewComponent prop} of the | * Common props for the {@link FileSelectBoxProps.previewComponent|previewComponent prop} of the | ||||
@@ -29,57 +27,9 @@ export interface CommonPreviewComponentProps<F extends Partial<File> = Partial<F | |||||
mini?: boolean; | mini?: boolean; | ||||
} | } | ||||
/** | |||||
* Derived HTML element of the {@link FileSelectBox} component. | |||||
*/ | |||||
export type FileSelectBoxDerivedElement = HTMLInputElement; | |||||
/** | |||||
* Props of the {@link FileSelectBox} component. | |||||
*/ | |||||
export interface FileSelectBoxProps< | |||||
F extends Partial<File> = Partial<File>, | |||||
P extends CommonPreviewComponentProps<F> = CommonPreviewComponentProps<F> | |||||
> extends Omit<React.HTMLProps<FileSelectBoxDerivedElement>, 'size' | 'type' | 'label' | 'list'> { | |||||
/** | |||||
* Should the component display a border? | |||||
*/ | |||||
border?: boolean, | |||||
/** | |||||
* Should the component occupy the whole width of its parent? | |||||
*/ | |||||
block?: boolean, | |||||
/** | |||||
* Short textual description indicating the nature of the component's value. | |||||
*/ | |||||
label?: React.ReactNode, | |||||
/** | |||||
* Short textual description as guidelines for valid input values. | |||||
*/ | |||||
hint?: React.ReactNode, | |||||
/** | |||||
* Should the component be enhanced? | |||||
*/ | |||||
enhanced?: boolean, | |||||
/** | |||||
* Is the label hidden? | |||||
*/ | |||||
hiddenLabel?: boolean, | |||||
/** | |||||
* Preview component for the selected file(s). | |||||
*/ | |||||
previewComponent?: React.ElementType<P>, | |||||
/** | |||||
* Reselect label. | |||||
*/ | |||||
reselectLabel?: string, | |||||
/** | |||||
* Clear label. | |||||
*/ | |||||
clearLabel?: string, | |||||
} | |||||
export type FileSelectBoxDefaultPreviewComponentDerivedElement = HTMLDivElement; | |||||
export type FileSelectBoxDefaultPreviewComponentDerivedElement = HTMLElementTagNameMap[ | |||||
typeof FileSelectBoxDefaultPreviewComponentDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Default component for the {@link FileSelectBoxProps.previewComponent|previewComponent prop} | * Default component for the {@link FileSelectBoxProps.previewComponent|previewComponent prop} | ||||
@@ -94,7 +44,7 @@ export const FileSelectBoxDefaultPreviewComponent = React.forwardRef< | |||||
enhanced, | enhanced, | ||||
disabled, | disabled, | ||||
}, forwardedRef) => ( | }, forwardedRef) => ( | ||||
<div | |||||
<FileSelectBoxDefaultPreviewComponentDerivedElementComponent | |||||
data-enhanced={enhanced} | data-enhanced={enhanced} | ||||
className={clsx({ | className={clsx({ | ||||
'opacity-50': disabled, | 'opacity-50': disabled, | ||||
@@ -138,12 +88,76 @@ export const FileSelectBoxDefaultPreviewComponent = React.forwardRef< | |||||
)} | )} | ||||
</> | </> | ||||
)} | )} | ||||
</div> | |||||
</FileSelectBoxDefaultPreviewComponentDerivedElementComponent> | |||||
)); | )); | ||||
const isButtonElement = (el: HTMLElement): el is HTMLButtonElement => el.tagName === 'BUTTON'; | |||||
const DEFAULT_ENHANCED_HEIGHT_PX = 64 as const; | |||||
const DEFAULT_NON_ENHANCED_SIDE_HEIGHT_PX = 256 as const; | |||||
const FileSelectBoxRootElementComponent = 'div' as const; | |||||
const isInputElement = (el: HTMLElement): el is HTMLInputElement => el.tagName === 'INPUT'; | |||||
type FileSelectBoxRootElement = HTMLElementTagNameMap[typeof FileSelectBoxRootElementComponent]; | |||||
const FileSelectBoxActionElementComponent = 'button' as const; | |||||
type FileSelectBoxActionElement = HTMLElementTagNameMap[typeof FileSelectBoxActionElementComponent]; | |||||
const FileSelectBoxDerivedElementComponent = 'input' as const; | |||||
/** | |||||
* Derived HTML element of the {@link FileSelectBox} component. | |||||
*/ | |||||
export type FileSelectBoxDerivedElement = HTMLElementTagNameMap[typeof FileSelectBoxDerivedElementComponent]; | |||||
/** | |||||
* Props of the {@link FileSelectBox} component. | |||||
*/ | |||||
export interface FileSelectBoxProps< | |||||
F extends Partial<File> = Partial<File>, | |||||
P extends CommonPreviewComponentProps<F> = CommonPreviewComponentProps<F> | |||||
> extends Omit<React.HTMLProps<FileSelectBoxDerivedElement>, 'size' | 'type' | 'label' | 'list'> { | |||||
/** | |||||
* Should the component display a border? | |||||
*/ | |||||
border?: boolean, | |||||
/** | |||||
* Should the component occupy the whole width of its parent? | |||||
*/ | |||||
block?: boolean, | |||||
/** | |||||
* Short textual description indicating the nature of the component's value. | |||||
*/ | |||||
label?: React.ReactNode, | |||||
/** | |||||
* Short textual description as guidelines for valid input values. | |||||
*/ | |||||
hint?: React.ReactNode, | |||||
/** | |||||
* Should the component be enhanced? | |||||
*/ | |||||
enhanced?: boolean, | |||||
/** | |||||
* Is the label hidden? | |||||
*/ | |||||
hiddenLabel?: boolean, | |||||
/** | |||||
* Preview component for the selected file(s). | |||||
*/ | |||||
previewComponent?: React.ElementType<P>, | |||||
/** | |||||
* Reselect label. | |||||
*/ | |||||
reselectLabel?: string, | |||||
/** | |||||
* Clear label. | |||||
*/ | |||||
clearLabel?: string, | |||||
} | |||||
const isButtonElement = (el: HTMLElement): el is FileSelectBoxActionElement => el.tagName === 'BUTTON'; | |||||
const isInputElement = (el: HTMLElement): el is FileSelectBoxDerivedElement => el.tagName === 'INPUT'; | |||||
const isKeyUpEvent = (e: React.SyntheticEvent): e is React.KeyboardEvent => e.type === 'keyup'; | const isKeyUpEvent = (e: React.SyntheticEvent): e is React.KeyboardEvent => e.type === 'keyup'; | ||||
@@ -211,8 +225,8 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
const { defaultRef, handleChange: doSetFileList } = useProxyInput< | const { defaultRef, handleChange: doSetFileList } = useProxyInput< | ||||
React.ChangeEvent<FileSelectBoxDerivedElement> | React.ChangeEvent<FileSelectBoxDerivedElement> | ||||
| React.MouseEvent<HTMLButtonElement> | |||||
| React.DragEvent<HTMLDivElement> | |||||
| React.MouseEvent<FileSelectBoxActionElement> | |||||
| React.DragEvent<FileSelectBoxRootElement> | |||||
| React.KeyboardEvent<FileSelectBoxDerivedElement> | | React.KeyboardEvent<FileSelectBoxDerivedElement> | ||||
| React.ClipboardEvent<FileSelectBoxDerivedElement>, | | React.ClipboardEvent<FileSelectBoxDerivedElement>, | ||||
FileSelectBoxDerivedElement | FileSelectBoxDerivedElement | ||||
@@ -270,12 +284,12 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
const labelId = React.useId(); | const labelId = React.useId(); | ||||
const id = useFallbackId(idProp); | const id = useFallbackId(idProp); | ||||
const cancelEvent: React.DragEventHandler<HTMLDivElement> = React.useCallback((e) => { | |||||
const cancelEvent: React.DragEventHandler<FileSelectBoxRootElement> = React.useCallback((e) => { | |||||
e.stopPropagation(); | e.stopPropagation(); | ||||
e.preventDefault(); | e.preventDefault(); | ||||
}, []); | }, []); | ||||
const handleDrop: React.DragEventHandler<HTMLDivElement> = React.useCallback((e) => { | |||||
const handleDrop: React.DragEventHandler<FileSelectBoxRootElement> = React.useCallback((e) => { | |||||
cancelEvent(e); | cancelEvent(e); | ||||
doSetFileList(e); | doSetFileList(e); | ||||
}, [cancelEvent, doSetFileList]); | }, [cancelEvent, doSetFileList]); | ||||
@@ -312,7 +326,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
}, []); | }, []); | ||||
const handleReselectMouseDown: React.MouseEventHandler< | const handleReselectMouseDown: React.MouseEventHandler< | ||||
HTMLButtonElement | |||||
FileSelectBoxActionElement | |||||
> = React.useCallback(() => { | > = React.useCallback(() => { | ||||
setAboutToSelect(true); | setAboutToSelect(true); | ||||
setTimeout(() => { | setTimeout(() => { | ||||
@@ -322,7 +336,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
}, [defaultRef]); | }, [defaultRef]); | ||||
const handleReselectMouseUp: React.MouseEventHandler< | const handleReselectMouseUp: React.MouseEventHandler< | ||||
HTMLButtonElement | |||||
FileSelectBoxActionElement | |||||
> = React.useCallback(() => { | > = React.useCallback(() => { | ||||
const fileInput = defaultRef.current as FileSelectBoxDerivedElement; | const fileInput = defaultRef.current as FileSelectBoxDerivedElement; | ||||
if (typeof fileInput.showPicker !== 'function') { | if (typeof fileInput.showPicker !== 'function') { | ||||
@@ -333,7 +347,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
}, [defaultRef]); | }, [defaultRef]); | ||||
const handleDeleteMouseDown: React.MouseEventHandler< | const handleDeleteMouseDown: React.MouseEventHandler< | ||||
HTMLButtonElement | |||||
FileSelectBoxActionElement | |||||
> = React.useCallback(() => { | > = React.useCallback(() => { | ||||
setAboutToClear(true); | setAboutToClear(true); | ||||
setTimeout(() => { | setTimeout(() => { | ||||
@@ -366,7 +380,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
const fileListArray = Array.from(fileList ?? []); | const fileListArray = Array.from(fileList ?? []); | ||||
return ( | return ( | ||||
<div | |||||
<FileSelectBoxRootElementComponent | |||||
className={clsx( | className={clsx( | ||||
'relative rounded ring-secondary/50 group file-select-box', | 'relative rounded ring-secondary/50 group file-select-box', | ||||
'focus-within:ring-4', | 'focus-within:ring-4', | ||||
@@ -401,7 +415,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
</label> | </label> | ||||
)} | )} | ||||
{clientSide && ( | {clientSide && ( | ||||
<button | |||||
<FileSelectBoxActionElementComponent | |||||
type="button" | type="button" | ||||
disabled={disabled} | disabled={disabled} | ||||
tabIndex={-1} | tabIndex={-1} | ||||
@@ -414,9 +428,9 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
onMouseUp={handleReselectMouseUp} | onMouseUp={handleReselectMouseUp} | ||||
> | > | ||||
{placeholder} | {placeholder} | ||||
</button> | |||||
</FileSelectBoxActionElementComponent> | |||||
)} | )} | ||||
<input | |||||
<FileSelectBoxDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
id={id} | id={id} | ||||
disabled={disabled} | disabled={disabled} | ||||
@@ -513,7 +527,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
className="absolute bottom-0 left-0 w-full text-center h-12 box-border flex" | className="absolute bottom-0 left-0 w-full text-center h-12 box-border flex" | ||||
> | > | ||||
<div className="w-0 flex-auto flex flex-col items-center justify-center h-full"> | <div className="w-0 flex-auto flex flex-col items-center justify-center h-full"> | ||||
<button | |||||
<FileSelectBoxActionElementComponent | |||||
type="button" | type="button" | ||||
data-testid="reselect" | data-testid="reselect" | ||||
disabled={disabled} | disabled={disabled} | ||||
@@ -533,10 +547,10 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
> | > | ||||
{reselectLabel} | {reselectLabel} | ||||
</span> | </span> | ||||
</button> | |||||
</FileSelectBoxActionElementComponent> | |||||
</div> | </div> | ||||
<div className="w-0 flex-auto flex flex-col items-center justify-center h-full"> | <div className="w-0 flex-auto flex flex-col items-center justify-center h-full"> | ||||
<button | |||||
<FileSelectBoxActionElementComponent | |||||
disabled={disabled} | disabled={disabled} | ||||
data-testid="clear" | data-testid="clear" | ||||
type="button" | type="button" | ||||
@@ -558,7 +572,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
> | > | ||||
{clearLabel} | {clearLabel} | ||||
</span> | </span> | ||||
</button> | |||||
</FileSelectBoxActionElementComponent> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</React.Fragment> | </React.Fragment> | ||||
@@ -569,7 +583,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
className="absolute z-[1] peer-disabled:opacity-50 inset-0 rounded-inherit border-2 border-primary pointer-events-none group-focus-within:border-secondary" | className="absolute z-[1] peer-disabled:opacity-50 inset-0 rounded-inherit border-2 border-primary pointer-events-none group-focus-within:border-secondary" | ||||
/> | /> | ||||
)} | )} | ||||
</div> | |||||
</FileSelectBoxRootElementComponent> | |||||
); | ); | ||||
}); | }); | ||||
@@ -3,10 +3,14 @@ import { TextControl } from '@tesseract-design/web-base'; | |||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
const ComboBoxDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link ComboBox} component. | * Derived HTML element of the {@link ComboBox} component. | ||||
*/ | */ | ||||
export type ComboBoxDerivedElement = HTMLInputElement; | |||||
export type ComboBoxDerivedElement = HTMLElementTagNameMap[ | |||||
typeof ComboBoxDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link ComboBox} component. | * Props of the {@link ComboBox} component. | ||||
@@ -143,7 +147,7 @@ export const ComboBox = React.forwardRef<ComboBoxDerivedElement, ComboBoxProps>( | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<input | |||||
<ComboBoxDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
size={length} | size={length} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
@@ -4,10 +4,14 @@ import clsx from 'clsx'; | |||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
const DropdownSelectDerivedElementComponent = 'select' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link DropdownSelect} component. | * Derived HTML element of the {@link DropdownSelect} component. | ||||
*/ | */ | ||||
export type DropdownSelectDerivedElement = HTMLSelectElement; | |||||
export type DropdownSelectDerivedElement = HTMLElementTagNameMap[ | |||||
typeof DropdownSelectDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link DropdownSelect} component. | * Props of the {@link DropdownSelect} component. | ||||
@@ -127,7 +131,7 @@ export const DropdownSelect = React.forwardRef<DropdownSelectDerivedElement, Dro | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<select | |||||
<DropdownSelectDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
id={id} | id={id} | ||||
@@ -150,7 +154,7 @@ export const DropdownSelect = React.forwardRef<DropdownSelectDerivedElement, Dro | |||||
)} | )} | ||||
> | > | ||||
{children} | {children} | ||||
</select> | |||||
</DropdownSelectDerivedElementComponent> | |||||
{hint && ( | {hint && ( | ||||
<div | <div | ||||
data-testid="hint" | data-testid="hint" | ||||
@@ -4,10 +4,14 @@ import clsx from 'clsx'; | |||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
const MenuSelectDerivedElementComponent = 'select' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link MenuSelect} component. | * Derived HTML element of the {@link MenuSelect} component. | ||||
*/ | */ | ||||
export type MenuSelectDerivedElement = HTMLSelectElement; | |||||
export type MenuSelectDerivedElement = HTMLElementTagNameMap[ | |||||
typeof MenuSelectDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link MenuSelect} component. | * Props of the {@link MenuSelect} component. | ||||
@@ -137,7 +141,7 @@ export const MenuSelect = React.forwardRef<MenuSelectDerivedElement, MenuSelectP | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<select | |||||
<MenuSelectDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
id={id} | id={id} | ||||
@@ -4,10 +4,14 @@ import { Button } from '@tesseract-design/web-base'; | |||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
const RadioButtonDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link RadioButton} component. | * Derived HTML element of the {@link RadioButton} component. | ||||
*/ | */ | ||||
export type RadioButtonDerivedElement = HTMLInputElement; | |||||
export type RadioButtonDerivedElement = HTMLElementTagNameMap[ | |||||
typeof RadioButtonDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link RadioButton} component. | * Props of the {@link RadioButton} component. | ||||
@@ -77,9 +81,9 @@ export const RadioButton = React.forwardRef<RadioButtonDerivedElement, RadioButt | |||||
return ( | return ( | ||||
<span | <span | ||||
className="contents" | |||||
> | |||||
<input | |||||
className="contents" | |||||
> | |||||
<RadioButtonDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
type="radio" | type="radio" | ||||
@@ -3,10 +3,14 @@ import clsx from 'clsx'; | |||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
const RadioTickBoxDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link RadioTickBox} component. | * Derived HTML element of the {@link RadioTickBox} component. | ||||
*/ | */ | ||||
export type RadioTickBoxDerivedElement = HTMLInputElement; | |||||
export type RadioTickBoxDerivedElement = HTMLElementTagNameMap[ | |||||
typeof RadioTickBoxDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link RadioTickBox} component. | * Props of the {@link RadioTickBox} component. | ||||
@@ -65,7 +69,7 @@ export const RadioTickBox = React.forwardRef<RadioTickBoxDerivedElement, RadioTi | |||||
style={style} | style={style} | ||||
data-testid="base" | data-testid="base" | ||||
> | > | ||||
<input | |||||
<RadioTickBoxDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
type="radio" | type="radio" | ||||
@@ -2,10 +2,14 @@ import * as React from 'react'; | |||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
const ColorPickerDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link ColorPicker} component. | * Derived HTML element of the {@link ColorPicker} component. | ||||
*/ | */ | ||||
export type ColorPickerDerivedElement = HTMLInputElement; | |||||
export type ColorPickerDerivedElement = HTMLElementTagNameMap[ | |||||
typeof ColorPickerDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link ColorPicker} component. | * Props of the {@link ColorPicker} component. | ||||
@@ -75,7 +79,7 @@ export const ColorPicker = React.forwardRef< | |||||
}, | }, | ||||
)} | )} | ||||
> | > | ||||
<input | |||||
<ColorPickerDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
className={clsx( | className={clsx( | ||||
'color-picker absolute top-0 left-0 w-full h-full overflow-hidden cursor-pointer disabled:cursor-not-allowed', | 'color-picker absolute top-0 left-0 w-full h-full overflow-hidden cursor-pointer disabled:cursor-not-allowed', | ||||
@@ -3,10 +3,14 @@ import clsx from 'clsx'; | |||||
import Color from 'color'; | import Color from 'color'; | ||||
import * as convert from 'color-convert'; | import * as convert from 'color-convert'; | ||||
const SwatchDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link Swatch} component. | * Derived HTML element of the {@link Swatch} component. | ||||
*/ | */ | ||||
export type SwatchDerivedElement = HTMLInputElement; | |||||
export type SwatchDerivedElement = HTMLElementTagNameMap[ | |||||
typeof SwatchDerivedElementComponent | |||||
]; | |||||
type ColorValue = ConstructorParameters<typeof Color>[0]; | type ColorValue = ConstructorParameters<typeof Color>[0]; | ||||
@@ -56,7 +60,7 @@ export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({ | |||||
)} | )} | ||||
style={style} | style={style} | ||||
> | > | ||||
<input | |||||
<SwatchDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
type="text" | type="text" | ||||
@@ -3,10 +3,14 @@ import { TextControl } from '@tesseract-design/web-base'; | |||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const EmailInputDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link EmailInput} component. | * Derived HTML element of the {@link EmailInput} component. | ||||
*/ | */ | ||||
export type EmailInputDerivedElement = HTMLInputElement; | |||||
export type EmailInputDerivedElement = HTMLElementTagNameMap[ | |||||
typeof EmailInputDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link EmailInput} component. | * Props of the {@link EmailInput} component. | ||||
@@ -124,7 +128,7 @@ export const EmailInput = React.forwardRef<EmailInputDerivedElement, EmailInputP | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<input | |||||
<EmailInputDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
size={length} | size={length} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
@@ -3,10 +3,14 @@ import { TextControl } from '@tesseract-design/web-base'; | |||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const PatternTextInputDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link PatternTextInput} component. | * Derived HTML element of the {@link PatternTextInput} component. | ||||
*/ | */ | ||||
export type PatternTextInputDerivedElement = HTMLInputElement; | |||||
export type PatternTextInputDerivedElement = HTMLElementTagNameMap[ | |||||
typeof PatternTextInputDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link PatternTextInput} component. | * Props of the {@link PatternTextInput} component. | ||||
@@ -138,7 +142,7 @@ export const PatternTextInput = React.forwardRef< | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<input | |||||
<PatternTextInputDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
size={length} | size={length} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
@@ -4,10 +4,14 @@ import { useClientSide, useFallbackId, useProxyInput } from '@modal-sh/react-uti | |||||
import PhoneInput, { Country, Value } from 'react-phone-number-input/input'; | import PhoneInput, { Country, Value } from 'react-phone-number-input/input'; | ||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
const PhoneNumberInputDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link PhoneNumberInput} component. | * Derived HTML element of the {@link PhoneNumberInput} component. | ||||
*/ | */ | ||||
export type PhoneNumberInputDerivedElement = HTMLInputElement; | |||||
export type PhoneNumberInputDerivedElement = HTMLElementTagNameMap[ | |||||
typeof PhoneNumberInputDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link PhoneNumberInput} component. | * Props of the {@link PhoneNumberInput} component. | ||||
@@ -155,7 +159,7 @@ export const PhoneNumberInput = React.forwardRef< | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<input | |||||
<PhoneNumberInputDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
size={length} | size={length} | ||||
value={value} | value={value} | ||||
@@ -3,10 +3,14 @@ import { TextControl } from '@tesseract-design/web-base'; | |||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const UrlInputDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link UrlInput} component. | * Derived HTML element of the {@link UrlInput} component. | ||||
*/ | */ | ||||
export type UrlInputDerivedElement = HTMLInputElement; | |||||
export type UrlInputDerivedElement = HTMLElementTagNameMap[ | |||||
typeof UrlInputDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link UrlInput} component. | * Props of the {@link UrlInput} component. | ||||
@@ -108,7 +112,7 @@ export const UrlInput = React.forwardRef<UrlInputDerivedElement, UrlInputProps>( | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<input | |||||
<UrlInputDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
size={length} | size={length} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
@@ -3,10 +3,14 @@ import { TextControl } from '@tesseract-design/web-base'; | |||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
import { useClientSide, useFallbackId } from '@modal-sh/react-utils'; | import { useClientSide, useFallbackId } from '@modal-sh/react-utils'; | ||||
const MaskedTextInputDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link MaskedTextInput} component. | * Derived HTML element of the {@link MaskedTextInput} component. | ||||
*/ | */ | ||||
export type MaskedTextInputDerivedElement = HTMLInputElement; | |||||
export type MaskedTextInputDerivedElement = HTMLElementTagNameMap[ | |||||
typeof MaskedTextInputDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link MaskedTextInput} component. | * Props of the {@link MaskedTextInput} component. | ||||
@@ -191,7 +195,7 @@ export const MaskedTextInput = React.forwardRef< | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<input | |||||
<MaskedTextInputDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
size={length} | size={length} | ||||
ref={typeof ref === 'function' ? defaultRef : ref} | ref={typeof ref === 'function' ? defaultRef : ref} | ||||
@@ -3,10 +3,14 @@ import { TextControl } from '@tesseract-design/web-base'; | |||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const MultilineTextInputDerivedElementComponent = 'textarea' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link MultilineTextInput} component. | * Derived HTML element of the {@link MultilineTextInput} component. | ||||
*/ | */ | ||||
export type MultilineTextInputDerivedElement = HTMLTextAreaElement; | |||||
export type MultilineTextInputDerivedElement = HTMLElementTagNameMap[ | |||||
typeof MultilineTextInputDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link MultilineTextInput} component. | * Props of the {@link MultilineTextInput} component. | ||||
@@ -116,7 +120,7 @@ export const MultilineTextInput = React.forwardRef< | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<textarea | |||||
<MultilineTextInputDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
aria-labelledby={labelId} | aria-labelledby={labelId} | ||||
@@ -3,10 +3,14 @@ import { TextControl } from '@tesseract-design/web-base'; | |||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const TextInputDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link TextInput} component. | * Derived HTML element of the {@link TextInput} component. | ||||
*/ | */ | ||||
export type TextInputDerivedElement = HTMLInputElement; | |||||
export type TextInputDerivedElement = HTMLElementTagNameMap[ | |||||
typeof TextInputDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link TextInput} component. | * Props of the {@link TextInput} component. | ||||
@@ -135,7 +139,7 @@ export const TextInput = React.forwardRef<TextInputDerivedElement, TextInputProp | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<input | |||||
<TextInputDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
size={length} | size={length} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
@@ -1,10 +1,14 @@ | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
const BadgeDerivedElementComponent = 'span' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link Badge} component. | * Derived HTML element of the {@link Badge} component. | ||||
*/ | */ | ||||
export type BadgeDerivedElement = HTMLSpanElement; | |||||
export type BadgeDerivedElement = HTMLElementTagNameMap[ | |||||
typeof BadgeDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link Badge} component. | * Props of the {@link Badge} component. | ||||
@@ -29,7 +33,7 @@ export const Badge = React.forwardRef<BadgeDerivedElement, BadgeProps>(( | |||||
}, | }, | ||||
forwardedRef, | forwardedRef, | ||||
) => ( | ) => ( | ||||
<span | |||||
<BadgeDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
className={clsx( | className={clsx( | ||||
@@ -47,7 +51,7 @@ export const Badge = React.forwardRef<BadgeDerivedElement, BadgeProps>(( | |||||
<span className="relative w-full"> | <span className="relative w-full"> | ||||
{children} | {children} | ||||
</span> | </span> | ||||
</span> | |||||
</BadgeDerivedElementComponent> | |||||
)); | )); | ||||
Badge.displayName = 'Badge'; | Badge.displayName = 'Badge'; | ||||
@@ -1,10 +1,20 @@ | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
const KeyValueTableDerivedElementComponent = 'dl' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link KeyValueTable} component. | * Derived HTML element of the {@link KeyValueTable} component. | ||||
*/ | */ | ||||
export type KeyValueTableDerivedElement = HTMLDListElement; | |||||
export type KeyValueTableDerivedElement = HTMLElementTagNameMap[ | |||||
typeof KeyValueTableDerivedElementComponent | |||||
]; | |||||
const KeyValueTablePropertyElementComponent = 'div' as const; | |||||
const KeyValueTableKeyElementComponent = 'dt' as const; | |||||
const KeyValueTableValueElementComponent = 'dd' as const; | |||||
/** | /** | ||||
* Individual property of the {@link KeyValueTable} component. | * Individual property of the {@link KeyValueTable} component. | ||||
@@ -51,7 +61,7 @@ export const KeyValueTable = React.forwardRef<KeyValueTableDerivedElement, KeyVa | |||||
}, | }, | ||||
forwardedRef, | forwardedRef, | ||||
) => ( | ) => ( | ||||
<dl | |||||
<KeyValueTableDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
className={clsx( | className={clsx( | ||||
'grid gap-y-1 grid-cols-3', | 'grid gap-y-1 grid-cols-3', | ||||
@@ -61,16 +71,16 @@ export const KeyValueTable = React.forwardRef<KeyValueTableDerivedElement, KeyVa | |||||
style={style} | style={style} | ||||
> | > | ||||
{properties.map((property) => typeof property === 'object' && property && ( | {properties.map((property) => typeof property === 'object' && property && ( | ||||
<div | |||||
<KeyValueTablePropertyElementComponent | |||||
key={property.key} | key={property.key} | ||||
className={clsx('contents', property.className)} | className={clsx('contents', property.className)} | ||||
> | > | ||||
<dt | |||||
<KeyValueTableKeyElementComponent | |||||
className={clsx(hiddenKeys && 'sr-only', 'pr-4')} | className={clsx(hiddenKeys && 'sr-only', 'pr-4')} | ||||
> | > | ||||
{property.key} | {property.key} | ||||
</dt> | |||||
<dd | |||||
</KeyValueTableKeyElementComponent> | |||||
<KeyValueTableValueElementComponent | |||||
{...(property.valueProps ?? {})} | {...(property.valueProps ?? {})} | ||||
className={clsx( | className={clsx( | ||||
'm-0 text-ellipsis overflow-hidden', | 'm-0 text-ellipsis overflow-hidden', | ||||
@@ -80,10 +90,10 @@ export const KeyValueTable = React.forwardRef<KeyValueTableDerivedElement, KeyVa | |||||
)} | )} | ||||
> | > | ||||
{property.valueProps?.children} | {property.valueProps?.children} | ||||
</dd> | |||||
</div> | |||||
</KeyValueTableValueElementComponent> | |||||
</KeyValueTablePropertyElementComponent> | |||||
))} | ))} | ||||
</dl> | |||||
</KeyValueTableDerivedElementComponent> | |||||
)); | )); | ||||
KeyValueTable.displayName = 'KeyValueTable'; | KeyValueTable.displayName = 'KeyValueTable'; | ||||
@@ -4,10 +4,14 @@ import clsx from 'clsx'; | |||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const MenuMultiSelectDerivedElementComponent = 'select' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link MenuMultiSelect} component. | * Derived HTML element of the {@link MenuMultiSelect} component. | ||||
*/ | */ | ||||
export type MenuMultiSelectDerivedElement = HTMLSelectElement; | |||||
export type MenuMultiSelectDerivedElement = HTMLElementTagNameMap[ | |||||
typeof MenuMultiSelectDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link MenuMultiSelect} component. | * Props of the {@link MenuMultiSelect} component. | ||||
@@ -144,7 +148,7 @@ export const MenuMultiSelect = React.forwardRef< | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<select | |||||
<MenuMultiSelectDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
id={id} | id={id} | ||||
@@ -24,10 +24,14 @@ const TAG_INPUT_VALUE_SEPARATOR_MAP: Record<TagInputSeparator, string> = { | |||||
'semicolon': ';', | 'semicolon': ';', | ||||
} as const; | } as const; | ||||
const TagInputDerivedElementComponent = ['textarea', 'input'] as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link TagInput} component. | * Derived HTML element of the {@link TagInput} component. | ||||
*/ | */ | ||||
export type TagInputDerivedElement = HTMLTextAreaElement | HTMLInputElement; | |||||
export type TagInputDerivedElement = HTMLElementTagNameMap[ | |||||
typeof TagInputDerivedElementComponent[number] | |||||
]; | |||||
/** | /** | ||||
* Proxied HTML element of the {@link TagInput} component. | * Proxied HTML element of the {@link TagInput} component. | ||||
@@ -85,7 +89,7 @@ export interface TagInputProps extends Omit<React.HTMLProps<TagInputDerivedEleme | |||||
/** | /** | ||||
* Fallback element for non-enhanced mode. | * Fallback element for non-enhanced mode. | ||||
*/ | */ | ||||
fallbackElement?: 'textarea' | 'input', | |||||
fallbackElement?: typeof TagInputDerivedElementComponent[number], | |||||
/** | /** | ||||
* Separator used on the value of the input. | * Separator used on the value of the input. | ||||
*/ | */ | ||||
@@ -236,12 +240,14 @@ export const TagInput = React.forwardRef<TagInputDerivedElement, TagInputProps>( | |||||
onBlur, | onBlur, | ||||
editOnRemove = false as const, | editOnRemove = false as const, | ||||
placeholder, | placeholder, | ||||
fallbackElement: FallbackElement = 'textarea' as const, | |||||
fallbackElement: FallbackElement = TagInputDerivedElementComponent[0], | |||||
...etcProps | ...etcProps | ||||
}, | }, | ||||
forwardedRef, | forwardedRef, | ||||
) => { | ) => { | ||||
const EffectiveFallbackElement = valueSeparator === 'newline' ? 'textarea' : FallbackElement; | |||||
const EffectiveFallbackElement = valueSeparator === 'newline' | |||||
? TagInputDerivedElementComponent[0] | |||||
: FallbackElement; | |||||
const { clientSide } = useClientSide({ clientSide: enhancedProp }); | const { clientSide } = useClientSide({ clientSide: enhancedProp }); | ||||
const [tags, setTags] = React.useState<string[]>(() => { | const [tags, setTags] = React.useState<string[]>(() => { | ||||
const effectiveValue = value ?? defaultValue; | const effectiveValue = value ?? defaultValue; | ||||
@@ -537,12 +543,12 @@ TagInput.defaultProps = { | |||||
indicator: undefined, | indicator: undefined, | ||||
size: 'medium' as const, | size: 'medium' as const, | ||||
variant: 'default' as const, | variant: 'default' as const, | ||||
separator: ['newline'], | |||||
separator: ['newline' as const], | |||||
border: false as const, | border: false as const, | ||||
block: false as const, | block: false as const, | ||||
hiddenLabel: false as const, | hiddenLabel: false as const, | ||||
enhanced: false as const, | enhanced: false as const, | ||||
editOnRemove: false as const, | editOnRemove: false as const, | ||||
fallbackElement: 'textarea' as const, | |||||
fallbackElement: TagInputDerivedElementComponent[0], | |||||
valueSeparator: 'newline' as const, | valueSeparator: 'newline' as const, | ||||
}; | }; |
@@ -4,10 +4,14 @@ import { Button } from '@tesseract-design/web-base'; | |||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const ToggleButtonDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link ToggleButton} component. | * Derived HTML element of the {@link ToggleButton} component. | ||||
*/ | */ | ||||
export type ToggleButtonDerivedElement = HTMLInputElement; | |||||
export type ToggleButtonDerivedElement = HTMLElementTagNameMap[ | |||||
typeof ToggleButtonDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link ToggleButton} component. | * Props of the {@link ToggleButton} component. | ||||
@@ -101,7 +105,7 @@ export const ToggleButton = React.forwardRef<ToggleButtonDerivedElement, ToggleB | |||||
<span | <span | ||||
className="contents" | className="contents" | ||||
> | > | ||||
<input | |||||
<ToggleButtonDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={typeof ref === 'function' ? defaultRef : ref} | ref={typeof ref === 'function' ? defaultRef : ref} | ||||
type="checkbox" | type="checkbox" | ||||
@@ -3,10 +3,14 @@ import clsx from 'clsx'; | |||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const ToggleSwitchDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link ToggleSwitch} component. | * Derived HTML element of the {@link ToggleSwitch} component. | ||||
*/ | */ | ||||
export type ToggleSwitchDerivedElement = HTMLInputElement; | |||||
export type ToggleSwitchDerivedElement = HTMLElementTagNameMap[ | |||||
typeof ToggleSwitchDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link ToggleSwitch} component. | * Props of the {@link ToggleSwitch} component. | ||||
@@ -198,7 +202,7 @@ export const ToggleSwitch = React.forwardRef<ToggleSwitchDerivedElement, ToggleS | |||||
style={style} | style={style} | ||||
data-testid="base" | data-testid="base" | ||||
> | > | ||||
<input | |||||
<ToggleSwitchDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={typeof ref === 'function' ? defaultRef : ref} | ref={typeof ref === 'function' ? defaultRef : ref} | ||||
type="checkbox" | type="checkbox" | ||||
@@ -3,10 +3,14 @@ import clsx from 'clsx'; | |||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const ToggleTickBoxDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link ToggleTickBox} component. | * Derived HTML element of the {@link ToggleTickBox} component. | ||||
*/ | */ | ||||
export type ToggleTickBoxDerivedElement = HTMLInputElement; | |||||
export type ToggleTickBoxDerivedElement = HTMLElementTagNameMap[ | |||||
typeof ToggleTickBoxDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link ToggleTickBox} component. | * Props of the {@link ToggleTickBox} component. | ||||
@@ -87,7 +91,7 @@ export const ToggleTickBox = React.forwardRef<ToggleTickBoxDerivedElement, Toggl | |||||
style={style} | style={style} | ||||
data-testid="base" | data-testid="base" | ||||
> | > | ||||
<input | |||||
<ToggleTickBoxDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={typeof ref === 'function' ? defaultRef : ref} | ref={typeof ref === 'function' ? defaultRef : ref} | ||||
type="checkbox" | type="checkbox" | ||||
@@ -2,10 +2,14 @@ import * as React from 'react'; | |||||
import clsx from 'clsx'; | import clsx from 'clsx'; | ||||
import { Button } from '@tesseract-design/web-base'; | import { Button } from '@tesseract-design/web-base'; | ||||
const LinkButtonDerivedElementComponent = 'a' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link LinkButton} component. | * Derived HTML element of the {@link LinkButton} component. | ||||
*/ | */ | ||||
export type LinkButtonDerivedElement = HTMLAnchorElement; | |||||
export type LinkButtonDerivedElement = HTMLElementTagNameMap[ | |||||
typeof LinkButtonDerivedElementComponent | |||||
]; | |||||
interface LinkButtonCommonProps extends Omit<React.HTMLProps<LinkButtonDerivedElement>, 'href' | 'size'> { | interface LinkButtonCommonProps extends Omit<React.HTMLProps<LinkButtonDerivedElement>, 'href' | 'size'> { | ||||
/** | /** | ||||
@@ -51,7 +55,7 @@ interface LinkButtonCommonProps extends Omit<React.HTMLProps<LinkButtonDerivedEl | |||||
} | } | ||||
interface LinkButtonAnchorProps extends Pick<React.HTMLProps<LinkButtonDerivedElement>, 'href'> { | interface LinkButtonAnchorProps extends Pick<React.HTMLProps<LinkButtonDerivedElement>, 'href'> { | ||||
component: 'a'; | |||||
component: typeof LinkButtonDerivedElementComponent; | |||||
} | } | ||||
interface LinkButtonComponentType { | interface LinkButtonComponentType { | ||||
@@ -92,7 +96,7 @@ export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonP | |||||
compact = false, | compact = false, | ||||
className, | className, | ||||
block = false, | block = false, | ||||
component: EnabledComponent = 'a' as const, | |||||
component: EnabledComponent = LinkButtonDerivedElementComponent, | |||||
disabled = false, | disabled = false, | ||||
href, | href, | ||||
style, | style, | ||||
@@ -102,7 +106,7 @@ export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonP | |||||
}, | }, | ||||
forwardedRef, | forwardedRef, | ||||
) => { | ) => { | ||||
const Component = (disabled ? 'button' : EnabledComponent) as 'a'; | |||||
const Component = (disabled ? 'button' : EnabledComponent) as typeof LinkButtonDerivedElementComponent; | |||||
const extraProps = { | const extraProps = { | ||||
disabled: disabled || undefined, | disabled: disabled || undefined, | ||||
}; | }; | ||||
@@ -237,7 +241,7 @@ LinkButton.defaultProps = { | |||||
icon: undefined, | icon: undefined, | ||||
iconAfterChildren: false as const, | iconAfterChildren: false as const, | ||||
// eslint-disable-next-line react/default-props-match-prop-types | // eslint-disable-next-line react/default-props-match-prop-types | ||||
component: 'a' as const, | |||||
component: LinkButtonDerivedElementComponent, | |||||
// eslint-disable-next-line react/default-props-match-prop-types | // eslint-disable-next-line react/default-props-match-prop-types | ||||
href: undefined, | href: undefined, | ||||
}; | }; | ||||
@@ -4,10 +4,20 @@ import clsx from 'clsx'; | |||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
import { useBrowser, useClientSide, useFallbackId } from '@modal-sh/react-utils'; | import { useBrowser, useClientSide, useFallbackId } from '@modal-sh/react-utils'; | ||||
const NumberSpinnerDerivedElementComponent = 'input' as const; | |||||
/** | /** | ||||
* Derived HTML element of the {@link NumberSpinner} component. | * Derived HTML element of the {@link NumberSpinner} component. | ||||
*/ | */ | ||||
export type NumberSpinnerDerivedElement = HTMLInputElement; | |||||
export type NumberSpinnerDerivedElement = HTMLElementTagNameMap[ | |||||
typeof NumberSpinnerDerivedElementComponent | |||||
]; | |||||
const NumberSpinnerActionElementComponent = 'button' as const; | |||||
type NumberSpinnerActionElement = HTMLElementTagNameMap[ | |||||
typeof NumberSpinnerActionElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link NumberSpinner} component. | * Props of the {@link NumberSpinner} component. | ||||
@@ -151,7 +161,7 @@ export const NumberSpinner = React.forwardRef<NumberSpinnerDerivedElement, Numbe | |||||
return clickYRef.current < spinnerYRef.current; | return clickYRef.current < spinnerYRef.current; | ||||
}; | }; | ||||
const doStepMouse: React.MouseEventHandler<HTMLButtonElement> = (e) => { | |||||
const doStepMouse: React.MouseEventHandler<NumberSpinnerActionElement> = (e) => { | |||||
if (spinEventSource.current === 'keyboard') { | if (spinEventSource.current === 'keyboard') { | ||||
return; | return; | ||||
} | } | ||||
@@ -285,7 +295,7 @@ export const NumberSpinner = React.forwardRef<NumberSpinnerDerivedElement, Numbe | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<input | |||||
<NumberSpinnerDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
size={length} | size={length} | ||||
ref={typeof ref === 'function' ? defaultRef : ref} | ref={typeof ref === 'function' ? defaultRef : ref} | ||||
@@ -357,7 +367,7 @@ export const NumberSpinner = React.forwardRef<NumberSpinnerDerivedElement, Numbe | |||||
</div> | </div> | ||||
)} | )} | ||||
{indicator && ( | {indicator && ( | ||||
<button | |||||
<NumberSpinnerActionElementComponent | |||||
data-testid="indicator" | data-testid="indicator" | ||||
type="button" | type="button" | ||||
className={clsx( | className={clsx( | ||||
@@ -413,7 +423,7 @@ export const NumberSpinner = React.forwardRef<NumberSpinnerDerivedElement, Numbe | |||||
Step Down | Step Down | ||||
</span> | </span> | ||||
</span> | </span> | ||||
</button> | |||||
</NumberSpinnerActionElementComponent> | |||||
)} | )} | ||||
{border && ( | {border && ( | ||||
<span | <span | ||||
@@ -43,15 +43,19 @@ export const AVAILABLE_SLIDER_ORIENTATIONS = ['horizontal', 'vertical'] as const | |||||
*/ | */ | ||||
export type SliderOrientation = typeof AVAILABLE_SLIDER_ORIENTATIONS[number]; | export type SliderOrientation = typeof AVAILABLE_SLIDER_ORIENTATIONS[number]; | ||||
const SliderDerivedElementComponent = 'input'; | |||||
/** | /** | ||||
* Derived HTML element of the {@link Slider} component. | * Derived HTML element of the {@link Slider} component. | ||||
*/ | */ | ||||
export type SliderDerivedElement = HTMLInputElement; | |||||
export type SliderDerivedElement = HTMLElementTagNameMap[ | |||||
typeof SliderDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link Slider} component. | * Props of the {@link Slider} component. | ||||
*/ | */ | ||||
export interface SliderProps extends Omit<React.HTMLProps<HTMLInputElement>, 'type'> { | |||||
export interface SliderProps extends Omit<React.HTMLProps<SliderDerivedElement>, 'type'> { | |||||
/** | /** | ||||
* Orientation of the component. | * Orientation of the component. | ||||
*/ | */ | ||||
@@ -245,7 +249,7 @@ export const Slider = React.forwardRef<SliderDerivedElement, SliderProps>(( | |||||
forwardedRef, | forwardedRef, | ||||
) => { | ) => { | ||||
const browser = useBrowser(); | const browser = useBrowser(); | ||||
const defaultRef = React.useRef<HTMLInputElement>(null); | |||||
const defaultRef = React.useRef<SliderDerivedElement>(null); | |||||
const ref = forwardedRef ?? defaultRef; | const ref = forwardedRef ?? defaultRef; | ||||
const tickMarkId = React.useId(); | const tickMarkId = React.useId(); | ||||
@@ -454,7 +458,7 @@ export const Slider = React.forwardRef<SliderDerivedElement, SliderProps>(( | |||||
className="flex slider" | className="flex slider" | ||||
data-orient={orient} | data-orient={orient} | ||||
> | > | ||||
<input | |||||
<SliderDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={ref} | ref={ref} | ||||
min={minValue} | min={minValue} | ||||
@@ -4,10 +4,14 @@ import clsx from 'clsx'; | |||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const DateDropdownDerivedElementComponent = 'input'; | |||||
/** | /** | ||||
* Derived HTML element of the {@link DateDropdown} component. | * Derived HTML element of the {@link DateDropdown} component. | ||||
*/ | */ | ||||
export type DateDropdownDerivedElement = HTMLInputElement; | |||||
export type DateDropdownDerivedElement = HTMLElementTagNameMap[ | |||||
typeof DateDropdownDerivedElementComponent | |||||
]; | |||||
/** | /** | ||||
* Props of the {@link DateDropdown} component. | * Props of the {@link DateDropdown} component. | ||||
@@ -139,7 +143,7 @@ export const DateDropdown = React.forwardRef< | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<input | |||||
<DateDropdownDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
size={length} | size={length} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
@@ -4,10 +4,14 @@ import clsx from 'clsx'; | |||||
import { PluginCreator } from 'tailwindcss/types/config'; | import { PluginCreator } from 'tailwindcss/types/config'; | ||||
import { useFallbackId } from '@modal-sh/react-utils'; | import { useFallbackId } from '@modal-sh/react-utils'; | ||||
const TimeSpinnerDerivedElementComponent = 'input'; | |||||
/** | /** | ||||
* Derived HTML element of the {@link TimeSpinner} component. | * Derived HTML element of the {@link TimeSpinner} component. | ||||
*/ | */ | ||||
export type TimeSpinnerDerivedElement = HTMLInputElement; | |||||
export type TimeSpinnerDerivedElement = HTMLElementTagNameMap[ | |||||
typeof TimeSpinnerDerivedElementComponent | |||||
]; | |||||
type Digit = (0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9); | type Digit = (0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9); | ||||
@@ -161,7 +165,7 @@ export const TimeSpinner = React.forwardRef< | |||||
{' '} | {' '} | ||||
</> | </> | ||||
)} | )} | ||||
<input | |||||
<TimeSpinnerDerivedElementComponent | |||||
{...etcProps} | {...etcProps} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
id={id} | id={id} | ||||