@@ -0,0 +1,9 @@ | |||
# tesseract | |||
Simple, accessible, and robust Web components for data-driven documents and apps. | |||
Tesseract supports the following frameworks: | |||
- [React](/web/react) | |||
- [Vue](/web/vue) (TODO) | |||
- [Solid](/web/solid) (TODO) |
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -2,6 +2,10 @@ import * as React from 'react'; | |||
import { useClientSide, useFallbackId, useProxyInput } from '@modal-sh/react-utils'; | |||
import clsx from 'clsx'; | |||
/** | |||
* Common props for the {@link FileSelectBoxProps.previewComponent|previewComponent prop} of the | |||
* {@link FileSelectBox} component. | |||
*/ | |||
export interface CommonPreviewComponentProps<F extends Partial<File> = Partial<File>> { | |||
/** | |||
* The file to preview. | |||
@@ -21,8 +25,14 @@ export interface CommonPreviewComponentProps<F extends Partial<File> = Partial<F | |||
mini?: boolean; | |||
} | |||
/** | |||
* Derived HTML element of the {@link FileSelectBox} component. | |||
*/ | |||
export type FileSelectBoxDerivedElement = HTMLInputElement; | |||
/** | |||
* Props of the {@link FileSelectBox} component. | |||
*/ | |||
export interface FileSelectBoxProps< | |||
F extends Partial<File> = Partial<File>, | |||
P extends CommonPreviewComponentProps<F> = CommonPreviewComponentProps<F> | |||
@@ -57,6 +67,10 @@ export interface FileSelectBoxProps< | |||
previewComponent?: React.ElementType<P>, | |||
} | |||
/** | |||
* Default component for the {@link FileSelectBoxProps.previewComponent|previewComponent prop} | |||
* of the {@link FileSelectBox} component. | |||
*/ | |||
export const FileSelectBoxDefaultPreviewComponent = React.forwardRef< | |||
HTMLDivElement, | |||
CommonPreviewComponentProps | |||
@@ -113,6 +127,9 @@ export const FileSelectBoxDefaultPreviewComponent = React.forwardRef< | |||
</div> | |||
)); | |||
/** | |||
* Component for selecting files. | |||
*/ | |||
export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileSelectBoxProps>(( | |||
{ | |||
label = '', | |||
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -2,8 +2,14 @@ import * as React from 'react'; | |||
import clsx from 'clsx'; | |||
import plugin from 'tailwindcss/plugin'; | |||
/** | |||
* Derived HTML element of the {@link ColorPicker} component. | |||
*/ | |||
export type ColorPickerDerivedElement = HTMLInputElement; | |||
/** | |||
* Props of the {@link ColorPicker} component. | |||
*/ | |||
export interface ColorPickerProps extends Omit<React.HTMLProps<ColorPickerDerivedElement>, 'size' | 'type' | 'label'> { | |||
square?: boolean; | |||
size?: 'small' | 'medium' | 'large'; | |||
@@ -25,6 +31,9 @@ export const colorPickerPlugin = plugin(({ addComponents }) => { | |||
}); | |||
}); | |||
/** | |||
* Component for picking a color. | |||
*/ | |||
export const ColorPicker = React.forwardRef< | |||
ColorPickerDerivedElement, | |||
ColorPickerProps | |||
@@ -3,12 +3,18 @@ import clsx from 'clsx'; | |||
import Color from 'color'; | |||
import * as convert from 'color-convert'; | |||
/** | |||
* Derived HTML element of the {@link Swatch} component. | |||
*/ | |||
export type SwatchDerivedElement = HTMLInputElement; | |||
type ColorValue = ConstructorParameters<typeof Color>[0]; | |||
type ColorMode = keyof typeof convert; | |||
/** | |||
* Props of the {@link Swatch} component. | |||
*/ | |||
export interface SwatchProps extends Omit<React.HTMLProps<SwatchDerivedElement>, 'color'> { | |||
color: NonNullable<ColorValue>; | |||
mode?: ColorMode; | |||
@@ -26,6 +32,9 @@ export const useSwatchControls = () => { | |||
}), [id, copyColor]); | |||
}; | |||
/** | |||
* Component for displaying a color. | |||
*/ | |||
export const Swatch = React.forwardRef<SwatchDerivedElement, SwatchProps>(({ | |||
// todo unify color and mode into one "value" attribute | |||
color, | |||
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -5,23 +5,23 @@ import { useClientSide, useFallbackId, useProxyInput } from '@modal-sh/react-uti | |||
import { TextControl } from '@tesseract-design/web-base'; | |||
import plugin from 'tailwindcss/plugin'; | |||
const TAG_INPUT_SEPARATOR_MAP = { | |||
/** | |||
* Separator for splitting the input value into multiple tags. | |||
*/ | |||
export type TagInputSeparator = 'comma' | 'newline' | 'semicolon'; | |||
const TAG_INPUT_SEPARATOR_MAP: Record<TagInputSeparator, string> = { | |||
'comma': ',', | |||
'newline': 'Enter', | |||
'semicolon': ';', | |||
} as const; | |||
const TAG_INPUT_VALUE_SEPARATOR_MAP = { | |||
const TAG_INPUT_VALUE_SEPARATOR_MAP: Record<TagInputSeparator, string> = { | |||
'comma': ',', | |||
'newline': '\n', | |||
'semicolon': ';', | |||
} as const; | |||
/** | |||
* Separator for splitting the input value into multiple tags. | |||
*/ | |||
export type TagInputSeparator = keyof typeof TAG_INPUT_SEPARATOR_MAP | |||
/** | |||
* Derived HTML element of the {@link TagInput} component. | |||
*/ | |||
@@ -263,12 +263,9 @@ export const TagInput = React.forwardRef<TagInputDerivedElement, TagInputProps>( | |||
valueSetterFn: (v) => { | |||
setTags(v); | |||
}, | |||
transformChangeHandlerArgs: (newTags) => { | |||
const thisNewTags = newTags as string[]; | |||
return ( | |||
thisNewTags.map((t) => t.trim()).join(TAG_INPUT_VALUE_SEPARATOR_MAP[valueSeparator]) | |||
); | |||
}, | |||
transformChangeHandlerArgs: (newTags) => ( | |||
newTags.map((t) => t.trim()).join(TAG_INPUT_VALUE_SEPARATOR_MAP[valueSeparator]) | |||
), | |||
}); | |||
const ref = forwardedRef ?? defaultRef; | |||
const labelId = React.useId(); | |||
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -49,6 +49,9 @@ export interface LinkButtonProps<T = any> extends Omit<React.HTMLProps<LinkButto | |||
disabled?: boolean; | |||
} | |||
/** | |||
* Component for performing a navigation action. | |||
*/ | |||
export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonProps>(( | |||
{ | |||
variant = 'bare' as const, | |||
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -15,7 +15,11 @@ type Segment = `${Digit}${Digit}`; | |||
type StepHhMm = `${Segment}:${Segment}`; | |||
type StepHhMmSs = `${StepHhMm}:${Segment}`; | |||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment | |||
// @ts-ignore | |||
// type StepHhMmSs = `${StepHhMm}:${Segment}`; | |||
type StepHhMmSs = string; | |||
type Step = StepHhMm | StepHhMmSs; | |||
@@ -58,7 +62,7 @@ export interface TimeSpinnerProps extends Omit<React.HTMLProps<TimeSpinnerDerive | |||
/** | |||
* Step size for the component. | |||
*/ | |||
step?: Step, | |||
step?: Step | string, | |||
} | |||
export const timeSpinnerPlugin = plugin(({ addComponents }) => { | |||
@@ -114,7 +118,7 @@ export const TimeSpinner = React.forwardRef< | |||
const labelId = React.useId(); | |||
const id = useFallbackId(idProp); | |||
const [hh, mm, ss = 0] = step.split(':').map((s: string) => parseInt(s, 10)) as number[]; | |||
const [hh, mm, ss = 0] = step.split(':').map((s: string) => parseInt(s, 10)); | |||
const stepValue = ss + (mm * 60) + (hh * 3600); | |||
return ( | |||
@@ -0,0 +1,8 @@ | |||
{ | |||
"extends": ["../../../typedoc.base.json"], | |||
"exclude": ["**/*.test.(ts|tsx)", "**/node_modules/**"], | |||
"entryPoints": ["src/index.ts"], | |||
"excludeNotDocumented": true, | |||
"includeVersion": true, | |||
"tsconfig": "../../../tsconfig.json" | |||
} |
@@ -1,4 +1,4 @@ | |||
# Tesseract | |||
# Philosophy | |||
## Design | |||
- Tesseract components follow a strict and simple design philosophy. | |||
@@ -1238,6 +1238,9 @@ importers: | |||
tailwindcss: | |||
specifier: 0.0.0-insiders.7f31ac1 | |||
version: 0.0.0-insiders.7f31ac1 | |||
typedoc: | |||
specifier: ^0.24.8 | |||
version: 0.24.8(typescript@5.1.3) | |||
packages: | |||
@@ -2634,6 +2637,10 @@ packages: | |||
engines: {node: '>=12'} | |||
dev: true | |||
/ansi-sequence-parser@1.1.1: | |||
resolution: {integrity: sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==} | |||
dev: true | |||
/ansi-styles@3.2.1: | |||
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} | |||
engines: {node: '>=4'} | |||
@@ -2843,6 +2850,12 @@ packages: | |||
balanced-match: 1.0.2 | |||
concat-map: 0.0.1 | |||
/brace-expansion@2.0.1: | |||
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} | |||
dependencies: | |||
balanced-match: 1.0.2 | |||
dev: true | |||
/braces@3.0.2: | |||
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} | |||
engines: {node: '>=8'} | |||
@@ -5446,6 +5459,10 @@ packages: | |||
dependencies: | |||
yallist: 4.0.0 | |||
/lunr@2.3.9: | |||
resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} | |||
dev: true | |||
/lz-string@1.5.0: | |||
resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} | |||
hasBin: true | |||
@@ -5465,6 +5482,12 @@ packages: | |||
semver: 6.3.0 | |||
dev: true | |||
/marked@4.3.0: | |||
resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} | |||
engines: {node: '>= 12'} | |||
hasBin: true | |||
dev: true | |||
/mdast-util-definitions@5.1.2: | |||
resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==} | |||
dependencies: | |||
@@ -5728,6 +5751,13 @@ packages: | |||
dependencies: | |||
brace-expansion: 1.1.11 | |||
/minimatch@9.0.3: | |||
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} | |||
engines: {node: '>=16 || 14 >=14.17'} | |||
dependencies: | |||
brace-expansion: 2.0.1 | |||
dev: true | |||
/minimist@1.2.8: | |||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} | |||
@@ -6763,6 +6793,15 @@ packages: | |||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} | |||
engines: {node: '>=8'} | |||
/shiki@0.14.3: | |||
resolution: {integrity: sha512-U3S/a+b0KS+UkTyMjoNojvTgrBHjgp7L6ovhFVZsXmBGnVdQ4K4U9oK0z63w538S91ATngv1vXigHCSWOwnr+g==} | |||
dependencies: | |||
ansi-sequence-parser: 1.1.1 | |||
jsonc-parser: 3.2.0 | |||
vscode-oniguruma: 1.7.0 | |||
vscode-textmate: 8.0.0 | |||
dev: true | |||
/side-channel@1.0.4: | |||
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} | |||
dependencies: | |||
@@ -7330,6 +7369,20 @@ packages: | |||
is-typedarray: 1.0.0 | |||
dev: true | |||
/typedoc@0.24.8(typescript@5.1.3): | |||
resolution: {integrity: sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==} | |||
engines: {node: '>= 14.14'} | |||
hasBin: true | |||
peerDependencies: | |||
typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x | |||
dependencies: | |||
lunr: 2.3.9 | |||
marked: 4.3.0 | |||
minimatch: 9.0.3 | |||
shiki: 0.14.3 | |||
typescript: 5.1.3 | |||
dev: true | |||
/typescript@4.9.5: | |||
resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} | |||
engines: {node: '>=4.2.0'} | |||
@@ -7713,6 +7766,14 @@ packages: | |||
- terser | |||
dev: true | |||
/vscode-oniguruma@1.7.0: | |||
resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} | |||
dev: true | |||
/vscode-textmate@8.0.0: | |||
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} | |||
dev: true | |||
/vue-eslint-parser@9.3.1(eslint@8.43.0): | |||
resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==} | |||
engines: {node: ^14.17.0 || >=16.0.0} | |||
@@ -33,3 +33,5 @@ yarn-error.log* | |||
# typescript | |||
*.tsbuildinfo | |||
next-env.d.ts | |||
typedoc.data.json |
@@ -3,6 +3,7 @@ | |||
"version": "0.1.0", | |||
"private": true, | |||
"scripts": { | |||
"typedoc": "", | |||
"dev": "next dev", | |||
"build": "next build", | |||
"start": "next start", | |||
@@ -47,6 +48,7 @@ | |||
"typescript": "5.1.3" | |||
}, | |||
"devDependencies": { | |||
"tailwindcss": "0.0.0-insiders.7f31ac1" | |||
"tailwindcss": "0.0.0-insiders.7f31ac1", | |||
"typedoc": "^0.24.8" | |||
} | |||
} |
@@ -7,7 +7,7 @@ export const Brand = () => { | |||
Tesseract | |||
</span> | |||
{' '} | |||
<span className="absolute left-2 top-4 font-semibold"> | |||
<span className="absolute left-4 top-4 font-semibold"> | |||
Web | |||
</span> | |||
{' '} | |||
@@ -17,7 +17,7 @@ export const Brand = () => { | |||
<span className="sr-only">)</span> | |||
</span> | |||
{' '} | |||
<span className="absolute right-1 top-4 font-black text-xs"> | |||
<span className="absolute right-0 top-4 font-black text-xs"> | |||
v.0.1.0 | |||
</span> | |||
</span> | |||
@@ -0,0 +1,203 @@ | |||
import * as React from 'react'; | |||
import {Layouts, Widgets} from '@tesseract-design/viewfinder-react'; | |||
import Link from 'next/link'; | |||
import {Brand} from '@/components/Brand'; | |||
import {DropdownSelect} from '@tesseract-design/web-choice-react'; | |||
export interface Page { | |||
id: string; | |||
href: string; | |||
label: string; | |||
} | |||
export interface DocsLayoutProps { | |||
componentPages?: { name: string; components: Page[] }[]; | |||
docsPages?: Page[]; | |||
examplePages?: Page[]; | |||
sidebarOpen?: boolean; | |||
children?: React.ReactNode; | |||
} | |||
const createSidebarPageLink = (p: Page) => ( | |||
<div | |||
key={p.id} | |||
> | |||
<Link | |||
href={p.href} | |||
className="no-underline font-semibold m-0 p-0 leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
<Layouts.LeftSidebar.SidebarContentContainer> | |||
{p.label} | |||
</Layouts.LeftSidebar.SidebarContentContainer> | |||
</Link> | |||
</div> | |||
); | |||
export const DocsLayout: React.FC<DocsLayoutProps> = ({ | |||
sidebarOpen = false, | |||
componentPages = [], | |||
docsPages = [], | |||
examplePages = [], | |||
children, | |||
}) => { | |||
return ( | |||
<Layouts.LeftSidebar.Root | |||
topBarWidget={ | |||
<Widgets.TopBar | |||
span="wide" | |||
brand={ | |||
<Link | |||
href="/" | |||
className="no-underline block" | |||
> | |||
<Brand /> | |||
</Link> | |||
} | |||
menuLink={ | |||
<Link | |||
href={{ | |||
query: { | |||
open: 'sidebar', | |||
}, | |||
}} | |||
className="no-underline p-0 m-0" | |||
> | |||
<svg | |||
className="w-6 h-6 fill-none stroke-current stroke-2 linejoin-round linecap-round" | |||
viewBox="0 0 24 24" | |||
role="presentation" | |||
> | |||
<line x1="3" y1="12" x2="21" y2="12"/> | |||
<line x1="3" y1="6" x2="21" y2="6"/> | |||
<line x1="3" y1="18" x2="21" y2="18"/> | |||
</svg> | |||
</Link> | |||
} | |||
/> | |||
} | |||
sidebarBaseWidget={ | |||
<Widgets.LeftSidebarBase | |||
open={sidebarOpen} | |||
> | |||
<div className="min-h-full py-4 box-border flex flex-col gap-8"> | |||
<div> | |||
<nav> | |||
<Layouts.LeftSidebar.SidebarContentContainer> | |||
<h1> | |||
Docs | |||
</h1> | |||
</Layouts.LeftSidebar.SidebarContentContainer> | |||
<div className="flex flex-col gap-2 my-8"> | |||
{docsPages?.map(createSidebarPageLink)} | |||
</div> | |||
</nav> | |||
<nav> | |||
<Layouts.LeftSidebar.SidebarContentContainer> | |||
<h1> | |||
Platforms | |||
</h1> | |||
</Layouts.LeftSidebar.SidebarContentContainer> | |||
<div className="flex flex-col gap-2 my-8"> | |||
<Layouts.LeftSidebar.SidebarContentContainer> | |||
<div className="flex gap-8"> | |||
<Link | |||
href={{ | |||
pathname: '[...url]', | |||
query: { | |||
url: ['web', 'react'], | |||
}, | |||
}} | |||
className="no-underline font-semibold leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
React | |||
</Link> | |||
<Link | |||
href={{ | |||
pathname: '[...url]', | |||
query: { | |||
url: ['web', 'vue'], | |||
}, | |||
}} | |||
className="no-underline font-semibold leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
Vue | |||
</Link> | |||
<Link | |||
href={{ | |||
pathname: '[...url]', | |||
query: { | |||
url: ['web', 'solid'], | |||
}, | |||
}} | |||
className="no-underline font-semibold leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
Solid | |||
</Link> | |||
</div> | |||
</Layouts.LeftSidebar.SidebarContentContainer> | |||
</div> | |||
</nav> | |||
{/*<div>*/} | |||
{/* <Layouts.LeftSidebar.SidebarContentContainer>*/} | |||
{/* <h1>*/} | |||
{/* Categories*/} | |||
{/* </h1>*/} | |||
{/* </Layouts.LeftSidebar.SidebarContentContainer>*/} | |||
{/* {componentPages.map(({name, components}) => (*/} | |||
{/* <nav key={name}>*/} | |||
{/* <h2>*/} | |||
{/* <Layouts.LeftSidebar.SidebarContentContainer>*/} | |||
{/* {name}*/} | |||
{/* </Layouts.LeftSidebar.SidebarContentContainer>*/} | |||
{/* </h2>*/} | |||
{/* <div className="flex flex-col gap-2 my-8">*/} | |||
{/* {components?.map(createSidebarPageLink)}*/} | |||
{/* </div>*/} | |||
{/* </nav>*/} | |||
{/* ))}*/} | |||
{/*</div>*/} | |||
{/*<nav>*/} | |||
{/* <Layouts.LeftSidebar.SidebarContentContainer>*/} | |||
{/* <h1>*/} | |||
{/* Examples*/} | |||
{/* </h1>*/} | |||
{/* </Layouts.LeftSidebar.SidebarContentContainer>*/} | |||
{/* <div className="flex flex-col gap-4 my-4">*/} | |||
{/* {examplePages?.map(createSidebarPageLink)}*/} | |||
{/* </div>*/} | |||
{/*</nav>*/} | |||
</div> | |||
<div className="mb-8"> | |||
<Layouts.LeftSidebar.SidebarContentContainer> | |||
<div className="flex gap-8"> | |||
<Link | |||
href="https://code.modal.sh/tesseract-design/tesseract" | |||
className="no-underline font-semibold leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
Repo | |||
</Link> | |||
<Link | |||
href="https://code.modal.sh/tesseract-design/tesseract" | |||
className="no-underline font-semibold leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
Website | |||
</Link> | |||
<Link | |||
href="https://code.modal.sh/tesseract-design/tesseract/issues" | |||
className="no-underline font-semibold leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
Issues | |||
</Link> | |||
</div> | |||
</Layouts.LeftSidebar.SidebarContentContainer> | |||
</div> | |||
</div> | |||
</Widgets.LeftSidebarBase> | |||
} | |||
> | |||
<Layouts.LeftSidebar.MainContentContainer> | |||
{children} | |||
</Layouts.LeftSidebar.MainContentContainer> | |||
</Layouts.LeftSidebar.Root> | |||
) | |||
}; |
@@ -0,0 +1,249 @@ | |||
import type {GetStaticPaths, GetStaticProps, NextPage} from 'next'; | |||
import * as fs from 'fs/promises'; | |||
import * as path from 'path'; | |||
import * as React from 'react' | |||
import {useRouter} from 'next/router'; | |||
import ReactMarkdown from 'react-markdown'; | |||
import {DocsLayout, Page} from '@/components/DocsLayout'; | |||
export interface Props { | |||
componentPages: { name: string; components: Page[] }[], | |||
docsPages: Page[], | |||
examplePages: Page[], | |||
markdown: string, | |||
} | |||
const InnerPage: NextPage<Props> = ({ | |||
componentPages, | |||
examplePages, | |||
docsPages, | |||
markdown, | |||
}) => { | |||
const router = useRouter(); | |||
const sidebarOpen = router.query.open === 'sidebar'; | |||
return ( | |||
<DocsLayout | |||
componentPages={componentPages} | |||
examplePages={examplePages} | |||
docsPages={docsPages} | |||
sidebarOpen={sidebarOpen} | |||
> | |||
{markdown && ( | |||
<ReactMarkdown | |||
className="my-12 leading-loose" | |||
components={{ | |||
ul: ({node, ordered: _ordered, ...props}) => ( | |||
<ul | |||
{...props} | |||
className="list-disc pl-4" | |||
/> | |||
), | |||
li: ({node, ...props}) => ( | |||
<li | |||
{...props} | |||
className="list-item pl-4" | |||
/> | |||
), | |||
}} | |||
> | |||
{markdown} | |||
</ReactMarkdown> | |||
)} | |||
<pre> | |||
<code> | |||
{JSON.stringify(componentPages, null, 2)} | |||
</code> | |||
</pre> | |||
</DocsLayout> | |||
) | |||
} | |||
export const getStaticProps: GetStaticProps = async (ctx) => { | |||
const { params } = ctx; | |||
const { url } = params as { url: string[] }; | |||
const [platform, framework, ...etcUrl] = url; | |||
const props = {} as Record<string, unknown>; | |||
const docsPath = path.resolve('../../docs'); | |||
const docs = await fs.readdir(docsPath); | |||
props.docsPages = docs.map((d) => ({ | |||
id: d, | |||
href: `/docs/${d}`, | |||
label: d | |||
.split('-') | |||
.slice(1) | |||
.map((dd) => dd.slice(0, 1).toUpperCase() + dd.slice(1)) | |||
.join(' ') | |||
.replace(/\.md/i, '') | |||
})); | |||
// const categoriesPath = path.resolve('../../categories'); | |||
// const categories = await fs.readdir(categoriesPath); | |||
// props.componentPages = categories.map((c) => ({ | |||
// id: c, | |||
// href: `/categories/${c}`, | |||
// label: c.split('-').map((cc) => cc.slice(0, 1).toUpperCase() + cc.slice(1)).join(' '), | |||
// })); | |||
// const pagesPath = path.resolve('src/pages'); | |||
// const examplesPath = path.resolve(pagesPath, 'examples'); | |||
// const examplesRaw = await fs.readdir(examplesPath); | |||
// const examplesIndexPage = await Promise.all( | |||
// examplesRaw.map(async (c) => { | |||
// const indexPath = await path.resolve(examplesPath, c, 'index.tsx'); | |||
// try { | |||
// const statResult = await fs.stat(indexPath); | |||
// return [c, statResult.isFile()]; | |||
// } catch { | |||
// // noop | |||
// } | |||
// | |||
// return [c, false]; | |||
// }) | |||
// ) as [string, boolean][]; | |||
// const examples = examplesIndexPage | |||
// .filter(([, hasIndexPage]) => hasIndexPage) | |||
// .map(([key]) => key); | |||
// props.examplePages = examples.map((e) => ({ | |||
// id: e, | |||
// href: `/examples/${e}`, | |||
// label: e.split('-').map((ee) => ee.slice(0, 1).toUpperCase() + ee.slice(1)).join(' '), | |||
// })); | |||
const isHome = !Array.isArray(params.url); | |||
if (isHome) { | |||
const readmePath = path.resolve('../../README.md'); | |||
props.markdown = await fs.readFile(readmePath, 'utf-8'); | |||
} | |||
const theParamsUrl = params.url as string[]; | |||
const isDocs = Array.isArray(theParamsUrl) && theParamsUrl[0] === 'docs'; | |||
if (isDocs) { | |||
const docsPath = path.resolve('../../docs', theParamsUrl[1] as string); | |||
props.markdown = await fs.readFile(docsPath, 'utf-8'); | |||
} | |||
const typedocData = await fs.readFile('typedoc.data.json', 'utf-8'); | |||
const project = JSON.parse(typedocData) as any; | |||
props.componentPages = project.children.reduce( | |||
(theComponents, pkg) => { | |||
const packageNameFragments = pkg.name.split('-'); | |||
const packageFramework = packageNameFragments.pop(); | |||
const categoryBaseName = packageNameFragments.pop(); | |||
console.log(packageFramework, categoryBaseName); | |||
if (theComponents.some((c) => c.name === categoryBaseName)) { | |||
return theComponents.map((cc) => { | |||
if (cc.name !== categoryBaseName) { | |||
return cc; | |||
} | |||
let components = []; | |||
if (packageFramework === 'react') { | |||
components = pkg.children | |||
.filter((exported) => { | |||
return exported.kind === 64; // Function, these are react components | |||
}) | |||
.map((component) => { | |||
return { | |||
...component, | |||
id: component.name, | |||
href: `/categories/${categoryBaseName}/${component.name}`, | |||
label: component.name, | |||
descriptionMarkdown: component.signatures[0].comment.summary.reduce( | |||
(theText, t) => { | |||
if (t.kind === 'text') { | |||
return `${theText}${t.text}`; | |||
} | |||
if (t.kind === 'inline-tag' && t.tag === '@link') { | |||
return `${theText}[${t.text}](#)` // TODO set URL | |||
} | |||
return theText; | |||
}, | |||
'' | |||
), | |||
}; | |||
}); | |||
} | |||
return { | |||
...cc, | |||
name: categoryBaseName, | |||
packages: { | |||
...(cc.packages ?? {}), | |||
[packageFramework]: { | |||
components, | |||
}, | |||
}, | |||
}; | |||
}) | |||
} | |||
let components = []; | |||
if (packageFramework === 'react') { | |||
components = pkg.children | |||
.filter((exported) => { | |||
return exported.kind === 64; // Function, these are react components | |||
}) | |||
.map((component) => { | |||
return { | |||
...component, | |||
id: component.name, | |||
href: `/categories/${categoryBaseName}/${component.name}`, | |||
label: component.name, | |||
descriptionMarkdown: component.signatures[0].comment.summary.reduce( | |||
(theText, t) => { | |||
if (t.kind === 'text') { | |||
return `${theText}${t.text}`; | |||
} | |||
if (t.kind === 'inline-tag' && t.tag === '@link') { | |||
return `${theText}[${t.text}](#)` // TODO set URL | |||
} | |||
return theText; | |||
}, | |||
'' | |||
), | |||
}; | |||
}); | |||
} | |||
return [ | |||
...theComponents, | |||
{ | |||
name: categoryBaseName, | |||
packages: { | |||
[packageFramework]: { | |||
components, | |||
} | |||
} | |||
} | |||
] | |||
}, | |||
[], | |||
); | |||
return { | |||
props, | |||
}; | |||
}; | |||
export default InnerPage; | |||
export const getStaticPaths: GetStaticPaths = async () => { | |||
const docsPath = path.resolve('../../docs'); | |||
const docs = await fs.readdir(docsPath); | |||
const categoriesPath = path.resolve('../../categories'); | |||
const categories = await fs.readdir(categoriesPath); | |||
return { | |||
paths: [ | |||
...docs.map((d) => `/docs/${d}`), | |||
], | |||
fallback: true, | |||
}; | |||
}; |
@@ -1,13 +0,0 @@ | |||
// 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,242 +0,0 @@ | |||
import { NextPage } from 'next'; | |||
import * as Action from '@tesseract-design/web-action-react'; | |||
import { DefaultLayout } from '@/components/DefaultLayout'; | |||
const ActionPage: NextPage = () => { | |||
return ( | |||
<DefaultLayout | |||
title="Action" | |||
> | |||
<section> | |||
<div className="container mx-auto px-4"> | |||
<h1> | |||
ActionButton | |||
</h1> | |||
<div> | |||
<section> | |||
<h2>Variants</h2> | |||
<div> | |||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 my-4"> | |||
<div> | |||
<Action.ActionButton | |||
variant="bare" | |||
block | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
variant="filled" | |||
block | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
variant="outline" | |||
block | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
variant="filled" | |||
block | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
variant="bare" | |||
block | |||
disabled | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
variant="filled" | |||
block | |||
disabled | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
variant="outline" | |||
block | |||
disabled | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
variant="filled" | |||
block | |||
disabled | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
</div> | |||
</div> | |||
</section> | |||
<section> | |||
<h2>Sizes</h2> | |||
<div> | |||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 my-4"> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
variant="outline" | |||
size="small" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
variant="filled" | |||
size="small" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
variant="outline" | |||
size="medium" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
variant="filled" | |||
size="medium" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
variant="outline" | |||
size="large" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
variant="filled" | |||
size="large" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
</div> | |||
</div> | |||
</section> | |||
<section> | |||
<h2>Compact</h2> | |||
<div> | |||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 my-4"> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
compact | |||
variant="outline" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
compact | |||
variant="filled" | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
compact | |||
variant="outline" | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
compact | |||
variant="filled" | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
compact | |||
variant="outline" | |||
size="small" | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
> | |||
Button | |||
</Action.ActionButton> | |||
</div> | |||
<div> | |||
<Action.ActionButton | |||
block | |||
compact | |||
variant="filled" | |||
size="small" | |||
subtext={ | |||
<> | |||
Very Long Line of Subtext That Spans More Than The Component Width For Testing Overflow | |||
</> | |||
} | |||
> | |||
Very Long Line of Text That Spans More Than The Component Width For Testing Overflow | |||
</Action.ActionButton> | |||
</div> | |||
</div> | |||
</div> | |||
</section> | |||
</div> | |||
</div> | |||
</section> | |||
</DefaultLayout> | |||
) | |||
} | |||
export default ActionPage |
@@ -1,61 +0,0 @@ | |||
import {NextPage} from 'next'; | |||
import {DefaultLayout} from '@/components/DefaultLayout'; | |||
import {Section, Subsection} from '@/components/Section'; | |||
import * as TesseractBlob from '@tesseract-design/web-blob-react'; | |||
const BlobPage: NextPage = () => { | |||
return ( | |||
<DefaultLayout title="Blob"> | |||
<Section title="FileSelectBox"> | |||
<Subsection title="Default"> | |||
<TesseractBlob.FileSelectBox | |||
label="File" | |||
name="file" | |||
border | |||
placeholder="Select a file" | |||
onChange={(e) => { console.log('change', e.currentTarget.name, e.currentTarget, e.currentTarget.files)}} | |||
/> | |||
</Subsection> | |||
<Subsection title="Default Multiple"> | |||
<TesseractBlob.FileSelectBox | |||
label="File" | |||
name="file" | |||
border | |||
multiple | |||
placeholder="Select a file" | |||
onChange={(e) => { console.log('change', e.currentTarget.name, e.currentTarget, e.currentTarget.files)}} | |||
/> | |||
</Subsection> | |||
<Subsection title="Enhanced"> | |||
<TesseractBlob.FileSelectBox | |||
label="File" | |||
name="file" | |||
border | |||
enhanced | |||
placeholder="Select a file" | |||
style={{ | |||
height: 256, | |||
}} | |||
onChange={(e) => { console.log('change', e.currentTarget.name, e.currentTarget, e.currentTarget.files)}} | |||
/> | |||
</Subsection> | |||
<Subsection title="Enhanced Multiple"> | |||
<TesseractBlob.FileSelectBox | |||
label="File" | |||
name="file" | |||
border | |||
enhanced | |||
placeholder="Select a file" | |||
multiple | |||
style={{ | |||
height: 256, | |||
}} | |||
onChange={(e) => { console.log('change', e.currentTarget.name, e.currentTarget, e.currentTarget.files)}} | |||
/> | |||
</Subsection> | |||
</Section> | |||
</DefaultLayout> | |||
) | |||
} | |||
export default BlobPage; |
@@ -1,90 +0,0 @@ | |||
import {NextPage} from 'next'; | |||
import {DefaultLayout} from '@/components/DefaultLayout'; | |||
import {Section, Subsection} from '@/components/Section'; | |||
import * as Color from '@tesseract-design/web-color-react'; | |||
import { TextInput } from '@tesseract-design/web-freeform-react'; | |||
const ColorPage: NextPage = () => { | |||
return ( | |||
<DefaultLayout title="Color"> | |||
<Section title="ColorPicker"> | |||
<Subsection title="Default"> | |||
<Color.ColorPicker | |||
size="small" | |||
defaultValue="#ff0000" | |||
/> | |||
<Color.ColorPicker | |||
size="medium" | |||
defaultValue="#00ff00" | |||
/> | |||
<Color.ColorPicker | |||
size="large" | |||
defaultValue="#0000ff" | |||
/> | |||
</Subsection> | |||
<Subsection title="Square"> | |||
<Color.ColorPicker | |||
size="small" | |||
square | |||
defaultValue="#ff0000" | |||
/> | |||
<Color.ColorPicker | |||
size="medium" | |||
square | |||
defaultValue="#00ff00" | |||
/> | |||
<Color.ColorPicker | |||
size="large" | |||
square | |||
defaultValue="#0000ff" | |||
/> | |||
</Subsection> | |||
<Subsection title="Disabled"> | |||
<Color.ColorPicker | |||
size="small" | |||
defaultValue="#ff0000" | |||
disabled | |||
/> | |||
<Color.ColorPicker | |||
size="medium" | |||
defaultValue="#00ff00" | |||
disabled | |||
/> | |||
<Color.ColorPicker | |||
size="large" | |||
defaultValue="#0000ff" | |||
disabled | |||
/> | |||
</Subsection> | |||
<Subsection title="Copy on select"> | |||
<Color.ColorPicker | |||
size="small" | |||
defaultValue="#ff0000" | |||
copyOnSelect | |||
readOnly | |||
/> | |||
<Color.ColorPicker | |||
size="medium" | |||
defaultValue="#00ff00" | |||
copyOnSelect | |||
readOnly | |||
/> | |||
<Color.ColorPicker | |||
size="large" | |||
defaultValue="#0000ff" | |||
copyOnSelect | |||
readOnly | |||
/> | |||
<div> | |||
<TextInput | |||
label="Color" | |||
border | |||
/> | |||
</div> | |||
</Subsection> | |||
</Section> | |||
</DefaultLayout> | |||
) | |||
} | |||
export default ColorPage; |
@@ -1,128 +0,0 @@ | |||
import {NextPage} from 'next'; | |||
import {DefaultLayout} from '@/components/DefaultLayout'; | |||
import {Section, Subsection} from '@/components/Section'; | |||
import * as Formatted from '@tesseract-design/web-formatted-react'; | |||
import {useRef} from 'react'; | |||
import {ActionButton} from '@tesseract-design/web-action-react'; | |||
const TemporalPage: NextPage = () => { | |||
const phoneNumberRef = useRef<HTMLInputElement>(null); | |||
return ( | |||
<DefaultLayout title="Formatted"> | |||
<Section title="PhoneNumberInput"> | |||
<Subsection title="Default"> | |||
<Formatted.PhoneNumberInput | |||
country="PH" | |||
label="Phone" | |||
name="phone" | |||
enhanced | |||
border | |||
onFocus={(e) => { console.log('focus', e.currentTarget)}} | |||
onBlur={(e) => { console.log('blur', e.currentTarget)}} | |||
onChange={(e) => { console.log('change', e.currentTarget.name, e.currentTarget, e.currentTarget.value)}} | |||
/> | |||
</Subsection> | |||
<Subsection title="Non-enhanced"> | |||
<Formatted.PhoneNumberInput | |||
country="PH" | |||
label="Phone" | |||
name="phone" | |||
border | |||
onFocus={(e) => { console.log('focus', e.currentTarget)}} | |||
onBlur={(e) => { console.log('blur', e.currentTarget)}} | |||
onChange={(e) => { console.log('change', e.currentTarget.name, e.currentTarget, e.currentTarget.value)}} | |||
/> | |||
</Subsection> | |||
<Subsection title="With Default Value"> | |||
<Formatted.PhoneNumberInput | |||
country="PH" | |||
label="Phone" | |||
name="phone2" | |||
enhanced | |||
border | |||
defaultValue="+639876543210" | |||
/> | |||
</Subsection> | |||
<Subsection title="With Ref"> | |||
<div className="flex gap-4 flex-wrap"> | |||
<div> | |||
<Formatted.PhoneNumberInput | |||
country="PH" | |||
label="Phone" | |||
name="phone3" | |||
enhanced | |||
border | |||
ref={phoneNumberRef} | |||
onChange={(e) => { console.log('change', e.currentTarget.name, e.currentTarget, e.currentTarget.value)}} | |||
/> | |||
</div> | |||
<div> | |||
<ActionButton | |||
onClick={() => { | |||
if (phoneNumberRef.current) { | |||
phoneNumberRef.current.value = '+639123456789'; | |||
} | |||
}} | |||
> | |||
Set Value | |||
</ActionButton> | |||
</div> | |||
<div> | |||
<ActionButton | |||
onClick={() => { | |||
if (phoneNumberRef.current) { | |||
phoneNumberRef.current.value = '+63465123456'; | |||
} | |||
}} | |||
> | |||
Set Other Value | |||
</ActionButton> | |||
</div> | |||
<div> | |||
<ActionButton | |||
onClick={() => { | |||
if (phoneNumberRef.current) { | |||
phoneNumberRef.current.value = '+63288888888'; | |||
} | |||
}} | |||
> | |||
Set Yet Other Value | |||
</ActionButton> | |||
</div> | |||
</div> | |||
</Subsection> | |||
</Section> | |||
<Section title="EmailInput"> | |||
<Subsection title="Default"> | |||
<Formatted.EmailInput | |||
label="Email" | |||
name="email" | |||
border | |||
/> | |||
</Subsection> | |||
<Subsection title="With domains"> | |||
<Formatted.EmailInput | |||
label="Email" | |||
name="email" | |||
border | |||
variant="alternate" | |||
domains={['gmail.com', 'yahoo.com']} | |||
hint="Only GMail or Yahoo Mail allowed" | |||
length={50} | |||
/> | |||
</Subsection> | |||
</Section> | |||
<Section title="UrlInput"> | |||
<Subsection title="Default"> | |||
<Formatted.UrlInput | |||
label="Website" | |||
name="website" | |||
border | |||
/> | |||
</Subsection> | |||
</Section> | |||
</DefaultLayout> | |||
) | |||
} | |||
export default TemporalPage; |
@@ -1,601 +0,0 @@ | |||
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…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
size="small" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
size="large" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
size="large" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
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…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
variant="alternate" | |||
size="small" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
variant="alternate" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
variant="alternate" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
variant="alternate" | |||
size="large" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
border | |||
block | |||
variant="alternate" | |||
size="large" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
variant="alternate" | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
block | |||
disabled | |||
/> | |||
</div> | |||
<div> | |||
<Freeform.MaskedTextInput | |||
variant="alternate" | |||
border | |||
label="MaskedTextInput" | |||
hint="Type anything here…" | |||
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; |
@@ -1,469 +0,0 @@ | |||
import { NextPage } from 'next'; | |||
import * as Navigation from '@tesseract-design/web-navigation-react'; | |||
import * as Info from '@tesseract-design/web-information-react'; | |||
const ActionPage: NextPage = () => { | |||
return ( | |||
<main className="my-16 md:my-32"> | |||
<section> | |||
<div className="container mx-auto px-4"> | |||
<h1> | |||
Navigation | |||
</h1> | |||
<div> | |||
<section> | |||
<h2> | |||
LinkButton | |||
</h2> | |||
<div> | |||
<section> | |||
<h3>Variants</h3> | |||
<div> | |||
<div className="grid md:grid-cols-2 gap-4 my-4"> | |||
<div> | |||
<Navigation.LinkButton | |||
variant="bare" | |||
href="#" | |||
block | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
variant="filled" | |||
block | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
variant="outline" | |||
block | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
variant="filled" | |||
block | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
disabled | |||
href="#" | |||
variant="bare" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
variant="filled" | |||
block | |||
disabled | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
variant="outline" | |||
block | |||
disabled | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
variant="filled" | |||
block | |||
disabled | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
</div> | |||
</div> | |||
</section> | |||
<section> | |||
<h3>Sizes</h3> | |||
<div> | |||
<div className="grid md:grid-cols-2 gap-4 my-4"> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="outline" | |||
size="small" | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="filled" | |||
size="small" | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="outline" | |||
size="medium" | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="filled" | |||
size="medium" | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="outline" | |||
size="large" | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="filled" | |||
size="large" | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
</div> | |||
</div> | |||
</section> | |||
<section> | |||
<h3>Compact</h3> | |||
<div> | |||
<div className="grid md:grid-cols-2 gap-4 my-4"> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
variant="outline" | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
variant="filled" | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="outline" | |||
compact | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
variant="filled" | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="outline" | |||
compact | |||
size="small" | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
badge={ | |||
<Info.Badge | |||
rounded | |||
> | |||
69 | |||
</Info.Badge> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
variant="filled" | |||
size="small" | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
badge={ | |||
<Info.Badge | |||
rounded | |||
> | |||
69 | |||
</Info.Badge> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="outline" | |||
compact | |||
size="large" | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
badge={ | |||
<Info.Badge | |||
rounded | |||
> | |||
69 | |||
</Info.Badge> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
variant="filled" | |||
size="large" | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
badge={ | |||
<Info.Badge | |||
rounded | |||
> | |||
69 | |||
</Info.Badge> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="outline" | |||
compact | |||
menuItem | |||
size="small" | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
badge={ | |||
<Info.Badge | |||
rounded | |||
> | |||
69 | |||
</Info.Badge> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
size="small" | |||
variant="filled" | |||
menuItem | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
badge={ | |||
<Info.Badge | |||
rounded | |||
> | |||
69 | |||
</Info.Badge> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="outline" | |||
compact | |||
menuItem | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
badge={ | |||
<Info.Badge | |||
rounded | |||
> | |||
69 | |||
</Info.Badge> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
variant="filled" | |||
menuItem | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
badge={ | |||
<Info.Badge | |||
rounded | |||
> | |||
69 | |||
</Info.Badge> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
variant="outline" | |||
compact | |||
menuItem | |||
size="large" | |||
subtext={ | |||
<> | |||
Subtext | |||
</> | |||
} | |||
badge={ | |||
<Info.Badge | |||
rounded | |||
> | |||
69 | |||
</Info.Badge> | |||
} | |||
href="#" | |||
> | |||
Button | |||
</Navigation.LinkButton> | |||
</div> | |||
<div> | |||
<Navigation.LinkButton | |||
block | |||
compact | |||
size="large" | |||
variant="filled" | |||
menuItem | |||
subtext={ | |||
<> | |||
Very Long Line of Subtext That Spans More Than The Component Width For Testing Overflow | |||
</> | |||
} | |||
badge={ | |||
<Info.Badge | |||
rounded | |||
> | |||
69 | |||
</Info.Badge> | |||
} | |||
href="#" | |||
> | |||
Very Long Line of Text That Spans More Than The Component Width For Testing Overflow | |||
</Navigation.LinkButton> | |||
</div> | |||
</div> | |||
</div> | |||
</section> | |||
</div> | |||
</section> | |||
</div> | |||
</div> | |||
</section> | |||
</main> | |||
) | |||
} | |||
export default ActionPage |
@@ -1,128 +0,0 @@ | |||
import * as React from 'react'; | |||
import { NextPage } from 'next'; | |||
import * as TesseractNumber from '@tesseract-design/web-number-react'; | |||
import {Section, Subsection} from '@/components/Section'; | |||
const NumberPage: NextPage = () => { | |||
return ( | |||
<main className="my-16 md:my-32"> | |||
<Section title="NumberSpinner"> | |||
<Subsection title="Default"> | |||
<TesseractNumber.NumberSpinner | |||
min={-100} | |||
max={100} | |||
step="any" | |||
label="Step" | |||
border | |||
enhanced | |||
size="small" | |||
/> | |||
<TesseractNumber.NumberSpinner | |||
min={-100} | |||
max={100} | |||
step="any" | |||
label="Step" | |||
border | |||
enhanced | |||
/> | |||
<TesseractNumber.NumberSpinner | |||
min={-100} | |||
max={100} | |||
step="any" | |||
label="Step" | |||
border | |||
enhanced | |||
size="large" | |||
/> | |||
</Subsection> | |||
</Section> | |||
<Section title="Slider"> | |||
<Subsection title="Default"> | |||
<TesseractNumber.Slider | |||
min={-100} | |||
max={100} | |||
/> | |||
</Subsection> | |||
<Subsection title="Default (with tick marks)"> | |||
<TesseractNumber.Slider | |||
min={-100} | |||
max={100} | |||
> | |||
<optgroup label="Test Values"> | |||
<option value={-100}> | |||
Lowest | |||
</option> | |||
<option value={25}> | |||
日本語 | |||
</option> | |||
<option value={50} /> | |||
<option value={100}> | |||
Highest | |||
</option> | |||
<option value={200}> | |||
Out of bounds | |||
</option> | |||
</optgroup> | |||
</TesseractNumber.Slider> | |||
</Subsection> | |||
<Subsection title="Vertical"> | |||
<TesseractNumber.Slider | |||
min={-100} | |||
max={100} | |||
orient="vertical" | |||
> | |||
<optgroup label="Test Values"> | |||
<option value={-100}> | |||
Lowest | |||
</option> | |||
<option value={25}> | |||
日本語 | |||
</option> | |||
<option value={50} /> | |||
<option value={100}> | |||
Highest | |||
</option> | |||
<option value={200}> | |||
Out of bounds | |||
</option> | |||
</optgroup> | |||
</TesseractNumber.Slider> | |||
<TesseractNumber.Slider | |||
min={-100} | |||
max={100} | |||
orient="vertical" | |||
> | |||
<optgroup label="Test Values"> | |||
<option value={-100}> | |||
Lowest | |||
</option> | |||
<option value={25}> | |||
日本語 | |||
</option> | |||
<option value={50} /> | |||
<option value={100}> | |||
Highest | |||
</option> | |||
<option value={200}> | |||
Out of bounds | |||
</option> | |||
</optgroup> | |||
</TesseractNumber.Slider> | |||
A | |||
</Subsection> | |||
</Section> | |||
<Section title="Matrix"> | |||
<h2> | |||
Matrix | |||
</h2> | |||
<div> | |||
TODO | |||
<input type="range" /> | |||
<input type="range" /> | |||
</div> | |||
</Section> | |||
</main> | |||
) | |||
} | |||
export default NumberPage; |
@@ -1,35 +0,0 @@ | |||
import { NextPage } from 'next'; | |||
import { DefaultLayout } from '@/components/DefaultLayout'; | |||
const PresentationPage: NextPage = () => { | |||
return ( | |||
<DefaultLayout | |||
title="Code" | |||
> | |||
<main className="mt-8 mb-16 md:mt-16 md:mb-32"> | |||
<section> | |||
<div className="container mx-auto px-4"> | |||
<h2> | |||
Tabs | |||
</h2> | |||
<div> | |||
TODO | |||
</div> | |||
</div> | |||
</section> | |||
<section> | |||
<div className="container mx-auto px-4"> | |||
<h2> | |||
Accordion | |||
</h2> | |||
<div> | |||
TODO | |||
</div> | |||
</div> | |||
</section> | |||
</main> | |||
</DefaultLayout> | |||
) | |||
} | |||
export default PresentationPage; |
@@ -1,66 +0,0 @@ | |||
import {NextPage} from 'next'; | |||
import {DefaultLayout} from '@/components/DefaultLayout'; | |||
import {Section, Subsection} from '@/components/Section'; | |||
import * as Temporal from '@tesseract-design/web-temporal-react'; | |||
import * as TemporalWip from '@/components/temporal'; | |||
const TemporalPage: NextPage = () => { | |||
return ( | |||
<DefaultLayout title="Temporal"> | |||
<Section title="DateDropdown"> | |||
<Subsection title="Default"> | |||
<Temporal.DateDropdown | |||
label="Birthday" | |||
border | |||
/> | |||
</Subsection> | |||
</Section> | |||
<Section title="TimeSpinner"> | |||
<Subsection title="Default"> | |||
<Temporal.TimeSpinner | |||
label="Time" | |||
variant="default" | |||
border | |||
/> | |||
</Subsection> | |||
<Subsection title="Step"> | |||
<Temporal.TimeSpinner | |||
label="Time" | |||
variant="default" | |||
border | |||
step="00:15:00" | |||
/> | |||
</Subsection> | |||
<Subsection title="Step + Display Seconds"> | |||
<Temporal.TimeSpinner | |||
label="Time" | |||
variant="default" | |||
border | |||
step="00:00:05" | |||
displaySeconds | |||
/> | |||
</Subsection> | |||
</Section> | |||
<Section title="YearMonthInput"> | |||
<Subsection title="Default"> | |||
<TemporalWip.YearMonthInput | |||
label="Month" | |||
variant="default" | |||
border | |||
/> | |||
</Subsection> | |||
</Section> | |||
<Section title="WeekInput"> | |||
<Subsection title="Default"> | |||
<TemporalWip.WeekInput | |||
label="Vacation" | |||
variant="default" | |||
border | |||
/> | |||
</Subsection> | |||
</Section> | |||
</DefaultLayout> | |||
) | |||
} | |||
export default TemporalPage; |
@@ -1,136 +1,24 @@ | |||
import type {GetStaticProps, NextPage} from 'next'; | |||
import Link from 'next/link'; | |||
import * as fs from 'fs/promises'; | |||
import * as path from 'path'; | |||
import { Layouts, Widgets } from '@tesseract-design/viewfinder-react'; | |||
import * as React from 'react' | |||
import {useRouter} from 'next/router'; | |||
import {Brand} from '@/components/Brand'; | |||
import ReactMarkdown from 'react-markdown'; | |||
import {Layouts} from '@tesseract-design/viewfinder-react'; | |||
type Page = { | |||
id: string, | |||
href: string, | |||
label: string, | |||
export interface Props { | |||
markdown: string, | |||
} | |||
type Props = { | |||
componentPages: Page[], | |||
examplePages: Page[], | |||
} | |||
const createSidebarPageLink = (p: Page) => ( | |||
<div | |||
key={p.id} | |||
> | |||
<Link | |||
href={p.href} | |||
className="no-underline font-semibold m-0 p-0 leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
<Layouts.LeftSidebar.SidebarContentContainer> | |||
{p.label} | |||
</Layouts.LeftSidebar.SidebarContentContainer> | |||
</Link> | |||
</div> | |||
); | |||
const IndexPage: NextPage<Props> = ({ | |||
componentPages, | |||
examplePages, | |||
markdown, | |||
}) => { | |||
const router = useRouter(); | |||
const sidebarOpen = router.query.open === 'sidebar'; | |||
return ( | |||
<Layouts.LeftSidebar.Root | |||
topBarWidget={ | |||
<Widgets.TopBar | |||
span="wide" | |||
brand={ | |||
<Link | |||
href="/" | |||
className="no-underline block" | |||
> | |||
<Brand /> | |||
</Link> | |||
} | |||
menuLink={ | |||
<Link | |||
href={{ | |||
query: { | |||
open: 'sidebar', | |||
}, | |||
}} | |||
className="no-underline p-0 m-0" | |||
> | |||
<svg | |||
className="w-6 h-6 fill-none stroke-current stroke-2 linejoin-round linecap-round" | |||
viewBox="0 0 24 24" | |||
role="presentation" | |||
> | |||
<line x1="3" y1="12" x2="21" y2="12"/> | |||
<line x1="3" y1="6" x2="21" y2="6"/> | |||
<line x1="3" y1="18" x2="21" y2="18"/> | |||
</svg> | |||
</Link> | |||
} | |||
/> | |||
} | |||
sidebarBaseWidget={ | |||
<Widgets.LeftSidebarBase | |||
open={router.query.open === 'sidebar'} | |||
> | |||
<div className="min-h-full py-4 flex flex-col gap-8"> | |||
<div> | |||
<nav> | |||
<h1> | |||
<Layouts.LeftSidebar.SidebarContentContainer> | |||
Categories | |||
</Layouts.LeftSidebar.SidebarContentContainer> | |||
</h1> | |||
<div className="flex flex-col gap-2 my-8"> | |||
{componentPages.map(createSidebarPageLink)} | |||
</div> | |||
</nav> | |||
<nav> | |||
<h1> | |||
<Layouts.LeftSidebar.SidebarContentContainer> | |||
Examples | |||
</Layouts.LeftSidebar.SidebarContentContainer> | |||
</h1> | |||
<div className="flex flex-col gap-4 my-4"> | |||
{examplePages.map(createSidebarPageLink)} | |||
</div> | |||
</nav> | |||
</div> | |||
<div className="mb-8"> | |||
<Layouts.LeftSidebar.SidebarContentContainer> | |||
<div className="flex gap-8"> | |||
<Link | |||
href="https://code.modal.sh/tesseract-design/tesseract" | |||
className="no-underline font-semibold leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
Repo | |||
</Link> | |||
<Link | |||
href="https://code.modal.sh/tesseract-design/tesseract" | |||
className="no-underline font-semibold leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
Website | |||
</Link> | |||
<Link | |||
href="https://code.modal.sh/tesseract-design/tesseract/issues" | |||
className="no-underline font-semibold leading-none h-8 flex items-center cursor-pointer uppercase text-sm" | |||
> | |||
Issues | |||
</Link> | |||
</div> | |||
</Layouts.LeftSidebar.SidebarContentContainer> | |||
</div> | |||
</div> | |||
</Widgets.LeftSidebarBase> | |||
} | |||
> | |||
<Layouts.LeftSidebar.MainContentContainer> | |||
<Layouts.Basic.Root> | |||
<Layouts.Basic.ContentContainer> | |||
<ReactMarkdown | |||
className="my-12 leading-loose" | |||
components={{ | |||
@@ -148,104 +36,21 @@ const IndexPage: NextPage<Props> = ({ | |||
), | |||
}} | |||
> | |||
{`# Tesseract | |||
## Design | |||
- Tesseract components follow a strict and simple design philosophy. | |||
- The aesthetics of the elements are rigid--any element which users can | |||
interact with should be easily recognizable--they are determined by the | |||
usage of the chosen accent color. | |||
- The look and feel of the elements are designed to be less opinionated | |||
as possible. | |||
## Engineering | |||
- Every component is a derivative of an existing HTML element, | |||
thus any Tesseract component can substitute for any HTML element | |||
with added capabilities like improved user experience and consistency. | |||
- In case of overloaded HTML elements such as \`<input>\`, Tesseract | |||
dissects the element into multiple components each having a single | |||
defined behavior. | |||
- Tesseract components gracefully degrade to their native counterparts, | |||
allowing user agents without client-side JavaScript to still use the | |||
components with minimal loss of functionality. | |||
- Tesseract components render Web-compliant HTML and CSS, thus | |||
making it resilient to future changes in the HTML/CSS specifications. | |||
- Tesseract components are designed to be used with popular JavaScript | |||
frameworks like React. Consumption of the components using the framework | |||
of choice should be seamless, even with the use of form-handling libraries. | |||
- Terminal-based browsers such as Lynx are used to test the components | |||
for accessibility and graceful degradation. | |||
## Accessibility | |||
- Components are made to be accessible according to Web standards (WAI-ARIA). | |||
- Focus handling is managed sensibly to facilitate functional | |||
keyboard navigation. | |||
- In cases where there are improvements in user experience, some | |||
elements may have different markup and appearance. Tesseract | |||
ensures components are still usable on most assistive technologies given | |||
both versions of the user interface. | |||
- All components are named in order to depict the purpose, the nature of data | |||
being operated, and UX expectations. | |||
`} | |||
{markdown} | |||
</ReactMarkdown> | |||
</Layouts.LeftSidebar.MainContentContainer> | |||
</Layouts.LeftSidebar.Root> | |||
) | |||
</Layouts.Basic.ContentContainer> | |||
</Layouts.Basic.Root> | |||
); | |||
} | |||
export const getStaticProps: GetStaticProps = async () => { | |||
const pagesPath = path.resolve('src/pages'); | |||
const categoriesPath = path.resolve(pagesPath, 'categories'); | |||
const categoriesRaw = await fs.readdir(categoriesPath); | |||
const categoriesIndexPage = await Promise.all( | |||
categoriesRaw.map(async (c) => { | |||
const indexPath = await path.resolve(categoriesPath, c, 'index.tsx'); | |||
try { | |||
const statResult = await fs.stat(indexPath); | |||
return [c, statResult.isFile()]; | |||
} catch { | |||
// noop | |||
} | |||
return [c, false]; | |||
}) | |||
) as [string, boolean][]; | |||
const categories = categoriesIndexPage | |||
.filter(([, hasIndexPage]) => hasIndexPage) | |||
.map(([key]) => key); | |||
const examplesPath = path.resolve(pagesPath, 'examples'); | |||
const examplesRaw = await fs.readdir(examplesPath); | |||
const examplesIndexPage = await Promise.all( | |||
examplesRaw.map(async (c) => { | |||
const indexPath = await path.resolve(examplesPath, c, 'index.tsx'); | |||
try { | |||
const statResult = await fs.stat(indexPath); | |||
return [c, statResult.isFile()]; | |||
} catch { | |||
// noop | |||
} | |||
export const getStaticProps: GetStaticProps = async (ctx) => { | |||
const props = {} as Record<string, unknown>; | |||
return [c, false]; | |||
}) | |||
) as [string, boolean][]; | |||
const examples = examplesIndexPage | |||
.filter(([, hasIndexPage]) => hasIndexPage) | |||
.map(([key]) => key); | |||
const readmePath = path.resolve('../../README.md'); | |||
props.markdown = await fs.readFile(readmePath, 'utf-8'); | |||
return { | |||
props: { | |||
componentPages: categories.map((c) => ({ | |||
id: c, | |||
href: `/categories/${c}`, | |||
label: c.split('-').map((cc) => cc.slice(0, 1).toUpperCase() + cc.slice(1)).join(' '), | |||
})), | |||
examplePages: examples.map((e) => ({ | |||
id: e, | |||
href: `/examples/${e}`, | |||
label: e.split('-').map((ee) => ee.slice(0, 1).toUpperCase() + ee.slice(1)).join(' '), | |||
})), | |||
}, | |||
props, | |||
}; | |||
}; | |||
@@ -0,0 +1,8 @@ | |||
{ | |||
"entryPoints": ["../../categories/**"], | |||
"entryPointStrategy": "packages", | |||
"name": "@tesseract-design/tesseract-web-react", | |||
"json": "typedoc.data.json", | |||
"pretty": true, | |||
"tsconfig": "../../tsconfig.json" | |||
} |
@@ -1,5 +1,9 @@ | |||
{ | |||
"exclude": ["node_modules"], | |||
"include": ["categories/**/src/*"], | |||
"exclude": [ | |||
"node_modules", | |||
"**/*.test.{ts,js,tsx,jsx}" | |||
], | |||
"compilerOptions": { | |||
"module": "ESNext", | |||
"lib": ["ESNext", "DOM"], | |||
@@ -0,0 +1,4 @@ | |||
{ | |||
"$schema": "https://typedoc.org/schema.json", | |||
"includeVersion": true | |||
} |