Implement components from the ground up using Tailwind styling.pull/1/head
@@ -23,7 +23,6 @@ | |||
npm-debug.log* | |||
yarn-debug.log* | |||
yarn-error.log* | |||
.pnpm-debug.log* | |||
# local env files | |||
.env*.local |
@@ -8,6 +8,8 @@ First, run the development server: | |||
npm run dev | |||
# or | |||
yarn dev | |||
# or | |||
pnpm dev | |||
``` | |||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. | |||
@@ -18,6 +20,8 @@ You can start editing the page by modifying `pages/index.tsx`. The page auto-upd | |||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. | |||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. | |||
## Learn More | |||
To learn more about Next.js, take a look at the following resources: |
@@ -1,7 +1,6 @@ | |||
/** @type {import('next').NextConfig} */ | |||
const nextConfig = { | |||
reactStrictMode: true, | |||
swcMinify: true, | |||
} | |||
module.exports = nextConfig |
@@ -0,0 +1,36 @@ | |||
{ | |||
"name": "web-kitchensink-reactnext", | |||
"version": "0.1.0", | |||
"private": true, | |||
"scripts": { | |||
"dev": "next dev", | |||
"build": "next build", | |||
"start": "next start", | |||
"lint": "next lint" | |||
}, | |||
"dependencies": { | |||
"@reach/slider": "^0.18.0", | |||
"@types/node": "20.3.1", | |||
"@types/react": "18.2.14", | |||
"@types/react-dom": "18.2.6", | |||
"autoprefixer": "10.4.14", | |||
"clsx": "^1.2.1", | |||
"eslint": "8.43.0", | |||
"eslint-config-next": "13.4.7", | |||
"languagedetect": "^2.0.0", | |||
"mime-types": "^2.1.35", | |||
"next": "13.4.7", | |||
"postcss": "8.4.24", | |||
"prismjs": "^1.29.0", | |||
"react": "18.2.0", | |||
"react-dom": "18.2.0", | |||
"tailwindcss": "3.3.2", | |||
"typescript": "5.1.3", | |||
"wavesurfer.js": "^6.6.4" | |||
}, | |||
"devDependencies": { | |||
"@types/mime-types": "^2.1.1", | |||
"@types/prismjs": "^1.26.0", | |||
"@types/wavesurfer.js": "^6.0.6" | |||
} | |||
} |
@@ -0,0 +1 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg> |
@@ -0,0 +1 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg> |
@@ -0,0 +1,5 @@ | |||
export type ButtonType = 'submit' | 'reset' | 'button'; | |||
export type ButtonVariant = 'bare' | 'filled' | 'outline'; | |||
export type ButtonSize = 'small' | 'medium' | 'large'; |
@@ -0,0 +1,5 @@ | |||
export interface SelectOption { | |||
label: string; | |||
value?: string; | |||
children?: SelectOption[]; | |||
} |
@@ -0,0 +1,5 @@ | |||
export type TextControlSize = 'small' | 'medium' | 'large'; | |||
export type TextControlVariant = 'default' | 'alternate'; | |||
export type TextControlInputType = 'text' | 'search'; |
@@ -0,0 +1,115 @@ | |||
import * as React from 'react'; | |||
import clsx from 'clsx'; | |||
import * as ButtonBase from '@tesseract-design/web-base-button'; | |||
type ActionButtonDerivedElement = HTMLButtonElement; | |||
export interface ActionButtonProps extends Omit<React.HTMLProps<ActionButtonDerivedElement>, 'type' | 'size'> { | |||
type?: ButtonBase.ButtonType; | |||
variant: ButtonBase.ButtonVariant; | |||
block?: boolean; | |||
subtext?: React.ReactNode; | |||
badge?: React.ReactNode; | |||
menuItem?: boolean; | |||
size?: ButtonBase.ButtonSize; | |||
compact?: boolean; | |||
} | |||
export const ActionButton = React.forwardRef<ActionButtonDerivedElement, ActionButtonProps>(({ | |||
type = 'button' as const, | |||
variant, | |||
subtext, | |||
badge, | |||
menuItem = false, | |||
children, | |||
size = 'medium' as const, | |||
compact = false, | |||
className, | |||
block = false, | |||
...etcProps | |||
}, forwardedRef) => ( | |||
<button | |||
{...etcProps} | |||
type={type} | |||
ref={forwardedRef} | |||
className={clsx( | |||
'items-center justify-center rounded overflow-hidden ring-secondary/50 leading-none gap-4 select-none', | |||
'focus:outline-0 focus:ring-4', | |||
'active:ring-tertiary/50', | |||
'disabled:opacity-50 disabled:cursor-not-allowed', | |||
{ | |||
'flex w-full': block, | |||
'inline-flex max-w-full align-middle': !block, | |||
}, | |||
{ | |||
'pl-2': compact, | |||
'pl-4': !compact, | |||
'pr-4': !(compact || menuItem), | |||
'pr-2': compact || menuItem, | |||
}, | |||
{ | |||
'border-2 border-primary disabled:border-primary focus:border-secondary active:border-tertiary' : variant !== 'bare', | |||
'bg-negative text-primary disabled:text-primary focus:text-secondary active:text-tertiary': variant !== 'filled', | |||
'bg-primary text-negative disabled:bg-primary focus:bg-secondary active:bg-tertiary': variant === 'filled', | |||
}, | |||
{ | |||
'h-10': size === 'small', | |||
'h-12': size === 'medium', | |||
'h-16': size === 'large', | |||
}, | |||
className, | |||
)} | |||
> | |||
<span | |||
className={clsx( | |||
'flex-auto min-w-0', | |||
{ | |||
'text-left': compact || menuItem, | |||
'text-center': !(compact || menuItem), | |||
}, | |||
)} | |||
> | |||
<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 | |||
data-testid="badge" | |||
> | |||
{badge} | |||
</span> | |||
)} | |||
{menuItem && ( | |||
<span | |||
data-testid="menuItemIndicator" | |||
> | |||
<svg | |||
className="w-6 h-6 fill-none stroke-current stroke-2 linejoin-round linecap-round" | |||
viewBox="0 0 24 24" | |||
role="presentation" | |||
> | |||
<polyline points="9 18 15 12 9 6"/> | |||
</svg> | |||
</span> | |||
)} | |||
</button> | |||
)); | |||
ActionButton.displayName = 'ActionButton'; |
@@ -1,79 +1,20 @@ | |||
import * as React from 'react'; | |||
import WaveSurfer from 'wavesurfer.js'; | |||
import {AudioFile, getMimeTypeDescription} from '../../utils/blob'; | |||
import {formatFileSize, formatNumeral, formatSecondsDurationPrecise} from '../../utils/numeral'; | |||
import {AudioFile, getMimeTypeDescription} from '@/utils/blob'; | |||
import {formatFileSize, formatNumeral, formatSecondsDurationPrecise} from '@/utils/numeral'; | |||
import {useAudioFilePreviewControls} from '@/categories/blob/react/hooks/audio'; | |||
export interface VideoFilePreviewProps { | |||
export interface AudioFilePreviewProps { | |||
file: AudioFile; | |||
} | |||
export const AudioFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||
export const AudioFilePreview: React.FC<AudioFilePreviewProps> = ({ | |||
file: f, | |||
}) => { | |||
const mediaContainerRef = React.useRef<HTMLDivElement>(null); | |||
const mediaControllerRef = React.useRef<WaveSurfer>(null); | |||
const [isPlaying, setIsPlaying] = React.useState(false); | |||
React.useEffect(() => { | |||
if (!mediaControllerRef.current) { | |||
return; | |||
} | |||
if (isPlaying) { | |||
void mediaControllerRef.current.play(); | |||
return; | |||
} | |||
mediaControllerRef.current.pause(); | |||
}, [isPlaying]); | |||
React.useEffect(() => { | |||
if (!mediaControllerRef.current) { | |||
return; | |||
} | |||
if (!mediaContainerRef.current) { | |||
return; | |||
} | |||
if (typeof f.metadata?.previewUrl !== 'string') { | |||
return; | |||
} | |||
mediaContainerRef.current.innerHTML = ''; | |||
if (f.type === 'audio/mid') { | |||
return; | |||
} | |||
const mediaControllerRefMutable = mediaControllerRef as React.MutableRefObject<WaveSurfer>; | |||
mediaControllerRefMutable.current = WaveSurfer.create({ | |||
container: mediaContainerRef.current, | |||
url: f.metadata.previewUrl, | |||
cursorWidth: 0, | |||
height: mediaContainerRef.current.offsetHeight, | |||
barWidth: 2, | |||
barGap: 2, | |||
barRadius: 1, | |||
}); | |||
mediaControllerRefMutable.current.on('finish', () => { | |||
setIsPlaying(false); | |||
mediaControllerRefMutable.current.seekTo(0); | |||
}); | |||
return () => { | |||
if (!mediaControllerRefMutable.current) { | |||
return; | |||
} | |||
mediaControllerRefMutable.current.destroy(); | |||
} | |||
}, [f, mediaContainerRef, mediaControllerRef]); | |||
const playMedia = () => { | |||
setIsPlaying((p) => !p); | |||
}; | |||
const { | |||
mediaContainerRef, | |||
playMedia, | |||
isPlaying, | |||
} = useAudioFilePreviewControls({ file: f }); | |||
return ( | |||
<div className="flex flex-col gap-4 w-full h-full relative"> | |||
@@ -110,7 +51,7 @@ export const AudioFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||
title={f.type} | |||
className="m-0 w-full text-ellipsis overflow-hidden" | |||
> | |||
{getMimeTypeDescription(f.type)} | |||
{getMimeTypeDescription(f.type, f.name)} | |||
</dd> | |||
</div> | |||
<div className="w-full"> |
@@ -0,0 +1,26 @@ | |||
import * as React from 'react'; | |||
import {AudioFile, getMimeTypeDescription} from '@/utils/blob'; | |||
import {formatFileSize, formatNumeral, formatSecondsDurationPrecise} from '@/utils/numeral'; | |||
import {useAudioFilePreviewControls} from '@/categories/blob/react/hooks/audio'; | |||
export interface AudioMiniFilePreviewProps { | |||
file: AudioFile; | |||
} | |||
export const AudioMiniFilePreview: React.FC<AudioMiniFilePreviewProps> = ({ | |||
file: f, | |||
}) => { | |||
const { | |||
mediaContainerRef, | |||
playMedia, | |||
isPlaying, | |||
} = useAudioFilePreviewControls({ file: f }); | |||
return ( | |||
<div | |||
className="absolute top-0 left-0 w-full h-full cursor-pointer" | |||
ref={mediaContainerRef} | |||
onClick={playMedia} | |||
/> | |||
); | |||
}; |
@@ -1,6 +1,6 @@ | |||
import * as React from 'react'; | |||
import {BinaryFile, getMimeTypeDescription} from '../../utils/blob'; | |||
import {formatFileSize, formatNumeral} from '../../utils/numeral'; | |||
import {BinaryFile, getMimeTypeDescription} from '@/utils/blob'; | |||
import {formatFileSize, formatNumeral} from '@/utils/numeral'; | |||
export interface BinaryFilePreviewProps { | |||
file: BinaryFile; |
@@ -0,0 +1,64 @@ | |||
import * as React from 'react'; | |||
import { TextFilePreview } from '../TextFilePreview'; | |||
import { ImageFilePreview } from '../ImageFilePreview'; | |||
import { AudioFilePreview } from '../AudioFilePreview'; | |||
import { VideoFilePreview } from '../VideoFilePreview'; | |||
import { BinaryFilePreview } from '../BinaryFilePreview'; | |||
import {AugmentedFile, augmentFile, ContentType, getContentType} from '@/utils/blob'; | |||
const FILE_PREVIEW_COMPONENTS: Record<ContentType, React.ElementType> = { | |||
[ContentType.TEXT]: TextFilePreview, | |||
[ContentType.IMAGE]: ImageFilePreview, | |||
[ContentType.AUDIO]: AudioFilePreview, | |||
[ContentType.VIDEO]: VideoFilePreview, | |||
[ContentType.BINARY]: BinaryFilePreview, | |||
}; | |||
const useFilePreviews = (fileList?: FileList) => { | |||
const [selectedFiles, setSelectedFiles] = React.useState([] as AugmentedFile[]); | |||
React.useEffect(() => { | |||
const loadFilePreviews = async (fileList: FileList) => { | |||
const files = Array.from(fileList); | |||
return Promise.all( | |||
files.map(async (f) => { | |||
const augmentedFile = await augmentFile(f); | |||
if (augmentedFile.resolvedType === ContentType.TEXT && augmentedFile.metadata?.scheme) { | |||
await import(`prismjs/components/prism-${augmentedFile.metadata.scheme}`); | |||
} | |||
return augmentedFile; | |||
}) | |||
); | |||
} | |||
if (fileList) { | |||
loadFilePreviews(fileList).then((fileResult) => { | |||
setSelectedFiles(fileResult); | |||
}); | |||
} | |||
}, [fileList]); | |||
return React.useMemo(() => ({ | |||
files: selectedFiles, | |||
}), [selectedFiles]); | |||
}; | |||
export interface FilePreviewProps { | |||
fileList?: FileList; | |||
} | |||
export const FilePreview: React.FC<FilePreviewProps> = ({ | |||
fileList, | |||
}) => { | |||
const { files } = useFilePreviews(fileList); | |||
if (files.length < 1) { | |||
return null; | |||
} | |||
const f = fileList?.[0]; | |||
const contentType = getContentType(f?.type, f?.name); | |||
const FilePreviewComponent = FILE_PREVIEW_COMPONENTS[contentType] ?? BinaryFilePreview; | |||
return ( | |||
<FilePreviewComponent file={f} /> | |||
); | |||
}; |
@@ -1,23 +1,9 @@ | |||
import {NextPage} from 'next'; | |||
import * as React from 'react'; | |||
//import * as BlobReact from '@tesseract-design/web-blob-react'; | |||
import * as BlobBase from '@tesseract-design/web-base-blob'; | |||
import * as ButtonBase from '@tesseract-design/web-base-button'; | |||
import {formatFileSize} from '../../../utils/numeral'; | |||
import { | |||
AugmentedFile, | |||
augmentFile, | |||
ContentType, | |||
getContentType, | |||
getMimeTypeDescription, | |||
} from '../../../utils/blob'; | |||
import {delegateTriggerChangeEvent} from '../../../utils/event'; | |||
import {TextFilePreview} from '../../../components/TextFilePreview'; | |||
import {ImageFilePreview} from '../../../components/ImageFilePreview'; | |||
import {AudioFilePreview} from '../../../components/AudioFilePreview'; | |||
import {VideoFilePreview} from '../../../components/VideoFilePreview'; | |||
import {BinaryFilePreview} from '../../../components/BinaryFilePreview'; | |||
import {AudioMiniFilePreview} from '../../../components/AudioMiniFilePreview'; | |||
import {AugmentedFile, augmentFile, ContentType, getMimeTypeDescription} from '@/utils/blob'; | |||
import { FilePreview as FilePreviewComponent} from '../FilePreview'; | |||
import {formatFileSize} from '@/utils/numeral'; | |||
import {AudioMiniFilePreview} from '@tesseract-design/web-blob-react'; | |||
import {delegateTriggerChangeEvent} from '@/utils/event'; | |||
export interface FileButtonProps extends Omit<React.HTMLProps<HTMLInputElement>, 'size' | 'type' | 'style' | 'label' | 'list'> { | |||
/** | |||
@@ -71,40 +57,6 @@ const useFilePreviews = (fileList?: FileList) => { | |||
}), [selectedFiles]); | |||
} | |||
const FILE_PREVIEW_COMPONENTS: Record<ContentType, React.ElementType> = { | |||
[ContentType.TEXT]: TextFilePreview, | |||
[ContentType.IMAGE]: ImageFilePreview, | |||
[ContentType.AUDIO]: AudioFilePreview, | |||
[ContentType.VIDEO]: VideoFilePreview, | |||
[ContentType.BINARY]: BinaryFilePreview, | |||
}; | |||
const FilePreview = ({ | |||
fileList: fileList, | |||
}: { fileList?: FileList }) => { | |||
const { files } = useFilePreviews(fileList); | |||
if (files.length < 1) { | |||
return null; | |||
} | |||
const f = files[0]; | |||
const contentType = getContentType(f.type, f.name); | |||
const FilePreviewComponent = FILE_PREVIEW_COMPONENTS[contentType] ?? BinaryFilePreview; | |||
return ( | |||
<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`}> | |||
<FilePreviewComponent | |||
file={f} | |||
/> | |||
</div> | |||
</div> | |||
) | |||
} | |||
const FilePreviewGrid = ({ | |||
fileList, | |||
}: { fileList?: FileList }) => { | |||
@@ -212,10 +164,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||
return ( | |||
<div | |||
className={BlobBase.Root({ | |||
border, | |||
block, | |||
})} | |||
className="block" | |||
onDragEnter={cancelEvent} | |||
onDragOver={cancelEvent} | |||
onDrop={handleDropZone} | |||
@@ -240,12 +189,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||
border && ( | |||
<span | |||
data-testid="border" | |||
className={ | |||
BlobBase.Border({ | |||
border, | |||
block, | |||
}) | |||
} | |||
className="block" | |||
/> | |||
) | |||
} | |||
@@ -255,10 +199,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||
&& ( | |||
<div | |||
data-testid="label" | |||
className={BlobBase.LabelWrapper({ | |||
border, | |||
block, | |||
})} | |||
className="block" | |||
> | |||
{label} | |||
</div> | |||
@@ -298,7 +239,15 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||
{ | |||
!multiple | |||
&& ( | |||
<FilePreview fileList={fileList} /> | |||
<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`}> | |||
<FilePreviewComponent | |||
fileList={fileList} | |||
/> | |||
</div> | |||
</div> | |||
) | |||
} | |||
</div> | |||
@@ -306,15 +255,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||
<div className="pointer-events-none 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"> | |||
<span | |||
className={ButtonBase.Button({ | |||
size: ButtonBase.ButtonSize.MEDIUM, | |||
border: false, | |||
block: true, | |||
variant: ButtonBase.ButtonVariant.OUTLINE, | |||
disabled, | |||
compact: false, | |||
menuItem: false, | |||
})} | |||
className="" | |||
> | |||
Reselect | |||
</span> | |||
@@ -324,15 +265,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||
data-testid="clear" | |||
type="button" | |||
onClick={deleteFiles} | |||
className={ButtonBase.Button({ | |||
size: ButtonBase.ButtonSize.MEDIUM, | |||
border: false, | |||
block: true, | |||
variant: ButtonBase.ButtonVariant.OUTLINE, | |||
disabled, | |||
compact: false, | |||
menuItem: false, | |||
})} | |||
className="" | |||
> | |||
{multiple ? 'Clear' : 'Delete'} | |||
</button> | |||
@@ -347,22 +280,3 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||
); | |||
FileSelectBox.displayName = 'FileSelectBox'; | |||
const BlobReact = { | |||
FileSelectBox | |||
} | |||
const BlobPage: NextPage = () => { | |||
return ( | |||
<BlobReact.FileSelectBox | |||
border | |||
enhanced | |||
label="Primary Image" | |||
hint="Select any files here" | |||
block | |||
onChange={(e) => console.log(e.currentTarget.files)} | |||
/> | |||
) | |||
} | |||
export default BlobPage; |
@@ -1,6 +1,6 @@ | |||
import * as React from 'react'; | |||
import {getMimeTypeDescription, ImageFile} from '../../utils/blob'; | |||
import {formatFileSize, formatNumeral} from '../../utils/numeral'; | |||
import {getMimeTypeDescription, ImageFile} from '@/utils/blob'; | |||
import {formatFileSize, formatNumeral} from '@/utils/numeral'; | |||
export interface ImageFilePreviewProps { | |||
file: ImageFile; |
@@ -1,7 +1,7 @@ | |||
import * as React from 'react'; | |||
import Prism from 'prismjs'; | |||
import {formatFileSize, formatNumeral} from '../../utils/numeral'; | |||
import {TextFile} from '../../utils/blob'; | |||
import {formatFileSize, formatNumeral} from '@/utils/numeral'; | |||
import {TextFile} from '@/utils/blob'; | |||
export interface TextFilePreviewProps { | |||
file: TextFile; |
@@ -1,6 +1,6 @@ | |||
import * as React from 'react'; | |||
import {getMimeTypeDescription, VideoFile} from '../../utils/blob'; | |||
import {formatFileSize, formatNumeral, formatSecondsDurationConcise} from '../../utils/numeral'; | |||
import {getMimeTypeDescription, VideoFile} from '@/utils/blob'; | |||
import {formatFileSize, formatNumeral, formatSecondsDurationConcise} from '@/utils/numeral'; | |||
export interface VideoFilePreviewProps { | |||
file: VideoFile; |
@@ -1,15 +1,12 @@ | |||
import * as React from 'react'; | |||
import WaveSurfer from 'wavesurfer.js'; | |||
import {AudioFile, getMimeTypeDescription} from '../../utils/blob'; | |||
import {formatFileSize, formatNumeral, formatSecondsDurationPrecise} from '../../utils/numeral'; | |||
import {AudioFile} from '@/utils/blob'; | |||
export interface VideoFilePreviewProps { | |||
export interface UseAudioFilePreviewControlsOptions { | |||
file: AudioFile; | |||
} | |||
export const AudioMiniFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||
file: f, | |||
}) => { | |||
export const useAudioFilePreviewControls = ({ file: f }: UseAudioFilePreviewControlsOptions) => { | |||
const mediaContainerRef = React.useRef<HTMLDivElement>(null); | |||
const mediaControllerRef = React.useRef<WaveSurfer>(null); | |||
const [isPlaying, setIsPlaying] = React.useState(false); | |||
@@ -41,10 +38,14 @@ export const AudioMiniFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||
} | |||
mediaContainerRef.current.innerHTML = ''; | |||
if (f.type === 'audio/mid') { | |||
return; | |||
} | |||
const mediaControllerRefMutable = mediaControllerRef as React.MutableRefObject<WaveSurfer>; | |||
mediaControllerRefMutable.current = WaveSurfer.create({ | |||
container: mediaContainerRef.current, | |||
url: f.metadata.previewUrl, | |||
cursorWidth: 0, | |||
height: mediaContainerRef.current.offsetHeight, | |||
barWidth: 2, | |||
@@ -57,6 +58,10 @@ export const AudioMiniFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||
mediaControllerRefMutable.current.seekTo(0); | |||
}); | |||
// TODO get the preview URL here | |||
mediaControllerRefMutable.current.load(f.metadata.previewUrl); | |||
return () => { | |||
if (!mediaControllerRefMutable.current) { | |||
return; | |||
@@ -66,15 +71,17 @@ export const AudioMiniFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||
} | |||
}, [f, mediaContainerRef, mediaControllerRef]); | |||
const playMedia = () => { | |||
const playMedia = React.useCallback(() => { | |||
setIsPlaying((p) => !p); | |||
}; | |||
return ( | |||
<div | |||
className="absolute top-0 left-0 w-full h-full cursor-pointer" | |||
ref={mediaContainerRef} | |||
onClick={playMedia} | |||
/> | |||
); | |||
}, []); | |||
return React.useMemo(() => ({ | |||
mediaContainerRef, | |||
playMedia, | |||
isPlaying, | |||
}), [ | |||
mediaContainerRef, | |||
playMedia, | |||
isPlaying, | |||
]); | |||
}; |
@@ -0,0 +1,8 @@ | |||
export * from './components/AudioFilePreview'; | |||
export * from './components/AudioMiniFilePreview'; | |||
export * from './components/BinaryFilePreview'; | |||
export * from './components/BinaryFilePreview'; | |||
export * from './components/FileSelectBox'; | |||
export * from './components/ImageFilePreview'; | |||
export * from './components/TextFilePreview'; | |||
export * from './components/VideoFilePreview'; |
@@ -0,0 +1,198 @@ | |||
import * as React from 'react'; | |||
import * as TextControlBase from '@tesseract-design/web-base-textcontrol'; | |||
import clsx from 'clsx'; | |||
type MaskedTextInputDerivedElement = HTMLInputElement; | |||
export interface MaskedTextInputProps extends Omit<React.HTMLProps<MaskedTextInputDerivedElement>, 'size' | 'type' | '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, | |||
} | |||
/** | |||
* Component for inputting textual values. | |||
* | |||
* This component supports multiline input and adjusts its layout accordingly. | |||
*/ | |||
export const MaskedTextInput = React.forwardRef<MaskedTextInputDerivedElement, MaskedTextInputProps>( | |||
( | |||
{ | |||
label, | |||
hint, | |||
indicator, | |||
size = 'medium' as const, | |||
border = false, | |||
block = false, | |||
variant = 'default' as const, | |||
hiddenLabel = false, | |||
className, | |||
...etcProps | |||
}: MaskedTextInputProps, | |||
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, | |||
)} | |||
> | |||
<input | |||
{...etcProps} | |||
ref={ref} | |||
aria-labelledby={labelId} | |||
type="password" | |||
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', | |||
}, | |||
)} | |||
/> | |||
{ | |||
label && ( | |||
<div | |||
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', | |||
}, | |||
)} | |||
> | |||
<div className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
{label} | |||
</div> | |||
</div> | |||
) | |||
} | |||
{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> | |||
); | |||
}, | |||
); | |||
MaskedTextInput.displayName = 'MaskedTextInput'; |
@@ -0,0 +1,211 @@ | |||
import * as React from 'react'; | |||
import * as TextControlBase from '@tesseract-design/web-base-textcontrol'; | |||
import clsx from 'clsx'; | |||
type MultilineTextInputDerivedElement = HTMLTextAreaElement; | |||
export interface MultilineTextInputProps extends Omit<React.HTMLProps<MultilineTextInputDerivedElement>, '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, | |||
} | |||
/** | |||
* Component for inputting textual values. | |||
* | |||
* This component supports multiline input and adjusts its layout accordingly. | |||
*/ | |||
export const MultilineTextInput = React.forwardRef<MultilineTextInputDerivedElement, MultilineTextInputProps>( | |||
( | |||
{ | |||
label, | |||
hint, | |||
indicator, | |||
size = 'medium' as const, | |||
border = false, | |||
block = false, | |||
variant = 'default' as const, | |||
hiddenLabel = false, | |||
className, | |||
...etcProps | |||
}: MultilineTextInputProps, | |||
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, | |||
)} | |||
> | |||
<textarea | |||
{...etcProps} | |||
ref={ref} | |||
aria-labelledby={labelId} | |||
data-testid="input" | |||
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 && ( | |||
<div | |||
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', | |||
}, | |||
)} | |||
> | |||
<div className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
{label} | |||
</div> | |||
</div> | |||
) | |||
} | |||
{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> | |||
); | |||
} | |||
); | |||
MultilineTextInput.displayName = 'MultilineTextInput'; |
@@ -0,0 +1,203 @@ | |||
import * as React from 'react'; | |||
import * as TextControlBase from '@tesseract-design/web-base-textcontrol'; | |||
import clsx from 'clsx'; | |||
type TextInputDerivedElement = HTMLInputElement; | |||
export interface TextInputProps extends Omit<React.HTMLProps<TextInputDerivedElement>, 'size' | 'type' | 'style' | 'label' | 'list'> { | |||
/** | |||
* 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, | |||
/** | |||
* Type of the component value. | |||
*/ | |||
type?: TextControlBase.TextControlInputType, | |||
/** | |||
* Style of the component. | |||
*/ | |||
variant?: TextControlBase.TextControlVariant, | |||
/** | |||
* Is the label hidden? | |||
*/ | |||
hiddenLabel?: boolean, | |||
} | |||
/** | |||
* Component for inputting textual values. | |||
* | |||
* This component supports multiline input and adjusts its layout accordingly. | |||
*/ | |||
export const TextInput = React.forwardRef<TextInputDerivedElement, TextInputProps>( | |||
( | |||
{ | |||
label = '', | |||
hint = '', | |||
indicator, | |||
size = 'medium' as const, | |||
border = false, | |||
block = false, | |||
type = 'text' as const, | |||
variant = 'default' as const, | |||
hiddenLabel = false, | |||
className, | |||
...etcProps | |||
}: TextInputProps, | |||
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, | |||
)} | |||
> | |||
<input | |||
{...etcProps} | |||
ref={ref} | |||
aria-labelledby={labelId} | |||
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', | |||
}, | |||
)} | |||
/> | |||
{ | |||
label && ( | |||
<div | |||
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', | |||
}, | |||
)} | |||
> | |||
<div className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
{label} | |||
</div> | |||
</div> | |||
) | |||
} | |||
{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> | |||
); | |||
} | |||
); | |||
TextInput.displayName = 'TextInput'; |
@@ -0,0 +1,35 @@ | |||
import * as React from 'react'; | |||
import clsx from 'clsx'; | |||
type BadgeDerivedElement = HTMLSpanElement; | |||
export interface BadgeProps extends React.HTMLProps<BadgeDerivedElement> { | |||
rounded?: boolean; | |||
} | |||
export const Badge = React.forwardRef<BadgeDerivedElement, BadgeProps>(({ | |||
children, | |||
rounded = false, | |||
className, | |||
...etcProps | |||
}, forwardedRef) => ( | |||
<span | |||
{...etcProps} | |||
ref={forwardedRef} | |||
className={clsx( | |||
'relative h-6 min-w-6 flex items-center justify-center text-xs font-bold overflow-hidden font-semi-expanded', | |||
'before:absolute before:top-0 before:left-0 before:w-full before:h-full before:bg-current before:opacity-25', | |||
{ | |||
'rounded-full px-2': rounded, | |||
'rounded px-1': !rounded, | |||
}, | |||
className, | |||
)} | |||
> | |||
<span className="relative w-full"> | |||
{children} | |||
</span> | |||
</span> | |||
)); | |||
Badge.displayName = 'Badge'; |
@@ -0,0 +1,108 @@ | |||
import * as React from 'react'; | |||
import clsx from 'clsx'; | |||
import * as ButtonBase from '@tesseract-design/web-base-button'; | |||
type LinkButtonDerivedElement = HTMLAnchorElement; | |||
export interface LinkButtonProps extends Omit<React.HTMLProps<LinkButtonDerivedElement>, 'size'> { | |||
block?: boolean; | |||
variant: ButtonBase.ButtonVariant; | |||
subtext?: React.ReactNode; | |||
badge?: React.ReactNode; | |||
menuItem?: boolean; | |||
size?: ButtonBase.ButtonSize; | |||
compact?: boolean; | |||
component?: React.ElementType; | |||
} | |||
export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonProps>(({ | |||
variant, | |||
subtext, | |||
badge, | |||
menuItem = false, | |||
children, | |||
size = 'medium' as const, | |||
compact = false, | |||
className, | |||
block = false, | |||
component: Component = 'a', | |||
...etcProps | |||
}, forwardedRef) => ( | |||
<Component | |||
{...etcProps} | |||
ref={forwardedRef} | |||
className={clsx( | |||
'items-center justify-center rounded overflow-hidden ring-secondary/50 leading-none gap-4 select-none', | |||
'focus:outline-0 focus:ring-4', | |||
'active:ring-tertiary/50', | |||
{ | |||
'flex w-full': block, | |||
'inline-flex max-w-full align-middle': !block, | |||
}, | |||
{ | |||
'pl-2': compact, | |||
'pl-4': !compact, | |||
'pr-4': !(compact || menuItem), | |||
'pr-2': compact || menuItem, | |||
}, | |||
{ | |||
'border-2 border-primary focus:border-secondary active:border-tertiary' : variant !== 'bare', | |||
'bg-negative text-primary focus:text-secondary active:text-tertiary': variant !== 'filled', | |||
'bg-primary text-negative focus:bg-secondary active:bg-tertiary': variant === 'filled', | |||
}, | |||
{ | |||
'h-10': size === 'small', | |||
'h-12': size === 'medium', | |||
'h-16': size === 'large', | |||
}, | |||
className, | |||
)} | |||
> | |||
<span | |||
className={clsx( | |||
'flex-auto min-w-0', | |||
{ | |||
'text-left': compact || menuItem, | |||
'text-center': !(compact || menuItem), | |||
}, | |||
)} | |||
> | |||
<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="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> | |||
)} | |||
{menuItem && ( | |||
<span | |||
data-testid="menuItemIndicator" | |||
> | |||
<svg | |||
className="w-6 h-6 fill-none stroke-current stroke-2 linejoin-round linecap-round" | |||
viewBox="0 0 24 24" | |||
role="presentation" | |||
> | |||
<polyline points="9 18 15 12 9 6"/> | |||
</svg> | |||
</span> | |||
)} | |||
</Component> | |||
)); | |||
LinkButton.displayName = 'LinkButton'; |
@@ -0,0 +1,5 @@ | |||
export const DropdownSelect = () => { | |||
return ( | |||
<select /> | |||
) | |||
}; |
@@ -0,0 +1 @@ | |||
export * from './components/DropdownSelect'; |
@@ -25,7 +25,9 @@ export const DefaultLayout: FC<DefaultLayoutProps> = ({ | |||
) | |||
} | |||
</Head> | |||
{children} | |||
<main className="mt-8 mb-16 md:mt-16 md:mb-32"> | |||
{children} | |||
</main> | |||
</> | |||
) | |||
} |
@@ -0,0 +1,25 @@ | |||
export const Section = ({ children, title }) => ( | |||
<section> | |||
<div className="container mx-auto px-4"> | |||
<h1> | |||
{title} | |||
</h1> | |||
<div> | |||
{children} | |||
</div> | |||
</div> | |||
</section> | |||
); | |||
export const Subsection = ({ children, title }) => ( | |||
<section> | |||
<div> | |||
<h2> | |||
{title} | |||
</h2> | |||
<div> | |||
{children} | |||
</div> | |||
</div> | |||
</section> | |||
); |
@@ -0,0 +1,11 @@ | |||
import '@/styles/globals.css' | |||
import '@/styles/kitchen-sink.css' | |||
import type { AppProps } from 'next/app' | |||
const App = ({ Component, pageProps }: AppProps) => { | |||
return ( | |||
<Component {...pageProps} /> | |||
); | |||
}; | |||
export default App; |
@@ -0,0 +1,13 @@ | |||
import { Html, Head, Main, NextScript } from 'next/document' | |||
export default function Document() { | |||
return ( | |||
<Html lang="en" className="bg-negative text-positive"> | |||
<Head /> | |||
<body> | |||
<Main /> | |||
<NextScript /> | |||
</body> | |||
</Html> | |||
) | |||
} |
@@ -0,0 +1,13 @@ | |||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction | |||
import type { NextApiRequest, NextApiResponse } from 'next' | |||
type Data = { | |||
name: string | |||
} | |||
export default function handler( | |||
req: NextApiRequest, | |||
res: NextApiResponse<Data> | |||
) { | |||
res.status(200).json({ name: 'John Doe' }) | |||
} |
@@ -1,7 +1,7 @@ | |||
import { NextPage } from 'next'; | |||
import { ButtonSize, ButtonVariant } from '@tesseract-design/web-base-button'; | |||
import * as Action from '@tesseract-design/web-action-react'; | |||
import { DefaultLayout } from 'src/components/DefaultLayout'; | |||
import { DefaultLayout } from '@/components/DefaultLayout'; | |||
const ActionPage: NextPage = () => { | |||
return ( | |||
@@ -21,6 +21,7 @@ const ActionPage: NextPage = () => { | |||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 my-4"> | |||
<div> | |||
<Action.ActionButton | |||
variant="bare" | |||
block | |||
> | |||
Button | |||
@@ -28,7 +29,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
> | |||
Button | |||
@@ -36,7 +37,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
border | |||
variant="outline" | |||
block | |||
> | |||
Button | |||
@@ -44,8 +45,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
> | |||
Button | |||
@@ -53,6 +53,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
variant="bare" | |||
block | |||
disabled | |||
> | |||
@@ -61,7 +62,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
disabled | |||
> | |||
@@ -70,7 +71,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
border | |||
variant="outline" | |||
block | |||
disabled | |||
> | |||
@@ -79,8 +80,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
disabled | |||
> | |||
@@ -97,8 +97,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Action.ActionButton | |||
block | |||
border | |||
size={ButtonSize.SMALL} | |||
variant="outline" | |||
size="small" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
@@ -106,9 +106,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Action.ActionButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.SMALL} | |||
variant="filled" | |||
size="small" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
@@ -116,8 +115,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Action.ActionButton | |||
block | |||
border | |||
size={ButtonSize.MEDIUM} | |||
variant="outline" | |||
size="medium" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
@@ -125,9 +124,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Action.ActionButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.MEDIUM} | |||
variant="filled" | |||
size="medium" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
@@ -135,8 +133,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Action.ActionButton | |||
block | |||
border | |||
size={ButtonSize.LARGE} | |||
variant="outline" | |||
size="large" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
@@ -144,9 +142,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Action.ActionButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.LARGE} | |||
variant="filled" | |||
size="large" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
@@ -162,7 +159,7 @@ const ActionPage: NextPage = () => { | |||
<Action.ActionButton | |||
block | |||
compact | |||
border | |||
variant="outline" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
@@ -171,8 +168,7 @@ const ActionPage: NextPage = () => { | |||
<Action.ActionButton | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
@@ -181,7 +177,7 @@ const ActionPage: NextPage = () => { | |||
<Action.ActionButton | |||
block | |||
compact | |||
border | |||
variant="outline" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -195,8 +191,7 @@ const ActionPage: NextPage = () => { | |||
<Action.ActionButton | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -210,8 +205,8 @@ const ActionPage: NextPage = () => { | |||
<Action.ActionButton | |||
block | |||
compact | |||
border | |||
size={ButtonSize.SMALL} | |||
variant="outline" | |||
size="small" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -225,9 +220,8 @@ const ActionPage: NextPage = () => { | |||
<Action.ActionButton | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.SMALL} | |||
variant="filled" | |||
size="small" | |||
subtext={ | |||
<> | |||
Very Long Line of Subtext That Spans More Than The Component Width For Testing Overflow |
@@ -0,0 +1,18 @@ | |||
import {NextPage} from 'next'; | |||
import * as React from 'react'; | |||
import * as BlobReact from '@tesseract-design/web-blob-react'; | |||
const BlobPage: NextPage = () => { | |||
return ( | |||
<BlobReact.FileSelectBox | |||
border | |||
enhanced | |||
label="Primary Image" | |||
hint="Select any files here" | |||
block | |||
onChange={(e) => console.log(e.currentTarget.files)} | |||
/> | |||
) | |||
} | |||
export default BlobPage; |
@@ -1,5 +1,5 @@ | |||
import { NextPage } from 'next'; | |||
import { DefaultLayout } from 'src/components/DefaultLayout'; | |||
import { DefaultLayout } from '@/components/DefaultLayout'; | |||
const CodePage: NextPage = () => { | |||
return ( |
@@ -0,0 +1,617 @@ | |||
import { NextPage } from 'next'; | |||
import * as Freeform from '@tesseract-design/web-freeform-react'; | |||
import { DefaultLayout } from '@/components/DefaultLayout'; | |||
import { Section, Subsection } from '@/components/Section'; | |||
const FreeformPage: NextPage = () => { | |||
return ( | |||
<DefaultLayout title="Freeform"> | |||
<Section title="TextInput"> | |||
<Subsection title="Default"> | |||
<div className="grid md:grid-cols-2 gap-4 my-4"> | |||
<div> | |||
<Freeform.TextInput | |||
size="small" | |||
label="TextInput ffgg" | |||
hint="Type anything here… ffgg" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
border | |||
size="small" | |||
label="TextInput ffgg" | |||
hint="Type anything here… ffgg" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
label="TextInput ffgg" | |||
hint="Type anything here… ffgg" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
border | |||
label="TextInput ffgg" | |||
hint="Type anything here… ffgg" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
size="large" | |||
label="TextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
border | |||
size="large" | |||
label="TextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
label="TextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
border | |||
label="TextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
</div> | |||
<form> | |||
<fieldset className="contents"> | |||
<legend className="sr-only">Fieldset Test</legend> | |||
<div className="grid grid-cols-6 gap-4 my-4"> | |||
<div className="col-span-2"> | |||
<Freeform.TextInput | |||
label="First Name" | |||
block | |||
border | |||
/> | |||
</div> | |||
<div className="col-span-2"> | |||
<Freeform.TextInput | |||
label="Middle Name" | |||
block | |||
border | |||
/> | |||
</div> | |||
<div className="col-span-2"> | |||
<Freeform.TextInput | |||
label="Last Name" | |||
block | |||
border | |||
/> | |||
</div> | |||
<div className="col-span-3"> | |||
<Freeform.TextInput | |||
label="Username" | |||
block | |||
border | |||
/> | |||
</div> | |||
<div className="col-span-3"> | |||
<Freeform.TextInput | |||
label="Title" | |||
block | |||
border | |||
disabled | |||
/> | |||
</div> | |||
</div> | |||
</fieldset> | |||
</form> | |||
<form> | |||
<fieldset | |||
disabled | |||
className="contents" | |||
> | |||
<legend className="sr-only">Disabled Test</legend> | |||
<div className="grid grid-cols-6 gap-4 my-4"> | |||
<div className="col-span-2"> | |||
<Freeform.TextInput | |||
label="First Name" | |||
block | |||
border | |||
/> | |||
</div> | |||
<div className="col-span-2"> | |||
<Freeform.TextInput | |||
label="Middle Name" | |||
block | |||
border | |||
/> | |||
</div> | |||
<div className="col-span-2"> | |||
<Freeform.TextInput | |||
label="Last Name" | |||
block | |||
border | |||
/> | |||
</div> | |||
<div className="col-span-3"> | |||
<Freeform.TextInput | |||
label="Username" | |||
block | |||
border | |||
/> | |||
</div> | |||
<div className="col-span-3"> | |||
<Freeform.TextInput | |||
label="Title" | |||
block | |||
border | |||
/> | |||
</div> | |||
</div> | |||
</fieldset> | |||
</form> | |||
<form> | |||
<div> | |||
Hi, my name is | |||
{' '} | |||
<Freeform.TextInput | |||
border | |||
label="Name" | |||
size="small" | |||
/> | |||
{' '} | |||
but you can call me | |||
{' '} | |||
<Freeform.TextInput | |||
border | |||
label="Nickname" | |||
size="small" | |||
/> | |||
. | |||
</div> | |||
</form> | |||
</Subsection> | |||
<Subsection title="Alternate"> | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Freeform.TextInput | |||
variant="alternate" | |||
size="small" | |||
label="TextInput ffgg" | |||
hint="Type anything here… ffgg" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
border | |||
variant="alternate" | |||
size="small" | |||
label="TextInput ffgg" | |||
hint="Type anything here… ffgg" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
variant="alternate" | |||
label="TextInput ffgg" | |||
hint="Type anything here… ffgg" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
border | |||
variant="alternate" | |||
label="TextInput ffgg" | |||
hint="Type anything here… ffgg" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
variant="alternate" | |||
size="large" | |||
label="TextInput ffgg" | |||
hint="Type anything here… ffgg" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
border | |||
block | |||
variant="alternate" | |||
size="large" | |||
label="TextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
variant="alternate" | |||
label="TextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.TextInput | |||
variant="alternate" | |||
border | |||
label="TextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
</div> | |||
</Subsection> | |||
</Section> | |||
<Section title="MaskedTextInput"> | |||
<Subsection title="Default"> | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
size="small" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
size="small" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
size="large" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
size="large" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
</div> | |||
</Subsection> | |||
<Subsection title="Alternate"> | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
variant="alternate" | |||
size="small" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
variant="alternate" | |||
size="small" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
variant="alternate" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
variant="alternate" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
variant="alternate" | |||
size="large" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
block | |||
variant="alternate" | |||
size="large" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
variant="alternate" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
variant="alternate" | |||
border | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
</div> | |||
</Subsection> | |||
</Section> | |||
<Section title="MultilineTextInput"> | |||
<Subsection title="Default"> | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
border | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
border | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
border | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
border | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
</div> | |||
</Subsection> | |||
<Subsection title="Alternate"> | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
variant="alternate" | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
border | |||
variant="alternate" | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
border | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
variant="alternate" | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
border | |||
block | |||
variant="alternate" | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MultilineTextInput | |||
variant="alternate" | |||
border | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
</div> | |||
</Subsection> | |||
</Section> | |||
</DefaultLayout> | |||
); | |||
}; | |||
export default FreeformPage; |
@@ -23,15 +23,16 @@ const ActionPage: NextPage = () => { | |||
<div className="grid md:grid-cols-2 gap-4 my-4"> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="bare" | |||
href="#" | |||
block | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
href="#" | |||
> | |||
@@ -40,7 +41,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
border | |||
variant="outline" | |||
block | |||
href="#" | |||
> | |||
@@ -49,8 +50,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
href="#" | |||
> | |||
@@ -62,13 +62,14 @@ const ActionPage: NextPage = () => { | |||
block | |||
disabled | |||
href="#" | |||
variant="bare" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
disabled | |||
href="#" | |||
@@ -78,7 +79,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
border | |||
variant="outline" | |||
block | |||
disabled | |||
href="#" | |||
@@ -88,8 +89,7 @@ const ActionPage: NextPage = () => { | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
disabled | |||
href="#" | |||
@@ -107,8 +107,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
size={ButtonSize.SMALL} | |||
variant="outline" | |||
size="small" | |||
href="#" | |||
> | |||
Button | |||
@@ -117,9 +117,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.SMALL} | |||
variant="filled" | |||
size="small" | |||
href="#" | |||
> | |||
Button | |||
@@ -128,8 +127,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
size={ButtonSize.MEDIUM} | |||
variant="outline" | |||
size="medium" | |||
href="#" | |||
> | |||
Button | |||
@@ -138,9 +137,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.MEDIUM} | |||
variant="filled" | |||
size="medium" | |||
href="#" | |||
> | |||
Button | |||
@@ -149,8 +147,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
size={ButtonSize.LARGE} | |||
variant="outline" | |||
size="large" | |||
href="#" | |||
> | |||
Button | |||
@@ -159,9 +157,8 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.LARGE} | |||
variant="filled" | |||
size="large" | |||
href="#" | |||
> | |||
Button | |||
@@ -178,7 +175,7 @@ const ActionPage: NextPage = () => { | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
border | |||
variant="outline" | |||
href="#" | |||
> | |||
Button | |||
@@ -188,8 +185,7 @@ const ActionPage: NextPage = () => { | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
href="#" | |||
> | |||
Button | |||
@@ -198,7 +194,7 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
variant="outline" | |||
compact | |||
subtext={ | |||
<> | |||
@@ -214,8 +210,7 @@ const ActionPage: NextPage = () => { | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -229,9 +224,9 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
variant="outline" | |||
compact | |||
size={ButtonSize.SMALL} | |||
size="small" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -253,9 +248,8 @@ const ActionPage: NextPage = () => { | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.SMALL} | |||
variant="filled" | |||
size="small" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -276,9 +270,9 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
variant="outline" | |||
compact | |||
size={ButtonSize.LARGE} | |||
size="large" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -300,9 +294,8 @@ const ActionPage: NextPage = () => { | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.LARGE} | |||
variant="filled" | |||
size="large" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -323,10 +316,10 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
variant="outline" | |||
compact | |||
menuItem | |||
size={ButtonSize.SMALL} | |||
size="small" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -348,9 +341,8 @@ const ActionPage: NextPage = () => { | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
border | |||
size={ButtonSize.SMALL} | |||
variant={ButtonVariant.FILLED} | |||
size="small" | |||
variant="filled" | |||
menuItem | |||
subtext={ | |||
<> | |||
@@ -372,7 +364,7 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
variant="outline" | |||
compact | |||
menuItem | |||
subtext={ | |||
@@ -396,8 +388,7 @@ const ActionPage: NextPage = () => { | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
menuItem | |||
subtext={ | |||
<> | |||
@@ -419,10 +410,10 @@ const ActionPage: NextPage = () => { | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
variant="outline" | |||
compact | |||
menuItem | |||
size={ButtonSize.LARGE} | |||
size="large" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -444,9 +435,8 @@ const ActionPage: NextPage = () => { | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
border | |||
size={ButtonSize.LARGE} | |||
variant={ButtonVariant.FILLED} | |||
size="large" | |||
variant="filled" | |||
menuItem | |||
subtext={ | |||
<> |
@@ -1,9 +1,9 @@ | |||
import { NextPage } from 'next'; | |||
import { TextControlSize, TextControlStyle } from '@tesseract-design/web-base-textcontrol'; | |||
import { TextControlSize, TextControlVariant } from '@tesseract-design/web-base-textcontrol'; | |||
import * as Option from '@tesseract-design/web-option-react'; | |||
import * as SelectControlBase from '@tesseract-design/web-base-selectcontrol'; | |||
import { ButtonSize, ButtonVariant } from '@tesseract-design/web-base-button'; | |||
import { DefaultLayout } from 'src/components/DefaultLayout'; | |||
import { DefaultLayout } from '@/components/DefaultLayout'; | |||
type Props = { | |||
options: SelectControlBase.SelectOption[], | |||
@@ -216,7 +216,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.DropdownSelect | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
label="Select" | |||
hint="Type anything here…" | |||
@@ -227,7 +227,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.DropdownSelect | |||
border | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
label="Select" | |||
hint="Type anything here…" | |||
@@ -237,7 +237,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.DropdownSelect | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -247,7 +247,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.DropdownSelect | |||
border | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -256,7 +256,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.DropdownSelect | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
label="Select" | |||
hint="Type anything here…" | |||
@@ -268,7 +268,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.DropdownSelect | |||
border | |||
block | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
label="Select" | |||
hint="Type anything here…" | |||
@@ -277,7 +277,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.DropdownSelect | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -287,7 +287,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.DropdownSelect | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
border | |||
label="Select" | |||
hint="Type anything here…" | |||
@@ -405,7 +405,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.MenuSelect | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -417,7 +417,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.MenuSelect | |||
border | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -428,7 +428,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.MenuSelect | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -439,7 +439,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.MenuSelect | |||
border | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -449,7 +449,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.MenuSelect | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -462,7 +462,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.MenuSelect | |||
border | |||
block | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -472,7 +472,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.MenuSelect | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -483,7 +483,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.MenuSelect | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
border | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -976,7 +976,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
label="TagInput" | |||
hint="Type anything here…" | |||
@@ -988,7 +988,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.TagInput | |||
enhanced | |||
border | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
label="TagInput" | |||
hint="Type anything here…" | |||
@@ -999,7 +999,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1010,7 +1010,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.TagInput | |||
enhanced | |||
border | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1020,7 +1020,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
label="TagInput" | |||
hint="Type anything here…" | |||
@@ -1033,7 +1033,7 @@ const OptionPage: NextPage<Props> = ({ | |||
enhanced | |||
border | |||
block | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
label="TagInput" | |||
hint="Type anything here…" | |||
@@ -1043,7 +1043,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1054,7 +1054,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
border | |||
label="TagInput" | |||
hint="Type anything here…" | |||
@@ -1511,7 +1511,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.ComboBox | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -1523,7 +1523,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.ComboBox | |||
border | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -1534,7 +1534,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ComboBox | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1545,7 +1545,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.ComboBox | |||
border | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1555,7 +1555,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ComboBox | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -1568,7 +1568,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.ComboBox | |||
border | |||
block | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -1578,7 +1578,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ComboBox | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1589,7 +1589,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ComboBox | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
border | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -1700,7 +1700,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.TagInput | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -1711,7 +1711,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
border | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -1721,7 +1721,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.TagInput | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1731,7 +1731,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
border | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1740,7 +1740,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.TagInput | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -1752,7 +1752,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.TagInput | |||
border | |||
block | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -1761,7 +1761,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.TagInput | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1771,7 +1771,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.TagInput | |||
style={TextControlStyle.ALTERNATE} | |||
style={TextControlVariant.ALTERNATE} | |||
border | |||
label="MultilineTextInput" | |||
hint="Type anything here…" |
@@ -69,10 +69,9 @@ const RegistrationFormPage: NextPage = () => { | |||
{' '} | |||
<div> | |||
<Action.ActionButton | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
border | |||
type={Action.ActionButtonType.SUBMIT} | |||
type="submit" | |||
menuItem | |||
subtext="Registration requires activation" | |||
> |
@@ -21,18 +21,15 @@ const createPageLink = (p: Page) => ( | |||
<div | |||
key={p.id} | |||
> | |||
<Link | |||
<Navigation.LinkButton | |||
block | |||
variant="outline" | |||
menuItem | |||
component={Link} | |||
href={p.href} | |||
passHref | |||
> | |||
<Navigation.LinkButton | |||
block | |||
border | |||
menuItem | |||
> | |||
{p.label} | |||
</Navigation.LinkButton> | |||
</Link> | |||
{p.label} | |||
</Navigation.LinkButton> | |||
</div> | |||
) | |||
@@ -0,0 +1,41 @@ | |||
@tailwind base; | |||
@tailwind utilities; | |||
@layer base { | |||
:root { | |||
--color-shade: 0 0 0; | |||
--color-negative: 34 34 34; | |||
--color-positive: 238 238 238; | |||
--color-primary: 199 138 179; | |||
--color-secondary: 255 153 0; | |||
--color-tertiary: 215 95 75; | |||
--color-code-number: 116 249 94; | |||
--color-code-keyword: 255 67 137; | |||
--color-code-type: 80 151 210; | |||
--color-code-instance-attribute: 118 167 210; | |||
--color-code-function: 103 194 82; | |||
--color-code-parameter: 145 94 194; | |||
--color-code-property: 255 161 201; | |||
--color-code-string: 238 211 113; | |||
--color-code-variable: 139 194 117; | |||
--color-code-regexp: 116 167 43; | |||
--color-code-url: 0 153 204; | |||
--color-code-global: 194 128 80; | |||
} | |||
} | |||
.font-condensed { | |||
font-stretch: condensed; | |||
} | |||
.font-semi-condensed { | |||
font-stretch: semi-condensed; | |||
} | |||
.font-expanded { | |||
font-stretch: expanded; | |||
} | |||
.font-semi-expanded { | |||
font-stretch: semi-expanded; | |||
} |
@@ -0,0 +1,54 @@ | |||
/** @type {import('tailwindcss').Config} */ | |||
module.exports = { | |||
content: [ | |||
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}', | |||
'./src/components/**/*.{js,ts,jsx,tsx,mdx}', | |||
'./src/categories/**/*.{js,ts,jsx,tsx,mdx}', | |||
], | |||
theme: { | |||
fontFamily: { | |||
sans: ['Encode Sans Semi Expanded', 'Encode Sans', 'sans-serif'], | |||
}, | |||
colors: { | |||
'shade': 'rgb(var(--color-shade))', | |||
'negative': 'rgb(var(--color-negative))', | |||
'positive': 'rgb(var(--color-positive))', | |||
'primary': 'rgb(var(--color-primary))', | |||
'secondary': 'rgb(var(--color-secondary))', | |||
'tertiary': 'rgb(var(--color-tertiary))', | |||
'code-number': 'rgb(var(--color-code-number))', | |||
'code-keyword': 'rgb(var(--color-code-keyword))', | |||
'code-type': 'rgb(var(--color-code-type))', | |||
'code-instance-attribute': 'rgb(var(--color-code-instance-attribute))', | |||
'code-function': 'rgb(var(--color-code-function))', | |||
'code-parameter': 'rgb(var(--color-code-parameter))', | |||
'code-property': 'rgb(var(--color-code-property))', | |||
'code-string': 'rgb(var(--color-code-string))', | |||
'code-variable': 'rgb(var(--color-code-variable))', | |||
'code-regexp': 'rgb(var(--color-code-regexp))', | |||
'code-url': 'rgb(var(--color-code-url))', | |||
'code-global': 'rgb(var(--color-code-global))', | |||
'current': 'currentcolor', | |||
}, | |||
extend: { | |||
fontSize: { | |||
'xxs': '0.625rem', | |||
}, | |||
borderRadius: { | |||
inherit: 'inherit', | |||
}, | |||
minWidth: { | |||
6: '1.5rem', | |||
10: '2.5rem', | |||
12: '3rem', | |||
16: '4rem', | |||
}, | |||
minHeight: { | |||
10: '2.5rem', | |||
12: '3rem', | |||
16: '4rem', | |||
}, | |||
}, | |||
}, | |||
plugins: [], | |||
} |
@@ -0,0 +1,32 @@ | |||
{ | |||
"compilerOptions": { | |||
"target": "es5", | |||
"lib": ["dom", "dom.iterable", "esnext"], | |||
"allowJs": true, | |||
"skipLibCheck": true, | |||
"strict": true, | |||
"forceConsistentCasingInFileNames": true, | |||
"noEmit": true, | |||
"esModuleInterop": true, | |||
"module": "esnext", | |||
"moduleResolution": "node", | |||
"resolveJsonModule": true, | |||
"isolatedModules": true, | |||
"jsx": "preserve", | |||
"incremental": true, | |||
"paths": { | |||
"@/*": ["./src/*"], | |||
"@tesseract-design/web-base-button": ["./src/base/button"], | |||
"@tesseract-design/web-base-selectcontrol": ["./src/base/selectcontrol"], | |||
"@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-freeform-react": ["./src/categories/freeform/react"], | |||
"@tesseract-design/web-information-react": ["./src/categories/information/react"], | |||
"@tesseract-design/web-option-react": ["./src/categories/option/react"], | |||
"@tesseract-design/web-navigation-react": ["./src/categories/navigation/react"], | |||
} | |||
}, | |||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], | |||
"exclude": ["node_modules"] | |||
} |
@@ -1,71 +0,0 @@ | |||
{ | |||
"name": "@tesseract-design/web-base-badge", | |||
"version": "0.0.0", | |||
"files": [ | |||
"dist", | |||
"src" | |||
], | |||
"engines": { | |||
"node": ">=10" | |||
}, | |||
"license": "MIT", | |||
"keywords": [ | |||
"pridepack" | |||
], | |||
"devDependencies": { | |||
"@types/node": "^18.0.0", | |||
"@types/react": "^18.2.6", | |||
"csstype": "^3.1.2", | |||
"eslint": "^8.20.0", | |||
"eslint-config-lxsmnsyc": "^0.4.7", | |||
"pridepack": "2.4.4", | |||
"tslib": "^2.4.0", | |||
"typescript": "^4.7.4", | |||
"vitest": "^0.19.1" | |||
}, | |||
"dependencies": { | |||
"@tesseract-design/goofy-goober": "link:../../../../../goofy-goober" | |||
}, | |||
"scripts": { | |||
"prepublishOnly": "pridepack clean && pridepack build", | |||
"build": "pridepack build", | |||
"type-check": "pridepack check", | |||
"lint": "pridepack lint", | |||
"clean": "pridepack clean", | |||
"watch": "pridepack watch", | |||
"start": "pridepack start", | |||
"dev": "pridepack dev", | |||
"test": "vitest" | |||
}, | |||
"private": true, | |||
"description": "Base badge styles for Tesseract.", | |||
"repository": { | |||
"url": "", | |||
"type": "git" | |||
}, | |||
"homepage": "", | |||
"bugs": { | |||
"url": "" | |||
}, | |||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | |||
"publishConfig": { | |||
"access": "restricted" | |||
}, | |||
"types": "./dist/types/index.d.ts", | |||
"exports": { | |||
".": { | |||
"development": { | |||
"require": "./dist/cjs/development/index.js", | |||
"import": "./dist/esm/development/index.js" | |||
}, | |||
"require": "./dist/cjs/production/index.js", | |||
"import": "./dist/esm/production/index.js", | |||
"types": "./dist/types/index.d.ts" | |||
} | |||
}, | |||
"typesVersions": { | |||
"*": {} | |||
}, | |||
"main": "./dist/cjs/production/index.js", | |||
"module": "./dist/esm/production/index.js" | |||
} |
@@ -1,3 +0,0 @@ | |||
{ | |||
"target": "es2017" | |||
} |
@@ -1,45 +0,0 @@ | |||
import { css } from '@tesseract-design/goofy-goober'; | |||
export type BadgeBaseArgs = { | |||
/** | |||
* Will the component be displayed with circular sides? | |||
*/ | |||
rounded: boolean, | |||
} | |||
export const Root = ({ | |||
rounded, | |||
}: BadgeBaseArgs) => css.cx( | |||
css` | |||
position: relative; | |||
height: 1.5em; | |||
min-width: 1.5em; | |||
display: inline-grid; | |||
vertical-align: middle; | |||
place-content: center; | |||
overflow: hidden; | |||
font-stretch: var(--font-stretch-base, normal); | |||
padding: 0 0.25rem; | |||
box-sizing: border-box; | |||
&::before { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
background-color: currentColor; | |||
opacity: 0.25; | |||
content: ''; | |||
} | |||
`, | |||
css.dynamic({ | |||
'border-radius': rounded ? '0.75em' : '0.25rem', | |||
}), | |||
); | |||
export const Content = () => css.cx( | |||
css` | |||
position: relative; | |||
font-size: 0.75em; | |||
` | |||
); |
@@ -1,9 +0,0 @@ | |||
{ | |||
"exclude": ["node_modules"], | |||
"extends": "../../../../tsconfig.json", | |||
"compilerOptions": { | |||
"rootDir": "src", | |||
"emitDeclarationOnly": true, | |||
"declaration": true | |||
} | |||
} |
@@ -1,71 +0,0 @@ | |||
{ | |||
"name": "@tesseract-design/web-base-blob", | |||
"version": "0.0.0", | |||
"files": [ | |||
"dist", | |||
"src" | |||
], | |||
"engines": { | |||
"node": ">=10" | |||
}, | |||
"license": "MIT", | |||
"keywords": [ | |||
"pridepack" | |||
], | |||
"devDependencies": { | |||
"@types/node": "^18.0.0", | |||
"@types/react": "^18.2.6", | |||
"csstype": "^3.1.2", | |||
"eslint": "^8.20.0", | |||
"eslint-config-lxsmnsyc": "^0.4.7", | |||
"pridepack": "2.4.4", | |||
"tslib": "^2.4.0", | |||
"typescript": "^4.7.4", | |||
"vitest": "^0.19.1" | |||
}, | |||
"dependencies": { | |||
"@tesseract-design/goofy-goober": "link:../../../../../goofy-goober" | |||
}, | |||
"scripts": { | |||
"prepublishOnly": "pridepack clean && pridepack build", | |||
"build": "pridepack build", | |||
"type-check": "pridepack check", | |||
"lint": "pridepack lint", | |||
"clean": "pridepack clean", | |||
"watch": "pridepack watch", | |||
"start": "pridepack start", | |||
"dev": "pridepack dev", | |||
"test": "vitest" | |||
}, | |||
"private": true, | |||
"description": "Base badge styles for Tesseract.", | |||
"repository": { | |||
"url": "", | |||
"type": "git" | |||
}, | |||
"homepage": "", | |||
"bugs": { | |||
"url": "" | |||
}, | |||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | |||
"publishConfig": { | |||
"access": "restricted" | |||
}, | |||
"types": "./dist/types/index.d.ts", | |||
"exports": { | |||
".": { | |||
"development": { | |||
"require": "./dist/cjs/development/index.js", | |||
"import": "./dist/esm/development/index.js" | |||
}, | |||
"require": "./dist/cjs/production/index.js", | |||
"import": "./dist/esm/production/index.js", | |||
"types": "./dist/types/index.d.ts" | |||
} | |||
}, | |||
"typesVersions": { | |||
"*": {} | |||
}, | |||
"main": "./dist/cjs/production/index.js", | |||
"module": "./dist/esm/production/index.js" | |||
} |
@@ -1,3 +0,0 @@ | |||
{ | |||
"target": "es2017" | |||
} |
@@ -1,127 +0,0 @@ | |||
import { css } from '@tesseract-design/goofy-goober'; | |||
export interface BlobBaseArgs { | |||
border: boolean, | |||
block: boolean, | |||
} | |||
export const Root = ({ | |||
block, | |||
}: BlobBaseArgs) => css.cx( | |||
css` | |||
vertical-align: middle; | |||
position: relative; | |||
border-radius: 0.25rem; | |||
font-family: var(--font-family-base, sans-serif); | |||
max-width: 100%; | |||
overflow: hidden; | |||
min-height: 20rem; | |||
min-width: 20rem; | |||
&:focus-within { | |||
--color-accent: var(--color-hover, red); | |||
} | |||
& > span { | |||
border-color: var(--color-accent, blue); | |||
box-sizing: border-box; | |||
display: inline-block; | |||
border-width: 0.125rem; | |||
border-style: solid; | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
border-radius: inherit; | |||
z-index: 2; | |||
pointer-events: none; | |||
transition-property: border-color; | |||
} | |||
& > span::before { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
content: ''; | |||
border-radius: 0.125rem; | |||
opacity: 0.5; | |||
pointer-events: none; | |||
box-shadow: 0 0 0 0 var(--color-accent, blue); | |||
transition-property: box-shadow; | |||
transition-duration: 150ms; | |||
transition-timing-function: linear; | |||
} | |||
&:focus-within > span::before { | |||
box-shadow: 0 0 0 0.375rem var(--color-accent, blue); | |||
} | |||
`, | |||
css.dynamic({ | |||
display: block ? 'block' : 'inline-block', | |||
}), | |||
); | |||
export const Border = ({ | |||
border | |||
}: BlobBaseArgs): string => css.cx( | |||
css.if (border) ( | |||
css` | |||
border-color: var(--color-accent, blue); | |||
box-sizing: border-box; | |||
display: inline-block; | |||
border-width: 0.125rem; | |||
border-style: solid; | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
border-radius: inherit; | |||
pointer-events: none; | |||
z-index: 10; | |||
&::before { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
content: ''; | |||
border-radius: 0.125rem; | |||
opacity: 0.5; | |||
pointer-events: none; | |||
} | |||
` | |||
), | |||
); | |||
export const LabelWrapper = ({ | |||
border, | |||
}: BlobBaseArgs): string => css.cx( | |||
css` | |||
color: var(--color-accent, blue); | |||
box-sizing: border-box; | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
font-weight: bolder; | |||
z-index: 1; | |||
pointer-events: none; | |||
transition-property: color; | |||
line-height: 0.65; | |||
user-select: none; | |||
font-size: 0.725em; | |||
padding-top: 0.25rem; | |||
padding-bottom: 0.25rem; | |||
padding-left: 0.5rem; | |||
padding-right: 0.5rem; | |||
`, | |||
css.if (border) ( | |||
css` | |||
background-color: var(--color-background, white); | |||
` | |||
), | |||
) |
@@ -1,9 +0,0 @@ | |||
{ | |||
"exclude": ["node_modules"], | |||
"extends": "../../../../tsconfig.json", | |||
"compilerOptions": { | |||
"rootDir": "src", | |||
"emitDeclarationOnly": true, | |||
"declaration": true | |||
} | |||
} |
@@ -1,71 +0,0 @@ | |||
{ | |||
"name": "@tesseract-design/web-base-button", | |||
"version": "0.0.0", | |||
"files": [ | |||
"dist", | |||
"src" | |||
], | |||
"engines": { | |||
"node": ">=10" | |||
}, | |||
"license": "MIT", | |||
"keywords": [ | |||
"pridepack" | |||
], | |||
"devDependencies": { | |||
"@types/node": "^18.0.0", | |||
"@types/react": "^18.2.6", | |||
"csstype": "^3.1.2", | |||
"eslint": "^8.20.0", | |||
"eslint-config-lxsmnsyc": "^0.4.7", | |||
"pridepack": "2.4.4", | |||
"tslib": "^2.4.0", | |||
"typescript": "^4.7.4", | |||
"vitest": "^0.19.1" | |||
}, | |||
"dependencies": { | |||
"@tesseract-design/goofy-goober": "link:../../../../../goofy-goober" | |||
}, | |||
"scripts": { | |||
"prepublishOnly": "pridepack clean && pridepack build", | |||
"build": "pridepack build", | |||
"type-check": "pridepack check", | |||
"lint": "pridepack lint", | |||
"clean": "pridepack clean", | |||
"watch": "pridepack watch", | |||
"start": "pridepack start", | |||
"dev": "pridepack dev", | |||
"test": "vitest" | |||
}, | |||
"private": true, | |||
"description": "Base button styles for Tesseract.", | |||
"repository": { | |||
"url": "", | |||
"type": "git" | |||
}, | |||
"homepage": "", | |||
"bugs": { | |||
"url": "" | |||
}, | |||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | |||
"publishConfig": { | |||
"access": "restricted" | |||
}, | |||
"types": "./dist/types/index.d.ts", | |||
"exports": { | |||
".": { | |||
"development": { | |||
"require": "./dist/cjs/development/index.js", | |||
"import": "./dist/esm/development/index.js" | |||
}, | |||
"require": "./dist/cjs/production/index.js", | |||
"import": "./dist/esm/production/index.js", | |||
"types": "./dist/types/index.d.ts" | |||
} | |||
}, | |||
"typesVersions": { | |||
"*": {} | |||
}, | |||
"main": "./dist/cjs/production/index.js", | |||
"module": "./dist/esm/production/index.js" | |||
} |
@@ -1,3 +0,0 @@ | |||
{ | |||
"target": "es2017" | |||
} |
@@ -1,318 +0,0 @@ | |||
import { css } from '@tesseract-design/goofy-goober'; | |||
export enum ButtonSize { | |||
SMALL = 'small', | |||
MEDIUM = 'medium', | |||
LARGE = 'large', | |||
} | |||
export enum ButtonVariant { | |||
OUTLINE = 'outline', | |||
FILLED = 'filled', | |||
} | |||
export type ButtonBaseArgs = { | |||
/** | |||
* Size of the component. | |||
*/ | |||
size: ButtonSize, | |||
/** | |||
* Will the component occupy the whole width of its container? | |||
*/ | |||
block: boolean, | |||
/** | |||
* Stylistic variant of the component. | |||
*/ | |||
variant: ButtonVariant, | |||
/** | |||
* Will the component display a surrounding border? | |||
*/ | |||
border: boolean, | |||
/** | |||
* Will the component reject any activation? | |||
*/ | |||
disabled: boolean, | |||
/** | |||
* Will the component conserve visual space? | |||
*/ | |||
compact: boolean, | |||
/** | |||
* Is the component an item inside a menu? | |||
*/ | |||
menuItem: boolean, | |||
} | |||
const MIN_HEIGHTS: Record<ButtonSize, string> = { | |||
[ButtonSize.SMALL]: '2.5rem', | |||
[ButtonSize.MEDIUM]: '3rem', | |||
[ButtonSize.LARGE]: '4rem', | |||
}; | |||
export const Button = ({ | |||
size, | |||
block, | |||
variant, | |||
disabled, | |||
compact, | |||
}: ButtonBaseArgs): string => css.cx( | |||
css` | |||
box-sizing: border-box; | |||
vertical-align: middle; | |||
appearance: none; | |||
font: inherit; | |||
font-family: var(--font-family-base, sans-serif); | |||
text-transform: uppercase; | |||
font-weight: bolder; | |||
border-radius: 0.25rem; | |||
justify-content: center; | |||
align-items: center; | |||
position: relative; | |||
border: 0; | |||
user-select: none; | |||
text-decoration: none; | |||
white-space: nowrap; | |||
line-height: 1; | |||
& > :first-child::before { | |||
box-shadow: 0 0 0 0 var(--color-accent, blue); | |||
transition-property: box-shadow; | |||
transition-duration: 150ms; | |||
transition-timing-function: linear; | |||
} | |||
&:disabled { | |||
opacity: 0.5; | |||
cursor: not-allowed; | |||
} | |||
&::-moz-focus-inner { | |||
outline: 0; | |||
border: 0; | |||
} | |||
&:focus > :first-child::before { | |||
box-shadow: 0 0 0 0.375rem var(--color-accent, blue); | |||
} | |||
&:disabled > :first-child::before { | |||
box-shadow: 0 0 0 0 var(--color-accent, blue) !important; | |||
} | |||
`, | |||
css.dynamic({ | |||
'min-height': MIN_HEIGHTS[size], | |||
}), | |||
css.if (disabled) ( | |||
css` | |||
--color-accent: var(--color-primary, blue); | |||
opacity: 0.5; | |||
cursor: not-allowed; | |||
` | |||
).else ( | |||
css` | |||
cursor: pointer; | |||
&:hover { | |||
--color-accent: var(--color-hover, blue); | |||
outline: 0; | |||
} | |||
&:focus { | |||
--color-accent: var(--color-hover, blue); | |||
outline: 0; | |||
} | |||
&:active { | |||
--color-accent: var(--color-active, red); | |||
outline: 0; | |||
} | |||
&:hover > :first-child::before { | |||
box-shadow: 0 0 0 0.375rem var(--color-accent, blue); | |||
} | |||
` | |||
), | |||
css.if (block) ( | |||
css` | |||
width: 100%; | |||
display: flex; | |||
` | |||
).else ( | |||
css` | |||
display: inline-flex; | |||
` | |||
), | |||
css.if (compact) ( | |||
css` | |||
font-stretch: condensed; | |||
padding: 0 0.5rem; | |||
` | |||
).else( | |||
css` | |||
padding: 0 1rem; | |||
` | |||
), | |||
css.if (variant === ButtonVariant.FILLED) ( | |||
css` | |||
background-color: var(--color-accent, blue); | |||
color: var(--color-background, white) !important; | |||
` | |||
), | |||
css.if (variant === ButtonVariant.OUTLINE) ( | |||
css` | |||
background-color: var(--color-background, white); | |||
color: var(--color-accent, blue); | |||
` | |||
), | |||
); | |||
export const Border = ({ | |||
border | |||
}: ButtonBaseArgs): string => css.cx( | |||
css.if (border) ( | |||
css` | |||
border-color: var(--color-accent, blue); | |||
box-sizing: border-box; | |||
display: inline-block; | |||
border-width: 0.125rem; | |||
border-style: solid; | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
border-radius: inherit; | |||
pointer-events: none; | |||
&::before { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
content: ''; | |||
border-radius: 0.125rem; | |||
opacity: 0.5; | |||
pointer-events: none; | |||
} | |||
` | |||
), | |||
); | |||
export const Label = ({ | |||
compact, | |||
menuItem, | |||
}: ButtonBaseArgs): string => css.cx( | |||
css` | |||
display: block; | |||
flex-grow: 1; | |||
flex-basis: 0; | |||
min-width: 0; | |||
`, | |||
css.if (compact || menuItem) ( | |||
css` | |||
text-align: left; | |||
` | |||
).else ( | |||
css` | |||
text-align: center; | |||
` | |||
), | |||
css.if (compact) ( | |||
css` | |||
& ~ :last-child { | |||
margin-right: -0.5rem; | |||
} | |||
` | |||
).else ( | |||
css` | |||
& ~ :last-child { | |||
margin-right: -1rem; | |||
} | |||
` | |||
), | |||
); | |||
export const BadgeContainer = ({ | |||
size, | |||
}: ButtonBaseArgs): string => css.cx( | |||
css` | |||
width: 2rem; | |||
text-align: center; | |||
flex-shrink: 0; | |||
& + * { | |||
margin-left: -0.5rem; | |||
} | |||
`, | |||
css.nest('&:last-child')( | |||
css.dynamic({ | |||
width: MIN_HEIGHTS[size], | |||
}) | |||
), | |||
); | |||
export const OverflowText = (): string => css.cx( | |||
css` | |||
width: 100%; | |||
display: block; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
height: 1.1em; | |||
line-height: 1; | |||
`, | |||
); | |||
export const IndicatorWrapper = ({ | |||
size | |||
}: ButtonBaseArgs): string => css.cx( | |||
css` | |||
flex-shrink: 0; | |||
box-sizing: border-box; | |||
display: grid; | |||
place-content: center; | |||
padding: 0 1rem; | |||
z-index: 1; | |||
pointer-events: none; | |||
line-height: 1; | |||
user-select: none; | |||
`, | |||
css.dynamic({ | |||
width: `calc(${MIN_HEIGHTS[size]} * 0.75)`, | |||
height: MIN_HEIGHTS[size], | |||
}), | |||
); | |||
export const Indicator = () => css.cx( | |||
css` | |||
width: 1.5em; | |||
height: 1.5em; | |||
fill: none; | |||
stroke: currentColor; | |||
stroke-width: 2; | |||
stroke-linecap: round; | |||
stroke-linejoin: round; | |||
`, | |||
); | |||
export const MainText = () => css.cx( | |||
css` | |||
width: 100%; | |||
`, | |||
); | |||
export const Subtext = () => css.cx( | |||
css` | |||
display: block; | |||
height: 1.1em; | |||
line-height: 1.1; | |||
width: 100%; | |||
font-size: 0.875em; | |||
text-transform: none; | |||
font-weight: var(--font-weight-base, normal); | |||
`, | |||
); |
@@ -1,9 +0,0 @@ | |||
{ | |||
"exclude": ["node_modules"], | |||
"extends": "../../../../tsconfig.json", | |||
"compilerOptions": { | |||
"rootDir": "src", | |||
"emitDeclarationOnly": true, | |||
"declaration": true | |||
} | |||
} |
@@ -1,71 +0,0 @@ | |||
{ | |||
"name": "@tesseract-design/web-base-checkcontrol", | |||
"version": "0.0.0", | |||
"files": [ | |||
"dist", | |||
"src" | |||
], | |||
"engines": { | |||
"node": ">=10" | |||
}, | |||
"license": "MIT", | |||
"keywords": [ | |||
"pridepack" | |||
], | |||
"devDependencies": { | |||
"@types/node": "^18.0.0", | |||
"@types/react": "^18.2.6", | |||
"csstype": "^3.1.2", | |||
"eslint": "^8.20.0", | |||
"eslint-config-lxsmnsyc": "^0.4.7", | |||
"pridepack": "2.4.4", | |||
"tslib": "^2.4.0", | |||
"typescript": "^4.7.4", | |||
"vitest": "^0.19.1" | |||
}, | |||
"dependencies": { | |||
"@tesseract-design/goofy-goober": "link:../../../../../goofy-goober" | |||
}, | |||
"scripts": { | |||
"prepublishOnly": "pridepack clean && pridepack build", | |||
"build": "pridepack build", | |||
"type-check": "pridepack check", | |||
"lint": "pridepack lint", | |||
"clean": "pridepack clean", | |||
"watch": "pridepack watch", | |||
"start": "pridepack start", | |||
"dev": "pridepack dev", | |||
"test": "vitest" | |||
}, | |||
"private": true, | |||
"description": "Base check control styles for Tesseract.", | |||
"repository": { | |||
"url": "", | |||
"type": "git" | |||
}, | |||
"homepage": "", | |||
"bugs": { | |||
"url": "" | |||
}, | |||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | |||
"publishConfig": { | |||
"access": "restricted" | |||
}, | |||
"types": "./dist/types/index.d.ts", | |||
"exports": { | |||
".": { | |||
"development": { | |||
"require": "./dist/cjs/development/index.js", | |||
"import": "./dist/esm/development/index.js" | |||
}, | |||
"require": "./dist/cjs/production/index.js", | |||
"import": "./dist/esm/production/index.js", | |||
"types": "./dist/types/index.d.ts" | |||
} | |||
}, | |||
"typesVersions": { | |||
"*": {} | |||
}, | |||
"main": "./dist/cjs/production/index.js", | |||
"module": "./dist/esm/production/index.js" | |||
} |
@@ -1,3 +0,0 @@ | |||
{ | |||
"target": "es2017" | |||
} |
@@ -1,346 +0,0 @@ | |||
import { css } from '@tesseract-design/goofy-goober' | |||
export enum CheckControlAppearance { | |||
TICK_BOX = 'tick-box', | |||
BUTTON = 'button', | |||
SWITCH = 'switch', | |||
} | |||
export enum CheckControlType { | |||
/** | |||
* One or more of this component within its group can be selected. | |||
*/ | |||
CHECKBOX = 'checkbox', | |||
/** | |||
* At most one of this component within its group can be selected. | |||
*/ | |||
RADIO = 'radio', | |||
} | |||
export type CheckControlBaseArgs = { | |||
/** | |||
* Will the component conserve visual space? | |||
*/ | |||
compact: boolean, | |||
/** | |||
* Appearance of the component. | |||
*/ | |||
appearance: CheckControlAppearance, | |||
/** | |||
* Will the component occupy the whole width of its container? | |||
*/ | |||
block: boolean, | |||
/** | |||
* Type of the component defining its behavior. | |||
*/ | |||
type: CheckControlType, | |||
/** | |||
* Label to display signifying the component's unselected state. | |||
*/ | |||
uncheckedLabel: boolean, | |||
} | |||
export const CheckStateContainer = ({ | |||
appearance, | |||
type, | |||
}: CheckControlBaseArgs): string => css.cx( | |||
css` | |||
position: absolute; | |||
width: 1px; | |||
height: 1px; | |||
padding: 0; | |||
margin: -1px; | |||
overflow: hidden; | |||
clip: rect(0, 0, 0, 0); | |||
white-space: nowrap; | |||
border-width: 0; | |||
&:disabled + * { | |||
cursor: not-allowed; | |||
} | |||
&:first-child + * > :first-child + * + * { | |||
align-items: flex-start; | |||
text-align: left; | |||
} | |||
&:checked + * { | |||
--color-accent: var(--color-active, Highlight); | |||
outline: 0; | |||
} | |||
&:indeterminate[type="checkbox"] + * { | |||
--color-accent: var(--color-active, Highlight); | |||
outline: 0; | |||
} | |||
&:indeterminate[type="checkbox"] + * > :first-child + * > * > :first-child { | |||
display: none; | |||
} | |||
&:checked + * > :first-child + * > * > :first-child + * { | |||
display: none; | |||
} | |||
&:focus + * { | |||
--color-accent: var(--color-hover, red); | |||
outline: 0; | |||
} | |||
&:focus[type="checkbox"] + * { | |||
--color-accent: var(--color-hover, red); | |||
outline: 0; | |||
} | |||
&:focus + * > :first-child::before { | |||
box-shadow: 0 0 0 0.375rem var(--color-accent, blue); | |||
} | |||
`, | |||
css.nest('&:checked + * > :first-child + * > *') ( | |||
css.if ( | |||
appearance === CheckControlAppearance.TICK_BOX | |||
|| appearance === CheckControlAppearance.BUTTON | |||
) ( | |||
css.if (type === 'checkbox') ( | |||
css` | |||
width: 1.5em; | |||
height: 1.5em; | |||
` | |||
), | |||
css.if (type === 'radio') ( | |||
css` | |||
width: 1em; | |||
height: 1em; | |||
` | |||
), | |||
), | |||
css.if (appearance === CheckControlAppearance.SWITCH) ( | |||
css` | |||
width: 1em; | |||
height: 1em; | |||
margin-right: 0; | |||
margin-left: 1em; | |||
` | |||
), | |||
), | |||
css.nest('&:first-child + *') ( | |||
css` | |||
cursor: pointer; | |||
`, | |||
css.if (appearance === CheckControlAppearance.BUTTON) ( | |||
css` | |||
display: flex; | |||
`, | |||
), | |||
css.if (appearance === CheckControlAppearance.SWITCH) ( | |||
css` | |||
width: 1em; | |||
height: 1em; | |||
`, | |||
), | |||
), | |||
css.nest('&:indeterminate[type="checkbox"] + * > :first-child + * > *') ( | |||
css.if ( | |||
appearance === CheckControlAppearance.BUTTON | |||
|| appearance === CheckControlAppearance.TICK_BOX | |||
) ( | |||
css` | |||
width: 1.5em; | |||
height: 1.5em; | |||
` | |||
), | |||
css.if (appearance === CheckControlAppearance.SWITCH) ( | |||
css` | |||
width: 1em; | |||
height: 1em; | |||
margin-right: 0.5em; | |||
margin-left: 0.5em; | |||
` | |||
) | |||
), | |||
css.nest('&:indeterminate[type="checkbox"] + * > :first-child + * > * > :first-child + *') ( | |||
css.if ( | |||
appearance === CheckControlAppearance.BUTTON | |||
|| appearance === CheckControlAppearance.TICK_BOX | |||
) ( | |||
css` | |||
display: block; | |||
` | |||
), | |||
), | |||
css.nest('&:checked + * > :first-child + * > * > :first-child') ( | |||
css.if ( | |||
appearance === CheckControlAppearance.BUTTON | |||
|| appearance === CheckControlAppearance.TICK_BOX | |||
) ( | |||
css` | |||
display: block; | |||
` | |||
), | |||
), | |||
); | |||
export const ClickArea = (): string => css.cx( | |||
css` | |||
display: contents; | |||
` | |||
); | |||
export const CheckIndicatorArea = ({ | |||
compact, | |||
appearance, | |||
type, | |||
uncheckedLabel, | |||
}: CheckControlBaseArgs): string => css.cx( | |||
css` | |||
display: inline-grid; | |||
vertical-align: middle; | |||
place-content: center; | |||
position: relative; | |||
background-color: var(--color-background, white); | |||
box-shadow: 0 0 0 0.125rem var(--color-background, white); | |||
color: var(--color-accent, blue); | |||
overflow: hidden; | |||
&::before { | |||
content: ''; | |||
width: 100%; | |||
height: 100%; | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
border-radius: inherit; | |||
border-width: 0.125rem; | |||
border-style: solid; | |||
box-sizing: border-box; | |||
} | |||
`, | |||
css.if (appearance === CheckControlAppearance.TICK_BOX) ( | |||
css` | |||
width: 1.5em; | |||
height: 1.5em; | |||
`, | |||
css.if (type === CheckControlType.CHECKBOX) ( | |||
css` | |||
border-radius: 0.25rem; | |||
` | |||
), | |||
css.if (type === CheckControlType.RADIO) ( | |||
css` | |||
border-radius: 50%; | |||
` | |||
), | |||
), | |||
css.if (appearance === CheckControlAppearance.BUTTON) ( | |||
css` | |||
width: 1.5em; | |||
height: 1.5em; | |||
`, | |||
css.if (!compact) ( | |||
css` | |||
margin-left: -0.25rem; | |||
` | |||
), | |||
css.if (type === CheckControlType.CHECKBOX) ( | |||
css` | |||
border-radius: 0.25rem; | |||
` | |||
), | |||
css.if (type === CheckControlType.RADIO) ( | |||
css` | |||
border-radius: 50%; | |||
` | |||
), | |||
), | |||
css.if (appearance === CheckControlAppearance.SWITCH) ( | |||
css` | |||
width: 2.5em; | |||
height: 1.5em; | |||
border-radius: 0.75em; | |||
`, | |||
css.if(uncheckedLabel) ( | |||
css.dynamic({ | |||
'margin-left': compact ? '0.375rem' : '0.75rem', | |||
}) | |||
), | |||
), | |||
css.nest('& + *') ( | |||
css.dynamic({ | |||
'margin-left': compact ? '0.375rem' : '0.75rem', | |||
}) | |||
) | |||
); | |||
export const CheckIndicatorWrapper = ({ | |||
appearance, | |||
}: CheckControlBaseArgs): string => css.cx( | |||
css` | |||
flex-shrink: 0; | |||
display: grid; | |||
position: relative; | |||
background-color: var(--color-accent, blue); | |||
overflow: hidden; | |||
border-radius: inherit; | |||
`, | |||
css.if( | |||
appearance === CheckControlAppearance.TICK_BOX | |||
|| appearance === CheckControlAppearance.BUTTON | |||
) ( | |||
css` | |||
width: 0; | |||
height: 0; | |||
` | |||
), | |||
css.if(appearance === CheckControlAppearance.SWITCH) ( | |||
css` | |||
width: 1em; | |||
height: 1em; | |||
margin-right: 1em; | |||
transition-property: margin-left, margin-right; | |||
transition-duration: 150ms; | |||
transition-timing-function: ease-out; | |||
`, | |||
), | |||
); | |||
export const CheckIndicator = ({ | |||
appearance, | |||
}: CheckControlBaseArgs) => css.cx( | |||
css` | |||
fill: none; | |||
stroke: var(--color-background, white); | |||
stroke-width: 2; | |||
stroke-linecap: round; | |||
stroke-linejoin: round; | |||
width: 1.5em; | |||
height: 1.5em; | |||
`, | |||
css.if(appearance === CheckControlAppearance.SWITCH) ( | |||
css` | |||
display: none; | |||
` | |||
) | |||
); | |||
export const ClickAreaWrapper = ({ | |||
block, | |||
appearance, | |||
uncheckedLabel, | |||
}: CheckControlBaseArgs) => css.cx( | |||
css` | |||
vertical-align: middle; | |||
`, | |||
css.dynamic({ | |||
display: block ? 'block' : 'inline-block', | |||
}), | |||
css.if (appearance === CheckControlAppearance.TICK_BOX) ( | |||
css` | |||
padding-left: 2.25rem; | |||
text-indent: -2.25rem; | |||
` | |||
), | |||
css.if (appearance === CheckControlAppearance.SWITCH) ( | |||
css.if (!uncheckedLabel) ( | |||
css` | |||
padding-left: 3.25rem; | |||
text-indent: -3.25rem; | |||
` | |||
), | |||
), | |||
); | |||
export const Subtext = () => css.cx( | |||
css` | |||
font-size: 0.875em; | |||
` | |||
); |
@@ -1,9 +0,0 @@ | |||
{ | |||
"exclude": ["node_modules"], | |||
"extends": "../../../../tsconfig.json", | |||
"compilerOptions": { | |||
"rootDir": "src", | |||
"emitDeclarationOnly": true, | |||
"declaration": true | |||
} | |||
} |
@@ -1,67 +0,0 @@ | |||
{ | |||
"name": "@tesseract-design/web-base-selectcontrol", | |||
"version": "0.0.0", | |||
"files": [ | |||
"dist", | |||
"src" | |||
], | |||
"engines": { | |||
"node": ">=10" | |||
}, | |||
"license": "MIT", | |||
"keywords": [ | |||
"pridepack" | |||
], | |||
"devDependencies": { | |||
"@types/node": "^18.0.0", | |||
"eslint": "^8.20.0", | |||
"eslint-config-lxsmnsyc": "^0.4.7", | |||
"pridepack": "2.4.4", | |||
"tslib": "^2.4.0", | |||
"typescript": "^4.7.4", | |||
"vitest": "^0.19.1" | |||
}, | |||
"dependencies": {}, | |||
"scripts": { | |||
"prepublishOnly": "pridepack clean && pridepack build", | |||
"build": "pridepack build", | |||
"type-check": "pridepack check", | |||
"lint": "pridepack lint", | |||
"clean": "pridepack clean", | |||
"watch": "pridepack watch", | |||
"start": "pridepack start", | |||
"dev": "pridepack dev", | |||
"test": "vitest" | |||
}, | |||
"private": true, | |||
"description": "Base select control styles for Tesseract.", | |||
"repository": { | |||
"url": "", | |||
"type": "git" | |||
}, | |||
"homepage": "", | |||
"bugs": { | |||
"url": "" | |||
}, | |||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | |||
"publishConfig": { | |||
"access": "restricted" | |||
}, | |||
"types": "./dist/types/index.d.ts", | |||
"exports": { | |||
".": { | |||
"development": { | |||
"require": "./dist/cjs/development/index.js", | |||
"import": "./dist/esm/development/index.js" | |||
}, | |||
"require": "./dist/cjs/production/index.js", | |||
"import": "./dist/esm/production/index.js", | |||
"types": "./dist/types/index.d.ts" | |||
} | |||
}, | |||
"typesVersions": { | |||
"*": {} | |||
}, | |||
"main": "./dist/cjs/production/index.js", | |||
"module": "./dist/esm/production/index.js" | |||
} |
@@ -1,3 +0,0 @@ | |||
{ | |||
"target": "es2017" | |||
} |
@@ -1,5 +0,0 @@ | |||
export interface SelectOption { | |||
label: string, | |||
value?: string | number | readonly string[] | |||
children?: SelectOption[] | |||
} |
@@ -1,9 +0,0 @@ | |||
{ | |||
"exclude": ["node_modules"], | |||
"extends": "../../../../tsconfig.json", | |||
"compilerOptions": { | |||
"rootDir": "src", | |||
"emitDeclarationOnly": true, | |||
"declaration": true | |||
} | |||
} |
@@ -1,71 +0,0 @@ | |||
{ | |||
"name": "@tesseract-design/web-base-textcontrol", | |||
"version": "0.0.0", | |||
"files": [ | |||
"dist", | |||
"src" | |||
], | |||
"engines": { | |||
"node": ">=10" | |||
}, | |||
"license": "MIT", | |||
"keywords": [ | |||
"pridepack" | |||
], | |||
"devDependencies": { | |||
"@types/node": "^18.0.0", | |||
"@types/react": "^18.2.6", | |||
"csstype": "^3.1.2", | |||
"eslint": "^8.20.0", | |||
"eslint-config-lxsmnsyc": "^0.4.7", | |||
"pridepack": "2.4.4", | |||
"tslib": "^2.4.0", | |||
"typescript": "^4.7.4", | |||
"vitest": "^0.19.1" | |||
}, | |||
"dependencies": { | |||
"@tesseract-design/goofy-goober": "link:../../../../../goofy-goober" | |||
}, | |||
"scripts": { | |||
"prepublishOnly": "pridepack clean && pridepack build", | |||
"build": "pridepack build", | |||
"type-check": "pridepack check", | |||
"lint": "pridepack lint", | |||
"clean": "pridepack clean", | |||
"watch": "pridepack watch", | |||
"start": "pridepack start", | |||
"dev": "pridepack dev", | |||
"test": "vitest" | |||
}, | |||
"private": true, | |||
"description": "Base text control styles for Tesseract.", | |||
"repository": { | |||
"url": "", | |||
"type": "git" | |||
}, | |||
"homepage": "", | |||
"bugs": { | |||
"url": "" | |||
}, | |||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | |||
"publishConfig": { | |||
"access": "restricted" | |||
}, | |||
"types": "./dist/types/index.d.ts", | |||
"exports": { | |||
".": { | |||
"development": { | |||
"require": "./dist/cjs/development/index.js", | |||
"import": "./dist/esm/development/index.js" | |||
}, | |||
"require": "./dist/cjs/production/index.js", | |||
"import": "./dist/esm/production/index.js", | |||
"types": "./dist/types/index.d.ts" | |||
} | |||
}, | |||
"typesVersions": { | |||
"*": {} | |||
}, | |||
"main": "./dist/cjs/production/index.js", | |||
"module": "./dist/esm/production/index.js" | |||
} |
@@ -1,3 +0,0 @@ | |||
{ | |||
"target": "es2017" | |||
} |
@@ -1,405 +0,0 @@ | |||
import { css } from '@tesseract-design/goofy-goober'; | |||
export enum TextControlSize { | |||
SMALL = 'small', | |||
MEDIUM = 'medium', | |||
LARGE = 'large', | |||
} | |||
export enum TextControlStyle { | |||
DEFAULT = 'default', | |||
ALTERNATE = 'alternate', | |||
} | |||
export enum TextControlInputType { | |||
TEXT = 'text', | |||
SEARCH = 'search', | |||
} | |||
export const MIN_HEIGHTS: Record<TextControlSize, string> = { | |||
[TextControlSize.SMALL]: '2.5rem', | |||
[TextControlSize.MEDIUM]: '3rem', | |||
[TextControlSize.LARGE]: '4rem', | |||
}; | |||
const LABEL_VERTICAL_PADDING_SIZES: Record<TextControlSize, string> = { | |||
[TextControlSize.SMALL]: '0.125rem', | |||
[TextControlSize.MEDIUM]: '0.25rem', | |||
[TextControlSize.LARGE]: '0.375rem', | |||
}; | |||
const INPUT_FONT_SIZES: Record<TextControlSize, string> = { | |||
[TextControlSize.SMALL]: '0.75em', | |||
[TextControlSize.MEDIUM]: '0.85em', | |||
[TextControlSize.LARGE]: '1em', | |||
}; | |||
const SECONDARY_TEXT_SIZES: Record<TextControlSize, string> = { | |||
[TextControlSize.SMALL]: '0.6em', | |||
[TextControlSize.MEDIUM]: '0.725em', | |||
[TextControlSize.LARGE]: '0.85em', | |||
}; | |||
const MULTILINE_VERTICAL_PADDING_FACTORS: Record<TextControlSize, string> = { | |||
[TextControlSize.SMALL]: '1.25', | |||
[TextControlSize.MEDIUM]: '1.2', | |||
[TextControlSize.LARGE]: '1.45', | |||
}; | |||
const ALTERNATE_VERTICAL_PADDING_FACTORS: Record<TextControlSize, string> = { | |||
[TextControlSize.SMALL]: '1.75', | |||
[TextControlSize.MEDIUM]: '1.35', | |||
[TextControlSize.LARGE]: '1.25', | |||
}; | |||
export type TextControlBaseArgs = { | |||
/** | |||
* Will the component occupy the whole width of its container? | |||
*/ | |||
block: boolean, | |||
/** | |||
* Stylistic variant of the component. | |||
*/ | |||
style: TextControlStyle, | |||
/** | |||
* Will the component display a surrounding border? | |||
*/ | |||
border: boolean, | |||
/** | |||
* Does the component include an additional indicator for labels? | |||
*/ | |||
indicator: boolean, | |||
/** | |||
* Size of the component. | |||
*/ | |||
size: TextControlSize, | |||
/** | |||
* Can the size of the component be changed? | |||
*/ | |||
resizable: boolean, | |||
/** | |||
* Does this component have predefined values? | |||
*/ | |||
predefinedValues: boolean, | |||
} | |||
export const Root = ({ | |||
block, | |||
}: TextControlBaseArgs): string => css.cx( | |||
css` | |||
vertical-align: middle; | |||
position: relative; | |||
border-radius: 0.25rem; | |||
font-family: var(--font-family-base, sans-serif); | |||
max-width: 100%; | |||
&:focus-within { | |||
--color-accent: var(--color-hover, red); | |||
} | |||
& > span { | |||
border-color: var(--color-accent, blue); | |||
box-sizing: border-box; | |||
display: inline-block; | |||
border-width: 0.125rem; | |||
border-style: solid; | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
border-radius: inherit; | |||
z-index: 2; | |||
pointer-events: none; | |||
transition-property: border-color; | |||
} | |||
& > span::before { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
content: ''; | |||
border-radius: 0.125rem; | |||
opacity: 0.5; | |||
pointer-events: none; | |||
box-shadow: 0 0 0 0 var(--color-accent, blue); | |||
transition-property: box-shadow; | |||
transition-duration: 150ms; | |||
transition-timing-function: linear; | |||
} | |||
&:focus-within > span::before { | |||
box-shadow: 0 0 0 0.375rem var(--color-accent, blue); | |||
} | |||
`, | |||
css.dynamic({ | |||
display: block ? 'block' : 'inline-block', | |||
}), | |||
); | |||
export const LabelWrapper = ({ | |||
style, | |||
border, | |||
indicator, | |||
size, | |||
}: TextControlBaseArgs): string => css.cx( | |||
css` | |||
color: var(--color-accent, blue); | |||
box-sizing: border-box; | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
font-weight: bolder; | |||
z-index: 1; | |||
pointer-events: none; | |||
transition-property: color; | |||
line-height: 0.65; | |||
user-select: none; | |||
`, | |||
css.dynamic({ | |||
'padding-bottom': LABEL_VERTICAL_PADDING_SIZES[size], | |||
'font-size': SECONDARY_TEXT_SIZES[size], | |||
}), | |||
css.if (border) ( | |||
css` | |||
background-color: var(--color-background, white); | |||
` | |||
), | |||
css.if (style === TextControlStyle.ALTERNATE) ( | |||
css.dynamic({ | |||
'padding-top': `calc(${LABEL_VERTICAL_PADDING_SIZES[size]} * 0.5)`, | |||
}), | |||
css.if (border) ( | |||
css` | |||
padding-left: 0.5rem; | |||
`, | |||
css.dynamic({ | |||
'padding-right': indicator ? MIN_HEIGHTS[size] : '0.5rem', | |||
}), | |||
), | |||
css.if (!border && indicator) ( | |||
css.dynamic({ | |||
'padding-right': MIN_HEIGHTS[size], | |||
}), | |||
), | |||
), | |||
css.if (style === TextControlStyle.DEFAULT) ( | |||
css` | |||
padding-left: 0.5rem; | |||
`, | |||
css.dynamic({ | |||
'padding-top': LABEL_VERTICAL_PADDING_SIZES[size], | |||
'padding-right': !indicator ? '0.5rem' : MIN_HEIGHTS[size], | |||
}), | |||
), | |||
) | |||
export const Input = ({ | |||
style, | |||
size, | |||
indicator, | |||
border, | |||
resizable, | |||
predefinedValues, | |||
}: TextControlBaseArgs): string => css.cx( | |||
css` | |||
appearance: none; | |||
display: block; | |||
box-sizing: border-box; | |||
position: relative; | |||
border: 0; | |||
border-radius: inherit; | |||
margin: 0; | |||
font-family: inherit; | |||
min-width: 8rem; | |||
max-width: 100%; | |||
width: 100%; | |||
z-index: 1; | |||
transition-property: background-color, color; | |||
&:focus { | |||
outline: 0; | |||
color: var(--color-foreground, black); | |||
} | |||
&:disabled { | |||
cursor: not-allowed; | |||
opacity: 0.5; | |||
} | |||
&:disabled ~ * { | |||
opacity: 0.5; | |||
} | |||
`, | |||
css.media('only screen') ( | |||
css` | |||
background-color: var(--color-background, white); | |||
color: var(--color-foreground, black); | |||
` | |||
), | |||
css.dynamic({ | |||
'min-height': MIN_HEIGHTS[size], | |||
'font-size': INPUT_FONT_SIZES[size], | |||
}), | |||
css.if (resizable) ( | |||
css` | |||
resize: vertical; | |||
` | |||
), | |||
css.if (predefinedValues) ( | |||
css` | |||
cursor: pointer; | |||
` | |||
), | |||
css.if (border) ( | |||
css` | |||
background-color: var(--color-background, white); | |||
` | |||
), | |||
css.if (style === TextControlStyle.ALTERNATE) ( | |||
css` | |||
padding-bottom: 0; | |||
`, | |||
css.dynamic({ | |||
'padding-top': resizable | |||
? `calc(${SECONDARY_TEXT_SIZES[size]} * 2.5)` | |||
: `calc(${SECONDARY_TEXT_SIZES[size]} * 2)`, | |||
'line-height': `calc(${MULTILINE_VERTICAL_PADDING_FACTORS[size]} * 1.1)`, | |||
}), | |||
css.if (border) ( | |||
css` | |||
padding-left: 0.5rem; | |||
`, | |||
css.dynamic({ | |||
'padding-right': indicator ? MIN_HEIGHTS[size] : '0.5rem', | |||
}), | |||
), | |||
css.if (!border && indicator) ( | |||
css.dynamic({ | |||
'padding-right': MIN_HEIGHTS[size], | |||
}), | |||
) | |||
), | |||
css.if (style === TextControlStyle.DEFAULT) ( | |||
css` | |||
padding-left: 1rem; | |||
`, | |||
css.dynamic({ | |||
'padding-right': !indicator ? '1rem' : MIN_HEIGHTS[size], | |||
'line-height': `calc(${MULTILINE_VERTICAL_PADDING_FACTORS[size]} * 1.1)`, | |||
}), | |||
css.if (resizable) ( | |||
css.dynamic({ | |||
'padding-top': `calc(${SECONDARY_TEXT_SIZES[size]} * ${MULTILINE_VERTICAL_PADDING_FACTORS[size]})`, | |||
'padding-bottom': `calc(${SECONDARY_TEXT_SIZES[size]} * ${MULTILINE_VERTICAL_PADDING_FACTORS[size]})`, | |||
}) | |||
), | |||
css.if (!resizable) ( | |||
css.dynamic({ | |||
'padding-bottom': `calc(${SECONDARY_TEXT_SIZES[size]} * ${MULTILINE_VERTICAL_PADDING_FACTORS[size]} * 0.5)`, | |||
}) | |||
) | |||
), | |||
) | |||
export const HintWrapper = ({ | |||
style, | |||
size, | |||
border, | |||
}: TextControlBaseArgs): string => css.cx( | |||
css` | |||
box-sizing: border-box; | |||
position: absolute; | |||
left: 0; | |||
font-size: 0.85em; | |||
max-width: 100%; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
z-index: 1; | |||
pointer-events: none; | |||
user-select: none; | |||
line-height: 0; | |||
`, | |||
css.if (border) ( | |||
css` | |||
background-color: var(--color-background, white); | |||
` | |||
), | |||
css.if (style === TextControlStyle.ALTERNATE) ( | |||
css` | |||
line-height: 1.25; | |||
`, | |||
css.dynamic({ | |||
top: `calc(${SECONDARY_TEXT_SIZES[size]} * ${ALTERNATE_VERTICAL_PADDING_FACTORS[size]})`, | |||
'font-size': SECONDARY_TEXT_SIZES[size], | |||
}), | |||
css.if (border) ( | |||
css` | |||
padding-left: 0.5rem; | |||
&:last-child { | |||
padding-right: 0.5rem; | |||
} | |||
`, | |||
css.dynamic({ | |||
'padding-right': MIN_HEIGHTS[size], | |||
}) | |||
) | |||
), | |||
css.if (style === TextControlStyle.DEFAULT) ( | |||
css` | |||
bottom: 0; | |||
padding-left: 1rem; | |||
line-height: 1.25; | |||
&:last-child { | |||
padding-right: 1rem; | |||
} | |||
`, | |||
css.dynamic({ | |||
'padding-bottom': `calc(${LABEL_VERTICAL_PADDING_SIZES[size]} * 0.9)`, | |||
'padding-right': MIN_HEIGHTS[size], | |||
'font-size': SECONDARY_TEXT_SIZES[size], | |||
}) | |||
) | |||
) | |||
export const Hint = (): string => css.cx( | |||
css` | |||
opacity: 0.5; | |||
` | |||
); | |||
export const IndicatorWrapper = ({ | |||
size | |||
}: TextControlBaseArgs): string => css.cx( | |||
css` | |||
color: var(--color-accent, blue); | |||
box-sizing: border-box; | |||
position: absolute; | |||
bottom: 0; | |||
right: 0; | |||
display: grid; | |||
place-content: center; | |||
padding: 0 1rem; | |||
z-index: 2; | |||
pointer-events: none; | |||
transition-property: color; | |||
line-height: 1; | |||
user-select: none; | |||
`, | |||
css.dynamic({ | |||
width: MIN_HEIGHTS[size], | |||
height: MIN_HEIGHTS[size], | |||
}), | |||
); | |||
export const Indicator = (): string => css.cx( | |||
css` | |||
width: 1.5em; | |||
height: 1.5em; | |||
fill: none; | |||
stroke: currentColor; | |||
stroke-width: 2; | |||
stroke-linecap: round; | |||
stroke-linejoin: round; | |||
`, | |||
); |
@@ -1,9 +0,0 @@ | |||
{ | |||
"exclude": ["node_modules"], | |||
"extends": "../../../../tsconfig.json", | |||
"compilerOptions": { | |||
"rootDir": "src", | |||
"emitDeclarationOnly": true, | |||
"declaration": true | |||
} | |||
} |
@@ -1,82 +0,0 @@ | |||
{ | |||
"name": "@tesseract-design/web-action-react", | |||
"version": "0.0.0", | |||
"files": [ | |||
"dist", | |||
"src" | |||
], | |||
"engines": { | |||
"node": ">=10" | |||
}, | |||
"license": "MIT", | |||
"keywords": [ | |||
"pridepack" | |||
], | |||
"dependencies": { | |||
"@tesseract-design/web-base-button": "link:../../../base/button" | |||
}, | |||
"devDependencies": { | |||
"@testing-library/jest-dom": "^5.16.4", | |||
"@testing-library/react": "^13.3.0", | |||
"@testing-library/react-hooks": "^8.0.1", | |||
"@testing-library/user-event": "^13.5.0", | |||
"@types/node": "^18.0.0", | |||
"@types/react": "^18.0.14", | |||
"eslint": "^8.20.0", | |||
"eslint-config-lxsmnsyc": "^0.4.7", | |||
"jsdom": "^20.0.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
"react-test-renderer": "^18.2.0", | |||
"tslib": "^2.4.0", | |||
"typescript": "^4.7.4", | |||
"vitest": "^0.31.0" | |||
}, | |||
"peerDependencies": { | |||
"react": "^16.8 || ^17.0 || ^18.0", | |||
"react-dom": "^16.8 || ^17.0 || ^18.0" | |||
}, | |||
"scripts": { | |||
"prepublishOnly": "pridepack clean && pridepack build", | |||
"build": "pridepack build", | |||
"type-check": "pridepack check", | |||
"lint": "pridepack lint", | |||
"clean": "pridepack clean", | |||
"watch": "pridepack watch", | |||
"start": "pridepack start", | |||
"dev": "pridepack dev", | |||
"test": "vitest" | |||
}, | |||
"private": true, | |||
"description": "Action components for Tesseract for use in React.", | |||
"repository": { | |||
"url": "", | |||
"type": "git" | |||
}, | |||
"homepage": "", | |||
"bugs": { | |||
"url": "" | |||
}, | |||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | |||
"publishConfig": { | |||
"access": "restricted" | |||
}, | |||
"types": "./dist/types/index.d.ts", | |||
"exports": { | |||
".": { | |||
"development": { | |||
"require": "./dist/cjs/development/index.js", | |||
"import": "./dist/esm/development/index.js" | |||
}, | |||
"require": "./dist/cjs/production/index.js", | |||
"import": "./dist/esm/production/index.js", | |||
"types": "./dist/types/index.d.ts" | |||
} | |||
}, | |||
"typesVersions": { | |||
"*": {} | |||
}, | |||
"main": "./dist/cjs/production/index.js", | |||
"module": "./dist/esm/production/index.js" | |||
} |
@@ -1,3 +0,0 @@ | |||
{ | |||
"target": "es2017" | |||
} |
@@ -1,4 +0,0 @@ | |||
import matchers from '@testing-library/jest-dom/matchers'; | |||
import '@testing-library/jest-dom'; | |||
expect.extend(matchers); |
@@ -1,190 +0,0 @@ | |||
import * as React from 'react'; | |||
import { | |||
render, | |||
screen, | |||
} from '@testing-library/react'; | |||
import userEvent from '@testing-library/user-event'; | |||
import * as ButtonBase from '@tesseract-design/web-base-button'; | |||
import { vi } from 'vitest'; | |||
import { | |||
ActionButton, | |||
ActionButtonType, | |||
} from '.'; | |||
vi.mock('@tesseract-design/web-base-button'); | |||
describe('ActionButton', () => { | |||
it('renders a button', () => { | |||
render( | |||
<ActionButton /> | |||
); | |||
const button: HTMLButtonElement = screen.getByRole('button'); | |||
expect(button).toBeInTheDocument(); | |||
expect(button).toHaveProperty('type', 'button'); | |||
}); | |||
it('renders a subtext', () => { | |||
render( | |||
<ActionButton | |||
subtext="subtext" | |||
/> | |||
); | |||
const subtext: HTMLElement = screen.getByTestId('subtext'); | |||
expect(subtext).toBeInTheDocument(); | |||
}); | |||
it('renders a badge', () => { | |||
render( | |||
<ActionButton | |||
badge="badge" | |||
/> | |||
); | |||
const badge: HTMLElement = screen.getByTestId('badge'); | |||
expect(badge).toBeInTheDocument(); | |||
}); | |||
it('renders as a menu item', () => { | |||
render( | |||
<ActionButton | |||
menuItem | |||
/> | |||
); | |||
const menuItemIndicator: HTMLElement = screen.getByTestId('menuItemIndicator'); | |||
expect(menuItemIndicator).toBeInTheDocument(); | |||
}); | |||
it('handles click events', () => { | |||
const onClick = vi.fn().mockImplementationOnce((e) => { e.preventDefault() }); | |||
render( | |||
<ActionButton | |||
onClick={onClick} | |||
/> | |||
); | |||
const button: HTMLButtonElement = screen.getByRole('button'); | |||
userEvent.click(button); | |||
expect(onClick).toBeCalled(); | |||
}); | |||
it('renders a compact button', () => { | |||
render( | |||
<ActionButton | |||
compact | |||
/> | |||
); | |||
expect(ButtonBase.Button).toBeCalledWith(expect.objectContaining({ | |||
compact: true, | |||
})); | |||
expect(ButtonBase.Label).toBeCalledWith(expect.objectContaining({ | |||
compact: true, | |||
})); | |||
}); | |||
describe.each(Object.values(ButtonBase.ButtonSize))('on %s size', (size) => { | |||
it('renders button styles', () => { | |||
render( | |||
<ActionButton | |||
size={size} | |||
/> | |||
); | |||
expect(ButtonBase.Button).toBeCalledWith(expect.objectContaining({ | |||
size, | |||
})); | |||
}); | |||
it('renders badge styles', () => { | |||
render( | |||
<ActionButton | |||
size={size} | |||
badge="badge" | |||
/> | |||
); | |||
expect(ButtonBase.BadgeContainer).toBeCalledWith(expect.objectContaining({ | |||
size, | |||
})); | |||
}); | |||
it('renders indicator styles', () => { | |||
render( | |||
<ActionButton | |||
size={size} | |||
menuItem | |||
/> | |||
); | |||
expect(ButtonBase.IndicatorWrapper).toBeCalledWith(expect.objectContaining({ | |||
size, | |||
})); | |||
}); | |||
}); | |||
it.each(Object.values(ButtonBase.ButtonVariant))('renders a button with variant %s', (variant) => { | |||
render( | |||
<ActionButton | |||
variant={variant} | |||
/> | |||
); | |||
expect(ButtonBase.Button).toBeCalledWith(expect.objectContaining({ | |||
variant, | |||
})); | |||
}); | |||
it('renders a bordered button', () => { | |||
render( | |||
<ActionButton | |||
border | |||
/> | |||
); | |||
expect(ButtonBase.Border).toBeCalledWith(expect.objectContaining({ | |||
border: true, | |||
})); | |||
}); | |||
it('renders a block button', () => { | |||
render( | |||
<ActionButton | |||
block | |||
/> | |||
); | |||
expect(ButtonBase.Border).toBeCalledWith(expect.objectContaining({ | |||
block: true, | |||
})); | |||
}); | |||
it('renders children', () => { | |||
render( | |||
<ActionButton> | |||
Foo | |||
</ActionButton> | |||
); | |||
const children: HTMLElement = screen.getByTestId('children'); | |||
expect(children).toHaveTextContent('Foo'); | |||
}); | |||
it.each(Object.values(ActionButtonType))('renders a button with type %s', (buttonType) => { | |||
render( | |||
<ActionButton | |||
type={buttonType} | |||
/> | |||
); | |||
const button: HTMLButtonElement = screen.getByRole('button'); | |||
expect(button).toHaveProperty('type', buttonType); | |||
}); | |||
it('renders a disabled button', () => { | |||
render( | |||
<ActionButton | |||
disabled | |||
/> | |||
); | |||
const button: HTMLButtonElement = screen.getByRole('button'); | |||
expect(button).toBeDisabled(); | |||
}); | |||
}); |
@@ -1,172 +0,0 @@ | |||
import * as React from 'react'; | |||
import * as ButtonBase from '@tesseract-design/web-base-button'; | |||
/** | |||
* Available ActionButton type values. | |||
*/ | |||
export enum ActionButtonType { | |||
SUBMIT = 'submit', | |||
RESET = 'reset', | |||
BUTTON = 'button', | |||
} | |||
/** | |||
* Props for the component. | |||
*/ | |||
export interface ActionButtonProps extends Omit<React.HTMLProps<HTMLButtonElement>, 'size' | 'type' | 'style'> { | |||
/** | |||
* Size of the component. | |||
*/ | |||
size?: ButtonBase.ButtonSize, | |||
/** | |||
* Variant of the component. | |||
*/ | |||
variant?: ButtonBase.ButtonVariant, | |||
/** | |||
* Should the component display a border? | |||
*/ | |||
border?: boolean, | |||
/** | |||
* Should the component occupy the whole width of its parent? | |||
*/ | |||
block?: boolean, | |||
/** | |||
* Type of the component. | |||
*/ | |||
type?: ActionButtonType, | |||
/** | |||
* Does the component need to conserve space? | |||
*/ | |||
compact?: boolean, | |||
/** | |||
* Complementary content of the component. | |||
*/ | |||
subtext?: React.ReactNode, | |||
/** | |||
* Short complementary content displayed at the edge of the component. | |||
*/ | |||
badge?: React.ReactNode, | |||
/** | |||
* Is this component part of a menu? | |||
*/ | |||
menuItem?: boolean, | |||
} | |||
/** | |||
* Component for performing an action upon activation (e.g. when clicked). | |||
* | |||
* This component functions as a regular button. | |||
*/ | |||
export const ActionButton = React.forwardRef<HTMLButtonElement, ActionButtonProps>( | |||
( | |||
{ | |||
size = ButtonBase.ButtonSize.MEDIUM, | |||
variant = ButtonBase.ButtonVariant.OUTLINE, | |||
border = false, | |||
children, | |||
type = ActionButtonType.BUTTON, | |||
block = false, | |||
disabled = false, | |||
compact = false, | |||
subtext, | |||
badge, | |||
menuItem = false, | |||
className: _className, | |||
as: _as, | |||
...etcProps | |||
}: ActionButtonProps, | |||
ref, | |||
) => { | |||
const styleProps: ButtonBase.ButtonBaseArgs = { | |||
size, | |||
block, | |||
variant, | |||
border, | |||
compact, | |||
menuItem, | |||
disabled, | |||
}; | |||
return ( | |||
<button | |||
{...etcProps} | |||
disabled={disabled} | |||
className={ButtonBase.Button(styleProps)} | |||
ref={ref} | |||
type={type} | |||
> | |||
<span | |||
className={ButtonBase.Border(styleProps)} | |||
/> | |||
<span | |||
className={ButtonBase.Label(styleProps)} | |||
> | |||
<span | |||
className={ButtonBase.MainText()} | |||
data-testid="children" | |||
> | |||
<span | |||
className={ButtonBase.OverflowText()} | |||
> | |||
{children} | |||
</span> | |||
</span> | |||
{ | |||
subtext | |||
&& ( | |||
<> | |||
{' '} | |||
<span | |||
className={ButtonBase.Subtext()} | |||
data-testid="subtext" | |||
> | |||
<span | |||
className={ButtonBase.OverflowText()} | |||
> | |||
{subtext} | |||
</span> | |||
</span> | |||
</> | |||
) | |||
} | |||
</span> | |||
{ | |||
badge | |||
&& ( | |||
<> | |||
{' '} | |||
<span | |||
className={ButtonBase.BadgeContainer(styleProps)} | |||
data-testid="badge" | |||
> | |||
{badge} | |||
</span> | |||
</> | |||
) | |||
} | |||
{ | |||
menuItem | |||
&& ( | |||
<> | |||
{' '} | |||
<span | |||
className={ButtonBase.IndicatorWrapper(styleProps)} | |||
data-testid="menuItemIndicator" | |||
> | |||
<svg | |||
className={ButtonBase.Indicator()} | |||
viewBox="0 0 24 24" | |||
role="presentation" | |||
> | |||
<polyline points="9 18 15 12 9 6"/> | |||
</svg> | |||
</span> | |||
</> | |||
) | |||
} | |||
</button> | |||
); | |||
}, | |||
); | |||
ActionButton.displayName = 'ActionButton'; |
@@ -1,9 +0,0 @@ | |||
import * as WebActionReact from '.'; | |||
describe('web-action-react', () => { | |||
it.each([ | |||
'ActionButton', | |||
])('exports %s', (namedExport) => { | |||
expect(WebActionReact).toHaveProperty(namedExport); | |||
}); | |||
}); |
@@ -1,11 +0,0 @@ | |||
{ | |||
"exclude": ["node_modules"], | |||
"extends": "../../../../../tsconfig.json", | |||
"compilerOptions": { | |||
"lib": ["dom"], | |||
"rootDir": "src", | |||
"jsx": "react", | |||
"emitDeclarationOnly": true, | |||
"declaration": true | |||
} | |||
} |
@@ -1,9 +0,0 @@ | |||
import { defineConfig } from 'vitest/config' | |||
export default defineConfig({ | |||
test: { | |||
globals: true, | |||
environment: 'jsdom', | |||
setupFiles: ['setupTests.ts'], | |||
}, | |||
}) |
@@ -1,81 +0,0 @@ | |||
{ | |||
"name": "@tesseract-design/web-blob-react", | |||
"version": "0.0.0", | |||
"files": [ | |||
"dist", | |||
"src" | |||
], | |||
"engines": { | |||
"node": ">=12" | |||
}, | |||
"license": "MIT", | |||
"keywords": [ | |||
"pridepack" | |||
], | |||
"dependencies": { | |||
"@tesseract-design/web-base-blob": "link:../../../base/blob", | |||
"@tesseract-design/web-base-button": "link:../../../base/button" | |||
}, | |||
"devDependencies": { | |||
"@testing-library/jest-dom": "^5.16.5", | |||
"@testing-library/react": "^13.4.0", | |||
"@types/node": "^18.14.1", | |||
"@types/react": "^18.0.27", | |||
"eslint": "^8.35.0", | |||
"eslint-config-lxsmnsyc": "^0.5.0", | |||
"jsdom": "^21.1.0", | |||
"pridepack": "2.4.4", | |||
"react": "^18.2.0", | |||
"react-dom": "^18.2.0", | |||
"react-test-renderer": "^18.2.0", | |||
"tslib": "^2.5.0", | |||
"typescript": "^4.9.5", | |||
"vitest": "^0.28.1" | |||
}, | |||
"peerDependencies": { | |||
"react": "^16.8 || ^17.0 || ^18.0", | |||
"react-dom": "^16.8 || ^17.0 || ^18.0" | |||
}, | |||
"scripts": { | |||
"prepublishOnly": "pridepack clean && pridepack build", | |||
"build": "pridepack build", | |||
"type-check": "pridepack check", | |||
"lint": "pridepack lint", | |||
"clean": "pridepack clean", | |||
"watch": "pridepack watch", | |||
"start": "pridepack start", | |||
"dev": "pridepack dev", | |||
"test": "vitest" | |||
}, | |||
"private": true, | |||
"description": "Blob components for Tesseract for use in React.", | |||
"repository": { | |||
"url": "", | |||
"type": "git" | |||
}, | |||
"homepage": "", | |||
"bugs": { | |||
"url": "" | |||
}, | |||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | |||
"publishConfig": { | |||
"access": "restricted" | |||
}, | |||
"types": "./dist/types/index.d.ts", | |||
"main": "./dist/cjs/production/index.js", | |||
"module": "./dist/esm/production/index.js", | |||
"exports": { | |||
".": { | |||
"development": { | |||
"require": "./dist/cjs/development/index.js", | |||
"import": "./dist/esm/development/index.js" | |||
}, | |||
"require": "./dist/cjs/production/index.js", | |||
"import": "./dist/esm/production/index.js", | |||
"types": "./dist/types/index.d.ts" | |||
} | |||
}, | |||
"typesVersions": { | |||
"*": {} | |||
} | |||
} |