Browse Source

Extract all categories outside kitchen sink

Define all categories presently implemented.
pull/1/head
TheoryOfNekomata 10 months ago
parent
commit
231b0382df
94 changed files with 1094 additions and 423 deletions
  1. +3
    -3
      categories/action/react/src/components/ActionButton/index.tsx
  2. +9
    -0
      categories/blob/react/.eslintrc
  3. +107
    -0
      categories/blob/react/.gitignore
  4. +7
    -0
      categories/blob/react/LICENSE
  5. +81
    -0
      categories/blob/react/package.json
  6. +3
    -0
      categories/blob/react/pridepack.json
  7. +35
    -53
      categories/blob/react/src/components/FileSelectBox/index.tsx
  8. +1
    -0
      categories/blob/react/src/index.ts
  9. +21
    -0
      categories/blob/react/tsconfig.eslint.json
  10. +21
    -0
      categories/blob/react/tsconfig.json
  11. +8
    -0
      categories/blob/react/vitest.config.ts
  12. +3
    -1
      categories/choice/react/package.json
  13. +4
    -4
      categories/multichoice/react/src/components/TagInput/TagInput.css
  14. +3
    -3
      categories/navigation/react/src/components/LinkButton/index.tsx
  15. +3
    -1
      categories/number/react/package.json
  16. +9
    -0
      packages/blob-utils/.eslintrc
  17. +107
    -0
      packages/blob-utils/.gitignore
  18. +7
    -0
      packages/blob-utils/LICENSE
  19. +70
    -0
      packages/blob-utils/package.json
  20. +3
    -0
      packages/blob-utils/pridepack.json
  21. +49
    -0
      packages/blob-utils/src/content-type.ts
  22. +59
    -0
      packages/blob-utils/src/description.ts
  23. +2
    -0
      packages/blob-utils/src/index.ts
  24. +21
    -0
      packages/blob-utils/tsconfig.eslint.json
  25. +21
    -0
      packages/blob-utils/tsconfig.json
  26. +9
    -0
      packages/react-blob-previews/.eslintrc
  27. +107
    -0
      packages/react-blob-previews/.gitignore
  28. +7
    -0
      packages/react-blob-previews/LICENSE
  29. +77
    -0
      packages/react-blob-previews/package.json
  30. +3
    -0
      packages/react-blob-previews/pridepack.json
  31. +9
    -9
      packages/react-blob-previews/src/components/AudioFilePreview/index.tsx
  32. +5
    -5
      packages/react-blob-previews/src/components/AudioMiniFilePreview/index.tsx
  33. +7
    -7
      packages/react-blob-previews/src/components/BinaryFilePreview/index.tsx
  34. +7
    -7
      packages/react-blob-previews/src/components/ImageFilePreview/index.tsx
  35. +7
    -7
      packages/react-blob-previews/src/components/TextFilePreview/index.tsx
  36. +7
    -7
      packages/react-blob-previews/src/components/VideoFilePreview/index.tsx
  37. +0
    -0
      packages/react-blob-previews/src/hooks/blob/index.ts
  38. +1
    -1
      packages/react-blob-previews/src/hooks/blob/metadata.ts
  39. +0
    -0
      packages/react-blob-previews/src/hooks/interactive/image.ts
  40. +0
    -0
      packages/react-blob-previews/src/hooks/interactive/index.ts
  41. +0
    -0
      packages/react-blob-previews/src/hooks/interactive/media.ts
  42. +0
    -1
      packages/react-blob-previews/src/index.ts
  43. +21
    -0
      packages/react-blob-previews/tsconfig.eslint.json
  44. +21
    -0
      packages/react-blob-previews/tsconfig.json
  45. +8
    -0
      packages/react-blob-previews/vitest.config.ts
  46. +0
    -10
      packages/web-kitchensink-reactnext/src/categories/blob/react/common.ts
  47. +0
    -187
      packages/web-kitchensink-reactnext/src/pages/categories/blob/index.tsx
  48. +138
    -7
      pnpm-lock.yaml
  49. +1
    -0
      pnpm-workspace.yaml
  50. +0
    -0
      showcases/web-kitchensink-reactnext/.eslintrc.json
  51. +0
    -0
      showcases/web-kitchensink-reactnext/.gitignore
  52. +0
    -0
      showcases/web-kitchensink-reactnext/README.md
  53. +0
    -0
      showcases/web-kitchensink-reactnext/colorthief.d.ts
  54. +0
    -0
      showcases/web-kitchensink-reactnext/next.config.js
  55. +1
    -0
      showcases/web-kitchensink-reactnext/package.json
  56. +0
    -0
      showcases/web-kitchensink-reactnext/pnpm-lock.yaml
  57. +0
    -0
      showcases/web-kitchensink-reactnext/postcss.config.js
  58. +0
    -0
      showcases/web-kitchensink-reactnext/public/audio.wav
  59. +0
    -0
      showcases/web-kitchensink-reactnext/public/binary.bin
  60. +0
    -0
      showcases/web-kitchensink-reactnext/public/code.py
  61. +0
    -0
      showcases/web-kitchensink-reactnext/public/favicon.ico
  62. +0
    -0
      showcases/web-kitchensink-reactnext/public/image.png
  63. +0
    -0
      showcases/web-kitchensink-reactnext/public/next.svg
  64. +0
    -0
      showcases/web-kitchensink-reactnext/public/plaintext.txt
  65. +0
    -0
      showcases/web-kitchensink-reactnext/public/vercel.svg
  66. +0
    -0
      showcases/web-kitchensink-reactnext/public/video.mp4
  67. +0
    -0
      showcases/web-kitchensink-reactnext/react-refractor.d.ts
  68. +0
    -0
      showcases/web-kitchensink-reactnext/src/components/DefaultLayout/index.tsx
  69. +0
    -0
      showcases/web-kitchensink-reactnext/src/components/Section/index.tsx
  70. +0
    -0
      showcases/web-kitchensink-reactnext/src/packages/react-refractor/index.tsx
  71. +0
    -0
      showcases/web-kitchensink-reactnext/src/packages/react-refractor/style.module.css
  72. +0
    -0
      showcases/web-kitchensink-reactnext/src/packages/react-wavesurfer/SpectrogramCanvas/index.tsx
  73. +0
    -0
      showcases/web-kitchensink-reactnext/src/packages/react-wavesurfer/WaveformCanvas/index.tsx
  74. +0
    -0
      showcases/web-kitchensink-reactnext/src/packages/react-wavesurfer/index.ts
  75. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/_app.tsx
  76. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/_document.tsx
  77. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/api/hello.ts
  78. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/categories/action/index.tsx
  79. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/categories/code/index.tsx
  80. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/categories/freeform/index.tsx
  81. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/categories/navigation/index.tsx
  82. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/categories/number/index.tsx
  83. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/categories/option/index.tsx
  84. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/categories/presentation/index.tsx
  85. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/examples/blog-post/index.tsx
  86. +1
    -1
      showcases/web-kitchensink-reactnext/src/pages/examples/registration-form/index.tsx
  87. +0
    -0
      showcases/web-kitchensink-reactnext/src/pages/index.tsx
  88. +0
    -0
      showcases/web-kitchensink-reactnext/src/styles/globals.css
  89. +0
    -0
      showcases/web-kitchensink-reactnext/src/styles/kitchen-sink.css
  90. +0
    -0
      showcases/web-kitchensink-reactnext/src/styles/theme.ts
  91. +0
    -109
      showcases/web-kitchensink-reactnext/src/utils/blob.ts
  92. +0
    -0
      showcases/web-kitchensink-reactnext/src/utils/numeral.ts
  93. +0
    -0
      showcases/web-kitchensink-reactnext/tailwind.config.js
  94. +0
    -0
      showcases/web-kitchensink-reactnext/tsconfig.json

