Browse Source

Define showcase structure

Allow showcase for other frameworks and platforms.
master
TheoryOfNekomata 9 months ago
parent
commit
1b5ee25c3c
42 changed files with 706 additions and 3728 deletions
  1. +9
    -0
      README.md
  2. +8
    -0
      categories/action/react/typedoc.json
  3. +17
    -0
      categories/blob/react/src/components/FileSelectBox/index.tsx
  4. +8
    -0
      categories/blob/react/typedoc.json
  5. +8
    -0
      categories/choice/react/typedoc.json
  6. +9
    -0
      categories/color/react/src/components/ColorPicker/index.tsx
  7. +9
    -0
      categories/color/react/src/components/Swatch/index.tsx
  8. +8
    -0
      categories/color/react/typedoc.json
  9. +8
    -0
      categories/formatted/react/typedoc.json
  10. +8
    -0
      categories/freeform/react/typedoc.json
  11. +8
    -0
      categories/information/react/typedoc.json
  12. +10
    -13
      categories/multichoice/react/src/components/TagInput/index.tsx
  13. +8
    -0
      categories/multichoice/react/typedoc.json
  14. +3
    -0
      categories/navigation/react/src/components/LinkButton/index.tsx
  15. +8
    -0
      categories/navigation/react/typedoc.json
  16. +8
    -0
      categories/number/react/typedoc.json
  17. +7
    -3
      categories/temporal/react/src/components/TimeSpinner/index.tsx
  18. +8
    -0
      categories/temporal/react/typedoc.json
  19. +1
    -1
      docs/00-philosophy.md
  20. +61
    -0
      pnpm-lock.yaml
  21. +2
    -0
      showcases/web-kitchensink-reactnext/.gitignore
  22. +3
    -1
      showcases/web-kitchensink-reactnext/package.json
  23. +2
    -2
      showcases/web-kitchensink-reactnext/src/components/Brand/index.tsx
  24. +203
    -0
      showcases/web-kitchensink-reactnext/src/components/DocsLayout.tsx
  25. +249
    -0
      showcases/web-kitchensink-reactnext/src/pages/[...url].tsx
  26. +0
    -13
      showcases/web-kitchensink-reactnext/src/pages/api/hello.ts
  27. +0
    -242
      showcases/web-kitchensink-reactnext/src/pages/categories/action/index.tsx
  28. +0
    -61
      showcases/web-kitchensink-reactnext/src/pages/categories/blob/index.tsx
  29. +0
    -90
      showcases/web-kitchensink-reactnext/src/pages/categories/color/index.tsx
  30. +0
    -128
      showcases/web-kitchensink-reactnext/src/pages/categories/formatted/index.tsx
  31. +0
    -601
      showcases/web-kitchensink-reactnext/src/pages/categories/freeform/index.tsx
  32. +0
    -469
      showcases/web-kitchensink-reactnext/src/pages/categories/navigation/index.tsx
  33. +0
    -128
      showcases/web-kitchensink-reactnext/src/pages/categories/number/index.tsx
  34. +0
    -1663
      showcases/web-kitchensink-reactnext/src/pages/categories/option/index.tsx
  35. +0
    -35
      showcases/web-kitchensink-reactnext/src/pages/categories/presentation/index.tsx
  36. +0
    -66
      showcases/web-kitchensink-reactnext/src/pages/categories/temporal/index.tsx
  37. +16
    -211
      showcases/web-kitchensink-reactnext/src/pages/index.tsx
  38. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/web/react/examples/blog-post/index.tsx
  39. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/web/react/examples/registration-form/index.tsx
  40. +8
    -0
      showcases/web-kitchensink-reactnext/typedoc.json
  41. +5
    -1
      tsconfig.json
  42. +4
    -0
      typedoc.base.json

+ 9
- 0
README.md View File

@@ -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)

+ 8
- 0
categories/action/react/typedoc.json View File

@@ -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"
}

+ 17
- 0
categories/blob/react/src/components/FileSelectBox/index.tsx View File

@@ -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 = '',


+ 8
- 0
categories/blob/react/typedoc.json View File

@@ -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"
}

+ 8
- 0
categories/choice/react/typedoc.json View File

@@ -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"
}

+ 9
- 0
categories/color/react/src/components/ColorPicker/index.tsx View File

@@ -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


+ 9
- 0
categories/color/react/src/components/Swatch/index.tsx View File

