Implement components from the ground up using Tailwind styling.pull/1/head
@@ -23,7 +23,6 @@ | |||||
npm-debug.log* | npm-debug.log* | ||||
yarn-debug.log* | yarn-debug.log* | ||||
yarn-error.log* | yarn-error.log* | ||||
.pnpm-debug.log* | |||||
# local env files | # local env files | ||||
.env*.local | .env*.local |
@@ -8,6 +8,8 @@ First, run the development server: | |||||
npm run dev | npm run dev | ||||
# or | # or | ||||
yarn dev | yarn dev | ||||
# or | |||||
pnpm dev | |||||
``` | ``` | ||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. | 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. | 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 | ## Learn More | ||||
To learn more about Next.js, take a look at the following resources: | To learn more about Next.js, take a look at the following resources: |
@@ -1,7 +1,6 @@ | |||||
/** @type {import('next').NextConfig} */ | /** @type {import('next').NextConfig} */ | ||||
const nextConfig = { | const nextConfig = { | ||||
reactStrictMode: true, | reactStrictMode: true, | ||||
swcMinify: true, | |||||
} | } | ||||
module.exports = nextConfig | 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 * 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; | file: AudioFile; | ||||
} | } | ||||
export const AudioFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||||
export const AudioFilePreview: React.FC<AudioFilePreviewProps> = ({ | |||||
file: f, | 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 ( | return ( | ||||
<div className="flex flex-col gap-4 w-full h-full relative"> | <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} | title={f.type} | ||||
className="m-0 w-full text-ellipsis overflow-hidden" | className="m-0 w-full text-ellipsis overflow-hidden" | ||||
> | > | ||||
{getMimeTypeDescription(f.type)} | |||||
{getMimeTypeDescription(f.type, f.name)} | |||||
</dd> | </dd> | ||||
</div> | </div> | ||||
<div className="w-full"> | <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 * 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 { | export interface BinaryFilePreviewProps { | ||||
file: BinaryFile; | 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 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'> { | export interface FileButtonProps extends Omit<React.HTMLProps<HTMLInputElement>, 'size' | 'type' | 'style' | 'label' | 'list'> { | ||||
/** | /** | ||||
@@ -71,40 +57,6 @@ const useFilePreviews = (fileList?: FileList) => { | |||||
}), [selectedFiles]); | }), [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 = ({ | const FilePreviewGrid = ({ | ||||
fileList, | fileList, | ||||
}: { fileList?: FileList }) => { | }: { fileList?: FileList }) => { | ||||
@@ -212,10 +164,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||||
return ( | return ( | ||||
<div | <div | ||||
className={BlobBase.Root({ | |||||
border, | |||||
block, | |||||
})} | |||||
className="block" | |||||
onDragEnter={cancelEvent} | onDragEnter={cancelEvent} | ||||
onDragOver={cancelEvent} | onDragOver={cancelEvent} | ||||
onDrop={handleDropZone} | onDrop={handleDropZone} | ||||
@@ -240,12 +189,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||||
border && ( | border && ( | ||||
<span | <span | ||||
data-testid="border" | data-testid="border" | ||||
className={ | |||||
BlobBase.Border({ | |||||
border, | |||||
block, | |||||
}) | |||||
} | |||||
className="block" | |||||
/> | /> | ||||
) | ) | ||||
} | } | ||||
@@ -255,10 +199,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||||
&& ( | && ( | ||||
<div | <div | ||||
data-testid="label" | data-testid="label" | ||||
className={BlobBase.LabelWrapper({ | |||||
border, | |||||
block, | |||||
})} | |||||
className="block" | |||||
> | > | ||||
{label} | {label} | ||||
</div> | </div> | ||||
@@ -298,7 +239,15 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||||
{ | { | ||||
!multiple | !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> | </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="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"> | <div className="w-0 flex-auto flex flex-col items-center justify-center h-full"> | ||||
<span | <span | ||||
className={ButtonBase.Button({ | |||||
size: ButtonBase.ButtonSize.MEDIUM, | |||||
border: false, | |||||
block: true, | |||||
variant: ButtonBase.ButtonVariant.OUTLINE, | |||||
disabled, | |||||
compact: false, | |||||
menuItem: false, | |||||
})} | |||||
className="" | |||||
> | > | ||||
Reselect | Reselect | ||||
</span> | </span> | ||||
@@ -324,15 +265,7 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||||
data-testid="clear" | data-testid="clear" | ||||
type="button" | type="button" | ||||
onClick={deleteFiles} | 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'} | {multiple ? 'Clear' : 'Delete'} | ||||
</button> | </button> | ||||
@@ -347,22 +280,3 @@ export const FileSelectBox = React.forwardRef<HTMLInputElement, FileButtonProps> | |||||
); | ); | ||||
FileSelectBox.displayName = 'FileSelectBox'; | 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 * 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 { | export interface ImageFilePreviewProps { | ||||
file: ImageFile; | file: ImageFile; |
@@ -1,7 +1,7 @@ | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import Prism from 'prismjs'; | 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 { | export interface TextFilePreviewProps { | ||||
file: TextFile; | file: TextFile; |
@@ -1,6 +1,6 @@ | |||||
import * as React from 'react'; | 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 { | export interface VideoFilePreviewProps { | ||||
file: VideoFile; | file: VideoFile; |
@@ -1,15 +1,12 @@ | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import WaveSurfer from 'wavesurfer.js'; | 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; | file: AudioFile; | ||||
} | } | ||||
export const AudioMiniFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||||
file: f, | |||||
}) => { | |||||
export const useAudioFilePreviewControls = ({ file: f }: UseAudioFilePreviewControlsOptions) => { | |||||
const mediaContainerRef = React.useRef<HTMLDivElement>(null); | const mediaContainerRef = React.useRef<HTMLDivElement>(null); | ||||
const mediaControllerRef = React.useRef<WaveSurfer>(null); | const mediaControllerRef = React.useRef<WaveSurfer>(null); | ||||
const [isPlaying, setIsPlaying] = React.useState(false); | const [isPlaying, setIsPlaying] = React.useState(false); | ||||
@@ -41,10 +38,14 @@ export const AudioMiniFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||||
} | } | ||||
mediaContainerRef.current.innerHTML = ''; | mediaContainerRef.current.innerHTML = ''; | ||||
if (f.type === 'audio/mid') { | |||||
return; | |||||
} | |||||
const mediaControllerRefMutable = mediaControllerRef as React.MutableRefObject<WaveSurfer>; | const mediaControllerRefMutable = mediaControllerRef as React.MutableRefObject<WaveSurfer>; | ||||
mediaControllerRefMutable.current = WaveSurfer.create({ | mediaControllerRefMutable.current = WaveSurfer.create({ | ||||
container: mediaContainerRef.current, | container: mediaContainerRef.current, | ||||
url: f.metadata.previewUrl, | |||||
cursorWidth: 0, | cursorWidth: 0, | ||||
height: mediaContainerRef.current.offsetHeight, | height: mediaContainerRef.current.offsetHeight, | ||||
barWidth: 2, | barWidth: 2, | ||||
@@ -57,6 +58,10 @@ export const AudioMiniFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||||
mediaControllerRefMutable.current.seekTo(0); | mediaControllerRefMutable.current.seekTo(0); | ||||
}); | }); | ||||
// TODO get the preview URL here | |||||
mediaControllerRefMutable.current.load(f.metadata.previewUrl); | |||||
return () => { | return () => { | ||||
if (!mediaControllerRefMutable.current) { | if (!mediaControllerRefMutable.current) { | ||||
return; | return; | ||||
@@ -66,15 +71,17 @@ export const AudioMiniFilePreview: React.FC<VideoFilePreviewProps> = ({ | |||||
} | } | ||||
}, [f, mediaContainerRef, mediaControllerRef]); | }, [f, mediaContainerRef, mediaControllerRef]); | ||||
const playMedia = () => { | |||||
const playMedia = React.useCallback(() => { | |||||
setIsPlaying((p) => !p); | 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> | </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 { NextPage } from 'next'; | ||||
import { ButtonSize, ButtonVariant } from '@tesseract-design/web-base-button'; | import { ButtonSize, ButtonVariant } from '@tesseract-design/web-base-button'; | ||||
import * as Action from '@tesseract-design/web-action-react'; | import * as Action from '@tesseract-design/web-action-react'; | ||||
import { DefaultLayout } from 'src/components/DefaultLayout'; | |||||
import { DefaultLayout } from '@/components/DefaultLayout'; | |||||
const ActionPage: NextPage = () => { | const ActionPage: NextPage = () => { | ||||
return ( | return ( | ||||
@@ -21,6 +21,7 @@ const ActionPage: NextPage = () => { | |||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 my-4"> | <div className="grid grid-cols-1 md:grid-cols-2 gap-4 my-4"> | ||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
variant="bare" | |||||
block | block | ||||
> | > | ||||
Button | Button | ||||
@@ -28,7 +29,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
block | block | ||||
> | > | ||||
Button | Button | ||||
@@ -36,7 +37,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
border | |||||
variant="outline" | |||||
block | block | ||||
> | > | ||||
Button | Button | ||||
@@ -44,8 +45,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
block | block | ||||
> | > | ||||
Button | Button | ||||
@@ -53,6 +53,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
variant="bare" | |||||
block | block | ||||
disabled | disabled | ||||
> | > | ||||
@@ -61,7 +62,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
block | block | ||||
disabled | disabled | ||||
> | > | ||||
@@ -70,7 +71,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
border | |||||
variant="outline" | |||||
block | block | ||||
disabled | disabled | ||||
> | > | ||||
@@ -79,8 +80,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
block | block | ||||
disabled | disabled | ||||
> | > | ||||
@@ -97,8 +97,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
border | |||||
size={ButtonSize.SMALL} | |||||
variant="outline" | |||||
size="small" | |||||
> | > | ||||
Button | Button | ||||
</Action.ActionButton> | </Action.ActionButton> | ||||
@@ -106,9 +106,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
size={ButtonSize.SMALL} | |||||
variant="filled" | |||||
size="small" | |||||
> | > | ||||
Button | Button | ||||
</Action.ActionButton> | </Action.ActionButton> | ||||
@@ -116,8 +115,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
border | |||||
size={ButtonSize.MEDIUM} | |||||
variant="outline" | |||||
size="medium" | |||||
> | > | ||||
Button | Button | ||||
</Action.ActionButton> | </Action.ActionButton> | ||||
@@ -125,9 +124,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
size={ButtonSize.MEDIUM} | |||||
variant="filled" | |||||
size="medium" | |||||
> | > | ||||
Button | Button | ||||
</Action.ActionButton> | </Action.ActionButton> | ||||
@@ -135,8 +133,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
border | |||||
size={ButtonSize.LARGE} | |||||
variant="outline" | |||||
size="large" | |||||
> | > | ||||
Button | Button | ||||
</Action.ActionButton> | </Action.ActionButton> | ||||
@@ -144,9 +142,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
size={ButtonSize.LARGE} | |||||
variant="filled" | |||||
size="large" | |||||
> | > | ||||
Button | Button | ||||
</Action.ActionButton> | </Action.ActionButton> | ||||
@@ -162,7 +159,7 @@ const ActionPage: NextPage = () => { | |||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant="outline" | |||||
> | > | ||||
Button | Button | ||||
</Action.ActionButton> | </Action.ActionButton> | ||||
@@ -171,8 +168,7 @@ const ActionPage: NextPage = () => { | |||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
> | > | ||||
Button | Button | ||||
</Action.ActionButton> | </Action.ActionButton> | ||||
@@ -181,7 +177,7 @@ const ActionPage: NextPage = () => { | |||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant="outline" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Subtext | Subtext | ||||
@@ -195,8 +191,7 @@ const ActionPage: NextPage = () => { | |||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Subtext | Subtext | ||||
@@ -210,8 +205,8 @@ const ActionPage: NextPage = () => { | |||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
size={ButtonSize.SMALL} | |||||
variant="outline" | |||||
size="small" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Subtext | Subtext | ||||
@@ -225,9 +220,8 @@ const ActionPage: NextPage = () => { | |||||
<Action.ActionButton | <Action.ActionButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
size={ButtonSize.SMALL} | |||||
variant="filled" | |||||
size="small" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Very Long Line of Subtext That Spans More Than The Component Width For Testing Overflow | 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 { NextPage } from 'next'; | ||||
import { DefaultLayout } from 'src/components/DefaultLayout'; | |||||
import { DefaultLayout } from '@/components/DefaultLayout'; | |||||
const CodePage: NextPage = () => { | const CodePage: NextPage = () => { | ||||
return ( | 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 className="grid md:grid-cols-2 gap-4 my-4"> | ||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | |||||
variant="bare" | |||||
href="#" | href="#" | ||||
block | |||||
> | > | ||||
Button | Button | ||||
</Navigation.LinkButton> | </Navigation.LinkButton> | ||||
</div> | </div> | ||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
block | block | ||||
href="#" | href="#" | ||||
> | > | ||||
@@ -40,7 +41,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
border | |||||
variant="outline" | |||||
block | block | ||||
href="#" | href="#" | ||||
> | > | ||||
@@ -49,8 +50,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
block | block | ||||
href="#" | href="#" | ||||
> | > | ||||
@@ -62,13 +62,14 @@ const ActionPage: NextPage = () => { | |||||
block | block | ||||
disabled | disabled | ||||
href="#" | href="#" | ||||
variant="bare" | |||||
> | > | ||||
Button | Button | ||||
</Navigation.LinkButton> | </Navigation.LinkButton> | ||||
</div> | </div> | ||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
block | block | ||||
disabled | disabled | ||||
href="#" | href="#" | ||||
@@ -78,7 +79,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
border | |||||
variant="outline" | |||||
block | block | ||||
disabled | disabled | ||||
href="#" | href="#" | ||||
@@ -88,8 +89,7 @@ const ActionPage: NextPage = () => { | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
block | block | ||||
disabled | disabled | ||||
href="#" | href="#" | ||||
@@ -107,8 +107,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
size={ButtonSize.SMALL} | |||||
variant="outline" | |||||
size="small" | |||||
href="#" | href="#" | ||||
> | > | ||||
Button | Button | ||||
@@ -117,9 +117,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
size={ButtonSize.SMALL} | |||||
variant="filled" | |||||
size="small" | |||||
href="#" | href="#" | ||||
> | > | ||||
Button | Button | ||||
@@ -128,8 +127,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
size={ButtonSize.MEDIUM} | |||||
variant="outline" | |||||
size="medium" | |||||
href="#" | href="#" | ||||
> | > | ||||
Button | Button | ||||
@@ -138,9 +137,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
size={ButtonSize.MEDIUM} | |||||
variant="filled" | |||||
size="medium" | |||||
href="#" | href="#" | ||||
> | > | ||||
Button | Button | ||||
@@ -149,8 +147,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
size={ButtonSize.LARGE} | |||||
variant="outline" | |||||
size="large" | |||||
href="#" | href="#" | ||||
> | > | ||||
Button | Button | ||||
@@ -159,9 +157,8 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
size={ButtonSize.LARGE} | |||||
variant="filled" | |||||
size="large" | |||||
href="#" | href="#" | ||||
> | > | ||||
Button | Button | ||||
@@ -178,7 +175,7 @@ const ActionPage: NextPage = () => { | |||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant="outline" | |||||
href="#" | href="#" | ||||
> | > | ||||
Button | Button | ||||
@@ -188,8 +185,7 @@ const ActionPage: NextPage = () => { | |||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
href="#" | href="#" | ||||
> | > | ||||
Button | Button | ||||
@@ -198,7 +194,7 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
variant="outline" | |||||
compact | compact | ||||
subtext={ | subtext={ | ||||
<> | <> | ||||
@@ -214,8 +210,7 @@ const ActionPage: NextPage = () => { | |||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Subtext | Subtext | ||||
@@ -229,9 +224,9 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
variant="outline" | |||||
compact | compact | ||||
size={ButtonSize.SMALL} | |||||
size="small" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Subtext | Subtext | ||||
@@ -253,9 +248,8 @@ const ActionPage: NextPage = () => { | |||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
size={ButtonSize.SMALL} | |||||
variant="filled" | |||||
size="small" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Subtext | Subtext | ||||
@@ -276,9 +270,9 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
variant="outline" | |||||
compact | compact | ||||
size={ButtonSize.LARGE} | |||||
size="large" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Subtext | Subtext | ||||
@@ -300,9 +294,8 @@ const ActionPage: NextPage = () => { | |||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
size={ButtonSize.LARGE} | |||||
variant="filled" | |||||
size="large" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Subtext | Subtext | ||||
@@ -323,10 +316,10 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
variant="outline" | |||||
compact | compact | ||||
menuItem | menuItem | ||||
size={ButtonSize.SMALL} | |||||
size="small" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Subtext | Subtext | ||||
@@ -348,9 +341,8 @@ const ActionPage: NextPage = () => { | |||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
size={ButtonSize.SMALL} | |||||
variant={ButtonVariant.FILLED} | |||||
size="small" | |||||
variant="filled" | |||||
menuItem | menuItem | ||||
subtext={ | subtext={ | ||||
<> | <> | ||||
@@ -372,7 +364,7 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
variant="outline" | |||||
compact | compact | ||||
menuItem | menuItem | ||||
subtext={ | subtext={ | ||||
@@ -396,8 +388,7 @@ const ActionPage: NextPage = () => { | |||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
menuItem | menuItem | ||||
subtext={ | subtext={ | ||||
<> | <> | ||||
@@ -419,10 +410,10 @@ const ActionPage: NextPage = () => { | |||||
<div> | <div> | ||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
border | |||||
variant="outline" | |||||
compact | compact | ||||
menuItem | menuItem | ||||
size={ButtonSize.LARGE} | |||||
size="large" | |||||
subtext={ | subtext={ | ||||
<> | <> | ||||
Subtext | Subtext | ||||
@@ -444,9 +435,8 @@ const ActionPage: NextPage = () => { | |||||
<Navigation.LinkButton | <Navigation.LinkButton | ||||
block | block | ||||
compact | compact | ||||
border | |||||
size={ButtonSize.LARGE} | |||||
variant={ButtonVariant.FILLED} | |||||
size="large" | |||||
variant="filled" | |||||
menuItem | menuItem | ||||
subtext={ | subtext={ | ||||
<> | <> |
@@ -1,9 +1,9 @@ | |||||
import { NextPage } from 'next'; | 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 Option from '@tesseract-design/web-option-react'; | ||||
import * as SelectControlBase from '@tesseract-design/web-base-selectcontrol'; | import * as SelectControlBase from '@tesseract-design/web-base-selectcontrol'; | ||||
import { ButtonSize, ButtonVariant } from '@tesseract-design/web-base-button'; | import { ButtonSize, ButtonVariant } from '@tesseract-design/web-base-button'; | ||||
import { DefaultLayout } from 'src/components/DefaultLayout'; | |||||
import { DefaultLayout } from '@/components/DefaultLayout'; | |||||
type Props = { | type Props = { | ||||
options: SelectControlBase.SelectOption[], | options: SelectControlBase.SelectOption[], | ||||
@@ -216,7 +216,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div className="grid md:grid-cols-2 gap-4"> | <div className="grid md:grid-cols-2 gap-4"> | ||||
<div> | <div> | ||||
<Option.DropdownSelect | <Option.DropdownSelect | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.SMALL} | size={TextControlSize.SMALL} | ||||
label="Select" | label="Select" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -227,7 +227,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.DropdownSelect | <Option.DropdownSelect | ||||
border | border | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.SMALL} | size={TextControlSize.SMALL} | ||||
label="Select" | label="Select" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -237,7 +237,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.DropdownSelect | <Option.DropdownSelect | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="Select" | label="Select" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
block | block | ||||
@@ -247,7 +247,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.DropdownSelect | <Option.DropdownSelect | ||||
border | border | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="Select" | label="Select" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
block | block | ||||
@@ -256,7 +256,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.DropdownSelect | <Option.DropdownSelect | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.LARGE} | size={TextControlSize.LARGE} | ||||
label="Select" | label="Select" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -268,7 +268,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<Option.DropdownSelect | <Option.DropdownSelect | ||||
border | border | ||||
block | block | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.LARGE} | size={TextControlSize.LARGE} | ||||
label="Select" | label="Select" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -277,7 +277,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.DropdownSelect | <Option.DropdownSelect | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="Select" | label="Select" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
block | block | ||||
@@ -287,7 +287,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.DropdownSelect | <Option.DropdownSelect | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
border | border | ||||
label="Select" | label="Select" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -405,7 +405,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div className="grid md:grid-cols-2 gap-4"> | <div className="grid md:grid-cols-2 gap-4"> | ||||
<div> | <div> | ||||
<Option.MenuSelect | <Option.MenuSelect | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.SMALL} | size={TextControlSize.SMALL} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -417,7 +417,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.MenuSelect | <Option.MenuSelect | ||||
border | border | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.SMALL} | size={TextControlSize.SMALL} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -428,7 +428,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.MenuSelect | <Option.MenuSelect | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -439,7 +439,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.MenuSelect | <Option.MenuSelect | ||||
border | border | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -449,7 +449,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.MenuSelect | <Option.MenuSelect | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.LARGE} | size={TextControlSize.LARGE} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -462,7 +462,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<Option.MenuSelect | <Option.MenuSelect | ||||
border | border | ||||
block | block | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.LARGE} | size={TextControlSize.LARGE} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -472,7 +472,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.MenuSelect | <Option.MenuSelect | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -483,7 +483,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.MenuSelect | <Option.MenuSelect | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
border | border | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -976,7 +976,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
enhanced | enhanced | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.SMALL} | size={TextControlSize.SMALL} | ||||
label="TagInput" | label="TagInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -988,7 +988,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<Option.TagInput | <Option.TagInput | ||||
enhanced | enhanced | ||||
border | border | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.SMALL} | size={TextControlSize.SMALL} | ||||
label="TagInput" | label="TagInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -999,7 +999,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
enhanced | enhanced | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="TagInput" | label="TagInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -1010,7 +1010,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<Option.TagInput | <Option.TagInput | ||||
enhanced | enhanced | ||||
border | border | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="TagInput" | label="TagInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -1020,7 +1020,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
enhanced | enhanced | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.LARGE} | size={TextControlSize.LARGE} | ||||
label="TagInput" | label="TagInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1033,7 +1033,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
enhanced | enhanced | ||||
border | border | ||||
block | block | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.LARGE} | size={TextControlSize.LARGE} | ||||
label="TagInput" | label="TagInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1043,7 +1043,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
enhanced | enhanced | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="TagInput" | label="TagInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -1054,7 +1054,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
enhanced | enhanced | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
border | border | ||||
label="TagInput" | label="TagInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1511,7 +1511,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div className="grid md:grid-cols-2 gap-4"> | <div className="grid md:grid-cols-2 gap-4"> | ||||
<div> | <div> | ||||
<Option.ComboBox | <Option.ComboBox | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.SMALL} | size={TextControlSize.SMALL} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1523,7 +1523,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.ComboBox | <Option.ComboBox | ||||
border | border | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.SMALL} | size={TextControlSize.SMALL} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1534,7 +1534,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.ComboBox | <Option.ComboBox | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -1545,7 +1545,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.ComboBox | <Option.ComboBox | ||||
border | border | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -1555,7 +1555,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.ComboBox | <Option.ComboBox | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.LARGE} | size={TextControlSize.LARGE} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1568,7 +1568,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<Option.ComboBox | <Option.ComboBox | ||||
border | border | ||||
block | block | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.LARGE} | size={TextControlSize.LARGE} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1578,7 +1578,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.ComboBox | <Option.ComboBox | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -1589,7 +1589,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.ComboBox | <Option.ComboBox | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
border | border | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1700,7 +1700,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div className="grid md:grid-cols-2 gap-4"> | <div className="grid md:grid-cols-2 gap-4"> | ||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.SMALL} | size={TextControlSize.SMALL} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1711,7 +1711,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
border | border | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.SMALL} | size={TextControlSize.SMALL} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1721,7 +1721,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -1731,7 +1731,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
border | border | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -1740,7 +1740,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.LARGE} | size={TextControlSize.LARGE} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1752,7 +1752,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
<Option.TagInput | <Option.TagInput | ||||
border | border | ||||
block | block | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
size={TextControlSize.LARGE} | size={TextControlSize.LARGE} | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
@@ -1761,7 +1761,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" | ||||
indicator="A" | indicator="A" | ||||
@@ -1771,7 +1771,7 @@ const OptionPage: NextPage<Props> = ({ | |||||
</div> | </div> | ||||
<div> | <div> | ||||
<Option.TagInput | <Option.TagInput | ||||
style={TextControlStyle.ALTERNATE} | |||||
style={TextControlVariant.ALTERNATE} | |||||
border | border | ||||
label="MultilineTextInput" | label="MultilineTextInput" | ||||
hint="Type anything here…" | hint="Type anything here…" |
@@ -69,10 +69,9 @@ const RegistrationFormPage: NextPage = () => { | |||||
{' '} | {' '} | ||||
<div> | <div> | ||||
<Action.ActionButton | <Action.ActionButton | ||||
variant={ButtonVariant.FILLED} | |||||
variant="filled" | |||||
block | block | ||||
border | |||||
type={Action.ActionButtonType.SUBMIT} | |||||
type="submit" | |||||
menuItem | menuItem | ||||
subtext="Registration requires activation" | subtext="Registration requires activation" | ||||
> | > |
@@ -21,18 +21,15 @@ const createPageLink = (p: Page) => ( | |||||
<div | <div | ||||
key={p.id} | key={p.id} | ||||
> | > | ||||
<Link | |||||
<Navigation.LinkButton | |||||
block | |||||
variant="outline" | |||||
menuItem | |||||
component={Link} | |||||
href={p.href} | href={p.href} | ||||
passHref | |||||
> | > | ||||
<Navigation.LinkButton | |||||
block | |||||
border | |||||
menuItem | |||||
> | |||||
{p.label} | |||||
</Navigation.LinkButton> | |||||
</Link> | |||||
{p.label} | |||||
</Navigation.LinkButton> | |||||
</div> | </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": { | |||||
"*": {} | |||||
} | |||||
} |