diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..296bbd2 --- /dev/null +++ b/biome.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.7.3/schema.json", + "organizeImports": { + "enabled": true + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 120 + }, + "linter": { + "enabled": false, + "rules": { + "recommended": true, + "style": { + "useConst": "off", + "noParameterAssign": "off" + }, + "suspicious": { + "noShadowRestrictedNames": "off" + } + } + }, + "files": { + "ignore": ["python"] + }, + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + } +} diff --git a/main.ts b/main.ts index 533d296..4c553a0 100644 --- a/main.ts +++ b/main.ts @@ -1,28 +1,28 @@ -import * as vizarr from './src/index'; -import debounce from 'just-debounce-it'; +import debounce from "just-debounce-it"; +import * as vizarr from "./src/index"; function initStandaloneApp(viewer: vizarr.VizarrViewer) { const url = new URL(window.location.href); - if (!url.searchParams.has('source')) { + if (!url.searchParams.has("source")) { return; } // see if we have initial viewState - if (url.searchParams.has('viewState')) { - const viewState = JSON.parse(url.searchParams.get('viewState')!); + if (url.searchParams.has("viewState")) { + const viewState = JSON.parse(url.searchParams.get("viewState")!); viewer.setViewState(viewState); } // Add event listener to sync viewState as query param. // Debounce to limit how quickly we are pushing to browser history viewer.on( - 'viewStateChange', + "viewStateChange", debounce((update: vizarr.ViewState) => { const url = new URL(window.location.href); - url.searchParams.set('viewState', JSON.stringify(update)); - window.history.pushState({}, '', decodeURIComponent(url.href)); - }, 200) + url.searchParams.set("viewState", JSON.stringify(update)); + window.history.pushState({}, "", decodeURIComponent(url.href)); + }, 200), ); // parse image config @@ -39,13 +39,13 @@ function initStandaloneApp(viewer: vizarr.VizarrViewer) { // Only update history if the new loacation is different from the current if (window.location.href !== newLocation) { - window.history.pushState(null, '', newLocation); + window.history.pushState(null, "", newLocation); } } async function main() { console.log(`vizarr v${vizarr.version}: https://github.com/hms-dbmi/vizarr`); - const viewer = await vizarr.createViewer(document.querySelector('#root')!); + const viewer = await vizarr.createViewer(document.querySelector("#root")!); initStandaloneApp(viewer); } diff --git a/package.json b/package.json index bda7a24..8f79962 100644 --- a/package.json +++ b/package.json @@ -4,16 +4,14 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build", + "build": "npm run check && vite build", "preview": "vite preview", - "export": "npm run check && npm run build", - "format": "prettier --write \"{src,types}/**/*.{js,jsx,ts,tsx}\" vite.config.js main.ts", - "lint": "prettier --check \"{src,types}/**/*.{js,jsx,ts,tsx}\" vite.config.js main.ts", + "lint": "biome ci", + "fix": "biome check --write", "check": "tsc" }, "dependencies": { "@hms-dbmi/viv": "^0.16.0", - "@hms-dbmi/vizarr": "link:", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/styles": "^4.11.5", @@ -29,19 +27,13 @@ "react-dom": "^18.2.0", "zarrita": "^0.4.0-next.14" }, - "prettier": { - "trailingComma": "es5", - "printWidth": 120, - "semi": true, - "singleQuote": true - }, "devDependencies": { + "@biomejs/biome": "^1.8.3", "@danmarshall/deckgl-typings": "^4.3.10", "@types/node": "^20.14.11", "@types/react": "^18.2.51", "@types/react-dom": "^18.2.18", "@vitejs/plugin-react": "^4.3.1", - "prettier": "^3.3.3", "typescript": "^5.5.3", "vite": "^5.3.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9e3111e..5181e13 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,6 @@ importers: '@hms-dbmi/viv': specifier: ^0.16.0 version: 0.16.1(ivym5kozhaht7xh26fph2oljpq) - '@hms-dbmi/vizarr': - specifier: 'link:' - version: 'link:' '@material-ui/core': specifier: ^4.11.0 version: 4.12.4(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -57,6 +54,9 @@ importers: specifier: ^0.4.0-next.14 version: 0.4.0-next.14 devDependencies: + '@biomejs/biome': + specifier: ^1.8.3 + version: 1.8.3 '@danmarshall/deckgl-typings': specifier: ^4.3.10 version: 4.9.28 @@ -72,9 +72,6 @@ importers: '@vitejs/plugin-react': specifier: ^4.3.1 version: 4.3.1(vite@5.3.4(@types/node@20.14.11)) - prettier: - specifier: ^3.3.3 - version: 3.3.3 typescript: specifier: ^5.5.3 version: 5.5.3 @@ -195,6 +192,59 @@ packages: resolution: {integrity: sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==} engines: {node: '>=6.9.0'} + '@biomejs/biome@1.8.3': + resolution: {integrity: sha512-/uUV3MV+vyAczO+vKrPdOW0Iaet7UnJMU4bNMinggGJTAnBPjCoLEYcyYtYHNnUNYlv4xZMH6hVIQCAozq8d5w==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@1.8.3': + resolution: {integrity: sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@1.8.3': + resolution: {integrity: sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@1.8.3': + resolution: {integrity: sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@1.8.3': + resolution: {integrity: sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@1.8.3': + resolution: {integrity: sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@1.8.3': + resolution: {integrity: sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@1.8.3': + resolution: {integrity: sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@1.8.3': + resolution: {integrity: sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + '@danmarshall/deckgl-typings@4.9.28': resolution: {integrity: sha512-cvp0sPunaOgzI/6Kb9zQjNPOegFrli8t/mWLESTDarZT1xBGe9FwLQ9wQT0XFcVagdlhe2NFBx0oeRy0L4f1GQ==} @@ -1257,11 +1307,6 @@ packages: resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} engines: {node: ^10 || ^12 || >=14} - prettier@3.3.3: - resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} - engines: {node: '>=14'} - hasBin: true - prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -1595,6 +1640,41 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + '@biomejs/biome@1.8.3': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 1.8.3 + '@biomejs/cli-darwin-x64': 1.8.3 + '@biomejs/cli-linux-arm64': 1.8.3 + '@biomejs/cli-linux-arm64-musl': 1.8.3 + '@biomejs/cli-linux-x64': 1.8.3 + '@biomejs/cli-linux-x64-musl': 1.8.3 + '@biomejs/cli-win32-arm64': 1.8.3 + '@biomejs/cli-win32-x64': 1.8.3 + + '@biomejs/cli-darwin-arm64@1.8.3': + optional: true + + '@biomejs/cli-darwin-x64@1.8.3': + optional: true + + '@biomejs/cli-linux-arm64-musl@1.8.3': + optional: true + + '@biomejs/cli-linux-arm64@1.8.3': + optional: true + + '@biomejs/cli-linux-x64-musl@1.8.3': + optional: true + + '@biomejs/cli-linux-x64@1.8.3': + optional: true + + '@biomejs/cli-win32-arm64@1.8.3': + optional: true + + '@biomejs/cli-win32-x64@1.8.3': + optional: true + '@danmarshall/deckgl-typings@4.9.28': dependencies: '@types/hammerjs': 2.0.45 @@ -2829,8 +2909,6 @@ snapshots: picocolors: 1.0.1 source-map-js: 1.2.0 - prettier@3.3.3: {} - prop-types@15.8.1: dependencies: loose-envify: 1.4.0 diff --git a/src/ZarrPixelSource.ts b/src/ZarrPixelSource.ts index b5fb4f4..613c845 100644 --- a/src/ZarrPixelSource.ts +++ b/src/ZarrPixelSource.ts @@ -1,18 +1,18 @@ -import * as zarr from 'zarrita'; +import * as zarr from "zarrita"; -import type * as viv from '@vivjs/types'; -import type { Readable } from '@zarrita/storage'; +import type * as viv from "@vivjs/types"; +import type { Readable } from "@zarrita/storage"; -import { assert } from './utils'; -import { getImageSize } from '@hms-dbmi/viv'; +import { getImageSize } from "@hms-dbmi/viv"; +import { assert } from "./utils"; // TODO: Export from top-level zarrita type Slice = ReturnType; -const X_AXIS_NAME = 'x'; -const Y_AXIS_NAME = 'y'; -const RGBA_CHANNEL_AXIS_NAME = '_c'; -const SUPPORTED_DTYPES = ['Uint8', 'Uint16', 'Uint32', 'Float32', 'Int8', 'Int16', 'Int32', 'Float64'] as const; +const X_AXIS_NAME = "x"; +const Y_AXIS_NAME = "y"; +const RGBA_CHANNEL_AXIS_NAME = "_c"; +const SUPPORTED_DTYPES = ["Uint8", "Uint16", "Uint32", "Float32", "Int8", "Int16", "Int32", "Float64"] as const; export class ZarrPixelSource = Array> implements viv.PixelSource { #arr: zarr.Array; @@ -25,7 +25,7 @@ export class ZarrPixelSource = Array> implements options: { labels: viv.Labels; tileSize: number; - } + }, ) { this.#arr = arr; this.labels = options.labels; @@ -64,10 +64,10 @@ export class ZarrPixelSource = Array> implements // a BoundsCheckError which is picked up in `ZarrPixelSource.onTileError` // and ignored by deck.gl. if (xStart === xStop || yStart === yStop) { - throw new BoundsCheckError('Tile slice is zero-sized.'); + throw new BoundsCheckError("Tile slice is zero-sized."); } if (xStart < 0 || yStart < 0 || xStop > width || yStop > height) { - throw new BoundsCheckError('Tile slice is out of bounds.'); + throw new BoundsCheckError("Tile slice is out of bounds."); } sel[this.labels.indexOf(X_AXIS_NAME)] = zarr.slice(xStart, xStop); @@ -126,8 +126,5 @@ function isSupportedDtype(dtype: string): dtype is viv.SupportedDtype { } class BoundsCheckError extends Error { - name = 'BoundsCheckError'; - constructor(message?: string) { - super(message); - } + name = "BoundsCheckError"; } diff --git a/src/codecs/jpeg2k.ts b/src/codecs/jpeg2k.ts index 258ed06..9f498b1 100644 --- a/src/codecs/jpeg2k.ts +++ b/src/codecs/jpeg2k.ts @@ -2,16 +2,16 @@ // `deno bundle` since the pdf.js dist does not include ESM source code (only UMD or CJS). // @ts-ignore -import { JpxImage } from 'https://cdn.jsdelivr.net/gh/mozilla/pdf.js@30bd5f0/src/core/jpx.js'; +import { JpxImage } from "https://cdn.jsdelivr.net/gh/mozilla/pdf.js@30bd5f0/src/core/jpx.js"; export default class Jpeg2k { - kind = 'bytes_to_bytes' as const; - static codecId = 'jpeg2k'; + kind = "bytes_to_bytes" as const; + static codecId = "jpeg2k"; static fromConfig(): Jpeg2k { return new Jpeg2k(); } encode(_: Uint8Array): never { - throw new Error('encode not implemented'); + throw new Error("encode not implemented"); } async decode(data: Uint8Array): Promise { const img = new JpxImage(); diff --git a/src/codecs/register.ts b/src/codecs/register.ts index cf9f022..c9c93dd 100644 --- a/src/codecs/register.ts +++ b/src/codecs/register.ts @@ -1,2 +1,2 @@ -import { registry } from 'zarrita'; -registry.set('jpeg2k', () => import('./jpeg2k').then((m) => m.default)); +import { registry } from "zarrita"; +registry.set("jpeg2k", () => import("./jpeg2k").then((m) => m.default)); diff --git a/src/components/LayerController/AcquisitionController.tsx b/src/components/LayerController/AcquisitionController.tsx index 7ecf928..92910b2 100644 --- a/src/components/LayerController/AcquisitionController.tsx +++ b/src/components/LayerController/AcquisitionController.tsx @@ -1,8 +1,8 @@ -import React from 'react'; -import { Grid, NativeSelect } from '@material-ui/core'; -import { useAtomValue } from 'jotai'; -import type { ChangeEvent } from 'react'; -import type { ControllerProps } from '../../state'; +import { Grid, NativeSelect } from "@material-ui/core"; +import { useAtomValue } from "jotai"; +import React from "react"; +import type { ChangeEvent } from "react"; +import type { ControllerProps } from "../../state"; function AcquisitionController({ sourceAtom }: ControllerProps) { const sourceData = useAtomValue(sourceAtom); @@ -15,10 +15,10 @@ function AcquisitionController({ sourceAtom }: ControllerProps) { const handleSelectionChange = (event: ChangeEvent) => { let value = event.target.value; const url = new URL(window.location.href); - if (value === '-1') { - url.searchParams.delete('acquisition'); + if (value === "-1") { + url.searchParams.delete("acquisition"); } else { - url.searchParams.set('acquisition', value); + url.searchParams.set("acquisition", value); } window.location.href = decodeURIComponent(url.href); }; @@ -26,7 +26,7 @@ function AcquisitionController({ sourceAtom }: ControllerProps) { return ( <> - + diff --git a/src/components/LayerController/AddChannelButton.tsx b/src/components/LayerController/AddChannelButton.tsx index cd791c5..e507f9e 100644 --- a/src/components/LayerController/AddChannelButton.tsx +++ b/src/components/LayerController/AddChannelButton.tsx @@ -1,11 +1,11 @@ -import React, { useState } from 'react'; -import type { MouseEvent, ChangeEvent } from 'react'; -import { useAtom } from 'jotai'; -import { IconButton, Popover, Paper, Typography, Divider, NativeSelect } from '@material-ui/core'; -import { Add } from '@material-ui/icons'; +import { Divider, IconButton, NativeSelect, Paper, Popover, Typography } from "@material-ui/core"; +import { Add } from "@material-ui/icons"; +import { useAtom } from "jotai"; +import React, { useState } from "react"; +import type { ChangeEvent, MouseEvent } from "react"; -import { calcDataRange, hexToRGB, MAX_CHANNELS } from '../../utils'; -import type { ControllerProps } from '../../state'; +import type { ControllerProps } from "../../state"; +import { MAX_CHANNELS, calcDataRange, hexToRGB } from "../../utils"; function AddChannelButton({ sourceAtom, layerAtom }: ControllerProps) { const [source, setSource] = useAtom(sourceAtom); @@ -73,10 +73,10 @@ function AddChannelButton({ sourceAtom, layerAtom }: ControllerProps) { onClick={handleClick} aria-describedby={id} style={{ - backgroundColor: 'transparent', + backgroundColor: "transparent", padding: 0, zIndex: 2, - cursor: 'pointer', + cursor: "pointer", }} disabled={layer.layerProps.selections.length === MAX_CHANNELS} > @@ -88,20 +88,20 @@ function AddChannelButton({ sourceAtom, layerAtom }: ControllerProps) { anchorEl={anchorEl} onClose={handleClose} anchorOrigin={{ - vertical: 'bottom', - horizontal: 'left', + vertical: "bottom", + horizontal: "left", }} transformOrigin={{ - vertical: 'top', - horizontal: 'left', + vertical: "top", + horizontal: "left", }} > - + selection: diff --git a/src/components/LayerController/AxisOptions.tsx b/src/components/LayerController/AxisOptions.tsx index dd57ad9..390925a 100644 --- a/src/components/LayerController/AxisOptions.tsx +++ b/src/components/LayerController/AxisOptions.tsx @@ -1,15 +1,15 @@ -import React, { useState } from 'react'; -import type { MouseEvent, ChangeEvent } from 'react'; -import { useAtom, useAtomValue } from 'jotai'; -import { IconButton, Popover, Paper, Typography, Divider, Input } from '@material-ui/core'; -import { withStyles } from '@material-ui/styles'; -import { MoreHoriz } from '@material-ui/icons'; -import type { ControllerProps } from '../../state'; +import { Divider, IconButton, Input, Paper, Popover, Typography } from "@material-ui/core"; +import { MoreHoriz } from "@material-ui/icons"; +import { withStyles } from "@material-ui/styles"; +import { useAtom, useAtomValue } from "jotai"; +import React, { useState } from "react"; +import type { ChangeEvent, MouseEvent } from "react"; +import type { ControllerProps } from "../../state"; const DenseInput = withStyles({ root: { - width: '5.5em', - fontSize: '0.7em', + width: "5.5em", + fontSize: "0.7em", }, })(Input); @@ -60,10 +60,10 @@ function AxisOptions({ sourceAtom, layerAtom, axisIndex, max }: ControllerProps< onClick={handleClick} aria-describedby={id} style={{ - backgroundColor: 'transparent', + backgroundColor: "transparent", padding: 0, zIndex: 2, - cursor: 'pointer', + cursor: "pointer", }} > @@ -74,15 +74,15 @@ function AxisOptions({ sourceAtom, layerAtom, axisIndex, max }: ControllerProps< anchorEl={anchorEl} onClose={handleClose} anchorOrigin={{ - vertical: 'bottom', - horizontal: 'left', + vertical: "bottom", + horizontal: "left", }} transformOrigin={{ - vertical: 'top', - horizontal: 'left', + vertical: "top", + horizontal: "left", }} > - + Index: diff --git a/src/components/LayerController/AxisSlider.tsx b/src/components/LayerController/AxisSlider.tsx index e65c387..a73600c 100644 --- a/src/components/LayerController/AxisSlider.tsx +++ b/src/components/LayerController/AxisSlider.tsx @@ -1,20 +1,20 @@ -import { Grid, Typography, Divider } from '@material-ui/core'; -import { useAtom, useAtomValue } from 'jotai'; -import type { ChangeEvent } from 'react'; -import React, { useState, useEffect } from 'react'; -import { Slider } from '@material-ui/core'; -import { withStyles } from '@material-ui/styles'; -import DimensionOptions from './AxisOptions'; -import type { ControllerProps } from '../../state'; +import { Divider, Grid, Typography } from "@material-ui/core"; +import { Slider } from "@material-ui/core"; +import { withStyles } from "@material-ui/styles"; +import { useAtom, useAtomValue } from "jotai"; +import type { ChangeEvent } from "react"; +import React, { useState, useEffect } from "react"; +import type { ControllerProps } from "../../state"; +import DimensionOptions from "./AxisOptions"; const DenseSlider = withStyles({ root: { - color: 'white', - padding: '10px 0px 5px 0px', - marginRight: '5px', + color: "white", + padding: "10px 0px 5px 0px", + marginRight: "5px", }, active: { - boxshadow: '0px 0px 0px 8px rgba(158, 158, 158, 0.16)', + boxshadow: "0px 0px 0px 8px rgba(158, 158, 158, 0.16)", }, })(Slider); @@ -28,7 +28,7 @@ function AxisSlider({ sourceAtom, layerAtom, axisIndex, max }: ControllerProps