@@ -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,


+ 8
- 0
categories/color/react/typedoc.json View File

@@ -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"
}

+ 8
- 0
categories/formatted/react/typedoc.json View File

@@ -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"
}

+ 8
- 0
categories/freeform/react/typedoc.json View File

@@ -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"
}

+ 8
- 0
categories/information/react/typedoc.json View File

@@ -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"
}

+ 10
- 13
categories/multichoice/react/src/components/TagInput/index.tsx View File

@@ -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();


+ 8
- 0
categories/multichoice/react/typedoc.json View File

@@ -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"
}

+ 3
- 0
categories/navigation/react/src/components/LinkButton/index.tsx View File

@@ -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,


+ 8
- 0
categories/navigation/react/typedoc.json View File

@@ -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"
}

+ 8
- 0
categories/number/react/typedoc.json View File

@@ -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"
}

+ 7
- 3
categories/temporal/react/src/components/TimeSpinner/index.tsx View File

@@ -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 (


+ 8
- 0
categories/temporal/react/typedoc.json View File

@@ -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
- 1
docs/00-philosophy.md View File

@@ -1,4 +1,4 @@
# Tesseract
# Philosophy

## Design
- Tesseract components follow a strict and simple design philosophy.


+ 61
- 0
pnpm-lock.yaml View File

@@ -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}


+ 2
- 0
showcases/web-kitchensink-reactnext/.gitignore View File

@@ -33,3 +33,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

typedoc.data.json

+ 3
- 1
showcases/web-kitchensink-reactnext/package.json View File

@@ -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"
}
}

+ 2
- 2
showcases/web-kitchensink-reactnext/src/components/Brand/index.tsx View File

@@ -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>


+ 203
- 0
showcases/web-kitchensink-reactnext/src/components/DocsLayout.tsx View File

@@ -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>
)
};

+ 249
- 0
showcases/web-kitchensink-reactnext/src/pages/[...url].tsx View File

@@ -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,
};
};

+ 0
- 13
showcases/web-kitchensink-reactnext/src/pages/api/hello.ts View File

@@ -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' })
}

+ 0
- 242
showcases/web-kitchensink-reactnext/src/pages/categories/action/index.tsx View File

@@ -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

+ 0
- 61
showcases/web-kitchensink-reactnext/src/pages/categories/blob/index.tsx View File

@@ -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;

+ 0
- 90
showcases/web-kitchensink-reactnext/src/pages/categories/color/index.tsx View File

@@ -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;

+ 0
- 128
showcases/web-kitchensink-reactnext/src/pages/categories/formatted/index.tsx View File

@@ -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;

+ 0
- 601
showcases/web-kitchensink-reactnext/src/pages/categories/freeform/index.tsx View File

