kaplay-plugin-ui 0.0.0 → 1.0.1
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/LICENSE +21 -0
- package/README.md +132 -0
- package/dist/plugin.cjs +162 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +221 -0
- package/dist/plugin.d.cts.map +1 -0
- package/dist/plugin.d.mts +221 -0
- package/dist/plugin.d.mts.map +1 -0
- package/dist/plugin.mjs +161 -0
- package/dist/plugin.mjs.map +1 -0
- package/dist/plugin.umd.js +166 -0
- package/dist/plugin.umd.js.map +1 -0
- package/dist/plugin.umd.min.js +2 -0
- package/dist/plugin.umd.min.js.map +1 -0
- package/global.d.ts +56 -0
- package/global.js +0 -0
- package/package.json +95 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Menglin "Mark" Xu <mark@remarkablemark.org>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# kaplay-plugin-ui
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/kaplay-plugin-ui)
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/kaplay-plugin-ui)
|
|
6
|
+
[](https://github.com/remarkablegames/kaplay-plugin-ui/actions/workflows/build.yml)
|
|
7
|
+
[](https://codecov.io/gh/remarkablegames/kaplay-plugin-ui)
|
|
8
|
+
|
|
9
|
+
🦖 KAPLAY plugin UI (see [API](#api)):
|
|
10
|
+
|
|
11
|
+
- `addButton`
|
|
12
|
+
- `getTheme`
|
|
13
|
+
- `setTheme`
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
Install [kaplay](https://www.npmjs.com/package/kaplay):
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install kaplay
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
[NPM](https://www.npmjs.com/package/kaplay-plugin-ui):
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm install kaplay-plugin-ui
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
[CDN](https://unpkg.com/browse/kaplay-plugin-ui/):
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<script src="https://unpkg.com/kaplay-plugin-ui@latest/dist/plugin.umd.js"></script>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
Import the plugin:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import kaplay from 'kaplay';
|
|
43
|
+
import { uiPlugin } from 'kaplay-plugin-ui';
|
|
44
|
+
|
|
45
|
+
const k = kaplay({
|
|
46
|
+
plugins: [uiPlugin],
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Import the plugin's global TypeScript definitions:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import 'kaplay-plugin-ui/global';
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
To load the plugin using a script:
|
|
57
|
+
|
|
58
|
+
```html
|
|
59
|
+
<script src="https://unpkg.com/kaplay@latest/dist/kaplay.js"></script>
|
|
60
|
+
<script src="https://unpkg.com/kaplay-plugin-ui@latest/dist/plugin.umd.js"></script>
|
|
61
|
+
|
|
62
|
+
<script>
|
|
63
|
+
const k = kaplay({
|
|
64
|
+
plugins: [KaplayPluginUI.uiPlugin],
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const button = k.addButton('Start');
|
|
68
|
+
</script>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Use the plugin:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
k.setTheme({
|
|
75
|
+
shape: {
|
|
76
|
+
borderRadius: 8,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
k.addButton('Start', {
|
|
81
|
+
onClick: () => {
|
|
82
|
+
k.go('game');
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## API
|
|
88
|
+
|
|
89
|
+
### Button
|
|
90
|
+
|
|
91
|
+
Add button game object:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
addButton(text, opt);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Update button text:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const button = addButton(text);
|
|
101
|
+
button.label.text = 'Hello';
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Theme
|
|
105
|
+
|
|
106
|
+
Retrieve theme:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
getTheme();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Customize theme:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
setTheme({
|
|
116
|
+
palette: {
|
|
117
|
+
primary: rgb(80, 160, 255),
|
|
118
|
+
text: rgb(255, 255, 255),
|
|
119
|
+
},
|
|
120
|
+
shape: {
|
|
121
|
+
borderRadius: 8,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Release
|
|
127
|
+
|
|
128
|
+
Release is automated with [Release Please](https://github.com/googleapis/release-please).
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
[MIT](https://github.com/remarkablegames/kaplay-plugin-ui/blob/master/LICENSE)
|
package/dist/plugin.cjs
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
// src/utils.ts
|
|
3
|
+
/**
|
|
4
|
+
* Convert hex string to color or return color.
|
|
5
|
+
*
|
|
6
|
+
* @param k - The Kaplay context.
|
|
7
|
+
* @param color - The hex string or color.
|
|
8
|
+
* @returns The color.
|
|
9
|
+
*/
|
|
10
|
+
function toColor(k, color) {
|
|
11
|
+
return typeof color === "string" ? k.rgb(color) : color;
|
|
12
|
+
}
|
|
13
|
+
// src/button.ts
|
|
14
|
+
function createButton(k, theme, text, opt) {
|
|
15
|
+
const width = opt.width ?? theme.components.button.width;
|
|
16
|
+
const height = opt.height ?? theme.components.button.height;
|
|
17
|
+
const radius = opt.radius ?? theme.shape.borderRadius;
|
|
18
|
+
const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);
|
|
19
|
+
const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);
|
|
20
|
+
const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);
|
|
21
|
+
const textColor = toColor(k, opt.textColor ?? theme.palette.text);
|
|
22
|
+
const size = opt.size ?? theme.typography.fontSize;
|
|
23
|
+
const font = opt.font ?? theme.typography.fontFamily;
|
|
24
|
+
const pos = opt.pos ?? k.vec2();
|
|
25
|
+
const button = k.add([
|
|
26
|
+
k.rect(width, height, radius > 0 ? { radius } : void 0),
|
|
27
|
+
k.pos(pos),
|
|
28
|
+
k.area(),
|
|
29
|
+
k.scale(),
|
|
30
|
+
k.color(baseColor),
|
|
31
|
+
k.anchor("center")
|
|
32
|
+
]);
|
|
33
|
+
const label = button.add([
|
|
34
|
+
k.text(text, {
|
|
35
|
+
size,
|
|
36
|
+
font
|
|
37
|
+
}),
|
|
38
|
+
k.color(textColor),
|
|
39
|
+
k.anchor("center")
|
|
40
|
+
]);
|
|
41
|
+
button.onClick(() => {
|
|
42
|
+
button.color = toColor(k, pressedColor);
|
|
43
|
+
opt.onClick?.();
|
|
44
|
+
});
|
|
45
|
+
button.onHover(() => {
|
|
46
|
+
button.color = toColor(k, hoverColor);
|
|
47
|
+
button.scale = k.vec2(1.05, 1.05);
|
|
48
|
+
k.setCursor("pointer");
|
|
49
|
+
});
|
|
50
|
+
button.onHoverEnd(() => {
|
|
51
|
+
button.color = baseColor;
|
|
52
|
+
button.scale = k.vec2(1, 1);
|
|
53
|
+
k.setCursor("default");
|
|
54
|
+
});
|
|
55
|
+
return {
|
|
56
|
+
...button,
|
|
57
|
+
label
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// src/theme.ts
|
|
61
|
+
const PRIMARY = "#4f8cff";
|
|
62
|
+
const TEXT = "#ffffff";
|
|
63
|
+
/** Default theme. */
|
|
64
|
+
const theme = {
|
|
65
|
+
palette: {
|
|
66
|
+
primary: PRIMARY,
|
|
67
|
+
secondary: PRIMARY,
|
|
68
|
+
background: "#111827",
|
|
69
|
+
surface: "#1f2937",
|
|
70
|
+
text: TEXT,
|
|
71
|
+
textSecondary: TEXT,
|
|
72
|
+
hover: PRIMARY,
|
|
73
|
+
pressed: PRIMARY,
|
|
74
|
+
disabled: "#6b7280",
|
|
75
|
+
error: "#ef4444"
|
|
76
|
+
},
|
|
77
|
+
typography: {
|
|
78
|
+
fontFamily: "sans-serif",
|
|
79
|
+
fontSize: 18,
|
|
80
|
+
fontWeight: 400,
|
|
81
|
+
lineHeight: 1.2
|
|
82
|
+
},
|
|
83
|
+
shape: { borderRadius: 0 },
|
|
84
|
+
spacing: 8,
|
|
85
|
+
components: {
|
|
86
|
+
button: {
|
|
87
|
+
width: 120,
|
|
88
|
+
height: 40,
|
|
89
|
+
minWidth: 120,
|
|
90
|
+
paddingX: 12,
|
|
91
|
+
paddingY: 8,
|
|
92
|
+
textTransform: "none"
|
|
93
|
+
},
|
|
94
|
+
modal: {
|
|
95
|
+
backdropOpacity: .5,
|
|
96
|
+
borderRadius: 8
|
|
97
|
+
},
|
|
98
|
+
tooltip: {
|
|
99
|
+
background: "#111827",
|
|
100
|
+
textColor: TEXT,
|
|
101
|
+
delay: 300
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
/** Resolve a partial theme into a fully resolved theme. */
|
|
106
|
+
function resolveTheme(input) {
|
|
107
|
+
return {
|
|
108
|
+
palette: {
|
|
109
|
+
...theme.palette,
|
|
110
|
+
...input?.palette
|
|
111
|
+
},
|
|
112
|
+
typography: {
|
|
113
|
+
...theme.typography,
|
|
114
|
+
...input?.typography
|
|
115
|
+
},
|
|
116
|
+
shape: {
|
|
117
|
+
...theme.shape,
|
|
118
|
+
...input?.shape
|
|
119
|
+
},
|
|
120
|
+
spacing: input?.spacing ?? theme.spacing,
|
|
121
|
+
components: {
|
|
122
|
+
button: {
|
|
123
|
+
...theme.components.button,
|
|
124
|
+
...input?.components?.button,
|
|
125
|
+
width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? theme.components.button.width
|
|
126
|
+
},
|
|
127
|
+
modal: {
|
|
128
|
+
...theme.components.modal,
|
|
129
|
+
...input?.components?.modal
|
|
130
|
+
},
|
|
131
|
+
tooltip: {
|
|
132
|
+
...theme.components.tooltip,
|
|
133
|
+
...input?.components?.tooltip
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
// src/plugin.ts
|
|
139
|
+
/** KAPLAY UI plugin. */
|
|
140
|
+
function uiPlugin(k, theme = {}) {
|
|
141
|
+
let userTheme = theme;
|
|
142
|
+
let currentTheme = resolveTheme(userTheme);
|
|
143
|
+
const getTheme = () => currentTheme;
|
|
144
|
+
const setTheme = (next) => {
|
|
145
|
+
userTheme = {
|
|
146
|
+
...userTheme,
|
|
147
|
+
...next
|
|
148
|
+
};
|
|
149
|
+
currentTheme = resolveTheme(userTheme);
|
|
150
|
+
};
|
|
151
|
+
const addButton = (text = "", opt = {}) => {
|
|
152
|
+
return createButton(k, currentTheme, text, opt);
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
addButton,
|
|
156
|
+
setTheme,
|
|
157
|
+
getTheme
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
exports.uiPlugin = uiPlugin;
|
|
161
|
+
|
|
162
|
+
//# sourceMappingURL=plugin.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.cjs","names":[],"sources":["../src/utils.ts","../src/button.ts","../src/theme.ts","../src/plugin.ts"],"sourcesContent":["import type { Color, KAPLAYCtx } from 'kaplay';\n\n/**\n * Convert hex string to color or return color.\n *\n * @param k - The Kaplay context.\n * @param color - The hex string or color.\n * @returns The color.\n */\nexport function toColor(k: KAPLAYCtx, color: string | Color): Color {\n return typeof color === 'string' ? k.rgb(color) : color;\n}\n","import type { Color, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport type { ButtonOpt, Theme } from './types';\nimport { toColor } from './utils';\n\nexport function createButton(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: string | Color;\n hoverColor?: string | Color;\n pressedColor?: string | Color;\n textColor?: string | Color;\n },\n) {\n const width = opt.width ?? theme.components.button.width;\n const height = opt.height ?? theme.components.button.height;\n const radius = opt.radius ?? theme.shape.borderRadius;\n const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);\n const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);\n const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);\n const textColor = toColor(k, opt.textColor ?? theme.palette.text);\n const size = opt.size ?? theme.typography.fontSize;\n const font = opt.font ?? theme.typography.fontFamily;\n const pos = opt.pos ?? k.vec2();\n\n const button = k.add([\n k.rect(width, height, radius > 0 ? { radius } : undefined),\n k.pos(pos),\n k.area(),\n k.scale(),\n k.color(baseColor),\n k.anchor('center'),\n ]);\n\n const label = button.add([\n k.text(text, { size, font }),\n k.color(textColor as never),\n k.anchor('center'),\n ]);\n\n button.onClick(() => {\n button.color = toColor(k, pressedColor);\n opt.onClick?.();\n });\n\n button.onHover(() => {\n button.color = toColor(k, hoverColor);\n button.scale = k.vec2(1.05, 1.05);\n k.setCursor('pointer');\n });\n\n button.onHoverEnd(() => {\n button.color = baseColor;\n button.scale = k.vec2(1, 1);\n k.setCursor('default');\n });\n\n return {\n ...button,\n label,\n };\n}\n","import type { DeepPartial, Theme } from './types';\n\nconst PRIMARY = '#4f8cff';\nconst TEXT = '#ffffff';\n\n/** Default theme. */\nconst theme: Theme = {\n palette: {\n primary: PRIMARY,\n secondary: PRIMARY,\n background: '#111827',\n surface: '#1f2937',\n text: TEXT,\n textSecondary: TEXT,\n hover: PRIMARY,\n pressed: PRIMARY,\n disabled: '#6b7280',\n error: '#ef4444',\n },\n typography: {\n fontFamily: 'sans-serif',\n fontSize: 18,\n fontWeight: 400,\n lineHeight: 1.2,\n },\n shape: {\n borderRadius: 0,\n },\n spacing: 8,\n components: {\n button: {\n width: 120,\n height: 40,\n minWidth: 120,\n paddingX: 12,\n paddingY: 8,\n textTransform: 'none',\n },\n modal: {\n backdropOpacity: 0.5,\n borderRadius: 8,\n },\n tooltip: {\n background: '#111827',\n textColor: TEXT,\n delay: 300,\n },\n },\n};\n\n/** Resolve a partial theme into a fully resolved theme. */\nexport function resolveTheme(input?: DeepPartial<Theme>): Theme {\n return {\n palette: { ...theme.palette, ...input?.palette },\n typography: { ...theme.typography, ...input?.typography },\n shape: { ...theme.shape, ...input?.shape },\n spacing: input?.spacing ?? theme.spacing,\n components: {\n button: {\n ...theme.components.button,\n ...input?.components?.button,\n width:\n input?.components?.button?.width ??\n input?.components?.button?.minWidth ??\n theme.components.button.width,\n },\n modal: {\n ...theme.components.modal,\n ...input?.components?.modal,\n },\n tooltip: {\n ...theme.components.tooltip,\n ...input?.components?.tooltip,\n },\n },\n };\n}\n","import type { Color, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport { createButton } from './button';\nimport { resolveTheme } from './theme';\nimport type { ButtonOpt, DeepPartial, Theme, UIPlugin } from './types';\n\nexport type { ButtonOpt, Theme, UIPlugin };\n\n/** KAPLAY UI plugin. */\nexport function uiPlugin(\n k: KAPLAYCtx,\n theme: DeepPartial<Theme> = {},\n): UIPlugin {\n let userTheme: DeepPartial<Theme> = theme;\n let currentTheme: Theme = resolveTheme(userTheme);\n\n const getTheme = (): Theme => currentTheme;\n\n const setTheme = (next: DeepPartial<Theme>): void => {\n userTheme = { ...userTheme, ...next };\n currentTheme = resolveTheme(userTheme);\n };\n\n const addButton = (\n text = '',\n opt: ButtonOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: string | Color;\n hoverColor?: string | Color;\n pressedColor?: string | Color;\n textColor?: string | Color;\n } = {},\n ) => {\n return createButton(k, currentTheme, text, opt);\n };\n\n return {\n addButton,\n setTheme,\n getTheme,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Color, KAPLAYCtx, Vec2 } from "kaplay";
|
|
2
|
+
declare function createButton(k: KAPLAYCtx, theme: Theme, text: string, opt: ButtonOpt & {
|
|
3
|
+
pos?: Vec2;
|
|
4
|
+
onClick?: () => void;
|
|
5
|
+
color?: string | Color;
|
|
6
|
+
hoverColor?: string | Color;
|
|
7
|
+
pressedColor?: string | Color;
|
|
8
|
+
textColor?: string | Color;
|
|
9
|
+
}): {
|
|
10
|
+
label: import("kaplay").GameObj<import("kaplay").ColorComp | import("kaplay").AnchorComp | import("kaplay").TextComp>;
|
|
11
|
+
add<T>(comps?: import("kaplay").CompList<T> | import("kaplay").GameObj<T>): import("kaplay").GameObj<T>;
|
|
12
|
+
readd<T>(obj: import("kaplay").GameObj<T>): import("kaplay").GameObj<T>;
|
|
13
|
+
remove(obj: import("kaplay").GameObj): void;
|
|
14
|
+
removeAll(tag: import("kaplay").Tag): void;
|
|
15
|
+
removeAll(): void;
|
|
16
|
+
get(tag: import("kaplay").Tag | import("kaplay").Tag[], opts?: import("kaplay").GetOpt): import("kaplay").GameObj[];
|
|
17
|
+
query(opt: import("kaplay").QueryOpt): import("kaplay").GameObj[];
|
|
18
|
+
parent: import("kaplay").GameObj | null;
|
|
19
|
+
children: import("kaplay").GameObj[];
|
|
20
|
+
tags: string[];
|
|
21
|
+
fixedUpdate(): void;
|
|
22
|
+
update(): void;
|
|
23
|
+
draw(): void;
|
|
24
|
+
drawInspect: () => void;
|
|
25
|
+
clearEvents: () => void;
|
|
26
|
+
use(comp: import("kaplay").Comp | import("kaplay").Tag): void;
|
|
27
|
+
unuse(comp: import("kaplay").Tag): void;
|
|
28
|
+
has(compId: string | string[], op?: "and" | "or"): boolean;
|
|
29
|
+
tag(tag: import("kaplay").Tag | import("kaplay").Tag[]): void;
|
|
30
|
+
untag(tag: import("kaplay").Tag | import("kaplay").Tag[]): void;
|
|
31
|
+
is(tag: import("kaplay").Tag | import("kaplay").Tag[], op?: "and" | "or"): boolean;
|
|
32
|
+
on(event: import("kaplay").GameObjEventNames | (string & {}), action: (...args: any) => void): import("kaplay").KEventController;
|
|
33
|
+
trigger(event: string, ...args: any): void;
|
|
34
|
+
destroy(): void;
|
|
35
|
+
c(id: string): import("kaplay").Comp | null;
|
|
36
|
+
inspect(): import("kaplay").GameObjInspect;
|
|
37
|
+
onAdd(action: () => void): import("kaplay").KEventController;
|
|
38
|
+
onUpdate(action: () => void): import("kaplay").KEventController;
|
|
39
|
+
onFixedUpdate(action: () => void): import("kaplay").KEventController;
|
|
40
|
+
onDraw(action: () => void): import("kaplay").KEventController;
|
|
41
|
+
onDestroy(action: () => void): import("kaplay").KEventController;
|
|
42
|
+
onUse(action: (id: string) => void): import("kaplay").KEventController;
|
|
43
|
+
onUnuse(action: (id: string) => void): import("kaplay").KEventController;
|
|
44
|
+
onTag(action: (tag: string) => void): import("kaplay").KEventController;
|
|
45
|
+
onUntag(action: (tag: string) => void): import("kaplay").KEventController;
|
|
46
|
+
exists(): boolean;
|
|
47
|
+
isAncestorOf(obj: import("kaplay").GameObj): boolean;
|
|
48
|
+
transform: import("kaplay").Mat4;
|
|
49
|
+
hidden: boolean;
|
|
50
|
+
paused: boolean;
|
|
51
|
+
id: import("kaplay").GameObjID | null;
|
|
52
|
+
canvas: import("kaplay").FrameBuffer | null;
|
|
53
|
+
onKeyDown: KAPLAYCtx["onKeyDown"];
|
|
54
|
+
onKeyPress: KAPLAYCtx["onKeyPress"];
|
|
55
|
+
onKeyPressRepeat: KAPLAYCtx["onKeyPressRepeat"];
|
|
56
|
+
onKeyRelease: KAPLAYCtx["onKeyRelease"];
|
|
57
|
+
onCharInput: KAPLAYCtx["onCharInput"];
|
|
58
|
+
onMouseDown: KAPLAYCtx["onMouseDown"];
|
|
59
|
+
onMousePress: KAPLAYCtx["onMousePress"];
|
|
60
|
+
onMouseRelease: KAPLAYCtx["onMouseRelease"];
|
|
61
|
+
onMouseMove: KAPLAYCtx["onMouseMove"];
|
|
62
|
+
onTouchStart: KAPLAYCtx["onTouchStart"];
|
|
63
|
+
onTouchMove: KAPLAYCtx["onTouchMove"];
|
|
64
|
+
onTouchEnd: KAPLAYCtx["onTouchEnd"];
|
|
65
|
+
onScroll: KAPLAYCtx["onScroll"];
|
|
66
|
+
onGamepadButtonDown: KAPLAYCtx["onGamepadButtonDown"];
|
|
67
|
+
onGamepadButtonPress: KAPLAYCtx["onGamepadButtonPress"];
|
|
68
|
+
onGamepadButtonRelease: KAPLAYCtx["onGamepadButtonRelease"];
|
|
69
|
+
onGamepadStick: KAPLAYCtx["onGamepadStick"];
|
|
70
|
+
onButtonDown: KAPLAYCtx["onButtonDown"];
|
|
71
|
+
onButtonPress: KAPLAYCtx["onButtonPress"];
|
|
72
|
+
onButtonRelease: KAPLAYCtx["onButtonRelease"];
|
|
73
|
+
radius?: number | [number, number, number, number] | undefined;
|
|
74
|
+
width: number;
|
|
75
|
+
height: number;
|
|
76
|
+
renderArea: () => import("kaplay").Rect;
|
|
77
|
+
pos: Vec2;
|
|
78
|
+
move: {
|
|
79
|
+
(xVel: number, yVel: number): void;
|
|
80
|
+
(vel: Vec2): void;
|
|
81
|
+
};
|
|
82
|
+
moveBy: {
|
|
83
|
+
(dx: number, dy: number): void;
|
|
84
|
+
(d: Vec2): void;
|
|
85
|
+
};
|
|
86
|
+
moveTo: {
|
|
87
|
+
(dest: Vec2, speed?: number): void;
|
|
88
|
+
(x: number, y: number, speed?: number): void;
|
|
89
|
+
};
|
|
90
|
+
screenPos: (newPos?: Vec2) => Vec2 | null;
|
|
91
|
+
worldPos: (newPos?: Vec2) => Vec2 | null;
|
|
92
|
+
toScreen: (this: import("kaplay").GameObj<import("kaplay").PosComp | import("kaplay").FixedComp>, p: Vec2) => Vec2;
|
|
93
|
+
toWorld: (this: import("kaplay").GameObj<import("kaplay").PosComp>, p: Vec2) => Vec2;
|
|
94
|
+
fromScreen: (this: import("kaplay").GameObj<import("kaplay").PosComp | import("kaplay").FixedComp>, p: Vec2) => Vec2;
|
|
95
|
+
fromWorld: (this: import("kaplay").GameObj<import("kaplay").PosComp>, p: Vec2) => Vec2;
|
|
96
|
+
toOther: (this: import("kaplay").GameObj<import("kaplay").PosComp>, other: import("kaplay").GameObj<import("kaplay").PosComp>, p: Vec2) => Vec2;
|
|
97
|
+
fromOther: (this: import("kaplay").GameObj<import("kaplay").PosComp>, other: import("kaplay").GameObj<import("kaplay").PosComp>, p: Vec2) => Vec2;
|
|
98
|
+
area: {
|
|
99
|
+
shape: import("kaplay").Shape | null;
|
|
100
|
+
scale: Vec2;
|
|
101
|
+
offset: Vec2;
|
|
102
|
+
cursor: import("kaplay").Cursor | null;
|
|
103
|
+
};
|
|
104
|
+
collisionIgnore: import("kaplay").Tag[];
|
|
105
|
+
isClicked: () => boolean;
|
|
106
|
+
isHovering: () => boolean;
|
|
107
|
+
checkCollision: (other: import("kaplay").GameObj<import("kaplay").AreaComp>) => import("kaplay").Collision | null;
|
|
108
|
+
getCollisions: () => import("kaplay").Collision[];
|
|
109
|
+
isColliding: (o: import("kaplay").GameObj<import("kaplay").AreaComp>) => boolean;
|
|
110
|
+
isOverlapping: (o: import("kaplay").GameObj<import("kaplay").AreaComp>) => boolean;
|
|
111
|
+
onClick: (f: () => void, btn?: import("kaplay").MouseButton) => import("kaplay").KEventController;
|
|
112
|
+
onHover: (action: () => void) => import("kaplay").KEventController;
|
|
113
|
+
onHoverUpdate: (action: () => void) => import("kaplay").KEventController;
|
|
114
|
+
onHoverEnd: (action: () => void) => import("kaplay").KEventController;
|
|
115
|
+
onCollide: {
|
|
116
|
+
(tag: import("kaplay").Tag, f: (obj: import("kaplay").GameObj, col?: import("kaplay").Collision) => void): import("kaplay").KEventController;
|
|
117
|
+
(f: (obj: import("kaplay").GameObj, col?: import("kaplay").Collision) => void): import("kaplay").KEventController;
|
|
118
|
+
};
|
|
119
|
+
onCollideUpdate: {
|
|
120
|
+
(tag: import("kaplay").Tag, f: (obj: import("kaplay").GameObj, col?: import("kaplay").Collision) => import("kaplay").KEventController): import("kaplay").KEventController;
|
|
121
|
+
(f: (obj: import("kaplay").GameObj, col?: import("kaplay").Collision) => void): import("kaplay").KEventController;
|
|
122
|
+
};
|
|
123
|
+
onCollideEnd: {
|
|
124
|
+
(tag: import("kaplay").Tag, f: (obj: import("kaplay").GameObj) => void): import("kaplay").KEventController;
|
|
125
|
+
(f: (obj: import("kaplay").GameObj) => void): void;
|
|
126
|
+
};
|
|
127
|
+
hasPoint: (p: Vec2) => boolean;
|
|
128
|
+
resolveCollision: (obj: import("kaplay").GameObj) => void;
|
|
129
|
+
localArea: () => import("kaplay").Shape;
|
|
130
|
+
worldArea: () => import("kaplay").Polygon;
|
|
131
|
+
screenArea: () => import("kaplay").Polygon;
|
|
132
|
+
scale: Vec2;
|
|
133
|
+
scaleTo: {
|
|
134
|
+
(s: number): void;
|
|
135
|
+
(s: Vec2): void;
|
|
136
|
+
(sx: number, sy: number): void;
|
|
137
|
+
};
|
|
138
|
+
scaleBy: {
|
|
139
|
+
(s: number): void;
|
|
140
|
+
(s: Vec2): void;
|
|
141
|
+
(sx: number, sy: number): void;
|
|
142
|
+
};
|
|
143
|
+
color: Color;
|
|
144
|
+
anchor: import("kaplay").Anchor | Vec2;
|
|
145
|
+
};
|
|
146
|
+
interface UIPlugin {
|
|
147
|
+
addButton: (text?: string, opt?: ButtonOpt & {
|
|
148
|
+
pos?: Vec2;
|
|
149
|
+
onClick?: () => void;
|
|
150
|
+
color?: string | Color;
|
|
151
|
+
hoverColor?: string | Color;
|
|
152
|
+
pressedColor?: string | Color;
|
|
153
|
+
textColor?: string | Color;
|
|
154
|
+
}) => ReturnType<typeof createButton>;
|
|
155
|
+
getTheme: () => Theme;
|
|
156
|
+
setTheme: (theme: DeepPartial<Theme>) => void;
|
|
157
|
+
}
|
|
158
|
+
declare module 'kaplay' {
|
|
159
|
+
interface KAPLAYCtx extends UIPlugin {}
|
|
160
|
+
}
|
|
161
|
+
/** Recursively partial version of a type. */
|
|
162
|
+
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; };
|
|
163
|
+
interface Theme {
|
|
164
|
+
palette: {
|
|
165
|
+
primary: string | Color;
|
|
166
|
+
secondary: string | Color;
|
|
167
|
+
background: string | Color;
|
|
168
|
+
surface: string | Color;
|
|
169
|
+
text: string | Color;
|
|
170
|
+
textSecondary: string | Color;
|
|
171
|
+
hover: string | Color;
|
|
172
|
+
pressed: string | Color;
|
|
173
|
+
disabled: string | Color;
|
|
174
|
+
error: string | Color;
|
|
175
|
+
};
|
|
176
|
+
typography: {
|
|
177
|
+
fontFamily: string;
|
|
178
|
+
fontSize: number;
|
|
179
|
+
fontWeight: number | string;
|
|
180
|
+
lineHeight: number;
|
|
181
|
+
};
|
|
182
|
+
shape: {
|
|
183
|
+
borderRadius: number;
|
|
184
|
+
};
|
|
185
|
+
spacing: number;
|
|
186
|
+
components: {
|
|
187
|
+
button: {
|
|
188
|
+
width: number;
|
|
189
|
+
height: number;
|
|
190
|
+
minWidth: number;
|
|
191
|
+
paddingX: number;
|
|
192
|
+
paddingY: number;
|
|
193
|
+
textTransform: 'none' | 'uppercase' | 'lowercase' | 'capitalize';
|
|
194
|
+
};
|
|
195
|
+
modal: {
|
|
196
|
+
backdropOpacity: number;
|
|
197
|
+
borderRadius: number;
|
|
198
|
+
};
|
|
199
|
+
tooltip: {
|
|
200
|
+
background: string | Color;
|
|
201
|
+
textColor: string | Color;
|
|
202
|
+
delay: number;
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/** Button options. */
|
|
207
|
+
interface ButtonOpt {
|
|
208
|
+
width?: number;
|
|
209
|
+
height?: number;
|
|
210
|
+
size?: number;
|
|
211
|
+
font?: string;
|
|
212
|
+
fill?: string | Color;
|
|
213
|
+
textColor?: string | Color;
|
|
214
|
+
radius?: number;
|
|
215
|
+
hoverFill?: string | Color;
|
|
216
|
+
pressedFill?: string | Color;
|
|
217
|
+
}
|
|
218
|
+
/** KAPLAY UI plugin. */
|
|
219
|
+
export declare function uiPlugin(k: KAPLAYCtx, theme?: DeepPartial<Theme>): UIPlugin;
|
|
220
|
+
export type { ButtonOpt, Theme, UIPlugin };
|
|
221
|
+
//# sourceMappingURL=plugin.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.cts","names":[],"sources":["../src/button.ts","../src/types.ts","../src/plugin.ts"],"mappings":";iBAKgB,aACd,GAAG,WACH,OAAO,OACP,cACA,KAAK;EACH,MAAM;EACN;EACA,iBAAiB;EACjB,sBAAsB;EACtB,wBAAwB;EACxB,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;EAmDuj0M,GAAA,wBAAA,mCAAA,YAAG,sCAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAA34hJ,sBAAA,KAAA,IAAA,sBAAA,SAAA,uBAAC,sCAAA;KAA8K,IAAA,sBAAA,SAAA,uBAAC,sCAAA;;;KAAsN,sBAAA,KAAA,IAAA,sBAAA,SAAA,uBAAC,+BAAA,oCAAA;KAAuM,IAAA,sBAAA,SAAA,uBAAC,sCAAA;;;;;;;;;;;;;;;;;;;;;;;;;UC9DtwzD;EACf,YACE,eACA,MAAM;IACJ,MAAM;IACN;IACA,iBAAiB;IACjB,sBAAsB;IACtB,wBAAwB;IACxB,qBAAqB;QAEpB,kBAAkB;EAEvB,gBAAgB;EAEhB,WAAW,OAAO,YAAY;;;YAKpB,kBAAkB;;;KAIlB,YAAY,QACrB,WAAW,KAAK,EAAE,oBAAoB,YAAY,EAAE,MAAM,EAAE;UAG9C;EACf;IACE,kBAAkB;IAClB,oBAAoB;IACpB,qBAAqB;IACrB,kBAAkB;IAClB,eAAe;IACf,wBAAwB;IACxB,gBAAgB;IAChB,kBAAkB;IAClB,mBAAmB;IACnB,gBAAgB;;EAElB;IACE;IACA;IACA;IACA;;EAEF;IACE;;EAEF;EACA;IACE;MACE;MACA;MACA;MACA;MACA;MACA;;IAEF;MACE;MACA;;IAEF;MACE,qBAAqB;MACrB,oBAAoB;MACpB;;;;;UAMW;EACf;EACA;EACA;EACA;EACA,gBAAgB;EAChB,qBAAqB;EACrB;EACA,qBAAqB;EACrB,uBAAuB;;;wBC7ET,SACd,GAAG,WACH,QAAO,YAAY,SAClB"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Color, KAPLAYCtx, Vec2 } from "kaplay";
|
|
2
|
+
declare function createButton(k: KAPLAYCtx, theme: Theme, text: string, opt: ButtonOpt & {
|
|
3
|
+
pos?: Vec2;
|
|
4
|
+
onClick?: () => void;
|
|
5
|
+
color?: string | Color;
|
|
6
|
+
hoverColor?: string | Color;
|
|
7
|
+
pressedColor?: string | Color;
|
|
8
|
+
textColor?: string | Color;
|
|
9
|
+
}): {
|
|
10
|
+
label: import("kaplay").GameObj<import("kaplay").ColorComp | import("kaplay").AnchorComp | import("kaplay").TextComp>;
|
|
11
|
+
add<T>(comps?: import("kaplay").CompList<T> | import("kaplay").GameObj<T>): import("kaplay").GameObj<T>;
|
|
12
|
+
readd<T>(obj: import("kaplay").GameObj<T>): import("kaplay").GameObj<T>;
|
|
13
|
+
remove(obj: import("kaplay").GameObj): void;
|
|
14
|
+
removeAll(tag: import("kaplay").Tag): void;
|
|
15
|
+
removeAll(): void;
|
|
16
|
+
get(tag: import("kaplay").Tag | import("kaplay").Tag[], opts?: import("kaplay").GetOpt): import("kaplay").GameObj[];
|
|
17
|
+
query(opt: import("kaplay").QueryOpt): import("kaplay").GameObj[];
|
|
18
|
+
parent: import("kaplay").GameObj | null;
|
|
19
|
+
children: import("kaplay").GameObj[];
|
|
20
|
+
tags: string[];
|
|
21
|
+
fixedUpdate(): void;
|
|
22
|
+
update(): void;
|
|
23
|
+
draw(): void;
|
|
24
|
+
drawInspect: () => void;
|
|
25
|
+
clearEvents: () => void;
|
|
26
|
+
use(comp: import("kaplay").Comp | import("kaplay").Tag): void;
|
|
27
|
+
unuse(comp: import("kaplay").Tag): void;
|
|
28
|
+
has(compId: string | string[], op?: "and" | "or"): boolean;
|
|
29
|
+
tag(tag: import("kaplay").Tag | import("kaplay").Tag[]): void;
|
|
30
|
+
untag(tag: import("kaplay").Tag | import("kaplay").Tag[]): void;
|
|
31
|
+
is(tag: import("kaplay").Tag | import("kaplay").Tag[], op?: "and" | "or"): boolean;
|
|
32
|
+
on(event: import("kaplay").GameObjEventNames | (string & {}), action: (...args: any) => void): import("kaplay").KEventController;
|
|
33
|
+
trigger(event: string, ...args: any): void;
|
|
34
|
+
destroy(): void;
|
|
35
|
+
c(id: string): import("kaplay").Comp | null;
|
|
36
|
+
inspect(): import("kaplay").GameObjInspect;
|
|
37
|
+
onAdd(action: () => void): import("kaplay").KEventController;
|
|
38
|
+
onUpdate(action: () => void): import("kaplay").KEventController;
|
|
39
|
+
onFixedUpdate(action: () => void): import("kaplay").KEventController;
|
|
40
|
+
onDraw(action: () => void): import("kaplay").KEventController;
|
|
41
|
+
onDestroy(action: () => void): import("kaplay").KEventController;
|
|
42
|
+
onUse(action: (id: string) => void): import("kaplay").KEventController;
|
|
43
|
+
onUnuse(action: (id: string) => void): import("kaplay").KEventController;
|
|
44
|
+
onTag(action: (tag: string) => void): import("kaplay").KEventController;
|
|
45
|
+
onUntag(action: (tag: string) => void): import("kaplay").KEventController;
|
|
46
|
+
exists(): boolean;
|
|
47
|
+
isAncestorOf(obj: import("kaplay").GameObj): boolean;
|
|
48
|
+
transform: import("kaplay").Mat4;
|
|
49
|
+
hidden: boolean;
|
|
50
|
+
paused: boolean;
|
|
51
|
+
id: import("kaplay").GameObjID | null;
|
|
52
|
+
canvas: import("kaplay").FrameBuffer | null;
|
|
53
|
+
onKeyDown: KAPLAYCtx["onKeyDown"];
|
|
54
|
+
onKeyPress: KAPLAYCtx["onKeyPress"];
|
|
55
|
+
onKeyPressRepeat: KAPLAYCtx["onKeyPressRepeat"];
|
|
56
|
+
onKeyRelease: KAPLAYCtx["onKeyRelease"];
|
|
57
|
+
onCharInput: KAPLAYCtx["onCharInput"];
|
|
58
|
+
onMouseDown: KAPLAYCtx["onMouseDown"];
|
|
59
|
+
onMousePress: KAPLAYCtx["onMousePress"];
|
|
60
|
+
onMouseRelease: KAPLAYCtx["onMouseRelease"];
|
|
61
|
+
onMouseMove: KAPLAYCtx["onMouseMove"];
|
|
62
|
+
onTouchStart: KAPLAYCtx["onTouchStart"];
|
|
63
|
+
onTouchMove: KAPLAYCtx["onTouchMove"];
|
|
64
|
+
onTouchEnd: KAPLAYCtx["onTouchEnd"];
|
|
65
|
+
onScroll: KAPLAYCtx["onScroll"];
|
|
66
|
+
onGamepadButtonDown: KAPLAYCtx["onGamepadButtonDown"];
|
|
67
|
+
onGamepadButtonPress: KAPLAYCtx["onGamepadButtonPress"];
|
|
68
|
+
onGamepadButtonRelease: KAPLAYCtx["onGamepadButtonRelease"];
|
|
69
|
+
onGamepadStick: KAPLAYCtx["onGamepadStick"];
|
|
70
|
+
onButtonDown: KAPLAYCtx["onButtonDown"];
|
|
71
|
+
onButtonPress: KAPLAYCtx["onButtonPress"];
|
|
72
|
+
onButtonRelease: KAPLAYCtx["onButtonRelease"];
|
|
73
|
+
radius?: number | [number, number, number, number] | undefined;
|
|
74
|
+
width: number;
|
|
75
|
+
height: number;
|
|
76
|
+
renderArea: () => import("kaplay").Rect;
|
|
77
|
+
pos: Vec2;
|
|
78
|
+
move: {
|
|
79
|
+
(xVel: number, yVel: number): void;
|
|
80
|
+
(vel: Vec2): void;
|
|
81
|
+
};
|
|
82
|
+
moveBy: {
|
|
83
|
+
(dx: number, dy: number): void;
|
|
84
|
+
(d: Vec2): void;
|
|
85
|
+
};
|
|
86
|
+
moveTo: {
|
|
87
|
+
(dest: Vec2, speed?: number): void;
|
|
88
|
+
(x: number, y: number, speed?: number): void;
|
|
89
|
+
};
|
|
90
|
+
screenPos: (newPos?: Vec2) => Vec2 | null;
|
|
91
|
+
worldPos: (newPos?: Vec2) => Vec2 | null;
|
|
92
|
+
toScreen: (this: import("kaplay").GameObj<import("kaplay").PosComp | import("kaplay").FixedComp>, p: Vec2) => Vec2;
|
|
93
|
+
toWorld: (this: import("kaplay").GameObj<import("kaplay").PosComp>, p: Vec2) => Vec2;
|
|
94
|
+
fromScreen: (this: import("kaplay").GameObj<import("kaplay").PosComp | import("kaplay").FixedComp>, p: Vec2) => Vec2;
|
|
95
|
+
fromWorld: (this: import("kaplay").GameObj<import("kaplay").PosComp>, p: Vec2) => Vec2;
|
|
96
|
+
toOther: (this: import("kaplay").GameObj<import("kaplay").PosComp>, other: import("kaplay").GameObj<import("kaplay").PosComp>, p: Vec2) => Vec2;
|
|
97
|
+
fromOther: (this: import("kaplay").GameObj<import("kaplay").PosComp>, other: import("kaplay").GameObj<import("kaplay").PosComp>, p: Vec2) => Vec2;
|
|
98
|
+
area: {
|
|
99
|
+
shape: import("kaplay").Shape | null;
|
|
100
|
+
scale: Vec2;
|
|
101
|
+
offset: Vec2;
|
|
102
|
+
cursor: import("kaplay").Cursor | null;
|
|
103
|
+
};
|
|
104
|
+
collisionIgnore: import("kaplay").Tag[];
|
|
105
|
+
isClicked: () => boolean;
|
|
106
|
+
isHovering: () => boolean;
|
|
107
|
+
checkCollision: (other: import("kaplay").GameObj<import("kaplay").AreaComp>) => import("kaplay").Collision | null;
|
|
108
|
+
getCollisions: () => import("kaplay").Collision[];
|
|
109
|
+
isColliding: (o: import("kaplay").GameObj<import("kaplay").AreaComp>) => boolean;
|
|
110
|
+
isOverlapping: (o: import("kaplay").GameObj<import("kaplay").AreaComp>) => boolean;
|
|
111
|
+
onClick: (f: () => void, btn?: import("kaplay").MouseButton) => import("kaplay").KEventController;
|
|
112
|
+
onHover: (action: () => void) => import("kaplay").KEventController;
|
|
113
|
+
onHoverUpdate: (action: () => void) => import("kaplay").KEventController;
|
|
114
|
+
onHoverEnd: (action: () => void) => import("kaplay").KEventController;
|
|
115
|
+
onCollide: {
|
|
116
|
+
(tag: import("kaplay").Tag, f: (obj: import("kaplay").GameObj, col?: import("kaplay").Collision) => void): import("kaplay").KEventController;
|
|
117
|
+
(f: (obj: import("kaplay").GameObj, col?: import("kaplay").Collision) => void): import("kaplay").KEventController;
|
|
118
|
+
};
|
|
119
|
+
onCollideUpdate: {
|
|
120
|
+
(tag: import("kaplay").Tag, f: (obj: import("kaplay").GameObj, col?: import("kaplay").Collision) => import("kaplay").KEventController): import("kaplay").KEventController;
|
|
121
|
+
(f: (obj: import("kaplay").GameObj, col?: import("kaplay").Collision) => void): import("kaplay").KEventController;
|
|
122
|
+
};
|
|
123
|
+
onCollideEnd: {
|
|
124
|
+
(tag: import("kaplay").Tag, f: (obj: import("kaplay").GameObj) => void): import("kaplay").KEventController;
|
|
125
|
+
(f: (obj: import("kaplay").GameObj) => void): void;
|
|
126
|
+
};
|
|
127
|
+
hasPoint: (p: Vec2) => boolean;
|
|
128
|
+
resolveCollision: (obj: import("kaplay").GameObj) => void;
|
|
129
|
+
localArea: () => import("kaplay").Shape;
|
|
130
|
+
worldArea: () => import("kaplay").Polygon;
|
|
131
|
+
screenArea: () => import("kaplay").Polygon;
|
|
132
|
+
scale: Vec2;
|
|
133
|
+
scaleTo: {
|
|
134
|
+
(s: number): void;
|
|
135
|
+
(s: Vec2): void;
|
|
136
|
+
(sx: number, sy: number): void;
|
|
137
|
+
};
|
|
138
|
+
scaleBy: {
|
|
139
|
+
(s: number): void;
|
|
140
|
+
(s: Vec2): void;
|
|
141
|
+
(sx: number, sy: number): void;
|
|
142
|
+
};
|
|
143
|
+
color: Color;
|
|
144
|
+
anchor: import("kaplay").Anchor | Vec2;
|
|
145
|
+
};
|
|
146
|
+
interface UIPlugin {
|
|
147
|
+
addButton: (text?: string, opt?: ButtonOpt & {
|
|
148
|
+
pos?: Vec2;
|
|
149
|
+
onClick?: () => void;
|
|
150
|
+
color?: string | Color;
|
|
151
|
+
hoverColor?: string | Color;
|
|
152
|
+
pressedColor?: string | Color;
|
|
153
|
+
textColor?: string | Color;
|
|
154
|
+
}) => ReturnType<typeof createButton>;
|
|
155
|
+
getTheme: () => Theme;
|
|
156
|
+
setTheme: (theme: DeepPartial<Theme>) => void;
|
|
157
|
+
}
|
|
158
|
+
declare module 'kaplay' {
|
|
159
|
+
interface KAPLAYCtx extends UIPlugin {}
|
|
160
|
+
}
|
|
161
|
+
/** Recursively partial version of a type. */
|
|
162
|
+
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; };
|
|
163
|
+
interface Theme {
|
|
164
|
+
palette: {
|
|
165
|
+
primary: string | Color;
|
|
166
|
+
secondary: string | Color;
|
|
167
|
+
background: string | Color;
|
|
168
|
+
surface: string | Color;
|
|
169
|
+
text: string | Color;
|
|
170
|
+
textSecondary: string | Color;
|
|
171
|
+
hover: string | Color;
|
|
172
|
+
pressed: string | Color;
|
|
173
|
+
disabled: string | Color;
|
|
174
|
+
error: string | Color;
|
|
175
|
+
};
|
|
176
|
+
typography: {
|
|
177
|
+
fontFamily: string;
|
|
178
|
+
fontSize: number;
|
|
179
|
+
fontWeight: number | string;
|
|
180
|
+
lineHeight: number;
|
|
181
|
+
};
|
|
182
|
+
shape: {
|
|
183
|
+
borderRadius: number;
|
|
184
|
+
};
|
|
185
|
+
spacing: number;
|
|
186
|
+
components: {
|
|
187
|
+
button: {
|
|
188
|
+
width: number;
|
|
189
|
+
height: number;
|
|
190
|
+
minWidth: number;
|
|
191
|
+
paddingX: number;
|
|
192
|
+
paddingY: number;
|
|
193
|
+
textTransform: 'none' | 'uppercase' | 'lowercase' | 'capitalize';
|
|
194
|
+
};
|
|
195
|
+
modal: {
|
|
196
|
+
backdropOpacity: number;
|
|
197
|
+
borderRadius: number;
|
|
198
|
+
};
|
|
199
|
+
tooltip: {
|
|
200
|
+
background: string | Color;
|
|
201
|
+
textColor: string | Color;
|
|
202
|
+
delay: number;
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/** Button options. */
|
|
207
|
+
interface ButtonOpt {
|
|
208
|
+
width?: number;
|
|
209
|
+
height?: number;
|
|
210
|
+
size?: number;
|
|
211
|
+
font?: string;
|
|
212
|
+
fill?: string | Color;
|
|
213
|
+
textColor?: string | Color;
|
|
214
|
+
radius?: number;
|
|
215
|
+
hoverFill?: string | Color;
|
|
216
|
+
pressedFill?: string | Color;
|
|
217
|
+
}
|
|
218
|
+
/** KAPLAY UI plugin. */
|
|
219
|
+
export declare function uiPlugin(k: KAPLAYCtx, theme?: DeepPartial<Theme>): UIPlugin;
|
|
220
|
+
export type { ButtonOpt, Theme, UIPlugin };
|
|
221
|
+
//# sourceMappingURL=plugin.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.mts","names":[],"sources":["../src/button.ts","../src/types.ts","../src/plugin.ts"],"mappings":";iBAKgB,aACd,GAAG,WACH,OAAO,OACP,cACA,KAAK;EACH,MAAM;EACN;EACA,iBAAiB;EACjB,sBAAsB;EACtB,wBAAwB;EACxB,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;EAmDuj0M,GAAA,wBAAA,mCAAA,YAAG,sCAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAA34hJ,sBAAA,KAAA,IAAA,sBAAA,SAAA,uBAAC,sCAAA;KAA8K,IAAA,sBAAA,SAAA,uBAAC,sCAAA;;;KAAsN,sBAAA,KAAA,IAAA,sBAAA,SAAA,uBAAC,+BAAA,oCAAA;KAAuM,IAAA,sBAAA,SAAA,uBAAC,sCAAA;;;;;;;;;;;;;;;;;;;;;;;;;UC9DtwzD;EACf,YACE,eACA,MAAM;IACJ,MAAM;IACN;IACA,iBAAiB;IACjB,sBAAsB;IACtB,wBAAwB;IACxB,qBAAqB;QAEpB,kBAAkB;EAEvB,gBAAgB;EAEhB,WAAW,OAAO,YAAY;;;YAKpB,kBAAkB;;;KAIlB,YAAY,QACrB,WAAW,KAAK,EAAE,oBAAoB,YAAY,EAAE,MAAM,EAAE;UAG9C;EACf;IACE,kBAAkB;IAClB,oBAAoB;IACpB,qBAAqB;IACrB,kBAAkB;IAClB,eAAe;IACf,wBAAwB;IACxB,gBAAgB;IAChB,kBAAkB;IAClB,mBAAmB;IACnB,gBAAgB;;EAElB;IACE;IACA;IACA;IACA;;EAEF;IACE;;EAEF;EACA;IACE;MACE;MACA;MACA;MACA;MACA;MACA;;IAEF;MACE;MACA;;IAEF;MACE,qBAAqB;MACrB,oBAAoB;MACpB;;;;;UAMW;EACf;EACA;EACA;EACA;EACA,gBAAgB;EAChB,qBAAqB;EACrB;EACA,qBAAqB;EACrB,uBAAuB;;;wBC7ET,SACd,GAAG,WACH,QAAO,YAAY,SAClB"}
|
package/dist/plugin.mjs
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
/**
|
|
3
|
+
* Convert hex string to color or return color.
|
|
4
|
+
*
|
|
5
|
+
* @param k - The Kaplay context.
|
|
6
|
+
* @param color - The hex string or color.
|
|
7
|
+
* @returns The color.
|
|
8
|
+
*/
|
|
9
|
+
function toColor(k, color) {
|
|
10
|
+
return typeof color === "string" ? k.rgb(color) : color;
|
|
11
|
+
}
|
|
12
|
+
// src/button.ts
|
|
13
|
+
function createButton(k, theme, text, opt) {
|
|
14
|
+
const width = opt.width ?? theme.components.button.width;
|
|
15
|
+
const height = opt.height ?? theme.components.button.height;
|
|
16
|
+
const radius = opt.radius ?? theme.shape.borderRadius;
|
|
17
|
+
const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);
|
|
18
|
+
const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);
|
|
19
|
+
const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);
|
|
20
|
+
const textColor = toColor(k, opt.textColor ?? theme.palette.text);
|
|
21
|
+
const size = opt.size ?? theme.typography.fontSize;
|
|
22
|
+
const font = opt.font ?? theme.typography.fontFamily;
|
|
23
|
+
const pos = opt.pos ?? k.vec2();
|
|
24
|
+
const button = k.add([
|
|
25
|
+
k.rect(width, height, radius > 0 ? { radius } : void 0),
|
|
26
|
+
k.pos(pos),
|
|
27
|
+
k.area(),
|
|
28
|
+
k.scale(),
|
|
29
|
+
k.color(baseColor),
|
|
30
|
+
k.anchor("center")
|
|
31
|
+
]);
|
|
32
|
+
const label = button.add([
|
|
33
|
+
k.text(text, {
|
|
34
|
+
size,
|
|
35
|
+
font
|
|
36
|
+
}),
|
|
37
|
+
k.color(textColor),
|
|
38
|
+
k.anchor("center")
|
|
39
|
+
]);
|
|
40
|
+
button.onClick(() => {
|
|
41
|
+
button.color = toColor(k, pressedColor);
|
|
42
|
+
opt.onClick?.();
|
|
43
|
+
});
|
|
44
|
+
button.onHover(() => {
|
|
45
|
+
button.color = toColor(k, hoverColor);
|
|
46
|
+
button.scale = k.vec2(1.05, 1.05);
|
|
47
|
+
k.setCursor("pointer");
|
|
48
|
+
});
|
|
49
|
+
button.onHoverEnd(() => {
|
|
50
|
+
button.color = baseColor;
|
|
51
|
+
button.scale = k.vec2(1, 1);
|
|
52
|
+
k.setCursor("default");
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
...button,
|
|
56
|
+
label
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// src/theme.ts
|
|
60
|
+
const PRIMARY = "#4f8cff";
|
|
61
|
+
const TEXT = "#ffffff";
|
|
62
|
+
/** Default theme. */
|
|
63
|
+
const theme = {
|
|
64
|
+
palette: {
|
|
65
|
+
primary: PRIMARY,
|
|
66
|
+
secondary: PRIMARY,
|
|
67
|
+
background: "#111827",
|
|
68
|
+
surface: "#1f2937",
|
|
69
|
+
text: TEXT,
|
|
70
|
+
textSecondary: TEXT,
|
|
71
|
+
hover: PRIMARY,
|
|
72
|
+
pressed: PRIMARY,
|
|
73
|
+
disabled: "#6b7280",
|
|
74
|
+
error: "#ef4444"
|
|
75
|
+
},
|
|
76
|
+
typography: {
|
|
77
|
+
fontFamily: "sans-serif",
|
|
78
|
+
fontSize: 18,
|
|
79
|
+
fontWeight: 400,
|
|
80
|
+
lineHeight: 1.2
|
|
81
|
+
},
|
|
82
|
+
shape: { borderRadius: 0 },
|
|
83
|
+
spacing: 8,
|
|
84
|
+
components: {
|
|
85
|
+
button: {
|
|
86
|
+
width: 120,
|
|
87
|
+
height: 40,
|
|
88
|
+
minWidth: 120,
|
|
89
|
+
paddingX: 12,
|
|
90
|
+
paddingY: 8,
|
|
91
|
+
textTransform: "none"
|
|
92
|
+
},
|
|
93
|
+
modal: {
|
|
94
|
+
backdropOpacity: .5,
|
|
95
|
+
borderRadius: 8
|
|
96
|
+
},
|
|
97
|
+
tooltip: {
|
|
98
|
+
background: "#111827",
|
|
99
|
+
textColor: TEXT,
|
|
100
|
+
delay: 300
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
/** Resolve a partial theme into a fully resolved theme. */
|
|
105
|
+
function resolveTheme(input) {
|
|
106
|
+
return {
|
|
107
|
+
palette: {
|
|
108
|
+
...theme.palette,
|
|
109
|
+
...input?.palette
|
|
110
|
+
},
|
|
111
|
+
typography: {
|
|
112
|
+
...theme.typography,
|
|
113
|
+
...input?.typography
|
|
114
|
+
},
|
|
115
|
+
shape: {
|
|
116
|
+
...theme.shape,
|
|
117
|
+
...input?.shape
|
|
118
|
+
},
|
|
119
|
+
spacing: input?.spacing ?? theme.spacing,
|
|
120
|
+
components: {
|
|
121
|
+
button: {
|
|
122
|
+
...theme.components.button,
|
|
123
|
+
...input?.components?.button,
|
|
124
|
+
width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? theme.components.button.width
|
|
125
|
+
},
|
|
126
|
+
modal: {
|
|
127
|
+
...theme.components.modal,
|
|
128
|
+
...input?.components?.modal
|
|
129
|
+
},
|
|
130
|
+
tooltip: {
|
|
131
|
+
...theme.components.tooltip,
|
|
132
|
+
...input?.components?.tooltip
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
// src/plugin.ts
|
|
138
|
+
/** KAPLAY UI plugin. */
|
|
139
|
+
function uiPlugin(k, theme = {}) {
|
|
140
|
+
let userTheme = theme;
|
|
141
|
+
let currentTheme = resolveTheme(userTheme);
|
|
142
|
+
const getTheme = () => currentTheme;
|
|
143
|
+
const setTheme = (next) => {
|
|
144
|
+
userTheme = {
|
|
145
|
+
...userTheme,
|
|
146
|
+
...next
|
|
147
|
+
};
|
|
148
|
+
currentTheme = resolveTheme(userTheme);
|
|
149
|
+
};
|
|
150
|
+
const addButton = (text = "", opt = {}) => {
|
|
151
|
+
return createButton(k, currentTheme, text, opt);
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
addButton,
|
|
155
|
+
setTheme,
|
|
156
|
+
getTheme
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
export { uiPlugin };
|
|
160
|
+
|
|
161
|
+
//# sourceMappingURL=plugin.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":[],"sources":["../src/utils.ts","../src/button.ts","../src/theme.ts","../src/plugin.ts"],"sourcesContent":["import type { Color, KAPLAYCtx } from 'kaplay';\n\n/**\n * Convert hex string to color or return color.\n *\n * @param k - The Kaplay context.\n * @param color - The hex string or color.\n * @returns The color.\n */\nexport function toColor(k: KAPLAYCtx, color: string | Color): Color {\n return typeof color === 'string' ? k.rgb(color) : color;\n}\n","import type { Color, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport type { ButtonOpt, Theme } from './types';\nimport { toColor } from './utils';\n\nexport function createButton(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: string | Color;\n hoverColor?: string | Color;\n pressedColor?: string | Color;\n textColor?: string | Color;\n },\n) {\n const width = opt.width ?? theme.components.button.width;\n const height = opt.height ?? theme.components.button.height;\n const radius = opt.radius ?? theme.shape.borderRadius;\n const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);\n const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);\n const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);\n const textColor = toColor(k, opt.textColor ?? theme.palette.text);\n const size = opt.size ?? theme.typography.fontSize;\n const font = opt.font ?? theme.typography.fontFamily;\n const pos = opt.pos ?? k.vec2();\n\n const button = k.add([\n k.rect(width, height, radius > 0 ? { radius } : undefined),\n k.pos(pos),\n k.area(),\n k.scale(),\n k.color(baseColor),\n k.anchor('center'),\n ]);\n\n const label = button.add([\n k.text(text, { size, font }),\n k.color(textColor as never),\n k.anchor('center'),\n ]);\n\n button.onClick(() => {\n button.color = toColor(k, pressedColor);\n opt.onClick?.();\n });\n\n button.onHover(() => {\n button.color = toColor(k, hoverColor);\n button.scale = k.vec2(1.05, 1.05);\n k.setCursor('pointer');\n });\n\n button.onHoverEnd(() => {\n button.color = baseColor;\n button.scale = k.vec2(1, 1);\n k.setCursor('default');\n });\n\n return {\n ...button,\n label,\n };\n}\n","import type { DeepPartial, Theme } from './types';\n\nconst PRIMARY = '#4f8cff';\nconst TEXT = '#ffffff';\n\n/** Default theme. */\nconst theme: Theme = {\n palette: {\n primary: PRIMARY,\n secondary: PRIMARY,\n background: '#111827',\n surface: '#1f2937',\n text: TEXT,\n textSecondary: TEXT,\n hover: PRIMARY,\n pressed: PRIMARY,\n disabled: '#6b7280',\n error: '#ef4444',\n },\n typography: {\n fontFamily: 'sans-serif',\n fontSize: 18,\n fontWeight: 400,\n lineHeight: 1.2,\n },\n shape: {\n borderRadius: 0,\n },\n spacing: 8,\n components: {\n button: {\n width: 120,\n height: 40,\n minWidth: 120,\n paddingX: 12,\n paddingY: 8,\n textTransform: 'none',\n },\n modal: {\n backdropOpacity: 0.5,\n borderRadius: 8,\n },\n tooltip: {\n background: '#111827',\n textColor: TEXT,\n delay: 300,\n },\n },\n};\n\n/** Resolve a partial theme into a fully resolved theme. */\nexport function resolveTheme(input?: DeepPartial<Theme>): Theme {\n return {\n palette: { ...theme.palette, ...input?.palette },\n typography: { ...theme.typography, ...input?.typography },\n shape: { ...theme.shape, ...input?.shape },\n spacing: input?.spacing ?? theme.spacing,\n components: {\n button: {\n ...theme.components.button,\n ...input?.components?.button,\n width:\n input?.components?.button?.width ??\n input?.components?.button?.minWidth ??\n theme.components.button.width,\n },\n modal: {\n ...theme.components.modal,\n ...input?.components?.modal,\n },\n tooltip: {\n ...theme.components.tooltip,\n ...input?.components?.tooltip,\n },\n },\n };\n}\n","import type { Color, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport { createButton } from './button';\nimport { resolveTheme } from './theme';\nimport type { ButtonOpt, DeepPartial, Theme, UIPlugin } from './types';\n\nexport type { ButtonOpt, Theme, UIPlugin };\n\n/** KAPLAY UI plugin. */\nexport function uiPlugin(\n k: KAPLAYCtx,\n theme: DeepPartial<Theme> = {},\n): UIPlugin {\n let userTheme: DeepPartial<Theme> = theme;\n let currentTheme: Theme = resolveTheme(userTheme);\n\n const getTheme = (): Theme => currentTheme;\n\n const setTheme = (next: DeepPartial<Theme>): void => {\n userTheme = { ...userTheme, ...next };\n currentTheme = resolveTheme(userTheme);\n };\n\n const addButton = (\n text = '',\n opt: ButtonOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: string | Color;\n hoverColor?: string | Color;\n pressedColor?: string | Color;\n textColor?: string | Color;\n } = {},\n ) => {\n return createButton(k, currentTheme, text, opt);\n };\n\n return {\n addButton,\n setTheme,\n getTheme,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
(function(global, factory) {
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.KaplayPluginUI = {}));
|
|
3
|
+
})(this, function(exports) {
|
|
4
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
5
|
+
// src/utils.ts
|
|
6
|
+
/**
|
|
7
|
+
* Convert hex string to color or return color.
|
|
8
|
+
*
|
|
9
|
+
* @param k - The Kaplay context.
|
|
10
|
+
* @param color - The hex string or color.
|
|
11
|
+
* @returns The color.
|
|
12
|
+
*/
|
|
13
|
+
function toColor(k, color) {
|
|
14
|
+
return typeof color === "string" ? k.rgb(color) : color;
|
|
15
|
+
}
|
|
16
|
+
// src/button.ts
|
|
17
|
+
function createButton(k, theme, text, opt) {
|
|
18
|
+
const width = opt.width ?? theme.components.button.width;
|
|
19
|
+
const height = opt.height ?? theme.components.button.height;
|
|
20
|
+
const radius = opt.radius ?? theme.shape.borderRadius;
|
|
21
|
+
const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);
|
|
22
|
+
const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);
|
|
23
|
+
const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);
|
|
24
|
+
const textColor = toColor(k, opt.textColor ?? theme.palette.text);
|
|
25
|
+
const size = opt.size ?? theme.typography.fontSize;
|
|
26
|
+
const font = opt.font ?? theme.typography.fontFamily;
|
|
27
|
+
const pos = opt.pos ?? k.vec2();
|
|
28
|
+
const button = k.add([
|
|
29
|
+
k.rect(width, height, radius > 0 ? { radius } : void 0),
|
|
30
|
+
k.pos(pos),
|
|
31
|
+
k.area(),
|
|
32
|
+
k.scale(),
|
|
33
|
+
k.color(baseColor),
|
|
34
|
+
k.anchor("center")
|
|
35
|
+
]);
|
|
36
|
+
const label = button.add([
|
|
37
|
+
k.text(text, {
|
|
38
|
+
size,
|
|
39
|
+
font
|
|
40
|
+
}),
|
|
41
|
+
k.color(textColor),
|
|
42
|
+
k.anchor("center")
|
|
43
|
+
]);
|
|
44
|
+
button.onClick(() => {
|
|
45
|
+
button.color = toColor(k, pressedColor);
|
|
46
|
+
opt.onClick?.();
|
|
47
|
+
});
|
|
48
|
+
button.onHover(() => {
|
|
49
|
+
button.color = toColor(k, hoverColor);
|
|
50
|
+
button.scale = k.vec2(1.05, 1.05);
|
|
51
|
+
k.setCursor("pointer");
|
|
52
|
+
});
|
|
53
|
+
button.onHoverEnd(() => {
|
|
54
|
+
button.color = baseColor;
|
|
55
|
+
button.scale = k.vec2(1, 1);
|
|
56
|
+
k.setCursor("default");
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
...button,
|
|
60
|
+
label
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// src/theme.ts
|
|
64
|
+
const PRIMARY = "#4f8cff";
|
|
65
|
+
const TEXT = "#ffffff";
|
|
66
|
+
/** Default theme. */
|
|
67
|
+
const theme = {
|
|
68
|
+
palette: {
|
|
69
|
+
primary: PRIMARY,
|
|
70
|
+
secondary: PRIMARY,
|
|
71
|
+
background: "#111827",
|
|
72
|
+
surface: "#1f2937",
|
|
73
|
+
text: TEXT,
|
|
74
|
+
textSecondary: TEXT,
|
|
75
|
+
hover: PRIMARY,
|
|
76
|
+
pressed: PRIMARY,
|
|
77
|
+
disabled: "#6b7280",
|
|
78
|
+
error: "#ef4444"
|
|
79
|
+
},
|
|
80
|
+
typography: {
|
|
81
|
+
fontFamily: "sans-serif",
|
|
82
|
+
fontSize: 18,
|
|
83
|
+
fontWeight: 400,
|
|
84
|
+
lineHeight: 1.2
|
|
85
|
+
},
|
|
86
|
+
shape: { borderRadius: 0 },
|
|
87
|
+
spacing: 8,
|
|
88
|
+
components: {
|
|
89
|
+
button: {
|
|
90
|
+
width: 120,
|
|
91
|
+
height: 40,
|
|
92
|
+
minWidth: 120,
|
|
93
|
+
paddingX: 12,
|
|
94
|
+
paddingY: 8,
|
|
95
|
+
textTransform: "none"
|
|
96
|
+
},
|
|
97
|
+
modal: {
|
|
98
|
+
backdropOpacity: .5,
|
|
99
|
+
borderRadius: 8
|
|
100
|
+
},
|
|
101
|
+
tooltip: {
|
|
102
|
+
background: "#111827",
|
|
103
|
+
textColor: TEXT,
|
|
104
|
+
delay: 300
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
/** Resolve a partial theme into a fully resolved theme. */
|
|
109
|
+
function resolveTheme(input) {
|
|
110
|
+
return {
|
|
111
|
+
palette: {
|
|
112
|
+
...theme.palette,
|
|
113
|
+
...input?.palette
|
|
114
|
+
},
|
|
115
|
+
typography: {
|
|
116
|
+
...theme.typography,
|
|
117
|
+
...input?.typography
|
|
118
|
+
},
|
|
119
|
+
shape: {
|
|
120
|
+
...theme.shape,
|
|
121
|
+
...input?.shape
|
|
122
|
+
},
|
|
123
|
+
spacing: input?.spacing ?? theme.spacing,
|
|
124
|
+
components: {
|
|
125
|
+
button: {
|
|
126
|
+
...theme.components.button,
|
|
127
|
+
...input?.components?.button,
|
|
128
|
+
width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? theme.components.button.width
|
|
129
|
+
},
|
|
130
|
+
modal: {
|
|
131
|
+
...theme.components.modal,
|
|
132
|
+
...input?.components?.modal
|
|
133
|
+
},
|
|
134
|
+
tooltip: {
|
|
135
|
+
...theme.components.tooltip,
|
|
136
|
+
...input?.components?.tooltip
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
// src/plugin.ts
|
|
142
|
+
/** KAPLAY UI plugin. */
|
|
143
|
+
function uiPlugin(k, theme = {}) {
|
|
144
|
+
let userTheme = theme;
|
|
145
|
+
let currentTheme = resolveTheme(userTheme);
|
|
146
|
+
const getTheme = () => currentTheme;
|
|
147
|
+
const setTheme = (next) => {
|
|
148
|
+
userTheme = {
|
|
149
|
+
...userTheme,
|
|
150
|
+
...next
|
|
151
|
+
};
|
|
152
|
+
currentTheme = resolveTheme(userTheme);
|
|
153
|
+
};
|
|
154
|
+
const addButton = (text = "", opt = {}) => {
|
|
155
|
+
return createButton(k, currentTheme, text, opt);
|
|
156
|
+
};
|
|
157
|
+
return {
|
|
158
|
+
addButton,
|
|
159
|
+
setTheme,
|
|
160
|
+
getTheme
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
exports.uiPlugin = uiPlugin;
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
//# sourceMappingURL=plugin.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.umd.js","names":[],"sources":["../src/utils.ts","../src/button.ts","../src/theme.ts","../src/plugin.ts"],"sourcesContent":["import type { Color, KAPLAYCtx } from 'kaplay';\n\n/**\n * Convert hex string to color or return color.\n *\n * @param k - The Kaplay context.\n * @param color - The hex string or color.\n * @returns The color.\n */\nexport function toColor(k: KAPLAYCtx, color: string | Color): Color {\n return typeof color === 'string' ? k.rgb(color) : color;\n}\n","import type { Color, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport type { ButtonOpt, Theme } from './types';\nimport { toColor } from './utils';\n\nexport function createButton(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: string | Color;\n hoverColor?: string | Color;\n pressedColor?: string | Color;\n textColor?: string | Color;\n },\n) {\n const width = opt.width ?? theme.components.button.width;\n const height = opt.height ?? theme.components.button.height;\n const radius = opt.radius ?? theme.shape.borderRadius;\n const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);\n const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);\n const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);\n const textColor = toColor(k, opt.textColor ?? theme.palette.text);\n const size = opt.size ?? theme.typography.fontSize;\n const font = opt.font ?? theme.typography.fontFamily;\n const pos = opt.pos ?? k.vec2();\n\n const button = k.add([\n k.rect(width, height, radius > 0 ? { radius } : undefined),\n k.pos(pos),\n k.area(),\n k.scale(),\n k.color(baseColor),\n k.anchor('center'),\n ]);\n\n const label = button.add([\n k.text(text, { size, font }),\n k.color(textColor as never),\n k.anchor('center'),\n ]);\n\n button.onClick(() => {\n button.color = toColor(k, pressedColor);\n opt.onClick?.();\n });\n\n button.onHover(() => {\n button.color = toColor(k, hoverColor);\n button.scale = k.vec2(1.05, 1.05);\n k.setCursor('pointer');\n });\n\n button.onHoverEnd(() => {\n button.color = baseColor;\n button.scale = k.vec2(1, 1);\n k.setCursor('default');\n });\n\n return {\n ...button,\n label,\n };\n}\n","import type { DeepPartial, Theme } from './types';\n\nconst PRIMARY = '#4f8cff';\nconst TEXT = '#ffffff';\n\n/** Default theme. */\nconst theme: Theme = {\n palette: {\n primary: PRIMARY,\n secondary: PRIMARY,\n background: '#111827',\n surface: '#1f2937',\n text: TEXT,\n textSecondary: TEXT,\n hover: PRIMARY,\n pressed: PRIMARY,\n disabled: '#6b7280',\n error: '#ef4444',\n },\n typography: {\n fontFamily: 'sans-serif',\n fontSize: 18,\n fontWeight: 400,\n lineHeight: 1.2,\n },\n shape: {\n borderRadius: 0,\n },\n spacing: 8,\n components: {\n button: {\n width: 120,\n height: 40,\n minWidth: 120,\n paddingX: 12,\n paddingY: 8,\n textTransform: 'none',\n },\n modal: {\n backdropOpacity: 0.5,\n borderRadius: 8,\n },\n tooltip: {\n background: '#111827',\n textColor: TEXT,\n delay: 300,\n },\n },\n};\n\n/** Resolve a partial theme into a fully resolved theme. */\nexport function resolveTheme(input?: DeepPartial<Theme>): Theme {\n return {\n palette: { ...theme.palette, ...input?.palette },\n typography: { ...theme.typography, ...input?.typography },\n shape: { ...theme.shape, ...input?.shape },\n spacing: input?.spacing ?? theme.spacing,\n components: {\n button: {\n ...theme.components.button,\n ...input?.components?.button,\n width:\n input?.components?.button?.width ??\n input?.components?.button?.minWidth ??\n theme.components.button.width,\n },\n modal: {\n ...theme.components.modal,\n ...input?.components?.modal,\n },\n tooltip: {\n ...theme.components.tooltip,\n ...input?.components?.tooltip,\n },\n },\n };\n}\n","import type { Color, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport { createButton } from './button';\nimport { resolveTheme } from './theme';\nimport type { ButtonOpt, DeepPartial, Theme, UIPlugin } from './types';\n\nexport type { ButtonOpt, Theme, UIPlugin };\n\n/** KAPLAY UI plugin. */\nexport function uiPlugin(\n k: KAPLAYCtx,\n theme: DeepPartial<Theme> = {},\n): UIPlugin {\n let userTheme: DeepPartial<Theme> = theme;\n let currentTheme: Theme = resolveTheme(userTheme);\n\n const getTheme = (): Theme => currentTheme;\n\n const setTheme = (next: DeepPartial<Theme>): void => {\n userTheme = { ...userTheme, ...next };\n currentTheme = resolveTheme(userTheme);\n };\n\n const addButton = (\n text = '',\n opt: ButtonOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: string | Color;\n hoverColor?: string | Color;\n pressedColor?: string | Color;\n textColor?: string | Color;\n } = {},\n ) => {\n return createButton(k, currentTheme, text, opt);\n };\n\n return {\n addButton,\n setTheme,\n getTheme,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.KaplayPluginUI={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e,t){return typeof t==`string`?e.rgb(t):t}function n(e,n,r,i){let a=i.width??n.components.button.width,o=i.height??n.components.button.height,s=i.radius??n.shape.borderRadius,c=t(e,i.color??i.fill??n.palette.primary),l=t(e,i.hoverColor??n.palette.hover),u=t(e,i.pressedColor??n.palette.pressed),d=t(e,i.textColor??n.palette.text),f=i.size??n.typography.fontSize,p=i.font??n.typography.fontFamily,m=i.pos??e.vec2(),h=e.add([e.rect(a,o,s>0?{radius:s}:void 0),e.pos(m),e.area(),e.scale(),e.color(c),e.anchor(`center`)]),g=h.add([e.text(r,{size:f,font:p}),e.color(d),e.anchor(`center`)]);return h.onClick(()=>{h.color=t(e,u),i.onClick?.()}),h.onHover(()=>{h.color=t(e,l),h.scale=e.vec2(1.05,1.05),e.setCursor(`pointer`)}),h.onHoverEnd(()=>{h.color=c,h.scale=e.vec2(1,1),e.setCursor(`default`)}),{...h,label:g}}let r=`#4f8cff`,i=`#ffffff`,a={palette:{primary:r,secondary:r,background:`#111827`,surface:`#1f2937`,text:i,textSecondary:i,hover:r,pressed:r,disabled:`#6b7280`,error:`#ef4444`},typography:{fontFamily:`sans-serif`,fontSize:18,fontWeight:400,lineHeight:1.2},shape:{borderRadius:0},spacing:8,components:{button:{width:120,height:40,minWidth:120,paddingX:12,paddingY:8,textTransform:`none`},modal:{backdropOpacity:.5,borderRadius:8},tooltip:{background:`#111827`,textColor:i,delay:300}}};function o(e){return{palette:{...a.palette,...e?.palette},typography:{...a.typography,...e?.typography},shape:{...a.shape,...e?.shape},spacing:e?.spacing??a.spacing,components:{button:{...a.components.button,...e?.components?.button,width:e?.components?.button?.width??e?.components?.button?.minWidth??a.components.button.width},modal:{...a.components.modal,...e?.components?.modal},tooltip:{...a.components.tooltip,...e?.components?.tooltip}}}}function s(e,t={}){let r=t,i=o(r);return{addButton:(t=``,r={})=>n(e,i,t,r),setTheme:e=>{r={...r,...e},i=o(r)},getTheme:()=>i}}e.uiPlugin=s});
|
|
2
|
+
//# sourceMappingURL=plugin.umd.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.umd.min.js","names":["factory","global","exports","toColor","color","k","createButton","width","opt","theme","height","radius","baseColor","hoverColor","pressedColor","textColor","size","font","pos","button","label","text","PRIMARY","TEXT","resolveTheme","input","uiPlugin","userTheme","currentTheme","next"],"sources":["../src/utils.ts","../src/button.ts","../src/theme.ts","../src/plugin.ts"],"sourcesContent":["import type { Color, KAPLAYCtx } from 'kaplay';\n\n/**\n * Convert hex string to color or return color.\n *\n * @param k - The Kaplay context.\n * @param color - The hex string or color.\n * @returns The color.\n */\nexport function toColor(k: KAPLAYCtx, color: string | Color): Color {\n return typeof color === 'string' ? k.rgb(color) : color;\n}\n","import type { Color, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport type { ButtonOpt, Theme } from './types';\nimport { toColor } from './utils';\n\nexport function createButton(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: string | Color;\n hoverColor?: string | Color;\n pressedColor?: string | Color;\n textColor?: string | Color;\n },\n) {\n const width = opt.width ?? theme.components.button.width;\n const height = opt.height ?? theme.components.button.height;\n const radius = opt.radius ?? theme.shape.borderRadius;\n const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);\n const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);\n const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);\n const textColor = toColor(k, opt.textColor ?? theme.palette.text);\n const size = opt.size ?? theme.typography.fontSize;\n const font = opt.font ?? theme.typography.fontFamily;\n const pos = opt.pos ?? k.vec2();\n\n const button = k.add([\n k.rect(width, height, radius > 0 ? { radius } : undefined),\n k.pos(pos),\n k.area(),\n k.scale(),\n k.color(baseColor),\n k.anchor('center'),\n ]);\n\n const label = button.add([\n k.text(text, { size, font }),\n k.color(textColor as never),\n k.anchor('center'),\n ]);\n\n button.onClick(() => {\n button.color = toColor(k, pressedColor);\n opt.onClick?.();\n });\n\n button.onHover(() => {\n button.color = toColor(k, hoverColor);\n button.scale = k.vec2(1.05, 1.05);\n k.setCursor('pointer');\n });\n\n button.onHoverEnd(() => {\n button.color = baseColor;\n button.scale = k.vec2(1, 1);\n k.setCursor('default');\n });\n\n return {\n ...button,\n label,\n };\n}\n","import type { DeepPartial, Theme } from './types';\n\nconst PRIMARY = '#4f8cff';\nconst TEXT = '#ffffff';\n\n/** Default theme. */\nconst theme: Theme = {\n palette: {\n primary: PRIMARY,\n secondary: PRIMARY,\n background: '#111827',\n surface: '#1f2937',\n text: TEXT,\n textSecondary: TEXT,\n hover: PRIMARY,\n pressed: PRIMARY,\n disabled: '#6b7280',\n error: '#ef4444',\n },\n typography: {\n fontFamily: 'sans-serif',\n fontSize: 18,\n fontWeight: 400,\n lineHeight: 1.2,\n },\n shape: {\n borderRadius: 0,\n },\n spacing: 8,\n components: {\n button: {\n width: 120,\n height: 40,\n minWidth: 120,\n paddingX: 12,\n paddingY: 8,\n textTransform: 'none',\n },\n modal: {\n backdropOpacity: 0.5,\n borderRadius: 8,\n },\n tooltip: {\n background: '#111827',\n textColor: TEXT,\n delay: 300,\n },\n },\n};\n\n/** Resolve a partial theme into a fully resolved theme. */\nexport function resolveTheme(input?: DeepPartial<Theme>): Theme {\n return {\n palette: { ...theme.palette, ...input?.palette },\n typography: { ...theme.typography, ...input?.typography },\n shape: { ...theme.shape, ...input?.shape },\n spacing: input?.spacing ?? theme.spacing,\n components: {\n button: {\n ...theme.components.button,\n ...input?.components?.button,\n width:\n input?.components?.button?.width ??\n input?.components?.button?.minWidth ??\n theme.components.button.width,\n },\n modal: {\n ...theme.components.modal,\n ...input?.components?.modal,\n },\n tooltip: {\n ...theme.components.tooltip,\n ...input?.components?.tooltip,\n },\n },\n };\n}\n","import type { Color, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport { createButton } from './button';\nimport { resolveTheme } from './theme';\nimport type { ButtonOpt, DeepPartial, Theme, UIPlugin } from './types';\n\nexport type { ButtonOpt, Theme, UIPlugin };\n\n/** KAPLAY UI plugin. */\nexport function uiPlugin(\n k: KAPLAYCtx,\n theme: DeepPartial<Theme> = {},\n): UIPlugin {\n let userTheme: DeepPartial<Theme> = theme;\n let currentTheme: Theme = resolveTheme(userTheme);\n\n const getTheme = (): Theme => currentTheme;\n\n const setTheme = (next: DeepPartial<Theme>): void => {\n userTheme = { ...userTheme, ...next };\n currentTheme = resolveTheme(userTheme);\n };\n\n const addButton = (\n text = '',\n opt: ButtonOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: string | Color;\n hoverColor?: string | Color;\n pressedColor?: string | Color;\n textColor?: string | Color;\n } = {},\n ) => {\n return createButton(k, currentTheme, text, opt);\n };\n\n return {\n addButton,\n setTheme,\n getTheme,\n };\n}\n"],"mappings":"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"}
|
package/global.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { UIPlugin } from './dist/plugin.cjs';
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
/**
|
|
5
|
+
* Add a button.
|
|
6
|
+
*
|
|
7
|
+
* @param text - The button text.
|
|
8
|
+
* @param opt - The button options.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```js
|
|
12
|
+
* addButton('Start', {
|
|
13
|
+
* onClick: () => {
|
|
14
|
+
* go('game');
|
|
15
|
+
* },
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @returns The button object.
|
|
20
|
+
*/
|
|
21
|
+
var addButton: UIPlugin['addButton'];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Retrieve the theme.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```js
|
|
28
|
+
* getTheme();
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @returns The theme config.
|
|
32
|
+
*/
|
|
33
|
+
var getTheme: UIPlugin['getTheme'];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Customize the theme.
|
|
37
|
+
*
|
|
38
|
+
* @param theme - The partial theme overrides.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```js
|
|
42
|
+
* setTheme({
|
|
43
|
+
* palette: {
|
|
44
|
+
* primary: rgb(80, 160, 255),
|
|
45
|
+
* text: rgb(255, 255, 255),
|
|
46
|
+
* },
|
|
47
|
+
* shape: {
|
|
48
|
+
* borderRadius: 8,
|
|
49
|
+
* },
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
var setTheme: UIPlugin['setTheme'];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export {};
|
package/global.js
ADDED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,4 +1,98 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kaplay-plugin-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Kaplay plugin UI",
|
|
5
|
+
"author": "Mark <mark@remarkablemark.org> (https://remarkablemark.org)",
|
|
6
|
+
"main": "./dist/plugin.cjs",
|
|
7
|
+
"module": "./dist/plugin.mjs",
|
|
8
|
+
"types": "./dist/plugin.d.mts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/plugin.d.mts",
|
|
13
|
+
"default": "./dist/plugin.mjs"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/plugin.d.cts",
|
|
17
|
+
"default": "./dist/plugin.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./global": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./global.d.ts",
|
|
23
|
+
"default": "./global.js"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./global.d.ts",
|
|
27
|
+
"default": "./global.js"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsdown",
|
|
33
|
+
"clean": "rm -rf coverage dist docs",
|
|
34
|
+
"docs": "typedoc",
|
|
35
|
+
"docs:watch": "npm run docs -- --watch",
|
|
36
|
+
"lint": "eslint .",
|
|
37
|
+
"lint:fix": "npm run lint -- --fix",
|
|
38
|
+
"lint:package": "publint",
|
|
39
|
+
"lint:tsc": "tsc",
|
|
40
|
+
"lint:types": "npx @arethetypeswrong/cli --pack",
|
|
41
|
+
"prepare": "husky",
|
|
42
|
+
"prepublishOnly": "npm run build && npm run lint && npm run lint:tsc && npm run test:ci",
|
|
43
|
+
"start": "vite --open",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"test:ci": "CI=true npm test -- --color --coverage",
|
|
46
|
+
"test:watch": "vitest --coverage.enabled=false"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/remarkablegames/kaplay-plugin-ui.git"
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/remarkablegames/kaplay-plugin-ui/issues"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"kaplay",
|
|
57
|
+
"plugin",
|
|
58
|
+
"ui",
|
|
59
|
+
"game"
|
|
60
|
+
],
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"kaplay": "*"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@commitlint/cli": "21.2.4",
|
|
66
|
+
"@commitlint/config-conventional": "21.2.4",
|
|
67
|
+
"@eslint/js": "10.0.1",
|
|
68
|
+
"@types/node": "26.6.6",
|
|
69
|
+
"@vitest/coverage-v8": "5.0.5",
|
|
70
|
+
"eslint": "10.14.0",
|
|
71
|
+
"eslint-plugin-prettier": "5.5.7",
|
|
72
|
+
"eslint-plugin-simple-import-sort": "14.0.0",
|
|
73
|
+
"eslint-plugin-tsdoc": "0.5.4",
|
|
74
|
+
"husky": "9.1.7",
|
|
75
|
+
"kaplay": "3001.0.19",
|
|
76
|
+
"lint-staged": "17.6.0",
|
|
77
|
+
"prettier": "3.9.10",
|
|
78
|
+
"publint": "0.3.25",
|
|
79
|
+
"tsdown": "0.23.4",
|
|
80
|
+
"typedoc": "0.28.20",
|
|
81
|
+
"typescript": "6.0.3",
|
|
82
|
+
"typescript-eslint": "8.72.1",
|
|
83
|
+
"vite": "8.3.5",
|
|
84
|
+
"vitest": "5.0.5"
|
|
85
|
+
},
|
|
86
|
+
"files": [
|
|
87
|
+
"dist/",
|
|
88
|
+
"global.d.ts",
|
|
89
|
+
"global.js"
|
|
90
|
+
],
|
|
91
|
+
"funding": [
|
|
92
|
+
{
|
|
93
|
+
"type": "github",
|
|
94
|
+
"url": "https://github.com/sponsors/remarkablemark"
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
"license": "MIT"
|
|
4
98
|
}
|