-

+
{axisLabel}: {value}/{max} diff --git a/src/components/LayerController/AxisSliders.tsx b/src/components/LayerController/AxisSliders.tsx index 02545d3..05cf27a 100644 --- a/src/components/LayerController/AxisSliders.tsx +++ b/src/components/LayerController/AxisSliders.tsx @@ -1,8 +1,8 @@ -import React from 'react'; -import { Grid, Divider } from '@material-ui/core'; -import { useAtomValue } from 'jotai'; -import AxisSlider from './AxisSlider'; -import type { ControllerProps } from '../../state'; +import { Divider, Grid } from "@material-ui/core"; +import { useAtomValue } from "jotai"; +import React from "react"; +import type { ControllerProps } from "../../state"; +import AxisSlider from "./AxisSlider"; function AxisSliders({ sourceAtom, layerAtom }: ControllerProps) { const sourceData = useAtomValue(sourceAtom); diff --git a/src/components/LayerController/ChannelController.tsx b/src/components/LayerController/ChannelController.tsx index d7eb792..20bcfd2 100644 --- a/src/components/LayerController/ChannelController.tsx +++ b/src/components/LayerController/ChannelController.tsx @@ -1,11 +1,11 @@ -import React from 'react'; -import { useAtom } from 'jotai'; -import { useAtomValue } from 'jotai'; -import type { ChangeEvent } from 'react'; -import { Slider, Typography, Grid, IconButton } from '@material-ui/core'; -import { RadioButtonChecked, RadioButtonUnchecked } from '@material-ui/icons'; -import ChannelOptions from './ChannelOptions'; -import type { ControllerProps } from '../../state'; +import { Grid, IconButton, Slider, Typography } from "@material-ui/core"; +import { RadioButtonChecked, RadioButtonUnchecked } from "@material-ui/icons"; +import { useAtom } from "jotai"; +import { useAtomValue } from "jotai"; +import React from "react"; +import type { ChangeEvent } from "react"; +import type { ControllerProps } from "../../state"; +import ChannelOptions from "./ChannelOptions"; interface ChannelConfig { channelIndex: number; @@ -47,7 +47,7 @@ function ChannelController({ sourceAtom, layerAtom, channelIndex }: ControllerPr <> -
+
{label} @@ -62,7 +62,7 @@ function ChannelController({ sourceAtom, layerAtom, channelIndex }: ControllerPr diff --git a/src/components/LayerController/ChannelOptions.tsx b/src/components/LayerController/ChannelOptions.tsx index 44a6dfe..43263da 100644 --- a/src/components/LayerController/ChannelOptions.tsx +++ b/src/components/LayerController/ChannelOptions.tsx @@ -1,17 +1,17 @@ -import React, { useState } from 'react'; -import type { MouseEvent, ChangeEvent } from 'react'; -import { useAtom } from 'jotai'; -import { useAtomValue } from 'jotai'; -import { IconButton, Popover, Paper, Typography, Divider, Input, NativeSelect } from '@material-ui/core'; -import { withStyles } from '@material-ui/styles'; -import { MoreHoriz, Remove } from '@material-ui/icons'; -import type { ControllerProps } from '../../state'; -import ColorPalette from './ColorPalette'; +import { Divider, IconButton, Input, NativeSelect, Paper, Popover, Typography } from "@material-ui/core"; +import { MoreHoriz, Remove } from "@material-ui/icons"; +import { withStyles } from "@material-ui/styles"; +import { useAtom } from "jotai"; +import { useAtomValue } from "jotai"; +import React, { useState } from "react"; +import type { ChangeEvent, MouseEvent } from "react"; +import type { ControllerProps } from "../../state"; +import ColorPalette from "./ColorPalette"; const DenseInput = withStyles({ root: { - width: '5.5em', - fontSize: '0.7em', + width: "5.5em", + fontSize: "0.7em", }, })(Input); @@ -57,7 +57,7 @@ function ChannelOptions({ sourceAtom, layerAtom, channelIndex }: ControllerProps const [smin, smax] = contrastLimits[channelIndex]; // Calculate climit update - const [umin, umax] = targetId === 'min' ? [value, cmax] : [cmin, value]; + const [umin, umax] = targetId === "min" ? [value, cmax] : [cmin, value]; // Update sliders if needed if (umin > smin) contrastLimits[channelIndex] = [umin, smax]; @@ -122,10 +122,10 @@ function ChannelOptions({ sourceAtom, layerAtom, channelIndex }: ControllerProps onClick={handleClick} aria-describedby={id} style={{ - backgroundColor: 'transparent', + backgroundColor: "transparent", padding: 0, zIndex: 2, - cursor: 'pointer', + cursor: "pointer", }} > @@ -136,16 +136,16 @@ function ChannelOptions({ sourceAtom, layerAtom, channelIndex }: ControllerProps anchorEl={anchorEl} onClose={handleClose} anchorOrigin={{ - vertical: 'bottom', - horizontal: 'left', + vertical: "bottom", + horizontal: "left", }} transformOrigin={{ - vertical: 'top', - horizontal: 'left', + vertical: "top", + horizontal: "left", }} > - -
+ +
remove: @@ -156,7 +156,7 @@ function ChannelOptions({ sourceAtom, layerAtom, channelIndex }: ControllerProps color: -
+
diff --git a/src/components/LayerController/ColorPalette.tsx b/src/components/LayerController/ColorPalette.tsx index 5110767..b9c77fe 100644 --- a/src/components/LayerController/ColorPalette.tsx +++ b/src/components/LayerController/ColorPalette.tsx @@ -1,20 +1,20 @@ -import React from 'react'; -import { IconButton } from '@material-ui/core'; -import { Lens } from '@material-ui/icons'; -import { makeStyles } from '@material-ui/styles'; -import { COLORS, hexToRGB } from '../../utils'; +import { IconButton } from "@material-ui/core"; +import { Lens } from "@material-ui/icons"; +import { makeStyles } from "@material-ui/styles"; +import React from "react"; +import { COLORS, hexToRGB } from "../../utils"; const useStyles = makeStyles(() => ({ container: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - padding: '2px', + display: "flex", + justifyContent: "space-between", + alignItems: "center", + padding: "2px", }, button: { - padding: '3px', - width: '16px', - height: '16px', + padding: "3px", + width: "16px", + height: "16px", }, })); diff --git a/src/components/LayerController/Content.tsx b/src/components/LayerController/Content.tsx index 766f8e8..b9e75f7 100644 --- a/src/components/LayerController/Content.tsx +++ b/src/components/LayerController/Content.tsx @@ -1,22 +1,22 @@ -import React from 'react'; -import { useAtomValue } from 'jotai'; -import { AccordionDetails, Grid, Typography, Divider } from '@material-ui/core'; -import { withStyles } from '@material-ui/styles'; +import { AccordionDetails, Divider, Grid, Typography } from "@material-ui/core"; +import { withStyles } from "@material-ui/styles"; +import { useAtomValue } from "jotai"; +import React from "react"; -import AcquisitionController from './AcquisitionController'; -import AddChannelButton from './AddChannelButton'; -import OpacitySlider from './OpacitySlider'; -import AxisSliders from './AxisSliders'; -import ChannelController from './ChannelController'; +import AcquisitionController from "./AcquisitionController"; +import AddChannelButton from "./AddChannelButton"; +import AxisSliders from "./AxisSliders"; +import ChannelController from "./ChannelController"; +import OpacitySlider from "./OpacitySlider"; -import { range } from '../../utils'; -import type { ControllerProps } from '../../state'; +import type { ControllerProps } from "../../state"; +import { range } from "../../utils"; const Details = withStyles({ root: { - padding: '2px 5px', - borderLeft: '1px solid rgba(150, 150, 150, .2)', - borderRight: '1px solid rgba(150, 150, 150, .2)', + padding: "2px 5px", + borderLeft: "1px solid rgba(150, 150, 150, .2)", + borderRight: "1px solid rgba(150, 150, 150, .2)", }, })(AccordionDetails); diff --git a/src/components/LayerController/Header.tsx b/src/components/LayerController/Header.tsx index f02eb82..82d3b45 100644 --- a/src/components/LayerController/Header.tsx +++ b/src/components/LayerController/Header.tsx @@ -1,27 +1,27 @@ -import React from 'react'; -import { useAtomValue } from 'jotai'; -import { AccordionSummary, Typography } from '@material-ui/core'; -import { withStyles } from '@material-ui/styles'; -import LayerVisibilityButton from './LayerVisibilityButton'; -import type { ControllerProps } from '../../state'; +import { AccordionSummary, Typography } from "@material-ui/core"; +import { withStyles } from "@material-ui/styles"; +import { useAtomValue } from "jotai"; +import React from "react"; +import type { ControllerProps } from "../../state"; +import LayerVisibilityButton from "./LayerVisibilityButton"; const DenseAccordionSummary = withStyles({ root: { - borderBottom: '1px solid rgba(150, 150, 150, .125)', - backgroundColor: 'rgba(150, 150, 150, 0.25)', - display: 'block', - padding: '0 3px', + borderBottom: "1px solid rgba(150, 150, 150, .125)", + backgroundColor: "rgba(150, 150, 150, 0.25)", + display: "block", + padding: "0 3px", height: 27, minHeight: 27, - overflow: 'hidden', - transition: 'none', - '&$expanded': { + overflow: "hidden", + transition: "none", + "&$expanded": { minHeight: 27, }, }, content: { margin: 0, - '&$expanded': { + "&$expanded": { margin: 0, }, }, @@ -37,12 +37,12 @@ function Header({ sourceAtom, layerAtom, name }: ControllerProps) { const label = `layer-controller-${sourceData.id}`; return ( -
+
diff --git a/src/components/LayerController/LayerVisibilityButton.tsx b/src/components/LayerController/LayerVisibilityButton.tsx index 2a9e3e5..4b7acd1 100644 --- a/src/components/LayerController/LayerVisibilityButton.tsx +++ b/src/components/LayerController/LayerVisibilityButton.tsx @@ -1,10 +1,10 @@ -import React from 'react'; -import { useAtom } from 'jotai'; -import { useAtomValue } from 'jotai'; -import type { MouseEvent } from 'react'; -import { IconButton } from '@material-ui/core'; -import { Visibility, VisibilityOff } from '@material-ui/icons'; -import type { ControllerProps } from '../../state'; +import { IconButton } from "@material-ui/core"; +import { Visibility, VisibilityOff } from "@material-ui/icons"; +import { useAtom } from "jotai"; +import { useAtomValue } from "jotai"; +import React from "react"; +import type { MouseEvent } from "react"; +import type { ControllerProps } from "../../state"; function LayerVisibilityButton({ sourceAtom, layerAtom }: ControllerProps) { const sourceData = useAtomValue(sourceAtom); @@ -21,8 +21,8 @@ function LayerVisibilityButton({ sourceAtom, layerAtom }: ControllerProps) { aria-label={`toggle-layer-visibility-${sourceData.id}`} onClick={toggle} style={{ - backgroundColor: 'transparent', - marginTop: '2px', + backgroundColor: "transparent", + marginTop: "2px", color: `rgb(255, 255, 255, ${layer.on ? 1 : 0.5})`, }} > diff --git a/src/components/LayerController/OpacitySlider.tsx b/src/components/LayerController/OpacitySlider.tsx index 89dd64d..e09a40f 100644 --- a/src/components/LayerController/OpacitySlider.tsx +++ b/src/components/LayerController/OpacitySlider.tsx @@ -1,18 +1,18 @@ -import React from 'react'; -import { useAtom } from 'jotai'; -import type { ChangeEvent } from 'react'; -import { Slider } from '@material-ui/core'; -import { withStyles } from '@material-ui/styles'; -import type { ControllerProps } from '../../state'; +import { Slider } from "@material-ui/core"; +import { withStyles } from "@material-ui/styles"; +import { useAtom } from "jotai"; +import React from "react"; +import type { ChangeEvent } from "react"; +import type { ControllerProps } from "../../state"; const DenseSlider = withStyles({ root: { - color: 'white', - padding: '10px 0px 5px 0px', - marginRight: '5px', + color: "white", + padding: "10px 0px 5px 0px", + marginRight: "5px", }, active: { - boxshadow: '0px 0px 0px 8px rgba(158, 158, 158, 0.16)', + boxshadow: "0px 0px 0px 8px rgba(158, 158, 158, 0.16)", }, })(Slider); diff --git a/src/components/LayerController/index.tsx b/src/components/LayerController/index.tsx index afc094f..70f3c09 100644 --- a/src/components/LayerController/index.tsx +++ b/src/components/LayerController/index.tsx @@ -1,25 +1,25 @@ -import React from 'react'; -import { useAtomValue } from 'jotai'; -import MuiAccordion from '@material-ui/core/Accordion'; -import { withStyles } from '@material-ui/styles'; +import MuiAccordion from "@material-ui/core/Accordion"; +import { withStyles } from "@material-ui/styles"; +import { useAtomValue } from "jotai"; +import React from "react"; -import Header from './Header'; -import Content from './Content'; -import type { ControllerProps } from '../../state'; -import { layerFamilyAtom } from '../../state'; +import type { ControllerProps } from "../../state"; +import { layerFamilyAtom } from "../../state"; +import Content from "./Content"; +import Header from "./Header"; const Accordion = withStyles({ root: { - borderBottom: '1px solid rgba(150, 150, 150, .2)', + borderBottom: "1px solid rgba(150, 150, 150, .2)", width: 200, - boxshadow: 'none', - '&:not(:last-child)': { + boxshadow: "none", + "&:not(:last-child)": { borderBottom: 0, }, - '&:before': { - display: 'none', + "&:before": { + display: "none", }, - '&$expanded': { + "&$expanded": { margin: 0, padding: 0, }, @@ -29,10 +29,10 @@ const Accordion = withStyles({ }, })(MuiAccordion); -function LayerController({ sourceAtom }: Omit) { +function LayerController({ sourceAtom }: Omit) { const sourceInfo = useAtomValue(sourceAtom); const layerAtom = layerFamilyAtom(sourceInfo); - const { name = '' } = sourceInfo; + const { name = "" } = sourceInfo; return (
diff --git a/src/components/Menu.tsx b/src/components/Menu.tsx index 16adff2..69d7255 100644 --- a/src/components/Menu.tsx +++ b/src/components/Menu.tsx @@ -1,31 +1,31 @@ -import React, { useReducer } from 'react'; -import { useAtomValue } from 'jotai'; -import { Grid, IconButton } from '@material-ui/core'; -import { Add, Remove } from '@material-ui/icons'; -import { makeStyles } from '@material-ui/styles'; +import { Grid, IconButton } from "@material-ui/core"; +import { Add, Remove } from "@material-ui/icons"; +import { makeStyles } from "@material-ui/styles"; +import { useAtomValue } from "jotai"; +import React, { useReducer } from "react"; -import { sourceInfoAtomAtoms } from '../state'; -import LayerController from './LayerController'; +import { sourceInfoAtomAtoms } from "../state"; +import LayerController from "./LayerController"; const useStyles = makeStyles({ root: { zIndex: 1, - position: 'absolute', - backgroundColor: 'rgba(0, 0, 0, 0.7)', - borderRadius: '5px', - left: '5px', - top: '5px', + position: "absolute", + backgroundColor: "rgba(0, 0, 0, 0.7)", + borderRadius: "5px", + left: "5px", + top: "5px", }, scroll: { maxHeight: 500, - overflowX: 'hidden', - overflowY: 'scroll', - '&::-webkit-scrollbar': { - display: 'none', - background: 'transparent', + overflowX: "hidden", + overflowY: "scroll", + "&::-webkit-scrollbar": { + display: "none", + background: "transparent", }, - scrollbarWidth: 'none', - flexDirection: 'column', + scrollbarWidth: "none", + flexDirection: "column", }, }); @@ -38,14 +38,14 @@ function Menu(props: { open?: boolean }) { {hidden ? : } -