@@ -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&hellip; ffgg"
indicator="A"
block
/>
</div>
<div>
<Freeform.TextInput
border
size="small"
label="TextInput ffgg"
hint="Type anything here&hellip; ffgg"
indicator="A"
block
/>
</div>
<div>
<Freeform.TextInput
label="TextInput ffgg"
hint="Type anything here&hellip; ffgg"
indicator="A"
block
/>
</div>
<div>
<Freeform.TextInput
border
label="TextInput ffgg"
hint="Type anything here&hellip; ffgg"
indicator="A"
block
/>
</div>
<div>
<Freeform.TextInput
size="large"
label="TextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.TextInput
border
size="large"
label="TextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.TextInput
label="TextInput"
hint="Type anything here&hellip;"
indicator="A"
block
disabled
/>
</div>
<div>
<Freeform.TextInput
border
label="TextInput"
hint="Type anything here&hellip;"
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&hellip; ffgg"
indicator="A"
block
/>
</div>
<div>
<Freeform.TextInput
border
variant="alternate"
size="small"
label="TextInput ffgg"
hint="Type anything here&hellip; ffgg"
indicator="A"
block
/>
</div>
<div>
<Freeform.TextInput
variant="alternate"
label="TextInput ffgg"
hint="Type anything here&hellip; ffgg"
block
/>
</div>
<div>
<Freeform.TextInput
border
variant="alternate"
label="TextInput ffgg"
hint="Type anything here&hellip; ffgg"
block
/>
</div>
<div>
<Freeform.TextInput
variant="alternate"
size="large"
label="TextInput ffgg"
hint="Type anything here&hellip; ffgg"
indicator="A"
block
/>
</div>
<div>
<Freeform.TextInput
border
block
variant="alternate"
size="large"
label="TextInput"
hint="Type anything here&hellip;"
indicator="A"
/>
</div>
<div>
<Freeform.TextInput
variant="alternate"
label="TextInput"
hint="Type anything here&hellip;"
indicator="A"
block
disabled
/>
</div>
<div>
<Freeform.TextInput
variant="alternate"
border
label="TextInput"
hint="Type anything here&hellip;"
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&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
border
size="small"
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
border
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
size="large"
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
border
size="large"
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
disabled
/>
</div>
<div>
<Freeform.MaskedTextInput
border
label="MaskedTextInput"
hint="Type anything here&hellip;"
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&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
border
variant="alternate"
size="small"
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
variant="alternate"
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
border
variant="alternate"
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
variant="alternate"
size="large"
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
/>
</div>
<div>
<Freeform.MaskedTextInput
border
block
variant="alternate"
size="large"
label="MaskedTextInput"
hint="Type anything here&hellip;"
/>
</div>
<div>
<Freeform.MaskedTextInput
variant="alternate"
label="MaskedTextInput"
hint="Type anything here&hellip;"
block
disabled
/>
</div>
<div>
<Freeform.MaskedTextInput
variant="alternate"
border
label="MaskedTextInput"
hint="Type anything here&hellip;"
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&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
border
size="small"
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
border
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
size="large"
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
border
size="large"
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
disabled
/>
</div>
<div>
<Freeform.MultilineTextInput
border
label="MultilineTextInput"
hint="Type anything here&hellip;"
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&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
border
variant="alternate"
size="small"
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
variant="alternate"
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
border
variant="alternate"
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
variant="alternate"
size="large"
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
/>
</div>
<div>
<Freeform.MultilineTextInput
border
block
variant="alternate"
size="large"
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
/>
</div>
<div>
<Freeform.MultilineTextInput
variant="alternate"
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
disabled
/>
</div>
<div>
<Freeform.MultilineTextInput
variant="alternate"
border
label="MultilineTextInput"
hint="Type anything here&hellip;"
indicator="A"
block
disabled
/>
</div>
</div>
</Subsection>
</Section>
</DefaultLayout>
);
};

export default FreeformPage;

+ 0
- 469
showcases/web-kitchensink-reactnext/src/pages/categories/navigation/index.tsx View File

@@ -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

+ 0
- 128
showcases/web-kitchensink-reactnext/src/pages/categories/number/index.tsx View File

@@ -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;

+ 0
- 1663
showcases/web-kitchensink-reactnext/src/pages/categories/option/index.tsx
File diff suppressed because it is too large
View File


+ 0
- 35
showcases/web-kitchensink-reactnext/src/pages/categories/presentation/index.tsx View File

@@ -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;

+ 0
- 66
showcases/web-kitchensink-reactnext/src/pages/categories/temporal/index.tsx View File

@@ -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;

+ 16
- 211
showcases/web-kitchensink-reactnext/src/pages/index.tsx View File

@@ -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,
};
};



showcases/web-kitchensink-reactnext/src/pages/examples/blog-post/index.tsx → showcases/web-kitchensink-reactnext/src/pages/web/react/examples/blog-post/index.tsx View File


showcases/web-kitchensink-reactnext/src/pages/examples/registration-form/index.tsx → showcases/web-kitchensink-reactnext/src/pages/web/react/examples/registration-form/index.tsx View File


+ 8
- 0
showcases/web-kitchensink-reactnext/typedoc.json View File

@@ -0,0 +1,8 @@
{
"entryPoints": ["../../categories/**"],
"entryPointStrategy": "packages",
"name": "@tesseract-design/tesseract-web-react",
"json": "typedoc.data.json",
"pretty": true,
"tsconfig": "../../tsconfig.json"
}

+ 5
- 1
tsconfig.json View File

@@ -1,5 +1,9 @@
{
"exclude": ["node_modules"],
"include": ["categories/**/src/*"],
"exclude": [
"node_modules",
"**/*.test.{ts,js,tsx,jsx}"
],
"compilerOptions": {
"module": "ESNext",
"lib": ["ESNext", "DOM"],


+ 4
- 0
typedoc.base.json View File

@@ -0,0 +1,4 @@
{
"$schema": "https://typedoc.org/schema.json",
"includeVersion": true
}

Loading…
Cancel
Save