+ 3
- 3
categories/action/react/src/components/ActionButton/index.tsx View File

@@ -33,7 +33,7 @@ export const ActionButton = React.forwardRef<ActionButtonDerivedElement, ActionB
type={type}
ref={forwardedRef}
className={clsx(
'items-center justify-center rounded overflow-hidden ring-secondary/50 leading-none gap-4 select-none',
'items-center justify-center rounded overflow-hidden ring-secondary/50 leading-none select-none',
'focus:outline-0 focus:ring-4',
'active:ring-tertiary/50',
'disabled:opacity-50 disabled:cursor-not-allowed',
@@ -42,8 +42,8 @@ export const ActionButton = React.forwardRef<ActionButtonDerivedElement, ActionB
'inline-flex max-w-full align-middle': !block,
},
{
'pl-2': compact,
'pl-4': !compact,
'pl-2 gap-2': compact,
'pl-4 gap-4': !compact,
'pr-4': !(compact || menuItem),
'pr-2': compact || menuItem,
},


+ 9
- 0
categories/blob/react/.eslintrc View File

@@ -0,0 +1,9 @@
{
"root": true,
"extends": [
"lxsmnsyc/typescript/react"
],
"parserOptions": {
"project": "./tsconfig.eslint.json"
}
}

+ 107
- 0
categories/blob/react/.gitignore View File

@@ -0,0 +1,107 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.production
.env.development

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

.npmrc

+ 7
- 0
categories/blob/react/LICENSE View File

@@ -0,0 +1,7 @@
MIT License Copyright (c) 2023 TheoryOfNekomata <allan.crisostomo@outlook.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 81
- 0
categories/blob/react/package.json View File

@@ -0,0 +1,81 @@
{
"name": "@tesseract-design/web-blob-react",
"version": "0.0.0",
"files": [
"dist",
"src"
],
"engines": {
"node": ">=12"
},
"license": "MIT",
"keywords": [
"pridepack"
],
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@types/node": "^18.14.1",
"@types/react": "^18.0.27",
"eslint": "^8.35.0",
"eslint-config-lxsmnsyc": "^0.5.0",
"jsdom": "^21.1.0",
"pridepack": "2.4.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0",
"tslib": "^2.5.0",
"typescript": "^4.9.5",
"vitest": "^0.28.1"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"scripts": {
"prepublishOnly": "pridepack clean && pridepack build",
"build": "pridepack build",
"type-check": "pridepack check",
"lint": "pridepack lint",
"clean": "pridepack clean",
"watch": "pridepack watch",
"start": "pridepack start",
"dev": "pridepack dev",
"test": "vitest"
},
"private": false,
"description": "Tesseract components for displaying data.",
"repository": {
"url": "",
"type": "git"
},
"homepage": "",
"bugs": {
"url": ""
},
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>",
"publishConfig": {
"access": "public"
},
"dependencies": {
"clsx": "^1.2.1",
"@modal-sh/react-utils": "workspace:*"
},
"types": "./dist/types/index.d.ts",
"main": "./dist/cjs/production/index.js",
"module": "./dist/esm/production/index.js",
"exports": {
".": {
"development": {
"require": "./dist/cjs/development/index.js",
"import": "./dist/esm/development/index.js"
},
"require": "./dist/cjs/production/index.js",
"import": "./dist/esm/production/index.js",
"types": "./dist/types/index.d.ts"
}
},
"typesVersions": {
"*": {}
}
}

+ 3
- 0
categories/blob/react/pridepack.json View File

@@ -0,0 +1,3 @@
{
"target": "es2018"
}

packages/web-kitchensink-reactnext/src/categories/blob/react/components/FileSelectBox/index.tsx → categories/blob/react/src/components/FileSelectBox/index.tsx View File

@@ -1,27 +1,20 @@
import * as React from 'react';
import {ContentType, FileWithResolvedContentType, getContentType, getMimeTypeDescription} from '@/utils/blob';
import {formatFileSize} from '@/utils/numeral';
import {AudioFilePreview} from '../AudioFilePreview';
import {BinaryFilePreview} from '../BinaryFilePreview';
import {ImageFilePreview} from '../ImageFilePreview';
import {VideoFilePreview} from '../VideoFilePreview';
import {TextFilePreview} from '../TextFilePreview';
import {AudioMiniFilePreview} from '../AudioMiniFilePreview';
import {delegateTriggerEvent, useClientSide} from '@modal-sh/react-utils';
import { delegateTriggerEvent, useClientSide } from '@modal-sh/react-utils';
import clsx from 'clsx';
import {FilePreviewComponent} from '@/categories/blob/react/common';

const FILE_PREVIEW_COMPONENTS: Record<ContentType, FilePreviewComponent> = {
[ContentType.IMAGE]: ImageFilePreview,
[ContentType.AUDIO]: AudioFilePreview,
[ContentType.VIDEO]: VideoFilePreview,
[ContentType.BINARY]: BinaryFilePreview,
[ContentType.TEXT]: TextFilePreview,
};
export interface CommonPreviewProps<F extends Partial<File> = Partial<File>> {
file?: F;
disabled?: boolean;
enhanced?: boolean;
mini?: boolean;
}

export type FileSelectBoxDerivedElement = HTMLInputElement;

export interface FileSelectBoxProps extends Omit<React.HTMLProps<FileSelectBoxDerivedElement>, 'size' | 'type' | 'style' | 'label' | 'list'> {
export interface FileSelectBoxProps<
F extends Partial<File> = Partial<File>,
P extends CommonPreviewProps<F> = CommonPreviewProps<F>
> extends Omit<React.HTMLProps<FileSelectBoxDerivedElement>, 'size' | 'type' | 'style' | 'label' | 'list'> {
/**
* Should the component display a border?
*/
@@ -43,6 +36,7 @@ export interface FileSelectBoxProps extends Omit<React.HTMLProps<FileSelectBoxDe
* Is the label hidden?
*/
hiddenLabel?: boolean,
previewComponent: React.ElementType<P>,
}

export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileSelectBoxProps>(
@@ -59,6 +53,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS
disabled = false,
className,
id: idProp,
previewComponent: FilePreviewComponent,
...etcProps
}: FileSelectBoxProps,
forwardedRef,
@@ -101,7 +96,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS
const cancelEvent = (e: React.DragEvent) => {
e.stopPropagation();
e.preventDefault();
}
};

const handleDropZone: React.DragEventHandler<HTMLDivElement> = async (e) => {
cancelEvent(e);
@@ -122,7 +117,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS
setTimeout(() => {
delegateTriggerEvent('change', current);
});
}
};

const filesCount = fileList?.length ?? 0;

