瀏覽代碼

Finish customizing option components

Render all option components.
pull/1/head
TheoryOfNekomata 11 月之前
父節點
當前提交
57bbb37372
共有 27 個文件被更改,包括 1559 次插入635 次删除
  1. +11
    -6
      packages/web-kitchensink-reactnext/src/categories/action/react/components/ActionButton/index.tsx
  2. +9
    -0
      packages/web-kitchensink-reactnext/src/categories/blob/react/common.ts
  3. +4
    -6
      packages/web-kitchensink-reactnext/src/categories/blob/react/components/AudioFilePreview/index.tsx
  4. +4
    -5
      packages/web-kitchensink-reactnext/src/categories/blob/react/components/BinaryFilePreview/index.tsx
  5. +79
    -65
      packages/web-kitchensink-reactnext/src/categories/blob/react/components/FileSelectBox/index.tsx
  6. +5
    -103
      packages/web-kitchensink-reactnext/src/categories/blob/react/components/ImageFilePreview/index.tsx
  7. +3
    -4
      packages/web-kitchensink-reactnext/src/categories/blob/react/components/TextFilePreview/index.tsx
  8. +4
    -6
      packages/web-kitchensink-reactnext/src/categories/blob/react/components/VideoFilePreview/index.tsx
  9. +99
    -0
      packages/web-kitchensink-reactnext/src/categories/color/react/components/Swatch/index.tsx
  10. +1
    -0
      packages/web-kitchensink-reactnext/src/categories/color/react/index.ts
  11. +21
    -11
      packages/web-kitchensink-reactnext/src/categories/navigation/react/components/LinkButton/index.tsx
  12. +118
    -108
      packages/web-kitchensink-reactnext/src/categories/option/react/components/ComboBox/index.tsx
  13. +204
    -15
      packages/web-kitchensink-reactnext/src/categories/option/react/components/MenuSelect/index.tsx
  14. +145
    -3
      packages/web-kitchensink-reactnext/src/categories/option/react/components/RadioButton/index.tsx
  15. +7
    -0
      packages/web-kitchensink-reactnext/src/categories/option/react/components/RadioButton/style.module.css
  16. +88
    -3
      packages/web-kitchensink-reactnext/src/categories/option/react/components/RadioTickBox/index.tsx
  17. +7
    -0
      packages/web-kitchensink-reactnext/src/categories/option/react/components/RadioTickBox/style.module.css
  18. +71
    -29
      packages/web-kitchensink-reactnext/src/categories/option/react/components/TagInput/index.tsx
  19. +180
    -3
      packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleButton/index.tsx
  20. +15
    -0
      packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleButton/style.module.css
  21. +121
    -3
      packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleSwitch/index.tsx
  22. +118
    -0
      packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleSwitch/style.module.css
  23. +122
    -3
      packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleTickBox/index.tsx
  24. +15
    -0
      packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleTickBox/style.module.css
  25. +104
    -262
      packages/web-kitchensink-reactnext/src/pages/categories/option/index.tsx
  26. +3
    -0
      packages/web-kitchensink-reactnext/tailwind.config.js
  27. +1
    -0
      packages/web-kitchensink-reactnext/tsconfig.json

+ 11
- 6
packages/web-kitchensink-reactnext/src/categories/action/react/components/ActionButton/index.tsx 查看文件

@@ -2,7 +2,7 @@ import * as React from 'react';
import clsx from 'clsx';
import * as ButtonBase from '@tesseract-design/web-base-button';

type ActionButtonDerivedElement = HTMLButtonElement;
export type ActionButtonDerivedElement = HTMLButtonElement;

