rlz-engine 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ import { type SxProps } from '@mui/material';
2
+ import { type ReactElement } from 'react';
3
+ export type ItemType = {
4
+ value: string;
5
+ label: string;
6
+ fontStyle?: string;
7
+ };
8
+ export type ItemsType = readonly ItemType[];
9
+ interface Props {
10
+ items: ItemsType;
11
+ selected: readonly string[];
12
+ onSelectedChange: (selected: string[]) => void;
13
+ selectMany: boolean;
14
+ selectZero: boolean;
15
+ sx?: SxProps;
16
+ }
17
+ export declare function ItemsSelect(props: Props): ReactElement;
18
+ export {};
@@ -0,0 +1,87 @@
1
+ import { Clear as ClearIcon } from '@mui/icons-material';
2
+ import { Box, Chip, FilledInput, FormControl, IconButton, InputAdornment, InputLabel, Stack } from '@mui/material';
3
+ import useEmblaCarousel from 'embla-carousel-react';
4
+ import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
5
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
6
+ import { useResizeDetector } from 'react-resize-detector';
7
+ const A_STYLE = { fontSize: '0' };
8
+ export function ItemsSelect(props) {
9
+ const { height, ref } = useResizeDetector();
10
+ const [carouselRef, carouselApi] = useEmblaCarousel({}, [WheelGesturesPlugin()]);
11
+ const selected = new Set(props.selected);
12
+ const pageHeight = (24 + 8) * 4;
13
+ const [pages, setPages] = useState(1);
14
+ const [page, setPage] = useState(0);
15
+ const [filter, setFilter] = useState(null);
16
+ const onSelect = useCallback((api) => {
17
+ setPage(api.selectedScrollSnap());
18
+ }, [pages]);
19
+ useEffect(() => {
20
+ setPages(height === undefined ? 1 : Math.ceil(height / pageHeight));
21
+ }, [height]);
22
+ useEffect(() => {
23
+ if (carouselApi !== undefined) {
24
+ carouselApi.on('select', onSelect);
25
+ return () => {
26
+ carouselApi.off('select', onSelect);
27
+ };
28
+ }
29
+ }, [carouselApi, onSelect]);
30
+ const onSelectedChangeContainer = useMemo(() => { return { v: props.onSelectedChange }; }, []);
31
+ onSelectedChangeContainer.v = props.onSelectedChange;
32
+ const items = useMemo(() => {
33
+ const items = filter === null
34
+ ? props.items
35
+ : (() => {
36
+ const re = new RegExp(filter, 'i');
37
+ return props.items.filter(i => re.test(i.label));
38
+ })();
39
+ return items.map((i) => {
40
+ const fontStyle = typeof i === 'string' ? undefined : i.fontStyle;
41
+ if (selected.has(i.value)) {
42
+ const chip = React.createElement(Chip, { key: i.value, color: 'primary', size: 'small', label: i.label, sx: { fontStyle } });
43
+ if (props.selectZero || (props.selectMany && selected.size > 1)) {
44
+ return (React.createElement("a", { key: i.value, style: A_STYLE, onClick: () => {
45
+ onSelectedChangeContainer.v(props.selected.filter(s => s !== i.value));
46
+ } }, chip));
47
+ }
48
+ return chip;
49
+ }
50
+ return (React.createElement("a", { key: i.value, style: A_STYLE, onClick: () => {
51
+ if (props.selectMany) {
52
+ onSelectedChangeContainer.v([...selected, i.value]);
53
+ }
54
+ else {
55
+ onSelectedChangeContainer.v([i.value]);
56
+ }
57
+ } },
58
+ React.createElement(Chip, { size: 'small', label: i.label, sx: { fontStyle } })));
59
+ });
60
+ }, [props.items, props.selected, filter, props.selectMany]);
61
+ return (React.createElement(Box, { sx: props.sx },
62
+ React.createElement(FormControl, { variant: 'filled', size: 'small', fullWidth: true, sx: { mb: 2 } },
63
+ React.createElement(InputLabel, null, 'Filter'),
64
+ React.createElement(FilledInput, { fullWidth: true, size: 'small', value: filter ?? '', onChange: (ev) => {
65
+ setFilter(ev.target.value === '' ? null : ev.target.value);
66
+ }, endAdornment: (React.createElement(InputAdornment, { position: 'end' },
67
+ React.createElement(IconButton, { disabled: filter === null, onClick: () => { setFilter(null); }, edge: 'end' },
68
+ React.createElement(ClearIcon, null)))) })),
69
+ React.createElement(Box, { overflow: 'hidden', ref: carouselRef },
70
+ React.createElement(Stack, { direction: 'row' },
71
+ React.createElement(Box, { height: pageHeight, overflow: 'hidden', flex: '0 0 100%' },
72
+ React.createElement(Box, { display: 'flex', ref: ref, flexWrap: 'wrap', gap: 1 }, items)),
73
+ Array.from(Iterator.range(pages ?? 0).map((p) => {
74
+ if (p === 0) {
75
+ return undefined;
76
+ }
77
+ return (React.createElement(Box, { key: p, height: pageHeight, overflow: 'hidden', position: 'relative', flex: '0 0 100%' },
78
+ React.createElement(Box, { position: 'absolute', top: -pageHeight * p },
79
+ React.createElement(Box, { display: 'flex', flexWrap: 'wrap', gap: 1 }, items))));
80
+ })))),
81
+ React.createElement(Stack, { direction: 'row', justifyContent: 'center', gap: 1, mt: 1, height: 10 }, pages > 1
82
+ ? Array.from(Iterator.range(pages ?? 0).map((p) => {
83
+ return (React.createElement("a", { key: p, style: A_STYLE, onClick: () => { carouselApi?.scrollTo(p); } },
84
+ React.createElement(Box, { width: 10, height: 10, bgcolor: p === page ? 'secondary.main' : 'text.primary', borderRadius: 10 })));
85
+ }))
86
+ : null)));
87
+ }
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "rlz-engine",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Deps and tools for my style of development",
5
5
  "scripts": {
6
- "build": "tsc"
6
+ "build": "tsc",
7
+ "publish": "rm -rf dist && tsc && npm publish"
7
8
  },
8
9
  "author": "Dmitry Maslennikov <maslennikovdm@gmail.com>",
9
10
  "license": "ISC",
@@ -45,6 +46,8 @@
45
46
  "@types/react-router-dom": "^5.3.3",
46
47
  "acme-client": "^5.4.0",
47
48
  "ajv-formats": "^3.0.1",
49
+ "embla-carousel-react": "^8.5.1",
50
+ "embla-carousel-wheel-gestures": "^8.0.1",
48
51
  "fastify": "^5.1.0",
49
52
  "fastify-acme": "^1.0.5",
50
53
  "fastify-plugin": "^5.0.1",
@@ -57,9 +60,10 @@
57
60
  "pino-pretty": "^13.0.0",
58
61
  "react": "^19.0.0",
59
62
  "react-dom": "^19.0.0",
63
+ "react-resize-detector": "^12.0.2",
60
64
  "react-router-dom": "^7.1.1",
61
65
  "uuidv7": "^1.0.2",
62
66
  "zod": "^3.23.8",
63
67
  "zod-to-json-schema": "^3.23.5"
64
68
  }
65
- }
69
+ }