import { h, Component } from 'preact'; import * as style from './style.css'; import 'add-css:./style.css'; import { cleanSet, cleanMerge } from '../../util/clean-modify'; import type { SourceImage, OutputType } from '..'; import { EncoderOptions, EncoderState, ProcessorState, ProcessorOptions, encoderMap, } from '../../feature-meta'; import Expander from './Expander'; import Toggle from './Toggle'; import Select from './Select'; import { Options as QuantOptionsComponent } from 'features/processors/quantize/client'; import { Options as ResizeOptionsComponent } from 'features/processors/resize/client'; import { SwapIcon } from 'client/lazy-app/icons'; interface Props { index: 0 | 1; mobileView: boolean; source?: SourceImage; encoderState?: EncoderState; processorState: ProcessorState; onEncoderTypeChange(index: 0 | 1, newType: OutputType): void; onEncoderOptionsChange(index: 0 | 1, newOptions: EncoderOptions): void; onProcessorOptionsChange(index: 0 | 1, newOptions: ProcessorState): void; onCopyToOtherSideClick(index: 0 | 1): void; } interface State { supportedEncoderMap?: PartialButNotUndefined; } type PartialButNotUndefined = { [P in keyof T]: T[P]; }; const supportedEncoderMapP: Promise> = (async () => { const supportedEncoderMap: PartialButNotUndefined = { ...encoderMap, }; // Filter out entries where the feature test fails await Promise.all( Object.entries(encoderMap).map(async ([encoderName, details]) => { if ('featureTest' in details && !(await details.featureTest())) { delete supportedEncoderMap[encoderName as keyof typeof encoderMap]; } }), ); return supportedEncoderMap; })(); export default class Options extends Component { state: State = { supportedEncoderMap: undefined, }; constructor() { super(); supportedEncoderMapP.then((supportedEncoderMap) => this.setState({ supportedEncoderMap }), ); } private onEncoderTypeChange = (event: Event) => { const el = event.currentTarget as HTMLSelectElement; // The select element only has values matching encoder types, // so 'as' is safe here. const type = el.value as OutputType; this.props.onEncoderTypeChange(this.props.index, type); }; private onProcessorEnabledChange = (event: Event) => { const el = event.currentTarget as HTMLInputElement; const processor = el.name.split('.')[0] as keyof ProcessorState; this.props.onProcessorOptionsChange( this.props.index, cleanSet(this.props.processorState, `${processor}.enabled`, el.checked), ); }; private onQuantizerOptionsChange = (opts: ProcessorOptions['quantize']) => { this.props.onProcessorOptionsChange( this.props.index, cleanMerge(this.props.processorState, 'quantize', opts), ); }; private onResizeOptionsChange = (opts: ProcessorOptions['resize']) => { this.props.onProcessorOptionsChange( this.props.index, cleanMerge(this.props.processorState, 'resize', opts), ); }; private onEncoderOptionsChange = (newOptions: EncoderOptions) => { this.props.onEncoderOptionsChange(this.props.index, newOptions); }; private onCopyToOtherSideClick = () => { this.props.onCopyToOtherSideClick(this.props.index); }; render( { source, encoderState, processorState }: Props, { supportedEncoderMap }: State, ) { const encoder = encoderState && encoderMap[encoderState.type]; const EncoderOptionComponent = encoder && 'Options' in encoder ? encoder.Options : undefined; return (
{!encoderState ? null : (

Edit

{processorState.resize.enabled ? ( ) : null} {processorState.quantize.enabled ? ( ) : null}
)}

Compress

{supportedEncoderMap ? ( ) : ( )}
{EncoderOptionComponent && ( )}
); } }