jevstrudel.git / website / src / repl / components / incrementor / Incrementor.jsx
Incrementor.jsx67 lines · 2.2 KB · raw
1import { Textbox } from '@src/repl/components/panel/SettingsTab';
2import cx from '@src/cx.mjs';
3
4function IncButton({ children, className, ...buttonProps }) {
5  return (
6    <button
7      tabIndex={-1}
8      className={cx(
9        'border border-transparent p-1 text-center hover:text-background text-sm transition-all hover:bg-foreground active:bg-lineBackground disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none',
10        className,
11      )}
12      type="button"
13      {...buttonProps}
14    >
15      {children}
16    </button>
17  );
18}
19export function Incrementor({
20  onChange,
21  value,
22  min = -Infinity,
23  max = Infinity,
24  className,
25  incrementLabel = 'next page',
26  decrementLabel = 'prev page',
27  ...incrementorProps
28}) {
29  value = parseInt(value);
30  value = isNaN(value) ? '' : value;
31  return (
32    <div className={cx('w-fit bg-background relative flex  items-center"> rounded-md', className)}>
33      <Textbox
34        min={min}
35        max={max}
36        onChange={(v) => {
37          if (v.length && v < min) {
38            return;
39          }
40          onChange(v);
41        }}
42        type="number"
43        placeholder=""
44        value={value}
45        className="w-32 mb-0 mt-0 border-none rounded-r-none bg-transparent appearance-none [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
46        {...incrementorProps}
47      />
48      <div className="flex gap-1 ">
49        <IncButton disabled={value <= min} onClick={() => onChange(value - 1)} aria-label={decrementLabel}>
50          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" className="w-4 h-4">
51            <path d="M3.75 7.25a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z" />
52          </svg>
53        </IncButton>
54        <IncButton
55          className="rounded-r-md"
56          disabled={value >= max}
57          onClick={() => onChange(value + 1)}
58          aria-label={incrementLabel}
59        >
60          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" className="w-4 h-4">
61            <path d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z" />
62          </svg>
63        </IncButton>
64      </div>
65    </div>
66  );
67}