@@ -131,6 +126,8 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS
className={clsx(
'relative rounded ring-secondary/50 group',
'focus-within:ring-4',
block && 'w-full',
!block && 'inline-block min-w-64',
className,
)}
onDragEnter={cancelEvent}
@@ -207,34 +204,19 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS
&& (
<div className="w-full h-full overflow-auto -mx-4 px-4">
<div className="w-full grid gap-4 grid-cols-3">
{Array.from(fileList ?? []).map((file: File) => {
const f = file as unknown as FileWithResolvedContentType;
const fileContentType = getContentType(file.type, file.name);
{Array.from(fileList ?? []).map((file, i) => {
return (
<div
key={`${file.name}:${i}`}
data-testid="selectedFileItem"
key={f?.url ?? f?.name}
className={`w-full aspect-square rounded overflow-hidden relative before:absolute before:content-[''] before:bg-current before:top-0 before:left-0 before:w-full before:h-full before:opacity-10`}
title={[f.name, getMimeTypeDescription(f.type), formatFileSize(f.size)].join(', ')}
>
{
fileContentType === ContentType.IMAGE
&& typeof f?.url === 'string'
&& (
<img
className="block w-full h-full object-center object-cover"
src={f.url}
alt={f.name}
data-testid="preview"
/>
)
}
{
fileContentType === ContentType.AUDIO
&& (
<AudioMiniFilePreview file={f} />
)
}
<FilePreviewComponent
file={file}
enhanced={clientSide}
disabled={disabled}
mini
/>
</div>
);
})}
@@ -244,25 +226,25 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS
}
{
!multiple
&& Array.from(fileList ?? []).map((file) => {
const f = file as unknown as FileWithResolvedContentType;
const fileContentType = getContentType(file.type, file.name);
const { [fileContentType]: FilePreviewComponent = BinaryFilePreview } = FILE_PREVIEW_COMPONENTS;
&& Array.from(fileList ?? []).map((file, i) => {
return (
<div
key={f?.url ?? f?.name}
key={`${file.name}:${i}`}
className="w-full h-full"
>
<div
data-testid="selectedFileItem"
className="h-full w-full p-4 box-border rounded overflow-hidden relative before:absolute before:content-[''] before:bg-current before:top-0 before:left-0 before:w-full before:h-full before:opacity-10"
>
<FilePreviewComponent
<div
className="w-full h-full relative"
file={f}
enhanced={clientSide}
disabled={disabled}
/>
>
<FilePreviewComponent
file={file}
enhanced={clientSide}
disabled={disabled}
/>
</div>
</div>
</div>
)

+ 1
- 0
categories/blob/react/src/index.ts View File

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

+ 21
- 0
categories/blob/react/tsconfig.eslint.json View File

@@ -0,0 +1,21 @@
{
"exclude": ["node_modules"],
"include": ["src", "types", "test"],
"compilerOptions": {
"module": "ESNext",
"lib": ["DOM", "ESNext"],
"importHelpers": true,
"declaration": true,
"sourceMap": true,
"rootDir": "./",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"jsx": "react",
"esModuleInterop": true,
"target": "es2018"
}
}

+ 21
- 0
categories/blob/react/tsconfig.json View File

@@ -0,0 +1,21 @@
{
"exclude": ["node_modules"],
"include": ["src", "types"],
"compilerOptions": {
"module": "ESNext",
"lib": ["DOM", "ESNext"],
"importHelpers": true,
"declaration": true,
"sourceMap": true,
"rootDir": "./src",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"jsx": "react",
"esModuleInterop": true,
"target": "es2018"
}
}

+ 8
- 0
categories/blob/react/vitest.config.ts View File

@@ -0,0 +1,8 @@
/// <reference types="vitest" />

export default ({
test: {
global: true,
environment: 'jsdom',
},
});

+ 3
- 1
categories/choice/react/package.json View File

@@ -74,7 +74,9 @@
"require": "./dist/cjs/production/index.js",
"import": "./dist/esm/production/index.js",
"types": "./dist/types/index.d.ts"
}
},
"./dist/RadioButton.css": "./dist/RadioButton.css",
"./dist/RadioTickBox.css": "./dist/RadioTickBox.css"
},
"typesVersions": {
"*": {}


+ 4
- 4
categories/multichoice/react/src/components/TagInput/TagInput.css View File

@@ -73,24 +73,24 @@
padding-right: 4rem;
}

.tesseract-design-tag-input.tag-input textarea + div > span {
.tesseract-design-tag-input textarea + div > span {
padding: 0.125rem;
border-radius: 0.25rem;
line-height: 1;
background-color: rgb(var(--color-positive) / 25%);
}

.tesseract-design-tag-input.tag-input textarea + div > span span {
.tesseract-design-tag-input textarea + div > span span {
pointer-events: none;
}

.tesseract-design-tag-input.tag-input textarea + div > span button {
.tesseract-design-tag-input textarea + div > span button {
color: rgb(var(--color-primary));
padding: 0;
width: 1rem;
margin-left: 0.25rem;
}

.tesseract-design-tag-input.tag-input textarea + div > span button:hover {
.tesseract-design-tag-input textarea + div > span button:hover {
color: rgb(var(--color-primary));
}

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

@@ -32,7 +32,7 @@ export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonP
{...etcProps}
ref={forwardedRef}
className={clsx(
'items-center justify-center rounded overflow-hidden ring-secondary/50 leading-none gap-4 select-none',
'items-center justify-center rounded overflow-hidden ring-secondary/50 leading-none select-none',
'focus:outline-0 focus:ring-4',
'active:ring-tertiary/50',
{
@@ -40,8 +40,8 @@ export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonP
'inline-flex max-w-full align-middle': !block,
},
{
'pl-2': compact,
'pl-4': !compact,
'pl-2 gap-2': compact,
'pl-4 gap-4': !compact,
'pr-4': !(compact || menuItem),
'pr-2': compact || menuItem,
},


+ 3
- 1
categories/number/react/package.json View File

@@ -74,7 +74,9 @@
"require": "./dist/cjs/production/index.js",
"import": "./dist/esm/production/index.js",
"types": "./dist/types/index.d.ts"
}
},
"./dist/Slider.css": "./dist/Slider.css",
"./dist/Spinner.css": "./dist/Spinner.css"
},
"typesVersions": {
"*": {}


+ 9
- 0
packages/blob-utils/.eslintrc View File

@@ -0,0 +1,9 @@
{
"root": true,
"extends": [
"lxsmnsyc/typescript"
],
"parserOptions": {
"project": "./tsconfig.eslint.json"
}
}

+ 107
- 0
packages/blob-utils/.gitignore View File

@@ -0,0 +1,107 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.production
.env.development

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

.npmrc

+ 7
- 0
packages/blob-utils/LICENSE View File

@@ -0,0 +1,7 @@
MIT License Copyright (c) 2023 TheoryOfNekomata <allan.crisostomo@outlook.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 70
- 0
packages/blob-utils/package.json View File

@@ -0,0 +1,70 @@
{
"name": "@modal-sh/blob-utils",
"version": "0.0.0",
"files": [
"dist",
"src"
],
"engines": {
"node": ">=12"
},
"license": "MIT",
"keywords": [
"pridepack"
],
"devDependencies": {
"@types/mime-types": "^2.1.1",
"@types/node": "^18.14.1",
"eslint": "^8.35.0",
"eslint-config-lxsmnsyc": "^0.5.0",
"pridepack": "2.4.4",
"tslib": "^2.5.0",
"typescript": "^4.9.5",
"vitest": "^0.28.1"
},
"scripts": {
"prepublishOnly": "pridepack clean && pridepack build",
"build": "pridepack build",
"type-check": "pridepack check",
"lint": "pridepack lint",
"clean": "pridepack clean",
"watch": "pridepack watch",
"start": "pridepack start",
"dev": "pridepack dev",
"test": "vitest"
},
"private": false,
"description": "Utilities for binary data.",
"repository": {
"url": "",
"type": "git"
},
"homepage": "",
"bugs": {
"url": ""
},
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>",
"publishConfig": {
"access": "public"
},
"types": "./dist/types/index.d.ts",
"main": "./dist/cjs/production/index.js",
"module": "./dist/esm/production/index.js",
"exports": {
".": {
"development": {
"require": "./dist/cjs/development/index.js",
"import": "./dist/esm/development/index.js"
},
"require": "./dist/cjs/production/index.js",
"import": "./dist/esm/production/index.js",
"types": "./dist/types/index.d.ts"
}
},
"typesVersions": {
"*": {}
},
"dependencies": {
"mime-types": "^2.1.35"
}
}

+ 3
- 0
packages/blob-utils/pridepack.json View File

@@ -0,0 +1,3 @@
{
"target": "es2018"
}

+ 49
- 0
packages/blob-utils/src/content-type.ts View File

@@ -0,0 +1,49 @@
import * as mimeTypes from 'mime-types';

export enum ContentType {
TEXT = 'text',
AUDIO = 'audio',
VIDEO = 'video',
IMAGE = 'image',
BINARY = 'binary',
}

export const getContentType = (mimeType?: string, filename?: string) => {
let effectiveMimeType: string;
if (typeof mimeType !== 'string') {
if (typeof filename !== 'string') {
return ContentType.BINARY;
}
const lookupMimeType = mimeTypes.lookup(filename);

if (typeof lookupMimeType !== 'string') {
return ContentType.BINARY;
}

effectiveMimeType = lookupMimeType;
} else {
effectiveMimeType = mimeType;
}

if (
effectiveMimeType === 'application/json'
|| effectiveMimeType === 'application/xml'
|| effectiveMimeType.startsWith('text/')
) {
return ContentType.TEXT;
}

if (effectiveMimeType.startsWith('video/')) {
return ContentType.VIDEO;
}

if (effectiveMimeType.startsWith('audio/')) {
return ContentType.AUDIO;
}

if (effectiveMimeType.startsWith('image/')) {
return ContentType.IMAGE;
}

return ContentType.BINARY;
};

+ 59
- 0
packages/blob-utils/src/description.ts View File

@@ -0,0 +1,59 @@
const MIME_TYPE_DESCRIPTIONS = {
'image/gif': 'GIF Image',
'image/jpeg': 'JPEG Image',
'image/png': 'PNG Image',
'image/tiff': 'TIFF Image',
'image/svg+xml': 'SVG Image',
'image/webp': 'WEBP Image',
'audio/wav': 'WAVE Audio',
'audio/ogg': 'OGG Audio',
'audio/mpeg': 'MPEG Audio',
'audio/mid': 'MIDI Track',
'application/json': 'JSON Data',
'application/xml': 'XML Data',
'application/x-bittorrent': 'Torrent File',
'application/x-zip-compressed': 'Compressed ZIP Archive',
'application/x-x509-ca-cert': 'Certificate File',
'application/x-tar': 'Compressed TAR Archive',
'application/x-rar': 'Compressed RAR Archive',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'Workbook',
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'Slideshow Presentation',
'application/msword': 'Microsoft Word Document',
'application/pdf': 'PDF Document',
'application/postscript': 'PostScript Document',
'application/epub+zip': 'EPUB Document',
'message/rfc822': 'Email Message',
'video/mp4': 'MP4 Video',
} as const;

const EXTENSION_DESCRIPTIONS = {
rar: 'Compressed RAR Archive',
'7z': 'Compressed 7-Zip Archive',
psd: 'Adobe Photoshop Document',
dmg: 'Disk Image',
'fb2k-component': 'foobar2000 Component',
} as const;

export const getFileDescription = (type?: string, filename?: string) => {
if (typeof (type as unknown) !== 'string') {
return '';
}

if (type === 'application/octet-stream' || type === '') {
if (typeof filename === 'string' && filename.includes('.')) {
const extension = filename.slice(filename.lastIndexOf('.') + '.'.length).toLowerCase();
const {
[extension as keyof typeof EXTENSION_DESCRIPTIONS]: extensionDescription = `${extension.toUpperCase()} File`,
} = EXTENSION_DESCRIPTIONS;

return extensionDescription;
}
return `${type} File`;
}

const {
[type as keyof typeof MIME_TYPE_DESCRIPTIONS]: description = type,
} = MIME_TYPE_DESCRIPTIONS;

return description;
};

+ 2
- 0
packages/blob-utils/src/index.ts View File

@@ -0,0 +1,2 @@
export * from './content-type';
export * from './description';

+ 21
- 0
packages/blob-utils/tsconfig.eslint.json View File

@@ -0,0 +1,21 @@
{
"exclude": ["node_modules"],
"include": ["src", "types", "test"],
"compilerOptions": {
"module": "ESNext",
"lib": ["ESNext"],
"importHelpers": true,
"declaration": true,
"sourceMap": true,
"rootDir": "./",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"jsx": "react",
"esModuleInterop": true,
"target": "es2018"
}
}

+ 21
- 0
packages/blob-utils/tsconfig.json View File

@@ -0,0 +1,21 @@
{
"exclude": ["node_modules"],
"include": ["src", "types"],
"compilerOptions": {
"module": "ESNext",
"lib": ["ESNext"],
"importHelpers": true,
"declaration": true,
"sourceMap": true,
"rootDir": "./src",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"jsx": "react",
"esModuleInterop": true,
"target": "es2018"
}
}

+ 9
- 0
packages/react-blob-previews/.eslintrc View File

@@ -0,0 +1,9 @@
{
"root": true,
"extends": [
"lxsmnsyc/typescript/react"
],
"parserOptions": {
"project": "./tsconfig.eslint.json"
}
}

+ 107
- 0
packages/react-blob-previews/.gitignore View File

@@ -0,0 +1,107 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
.env.production
.env.development

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

.npmrc

+ 7
- 0
packages/react-blob-previews/LICENSE View File

@@ -0,0 +1,7 @@
MIT License Copyright (c) 2023 TheoryOfNekomata <allan.crisostomo@outlook.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 77
- 0
packages/react-blob-previews/package.json View File

@@ -0,0 +1,77 @@
{
"name": "@modal-sh/react-utils",
"version": "0.0.0",
"files": [
"dist",
"src"
],
"engines": {
"node": ">=12"
},
"license": "MIT",
"keywords": [
"pridepack"
],
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@types/node": "^18.14.1",
"@types/react": "^18.0.27",
"eslint": "^8.35.0",
"eslint-config-lxsmnsyc": "^0.5.0",
"jsdom": "^21.1.0",
"pridepack": "2.4.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0",
"tslib": "^2.5.0",
"typescript": "^4.9.5",
"vitest": "^0.28.1"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"scripts": {
"prepublishOnly": "pridepack clean && pridepack build",
"build": "pridepack build",
"type-check": "pridepack check",
"lint": "pridepack lint",
"clean": "pridepack clean",
"watch": "pridepack watch",
"start": "pridepack start",
"dev": "pridepack dev",
"test": "vitest"
},
"private": false,
"description": "Utilities for React.",
"repository": {
"url": "",
"type": "git"
},
"homepage": "",
"bugs": {
"url": ""
},
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>",
"publishConfig": {
"access": "public"
},
"types": "./dist/types/index.d.ts",
"main": "./dist/cjs/production/index.js",
"module": "./dist/esm/production/index.js",
"exports": {
".": {
"development": {
"require": "./dist/cjs/development/index.js",
"import": "./dist/esm/development/index.js"
},
"require": "./dist/cjs/production/index.js",
"import": "./dist/esm/production/index.js",
"types": "./dist/types/index.d.ts"
}
},
"typesVersions": {
"*": {}
}
}

+ 3
- 0
packages/react-blob-previews/pridepack.json View File

@@ -0,0 +1,3 @@
{
"target": "es2018"
}

packages/web-kitchensink-reactnext/src/categories/blob/react/components/AudioFilePreview/index.tsx → packages/react-blob-previews/src/components/AudioFilePreview/index.tsx View File

@@ -1,21 +1,21 @@
import * as React from 'react';
import {augmentAudioFile, getMimeTypeDescription} from '@/utils/blob';
import {augmentAudioFile, getMimeTypeDescription} from 'packages/web-kitchensink-reactnext/src/utils/blob';
import {
formatFileSize,
formatNumeral,
formatSecondsDurationConcise,
formatSecondsDurationPrecise,
} from '@/utils/numeral';
import theme from '@/styles/theme';
} from 'packages/web-kitchensink-reactnext/src/utils/numeral';
import theme from 'packages/web-kitchensink-reactnext/src/styles/theme';
import {useMediaControls} from '../../hooks/interactive';
import {useFileMetadata, useFileUrl} from '@/categories/blob/react';
import {useFileMetadata, useFileUrl} from 'src/index';

import clsx from 'clsx';
import {SpectrogramCanvas, WaveformCanvas} from '@modal-sh/react-wavesurfer';
import {Slider} from '@tesseract-design/web-number-react';
import {KeyValueTable} from '@tesseract-design/web-information-react';
import {useClientSide} from '@modal-sh/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';
import {SpectrogramCanvas, WaveformCanvas} from 'packages/web-kitchensink-reactnext/src/packages/react-wavesurfer';
import {Slider} from 'categories/number/react';
import {KeyValueTable} from 'categories/information/react';
import {useClientSide} from 'packages/react-utils';
import type {CommonPreviewProps} from '../../../../../categories/blob/react/src/components/FileSelectBox';

export type AudioFilePreviewDerivedElement = HTMLAudioElement;


packages/web-kitchensink-reactnext/src/categories/blob/react/components/AudioMiniFilePreview/index.tsx → packages/react-blob-previews/src/components/AudioMiniFilePreview/index.tsx View File

@@ -1,11 +1,11 @@
import * as React from 'react';
import {augmentAudioFile} from '@/utils/blob';
import theme from '@/styles/theme';
import {augmentAudioFile} from 'packages/web-kitchensink-reactnext/src/utils/blob';
import theme from 'packages/web-kitchensink-reactnext/src/styles/theme';
import {useMediaControls} from '../../hooks/interactive';
import {useFileMetadata, useFileUrl} from '@/categories/blob/react';
import {useFileMetadata, useFileUrl} from 'src/index';
import clsx from 'clsx';
import {SpectrogramCanvas, WaveformCanvas} from '@modal-sh/react-wavesurfer';
import {useClientSide} from '@modal-sh/react-utils';
import {SpectrogramCanvas, WaveformCanvas} from 'packages/web-kitchensink-reactnext/src/packages/react-wavesurfer';
import {useClientSide} from 'packages/react-utils';

export type AudioMiniFilePreviewDerivedElement = HTMLAudioElement;


packages/web-kitchensink-reactnext/src/categories/blob/react/components/BinaryFilePreview/index.tsx → packages/react-blob-previews/src/components/BinaryFilePreview/index.tsx View File

@@ -1,12 +1,12 @@
import * as React from 'react';
import {augmentBinaryFile, getMimeTypeDescription} from '@/utils/blob';
import {formatFileSize, formatNumeral} from '@/utils/numeral';
import {useFileMetadata, useFileUrl} from '@/categories/blob/react';
import {augmentBinaryFile, getMimeTypeDescription} from 'packages/web-kitchensink-reactnext/src/utils/blob';
import {formatFileSize, formatNumeral} from 'packages/web-kitchensink-reactnext/src/utils/numeral';
import {useFileMetadata, useFileUrl} from 'src/index';
import clsx from 'clsx';
import {KeyValueTable} from '@tesseract-design/web-information-react';
import {BinaryDataCanvas} from '@modal-sh/react-binary-data-canvas';
import {useClientSide} from '@modal-sh/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';
import {KeyValueTable} from 'categories/information/react';
import {BinaryDataCanvas} from 'packages/react-binary-data-canvas';
import {useClientSide} from 'packages/react-utils';
import type {CommonPreviewProps} from '../../../../../categories/blob/react/src/components/FileSelectBox';

export type BinaryFilePreviewDerivedElement = HTMLDivElement;


packages/web-kitchensink-reactnext/src/categories/blob/react/components/ImageFilePreview/index.tsx → packages/react-blob-previews/src/components/ImageFilePreview/index.tsx View File

@@ -1,12 +1,12 @@
import * as React from 'react';
import {augmentImageFile, getMimeTypeDescription} from '@/utils/blob';
import {formatFileSize, formatNumeral} from '@/utils/numeral';
import {augmentImageFile, getMimeTypeDescription} from 'packages/web-kitchensink-reactnext/src/utils/blob';
import {formatFileSize, formatNumeral} from 'packages/web-kitchensink-reactnext/src/utils/numeral';
import clsx from 'clsx';
import {useFileMetadata, useFileUrl, useImageControls} from '@/categories/blob/react';
import {KeyValueTable} from '@tesseract-design/web-information-react';
import {useClientSide} from '@modal-sh/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';
import {Swatch} from '@tesseract-design/web-color-react';
import {useFileMetadata, useFileUrl, useImageControls} from 'src/index';
import {KeyValueTable} from 'categories/information/react';
import {useClientSide} from 'packages/react-utils';
import type {CommonPreviewProps} from '../../../../../categories/blob/react/src/components/FileSelectBox';
import {Swatch} from 'categories/color/react';

export type ImageFilePreviewDerivedElement = HTMLImageElement;


packages/web-kitchensink-reactnext/src/categories/blob/react/components/TextFilePreview/index.tsx → packages/react-blob-previews/src/components/TextFilePreview/index.tsx View File

@@ -1,12 +1,12 @@
import * as React from 'react';
import {formatFileSize, formatNumeral} from '@/utils/numeral';
import {useFileMetadata, useFileUrl} from '@/categories/blob/react';
import {augmentTextFile, getMimeTypeDescription} from '@/utils/blob';
import {formatFileSize, formatNumeral} from 'packages/web-kitchensink-reactnext/src/utils/numeral';
import {useFileMetadata, useFileUrl} from 'src/index';
import {augmentTextFile, getMimeTypeDescription} from 'packages/web-kitchensink-reactnext/src/utils/blob';
import clsx from 'clsx';
import {KeyValueTable} from '@tesseract-design/web-information-react';
import {Refractor} from '@modal-sh/react-refractor';
import {useClientSide} from '@modal-sh/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';
import {KeyValueTable} from 'categories/information/react';
import {Refractor} from 'packages/web-kitchensink-reactnext/src/packages/react-refractor';
import {useClientSide} from 'packages/react-utils';
import type {CommonPreviewProps} from '../../../../../categories/blob/react/src/components/FileSelectBox';

type TextFilePreviewDerivedComponent = HTMLDivElement;


packages/web-kitchensink-reactnext/src/categories/blob/react/components/VideoFilePreview/index.tsx → packages/react-blob-previews/src/components/VideoFilePreview/index.tsx View File

@@ -1,12 +1,12 @@
import * as React from 'react';
import {augmentVideoFile, getMimeTypeDescription} from '@/utils/blob';
import {formatFileSize, formatNumeral, formatSecondsDurationConcise} from '@/utils/numeral';
import {useFileMetadata, useFileUrl, useMediaControls} from '@tesseract-design/web-blob-react';
import {augmentVideoFile, getMimeTypeDescription} from 'packages/web-kitchensink-reactnext/src/utils/blob';
import {formatFileSize, formatNumeral, formatSecondsDurationConcise} from 'packages/web-kitchensink-reactnext/src/utils/numeral';
import {useFileMetadata, useFileUrl, useMediaControls} from 'src/index';
import clsx from 'clsx';
import {Slider} from '@tesseract-design/web-number-react';
import {KeyValueTable} from '@tesseract-design/web-information-react';
import {useClientSide} from '@modal-sh/react-utils';
import {CommonPreviewProps} from '@/categories/blob/react/common';
import {Slider} from 'categories/number/react';
import {KeyValueTable} from 'categories/information/react';
import {useClientSide} from 'packages/react-utils';
import type {CommonPreviewProps} from '../../../../../categories/blob/react/src/components/FileSelectBox';

export type VideoFilePreviewDerivedComponent = HTMLVideoElement;


packages/web-kitchensink-reactnext/src/categories/blob/react/hooks/blob/index.ts → packages/react-blob-previews/src/hooks/blob/index.ts View File


packages/web-kitchensink-reactnext/src/categories/blob/react/hooks/blob/metadata.ts → packages/react-blob-previews/src/hooks/blob/metadata.ts View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import {addDataUrl, FileWithDataUrl} from '@/utils/blob';
import {addDataUrl, FileWithDataUrl} from 'packages/web-kitchensink-reactnext/src/utils/blob';

export interface UseFileUrlOptions {
file?: Partial<File>;

packages/web-kitchensink-reactnext/src/categories/blob/react/hooks/interactive/image.ts → packages/react-blob-previews/src/hooks/interactive/image.ts View File


packages/web-kitchensink-reactnext/src/categories/blob/react/hooks/interactive/index.ts → packages/react-blob-previews/src/hooks/interactive/index.ts View File


packages/web-kitchensink-reactnext/src/categories/blob/react/hooks/interactive/media.ts → packages/react-blob-previews/src/hooks/interactive/media.ts View File


packages/web-kitchensink-reactnext/src/categories/blob/react/index.ts → packages/react-blob-previews/src/index.ts View File

@@ -1,7 +1,6 @@
export * from './components/AudioFilePreview';
export * from './components/AudioMiniFilePreview';
export * from './components/BinaryFilePreview';
export * from './components/FileSelectBox';
export * from './components/ImageFilePreview';
export * from './components/TextFilePreview';
export * from './components/VideoFilePreview';

+ 21
- 0
packages/react-blob-previews/tsconfig.eslint.json View File

@@ -0,0 +1,21 @@
{
"exclude": ["node_modules"],
"include": ["src", "types", "test"],
"compilerOptions": {
"module": "ESNext",
"lib": ["DOM", "ESNext"],
"importHelpers": true,
"declaration": true,
"sourceMap": true,
"rootDir": "./",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"jsx": "react",
"esModuleInterop": true,
"target": "es2018"
}
}

+ 21
- 0
packages/react-blob-previews/tsconfig.json View File

@@ -0,0 +1,21 @@
{
"exclude": ["node_modules"],
"include": ["src", "types"],
"compilerOptions": {
"module": "ESNext",
"lib": ["DOM", "ESNext"],
"importHelpers": true,
"declaration": true,
"sourceMap": true,
"rootDir": "./src",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"jsx": "react",
"esModuleInterop": true,
"target": "es2018"
}
}

+ 8
- 0
packages/react-blob-previews/vitest.config.ts View File

@@ -0,0 +1,8 @@
/// <reference types="vitest" />

export default ({
test: {
global: true,
environment: 'jsdom',
},
});

+ 0
- 10
packages/web-kitchensink-reactnext/src/categories/blob/react/common.ts View File

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

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

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

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

@@ -1,187 +0,0 @@
import {NextPage} from 'next';
import * as React from 'react';
import * as BlobReact from '@tesseract-design/web-blob-react';
import {DefaultLayout} from '@/components/DefaultLayout';
import {Section, Subsection} from '@/components/Section';
import {addDataUrl} from '@/utils/blob';

const BlobPage: NextPage = () => {
const [imageFile, setImageFile] = React.useState<Partial<File>>();
React.useEffect(() => {
fetch('/image.png').then((response) => {
response.blob().then(async (blob) => {
const imageFile = new File([blob], 'image.png', {
type: 'image/png',
});
const theFile = await addDataUrl(imageFile);
setImageFile(theFile);
});
});
}, []);

const [videoFile, setVideoFile] = React.useState<File>();
React.useEffect(() => {
fetch('/video.mp4').then((response) => {
response.blob().then((blob) => {
setVideoFile(new File([blob], 'video.mp4', {
type: 'video/mp4',
}));
});
});
}, []);

const [audioFile, setAudioFile] = React.useState<File>();
React.useEffect(() => {
fetch('/audio.wav').then((response) => {
response.blob().then((blob) => {
setAudioFile(new File([blob], 'audio.wav', {
type: 'audio/wav',
}));
});
});
}, []);

const [binaryFile, setBinaryFile] = React.useState<File>();
React.useEffect(() => {
fetch('/binary.bin').then((response) => {
response.blob().then((blob) => {
setBinaryFile(new File([blob], 'binary.bin', {
type: 'application/octet-stream',
}));
});
});
}, []);

const [plaintextFile, setPlaintextFile] = React.useState<File>();
React.useEffect(() => {
fetch('/plaintext.txt').then((response) => {
response.blob().then((blob) => {
setPlaintextFile(new File([blob], 'plaintext.txt', {
type: 'text/plain',
}));
});
});
}, []);

const [codeFile, setCodeFile] = React.useState<File>();
React.useEffect(() => {
fetch('/code.py').then((response) => {
response.blob().then((blob) => {
setCodeFile(new File([blob], 'code.py', {
type: 'text/x-python',
}));
});
});
}, []);

return (
<DefaultLayout title="Blob">
<Section title="ImageFilePreview">
<Subsection title="Single File">
<BlobReact.ImageFilePreview
enhanced
file={
imageFile
?? {
name: 'image.png',
type: 'image/png',
url: '/image.png',
} as Partial<File>
}
className="sm:h-64"
/>
</Subsection>
</Section>
<Section title="VideoFilePreview">
<Subsection title="Single File">
<BlobReact.VideoFilePreview
file={
videoFile
?? {
name: 'video.mp4',
type: 'video/mp4',
url: '/video.mp4',
} as Partial<File>
}
className="sm:h-64"
enhanced
/>
</Subsection>
</Section>
<Section title="AudioFilePreview">
<Subsection title="Single File">
<BlobReact.AudioFilePreview
file={
audioFile
?? {
name: 'audio.wav',
type: 'audio/wav',
url: '/audio.wav',
} as Partial<File>
}
className="sm:h-64"
enhanced
/>
</Subsection>
</Section>
<Section title="BinaryFilePreview">
<Subsection title="Single File">
<BlobReact.BinaryFilePreview
file={
binaryFile
?? {
name: 'binary.bin',
type: 'application/octet-stream',
url: '/binary.bin',
} as Partial<File>
}
className="sm:h-64"
/>
</Subsection>
</Section>
<Section title="TextFilePreview">
<Subsection title="Single File (Plaintext)">
<BlobReact.TextFilePreview
file={
plaintextFile
?? {
name: 'plaintext.txt',
type: 'text/plain',
url: '/plaintext.txt',
} as Partial<File>
}
className="sm:h-64"
/>
</Subsection>
<Subsection title="Single File (Code)">
<BlobReact.TextFilePreview
file={
codeFile
?? {
name: 'code.py',
type: 'text/x-python',
url: '/code.py',
} as Partial<File>
}
className="sm:h-64"
/>
</Subsection>
</Section>
<Section title="FileSelectBox">
<Subsection title="Single File">
<BlobReact.FileSelectBox
border
enhanced
label="Primary Image"
hint="Select any files here"
block
className="sm:h-96"
onChange={(e) => console.log(e.currentTarget.files)}
/>
</Subsection>
</Section>
</DefaultLayout>
)
}

export default BlobPage;

+ 138
- 7
pnpm-lock.yaml View File

@@ -82,6 +82,58 @@ importers:
specifier: ^0.28.1
version: 0.28.1(jsdom@21.1.0)

categories/blob/react:
dependencies:
'@modal-sh/react-utils':
specifier: workspace:*
version: link:../../../packages/react-utils
clsx:
specifier: ^1.2.1
version: 1.2.1
devDependencies:
'@testing-library/jest-dom':
specifier: ^5.16.5
version: 5.16.5
'@testing-library/react':
specifier: ^13.4.0
version: 13.4.0(react-dom@18.2.0)(react@18.2.0)
'@types/node':
specifier: ^18.14.1
version: 18.14.1
'@types/react':
specifier: ^18.0.27
version: 18.2.14
eslint:
specifier: ^8.35.0
version: 8.43.0
eslint-config-lxsmnsyc:
specifier: ^0.5.0
version: 0.5.0(eslint@8.43.0)(typescript@4.9.5)
jsdom:
specifier: ^21.1.0
version: 21.1.0
pridepack:
specifier: 2.4.4
version: 2.4.4(eslint@8.43.0)(tslib@2.6.0)(typescript@4.9.5)
react:
specifier: ^18.2.0
version: 18.2.0
react-dom:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
react-test-renderer:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
tslib:
specifier: ^2.5.0
version: 2.6.0
typescript:
specifier: ^4.9.5
version: 4.9.5
vitest:
specifier: ^0.28.1
version: 0.28.1(jsdom@21.1.0)

categories/choice/react:
dependencies:
'@tesseract-design/web-base':
@@ -535,6 +587,37 @@ importers:
specifier: ^0.28.1
version: 0.28.1(jsdom@21.1.0)

packages/blob-utils:
dependencies:
mime-types:
specifier: ^2.1.35
version: 2.1.35
devDependencies:
'@types/mime-types':
specifier: ^2.1.1
version: 2.1.1
'@types/node':
specifier: ^18.14.1
version: 18.14.1
eslint:
specifier: ^8.35.0
version: 8.43.0
eslint-config-lxsmnsyc:
specifier: ^0.5.0
version: 0.5.0(eslint@8.43.0)(typescript@4.9.5)
pridepack:
specifier: 2.4.4
version: 2.4.4(eslint@8.43.0)(tslib@2.6.0)(typescript@4.9.5)
tslib:
specifier: ^2.5.0
version: 2.6.0
typescript:
specifier: ^4.9.5
version: 4.9.5
vitest:
specifier: ^0.28.1
version: 0.28.1(jsdom@21.1.0)

packages/image-utils:
dependencies:
colorthief:
@@ -617,6 +700,51 @@ importers:
specifier: ^0.28.1
version: 0.28.1(jsdom@21.1.0)

packages/react-blob-previews:
devDependencies:
'@testing-library/jest-dom':
specifier: ^5.16.5
version: 5.16.5
'@testing-library/react':
specifier: ^13.4.0
version: 13.4.0(react-dom@18.2.0)(react@18.2.0)
'@types/node':
specifier: ^18.14.1
version: 18.14.1
'@types/react':
specifier: ^18.0.27
version: 18.2.14
eslint:
specifier: ^8.35.0
version: 8.43.0
eslint-config-lxsmnsyc:
specifier: ^0.5.0
version: 0.5.0(eslint@8.43.0)(typescript@4.9.5)
jsdom:
specifier: ^21.1.0
version: 21.1.0
pridepack:
specifier: 2.4.4
version: 2.4.4(eslint@8.43.0)(tslib@2.6.0)(typescript@4.9.5)
react:
specifier: ^18.2.0
version: 18.2.0
react-dom:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
react-test-renderer:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
tslib:
specifier: ^2.5.0
version: 2.6.0
typescript:
specifier: ^4.9.5
version: 4.9.5
vitest:
specifier: ^0.28.1
version: 0.28.1(jsdom@21.1.0)

packages/react-utils:
devDependencies:
'@testing-library/jest-dom':
@@ -720,32 +848,35 @@ importers:
specifier: ^0.28.1
version: 0.28.1(jsdom@21.1.0)

packages/web-kitchensink-reactnext:
showcases/web-kitchensink-reactnext:
dependencies:
'@modal-sh/audio-utils':
specifier: workspace:*
version: link:../audio-utils
version: link:../../packages/audio-utils
'@modal-sh/image-utils':
specifier: workspace:*
version: link:../image-utils
version: link:../../packages/image-utils
'@modal-sh/react-binary-data-canvas':
specifier: workspace:*
version: link:../react-binary-data-canvas
version: link:../../packages/react-binary-data-canvas
'@modal-sh/react-utils':
specifier: workspace:*
version: link:../react-utils
version: link:../../packages/react-utils
'@modal-sh/text-utils':
specifier: workspace:*
version: link:../text-utils
version: link:../../packages/text-utils
'@modal-sh/video-utils':
specifier: workspace:*
version: link:../video-utils
version: link:../../packages/video-utils
'@tesseract-design/web-action-react':
specifier: workspace:*
version: link:../../categories/action/react
'@tesseract-design/web-base':
specifier: workspace:*
version: link:../../base
'@tesseract-design/web-blob-react':
specifier: workspace:*
version: link:../../categories/blob/react
'@tesseract-design/web-choice-react':
specifier: workspace:*
version: link:../../categories/choice/react


+ 1
- 0
pnpm-workspace.yaml View File

@@ -2,3 +2,4 @@ packages:
- 'base'
- 'packages/*'
- 'categories/**'
- 'showcases/**'

packages/web-kitchensink-reactnext/.eslintrc.json → showcases/web-kitchensink-reactnext/.eslintrc.json View File


packages/web-kitchensink-reactnext/.gitignore → showcases/web-kitchensink-reactnext/.gitignore View File


packages/web-kitchensink-reactnext/README.md → showcases/web-kitchensink-reactnext/README.md View File


packages/web-kitchensink-reactnext/colorthief.d.ts → showcases/web-kitchensink-reactnext/colorthief.d.ts View File


packages/web-kitchensink-reactnext/next.config.js → showcases/web-kitchensink-reactnext/next.config.js View File


packages/web-kitchensink-reactnext/package.json → showcases/web-kitchensink-reactnext/package.json View File

@@ -38,6 +38,7 @@
"@modal-sh/react-binary-data-canvas": "workspace:*",
"@tesseract-design/web-base": "workspace:*",
"@tesseract-design/web-action-react": "workspace:*",
"@tesseract-design/web-blob-react": "workspace:*",
"@tesseract-design/web-color-react": "workspace:*",
"@tesseract-design/web-choice-react": "workspace:*",
"@tesseract-design/web-formatted-react": "workspace:*",

packages/web-kitchensink-reactnext/pnpm-lock.yaml → showcases/web-kitchensink-reactnext/pnpm-lock.yaml View File


packages/web-kitchensink-reactnext/postcss.config.js → showcases/web-kitchensink-reactnext/postcss.config.js View File


packages/web-kitchensink-reactnext/public/audio.wav → showcases/web-kitchensink-reactnext/public/audio.wav View File


packages/web-kitchensink-reactnext/public/binary.bin → showcases/web-kitchensink-reactnext/public/binary.bin View File


packages/web-kitchensink-reactnext/public/code.py → showcases/web-kitchensink-reactnext/public/code.py View File


packages/web-kitchensink-reactnext/public/favicon.ico → showcases/web-kitchensink-reactnext/public/favicon.ico View File


packages/web-kitchensink-reactnext/public/image.png → showcases/web-kitchensink-reactnext/public/image.png View File


packages/web-kitchensink-reactnext/public/next.svg → showcases/web-kitchensink-reactnext/public/next.svg View File


packages/web-kitchensink-reactnext/public/plaintext.txt → showcases/web-kitchensink-reactnext/public/plaintext.txt View File


packages/web-kitchensink-reactnext/public/vercel.svg → showcases/web-kitchensink-reactnext/public/vercel.svg View File


packages/web-kitchensink-reactnext/public/video.mp4 → showcases/web-kitchensink-reactnext/public/video.mp4 View File


packages/web-kitchensink-reactnext/react-refractor.d.ts → showcases/web-kitchensink-reactnext/react-refractor.d.ts View File


packages/web-kitchensink-reactnext/src/components/DefaultLayout/index.tsx → showcases/web-kitchensink-reactnext/src/components/DefaultLayout/index.tsx View File


packages/web-kitchensink-reactnext/src/components/Section/index.tsx → showcases/web-kitchensink-reactnext/src/components/Section/index.tsx View File


packages/web-kitchensink-reactnext/src/packages/react-refractor/index.tsx → showcases/web-kitchensink-reactnext/src/packages/react-refractor/index.tsx View File


packages/web-kitchensink-reactnext/src/packages/react-refractor/style.module.css → showcases/web-kitchensink-reactnext/src/packages/react-refractor/style.module.css View File


packages/web-kitchensink-reactnext/src/packages/react-wavesurfer/SpectrogramCanvas/index.tsx → showcases/web-kitchensink-reactnext/src/packages/react-wavesurfer/SpectrogramCanvas/index.tsx View File


packages/web-kitchensink-reactnext/src/packages/react-wavesurfer/WaveformCanvas/index.tsx → showcases/web-kitchensink-reactnext/src/packages/react-wavesurfer/WaveformCanvas/index.tsx View File


packages/web-kitchensink-reactnext/src/packages/react-wavesurfer/index.ts → showcases/web-kitchensink-reactnext/src/packages/react-wavesurfer/index.ts View File


packages/web-kitchensink-reactnext/src/pages/_app.tsx → showcases/web-kitchensink-reactnext/src/pages/_app.tsx View File


packages/web-kitchensink-reactnext/src/pages/_document.tsx → showcases/web-kitchensink-reactnext/src/pages/_document.tsx View File


packages/web-kitchensink-reactnext/src/pages/api/hello.ts → showcases/web-kitchensink-reactnext/src/pages/api/hello.ts View File


packages/web-kitchensink-reactnext/src/pages/categories/action/index.tsx → showcases/web-kitchensink-reactnext/src/pages/categories/action/index.tsx View File


packages/web-kitchensink-reactnext/src/pages/categories/code/index.tsx → showcases/web-kitchensink-reactnext/src/pages/categories/code/index.tsx View File


packages/web-kitchensink-reactnext/src/pages/categories/freeform/index.tsx → showcases/web-kitchensink-reactnext/src/pages/categories/freeform/index.tsx View File


packages/web-kitchensink-reactnext/src/pages/categories/navigation/index.tsx → showcases/web-kitchensink-reactnext/src/pages/categories/navigation/index.tsx View File


packages/web-kitchensink-reactnext/src/pages/categories/number/index.tsx → showcases/web-kitchensink-reactnext/src/pages/categories/number/index.tsx View File


packages/web-kitchensink-reactnext/src/pages/categories/option/index.tsx → showcases/web-kitchensink-reactnext/src/pages/categories/option/index.tsx View File


packages/web-kitchensink-reactnext/src/pages/categories/presentation/index.tsx → showcases/web-kitchensink-reactnext/src/pages/categories/presentation/index.tsx View File


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


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

@@ -1,5 +1,5 @@
import { NextPage } from 'next';
import * as Freeform from '../../../../../../categories/freeform/react/src';
import * as Freeform from '@tesseract-design/web-freeform-react';
import * as Action from '@tesseract-design/web-action-react';

const RegistrationFormPage: NextPage = () => {

packages/web-kitchensink-reactnext/src/pages/index.tsx → showcases/web-kitchensink-reactnext/src/pages/index.tsx View File


packages/web-kitchensink-reactnext/src/styles/globals.css → showcases/web-kitchensink-reactnext/src/styles/globals.css View File


packages/web-kitchensink-reactnext/src/styles/kitchen-sink.css → showcases/web-kitchensink-reactnext/src/styles/kitchen-sink.css View File


packages/web-kitchensink-reactnext/src/styles/theme.ts → showcases/web-kitchensink-reactnext/src/styles/theme.ts View File


packages/web-kitchensink-reactnext/src/utils/blob.ts → showcases/web-kitchensink-reactnext/src/utils/blob.ts View File

@@ -1,117 +1,8 @@
import * as mimeTypes from 'mime-types';
import {getTextMetadata, TextMetadata} from '@modal-sh/text-utils';
import {getMetadataFromUrl as getImageMetadataFromUrl, ImageMetadata} from '@modal-sh/image-utils';
import {getMetadataFromUrl as getAudioMetadataFromUrl, AudioMetadata} from '@modal-sh/audio-utils';
import {getMetadataFromUrl as getVideoMetadataFromUrl, VideoMetadata} from '@modal-sh/video-utils';

const MIME_TYPE_DESCRIPTIONS = {
'image/gif': 'GIF Image',
'image/jpeg': 'JPEG Image',
'image/png': 'PNG Image',
'image/tiff': 'TIFF Image',
'image/svg+xml': 'SVG Image',
'image/webp': 'WEBP Image',
'audio/wav': 'WAVE Audio',
'audio/ogg': 'OGG Audio',
'audio/mpeg': 'MPEG Audio',
'audio/mid': 'MIDI Track',
'application/json': 'JSON Data',
'application/xml': 'XML Data',
'application/x-bittorrent': 'Torrent File',
'application/x-zip-compressed': 'Compressed ZIP Archive',
'application/x-x509-ca-cert': 'Certificate File',
'application/x-tar': 'Compressed TAR Archive',
'application/x-rar': 'Compressed RAR Archive',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'Workbook',
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'Slideshow Presentation',
'application/msword': 'Microsoft Word Document',
'application/pdf': 'PDF Document',
'application/postscript': 'PostScript Document',
'application/epub+zip': 'EPUB Document',
'message/rfc822': 'Email Message',
'video/mp4': 'MP4 Video',
} as const;

const EXTENSION_DESCRIPTIONS = {
'rar': 'Compressed RAR Archive',
'7z': 'Compressed 7-Zip Archive',
'psd': 'Adobe Photoshop Document',
'dmg': 'Disk Image',
'fb2k-component': 'foobar2000 Component',
} as const;

export const getMimeTypeDescription = (type?: string, filename?: string) => {
if (typeof (type as unknown) !== 'string') {
return '';
}

if (type === 'application/octet-stream' || type === '') {
if (typeof filename === 'string' && filename.includes('.')) {
const extension = filename.slice(filename.lastIndexOf('.') + '.'.length).toLowerCase();
const {
[extension as keyof typeof EXTENSION_DESCRIPTIONS]: extensionDescription = `${extension.toUpperCase()} File`,
} = EXTENSION_DESCRIPTIONS;

return extensionDescription;
}
return `${type} File`;
}

const {
[type as keyof typeof MIME_TYPE_DESCRIPTIONS]: description = type,
} = MIME_TYPE_DESCRIPTIONS;

return description;
}

export enum ContentType {
TEXT = 'text',
AUDIO = 'audio',
VIDEO = 'video',
IMAGE = 'image',
BINARY = 'binary',
}

export const getContentType = (mimeType?: string, filename?: string) => {
let effectiveMimeType: string;
if (typeof mimeType !== 'string') {
if (typeof filename !== 'string') {
return ContentType.BINARY;
}
const lookupMimeType = mimeTypes.lookup(filename);

if (typeof lookupMimeType !== 'string') {
return ContentType.BINARY;
}

effectiveMimeType = lookupMimeType;
} else {
effectiveMimeType = mimeType;
}

if (
effectiveMimeType === 'application/json'
|| effectiveMimeType === 'application/xml'
|| effectiveMimeType.startsWith('text/')
) {
return ContentType.TEXT;
}

if (effectiveMimeType.startsWith('video/')) {
return ContentType.VIDEO;
}

if (effectiveMimeType.startsWith('audio/')) {
return ContentType.AUDIO;
}

if (effectiveMimeType.startsWith('image/')) {
return ContentType.IMAGE;
}

return ContentType.BINARY;
}

export const readAsDataURL = (blob: Partial<Blob>) => new Promise<string>((resolve, reject) => {
// TODO when to revoke these URLs
// return URL.createObjectURL(blob as Blob);

packages/web-kitchensink-reactnext/src/utils/numeral.ts → showcases/web-kitchensink-reactnext/src/utils/numeral.ts View File


packages/web-kitchensink-reactnext/tailwind.config.js → showcases/web-kitchensink-reactnext/tailwind.config.js View File


packages/web-kitchensink-reactnext/tsconfig.json → showcases/web-kitchensink-reactnext/tsconfig.json View File


Loading…
Cancel
Save