@bccampus/ui-components 0.5.4 → 0.5.5
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.
- package/dist/components/ui/composite/layout-grid.d.ts +2 -0
- package/dist/components/ui/composite/layout-grid.js +59 -0
- package/dist/components/ui/icon-generator/generate-tiles.js +20 -4
- package/dist/components/ui/icon-generator/types.d.ts +3 -1
- package/package.json +1 -1
- package/src/components/ui/composite/layout-grid.tsx +61 -0
- package/src/components/ui/icon-generator/generate-tiles.tsx +24 -7
- package/src/components/ui/icon-generator/types.ts +3 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { CompositeComponent } from "./composite-component.js";
|
|
3
|
+
import { useRef, useCallback } from "react";
|
|
4
|
+
import "nanostores";
|
|
5
|
+
import { useKeyboardEvent } from "../../../hooks/use-keyboard-event.js";
|
|
6
|
+
function LayoutGrid({ data, ...props }) {
|
|
7
|
+
const compositeRef = useRef(null);
|
|
8
|
+
const focusElement = useCallback(() => {
|
|
9
|
+
const itemKey = data.focusProvider.focusedItem.get()?.key;
|
|
10
|
+
if (itemKey && compositeRef.current) {
|
|
11
|
+
const focusedItemEl = compositeRef.current.querySelector(`[data-key="${itemKey}"]`);
|
|
12
|
+
if (focusedItemEl) focusedItemEl.focus();
|
|
13
|
+
}
|
|
14
|
+
}, [data]);
|
|
15
|
+
const handleKeyboardEvent = useKeyboardEvent({
|
|
16
|
+
ArrowUp: () => {
|
|
17
|
+
data.focusProvider.focusUp();
|
|
18
|
+
focusElement();
|
|
19
|
+
},
|
|
20
|
+
ArrowDown: () => {
|
|
21
|
+
data.focusProvider.focusDown();
|
|
22
|
+
focusElement();
|
|
23
|
+
},
|
|
24
|
+
Home: () => {
|
|
25
|
+
data.focusProvider.focusToFirst();
|
|
26
|
+
focusElement();
|
|
27
|
+
},
|
|
28
|
+
End: () => {
|
|
29
|
+
data.focusProvider.focusToLast();
|
|
30
|
+
focusElement();
|
|
31
|
+
},
|
|
32
|
+
Space: () => {
|
|
33
|
+
data.selectionProvider?.toggleSelect();
|
|
34
|
+
focusElement();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const handleItemMouseEvent = useCallback(
|
|
38
|
+
(item) => {
|
|
39
|
+
data.focusProvider.focus(item.key);
|
|
40
|
+
data.selectionProvider?.toggleSelect(item);
|
|
41
|
+
focusElement();
|
|
42
|
+
},
|
|
43
|
+
[data.focusProvider, data.selectionProvider, focusElement]
|
|
44
|
+
);
|
|
45
|
+
return /* @__PURE__ */ jsx(
|
|
46
|
+
CompositeComponent,
|
|
47
|
+
{
|
|
48
|
+
ref: compositeRef,
|
|
49
|
+
variant: "listbox",
|
|
50
|
+
data,
|
|
51
|
+
onKeyDown: handleKeyboardEvent,
|
|
52
|
+
itemMouseEventHandler: handleItemMouseEvent,
|
|
53
|
+
...props
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
LayoutGrid
|
|
59
|
+
};
|
|
@@ -71,7 +71,12 @@ const TileTemplates = {
|
|
|
71
71
|
`tile-${tileX}-${tileY}`
|
|
72
72
|
);
|
|
73
73
|
},
|
|
74
|
-
[TileShape.RandBasic]: (tileX, tileY, tileSize, tileConfig) => TileTemplates[TileShape.Square + Math.floor(Math.random() * 4)](
|
|
74
|
+
[TileShape.RandBasic]: (tileX, tileY, tileSize, tileConfig) => TileTemplates[TileShape.Square + Math.floor(Math.random() * 4)](
|
|
75
|
+
tileX,
|
|
76
|
+
tileY,
|
|
77
|
+
tileSize,
|
|
78
|
+
tileConfig
|
|
79
|
+
),
|
|
75
80
|
[TileShape.TriangleSE]: (tileX, tileY, tileSize, tileConfig) => /* @__PURE__ */ jsx(
|
|
76
81
|
"path",
|
|
77
82
|
{
|
|
@@ -158,7 +163,12 @@ const TileTemplates = {
|
|
|
158
163
|
},
|
|
159
164
|
`tile-${tileX}-${tileY}`
|
|
160
165
|
),
|
|
161
|
-
[TileShape.CaretRand]: (tileX, tileY, tileSize, tileConfig) => TileTemplates[TileShape.CaretN + Math.floor(Math.random() * 4)](
|
|
166
|
+
[TileShape.CaretRand]: (tileX, tileY, tileSize, tileConfig) => TileTemplates[TileShape.CaretN + Math.floor(Math.random() * 4)](
|
|
167
|
+
tileX,
|
|
168
|
+
tileY,
|
|
169
|
+
tileSize,
|
|
170
|
+
tileConfig
|
|
171
|
+
),
|
|
162
172
|
[TileShape.PieSE]: (tileX, tileY, tileSize, tileConfig) => /* @__PURE__ */ jsx(
|
|
163
173
|
"path",
|
|
164
174
|
{
|
|
@@ -199,7 +209,12 @@ const TileTemplates = {
|
|
|
199
209
|
},
|
|
200
210
|
`tile-${tileX}-${tileY}`
|
|
201
211
|
),
|
|
202
|
-
[TileShape.PieRand]: (tileX, tileY, tileSize, tileConfig) => TileTemplates[TileShape.PieSE + Math.floor(Math.random() * 4)](
|
|
212
|
+
[TileShape.PieRand]: (tileX, tileY, tileSize, tileConfig) => TileTemplates[TileShape.PieSE + Math.floor(Math.random() * 4)](
|
|
213
|
+
tileX,
|
|
214
|
+
tileY,
|
|
215
|
+
tileSize,
|
|
216
|
+
tileConfig
|
|
217
|
+
)
|
|
203
218
|
};
|
|
204
219
|
const generateIconPattern = (width, height, tileConfig) => {
|
|
205
220
|
const pattern = [];
|
|
@@ -211,10 +226,11 @@ const generateIconPattern = (width, height, tileConfig) => {
|
|
|
211
226
|
}
|
|
212
227
|
return pattern;
|
|
213
228
|
};
|
|
229
|
+
const itemShape = (shape) => typeof shape === "string" ? TileShape[shape] : shape;
|
|
214
230
|
const generateTiles = (pattern, tileSize, tileClassName) => pattern.map(
|
|
215
231
|
(rows, y) => rows.map((item, x) => {
|
|
216
232
|
const tileConfig = typeof item === "object" ? { className: cn(tileClassName, item.className), scale: item.scale ?? 1, shape: item.shape } : { className: tileClassName, scale: 1, shape: item };
|
|
217
|
-
return TileTemplates[tileConfig.shape](x, y, tileSize, tileConfig);
|
|
233
|
+
return TileTemplates[itemShape(tileConfig.shape)](x, y, tileSize, tileConfig);
|
|
218
234
|
})
|
|
219
235
|
).flat();
|
|
220
236
|
export {
|
|
@@ -26,7 +26,9 @@ export declare const TileShape: {
|
|
|
26
26
|
readonly PieNE: 24;
|
|
27
27
|
readonly PieRand: 25;
|
|
28
28
|
};
|
|
29
|
-
export type
|
|
29
|
+
export type TileShapeKeys = keyof typeof TileShape;
|
|
30
|
+
export type TileShapeValue = (typeof TileShape)[TileShapeKeys];
|
|
31
|
+
export type TileShape = TileShapeKeys | TileShapeValue;
|
|
30
32
|
export interface TileConfig {
|
|
31
33
|
shape: TileShape;
|
|
32
34
|
scale?: number;
|
package/package.json
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { CompositeComponent } from "./composite-component";
|
|
2
|
+
import { useCallback, useRef } from "react";
|
|
3
|
+
import { CompositeDataItem } from "./CompositeDataItem";
|
|
4
|
+
import type { BaseCompositeProps } from "./types";
|
|
5
|
+
import { useKeyboardEvent } from "@/hooks/use-keyboard-event";
|
|
6
|
+
|
|
7
|
+
export function LayoutGrid<T extends object>({ data, ...props }: BaseCompositeProps<T>) {
|
|
8
|
+
const compositeRef = useRef<HTMLDivElement>(null);
|
|
9
|
+
|
|
10
|
+
const focusElement = useCallback(() => {
|
|
11
|
+
const itemKey = data.focusProvider.focusedItem.get()?.key;
|
|
12
|
+
|
|
13
|
+
if (itemKey && compositeRef.current) {
|
|
14
|
+
const focusedItemEl = compositeRef.current.querySelector<HTMLDivElement>(`[data-key="${itemKey}"]`);
|
|
15
|
+
if (focusedItemEl) focusedItemEl.focus();
|
|
16
|
+
}
|
|
17
|
+
}, [data]);
|
|
18
|
+
|
|
19
|
+
const handleKeyboardEvent = useKeyboardEvent({
|
|
20
|
+
ArrowUp: () => {
|
|
21
|
+
data.focusProvider.focusUp();
|
|
22
|
+
focusElement();
|
|
23
|
+
},
|
|
24
|
+
ArrowDown: () => {
|
|
25
|
+
data.focusProvider.focusDown();
|
|
26
|
+
focusElement();
|
|
27
|
+
},
|
|
28
|
+
Home: () => {
|
|
29
|
+
data.focusProvider.focusToFirst();
|
|
30
|
+
focusElement();
|
|
31
|
+
},
|
|
32
|
+
End: () => {
|
|
33
|
+
data.focusProvider.focusToLast();
|
|
34
|
+
focusElement();
|
|
35
|
+
},
|
|
36
|
+
Space: () => {
|
|
37
|
+
data.selectionProvider?.toggleSelect();
|
|
38
|
+
focusElement();
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const handleItemMouseEvent = useCallback(
|
|
43
|
+
(item: CompositeDataItem<T>) => {
|
|
44
|
+
data.focusProvider.focus(item.key);
|
|
45
|
+
data.selectionProvider?.toggleSelect(item);
|
|
46
|
+
focusElement();
|
|
47
|
+
},
|
|
48
|
+
[data.focusProvider, data.selectionProvider, focusElement]
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<CompositeComponent
|
|
53
|
+
ref={compositeRef}
|
|
54
|
+
variant="listbox"
|
|
55
|
+
data={data}
|
|
56
|
+
onKeyDown={handleKeyboardEvent}
|
|
57
|
+
itemMouseEventHandler={handleItemMouseEvent}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { JSX } from "react";
|
|
2
|
-
import type { TileConfig } from "./types";
|
|
2
|
+
import type { TileConfig, TileShapeValue } from "./types";
|
|
3
3
|
import { cn } from "@/lib/utils";
|
|
4
4
|
import { TileShape } from "./types";
|
|
5
5
|
|
|
@@ -21,7 +21,7 @@ const randomSet = [
|
|
|
21
21
|
type TileTemplatesConfig = TileConfig & Required<Pick<TileConfig, "scale">>;
|
|
22
22
|
|
|
23
23
|
const TileTemplates: Record<
|
|
24
|
-
|
|
24
|
+
TileShapeValue,
|
|
25
25
|
(tileX: number, tileY: number, tileSize: number, tileConfig: TileTemplatesConfig) => JSX.Element | null
|
|
26
26
|
> = {
|
|
27
27
|
[TileShape.Blank]: () => null,
|
|
@@ -85,7 +85,12 @@ const TileTemplates: Record<
|
|
|
85
85
|
);
|
|
86
86
|
},
|
|
87
87
|
[TileShape.RandBasic]: (tileX, tileY, tileSize, tileConfig) =>
|
|
88
|
-
TileTemplates[(TileShape.Square + Math.floor(Math.random() * 4)) as
|
|
88
|
+
TileTemplates[(TileShape.Square + Math.floor(Math.random() * 4)) as TileShapeValue](
|
|
89
|
+
tileX,
|
|
90
|
+
tileY,
|
|
91
|
+
tileSize,
|
|
92
|
+
tileConfig
|
|
93
|
+
),
|
|
89
94
|
|
|
90
95
|
[TileShape.TriangleSE]: (tileX, tileY, tileSize, tileConfig) => (
|
|
91
96
|
<path
|
|
@@ -124,7 +129,7 @@ const TileTemplates: Record<
|
|
|
124
129
|
/>
|
|
125
130
|
),
|
|
126
131
|
[TileShape.TriangleRand]: (tileX, tileY, tileSize, tileConfig) =>
|
|
127
|
-
TileTemplates[(TileShape.TriangleSE + Math.floor(Math.random() * 4)) as
|
|
132
|
+
TileTemplates[(TileShape.TriangleSE + Math.floor(Math.random() * 4)) as TileShapeValue](
|
|
128
133
|
tileX,
|
|
129
134
|
tileY,
|
|
130
135
|
tileSize,
|
|
@@ -168,7 +173,12 @@ const TileTemplates: Record<
|
|
|
168
173
|
/>
|
|
169
174
|
),
|
|
170
175
|
[TileShape.CaretRand]: (tileX, tileY, tileSize, tileConfig) =>
|
|
171
|
-
TileTemplates[(TileShape.CaretN + Math.floor(Math.random() * 4)) as
|
|
176
|
+
TileTemplates[(TileShape.CaretN + Math.floor(Math.random() * 4)) as TileShapeValue](
|
|
177
|
+
tileX,
|
|
178
|
+
tileY,
|
|
179
|
+
tileSize,
|
|
180
|
+
tileConfig
|
|
181
|
+
),
|
|
172
182
|
|
|
173
183
|
[TileShape.PieSE]: (tileX, tileY, tileSize, tileConfig) => (
|
|
174
184
|
<path
|
|
@@ -213,7 +223,12 @@ const TileTemplates: Record<
|
|
|
213
223
|
/>
|
|
214
224
|
),
|
|
215
225
|
[TileShape.PieRand]: (tileX, tileY, tileSize, tileConfig) =>
|
|
216
|
-
TileTemplates[(TileShape.PieSE + Math.floor(Math.random() * 4)) as
|
|
226
|
+
TileTemplates[(TileShape.PieSE + Math.floor(Math.random() * 4)) as TileShapeValue](
|
|
227
|
+
tileX,
|
|
228
|
+
tileY,
|
|
229
|
+
tileSize,
|
|
230
|
+
tileConfig
|
|
231
|
+
),
|
|
217
232
|
};
|
|
218
233
|
|
|
219
234
|
export const generateIconPattern = (width: number, height: number, tileConfig: TileShape | TileConfig) => {
|
|
@@ -228,6 +243,8 @@ export const generateIconPattern = (width: number, height: number, tileConfig: T
|
|
|
228
243
|
return pattern;
|
|
229
244
|
};
|
|
230
245
|
|
|
246
|
+
const itemShape = (shape: TileShape) => (typeof shape === "string" ? TileShape[shape] : shape);
|
|
247
|
+
|
|
231
248
|
export const generateTiles = (pattern: (TileShape | TileConfig)[][], tileSize: number, tileClassName?: string) =>
|
|
232
249
|
pattern
|
|
233
250
|
.map((rows, y) =>
|
|
@@ -237,7 +254,7 @@ export const generateTiles = (pattern: (TileShape | TileConfig)[][], tileSize: n
|
|
|
237
254
|
? { className: cn(tileClassName, item.className), scale: item.scale ?? 1, shape: item.shape }
|
|
238
255
|
: { className: tileClassName, scale: 1, shape: item };
|
|
239
256
|
|
|
240
|
-
return TileTemplates[tileConfig.shape](x, y, tileSize, tileConfig);
|
|
257
|
+
return TileTemplates[itemShape(tileConfig.shape)](x, y, tileSize, tileConfig);
|
|
241
258
|
})
|
|
242
259
|
)
|
|
243
260
|
.flat();
|
|
@@ -28,7 +28,9 @@ export const TileShape = {
|
|
|
28
28
|
PieRand: 25,
|
|
29
29
|
} as const;
|
|
30
30
|
|
|
31
|
-
export type
|
|
31
|
+
export type TileShapeKeys = keyof typeof TileShape;
|
|
32
|
+
export type TileShapeValue = (typeof TileShape)[TileShapeKeys];
|
|
33
|
+
export type TileShape = TileShapeKeys | TileShapeValue;
|
|
32
34
|
|
|
33
35
|
export interface TileConfig {
|
|
34
36
|
shape: TileShape;
|