Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions src/lib/params.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, { ChangeEvent } from "react";


type Validator<T> = {validate: (val: any) => T | undefined}

interface Parameter<T> {
tryParseAndSet: (str: string) => boolean;
get value(): T;
}

export class Num implements Parameter<number> {
_value: number;

get value(): number {
return this._value;
}

tryParseAndSet = (str: string) => {
const newValue = parseFloat(str);
if (isNaN(newValue)) {
return false;
}
this._value = newValue;
return true;
}

validate = (val: any) => {
if (typeof val !== 'number') {
return undefined;
}
return val;
}
}

export class Str implements Parameter<string> {
_value: string;
get value(): string {
return this._value;
}
tryParseAndSet = (str: string) => {
this._value = str;
return true;
}
validate = (val: any) => {
if (typeof val !== 'string') {
return undefined;
}
return val;
}
}

export class Arr<V, T extends Validator<V>> implements Parameter<V[]> {
_value: V[];
_validator: T;
constructor(validator: T) {
this._validator = validator;
}
get value(): V[] {
return this._value;
}

tryParseAndSet = (str: string) => {
const json = JSON.parse(str);
const res = this.validate(json);
if (res === undefined) {
return false;
}
this._value = res;
return true;
}

validate = (val: any) => {
if (!Array.isArray(val)) {
return undefined;
}
return val.map(this._validator.validate).every(v => v !== undefined) ? val as V[] : undefined;
}
}

export type ParameterProps<T> = {
label: string,
value: Parameter<T>
}

export type State<T> = {
value: Parameter<T>,
error: boolean
}

export class ParameterComponent<T> extends React.Component<ParameterProps<T>, State<T>> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Классовые компоненты - зло.
Давай перепишем на функциональные?
А ещё кажется что это не должно быть в lib
в lib скорее должно быть всё что нужно для алгоритмов
Давай компоненты для отрисовки вынесем в папочку components и будем делать по одному семантически важному компоненту в файле?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да, парадигма реакта сложная
Но в то же время достаточно простая и минималистичная.
Нужно просто немного по-другому думать.
Если нужно - я могу это доделать

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • если мы вынесем это из lib то можно будет более логично описать стили для того чтобы сделать красиво

label: string;
constructor(prop: ParameterProps<T>) {
super(prop);
this.label = prop.label;
this.state = {
value: prop.value,
error: false,
}
}

onChange(event: ChangeEvent<HTMLInputElement>) {
console.log(this)
try {
this.setState({
value: this.state.value,
error: !this.state.value.tryParseAndSet(event.target.value),
})
} catch {
this.setState({
value: this.state.value,
error: true,
})
}
}

render(): React.ReactNode {
return <div>{this.label}: <input onChange={(e) => this.onChange(e)}/> {this.state.error && "invalid value"}</div>
}

}

// export const ParametersComponent = <T, >(object: Parameter<T>) => {
// return <input onChange={object.tryParseAndSet}></input>
// const c = new Arr(new Arr(new Num()))
// console.log(c)
// console.log(c.tryParseAndSet("[[1], [2], [3]]"))
// console.log(c)
// }
14 changes: 12 additions & 2 deletions src/visualizers/bubble-sort/start.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { ParameterComponent, Num, Arr } from "../../lib/params"
import { BubbleSortArguments } from "./bubble-sort"

// type Props = {
// doStart: (args: BubbleSortArguments, noStop: boolean) => void
// }

export const BubbleSortStarter = ({ doStart }) => {

const propArr = {
label: "массив",
value: new Arr<number, Num>(new Num())
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Семантически непонятно - зачем передавать сначала number - тип, а потом Num - класс который по сути боксит значение при валидации
Может переименуем классы в ValidNum или SafeNum или во что то другое?

}

const components = [<ParameterComponent<number[]> {...propArr} />].map((v) => <li>{v}</li>);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если честно, то такая конструкция мне немного режет глаза :)
Давай перенесем map в return?
Или сделаем компонент для того чтобы рендерить несколько параметров через children?
Там же можно будет и стили накидать


return <div>
<button onClick={() => doStart([[5, 4, 3, 2, 1]], false)}>Start</button>
<button onClick={() => doStart([[5, 4, 3, 2, 1]], true)}>Run Full</button>
<ul>{components}</ul>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Когда рисуешь список компонентов каждому нужно указывать key=...

<button onClick={() => doStart([propArr.value.value], false)}>Start</button>
<button onClick={() => doStart([propArr.value.value], true)}>Run Full</button>
</div>;
}