export interface ActionButtonProps extends Omit<React.HTMLProps<ActionButtonDerivedElement>, 'type' | 'size'> {
type?: ButtonBase.ButtonType;
@@ -90,11 +90,16 @@ export const ActionButton = React.forwardRef<ActionButtonDerivedElement, ActionB
)}
</span>
{badge && (
<span
data-testid="badge"
>
{badge}
</span>
<>
<span className="sr-only">
{' - '}
</span>
<span
data-testid="badge"
>
{badge}
</span>
</>
)}
{menuItem && (
<span


+ 9
- 0
packages/web-kitchensink-reactnext/src/categories/blob/react/common.ts 查看文件

@@ -0,0 +1,9 @@
import * as React from 'react';

export interface CommonPreviewProps<F extends Partial<File> = Partial<File>> {
file?: F;
disabled?: boolean;
enhanced?: boolean;
}

export type FilePreviewComponent<T extends CommonPreviewProps = CommonPreviewProps> = (props: T) => React.ReactNode;

+ 4
- 6
packages/web-kitchensink-reactnext/src/categories/blob/react/components/AudioFilePreview/index.tsx 查看文件

@@ -15,14 +15,12 @@ import {SpectrogramCanvas, WaveformCanvas} from '@modal-soft/react-wavesurfer';
import {Slider} from '@/categories/number/react';
import {KeyValueTable} from '@/categories/information/react';
import {useEnhanced} from '@modal-soft/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';

type AudioFilePreviewDerivedElement = HTMLAudioElement;
export type AudioFilePreviewDerivedElement = HTMLAudioElement;

export interface AudioFilePreviewProps<F extends Partial<File> = Partial<File>> extends Omit<React.HTMLProps<AudioFilePreviewDerivedElement>, 'controls'> {
file?: F;
disabled?: boolean;
enhanced?: boolean;
}
export interface AudioFilePreviewProps<F extends Partial<File> = Partial<File>>
extends Omit<React.HTMLProps<AudioFilePreviewDerivedElement>, 'controls'>, CommonPreviewProps<F> {}

export const AudioFilePreview = React.forwardRef<AudioFilePreviewDerivedElement, AudioFilePreviewProps>(({
file,


+ 4
- 5
packages/web-kitchensink-reactnext/src/categories/blob/react/components/BinaryFilePreview/index.tsx 查看文件

@@ -6,13 +6,12 @@ import clsx from 'clsx';
import {KeyValueTable} from '@/categories/information/react';
import {BinaryDataCanvas} from '@modal-soft/react-binary-data-canvas';
import {useEnhanced} from '@modal-soft/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';

type BinaryFilePreviewDerivedElement = HTMLDivElement;
export type BinaryFilePreviewDerivedElement = HTMLDivElement;

export interface BinaryFilePreviewProps<F extends Partial<File> = Partial<File>> extends React.HTMLProps<BinaryFilePreviewDerivedElement> {
file?: F;
enhanced?: boolean;
}
export interface BinaryFilePreviewProps<F extends Partial<File> = Partial<File>>
extends React.HTMLProps<BinaryFilePreviewDerivedElement>, CommonPreviewProps<F> {}

export const BinaryFilePreview = React.forwardRef<BinaryFilePreviewDerivedElement, BinaryFilePreviewProps>(({
file,


+ 79
- 65
packages/web-kitchensink-reactnext/src/categories/blob/react/components/FileSelectBox/index.tsx 查看文件

@@ -1,13 +1,28 @@
import * as React from 'react';
import {ContentType, FileWithResolvedContentType, getMimeTypeDescription} from '@/utils/blob';
import { FilePreview } from '../FilePreview';
import {ContentType, FileWithResolvedContentType, getContentType, getMimeTypeDescription} from '@/utils/blob';
import {formatFileSize} from '@/utils/numeral';
import {AudioMiniFilePreview} from '@tesseract-design/web-blob-react';
import {AudioFilePreview} from '../AudioFilePreview';
import {BinaryFilePreview} from '../BinaryFilePreview';
import {ImageFilePreview} from '../ImageFilePreview';
import {VideoFilePreview} from '../VideoFilePreview';
import {TextFilePreview} from '../TextFilePreview';
import {AudioMiniFilePreview} from '../AudioMiniFilePreview';
import {delegateTriggerChangeEvent} from '@/utils/event';
import clsx from 'clsx';
import {useEnhanced} from '@modal-soft/react-utils';
import {FilePreviewComponent} from '@/categories/blob/react/common';

export interface FileButtonProps extends Omit<React.HTMLProps<HTMLInputElement>, 'size' | 'type' | 'style' | 'label' | 'list'> {
const FILE_PREVIEW_COMPONENTS: Record<ContentType, FilePreviewComponent> = {
[ContentType.IMAGE]: ImageFilePreview,
[ContentType.AUDIO]: AudioFilePreview,
[ContentType.VIDEO]: VideoFilePreview,
[ContentType.BINARY]: BinaryFilePreview,
[ContentType.TEXT]: TextFilePreview,
};

export type FileSelectBoxDerivedElement = HTMLInputElement;

export interface FileSelectBoxProps extends Omit<React.HTMLProps<FileSelectBoxDerivedElement>, 'size' | 'type' | 'style' | 'label' | 'list'> {
/**
* Should the component display a border?
*/
@@ -31,52 +46,7 @@ export interface FileButtonProps extends Omit<React.HTMLProps<HTMLInputElement>,
hiddenLabel?: boolean,
}

const FilePreviewGrid = ({
fileList: files,
}: { fileList?: FileList }) => {
if (!files) {
return null;
}

return (
<div className="w-full h-full overflow-auto -mx-4 px-4">
<div className="w-full grid gap-4 grid-cols-3">
{Array.from(files).map((file: File, i) => {
const f = file as unknown as FileWithResolvedContentType;
return (
<div
data-testid="selectedFileItem"
key={i}
className={`w-full aspect-square rounded overflow-hidden relative before:absolute before:content-[''] before:bg-current before:top-0 before:left-0 before:w-full before:h-full before:opacity-10`}
title={[f.name, getMimeTypeDescription(f.type), formatFileSize(f.size)].join(', ')}
>
{
f.resolvedType === ContentType.IMAGE
&& typeof f?.url === 'string'
&& (
<img
className="block w-full h-full object-center object-cover"
src={f.url}
alt={f.name}
data-testid="preview"
/>
)
}
{
f.resolvedType === ContentType.AUDIO
&& (
<AudioMiniFilePreview file={f} />
)
}
</div>
);
})}
</div>
</div>
)
}

export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps>(
export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileSelectBoxProps>(
(
{
label = '',
@@ -91,7 +61,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps>
className,
id: idProp,
...etcProps
}: FileButtonProps,
}: FileSelectBoxProps,
forwardedRef,
) => {
const { enhanced } = useEnhanced({ enhanced: enhancedProp });
@@ -155,7 +125,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps>
});
}

const filesCount = React.useMemo(() => fileList?.length ?? 0, [fileList]);
const filesCount = fileList?.length ?? 0;

return (
<div
@@ -174,7 +144,6 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps>
data-testid="clickArea"
htmlFor={id}
/>

<input
{...etcProps}
id={id}
@@ -237,23 +206,68 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps>
{
multiple
&& (
<FilePreviewGrid fileList={fileList} />
<div className="w-full h-full overflow-auto -mx-4 px-4">
<div className="w-full grid gap-4 grid-cols-3">
{Array.from(fileList ?? []).map((file: File) => {
const f = file as unknown as FileWithResolvedContentType;
const fileContentType = getContentType(file.type, file.name);
return (
<div
data-testid="selectedFileItem"
key={f?.url ?? f?.name}
className={`w-full aspect-square rounded overflow-hidden relative before:absolute before:content-[''] before:bg-current before:top-0 before:left-0 before:w-full before:h-full before:opacity-10`}
title={[f.name, getMimeTypeDescription(f.type), formatFileSize(f.size)].join(', ')}
>
{
fileContentType === ContentType.IMAGE
&& typeof f?.url === 'string'
&& (
<img
className="block w-full h-full object-center object-cover"
src={f.url}
alt={f.name}
data-testid="preview"
/>
)
}
{
fileContentType === ContentType.AUDIO
&& (
<AudioMiniFilePreview file={f} />
)
}
</div>
);
})}
</div>
</div>
)
}
{
!multiple
&& (
<div
className={`w-full h-full`}
>
<div data-testid="selectedFileItem" className={`h-full w-full p-4 box-border rounded overflow-hidden relative before:absolute before:content-[''] before:bg-current before:top-0 before:left-0 before:w-full before:h-full before:opacity-10`}>
<FilePreview
className="w-full h-full relative"
fileList={fileList}
/>
&& Array.from(fileList ?? []).map((file) => {
const f = file as unknown as FileWithResolvedContentType;
const fileContentType = getContentType(file.type, file.name);
const { [fileContentType]: FilePreviewComponent = BinaryFilePreview } = FILE_PREVIEW_COMPONENTS;
return (
<div
key={f?.url ?? f?.name}
className="w-full h-full"
>
<div
data-testid="selectedFileItem"
className="h-full w-full p-4 box-border rounded overflow-hidden relative before:absolute before:content-[''] before:bg-current before:top-0 before:left-0 before:w-full before:h-full before:opacity-10"
>
<FilePreviewComponent
className="w-full h-full relative"
file={f}
enhanced={enhanced}
disabled={disabled}
/>
</div>
</div>
</div>
)
)
})
}
</div>
</div>


+ 5
- 103
packages/web-kitchensink-reactnext/src/categories/blob/react/components/ImageFilePreview/index.tsx 查看文件

@@ -5,111 +5,13 @@ import clsx from 'clsx';
import {useFileMetadata, useFileUrl, useImageControls} from '@/categories/blob/react';
import {KeyValueTable} from '@/categories/information/react';
import {useEnhanced} from '@modal-soft/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';
import {Swatch} from '@tesseract-design/web-color-react';

type RgbTuple = [number, number, number];
export type ImageFilePreviewDerivedElement = HTMLImageElement;

type SwatchDerivedElement = HTMLInputElement;

export interface SwatchProps extends Omit<React.HTMLProps<SwatchDerivedElement>, 'color'> {
color: RgbTuple;
mode?: 'rgb' | 'hsl';
}

export const useSwatchControls = () => {
const id = React.useId();
const copyColor: React.ReactEventHandler<SwatchDerivedElement> = React.useCallback(async (e) => {
const { value } = e.currentTarget;
await window.navigator.clipboard.writeText(value);
}, []);
return React.useMemo(() => ({
id,
copyColor,
}), [id, copyColor]);
};

export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({
color,
mode = 'rgb',
className,
style,
...etcProps
}, forwardedRef) => {
const { id, copyColor } = useSwatchControls();
const colorValue = `${mode}(${color.join(', ')})`;

return (
<span
className={clsx(
'inline-block align-middle',
className,
)}
style={style}
>
<input
{...etcProps}
ref={forwardedRef}
type="text"
value={colorValue}
className="sr-only select-all peer"
readOnly
id={id}
onSelect={copyColor}
/>
<label
className={clsx(
'relative rounded ring-secondary/50 whitespace-nowrap inline-block align-top leading-none cursor-pointer', // todo eyedropper cursor
'peer-focus:outline-0 peer-focus:ring-4',
'peer-active:ring-tertiary/50',
'peer-disabled:opacity-50 peer-disabled:cursor-not-allowed',
)}
title={colorValue}
htmlFor={id}
>
<span
className="inline-block w-5 h-5 align-middle border border-[#ffffff]"
>
<span
className="block w-full h-full border border-[#000000]"
style={{
backgroundColor: `${mode}(${color.join(' ')})`,
}}
/>
</span>
<span className="tabular-nums text-xs sr-only">
{
color
.map((c) => c
.toString()
.padStart(4, ' ')
.split('')
.map((cc, j) => (
<span
key={`${cc}:${j}`}
className={clsx({
'opacity-0': cc === ' ',
})}
>
{j === 0 && ' '}
{cc === ' ' && j > 0 ? '0' : cc}
</span>
))
)
}
</span>
</label>
</span>
);
});

Swatch.displayName = 'Swatch';

type ImageFilePreviewDerivedElement = HTMLImageElement;

export interface ImageFilePreviewProps<F extends Partial<File> = Partial<File>> extends Omit<React.HTMLProps<ImageFilePreviewDerivedElement>, 'src' | 'alt'> {
file?: F;
disabled?: boolean;
enhanced?: boolean;
}
export interface ImageFilePreviewProps<F extends Partial<File> = Partial<File>>
extends Omit<React.HTMLProps<ImageFilePreviewDerivedElement>, 'src' | 'alt'>, CommonPreviewProps<F> {}

export const ImageFilePreview = React.forwardRef<ImageFilePreviewDerivedElement, ImageFilePreviewProps>(({
file,


+ 3
- 4
packages/web-kitchensink-reactnext/src/categories/blob/react/components/TextFilePreview/index.tsx 查看文件

@@ -6,13 +6,12 @@ import clsx from 'clsx';
import {KeyValueTable} from '@/categories/information/react';
import {Refractor} from '@modal-soft/react-refractor';
import {useEnhanced} from '@modal-soft/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';

type TextFilePreviewDerivedComponent = HTMLDivElement;

export interface TextFilePreviewProps<F extends Partial<File> = Partial<File>> extends React.HTMLProps<TextFilePreviewDerivedComponent> {
file?: F;
enhanced?: boolean;
}
export interface TextFilePreviewProps<F extends Partial<File> = Partial<File>>
extends React.HTMLProps<TextFilePreviewDerivedComponent>, CommonPreviewProps<F> {}

export const TextFilePreview = React.forwardRef<TextFilePreviewDerivedComponent, TextFilePreviewProps>(({
file,


+ 4
- 6
packages/web-kitchensink-reactnext/src/categories/blob/react/components/VideoFilePreview/index.tsx 查看文件

@@ -6,14 +6,12 @@ import clsx from 'clsx';
import {Slider} from '@tesseract-design/web-number-react';
import {KeyValueTable} from '@/categories/information/react';
import {useEnhanced} from '@modal-soft/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';

type VideoFilePreviewDerivedComponent = HTMLVideoElement;
export type VideoFilePreviewDerivedComponent = HTMLVideoElement;

export interface VideoFilePreviewProps<F extends Partial<File> = Partial<File>> extends Omit<React.HTMLProps<VideoFilePreviewDerivedComponent>, 'controls'> {
file?: F;
disabled?: boolean;
enhanced?: boolean;
}
export interface VideoFilePreviewProps<F extends Partial<File> = Partial<File>>
extends Omit<React.HTMLProps<VideoFilePreviewDerivedComponent>, 'controls'>, CommonPreviewProps<F> {}

export const VideoFilePreview = React.forwardRef<VideoFilePreviewDerivedComponent, VideoFilePreviewProps>(({
file,


+ 99
- 0
packages/web-kitchensink-reactnext/src/categories/color/react/components/Swatch/index.tsx 查看文件

@@ -0,0 +1,99 @@
import * as React from 'react';
import clsx from 'clsx';

type RgbTuple = [number, number, number];

export type SwatchDerivedElement = HTMLInputElement;

export interface SwatchProps extends Omit<React.HTMLProps<SwatchDerivedElement>, 'color'> {
color: RgbTuple;
mode?: 'rgb' | 'hsl';
}

export const useSwatchControls = () => {
const id = React.useId();
const copyColor: React.ReactEventHandler<SwatchDerivedElement> = React.useCallback(async (e) => {
const { value } = e.currentTarget;
await window.navigator.clipboard.writeText(value);
}, []);
return React.useMemo(() => ({
id,
copyColor,
}), [id, copyColor]);
};

export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({
color,
mode = 'rgb',
className,
style,
...etcProps
}, forwardedRef) => {
const { id, copyColor } = useSwatchControls();
const colorValue = `${mode}(${color.join(', ')})`;

return (
<span
className={clsx(
'inline-block align-middle',
className,
)}
style={style}
>
<input
{...etcProps}
ref={forwardedRef}
type="text"
value={colorValue}
className="sr-only select-all peer"
readOnly
id={id}
onSelect={copyColor}
/>
<label
className={clsx(
'relative rounded ring-secondary/50 whitespace-nowrap inline-block align-top leading-none cursor-pointer', // todo eyedropper cursor
'peer-focus:outline-0 peer-focus:ring-4',
'peer-active:ring-tertiary/50',
'peer-disabled:opacity-50 peer-disabled:cursor-not-allowed',
)}
title={colorValue}
htmlFor={id}
>
<span
className="inline-block w-5 h-5 align-middle border border-[#ffffff]"
>
<span
className="block w-full h-full border border-[#000000]"
style={{
backgroundColor: `${mode}(${color.join(' ')})`,
}}
/>
</span>
<span className="tabular-nums text-xs sr-only">
{
color
.map((c) => c
.toString()
.padStart(4, ' ')
.split('')
.map((cc, j) => (
<span
key={`${cc}:${j}`}
className={clsx({
'opacity-0': cc === ' ',
})}
>
{j === 0 && ' '}
{cc === ' ' && j > 0 ? '0' : cc}
</span>
))
)
}
</span>
</label>
</span>
);
});

Swatch.displayName = 'Swatch';

+ 1
- 0
packages/web-kitchensink-reactnext/src/categories/color/react/index.ts 查看文件

@@ -0,0 +1 @@
export * from './components/Swatch';

+ 21
- 11
packages/web-kitchensink-reactnext/src/categories/navigation/react/components/LinkButton/index.tsx 查看文件

@@ -74,20 +74,30 @@ export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonP
{children}
</span>
{subtext && (
<span
className="block h-[1.3em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded font-bold text-xs"
data-testid="subtext"
>
{subtext}
</span>
<>
<span className="sr-only">
{' - '}
</span>
<span
className="block h-[1.3em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded font-bold text-xs"
data-testid="subtext"
>
{subtext}
</span>
</>
)}
</span>
{badge && (
<span
data-testid="badge"
>
{badge}
</span>
<>
<span className="sr-only">
{' - '}
</span>
<span
data-testid="badge"
>
{badge}
</span>
</>
)}
{menuItem && (
<span


+ 118
- 108
packages/web-kitchensink-reactnext/src/categories/option/react/components/ComboBox/index.tsx 查看文件

@@ -61,141 +61,151 @@ export const ComboBox = React.forwardRef<ComboBoxDerivedElement, ComboBoxProps>(
variant = 'default' as const,
hiddenLabel = false,
className,
children,
...etcProps
}: ComboBoxProps,
ref,
) => {
const labelId = React.useId();
const datalistId = React.useId();

return (
<div
className={clsx(
'relative rounded ring-secondary/50',
'focus-within:ring-4',
{
'block': block,
'inline-block align-middle': !block,
},
className,
)}
>
<input
{...etcProps}
ref={ref}
aria-labelledby={labelId}
type={type}
data-testid="input"
<>
<datalist
id={datalistId}
>
{children}
</datalist>
<div
className={clsx(
'bg-negative rounded-inherit w-full peer block',
'focus:outline-0',
'disabled:opacity-50 disabled:cursor-not-allowed',
{
'text-xxs': size === 'small',
'text-xs': size === 'medium',
},
{
'pl-4': variant === 'default',
'pl-1.5': variant === 'alternate',
},
{
'pt-4': variant === 'alternate',
},
'relative rounded ring-secondary/50',
'focus-within:ring-4',
{
'pr-4': variant === 'default' && !indicator,
'pr-1.5': variant === 'alternate' && !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
{
'h-10': size === 'small',
'h-12': size === 'medium',
'h-16': size === 'large',
'block': block,
'inline-block align-middle': !block,
},
className,
)}
/>
{
label && (
<label
data-testid="label"
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)
}
{hint && (
<div
data-testid="hint"
>
<input
{...etcProps}
ref={ref}
aria-labelledby={labelId}
type={type}
list={datalistId}
data-testid="input"
className={clsx(
'absolute left-0 px-1 pointer-events-none text-xxs peer-disabled:opacity-50 leading-none w-full bg-negative',
'bg-negative rounded-inherit w-full peer block',
'focus:outline-0',
'disabled:opacity-50 disabled:cursor-not-allowed',
{
'text-xxs': size === 'small',
'text-xs': size === 'medium',
},
{
'bottom-0 pl-4 pb-1': variant === 'default',
'top-0.5': variant === 'alternate',
'pl-4': variant === 'default',
'pl-1.5': variant === 'alternate',
},
{
'pt-2': variant === 'alternate' && size === 'small',
'pt-3': variant === 'alternate' && size !== 'small',
'pt-4': variant === 'alternate',
},
{
'pr-4': !indicator && variant === 'default',
'pr-1': !indicator && variant === 'alternate',
'pr-4': variant === 'default' && !indicator,
'pr-1.5': variant === 'alternate' && !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
{
'h-10': size === 'small',
'h-12': size === 'medium',
'h-16': size === 'large',
},
)}
>
/>
{
label && (
<label
data-testid="label"
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)
}
{hint && (
<div
className="opacity-50 whitespace-nowrap w-full h-[1.1em] overflow-hidden text-ellipsis"
data-testid="hint"
className={clsx(
'absolute left-0 px-1 pointer-events-none text-xxs peer-disabled:opacity-50 leading-none w-full bg-negative',
{
'bottom-0 pl-4 pb-1': variant === 'default',
'top-0.5': variant === 'alternate',
},
{
'pt-2': variant === 'alternate' && size === 'small',
'pt-3': variant === 'alternate' && size !== 'small',
},
{
'pr-4': !indicator && variant === 'default',
'pr-1': !indicator && variant === 'alternate',
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
{hint}
<div
className="opacity-50 whitespace-nowrap w-full h-[1.1em] overflow-hidden text-ellipsis"
>
{hint}
</div>
</div>
</div>
)}
{indicator && (
<div
className={clsx(
'text-center flex items-center justify-center peer-disabled:opacity-50 aspect-square absolute bottom-0 right-0 pointer-events-none',
{
'w-10': size === 'small',
'w-12': size === 'medium',
'w-16': size === 'large',
},
)}
>
{indicator}
</div>
)}
{
border && (
<span
data-testid="border"
className="absolute z-[1] peer-disabled:opacity-50 inset-0 rounded-inherit border-2 border-primary pointer-events-none peer-focus:border-secondary"
/>
)
}
</div>
)}
{indicator && (
<div
className={clsx(
'text-center flex items-center justify-center peer-disabled:opacity-50 aspect-square absolute bottom-0 right-0 pointer-events-none',
{
'w-10': size === 'small',
'w-12': size === 'medium',
'w-16': size === 'large',
},
)}
>
{indicator}
</div>
)}
{
border && (
<span
data-testid="border"
className="absolute z-[1] peer-disabled:opacity-50 inset-0 rounded-inherit border-2 border-primary pointer-events-none peer-focus:border-secondary"
/>
)
}
</div>
</>
);
}
);


+ 204
- 15
packages/web-kitchensink-reactnext/src/categories/option/react/components/MenuSelect/index.tsx 查看文件

@@ -1,23 +1,212 @@
import * as React from 'react';
import * as TextControlBase from '@tesseract-design/web-base-textcontrol';
import clsx from 'clsx';

type MenuSelectDerivedElement = HTMLSelectElement;

export interface MenuSelectProps extends React.HTMLProps<MenuSelectDerivedElement> {

export interface MenuSelectProps extends Omit<React.HTMLProps<MenuSelectDerivedElement>, 'size' | 'style' | 'label'> {
/**
* 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,
/**
* Size of the component.
*/
size?: TextControlBase.TextControlSize,
/**
* Additional description, usually graphical, indicating the nature of the component's value.
*/
indicator?: React.ReactNode,
/**
* Should the component display a border?
*/
border?: boolean,
/**
* Should the component occupy the whole width of its parent?
*/
block?: boolean,
/**
* Style of the component.
*/
variant?: TextControlBase.TextControlVariant,
/**
* Is the label hidden?
*/
hiddenLabel?: boolean,
}

export const MenuSelect = React.forwardRef<MenuSelectDerivedElement, MenuSelectProps>(({
children,
...etcProps
}, forwardedRef) => {
return (
<div>
<select
{...etcProps}
ref={forwardedRef}
/>
</div>
)
});
/**
* Component for inputting textual values.
*
* This component supports multiline input and adjusts its layout accordingly.
*/
export const MenuSelect = React.forwardRef<MenuSelectDerivedElement, MenuSelectProps>(
(
{
label,
hint,
indicator,
size = 'medium' as const,
border = false,
block = false,
variant = 'default' as const,
hiddenLabel = false,
className,
...etcProps
}: MenuSelectProps,
ref,
) => {
const labelId = React.useId();

return (
<div
className={clsx(
'relative rounded ring-secondary/50',
'focus-within:ring-4',
{
'block': block,
'inline-block align-middle': !block,
},
className,
)}
>
<select
{...etcProps}
ref={ref}
aria-labelledby={labelId}
data-testid="input"
size={2}
style={{
height: 0,
}}
className={clsx(
'bg-negative rounded-inherit w-full peer block',
'focus:outline-0',
'disabled:opacity-50 disabled:cursor-not-allowed',
{
'resize': !block,
'resize-y': block,
},
{
'text-xxs': size === 'small',
'text-xs': size === 'medium',
},
{
'pl-4': variant === 'default',
'pl-1.5': variant === 'alternate',
},
{
'pt-4': variant === 'alternate' && size === 'small',
'pt-5': variant === 'alternate' && size === 'medium',
'pt-8': variant === 'alternate' && size === 'large',
},
{
'py-2.5': variant === 'default' && size === 'small',
'py-3': variant === 'default' && size === 'medium',
'py-5': variant === 'default' && size === 'large',
},
{
'pr-4': variant === 'default' && !indicator,
'pr-1.5': variant === 'alternate' && !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
{
'min-h-10': size === 'small',
'min-h-12': size === 'medium',
'min-h-16': size === 'large',
},
)}
/>
{
label && (
<label
data-testid="label"
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)
}
{hint && (
<div
data-testid="hint"
className={clsx(
'absolute left-0 px-1 pointer-events-none text-xxs peer-disabled:opacity-50 leading-none w-full bg-negative',
{
'bottom-0 pl-4 pb-1': variant === 'default',
'top-0.5': variant === 'alternate',
},
{
'pt-2': variant === 'alternate' && size === 'small',
'pt-3': variant === 'alternate' && size !== 'small',
},
{
'pr-4': !indicator && variant === 'default',
'pr-1': !indicator && variant === 'alternate',
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<div
className="opacity-50 whitespace-nowrap w-full h-[1.1em] overflow-hidden text-ellipsis"
>
{hint}
</div>
</div>
)}
{indicator && (
<div
className={clsx(
'text-center flex items-center justify-center peer-disabled:opacity-50 aspect-square absolute bottom-0 right-0 pointer-events-none',
{
'w-10': size === 'small',
'w-12': size === 'medium',
'w-16': size === 'large',
},
)}
>
{indicator}
</div>
)}
{
border && (
<span
data-testid="border"
className="absolute z-[1] peer-disabled:opacity-50 inset-0 rounded-inherit border-2 border-primary pointer-events-none peer-focus:border-secondary"
/>
)
}
</div>
);
}
);

MenuSelect.displayName = 'MenuSelect';

+ 145
- 3
packages/web-kitchensink-reactnext/src/categories/option/react/components/RadioButton/index.tsx 查看文件

@@ -1,3 +1,145 @@
export const RadioButton = () => (
<input type="radio" />
);
import * as React from 'react';
import clsx from 'clsx';
import * as ButtonBase from '@tesseract-design/web-base-button';
import styles from './style.module.css';

export type RadioButtonDerivedElement = HTMLInputElement;

export interface RadioButtonProps extends Omit<React.InputHTMLAttributes<RadioButtonDerivedElement>, 'type' | 'size'> {
block?: boolean;
compact?: boolean;
size?: ButtonBase.ButtonSize;
subtext?: React.ReactNode;
badge?: React.ReactNode;
variant: ButtonBase.ButtonVariant;
}

export const RadioButton = React.forwardRef<RadioButtonDerivedElement, RadioButtonProps>(({
children,
block = false,
compact = false,
size = 'medium',
id: idProp,
className,
subtext,
badge,
variant,
style,
...etcProps
}, forwardedRef) => {
const defaultId = React.useId();
const id = idProp ?? defaultId;
return (
<>
<input
{...etcProps}
ref={forwardedRef}
type="radio"
id={id}
className={clsx(
'sr-only peer',
styles['radio-button'],
)}
/>
<label
style={style}
htmlFor={id}
className={clsx(
'items-center justify-start rounded overflow-hidden ring-secondary/50 gap-4 leading-none select-none cursor-pointer',
'peer-focus:outline-0 peer-focus:ring-4 peer-focus:ring-secondary/50',
'active:ring-tertiary/50 active:ring-4',
'peer-disabled:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:ring-0',
'text-primary peer-disabled:text-primary peer-focus:text-secondary peer-checked:text-tertiary active:text-tertiary',
{
'flex w-full': block,
'inline-flex max-w-full align-middle': !block,
},
{
'pl-2 pr-2': compact,
'pl-4 pr-4': !compact,
},
{
'border-2 border-primary peer-disabled:border-primary peer-focus:border-secondary peer-checked:border-tertiary active:border-tertiary' : variant !== 'bare',
'bg-primary text-negative peer-disabled:bg-primary peer-focus:bg-secondary peer-checked:bg-tertiary active:bg-tertiary': variant === 'filled',
},
{
'h-10': size === 'small',
'h-12': size === 'medium',
'h-16': size === 'large',
},
className,
)}
>
<span
className={clsx(
'w-6 h-6 block rounded-full border-2 p-0.5 box-border',
{
'-mr-2': compact,
'border-current': variant !== 'filled',
'border-negative': variant === 'filled',
}
)}
>
<span
className={clsx(
'w-full h-full rounded-full bg-current',
{
'text-current': variant !== 'filled',
'text-negative': variant === 'filled',
},
)}
/>
</span>
<span
className={clsx(
'contents',
{
'text-current': variant !== 'filled',
'text-negative': variant === 'filled',
},
)}
>
<span
className={clsx(
'flex-auto min-w-0',
)}
>
<span
className="block uppercase font-bold h-[1.1em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded"
data-testid="children"
>
{children}
</span>
{subtext && (
<>
<span className="sr-only">
{' - '}
</span>
<span
className="block h-[1.3em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded font-bold text-xs"
data-testid="subtext"
>
{subtext}
</span>
</>
)}
</span>
{badge && (
<>
<span className="sr-only">
{' - '}
</span>
<span
data-testid="badge"
>
{badge}
</span>
</>
)}
</span>
</label>
</>
)
});

RadioButton.displayName = 'RadioButton';

+ 7
- 0
packages/web-kitchensink-reactnext/src/categories/option/react/components/RadioButton/style.module.css 查看文件

@@ -0,0 +1,7 @@
.radio-button + label > :first-child > :first-child {
display: none;
}

.radio-button:checked + label > :first-child > :first-child {
display: block;
}

+ 88
- 3
packages/web-kitchensink-reactnext/src/categories/option/react/components/RadioTickBox/index.tsx 查看文件

@@ -1,3 +1,88 @@
export const RadioTickBox = () => (
<input type="radio" />
);
import * as React from 'react';
import clsx from 'clsx';
import styles from './style.module.css';

export type RadioTickBoxDerivedElement = HTMLInputElement;

export interface RadioTickBoxProps extends Omit<React.InputHTMLAttributes<RadioTickBoxDerivedElement>, 'type' | 'size'> {
block?: boolean;
subtext?: React.ReactNode;
badge?: React.ReactNode;
}

export const RadioTickBox = React.forwardRef<RadioTickBoxDerivedElement, RadioTickBoxProps>(({
children,
block = false,
id: idProp,
className,
subtext,
badge,
style,
...etcProps
}, forwardedRef) => {
const defaultId = React.useId();
const id = idProp ?? defaultId;
return (
<div
className={clsx(
'flex gap-x-4 flex-wrap',
className,
)}
style={style}
>
<input
{...etcProps}
ref={forwardedRef}
type="radio"
id={id}
className={clsx(
'sr-only peer/radio',
styles['radio-tick-box'],
)}
/>
<label
htmlFor={id}
className="peer/children order-2 cursor-pointer peer-disabled/radio:cursor-not-allowed"
>
<span
data-testid="children"
>
{children}
</span>
</label>
<label
htmlFor={id}
className={clsx(
'order-1 block rounded-full ring-secondary/50 overflow-hidden gap-4 leading-none select-none cursor-pointer',
'peer-focus/radio:outline-0 peer-focus/radio:ring-4 peer-focus/radio:ring-secondary/50',
'active:ring-tertiary/50 active:ring-4',
'peer-active/children:ring-tertiary/50 peer-active/children:ring-4 peer-active/children:text-tertiary',
'peer-disabled/radio:opacity-50 peer-disabled/radio:cursor-not-allowed peer-disabled/radio:ring-0',
'text-primary peer-disabled/radio:text-primary peer-focus/radio:text-secondary peer-checked/radio:text-tertiary active:text-tertiary',
)}
>
<span
className={clsx(
'w-6 h-6 block rounded-full border-2 p-0.5 box-border border-current',
)}
>
<span
className={clsx(
'w-full h-full rounded-full bg-current text-current',
)}
/>
</span>
</label>
{subtext && (
<div
className="block w-full font-semi-expanded text-xs pl-10 order-3"
data-testid="subtext"
>
{subtext}
</div>
)}
</div>
)
});

RadioTickBox.displayName = 'RadioTickBox';

+ 7
- 0
packages/web-kitchensink-reactnext/src/categories/option/react/components/RadioTickBox/style.module.css 查看文件

@@ -0,0 +1,7 @@
.radio-tick-box + label + label > :first-child > :first-child {
display: none;
}

.radio-tick-box:checked + label + label > :first-child > :first-child {
display: block;
}

+ 71
- 29
packages/web-kitchensink-reactnext/src/categories/option/react/components/TagInput/index.tsx 查看文件

@@ -1,6 +1,7 @@
import * as React from 'react';
import * as TextControlBase from '@tesseract-design/web-base-textcontrol';
import clsx from 'clsx';
import {useEnhanced} from '@/packages/react-utils';

type TagInputDerivedElement = HTMLInputElement;

@@ -41,6 +42,7 @@ export interface TagInputProps extends Omit<React.HTMLProps<TagInputDerivedEleme
* Is the label hidden?
*/
hiddenLabel?: boolean,
enhanced?: boolean,
}

/**
@@ -61,11 +63,38 @@ export const TagInput = React.forwardRef<TagInputDerivedElement, TagInputProps>(
variant = 'default' as const,
hiddenLabel = false,
className,
enhanced: enhancedProp = false,
...etcProps
}: TagInputProps,
ref,
forwardedRef,
) => {
const {enhanced} = useEnhanced({ enhanced: enhancedProp });
const defaultRef = React.useRef<TagInputDerivedElement>(null);
const ref = forwardedRef ?? defaultRef;
const labelId = React.useId();
const dummyInputRef = React.useRef<HTMLInputElement>(null);

const handleFocus: React.FocusEventHandler<HTMLInputElement> = (e) => {
if (!(typeof ref === 'object' && ref)) {
return;
}
const { current: input } = ref;
if (!input) {
return;
}
input.focus();
};

const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
if (!(typeof dummyInputRef === 'object' && dummyInputRef)) {
return;
}
const { current: input } = dummyInputRef;
if (!input) {
return;
}
input.value = e.currentTarget.value;
};

return (
<div
@@ -86,36 +115,49 @@ export const TagInput = React.forwardRef<TagInputDerivedElement, TagInputProps>(
type={type}
data-testid="input"
className={clsx(
'bg-negative rounded-inherit w-full peer block',
'focus:outline-0',
'disabled:opacity-50 disabled:cursor-not-allowed',
{
'text-xxs': size === 'small',
'text-xs': size === 'medium',
},
{
'pl-4': variant === 'default',
'pl-1.5': variant === 'alternate',
},
{
'pt-4': variant === 'alternate',
},
{
'pr-4': variant === 'default' && !indicator,
'pr-1.5': variant === 'alternate' && !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
{
'h-10': size === 'small',
'h-12': size === 'medium',
'h-16': size === 'large',
},
'peer',
enhanced && 'sr-only',
)}
onChange={handleChange}
/>
{enhanced && (
<input
ref={dummyInputRef}
readOnly
tabIndex={-1}
onFocus={handleFocus}
className={clsx(
'bg-negative rounded-inherit w-full block',
'focus:outline-0',
'disabled:opacity-50 disabled:cursor-not-allowed',
{
'text-xxs': size === 'small',
'text-xs': size === 'medium',
},
{
'pl-4': variant === 'default',
'pl-1.5': variant === 'alternate',
},
{
'pt-4': variant === 'alternate',
},
{
'pr-4': variant === 'default' && !indicator,
'pr-1.5': variant === 'alternate' && !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
{
'h-10': size === 'small',
'h-12': size === 'medium',
'h-16': size === 'large',
},
)}
/>
)}
{
label && (
<label


+ 180
- 3
packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleButton/index.tsx 查看文件

@@ -1,3 +1,180 @@
export const ToggleButton = () => (
<input type="checkbox" />
);
import * as React from 'react';
import clsx from 'clsx';
import * as ButtonBase from '@tesseract-design/web-base-button';
import styles from './style.module.css';

export type ToggleButtonDerivedElement = HTMLInputElement;

export interface ToggleButtonProps extends Omit<React.InputHTMLAttributes<ToggleButtonDerivedElement>, 'type' | 'size'> {
block?: boolean;
compact?: boolean;
size?: ButtonBase.ButtonSize;
subtext?: React.ReactNode;
badge?: React.ReactNode;
variant: ButtonBase.ButtonVariant;
indeterminate?: boolean;
}

export const ToggleButton = React.forwardRef<ToggleButtonDerivedElement, ToggleButtonProps>(({
children,
block = false,
compact = false,
size = 'medium',
id: idProp,
className,
subtext,
badge,
variant,
indeterminate = false,
...etcProps
}, forwardedRef) => {
const defaultRef = React.useRef<ToggleButtonDerivedElement>(null);
const ref = forwardedRef ?? defaultRef;
const defaultId = React.useId();
const id = idProp ?? defaultId;

React.useEffect(() => {
if (!(typeof ref === 'object' && ref)) {
return;
}
const { current: element } = ref;
if (!element) {
return;
}
element.indeterminate = indeterminate;
}, [indeterminate, ref]);

return (
<>
<input
{...etcProps}
ref={ref}
type="checkbox"
id={id}
className={clsx(
'sr-only peer',
styles['toggle-button'],
)}
/>
<label
htmlFor={id}
className={clsx(
'items-center justify-start rounded overflow-hidden ring-secondary/50 gap-4 leading-none select-none cursor-pointer',
'peer-focus:outline-0 peer-focus:ring-4 peer-focus:ring-secondary/50',
'active:ring-tertiary/50 active:ring-4',
'peer-disabled:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:ring-0',
'text-primary peer-disabled:text-primary peer-focus:text-secondary peer-checked:text-tertiary active:text-tertiary',
{
'flex w-full': block,
'inline-flex max-w-full align-middle': !block,
},
{
'pl-2 pr-2': compact,
'pl-4 pr-4': !compact,
},
{
'border-2 border-primary peer-disabled:border-primary peer-focus:border-secondary peer-checked:border-tertiary active:border-tertiary' : variant !== 'bare',
'bg-primary text-negative peer-disabled:bg-primary peer-focus:bg-secondary peer-checked:bg-tertiary active:bg-tertiary': variant === 'filled',
},
{
'h-10': size === 'small',
'h-12': size === 'medium',
'h-16': size === 'large',
},
className,
)}
>
<span
className={clsx(
'w-6 h-6 block rounded border-2 p-0.5 box-border',
{
'border-current': variant !== 'filled',
'border-negative': variant === 'filled',
'-mr-2': compact,
}
)}
>
<svg
className={clsx(
'w-full h-full fill-none stroke-3 linejoin-round linecap-round',
{
'stroke-negative': variant === 'filled',
'stroke-current': variant !== 'filled',
}
)}
viewBox="0 0 24 24"
role="presentation"
>
<polyline
points="20 6 9 17 4 12"
/>
</svg>
<svg
className={clsx(
'w-full h-full fill-none stroke-3 linejoin-round linecap-round',
{
'stroke-negative': variant === 'filled',
'stroke-current': variant !== 'filled',
}
)}
viewBox="0 0 24 24"
role="presentation"
>
<polyline
points="20 12 4 12"
/>
</svg>
</span>
<span
className={clsx(
'contents',
{
'text-current': variant !== 'filled',
'text-negative': variant === 'filled',
},
)}
>
<span
className={clsx(
'flex-auto min-w-0',
)}
>
<span
className="block uppercase font-bold h-[1.1em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded"
data-testid="children"
>
{children}
</span>
{subtext && (
<>
<span className="sr-only">
{' - '}
</span>
<span
className="block h-[1.3em] w-full whitespace-nowrap overflow-hidden text-ellipsis font-semi-expanded font-bold text-xs"
data-testid="subtext"
>
{subtext}
</span>
</>
)}
</span>
{badge && (
<>
<span className="sr-only">
{' - '}
</span>
<span
data-testid="badge"
>
{badge}
</span>
</>
)}
</span>
</label>
</>
)
});

ToggleButton.displayName = 'ToggleButton';

+ 15
- 0
packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleButton/style.module.css 查看文件

@@ -0,0 +1,15 @@
.toggle-button + label > :first-child > :first-child {
display: none;
}

.toggle-button:checked + label > :first-child > :first-child {
display: block;
}

.toggle-button + label > :first-child > :first-child + * {
display: none;
}

.toggle-button:indeterminate + label > :first-child > :first-child + * {
display: block;
}

+ 121
- 3
packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleSwitch/index.tsx 查看文件

@@ -1,3 +1,121 @@
export const ToggleSwitch = () => (
<input type="checkbox" />
);
import * as React from 'react';
import clsx from 'clsx';
import styles from './style.module.css';
import {ToggleButtonDerivedElement} from '@/categories/option/react';

export type ToggleSwitchDerivedElement = HTMLInputElement;

export interface ToggleSwitchProps extends Omit<React.InputHTMLAttributes<ToggleSwitchDerivedElement>, 'type' | 'size'> {
block?: boolean;
subtext?: React.ReactNode;
badge?: React.ReactNode;
indeterminate?: boolean;
checkedLabel?: React.ReactNode;
uncheckedLabel?: React.ReactNode;
}

export const ToggleSwitch = React.forwardRef<ToggleSwitchDerivedElement, ToggleSwitchProps>(({
uncheckedLabel,
checkedLabel,
block = false,
id: idProp,
className,
subtext,
badge,
style,
indeterminate = false,
...etcProps
}, forwardedRef) => {
const defaultRef = React.useRef<ToggleButtonDerivedElement>(null);
const ref = forwardedRef ?? defaultRef;
const defaultId = React.useId();
const id = idProp ?? defaultId;

React.useEffect(() => {
if (!(typeof ref === 'object' && ref)) {
return;
}
const { current: element } = ref;
if (!element) {
return;
}
element.indeterminate = indeterminate;
}, [indeterminate, ref]);

return (
<div
className={clsx(
'flex gap-x-4 flex-wrap',
className,
)}
style={style}
>
<input
{...etcProps}
ref={ref}
type="checkbox"
id={id}
className={clsx(
'sr-only peer/radio',
styles['toggle-switch'],
)}
/>
<label
htmlFor={id}
className="peer/children order-3 cursor-pointer peer-disabled/radio:cursor-not-allowed"
>
<span
data-testid="children"
>
{checkedLabel}
</span>
</label>
<label
htmlFor={id}
className="peer/children order-1 cursor-pointer peer-disabled/radio:cursor-not-allowed"
>
{uncheckedLabel && (
<span
data-testid="uncheckedLabel"
>
{uncheckedLabel}
</span>
)}
</label>
<label
htmlFor={id}
className={clsx(
'order-2 block rounded-full ring-secondary/50 overflow-hidden gap-4 leading-none select-none cursor-pointer',
'peer-focus/radio:outline-0 peer-focus/radio:ring-4 peer-focus/radio:ring-secondary/50',
'active:ring-tertiary/50 active:ring-4',
'peer-active/children:ring-tertiary/50 peer-active/children:ring-4 peer-active/children:text-tertiary',
'peer-disabled/radio:opacity-50 peer-disabled/radio:cursor-not-allowed peer-disabled/radio:ring-0',
'text-primary peer-disabled/radio:text-primary peer-focus/radio:text-secondary peer-checked/radio:text-tertiary active:text-tertiary',
!uncheckedLabel && '-ml-4',
)}
>
<span>
<span>
<span>
<span />
</span>
</span>
</span>
</label>
{subtext && (
<div
className={clsx(
'block w-full font-semi-expanded text-xs order-4',
!uncheckedLabel && 'pl-16',
uncheckedLabel && 'pt-2',
)}
data-testid="subtext"
>
{subtext}
</div>
)}
</div>
)
});

ToggleSwitch.displayName = 'ToggleSwitch';

+ 118
- 0
packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleSwitch/style.module.css 查看文件

@@ -0,0 +1,118 @@
.toggle-switch + label + label + label > :first-child {
appearance: none;
cursor: pointer;
position: relative;
overflow: hidden;
height: 1.5em;
width: 3em;
display: block;
box-sizing: border-box;
border-radius: 9999px;
color: rgb(var(--color-primary));
}

.toggle-switch:checked + label + label + label > :first-child {
color: rgb(var(--color-tertiary));
}

.toggle-switch:focus + label + label + label > :first-child {
color: rgb(var(--color-secondary));
}

.toggle-switch + label:active + label + label > :first-child {
color: rgb(var(--color-tertiary));
}

.toggle-switch + label + label:active + label > :first-child {
color: rgb(var(--color-tertiary));
}

.toggle-switch + label + label + label:active > :first-child {
color: rgb(var(--color-tertiary));
}

.toggle-switch + label + label + label > :first-child > :first-child {
width: 100%;
height: 100%;
background-color: rgb(var(--color-primary) / 50%);
border-radius: 9999px;
display: block;
box-sizing: border-box;
background-clip: content-box;
padding: 0.25em;
appearance: none;
}

.toggle-switch:checked + label + label + label > :first-child > :first-child {
background-color: rgb(var(--color-tertiary) / 50%);
}

.toggle-switch:focus + label + label + label > :first-child > :first-child {
background-color: rgb(var(--color-secondary) / 50%);
}

.toggle-switch + label:active + label + label > :first-child > :first-child {
background-color: rgb(var(--color-tertiary) / 50%);
}

.toggle-switch + label + label:active + label > :first-child > :first-child {
background-color: rgb(var(--color-tertiary) / 50%);
}

.toggle-switch + label + label + label:active > :first-child > :first-child {
background-color: rgb(var(--color-tertiary) / 50%);
}

.toggle-switch + label + label + label > :first-child > :first-child > :first-child {
appearance: none;
border-radius: 9999px;
display: block;
width: 100%;
height: 100%;
margin: -0.25em;
box-sizing: border-box;
background-clip: content-box;
}

.toggle-switch + label + label + label > :first-child > :first-child > :first-child > :first-child {
width: 1.5em;
height: 1.5em;
margin: -0.25em 0 0 0;
display: block;
border-radius: 9999px;
background-color: currentColor;
appearance: none;
aspect-ratio: 1 / 1;
z-index: 1;
position: relative;
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-primary) / 50%);
}

.toggle-switch:checked + label + label + label > :first-child > :first-child > :first-child > :first-child {
margin-left: calc(100% - 1em);
}

.toggle-switch:indeterminate + label + label + label > :first-child > :first-child > :first-child > :first-child {
margin-left: calc(50% - 0.5em);
}

.toggle-switch:checked + label + label + label > :first-child > :first-child > :first-child > :first-child {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%);
}

.toggle-switch:focus + label + label + label > :first-child > :first-child > :first-child > :first-child {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-secondary) / 50%);
}

.toggle-switch + label:active + label + label > :first-child > :first-child > :first-child > :first-child {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%);
}

.toggle-switch + label + label:active + label > :first-child > :first-child > :first-child > :first-child {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%);
}

.toggle-switch + label + label + label:active > :first-child > :first-child > :first-child > :first-child {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%);
}


+ 122
- 3
packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleTickBox/index.tsx 查看文件

@@ -1,3 +1,122 @@
export const ToggleTickBox = () => (
<input type="checkbox" />
);
import * as React from 'react';
import clsx from 'clsx';
import styles from './style.module.css';
import {ToggleButtonDerivedElement} from '@/categories/option/react';

export type ToggleTickBoxDerivedElement = HTMLInputElement;

export interface ToggleTickBoxProps extends Omit<React.InputHTMLAttributes<ToggleTickBoxDerivedElement>, 'type' | 'size'> {
block?: boolean;
subtext?: React.ReactNode;
badge?: React.ReactNode;
indeterminate?: boolean;
}

export const ToggleTickBox = React.forwardRef<ToggleTickBoxDerivedElement, ToggleTickBoxProps>(({
children,
block = false,
id: idProp,
className,
subtext,
badge,
style,
indeterminate = false,
...etcProps
}, forwardedRef) => {
const defaultRef = React.useRef<ToggleButtonDerivedElement>(null);
const ref = forwardedRef ?? defaultRef;
const defaultId = React.useId();
const id = idProp ?? defaultId;

React.useEffect(() => {
if (!(typeof ref === 'object' && ref)) {
return;
}
const { current: element } = ref;
if (!element) {
return;
}
element.indeterminate = indeterminate;
}, [indeterminate, ref]);

return (
<div
className={clsx(
'flex gap-x-4 flex-wrap',
className,
)}
style={style}
>
<input
{...etcProps}
ref={ref}
type="checkbox"
id={id}
className={clsx(
'sr-only peer/radio',
styles['toggle-tick-box'],
)}
/>
<label
htmlFor={id}
className="peer/children order-2 cursor-pointer peer-disabled/radio:cursor-not-allowed"
>
<span
data-testid="children"
>
{children}
</span>
</label>
<label
htmlFor={id}
className={clsx(
'order-1 block rounded ring-secondary/50 overflow-hidden gap-4 leading-none select-none cursor-pointer',
'peer-focus/radio:outline-0 peer-focus/radio:ring-4 peer-focus/radio:ring-secondary/50',
'active:ring-tertiary/50 active:ring-4',
'peer-active/children:ring-tertiary/50 peer-active/children:ring-4 peer-active/children:text-tertiary',
'peer-disabled/radio:opacity-50 peer-disabled/radio:cursor-not-allowed peer-disabled/radio:ring-0',
'text-primary peer-disabled/radio:text-primary peer-focus/radio:text-secondary peer-checked/radio:text-tertiary active:text-tertiary',
)}
>
<span
className={clsx(
'w-6 h-6 block rounded-inherit border-2 p-0.5 box-border border-current',
)}
>
<svg
className={clsx(
'w-full h-full fill-none stroke-3 linejoin-round linecap-round stroke-current',
)}
viewBox="0 0 24 24"
role="presentation"
>
<polyline
points="20 6 9 17 4 12"
/>
</svg>
<svg
className={clsx(
'w-full h-full fill-none stroke-3 linejoin-round linecap-round stroke-current',
)}
viewBox="0 0 24 24"
role="presentation"
>
<polyline
points="20 12 4 12"
/>
</svg>
</span>
</label>
{subtext && (
<div
className="block w-full font-semi-expanded text-xs pl-10 order-3"
data-testid="subtext"
>
{subtext}
</div>
)}
</div>
)
});

ToggleTickBox.displayName = 'ToggleTickBox';

+ 15
- 0
packages/web-kitchensink-reactnext/src/categories/option/react/components/ToggleTickBox/style.module.css 查看文件

@@ -0,0 +1,15 @@
.toggle-tick-box + label + label > :first-child > :first-child {
display: none;
}

.toggle-tick-box:checked + label + label > :first-child > :first-child {
display: block;
}

.toggle-tick-box + label + label > :first-child > :first-child + * {
display: none;
}

.toggle-tick-box:indeterminate + label + label > :first-child > :first-child + * {
display: block;
}

+ 104
- 262
packages/web-kitchensink-reactnext/src/pages/categories/option/index.tsx 查看文件

@@ -1,6 +1,5 @@
import { NextPage } from 'next';
import * as Option from '@tesseract-design/web-option-react';
import * as SelectControlBase from '@tesseract-design/web-base-selectcontrol';
import { DefaultLayout } from '@/components/DefaultLayout';
import {ReactNode} from 'react';

@@ -625,6 +624,7 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.RadioButton
block
variant="bare"
name="RadioButton"
>
Button
@@ -641,7 +641,7 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.RadioButton
border
variant="outline"
block
name="RadioButton"
>
@@ -650,7 +650,6 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.RadioButton
border
variant="filled"
block
name="RadioButton"
@@ -663,6 +662,7 @@ const OptionPage: NextPage<Props> = ({
block
disabled
name="RadioButton"
variant="bare"
>
Button
</Option.RadioButton>
@@ -679,7 +679,7 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.RadioButton
border
variant="outline"
block
disabled
name="RadioButton"
@@ -689,7 +689,6 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.RadioButton
border
variant="filled"
block
disabled
@@ -708,7 +707,7 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.RadioButton
block
border
variant="outline"
size="small"
name="RadioButton"
>
@@ -718,7 +717,6 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.RadioButton
block
border
variant="filled"
size="small"
name="RadioButton"
@@ -729,7 +727,7 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.RadioButton
block
border
variant="outline"
size="medium"
name="RadioButton"
>
@@ -739,7 +737,6 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.RadioButton
block
border
variant="filled"
size="medium"
name="RadioButton"
@@ -750,7 +747,7 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.RadioButton
block
border
variant="outline"
size="large"
name="RadioButton"
>
@@ -760,7 +757,6 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.RadioButton
block
border
variant="filled"
size="large"
name="RadioButton"
@@ -779,7 +775,7 @@ const OptionPage: NextPage<Props> = ({
<Option.RadioButton
block
compact
border
variant="outline"
name="RadioButton"
>
Button
@@ -789,7 +785,6 @@ const OptionPage: NextPage<Props> = ({
<Option.RadioButton
block
compact
border
variant="filled"
name="RadioButton"
>
@@ -800,7 +795,7 @@ const OptionPage: NextPage<Props> = ({
<Option.RadioButton
block
compact
border
variant="outline"
name="RadioButton"
subtext={
<>
@@ -815,7 +810,6 @@ const OptionPage: NextPage<Props> = ({
<Option.RadioButton
block
compact
border
variant="filled"
name="RadioButton"
subtext={
@@ -831,7 +825,7 @@ const OptionPage: NextPage<Props> = ({
<Option.RadioButton
block
compact
border
variant="outline"
size="small"
name="RadioButton"
subtext={
@@ -847,7 +841,6 @@ const OptionPage: NextPage<Props> = ({
<Option.RadioButton
block
compact
border
variant="filled"
size="small"
name="RadioButton"
@@ -883,203 +876,26 @@ const OptionPage: NextPage<Props> = ({
</Option.RadioTickBox>
</div>
</div>
</div>
</div>
</section>
<section>
<div className="container mx-auto px-4">
<h1>
TagInput
</h1>
<div>
<section>
<h2>
Default
</h2>
<div>
<div className="grid md:grid-cols-2 gap-4">
<div>
<Option.TagInput
enhanced
size="small"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
border
size="small"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
border
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
size="large"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
border
size="large"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
disabled
/>
</div>
<div>
<Option.TagInput
enhanced
border
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
disabled
/>
</div>
</div>
</div>
</section>
<section>
<h2>Alternate</h2>
<div className="grid gap-4 my-4">
<div>
<div className="grid md:grid-cols-2 gap-4">
<div>
<Option.TagInput
enhanced
variant="alternate"
size="small"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
border
variant="alternate"
size="small"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
variant="alternate"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
border
variant="alternate"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
variant="alternate"
size="large"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Option.TagInput
enhanced
border
block
variant="alternate"
size="large"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
/>
</div>
<div>
<Option.TagInput
enhanced
variant="alternate"
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
disabled
/>
</div>
<div>
<Option.TagInput
enhanced
variant="alternate"
border
label="TagInput"
hint="Type anything here&hellip;"
indicator="A"
block
disabled
/>
</div>
</div>
<Option.RadioTickBox
block
subtext={
<>
<div>
This is a very long text that may span a couple of lines.
</div>
<div>
The subtext should not be included with the click area of the component.
</div>
</>
}
name="RadioButton"
>
RadioButton
</Option.RadioTickBox>
</div>
</section>
</div>
</div>
</div>
</section>
@@ -1095,6 +911,7 @@ const OptionPage: NextPage<Props> = ({
<div className="grid md:grid-cols-2 gap-4 my-4">
<div>
<Option.ToggleButton
variant="bare"
block
>
Button
@@ -1110,7 +927,7 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.ToggleButton
border
variant="outline"
block
>
Button
@@ -1118,7 +935,6 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.ToggleButton
border
variant="filled"
block
>
@@ -1127,6 +943,7 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.ToggleButton
variant="bare"
block
disabled
>
@@ -1144,7 +961,7 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.ToggleButton
border
variant="outline"
block
disabled
>
@@ -1153,7 +970,6 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.ToggleButton
border
variant="filled"
block
disabled
@@ -1163,7 +979,7 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.ToggleButton
border
variant="outline"
block
indeterminate
>
@@ -1172,7 +988,6 @@ const OptionPage: NextPage<Props> = ({
</div>
<div>
<Option.ToggleButton
border
variant="filled"
block
indeterminate
@@ -1190,7 +1005,7 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.ToggleButton
block
border
variant="outline"
size="small"
>
Button
@@ -1199,7 +1014,6 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.ToggleButton
block
border
variant="filled"
size="small"
>
@@ -1209,7 +1023,7 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.ToggleButton
block
border
variant="outline"
size="medium"
>
Button
@@ -1218,7 +1032,6 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.ToggleButton
block
border
variant="filled"
size="medium"
>
@@ -1228,7 +1041,7 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.ToggleButton
block
border
variant="outline"
size="large"
>
Button
@@ -1237,7 +1050,6 @@ const OptionPage: NextPage<Props> = ({
<div>
<Option.ToggleButton
block
border
variant="filled"
size="large"
>
@@ -1255,7 +1067,7 @@ const OptionPage: NextPage<Props> = ({
<Option.ToggleButton
block
compact
border
variant="outline"
>
Button
</Option.ToggleButton>
@@ -1264,7 +1076,6 @@ const OptionPage: NextPage<Props> = ({
<Option.ToggleButton
block
compact
border
variant="filled"
>
Button
@@ -1274,7 +1085,7 @@ const OptionPage: NextPage<Props> = ({
<Option.ToggleButton
block
compact
border
variant="outline"
subtext={
<>
Subtext
@@ -1288,7 +1099,6 @@ const OptionPage: NextPage<Props> = ({
<Option.ToggleButton
block
compact
border
variant="filled"
subtext={
<>
@@ -1303,7 +1113,7 @@ const OptionPage: NextPage<Props> = ({
<Option.ToggleButton
block
compact
border
variant="outline"
size="small"
subtext={
<>
@@ -1318,7 +1128,6 @@ const OptionPage: NextPage<Props> = ({
<Option.ToggleButton
block
compact
border
variant="filled"
size="small"
subtext={
@@ -1379,6 +1188,7 @@ const OptionPage: NextPage<Props> = ({
<Option.ToggleSwitch
block
subtext="Subtext"
indeterminate
checkedLabel="On"
uncheckedLabel="Off"
/>
@@ -1441,8 +1251,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1452,8 +1263,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1461,8 +1273,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1471,8 +1284,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1481,8 +1295,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1492,8 +1307,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1502,8 +1318,9 @@ const OptionPage: NextPage<Props> = ({
indicator="A"
block
disabled
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1513,8 +1330,9 @@ const OptionPage: NextPage<Props> = ({
indicator="A"
block
disabled
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
</div>
</div>
@@ -1531,8 +1349,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1543,8 +1362,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1553,8 +1373,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1564,8 +1385,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1575,8 +1397,9 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1587,8 +1410,9 @@ const OptionPage: NextPage<Props> = ({
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1598,8 +1422,9 @@ const OptionPage: NextPage<Props> = ({
indicator="A"
block
disabled
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
<div>
<Option.ComboBox
@@ -1610,8 +1435,9 @@ const OptionPage: NextPage<Props> = ({
indicator="A"
block
disabled
options={options}
/>
>
{options}
</Option.ComboBox>
</div>
</div>
</div>
@@ -1638,6 +1464,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1648,6 +1475,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1656,6 +1484,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1665,6 +1494,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1674,6 +1504,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1684,6 +1515,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1693,6 +1525,7 @@ const OptionPage: NextPage<Props> = ({
indicator="A"
block
disabled
enhanced
/>
</div>
<div>
@@ -1703,6 +1536,7 @@ const OptionPage: NextPage<Props> = ({
indicator="A"
block
disabled
enhanced
/>
</div>
</div>
@@ -1720,6 +1554,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1731,6 +1566,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1740,6 +1576,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1750,6 +1587,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1760,6 +1598,7 @@ const OptionPage: NextPage<Props> = ({
hint="Type anything here&hellip;"
indicator="A"
block
enhanced
/>
</div>
<div>
@@ -1771,6 +1610,7 @@ const OptionPage: NextPage<Props> = ({
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
enhanced
/>
</div>
<div>
@@ -1781,6 +1621,7 @@ const OptionPage: NextPage<Props> = ({
indicator="A"
block
disabled
enhanced
/>
</div>
<div>
@@ -1792,6 +1633,7 @@ const OptionPage: NextPage<Props> = ({
indicator="A"
block
disabled
enhanced
/>
</div>
</div>


+ 3
- 0
packages/web-kitchensink-reactnext/tailwind.config.js 查看文件

@@ -65,6 +65,9 @@ module.exports = {
16: '4rem',
64: '16rem',
},
strokeWidth: {
3: '3',
},
},
},
plugins: [],


+ 1
- 0
packages/web-kitchensink-reactnext/tsconfig.json 查看文件

@@ -22,6 +22,7 @@
"@tesseract-design/web-base-textcontrol": ["./src/base/textcontrol"],
"@tesseract-design/web-action-react": ["./src/categories/action/react"],
"@tesseract-design/web-blob-react": ["./src/categories/blob/react"],
"@tesseract-design/web-color-react": ["./src/categories/color/react"],
"@tesseract-design/web-freeform-react": ["./src/categories/freeform/react"],
"@tesseract-design/web-information-react": ["./src/categories/information/react"],
"@tesseract-design/web-option-react": ["./src/categories/option/react"],


Loading…
取消
儲存