@bccampus/ui-components 0.4.0 → 0.4.2
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/AbstractFocusProvider-CxvlcEki.js +29 -0
- package/dist/AbstractSelectionProvider-BtaROstC.js +30 -0
- package/dist/CompositeDataItem-DuHOHCWy.js +158 -0
- package/dist/ListboxFocusProvider.d.ts +149 -0
- package/dist/ListboxFocusProvider.js +53 -0
- package/dist/MultipleSelectionProvider.d.ts +141 -0
- package/dist/MultipleSelectionProvider.js +19 -0
- package/dist/SingleSelectionProvider.d.ts +141 -0
- package/dist/SingleSelectionProvider.js +23 -0
- package/dist/composite-component-DSUbd1XS.js +122 -0
- package/dist/composite.d.ts +108 -51
- package/dist/composite.js +57 -447
- package/dist/icon-generator-tuhuqdpL.js +76 -0
- package/dist/icon-generator.d.ts +11 -4
- package/dist/icon-generator.js +4 -74
- package/dist/listbox.d.ts +171 -0
- package/dist/listbox.js +76 -0
- package/dist/masked-image-generator.js +7 -7
- package/dist/ui-components.js +5 -5
- package/package.json +5 -1
- package/src/components/ui/composite/CompositeData.ts +22 -114
- package/src/components/ui/composite/FocusProvider/AbstractFocusProvider.ts +83 -0
- package/src/components/ui/composite/FocusProvider/ListboxFocusProvider.ts +74 -0
- package/src/components/ui/composite/SelectionProvider/AbstractSelectionProvider.ts +45 -0
- package/src/components/ui/composite/SelectionProvider/MultipleSelectionProvider.ts +28 -0
- package/src/components/ui/composite/SelectionProvider/SingleSelectionProvider.ts +37 -0
- package/src/components/ui/composite/composite-component-item.tsx +12 -10
- package/src/components/ui/composite/composite-component.tsx +39 -68
- package/src/components/ui/composite/index.ts +4 -1
- package/src/components/ui/composite/listbox.tsx +61 -0
- package/src/components/ui/composite/types.ts +51 -30
- package/src/components/ui/icon-generator/index.ts +2 -0
- package/src/hooks/use-keyboard-event.ts +31 -42
- package/vite.config.ts +6 -2
- package/src/components/ui/composite/composite-data-context.tsx +0 -31
- /package/dist/{igenerate-tiles.d.ts → generate-tiles.d.ts} +0 -0
- /package/dist/{igenerate-tiles.js → generate-tiles.js} +0 -0
|
@@ -1,52 +1,38 @@
|
|
|
1
1
|
import type { KeyboardEvent, KeyboardEventHandler } from 'react';
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const KEY_MAPPINGS: Record<string, string> = {
|
|
7
|
-
' ': 'space',
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export interface KeyBindings {
|
|
4
|
+
interface KeyBindings {
|
|
11
5
|
[sequence: string]: (event: KeyboardEvent) => void;
|
|
12
6
|
}
|
|
13
|
-
|
|
14
7
|
interface KeybindingLookupItem {
|
|
15
|
-
sequence:
|
|
8
|
+
sequence: RegExp;
|
|
16
9
|
handler: (event: KeyboardEvent) => void;
|
|
17
10
|
}
|
|
11
|
+
const MODIFIER_KEYS = new Set(["ctrl", "shift", "alt", "meta"]);
|
|
12
|
+
|
|
13
|
+
const KEY_MAPPINGS: Record<string, string> = {
|
|
14
|
+
" ": "space",
|
|
15
|
+
};
|
|
18
16
|
|
|
19
17
|
interface UseKeyboardEventOptions {
|
|
20
18
|
eventKeyProp: 'key' | 'code';
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
function isSequenceEqual<T>(sequenceA: Set<T>, sequenceB: Set<T>) {
|
|
24
|
-
if (sequenceA.size !== sequenceB.size) return false;
|
|
25
|
-
|
|
26
|
-
for (const element of sequenceB) {
|
|
27
|
-
if (!sequenceA.has(element)) return false;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
21
|
function parseKeybindings(bindings: KeyBindings) {
|
|
34
22
|
const parsedKeybindings: KeybindingLookupItem[] = [];
|
|
35
23
|
for (const [sequence, handler] of Object.entries(bindings)) {
|
|
36
24
|
const parsedSequence = sequence
|
|
37
25
|
.toLowerCase()
|
|
38
26
|
.trim()
|
|
39
|
-
.split(/\s*\+\s*/);
|
|
27
|
+
.split(/\s*\+\s*/g);
|
|
40
28
|
|
|
41
29
|
if (parsedSequence.length === 1 && MODIFIER_KEYS.has(parsedSequence[0])) {
|
|
42
|
-
console.error(`[useKeyboardEvent]
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
30
|
+
console.error(`[useKeyboardEvent] '${sequence}': A key sequence cannot be only a modifier key.`);
|
|
31
|
+
} else if (parsedSequence.includes("")) {
|
|
32
|
+
console.error(`[useKeyboardEvent] '${sequence}': Invalid key sequence defined in the sequence.`);
|
|
33
|
+
} else {
|
|
48
34
|
parsedKeybindings.push({
|
|
49
|
-
sequence: new
|
|
35
|
+
sequence: new RegExp("^" + parsedSequence.join("\\+") + "$"),
|
|
50
36
|
handler,
|
|
51
37
|
});
|
|
52
38
|
}
|
|
@@ -68,21 +54,22 @@ export function keyboardEventHandler(
|
|
|
68
54
|
const keyBindings = parseKeybindings(bindings);
|
|
69
55
|
|
|
70
56
|
return (event: KeyboardEvent) => {
|
|
71
|
-
const keySequence = new Set<string>();
|
|
72
57
|
const eventKey = event[_options.eventKeyProp];
|
|
58
|
+
const keySequence: string[] = [];
|
|
73
59
|
|
|
74
|
-
if (event.ctrlKey) keySequence.
|
|
60
|
+
if (event.ctrlKey) keySequence.push("ctrl");
|
|
75
61
|
|
|
76
|
-
if (event.shiftKey) keySequence.
|
|
62
|
+
if (event.shiftKey) keySequence.push("shift");
|
|
77
63
|
|
|
78
|
-
if (event.altKey) keySequence.
|
|
64
|
+
if (event.altKey) keySequence.push("alt");
|
|
79
65
|
|
|
80
|
-
if (event.metaKey) keySequence.
|
|
66
|
+
if (event.metaKey) keySequence.push("meta");
|
|
81
67
|
|
|
82
|
-
if (!KEY_MAPPINGS[eventKey]) keySequence.
|
|
83
|
-
else keySequence.
|
|
68
|
+
if (!KEY_MAPPINGS[eventKey]) keySequence.push(eventKey.toLowerCase());
|
|
69
|
+
else keySequence.push(KEY_MAPPINGS[eventKey]);
|
|
84
70
|
|
|
85
|
-
const matchedSequence = keyBindings.find(keyBinding =>
|
|
71
|
+
const matchedSequence = keyBindings.find((keyBinding) => keyBinding.sequence.test(keySequence.join("+")));
|
|
72
|
+
|
|
86
73
|
if (matchedSequence) {
|
|
87
74
|
event.preventDefault();
|
|
88
75
|
event.stopPropagation();
|
|
@@ -91,16 +78,18 @@ export function keyboardEventHandler(
|
|
|
91
78
|
};
|
|
92
79
|
}
|
|
93
80
|
|
|
81
|
+
|
|
94
82
|
/**
|
|
95
83
|
* Returns a `KeyboardEventHandler`
|
|
96
|
-
* that checks the defined key
|
|
84
|
+
* that checks the defined key sequences against a keyboard event
|
|
97
85
|
* and executes the handler of the first matched key binding.
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
86
|
+
*
|
|
87
|
+
* Key Sequence Rules:
|
|
88
|
+
* - Multiple key must be seperated by `+`
|
|
89
|
+
* - Only the following modifier key values as allowed: ctrl, shift, alt, meta
|
|
90
|
+
* - Modifier key must followed by a key
|
|
91
|
+
* - Space character (` `) cannot be used in the key sequences. Use the `space` keyword instead.
|
|
92
|
+
* - Plus character (`+`) cannot be used in the key sequences. Use the `shit + =` sequence instead.
|
|
104
93
|
*
|
|
105
94
|
* @example
|
|
106
95
|
* ```
|
package/vite.config.ts
CHANGED
|
@@ -21,8 +21,12 @@ export default defineConfig({
|
|
|
21
21
|
entry: {
|
|
22
22
|
'ui-components': path.resolve(__dirname, 'src/components/ui/index.ts'),
|
|
23
23
|
'composite': path.resolve(__dirname, 'src/components/ui/composite/index.ts'),
|
|
24
|
-
'
|
|
25
|
-
'
|
|
24
|
+
'listbox': path.resolve(__dirname, 'src/components/ui/composite/listbox.tsx'),
|
|
25
|
+
'SingleSelectionProvider': path.resolve(__dirname, 'src/components/ui/composite/SelectionProvider/SingleSelectionProvider.ts'),
|
|
26
|
+
'MultipleSelectionProvider': path.resolve(__dirname, 'src/components/ui/composite/SelectionProvider/MultipleSelectionProvider.ts'),
|
|
27
|
+
'ListboxFocusProvider': path.resolve(__dirname, 'src/components/ui/composite/FocusProvider/ListboxFocusProvider.ts'),
|
|
28
|
+
'icon-generator': path.resolve(__dirname, 'src/components/ui/icon-generator/index.ts'),
|
|
29
|
+
'generate-tiles': path.resolve(__dirname, 'src/components/ui/icon-generator/generate-tiles.tsx'),
|
|
26
30
|
'masked-image-generator': path.resolve(__dirname, 'src/components/ui/icon-generator/masked-image-generator.tsx'),
|
|
27
31
|
'caption': path.resolve(__dirname, 'src/components/ui/typography/caption.tsx'),
|
|
28
32
|
'banner': path.resolve(__dirname, 'src/components/ui/banner.tsx'),
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext, useMemo } from "react";
|
|
2
|
-
import { CompositeData } from "./CompositeData";
|
|
3
|
-
import type { CompositeOptions } from "./types";
|
|
4
|
-
|
|
5
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
-
const CompositeDataContext = createContext<CompositeData<any> | undefined>(undefined);
|
|
7
|
-
|
|
8
|
-
export function useCompositeContext<T extends object>() {
|
|
9
|
-
const context = useContext(CompositeDataContext);
|
|
10
|
-
|
|
11
|
-
if (!context) {
|
|
12
|
-
throw new Error("No CompositeDataContext has been set, use CompositeDataContext to provide a context");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return context as CompositeData<T>;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface CompositeComponentContextProps<T extends object> extends CompositeOptions {
|
|
19
|
-
data: T[];
|
|
20
|
-
children: React.ReactNode;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function CompositeComponentContext<T extends object>({
|
|
24
|
-
data,
|
|
25
|
-
children,
|
|
26
|
-
...compositeOptions
|
|
27
|
-
}: CompositeComponentContextProps<T>) {
|
|
28
|
-
const composite = useMemo(() => new CompositeData(data, compositeOptions), [data, compositeOptions]);
|
|
29
|
-
|
|
30
|
-
return <CompositeDataContext value={composite}>{children}</CompositeDataContext>;
|
|
31
|
-
}
|
|
File without changes
|
|
File without changes
|