Define all categories presently implemented.pull/1/head
@@ -33,7 +33,7 @@ export const ActionButton = React.forwardRef<ActionButtonDerivedElement, ActionB | |||||
type={type} | type={type} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
className={clsx( | 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', | 'focus:outline-0 focus:ring-4', | ||||
'active:ring-tertiary/50', | 'active:ring-tertiary/50', | ||||
'disabled:opacity-50 disabled:cursor-not-allowed', | '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, | '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-4': !(compact || menuItem), | ||||
'pr-2': compact || menuItem, | 'pr-2': compact || menuItem, | ||||
}, | }, | ||||
@@ -0,0 +1,9 @@ | |||||
{ | |||||
"root": true, | |||||
"extends": [ | |||||
"lxsmnsyc/typescript/react" | |||||
], | |||||
"parserOptions": { | |||||
"project": "./tsconfig.eslint.json" | |||||
} | |||||
} |
@@ -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 |
@@ -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. |
@@ -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": { | |||||
"*": {} | |||||
} | |||||
} |
@@ -0,0 +1,3 @@ | |||||
{ | |||||
"target": "es2018" | |||||
} |
@@ -1,27 +1,20 @@ | |||||
import * as React from 'react'; | 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 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 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? | * Should the component display a border? | ||||
*/ | */ | ||||
@@ -43,6 +36,7 @@ export interface FileSelectBoxProps extends Omit<React.HTMLProps<FileSelectBoxDe | |||||
* Is the label hidden? | * Is the label hidden? | ||||
*/ | */ | ||||
hiddenLabel?: boolean, | hiddenLabel?: boolean, | ||||
previewComponent: React.ElementType<P>, | |||||
} | } | ||||
export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileSelectBoxProps>( | export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileSelectBoxProps>( | ||||
@@ -59,6 +53,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
disabled = false, | disabled = false, | ||||
className, | className, | ||||
id: idProp, | id: idProp, | ||||
previewComponent: FilePreviewComponent, | |||||
...etcProps | ...etcProps | ||||
}: FileSelectBoxProps, | }: FileSelectBoxProps, | ||||
forwardedRef, | forwardedRef, | ||||
@@ -101,7 +96,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
const cancelEvent = (e: React.DragEvent) => { | const cancelEvent = (e: React.DragEvent) => { | ||||
e.stopPropagation(); | e.stopPropagation(); | ||||
e.preventDefault(); | e.preventDefault(); | ||||
} | |||||
}; | |||||
const handleDropZone: React.DragEventHandler<HTMLDivElement> = async (e) => { | const handleDropZone: React.DragEventHandler<HTMLDivElement> = async (e) => { | ||||
cancelEvent(e); | cancelEvent(e); | ||||
@@ -122,7 +117,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
setTimeout(() => { | setTimeout(() => { | ||||
delegateTriggerEvent('change', current); | delegateTriggerEvent('change', current); | ||||
}); | }); | ||||
} | |||||
}; | |||||
const filesCount = fileList?.length ?? 0; | const filesCount = fileList?.length ?? 0; | ||||
@@ -131,6 +126,8 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
className={clsx( | className={clsx( | ||||
'relative rounded ring-secondary/50 group', | 'relative rounded ring-secondary/50 group', | ||||
'focus-within:ring-4', | 'focus-within:ring-4', | ||||
block && 'w-full', | |||||
!block && 'inline-block min-w-64', | |||||
className, | className, | ||||
)} | )} | ||||
onDragEnter={cancelEvent} | 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 h-full overflow-auto -mx-4 px-4"> | ||||
<div className="w-full grid gap-4 grid-cols-3"> | <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 ( | return ( | ||||
<div | <div | ||||
key={`${file.name}:${i}`} | |||||
data-testid="selectedFileItem" | 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`} | 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> | </div> | ||||
); | ); | ||||
})} | })} | ||||
@@ -244,25 +226,25 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS | |||||
} | } | ||||
{ | { | ||||
!multiple | !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 ( | return ( | ||||
<div | <div | ||||
key={f?.url ?? f?.name} | |||||
key={`${file.name}:${i}`} | |||||
className="w-full h-full" | className="w-full h-full" | ||||
> | > | ||||
<div | <div | ||||
data-testid="selectedFileItem" | 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" | 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" | className="w-full h-full relative" | ||||
file={f} | |||||
enhanced={clientSide} | |||||
disabled={disabled} | |||||
/> | |||||
> | |||||
<FilePreviewComponent | |||||
file={file} | |||||
enhanced={clientSide} | |||||
disabled={disabled} | |||||
/> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
) | ) |
@@ -0,0 +1 @@ | |||||
export * from './components/FileSelectBox'; |
@@ -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" | |||||
} | |||||
} |
@@ -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" | |||||
} | |||||
} |
@@ -0,0 +1,8 @@ | |||||
/// <reference types="vitest" /> | |||||
export default ({ | |||||
test: { | |||||
global: true, | |||||
environment: 'jsdom', | |||||
}, | |||||
}); |
@@ -74,7 +74,9 @@ | |||||
"require": "./dist/cjs/production/index.js", | "require": "./dist/cjs/production/index.js", | ||||
"import": "./dist/esm/production/index.js", | "import": "./dist/esm/production/index.js", | ||||
"types": "./dist/types/index.d.ts" | "types": "./dist/types/index.d.ts" | ||||
} | |||||
}, | |||||
"./dist/RadioButton.css": "./dist/RadioButton.css", | |||||
"./dist/RadioTickBox.css": "./dist/RadioTickBox.css" | |||||
}, | }, | ||||
"typesVersions": { | "typesVersions": { | ||||
"*": {} | "*": {} | ||||
@@ -73,24 +73,24 @@ | |||||
padding-right: 4rem; | padding-right: 4rem; | ||||
} | } | ||||
.tesseract-design-tag-input.tag-input textarea + div > span { | |||||
.tesseract-design-tag-input textarea + div > span { | |||||
padding: 0.125rem; | padding: 0.125rem; | ||||
border-radius: 0.25rem; | border-radius: 0.25rem; | ||||
line-height: 1; | line-height: 1; | ||||
background-color: rgb(var(--color-positive) / 25%); | 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; | 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)); | color: rgb(var(--color-primary)); | ||||
padding: 0; | padding: 0; | ||||
width: 1rem; | width: 1rem; | ||||
margin-left: 0.25rem; | 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)); | color: rgb(var(--color-primary)); | ||||
} | } |
@@ -32,7 +32,7 @@ export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonP | |||||
{...etcProps} | {...etcProps} | ||||
ref={forwardedRef} | ref={forwardedRef} | ||||
className={clsx( | 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', | 'focus:outline-0 focus:ring-4', | ||||
'active:ring-tertiary/50', | 'active:ring-tertiary/50', | ||||
{ | { | ||||
@@ -40,8 +40,8 @@ export const LinkButton = React.forwardRef<LinkButtonDerivedElement, LinkButtonP | |||||
'inline-flex max-w-full align-middle': !block, | '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-4': !(compact || menuItem), | ||||
'pr-2': compact || menuItem, | 'pr-2': compact || menuItem, | ||||
}, | }, | ||||
@@ -74,7 +74,9 @@ | |||||
"require": "./dist/cjs/production/index.js", | "require": "./dist/cjs/production/index.js", | ||||
"import": "./dist/esm/production/index.js", | "import": "./dist/esm/production/index.js", | ||||
"types": "./dist/types/index.d.ts" | "types": "./dist/types/index.d.ts" | ||||
} | |||||
}, | |||||
"./dist/Slider.css": "./dist/Slider.css", | |||||
"./dist/Spinner.css": "./dist/Spinner.css" | |||||
}, | }, | ||||
"typesVersions": { | "typesVersions": { | ||||
"*": {} | "*": {} | ||||
@@ -0,0 +1,9 @@ | |||||
{ | |||||
"root": true, | |||||
"extends": [ | |||||
"lxsmnsyc/typescript" | |||||
], | |||||
"parserOptions": { | |||||
"project": "./tsconfig.eslint.json" | |||||
} | |||||
} |
@@ -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 |
@@ -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. |
@@ -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" | |||||
} | |||||
} |
@@ -0,0 +1,3 @@ | |||||
{ | |||||
"target": "es2018" | |||||
} |
@@ -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; | |||||
}; |
@@ -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; | |||||
}; |
@@ -0,0 +1,2 @@ | |||||
export * from './content-type'; | |||||
export * from './description'; |
@@ -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" | |||||
} | |||||
} |
@@ -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" | |||||
} | |||||
} |
@@ -0,0 +1,9 @@ | |||||
{ | |||||
"root": true, | |||||
"extends": [ | |||||
"lxsmnsyc/typescript/react" | |||||
], | |||||
"parserOptions": { | |||||
"project": "./tsconfig.eslint.json" | |||||
} | |||||
} |
@@ -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 |
@@ -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. |
@@ -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": { | |||||
"*": {} | |||||
} | |||||
} |
@@ -0,0 +1,3 @@ | |||||
{ | |||||
"target": "es2018" | |||||
} |
@@ -1,21 +1,21 @@ | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import {augmentAudioFile, getMimeTypeDescription} from '@/utils/blob'; | |||||
import {augmentAudioFile, getMimeTypeDescription} from 'packages/web-kitchensink-reactnext/src/utils/blob'; | |||||
import { | import { | ||||
formatFileSize, | formatFileSize, | ||||
formatNumeral, | formatNumeral, | ||||
formatSecondsDurationConcise, | formatSecondsDurationConcise, | ||||
formatSecondsDurationPrecise, | 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 {useMediaControls} from '../../hooks/interactive'; | ||||
import {useFileMetadata, useFileUrl} from '@/categories/blob/react'; | |||||
import {useFileMetadata, useFileUrl} from 'src/index'; | |||||
import clsx from 'clsx'; | 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; | export type AudioFilePreviewDerivedElement = HTMLAudioElement; | ||||
@@ -1,11 +1,11 @@ | |||||
import * as React from 'react'; | 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 {useMediaControls} from '../../hooks/interactive'; | ||||
import {useFileMetadata, useFileUrl} from '@/categories/blob/react'; | |||||
import {useFileMetadata, useFileUrl} from 'src/index'; | |||||
import clsx from 'clsx'; | 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; | export type AudioMiniFilePreviewDerivedElement = HTMLAudioElement; | ||||
@@ -1,12 +1,12 @@ | |||||
import * as React from 'react'; | 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 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; | export type BinaryFilePreviewDerivedElement = HTMLDivElement; | ||||
@@ -1,12 +1,12 @@ | |||||
import * as React from 'react'; | 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 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; | export type ImageFilePreviewDerivedElement = HTMLImageElement; | ||||
@@ -1,12 +1,12 @@ | |||||
import * as React from 'react'; | 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 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; | type TextFilePreviewDerivedComponent = HTMLDivElement; | ||||
@@ -1,12 +1,12 @@ | |||||
import * as React from 'react'; | 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 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; | export type VideoFilePreviewDerivedComponent = HTMLVideoElement; | ||||
@@ -1,5 +1,5 @@ | |||||
import * as React from 'react'; | 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 { | export interface UseFileUrlOptions { | ||||
file?: Partial<File>; | file?: Partial<File>; |
@@ -1,7 +1,6 @@ | |||||
export * from './components/AudioFilePreview'; | export * from './components/AudioFilePreview'; | ||||
export * from './components/AudioMiniFilePreview'; | export * from './components/AudioMiniFilePreview'; | ||||
export * from './components/BinaryFilePreview'; | export * from './components/BinaryFilePreview'; | ||||
export * from './components/FileSelectBox'; | |||||
export * from './components/ImageFilePreview'; | export * from './components/ImageFilePreview'; | ||||
export * from './components/TextFilePreview'; | export * from './components/TextFilePreview'; | ||||
export * from './components/VideoFilePreview'; | export * from './components/VideoFilePreview'; |
@@ -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" | |||||
} | |||||
} |
@@ -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" | |||||
} | |||||
} |
@@ -0,0 +1,8 @@ | |||||
/// <reference types="vitest" /> | |||||
export default ({ | |||||
test: { | |||||
global: true, | |||||
environment: 'jsdom', | |||||
}, | |||||
}); |
@@ -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; |
@@ -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; |
@@ -82,6 +82,58 @@ importers: | |||||
specifier: ^0.28.1 | specifier: ^0.28.1 | ||||
version: 0.28.1(jsdom@21.1.0) | 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: | categories/choice/react: | ||||
dependencies: | dependencies: | ||||
'@tesseract-design/web-base': | '@tesseract-design/web-base': | ||||
@@ -535,6 +587,37 @@ importers: | |||||
specifier: ^0.28.1 | specifier: ^0.28.1 | ||||
version: 0.28.1(jsdom@21.1.0) | 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: | packages/image-utils: | ||||
dependencies: | dependencies: | ||||
colorthief: | colorthief: | ||||
@@ -617,6 +700,51 @@ importers: | |||||
specifier: ^0.28.1 | specifier: ^0.28.1 | ||||
version: 0.28.1(jsdom@21.1.0) | 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: | packages/react-utils: | ||||
devDependencies: | devDependencies: | ||||
'@testing-library/jest-dom': | '@testing-library/jest-dom': | ||||
@@ -720,32 +848,35 @@ importers: | |||||
specifier: ^0.28.1 | specifier: ^0.28.1 | ||||
version: 0.28.1(jsdom@21.1.0) | version: 0.28.1(jsdom@21.1.0) | ||||
packages/web-kitchensink-reactnext: | |||||
showcases/web-kitchensink-reactnext: | |||||
dependencies: | dependencies: | ||||
'@modal-sh/audio-utils': | '@modal-sh/audio-utils': | ||||
specifier: workspace:* | specifier: workspace:* | ||||
version: link:../audio-utils | |||||
version: link:../../packages/audio-utils | |||||
'@modal-sh/image-utils': | '@modal-sh/image-utils': | ||||
specifier: workspace:* | specifier: workspace:* | ||||
version: link:../image-utils | |||||
version: link:../../packages/image-utils | |||||
'@modal-sh/react-binary-data-canvas': | '@modal-sh/react-binary-data-canvas': | ||||
specifier: workspace:* | specifier: workspace:* | ||||
version: link:../react-binary-data-canvas | |||||
version: link:../../packages/react-binary-data-canvas | |||||
'@modal-sh/react-utils': | '@modal-sh/react-utils': | ||||
specifier: workspace:* | specifier: workspace:* | ||||
version: link:../react-utils | |||||
version: link:../../packages/react-utils | |||||
'@modal-sh/text-utils': | '@modal-sh/text-utils': | ||||
specifier: workspace:* | specifier: workspace:* | ||||
version: link:../text-utils | |||||
version: link:../../packages/text-utils | |||||
'@modal-sh/video-utils': | '@modal-sh/video-utils': | ||||
specifier: workspace:* | specifier: workspace:* | ||||
version: link:../video-utils | |||||
version: link:../../packages/video-utils | |||||
'@tesseract-design/web-action-react': | '@tesseract-design/web-action-react': | ||||
specifier: workspace:* | specifier: workspace:* | ||||
version: link:../../categories/action/react | version: link:../../categories/action/react | ||||
'@tesseract-design/web-base': | '@tesseract-design/web-base': | ||||
specifier: workspace:* | specifier: workspace:* | ||||
version: link:../../base | version: link:../../base | ||||
'@tesseract-design/web-blob-react': | |||||
specifier: workspace:* | |||||
version: link:../../categories/blob/react | |||||
'@tesseract-design/web-choice-react': | '@tesseract-design/web-choice-react': | ||||
specifier: workspace:* | specifier: workspace:* | ||||
version: link:../../categories/choice/react | version: link:../../categories/choice/react | ||||
@@ -2,3 +2,4 @@ packages: | |||||
- 'base' | - 'base' | ||||
- 'packages/*' | - 'packages/*' | ||||
- 'categories/**' | - 'categories/**' | ||||
- 'showcases/**' |
@@ -38,6 +38,7 @@ | |||||
"@modal-sh/react-binary-data-canvas": "workspace:*", | "@modal-sh/react-binary-data-canvas": "workspace:*", | ||||
"@tesseract-design/web-base": "workspace:*", | "@tesseract-design/web-base": "workspace:*", | ||||
"@tesseract-design/web-action-react": "workspace:*", | "@tesseract-design/web-action-react": "workspace:*", | ||||
"@tesseract-design/web-blob-react": "workspace:*", | |||||
"@tesseract-design/web-color-react": "workspace:*", | "@tesseract-design/web-color-react": "workspace:*", | ||||
"@tesseract-design/web-choice-react": "workspace:*", | "@tesseract-design/web-choice-react": "workspace:*", | ||||
"@tesseract-design/web-formatted-react": "workspace:*", | "@tesseract-design/web-formatted-react": "workspace:*", |
@@ -1,5 +1,5 @@ | |||||
import { NextPage } from 'next'; | 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'; | import * as Action from '@tesseract-design/web-action-react'; | ||||
const RegistrationFormPage: NextPage = () => { | const RegistrationFormPage: NextPage = () => { |
@@ -1,117 +1,8 @@ | |||||
import * as mimeTypes from 'mime-types'; | |||||
import {getTextMetadata, TextMetadata} from '@modal-sh/text-utils'; | import {getTextMetadata, TextMetadata} from '@modal-sh/text-utils'; | ||||
import {getMetadataFromUrl as getImageMetadataFromUrl, ImageMetadata} from '@modal-sh/image-utils'; | import {getMetadataFromUrl as getImageMetadataFromUrl, ImageMetadata} from '@modal-sh/image-utils'; | ||||
import {getMetadataFromUrl as getAudioMetadataFromUrl, AudioMetadata} from '@modal-sh/audio-utils'; | import {getMetadataFromUrl as getAudioMetadataFromUrl, AudioMetadata} from '@modal-sh/audio-utils'; | ||||
import {getMetadataFromUrl as getVideoMetadataFromUrl, VideoMetadata} from '@modal-sh/video-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) => { | export const readAsDataURL = (blob: Partial<Blob>) => new Promise<string>((resolve, reject) => { | ||||
// TODO when to revoke these URLs | // TODO when to revoke these URLs | ||||
// return URL.createObjectURL(blob as Blob); | // return URL.createObjectURL(blob as Blob); |