kaplay-plugin-ui 0.0.0 → 1.0.0
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 +95 -0
- package/dist/plugin.cjs +243 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +109 -0
- package/dist/plugin.d.cts.map +1 -0
- package/dist/plugin.d.mts +109 -0
- package/dist/plugin.d.mts.map +1 -0
- package/dist/plugin.mjs +240 -0
- package/dist/plugin.mjs.map +1 -0
- package/dist/plugin.umd.js +247 -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 +7 -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,95 @@
|
|
|
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:
|
|
10
|
+
|
|
11
|
+
- `addButton(text?, opt?)`: button game object
|
|
12
|
+
- `button(text?, opt?)`: button component (use in `add([button(...)])`)
|
|
13
|
+
- `setTheme(theme)`: update theme
|
|
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
|
+
Use the plugin:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const button = k.addButton('Start', {
|
|
54
|
+
onClick: () => {
|
|
55
|
+
k.go('game');
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Customize the theme:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
k.setTheme({
|
|
64
|
+
palette: {
|
|
65
|
+
primary: k.rgb(80, 160, 255),
|
|
66
|
+
text: k.rgb(255, 255, 255),
|
|
67
|
+
},
|
|
68
|
+
shape: {
|
|
69
|
+
borderRadius: 8,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
To load the plugin using a script:
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<script src="https://unpkg.com/kaplay@latest/dist/kaplay.js"></script>
|
|
78
|
+
<script src="https://unpkg.com/kaplay-plugin-ui@latest/dist/plugin.umd.js"></script>
|
|
79
|
+
|
|
80
|
+
<script>
|
|
81
|
+
const k = kaplay({
|
|
82
|
+
plugins: [KaplayPluginUI.uiPlugin],
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const button = k.addButton('Start');
|
|
86
|
+
</script>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Release
|
|
90
|
+
|
|
91
|
+
Release is automated with [Release Please](https://github.com/googleapis/release-please).
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
[MIT](https://github.com/remarkablegames/kaplay-plugin-ui/blob/master/LICENSE)
|
package/dist/plugin.cjs
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
// src/button.ts
|
|
3
|
+
function createButtonComponent(k, theme, text, opt) {
|
|
4
|
+
let currentText = text;
|
|
5
|
+
let currentOpt = { ...opt };
|
|
6
|
+
const readWidth = () => {
|
|
7
|
+
return currentOpt.width ?? theme.components.button.width;
|
|
8
|
+
};
|
|
9
|
+
const readHeight = () => {
|
|
10
|
+
return currentOpt.height ?? theme.components.button.height;
|
|
11
|
+
};
|
|
12
|
+
const comp = {
|
|
13
|
+
id: "button",
|
|
14
|
+
get text() {
|
|
15
|
+
return currentText;
|
|
16
|
+
},
|
|
17
|
+
set text(value) {
|
|
18
|
+
currentText = value;
|
|
19
|
+
},
|
|
20
|
+
get width() {
|
|
21
|
+
return readWidth();
|
|
22
|
+
},
|
|
23
|
+
set width(value) {
|
|
24
|
+
currentOpt.width = value;
|
|
25
|
+
},
|
|
26
|
+
get height() {
|
|
27
|
+
return readHeight();
|
|
28
|
+
},
|
|
29
|
+
set height(value) {
|
|
30
|
+
currentOpt.height = value;
|
|
31
|
+
},
|
|
32
|
+
renderArea() {
|
|
33
|
+
return new k.Rect(k.vec2(), comp.width, comp.height);
|
|
34
|
+
},
|
|
35
|
+
setStyle(next) {
|
|
36
|
+
currentOpt = {
|
|
37
|
+
...currentOpt,
|
|
38
|
+
...next
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
add() {},
|
|
42
|
+
draw() {
|
|
43
|
+
const width = comp.width;
|
|
44
|
+
const height = comp.height;
|
|
45
|
+
const radius = currentOpt.radius ?? theme.shape.borderRadius;
|
|
46
|
+
const fill = currentOpt.fill ?? theme.palette.primary;
|
|
47
|
+
const textColor = currentOpt.textColor ?? theme.palette.text;
|
|
48
|
+
const size = currentOpt.size ?? theme.typography.fontSize;
|
|
49
|
+
const font = currentOpt.font ?? theme.typography.fontFamily;
|
|
50
|
+
const drawRect = k.drawRect;
|
|
51
|
+
drawRect?.({
|
|
52
|
+
pos: k.vec2(),
|
|
53
|
+
width,
|
|
54
|
+
height,
|
|
55
|
+
color: fill,
|
|
56
|
+
radius
|
|
57
|
+
});
|
|
58
|
+
const drawText = k.drawText;
|
|
59
|
+
drawText?.({
|
|
60
|
+
text: currentText,
|
|
61
|
+
pos: k.vec2(width / 2, height / 2),
|
|
62
|
+
size,
|
|
63
|
+
font,
|
|
64
|
+
color: textColor,
|
|
65
|
+
anchor: "center"
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
destroy() {}
|
|
69
|
+
};
|
|
70
|
+
return comp;
|
|
71
|
+
}
|
|
72
|
+
function createButtonObject(k, theme, text, opt) {
|
|
73
|
+
const width = opt.width ?? theme.components.button.width;
|
|
74
|
+
const height = opt.height ?? theme.components.button.height;
|
|
75
|
+
const radius = opt.radius ?? theme.shape.borderRadius;
|
|
76
|
+
const baseColor = opt.color ?? opt.fill ?? theme.palette.primary;
|
|
77
|
+
const hoverColor = opt.hoverColor ?? theme.palette.hover;
|
|
78
|
+
const pressedColor = opt.pressedColor ?? theme.palette.pressed;
|
|
79
|
+
const textColor = opt.textColor ?? theme.palette.text;
|
|
80
|
+
const size = opt.size ?? theme.typography.fontSize;
|
|
81
|
+
const font = opt.font ?? theme.typography.fontFamily;
|
|
82
|
+
const pos = opt.pos ?? k.vec2();
|
|
83
|
+
const obj = k.add([
|
|
84
|
+
k.rect(width, height, radius > 0 ? { radius } : void 0),
|
|
85
|
+
k.pos(pos),
|
|
86
|
+
k.area(),
|
|
87
|
+
k.color(baseColor),
|
|
88
|
+
k.anchor("center")
|
|
89
|
+
]);
|
|
90
|
+
const label = obj.add([
|
|
91
|
+
k.text(text, {
|
|
92
|
+
size,
|
|
93
|
+
font
|
|
94
|
+
}),
|
|
95
|
+
k.color(textColor),
|
|
96
|
+
k.anchor("center")
|
|
97
|
+
]);
|
|
98
|
+
let currentText = text;
|
|
99
|
+
let currentColor = baseColor;
|
|
100
|
+
obj.onClick(() => {
|
|
101
|
+
obj.color = pressedColor;
|
|
102
|
+
opt.onClick?.();
|
|
103
|
+
});
|
|
104
|
+
obj.onHover(() => {
|
|
105
|
+
obj.color = hoverColor;
|
|
106
|
+
obj.scale = k.vec2(1.05, 1.05);
|
|
107
|
+
k.setCursor("pointer");
|
|
108
|
+
});
|
|
109
|
+
obj.onHoverEnd(() => {
|
|
110
|
+
obj.color = currentColor;
|
|
111
|
+
obj.scale = k.vec2(1, 1);
|
|
112
|
+
k.setCursor("default");
|
|
113
|
+
});
|
|
114
|
+
obj.setSize = (w, h) => {
|
|
115
|
+
obj.width = w;
|
|
116
|
+
obj.height = h;
|
|
117
|
+
};
|
|
118
|
+
obj.setButtonColor = (color) => {
|
|
119
|
+
currentColor = color;
|
|
120
|
+
obj.color = color;
|
|
121
|
+
};
|
|
122
|
+
obj.setButtonText = (value) => {
|
|
123
|
+
currentText = value;
|
|
124
|
+
label.text = value;
|
|
125
|
+
};
|
|
126
|
+
obj.setButtonTextSize = (value) => {
|
|
127
|
+
label.textSize = value;
|
|
128
|
+
};
|
|
129
|
+
obj.setPosition = (x, y) => {
|
|
130
|
+
obj.pos = k.vec2(x, y);
|
|
131
|
+
};
|
|
132
|
+
label.text = currentText;
|
|
133
|
+
return obj;
|
|
134
|
+
}
|
|
135
|
+
// src/theme.ts
|
|
136
|
+
const DEFAULT_PRIMARY = "#4f8cff";
|
|
137
|
+
const DEFAULT_TEXT = "#ffffff";
|
|
138
|
+
/** Default theme used when no theme is provided. */
|
|
139
|
+
const defaultTheme = {
|
|
140
|
+
palette: {
|
|
141
|
+
primary: DEFAULT_PRIMARY,
|
|
142
|
+
secondary: DEFAULT_PRIMARY,
|
|
143
|
+
background: "#111827",
|
|
144
|
+
surface: "#1f2937",
|
|
145
|
+
text: DEFAULT_TEXT,
|
|
146
|
+
textSecondary: DEFAULT_TEXT,
|
|
147
|
+
hover: DEFAULT_PRIMARY,
|
|
148
|
+
pressed: DEFAULT_PRIMARY,
|
|
149
|
+
disabled: "#6b7280",
|
|
150
|
+
error: "#ef4444"
|
|
151
|
+
},
|
|
152
|
+
typography: {
|
|
153
|
+
fontFamily: "sans-serif",
|
|
154
|
+
fontSize: 18,
|
|
155
|
+
fontWeight: 400,
|
|
156
|
+
lineHeight: 1.2
|
|
157
|
+
},
|
|
158
|
+
shape: { borderRadius: 0 },
|
|
159
|
+
spacing: 8,
|
|
160
|
+
components: {
|
|
161
|
+
button: {
|
|
162
|
+
width: 120,
|
|
163
|
+
height: 40,
|
|
164
|
+
minWidth: 120,
|
|
165
|
+
paddingX: 12,
|
|
166
|
+
paddingY: 8,
|
|
167
|
+
textTransform: "none"
|
|
168
|
+
},
|
|
169
|
+
modal: {
|
|
170
|
+
backdropOpacity: .5,
|
|
171
|
+
borderRadius: 8
|
|
172
|
+
},
|
|
173
|
+
tooltip: {
|
|
174
|
+
background: "#111827",
|
|
175
|
+
textColor: DEFAULT_TEXT,
|
|
176
|
+
delay: 300
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
/** Resolve a partial theme into a fully resolved theme. */
|
|
181
|
+
function resolveTheme(input) {
|
|
182
|
+
return {
|
|
183
|
+
palette: {
|
|
184
|
+
...defaultTheme.palette,
|
|
185
|
+
...input?.palette
|
|
186
|
+
},
|
|
187
|
+
typography: {
|
|
188
|
+
...defaultTheme.typography,
|
|
189
|
+
...input?.typography
|
|
190
|
+
},
|
|
191
|
+
shape: {
|
|
192
|
+
...defaultTheme.shape,
|
|
193
|
+
...input?.shape
|
|
194
|
+
},
|
|
195
|
+
spacing: input?.spacing ?? defaultTheme.spacing,
|
|
196
|
+
components: {
|
|
197
|
+
button: {
|
|
198
|
+
...defaultTheme.components.button,
|
|
199
|
+
...input?.components?.button,
|
|
200
|
+
width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? defaultTheme.components.button.width
|
|
201
|
+
},
|
|
202
|
+
modal: {
|
|
203
|
+
...defaultTheme.components.modal,
|
|
204
|
+
...input?.components?.modal
|
|
205
|
+
},
|
|
206
|
+
tooltip: {
|
|
207
|
+
...defaultTheme.components.tooltip,
|
|
208
|
+
...input?.components?.tooltip
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
// src/plugin.ts
|
|
214
|
+
/** KAPLAY UI plugin. */
|
|
215
|
+
function uiPlugin(k, theme = {}) {
|
|
216
|
+
let userTheme = theme;
|
|
217
|
+
let currentTheme = resolveTheme(userTheme);
|
|
218
|
+
const getTheme = () => currentTheme;
|
|
219
|
+
const setTheme = (next) => {
|
|
220
|
+
userTheme = {
|
|
221
|
+
...userTheme,
|
|
222
|
+
...next
|
|
223
|
+
};
|
|
224
|
+
currentTheme = resolveTheme(userTheme);
|
|
225
|
+
};
|
|
226
|
+
const button = (text = "", opt = {}) => {
|
|
227
|
+
return createButtonComponent(k, currentTheme, text, opt);
|
|
228
|
+
};
|
|
229
|
+
const addButton = (text = "", opt = {}) => {
|
|
230
|
+
return createButtonObject(k, currentTheme, text, opt);
|
|
231
|
+
};
|
|
232
|
+
return {
|
|
233
|
+
button,
|
|
234
|
+
addButton,
|
|
235
|
+
setTheme,
|
|
236
|
+
getTheme
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
exports.createButtonComponent = createButtonComponent;
|
|
240
|
+
exports.createButtonObject = createButtonObject;
|
|
241
|
+
exports.uiPlugin = uiPlugin;
|
|
242
|
+
|
|
243
|
+
//# sourceMappingURL=plugin.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.cjs","names":[],"sources":["../src/button.ts","../src/theme.ts","../src/plugin.ts"],"sourcesContent":["import type { Comp, GameObj, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport type { ButtonComp, ButtonCompOpt, Color, Theme } from './types';\n\nexport function createButtonComponent(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonCompOpt,\n): ButtonComp {\n let currentText = text;\n let currentOpt: ButtonCompOpt = { ...opt };\n\n const readWidth = (): number => {\n return currentOpt.width ?? theme.components.button.width;\n };\n\n const readHeight = (): number => {\n return currentOpt.height ?? theme.components.button.height;\n };\n\n const comp: ButtonComp = {\n id: 'button',\n get text() {\n return currentText;\n },\n set text(value: string) {\n currentText = value;\n },\n get width() {\n return readWidth();\n },\n set width(value: number) {\n currentOpt.width = value;\n },\n get height() {\n return readHeight();\n },\n set height(value: number) {\n currentOpt.height = value;\n },\n renderArea() {\n return new k.Rect(k.vec2(), comp.width, comp.height);\n },\n setStyle(next: Partial<ButtonCompOpt>): void {\n currentOpt = { ...currentOpt, ...next };\n },\n add(): void {\n // No-op: rendering is handled in draw().\n },\n draw(): void {\n const width = comp.width;\n const height = comp.height;\n const radius = currentOpt.radius ?? theme.shape.borderRadius;\n const fill = currentOpt.fill ?? theme.palette.primary;\n const textColor = currentOpt.textColor ?? theme.palette.text;\n const size = currentOpt.size ?? theme.typography.fontSize;\n const font = currentOpt.font ?? theme.typography.fontFamily;\n\n const drawRect = k.drawRect as unknown as\n ((opt: Record<string, unknown>) => void) | undefined;\n drawRect?.({\n pos: k.vec2(),\n width,\n height,\n color: fill,\n radius,\n });\n\n const drawText = k.drawText as unknown as\n ((opt: Record<string, unknown>) => void) | undefined;\n drawText?.({\n text: currentText,\n pos: k.vec2(width / 2, height / 2),\n size,\n font,\n color: textColor,\n anchor: 'center',\n });\n },\n destroy(): void {\n // No resources to release.\n },\n };\n\n return comp;\n}\n\nexport function createButtonObject(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n },\n): GameObj {\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 = opt.color ?? opt.fill ?? theme.palette.primary;\n const hoverColor = opt.hoverColor ?? theme.palette.hover;\n const pressedColor = opt.pressedColor ?? theme.palette.pressed;\n const textColor = 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 interface ButtonGameObj {\n add: (comps: Comp[]) => { text: string; textSize: number };\n onClick: (cb: () => void) => void;\n onHover: (cb: () => void) => void;\n onHoverEnd: (cb: () => void) => void;\n width: number;\n height: number;\n color: unknown;\n scale: { x: number; y: number };\n pos: { x: number; y: number };\n setSize: (w: number, h: number) => void;\n setButtonColor: (color: Color) => void;\n setButtonText: (value: string) => void;\n setButtonTextSize: (value: number) => void;\n setPosition: (x: number, y: number) => void;\n }\n\n const obj = k.add([\n k.rect(width, height, radius > 0 ? { radius } : undefined),\n k.pos(pos as never),\n k.area(),\n k.color(baseColor as never),\n k.anchor('center'),\n ]) as unknown as ButtonGameObj;\n\n const label = obj.add([\n k.text(text, { size, font }),\n k.color(textColor as never),\n k.anchor('center'),\n ]) as GameObj & { text: string; textSize: number };\n\n let currentText = text;\n let currentColor: Color = baseColor;\n\n obj.onClick(() => {\n obj.color = pressedColor;\n opt.onClick?.();\n });\n obj.onHover(() => {\n obj.color = hoverColor;\n obj.scale = k.vec2(1.05, 1.05);\n k.setCursor('pointer');\n });\n obj.onHoverEnd(() => {\n obj.color = currentColor;\n obj.scale = k.vec2(1, 1);\n k.setCursor('default');\n });\n\n obj.setSize = (w: number, h: number): void => {\n obj.width = w;\n obj.height = h;\n };\n\n obj.setButtonColor = (color: Color): void => {\n currentColor = color;\n obj.color = color;\n };\n\n obj.setButtonText = (value: string): void => {\n currentText = value;\n label.text = value;\n };\n\n obj.setButtonTextSize = (value: number): void => {\n label.textSize = value;\n };\n\n obj.setPosition = (x: number, y: number): void => {\n obj.pos = k.vec2(x, y);\n };\n\n label.text = currentText;\n\n return obj as unknown as GameObj;\n}\n","import type { DeepPartial, Theme } from './types';\n\nconst DEFAULT_PRIMARY = '#4f8cff';\nconst DEFAULT_TEXT = '#ffffff';\n\n/** Default theme used when no theme is provided. */\nexport const defaultTheme: Theme = {\n palette: {\n primary: DEFAULT_PRIMARY,\n secondary: DEFAULT_PRIMARY,\n background: '#111827',\n surface: '#1f2937',\n text: DEFAULT_TEXT,\n textSecondary: DEFAULT_TEXT,\n hover: DEFAULT_PRIMARY,\n pressed: DEFAULT_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: DEFAULT_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: { ...defaultTheme.palette, ...input?.palette },\n typography: { ...defaultTheme.typography, ...input?.typography },\n shape: { ...defaultTheme.shape, ...input?.shape },\n spacing: input?.spacing ?? defaultTheme.spacing,\n components: {\n button: {\n ...defaultTheme.components.button,\n ...input?.components?.button,\n width:\n input?.components?.button?.width ??\n input?.components?.button?.minWidth ??\n defaultTheme.components.button.width,\n },\n modal: {\n ...defaultTheme.components.modal,\n ...input?.components?.modal,\n },\n tooltip: {\n ...defaultTheme.components.tooltip,\n ...input?.components?.tooltip,\n },\n },\n };\n}\n","import type { GameObj, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport { createButtonComponent, createButtonObject } from './button';\nimport { resolveTheme } from './theme';\nimport type {\n ButtonComp,\n ButtonCompOpt,\n Color,\n DeepPartial,\n Theme,\n} from './types';\n\nexport { createButtonComponent, createButtonObject } from './button';\nexport type { ButtonComp, ButtonCompOpt, Color, Theme } from './types';\n\ndeclare module 'kaplay' {\n interface KAPLAYCtx {\n button: (text?: string, opt?: ButtonCompOpt) => ButtonComp;\n addButton: (\n text?: string,\n opt?: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n },\n ) => GameObj;\n setTheme: (theme: DeepPartial<Theme>) => void;\n getTheme: () => Theme;\n }\n}\n\n/** KAPLAY UI plugin. */\nexport function uiPlugin(k: KAPLAYCtx, theme: DeepPartial<Theme> = {}) {\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 button = (text = '', opt: ButtonCompOpt = {}): ButtonComp => {\n return createButtonComponent(k, currentTheme, text, opt);\n };\n\n const addButton = (\n text = '',\n opt: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n } = {},\n ): GameObj => {\n return createButtonObject(k, currentTheme, text, opt);\n };\n\n return {\n button,\n addButton,\n setTheme,\n getTheme,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Color as Color$1, Comp, GameObj, KAPLAYCtx, Rect, Vec2 } from "kaplay";
|
|
2
|
+
/** Color value accepted by the UI theme and components. */
|
|
3
|
+
type Color = Color$1 | string;
|
|
4
|
+
/** Recursively partial version of a type. */
|
|
5
|
+
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; };
|
|
6
|
+
interface Theme {
|
|
7
|
+
palette: {
|
|
8
|
+
primary: Color;
|
|
9
|
+
secondary: Color;
|
|
10
|
+
background: Color;
|
|
11
|
+
surface: Color;
|
|
12
|
+
text: Color;
|
|
13
|
+
textSecondary: Color;
|
|
14
|
+
hover: Color;
|
|
15
|
+
pressed: Color;
|
|
16
|
+
disabled: Color;
|
|
17
|
+
error: Color;
|
|
18
|
+
};
|
|
19
|
+
typography: {
|
|
20
|
+
fontFamily: string;
|
|
21
|
+
fontSize: number;
|
|
22
|
+
fontWeight: number | string;
|
|
23
|
+
lineHeight: number;
|
|
24
|
+
};
|
|
25
|
+
shape: {
|
|
26
|
+
borderRadius: number;
|
|
27
|
+
};
|
|
28
|
+
spacing: number;
|
|
29
|
+
components: {
|
|
30
|
+
button: {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
minWidth: number;
|
|
34
|
+
paddingX: number;
|
|
35
|
+
paddingY: number;
|
|
36
|
+
textTransform: 'none' | 'uppercase' | 'lowercase' | 'capitalize';
|
|
37
|
+
};
|
|
38
|
+
modal: {
|
|
39
|
+
backdropOpacity: number;
|
|
40
|
+
borderRadius: number;
|
|
41
|
+
};
|
|
42
|
+
tooltip: {
|
|
43
|
+
background: Color;
|
|
44
|
+
textColor: Color;
|
|
45
|
+
delay: number;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Options for a single button. */
|
|
50
|
+
interface ButtonCompOpt {
|
|
51
|
+
width?: number;
|
|
52
|
+
height?: number;
|
|
53
|
+
size?: number;
|
|
54
|
+
font?: string;
|
|
55
|
+
fill?: Color;
|
|
56
|
+
textColor?: Color;
|
|
57
|
+
radius?: number;
|
|
58
|
+
hoverFill?: Color;
|
|
59
|
+
pressedFill?: Color;
|
|
60
|
+
}
|
|
61
|
+
/** The `button` component. */
|
|
62
|
+
interface ButtonComp extends Comp {
|
|
63
|
+
id: 'button';
|
|
64
|
+
text: string;
|
|
65
|
+
width: number;
|
|
66
|
+
height: number;
|
|
67
|
+
renderArea(): Rect;
|
|
68
|
+
setStyle(opt: Partial<ButtonCompOpt>): void;
|
|
69
|
+
}
|
|
70
|
+
export declare function createButtonComponent(k: KAPLAYCtx, theme: Theme, text: string, opt: ButtonCompOpt): ButtonComp;
|
|
71
|
+
export declare function createButtonObject(k: KAPLAYCtx, theme: Theme, text: string, opt: ButtonCompOpt & {
|
|
72
|
+
pos?: Vec2;
|
|
73
|
+
onClick?: () => void;
|
|
74
|
+
color?: Color;
|
|
75
|
+
hoverColor?: Color;
|
|
76
|
+
pressedColor?: Color;
|
|
77
|
+
textColor?: Color;
|
|
78
|
+
}): GameObj;
|
|
79
|
+
declare module 'kaplay' {
|
|
80
|
+
interface KAPLAYCtx {
|
|
81
|
+
button: (text?: string, opt?: ButtonCompOpt) => ButtonComp;
|
|
82
|
+
addButton: (text?: string, opt?: ButtonCompOpt & {
|
|
83
|
+
pos?: Vec2;
|
|
84
|
+
onClick?: () => void;
|
|
85
|
+
color?: Color;
|
|
86
|
+
hoverColor?: Color;
|
|
87
|
+
pressedColor?: Color;
|
|
88
|
+
textColor?: Color;
|
|
89
|
+
}) => GameObj;
|
|
90
|
+
setTheme: (theme: DeepPartial<Theme>) => void;
|
|
91
|
+
getTheme: () => Theme;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** KAPLAY UI plugin. */
|
|
95
|
+
export declare function uiPlugin(k: KAPLAYCtx, theme?: DeepPartial<Theme>): {
|
|
96
|
+
button: (text?: string, opt?: ButtonCompOpt) => ButtonComp;
|
|
97
|
+
addButton: (text?: string, opt?: ButtonCompOpt & {
|
|
98
|
+
pos?: Vec2;
|
|
99
|
+
onClick?: () => void;
|
|
100
|
+
color?: Color;
|
|
101
|
+
hoverColor?: Color;
|
|
102
|
+
pressedColor?: Color;
|
|
103
|
+
textColor?: Color;
|
|
104
|
+
}) => GameObj;
|
|
105
|
+
setTheme: (next: DeepPartial<Theme>) => void;
|
|
106
|
+
getTheme: () => Theme;
|
|
107
|
+
};
|
|
108
|
+
export type { ButtonComp, ButtonCompOpt, Color, Theme };
|
|
109
|
+
//# sourceMappingURL=plugin.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.cts","names":["KaplayColor"],"sources":["../src/types.ts","../src/button.ts","../src/plugin.ts"],"mappings":";;KAGY,QAAQA;;KAGR,YAAY,QACrB,WAAW,KAAK,EAAE,oBAAoB,YAAY,EAAE,MAAM,EAAE;UAG9C;EACf;IACE,SAAS;IACT,WAAW;IACX,YAAY;IACZ,SAAS;IACT,MAAM;IACN,eAAe;IACf,OAAO;IACP,SAAS;IACT,UAAU;IACV,OAAO;;EAET;IACE;IACA;IACA;IACA;;EAEF;IACE;;EAEF;EACA;IACE;MACE;MACA;MACA;MACA;MACA;MACA;;IAEF;MACE;MACA;;IAEF;MACE,YAAY;MACZ,WAAW;MACX;;;;;UAMW;EACf;EACA;EACA;EACA;EACA,OAAO;EACP,YAAY;EACZ;EACA,YAAY;EACZ,cAAc;;;UAIC,mBAAmB;EAClC;EACA;EACA;EACA;EACA,cAAc;EACd,SAAS,KAAK,QAAQ;;wBCtER,sBACd,GAAG,WACH,OAAO,OACP,cACA,KAAK,gBACJ;wBA+Ea,mBACd,GAAG,WACH,OAAO,OACP,cACA,KAAK;EACH,MAAM;EACN;EACA,QAAQ;EACR,aAAa;EACb,eAAe;EACf,YAAY;IAEb;;YCpFS;IACR,SAAS,eAAe,MAAM,kBAAkB;IAChD,YACE,eACA,MAAM;MACJ,MAAM;MACN;MACA,QAAQ;MACR,aAAa;MACb,eAAe;MACf,YAAY;UAEX;IACL,WAAW,OAAO,YAAY;IAC9B,gBAAgB;;;;wBAKJ,SAAS,GAAG,WAAW,QAAO,YAAY;EAWxB,SAAA,eAAA,MAAA,kBAAqB;EAM9C,YAAA,eAAA,MAAA;IACH,MAAM;IACN;IACA,QAAQ;IACR,aAAa;IACb,eAAe;IACf,YAAY;QAEb;EAnBqB,WAAA,MAAA,YAAY;EAFf,gBAAA"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Color as Color$1, Comp, GameObj, KAPLAYCtx, Rect, Vec2 } from "kaplay";
|
|
2
|
+
/** Color value accepted by the UI theme and components. */
|
|
3
|
+
type Color = Color$1 | string;
|
|
4
|
+
/** Recursively partial version of a type. */
|
|
5
|
+
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; };
|
|
6
|
+
interface Theme {
|
|
7
|
+
palette: {
|
|
8
|
+
primary: Color;
|
|
9
|
+
secondary: Color;
|
|
10
|
+
background: Color;
|
|
11
|
+
surface: Color;
|
|
12
|
+
text: Color;
|
|
13
|
+
textSecondary: Color;
|
|
14
|
+
hover: Color;
|
|
15
|
+
pressed: Color;
|
|
16
|
+
disabled: Color;
|
|
17
|
+
error: Color;
|
|
18
|
+
};
|
|
19
|
+
typography: {
|
|
20
|
+
fontFamily: string;
|
|
21
|
+
fontSize: number;
|
|
22
|
+
fontWeight: number | string;
|
|
23
|
+
lineHeight: number;
|
|
24
|
+
};
|
|
25
|
+
shape: {
|
|
26
|
+
borderRadius: number;
|
|
27
|
+
};
|
|
28
|
+
spacing: number;
|
|
29
|
+
components: {
|
|
30
|
+
button: {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
minWidth: number;
|
|
34
|
+
paddingX: number;
|
|
35
|
+
paddingY: number;
|
|
36
|
+
textTransform: 'none' | 'uppercase' | 'lowercase' | 'capitalize';
|
|
37
|
+
};
|
|
38
|
+
modal: {
|
|
39
|
+
backdropOpacity: number;
|
|
40
|
+
borderRadius: number;
|
|
41
|
+
};
|
|
42
|
+
tooltip: {
|
|
43
|
+
background: Color;
|
|
44
|
+
textColor: Color;
|
|
45
|
+
delay: number;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Options for a single button. */
|
|
50
|
+
interface ButtonCompOpt {
|
|
51
|
+
width?: number;
|
|
52
|
+
height?: number;
|
|
53
|
+
size?: number;
|
|
54
|
+
font?: string;
|
|
55
|
+
fill?: Color;
|
|
56
|
+
textColor?: Color;
|
|
57
|
+
radius?: number;
|
|
58
|
+
hoverFill?: Color;
|
|
59
|
+
pressedFill?: Color;
|
|
60
|
+
}
|
|
61
|
+
/** The `button` component. */
|
|
62
|
+
interface ButtonComp extends Comp {
|
|
63
|
+
id: 'button';
|
|
64
|
+
text: string;
|
|
65
|
+
width: number;
|
|
66
|
+
height: number;
|
|
67
|
+
renderArea(): Rect;
|
|
68
|
+
setStyle(opt: Partial<ButtonCompOpt>): void;
|
|
69
|
+
}
|
|
70
|
+
export declare function createButtonComponent(k: KAPLAYCtx, theme: Theme, text: string, opt: ButtonCompOpt): ButtonComp;
|
|
71
|
+
export declare function createButtonObject(k: KAPLAYCtx, theme: Theme, text: string, opt: ButtonCompOpt & {
|
|
72
|
+
pos?: Vec2;
|
|
73
|
+
onClick?: () => void;
|
|
74
|
+
color?: Color;
|
|
75
|
+
hoverColor?: Color;
|
|
76
|
+
pressedColor?: Color;
|
|
77
|
+
textColor?: Color;
|
|
78
|
+
}): GameObj;
|
|
79
|
+
declare module 'kaplay' {
|
|
80
|
+
interface KAPLAYCtx {
|
|
81
|
+
button: (text?: string, opt?: ButtonCompOpt) => ButtonComp;
|
|
82
|
+
addButton: (text?: string, opt?: ButtonCompOpt & {
|
|
83
|
+
pos?: Vec2;
|
|
84
|
+
onClick?: () => void;
|
|
85
|
+
color?: Color;
|
|
86
|
+
hoverColor?: Color;
|
|
87
|
+
pressedColor?: Color;
|
|
88
|
+
textColor?: Color;
|
|
89
|
+
}) => GameObj;
|
|
90
|
+
setTheme: (theme: DeepPartial<Theme>) => void;
|
|
91
|
+
getTheme: () => Theme;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** KAPLAY UI plugin. */
|
|
95
|
+
export declare function uiPlugin(k: KAPLAYCtx, theme?: DeepPartial<Theme>): {
|
|
96
|
+
button: (text?: string, opt?: ButtonCompOpt) => ButtonComp;
|
|
97
|
+
addButton: (text?: string, opt?: ButtonCompOpt & {
|
|
98
|
+
pos?: Vec2;
|
|
99
|
+
onClick?: () => void;
|
|
100
|
+
color?: Color;
|
|
101
|
+
hoverColor?: Color;
|
|
102
|
+
pressedColor?: Color;
|
|
103
|
+
textColor?: Color;
|
|
104
|
+
}) => GameObj;
|
|
105
|
+
setTheme: (next: DeepPartial<Theme>) => void;
|
|
106
|
+
getTheme: () => Theme;
|
|
107
|
+
};
|
|
108
|
+
export type { ButtonComp, ButtonCompOpt, Color, Theme };
|
|
109
|
+
//# sourceMappingURL=plugin.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.mts","names":["KaplayColor"],"sources":["../src/types.ts","../src/button.ts","../src/plugin.ts"],"mappings":";;KAGY,QAAQA;;KAGR,YAAY,QACrB,WAAW,KAAK,EAAE,oBAAoB,YAAY,EAAE,MAAM,EAAE;UAG9C;EACf;IACE,SAAS;IACT,WAAW;IACX,YAAY;IACZ,SAAS;IACT,MAAM;IACN,eAAe;IACf,OAAO;IACP,SAAS;IACT,UAAU;IACV,OAAO;;EAET;IACE;IACA;IACA;IACA;;EAEF;IACE;;EAEF;EACA;IACE;MACE;MACA;MACA;MACA;MACA;MACA;;IAEF;MACE;MACA;;IAEF;MACE,YAAY;MACZ,WAAW;MACX;;;;;UAMW;EACf;EACA;EACA;EACA;EACA,OAAO;EACP,YAAY;EACZ;EACA,YAAY;EACZ,cAAc;;;UAIC,mBAAmB;EAClC;EACA;EACA;EACA;EACA,cAAc;EACd,SAAS,KAAK,QAAQ;;wBCtER,sBACd,GAAG,WACH,OAAO,OACP,cACA,KAAK,gBACJ;wBA+Ea,mBACd,GAAG,WACH,OAAO,OACP,cACA,KAAK;EACH,MAAM;EACN;EACA,QAAQ;EACR,aAAa;EACb,eAAe;EACf,YAAY;IAEb;;YCpFS;IACR,SAAS,eAAe,MAAM,kBAAkB;IAChD,YACE,eACA,MAAM;MACJ,MAAM;MACN;MACA,QAAQ;MACR,aAAa;MACb,eAAe;MACf,YAAY;UAEX;IACL,WAAW,OAAO,YAAY;IAC9B,gBAAgB;;;;wBAKJ,SAAS,GAAG,WAAW,QAAO,YAAY;EAWxB,SAAA,eAAA,MAAA,kBAAqB;EAM9C,YAAA,eAAA,MAAA;IACH,MAAM;IACN;IACA,QAAQ;IACR,aAAa;IACb,eAAe;IACf,YAAY;QAEb;EAnBqB,WAAA,MAAA,YAAY;EAFf,gBAAA"}
|
package/dist/plugin.mjs
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// src/button.ts
|
|
2
|
+
function createButtonComponent(k, theme, text, opt) {
|
|
3
|
+
let currentText = text;
|
|
4
|
+
let currentOpt = { ...opt };
|
|
5
|
+
const readWidth = () => {
|
|
6
|
+
return currentOpt.width ?? theme.components.button.width;
|
|
7
|
+
};
|
|
8
|
+
const readHeight = () => {
|
|
9
|
+
return currentOpt.height ?? theme.components.button.height;
|
|
10
|
+
};
|
|
11
|
+
const comp = {
|
|
12
|
+
id: "button",
|
|
13
|
+
get text() {
|
|
14
|
+
return currentText;
|
|
15
|
+
},
|
|
16
|
+
set text(value) {
|
|
17
|
+
currentText = value;
|
|
18
|
+
},
|
|
19
|
+
get width() {
|
|
20
|
+
return readWidth();
|
|
21
|
+
},
|
|
22
|
+
set width(value) {
|
|
23
|
+
currentOpt.width = value;
|
|
24
|
+
},
|
|
25
|
+
get height() {
|
|
26
|
+
return readHeight();
|
|
27
|
+
},
|
|
28
|
+
set height(value) {
|
|
29
|
+
currentOpt.height = value;
|
|
30
|
+
},
|
|
31
|
+
renderArea() {
|
|
32
|
+
return new k.Rect(k.vec2(), comp.width, comp.height);
|
|
33
|
+
},
|
|
34
|
+
setStyle(next) {
|
|
35
|
+
currentOpt = {
|
|
36
|
+
...currentOpt,
|
|
37
|
+
...next
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
add() {},
|
|
41
|
+
draw() {
|
|
42
|
+
const width = comp.width;
|
|
43
|
+
const height = comp.height;
|
|
44
|
+
const radius = currentOpt.radius ?? theme.shape.borderRadius;
|
|
45
|
+
const fill = currentOpt.fill ?? theme.palette.primary;
|
|
46
|
+
const textColor = currentOpt.textColor ?? theme.palette.text;
|
|
47
|
+
const size = currentOpt.size ?? theme.typography.fontSize;
|
|
48
|
+
const font = currentOpt.font ?? theme.typography.fontFamily;
|
|
49
|
+
const drawRect = k.drawRect;
|
|
50
|
+
drawRect?.({
|
|
51
|
+
pos: k.vec2(),
|
|
52
|
+
width,
|
|
53
|
+
height,
|
|
54
|
+
color: fill,
|
|
55
|
+
radius
|
|
56
|
+
});
|
|
57
|
+
const drawText = k.drawText;
|
|
58
|
+
drawText?.({
|
|
59
|
+
text: currentText,
|
|
60
|
+
pos: k.vec2(width / 2, height / 2),
|
|
61
|
+
size,
|
|
62
|
+
font,
|
|
63
|
+
color: textColor,
|
|
64
|
+
anchor: "center"
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
destroy() {}
|
|
68
|
+
};
|
|
69
|
+
return comp;
|
|
70
|
+
}
|
|
71
|
+
function createButtonObject(k, theme, text, opt) {
|
|
72
|
+
const width = opt.width ?? theme.components.button.width;
|
|
73
|
+
const height = opt.height ?? theme.components.button.height;
|
|
74
|
+
const radius = opt.radius ?? theme.shape.borderRadius;
|
|
75
|
+
const baseColor = opt.color ?? opt.fill ?? theme.palette.primary;
|
|
76
|
+
const hoverColor = opt.hoverColor ?? theme.palette.hover;
|
|
77
|
+
const pressedColor = opt.pressedColor ?? theme.palette.pressed;
|
|
78
|
+
const textColor = opt.textColor ?? theme.palette.text;
|
|
79
|
+
const size = opt.size ?? theme.typography.fontSize;
|
|
80
|
+
const font = opt.font ?? theme.typography.fontFamily;
|
|
81
|
+
const pos = opt.pos ?? k.vec2();
|
|
82
|
+
const obj = k.add([
|
|
83
|
+
k.rect(width, height, radius > 0 ? { radius } : void 0),
|
|
84
|
+
k.pos(pos),
|
|
85
|
+
k.area(),
|
|
86
|
+
k.color(baseColor),
|
|
87
|
+
k.anchor("center")
|
|
88
|
+
]);
|
|
89
|
+
const label = obj.add([
|
|
90
|
+
k.text(text, {
|
|
91
|
+
size,
|
|
92
|
+
font
|
|
93
|
+
}),
|
|
94
|
+
k.color(textColor),
|
|
95
|
+
k.anchor("center")
|
|
96
|
+
]);
|
|
97
|
+
let currentText = text;
|
|
98
|
+
let currentColor = baseColor;
|
|
99
|
+
obj.onClick(() => {
|
|
100
|
+
obj.color = pressedColor;
|
|
101
|
+
opt.onClick?.();
|
|
102
|
+
});
|
|
103
|
+
obj.onHover(() => {
|
|
104
|
+
obj.color = hoverColor;
|
|
105
|
+
obj.scale = k.vec2(1.05, 1.05);
|
|
106
|
+
k.setCursor("pointer");
|
|
107
|
+
});
|
|
108
|
+
obj.onHoverEnd(() => {
|
|
109
|
+
obj.color = currentColor;
|
|
110
|
+
obj.scale = k.vec2(1, 1);
|
|
111
|
+
k.setCursor("default");
|
|
112
|
+
});
|
|
113
|
+
obj.setSize = (w, h) => {
|
|
114
|
+
obj.width = w;
|
|
115
|
+
obj.height = h;
|
|
116
|
+
};
|
|
117
|
+
obj.setButtonColor = (color) => {
|
|
118
|
+
currentColor = color;
|
|
119
|
+
obj.color = color;
|
|
120
|
+
};
|
|
121
|
+
obj.setButtonText = (value) => {
|
|
122
|
+
currentText = value;
|
|
123
|
+
label.text = value;
|
|
124
|
+
};
|
|
125
|
+
obj.setButtonTextSize = (value) => {
|
|
126
|
+
label.textSize = value;
|
|
127
|
+
};
|
|
128
|
+
obj.setPosition = (x, y) => {
|
|
129
|
+
obj.pos = k.vec2(x, y);
|
|
130
|
+
};
|
|
131
|
+
label.text = currentText;
|
|
132
|
+
return obj;
|
|
133
|
+
}
|
|
134
|
+
// src/theme.ts
|
|
135
|
+
const DEFAULT_PRIMARY = "#4f8cff";
|
|
136
|
+
const DEFAULT_TEXT = "#ffffff";
|
|
137
|
+
/** Default theme used when no theme is provided. */
|
|
138
|
+
const defaultTheme = {
|
|
139
|
+
palette: {
|
|
140
|
+
primary: DEFAULT_PRIMARY,
|
|
141
|
+
secondary: DEFAULT_PRIMARY,
|
|
142
|
+
background: "#111827",
|
|
143
|
+
surface: "#1f2937",
|
|
144
|
+
text: DEFAULT_TEXT,
|
|
145
|
+
textSecondary: DEFAULT_TEXT,
|
|
146
|
+
hover: DEFAULT_PRIMARY,
|
|
147
|
+
pressed: DEFAULT_PRIMARY,
|
|
148
|
+
disabled: "#6b7280",
|
|
149
|
+
error: "#ef4444"
|
|
150
|
+
},
|
|
151
|
+
typography: {
|
|
152
|
+
fontFamily: "sans-serif",
|
|
153
|
+
fontSize: 18,
|
|
154
|
+
fontWeight: 400,
|
|
155
|
+
lineHeight: 1.2
|
|
156
|
+
},
|
|
157
|
+
shape: { borderRadius: 0 },
|
|
158
|
+
spacing: 8,
|
|
159
|
+
components: {
|
|
160
|
+
button: {
|
|
161
|
+
width: 120,
|
|
162
|
+
height: 40,
|
|
163
|
+
minWidth: 120,
|
|
164
|
+
paddingX: 12,
|
|
165
|
+
paddingY: 8,
|
|
166
|
+
textTransform: "none"
|
|
167
|
+
},
|
|
168
|
+
modal: {
|
|
169
|
+
backdropOpacity: .5,
|
|
170
|
+
borderRadius: 8
|
|
171
|
+
},
|
|
172
|
+
tooltip: {
|
|
173
|
+
background: "#111827",
|
|
174
|
+
textColor: DEFAULT_TEXT,
|
|
175
|
+
delay: 300
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
/** Resolve a partial theme into a fully resolved theme. */
|
|
180
|
+
function resolveTheme(input) {
|
|
181
|
+
return {
|
|
182
|
+
palette: {
|
|
183
|
+
...defaultTheme.palette,
|
|
184
|
+
...input?.palette
|
|
185
|
+
},
|
|
186
|
+
typography: {
|
|
187
|
+
...defaultTheme.typography,
|
|
188
|
+
...input?.typography
|
|
189
|
+
},
|
|
190
|
+
shape: {
|
|
191
|
+
...defaultTheme.shape,
|
|
192
|
+
...input?.shape
|
|
193
|
+
},
|
|
194
|
+
spacing: input?.spacing ?? defaultTheme.spacing,
|
|
195
|
+
components: {
|
|
196
|
+
button: {
|
|
197
|
+
...defaultTheme.components.button,
|
|
198
|
+
...input?.components?.button,
|
|
199
|
+
width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? defaultTheme.components.button.width
|
|
200
|
+
},
|
|
201
|
+
modal: {
|
|
202
|
+
...defaultTheme.components.modal,
|
|
203
|
+
...input?.components?.modal
|
|
204
|
+
},
|
|
205
|
+
tooltip: {
|
|
206
|
+
...defaultTheme.components.tooltip,
|
|
207
|
+
...input?.components?.tooltip
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
// src/plugin.ts
|
|
213
|
+
/** KAPLAY UI plugin. */
|
|
214
|
+
function uiPlugin(k, theme = {}) {
|
|
215
|
+
let userTheme = theme;
|
|
216
|
+
let currentTheme = resolveTheme(userTheme);
|
|
217
|
+
const getTheme = () => currentTheme;
|
|
218
|
+
const setTheme = (next) => {
|
|
219
|
+
userTheme = {
|
|
220
|
+
...userTheme,
|
|
221
|
+
...next
|
|
222
|
+
};
|
|
223
|
+
currentTheme = resolveTheme(userTheme);
|
|
224
|
+
};
|
|
225
|
+
const button = (text = "", opt = {}) => {
|
|
226
|
+
return createButtonComponent(k, currentTheme, text, opt);
|
|
227
|
+
};
|
|
228
|
+
const addButton = (text = "", opt = {}) => {
|
|
229
|
+
return createButtonObject(k, currentTheme, text, opt);
|
|
230
|
+
};
|
|
231
|
+
return {
|
|
232
|
+
button,
|
|
233
|
+
addButton,
|
|
234
|
+
setTheme,
|
|
235
|
+
getTheme
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
export { createButtonComponent, createButtonObject, uiPlugin };
|
|
239
|
+
|
|
240
|
+
//# sourceMappingURL=plugin.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":[],"sources":["../src/button.ts","../src/theme.ts","../src/plugin.ts"],"sourcesContent":["import type { Comp, GameObj, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport type { ButtonComp, ButtonCompOpt, Color, Theme } from './types';\n\nexport function createButtonComponent(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonCompOpt,\n): ButtonComp {\n let currentText = text;\n let currentOpt: ButtonCompOpt = { ...opt };\n\n const readWidth = (): number => {\n return currentOpt.width ?? theme.components.button.width;\n };\n\n const readHeight = (): number => {\n return currentOpt.height ?? theme.components.button.height;\n };\n\n const comp: ButtonComp = {\n id: 'button',\n get text() {\n return currentText;\n },\n set text(value: string) {\n currentText = value;\n },\n get width() {\n return readWidth();\n },\n set width(value: number) {\n currentOpt.width = value;\n },\n get height() {\n return readHeight();\n },\n set height(value: number) {\n currentOpt.height = value;\n },\n renderArea() {\n return new k.Rect(k.vec2(), comp.width, comp.height);\n },\n setStyle(next: Partial<ButtonCompOpt>): void {\n currentOpt = { ...currentOpt, ...next };\n },\n add(): void {\n // No-op: rendering is handled in draw().\n },\n draw(): void {\n const width = comp.width;\n const height = comp.height;\n const radius = currentOpt.radius ?? theme.shape.borderRadius;\n const fill = currentOpt.fill ?? theme.palette.primary;\n const textColor = currentOpt.textColor ?? theme.palette.text;\n const size = currentOpt.size ?? theme.typography.fontSize;\n const font = currentOpt.font ?? theme.typography.fontFamily;\n\n const drawRect = k.drawRect as unknown as\n ((opt: Record<string, unknown>) => void) | undefined;\n drawRect?.({\n pos: k.vec2(),\n width,\n height,\n color: fill,\n radius,\n });\n\n const drawText = k.drawText as unknown as\n ((opt: Record<string, unknown>) => void) | undefined;\n drawText?.({\n text: currentText,\n pos: k.vec2(width / 2, height / 2),\n size,\n font,\n color: textColor,\n anchor: 'center',\n });\n },\n destroy(): void {\n // No resources to release.\n },\n };\n\n return comp;\n}\n\nexport function createButtonObject(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n },\n): GameObj {\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 = opt.color ?? opt.fill ?? theme.palette.primary;\n const hoverColor = opt.hoverColor ?? theme.palette.hover;\n const pressedColor = opt.pressedColor ?? theme.palette.pressed;\n const textColor = 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 interface ButtonGameObj {\n add: (comps: Comp[]) => { text: string; textSize: number };\n onClick: (cb: () => void) => void;\n onHover: (cb: () => void) => void;\n onHoverEnd: (cb: () => void) => void;\n width: number;\n height: number;\n color: unknown;\n scale: { x: number; y: number };\n pos: { x: number; y: number };\n setSize: (w: number, h: number) => void;\n setButtonColor: (color: Color) => void;\n setButtonText: (value: string) => void;\n setButtonTextSize: (value: number) => void;\n setPosition: (x: number, y: number) => void;\n }\n\n const obj = k.add([\n k.rect(width, height, radius > 0 ? { radius } : undefined),\n k.pos(pos as never),\n k.area(),\n k.color(baseColor as never),\n k.anchor('center'),\n ]) as unknown as ButtonGameObj;\n\n const label = obj.add([\n k.text(text, { size, font }),\n k.color(textColor as never),\n k.anchor('center'),\n ]) as GameObj & { text: string; textSize: number };\n\n let currentText = text;\n let currentColor: Color = baseColor;\n\n obj.onClick(() => {\n obj.color = pressedColor;\n opt.onClick?.();\n });\n obj.onHover(() => {\n obj.color = hoverColor;\n obj.scale = k.vec2(1.05, 1.05);\n k.setCursor('pointer');\n });\n obj.onHoverEnd(() => {\n obj.color = currentColor;\n obj.scale = k.vec2(1, 1);\n k.setCursor('default');\n });\n\n obj.setSize = (w: number, h: number): void => {\n obj.width = w;\n obj.height = h;\n };\n\n obj.setButtonColor = (color: Color): void => {\n currentColor = color;\n obj.color = color;\n };\n\n obj.setButtonText = (value: string): void => {\n currentText = value;\n label.text = value;\n };\n\n obj.setButtonTextSize = (value: number): void => {\n label.textSize = value;\n };\n\n obj.setPosition = (x: number, y: number): void => {\n obj.pos = k.vec2(x, y);\n };\n\n label.text = currentText;\n\n return obj as unknown as GameObj;\n}\n","import type { DeepPartial, Theme } from './types';\n\nconst DEFAULT_PRIMARY = '#4f8cff';\nconst DEFAULT_TEXT = '#ffffff';\n\n/** Default theme used when no theme is provided. */\nexport const defaultTheme: Theme = {\n palette: {\n primary: DEFAULT_PRIMARY,\n secondary: DEFAULT_PRIMARY,\n background: '#111827',\n surface: '#1f2937',\n text: DEFAULT_TEXT,\n textSecondary: DEFAULT_TEXT,\n hover: DEFAULT_PRIMARY,\n pressed: DEFAULT_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: DEFAULT_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: { ...defaultTheme.palette, ...input?.palette },\n typography: { ...defaultTheme.typography, ...input?.typography },\n shape: { ...defaultTheme.shape, ...input?.shape },\n spacing: input?.spacing ?? defaultTheme.spacing,\n components: {\n button: {\n ...defaultTheme.components.button,\n ...input?.components?.button,\n width:\n input?.components?.button?.width ??\n input?.components?.button?.minWidth ??\n defaultTheme.components.button.width,\n },\n modal: {\n ...defaultTheme.components.modal,\n ...input?.components?.modal,\n },\n tooltip: {\n ...defaultTheme.components.tooltip,\n ...input?.components?.tooltip,\n },\n },\n };\n}\n","import type { GameObj, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport { createButtonComponent, createButtonObject } from './button';\nimport { resolveTheme } from './theme';\nimport type {\n ButtonComp,\n ButtonCompOpt,\n Color,\n DeepPartial,\n Theme,\n} from './types';\n\nexport { createButtonComponent, createButtonObject } from './button';\nexport type { ButtonComp, ButtonCompOpt, Color, Theme } from './types';\n\ndeclare module 'kaplay' {\n interface KAPLAYCtx {\n button: (text?: string, opt?: ButtonCompOpt) => ButtonComp;\n addButton: (\n text?: string,\n opt?: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n },\n ) => GameObj;\n setTheme: (theme: DeepPartial<Theme>) => void;\n getTheme: () => Theme;\n }\n}\n\n/** KAPLAY UI plugin. */\nexport function uiPlugin(k: KAPLAYCtx, theme: DeepPartial<Theme> = {}) {\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 button = (text = '', opt: ButtonCompOpt = {}): ButtonComp => {\n return createButtonComponent(k, currentTheme, text, opt);\n };\n\n const addButton = (\n text = '',\n opt: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n } = {},\n ): GameObj => {\n return createButtonObject(k, currentTheme, text, opt);\n };\n\n return {\n button,\n addButton,\n setTheme,\n getTheme,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,247 @@
|
|
|
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/button.ts
|
|
6
|
+
function createButtonComponent(k, theme, text, opt) {
|
|
7
|
+
let currentText = text;
|
|
8
|
+
let currentOpt = { ...opt };
|
|
9
|
+
const readWidth = () => {
|
|
10
|
+
return currentOpt.width ?? theme.components.button.width;
|
|
11
|
+
};
|
|
12
|
+
const readHeight = () => {
|
|
13
|
+
return currentOpt.height ?? theme.components.button.height;
|
|
14
|
+
};
|
|
15
|
+
const comp = {
|
|
16
|
+
id: "button",
|
|
17
|
+
get text() {
|
|
18
|
+
return currentText;
|
|
19
|
+
},
|
|
20
|
+
set text(value) {
|
|
21
|
+
currentText = value;
|
|
22
|
+
},
|
|
23
|
+
get width() {
|
|
24
|
+
return readWidth();
|
|
25
|
+
},
|
|
26
|
+
set width(value) {
|
|
27
|
+
currentOpt.width = value;
|
|
28
|
+
},
|
|
29
|
+
get height() {
|
|
30
|
+
return readHeight();
|
|
31
|
+
},
|
|
32
|
+
set height(value) {
|
|
33
|
+
currentOpt.height = value;
|
|
34
|
+
},
|
|
35
|
+
renderArea() {
|
|
36
|
+
return new k.Rect(k.vec2(), comp.width, comp.height);
|
|
37
|
+
},
|
|
38
|
+
setStyle(next) {
|
|
39
|
+
currentOpt = {
|
|
40
|
+
...currentOpt,
|
|
41
|
+
...next
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
add() {},
|
|
45
|
+
draw() {
|
|
46
|
+
const width = comp.width;
|
|
47
|
+
const height = comp.height;
|
|
48
|
+
const radius = currentOpt.radius ?? theme.shape.borderRadius;
|
|
49
|
+
const fill = currentOpt.fill ?? theme.palette.primary;
|
|
50
|
+
const textColor = currentOpt.textColor ?? theme.palette.text;
|
|
51
|
+
const size = currentOpt.size ?? theme.typography.fontSize;
|
|
52
|
+
const font = currentOpt.font ?? theme.typography.fontFamily;
|
|
53
|
+
const drawRect = k.drawRect;
|
|
54
|
+
drawRect?.({
|
|
55
|
+
pos: k.vec2(),
|
|
56
|
+
width,
|
|
57
|
+
height,
|
|
58
|
+
color: fill,
|
|
59
|
+
radius
|
|
60
|
+
});
|
|
61
|
+
const drawText = k.drawText;
|
|
62
|
+
drawText?.({
|
|
63
|
+
text: currentText,
|
|
64
|
+
pos: k.vec2(width / 2, height / 2),
|
|
65
|
+
size,
|
|
66
|
+
font,
|
|
67
|
+
color: textColor,
|
|
68
|
+
anchor: "center"
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
destroy() {}
|
|
72
|
+
};
|
|
73
|
+
return comp;
|
|
74
|
+
}
|
|
75
|
+
function createButtonObject(k, theme, text, opt) {
|
|
76
|
+
const width = opt.width ?? theme.components.button.width;
|
|
77
|
+
const height = opt.height ?? theme.components.button.height;
|
|
78
|
+
const radius = opt.radius ?? theme.shape.borderRadius;
|
|
79
|
+
const baseColor = opt.color ?? opt.fill ?? theme.palette.primary;
|
|
80
|
+
const hoverColor = opt.hoverColor ?? theme.palette.hover;
|
|
81
|
+
const pressedColor = opt.pressedColor ?? theme.palette.pressed;
|
|
82
|
+
const textColor = opt.textColor ?? theme.palette.text;
|
|
83
|
+
const size = opt.size ?? theme.typography.fontSize;
|
|
84
|
+
const font = opt.font ?? theme.typography.fontFamily;
|
|
85
|
+
const pos = opt.pos ?? k.vec2();
|
|
86
|
+
const obj = k.add([
|
|
87
|
+
k.rect(width, height, radius > 0 ? { radius } : void 0),
|
|
88
|
+
k.pos(pos),
|
|
89
|
+
k.area(),
|
|
90
|
+
k.color(baseColor),
|
|
91
|
+
k.anchor("center")
|
|
92
|
+
]);
|
|
93
|
+
const label = obj.add([
|
|
94
|
+
k.text(text, {
|
|
95
|
+
size,
|
|
96
|
+
font
|
|
97
|
+
}),
|
|
98
|
+
k.color(textColor),
|
|
99
|
+
k.anchor("center")
|
|
100
|
+
]);
|
|
101
|
+
let currentText = text;
|
|
102
|
+
let currentColor = baseColor;
|
|
103
|
+
obj.onClick(() => {
|
|
104
|
+
obj.color = pressedColor;
|
|
105
|
+
opt.onClick?.();
|
|
106
|
+
});
|
|
107
|
+
obj.onHover(() => {
|
|
108
|
+
obj.color = hoverColor;
|
|
109
|
+
obj.scale = k.vec2(1.05, 1.05);
|
|
110
|
+
k.setCursor("pointer");
|
|
111
|
+
});
|
|
112
|
+
obj.onHoverEnd(() => {
|
|
113
|
+
obj.color = currentColor;
|
|
114
|
+
obj.scale = k.vec2(1, 1);
|
|
115
|
+
k.setCursor("default");
|
|
116
|
+
});
|
|
117
|
+
obj.setSize = (w, h) => {
|
|
118
|
+
obj.width = w;
|
|
119
|
+
obj.height = h;
|
|
120
|
+
};
|
|
121
|
+
obj.setButtonColor = (color) => {
|
|
122
|
+
currentColor = color;
|
|
123
|
+
obj.color = color;
|
|
124
|
+
};
|
|
125
|
+
obj.setButtonText = (value) => {
|
|
126
|
+
currentText = value;
|
|
127
|
+
label.text = value;
|
|
128
|
+
};
|
|
129
|
+
obj.setButtonTextSize = (value) => {
|
|
130
|
+
label.textSize = value;
|
|
131
|
+
};
|
|
132
|
+
obj.setPosition = (x, y) => {
|
|
133
|
+
obj.pos = k.vec2(x, y);
|
|
134
|
+
};
|
|
135
|
+
label.text = currentText;
|
|
136
|
+
return obj;
|
|
137
|
+
}
|
|
138
|
+
// src/theme.ts
|
|
139
|
+
const DEFAULT_PRIMARY = "#4f8cff";
|
|
140
|
+
const DEFAULT_TEXT = "#ffffff";
|
|
141
|
+
/** Default theme used when no theme is provided. */
|
|
142
|
+
const defaultTheme = {
|
|
143
|
+
palette: {
|
|
144
|
+
primary: DEFAULT_PRIMARY,
|
|
145
|
+
secondary: DEFAULT_PRIMARY,
|
|
146
|
+
background: "#111827",
|
|
147
|
+
surface: "#1f2937",
|
|
148
|
+
text: DEFAULT_TEXT,
|
|
149
|
+
textSecondary: DEFAULT_TEXT,
|
|
150
|
+
hover: DEFAULT_PRIMARY,
|
|
151
|
+
pressed: DEFAULT_PRIMARY,
|
|
152
|
+
disabled: "#6b7280",
|
|
153
|
+
error: "#ef4444"
|
|
154
|
+
},
|
|
155
|
+
typography: {
|
|
156
|
+
fontFamily: "sans-serif",
|
|
157
|
+
fontSize: 18,
|
|
158
|
+
fontWeight: 400,
|
|
159
|
+
lineHeight: 1.2
|
|
160
|
+
},
|
|
161
|
+
shape: { borderRadius: 0 },
|
|
162
|
+
spacing: 8,
|
|
163
|
+
components: {
|
|
164
|
+
button: {
|
|
165
|
+
width: 120,
|
|
166
|
+
height: 40,
|
|
167
|
+
minWidth: 120,
|
|
168
|
+
paddingX: 12,
|
|
169
|
+
paddingY: 8,
|
|
170
|
+
textTransform: "none"
|
|
171
|
+
},
|
|
172
|
+
modal: {
|
|
173
|
+
backdropOpacity: .5,
|
|
174
|
+
borderRadius: 8
|
|
175
|
+
},
|
|
176
|
+
tooltip: {
|
|
177
|
+
background: "#111827",
|
|
178
|
+
textColor: DEFAULT_TEXT,
|
|
179
|
+
delay: 300
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
/** Resolve a partial theme into a fully resolved theme. */
|
|
184
|
+
function resolveTheme(input) {
|
|
185
|
+
return {
|
|
186
|
+
palette: {
|
|
187
|
+
...defaultTheme.palette,
|
|
188
|
+
...input?.palette
|
|
189
|
+
},
|
|
190
|
+
typography: {
|
|
191
|
+
...defaultTheme.typography,
|
|
192
|
+
...input?.typography
|
|
193
|
+
},
|
|
194
|
+
shape: {
|
|
195
|
+
...defaultTheme.shape,
|
|
196
|
+
...input?.shape
|
|
197
|
+
},
|
|
198
|
+
spacing: input?.spacing ?? defaultTheme.spacing,
|
|
199
|
+
components: {
|
|
200
|
+
button: {
|
|
201
|
+
...defaultTheme.components.button,
|
|
202
|
+
...input?.components?.button,
|
|
203
|
+
width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? defaultTheme.components.button.width
|
|
204
|
+
},
|
|
205
|
+
modal: {
|
|
206
|
+
...defaultTheme.components.modal,
|
|
207
|
+
...input?.components?.modal
|
|
208
|
+
},
|
|
209
|
+
tooltip: {
|
|
210
|
+
...defaultTheme.components.tooltip,
|
|
211
|
+
...input?.components?.tooltip
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
// src/plugin.ts
|
|
217
|
+
/** KAPLAY UI plugin. */
|
|
218
|
+
function uiPlugin(k, theme = {}) {
|
|
219
|
+
let userTheme = theme;
|
|
220
|
+
let currentTheme = resolveTheme(userTheme);
|
|
221
|
+
const getTheme = () => currentTheme;
|
|
222
|
+
const setTheme = (next) => {
|
|
223
|
+
userTheme = {
|
|
224
|
+
...userTheme,
|
|
225
|
+
...next
|
|
226
|
+
};
|
|
227
|
+
currentTheme = resolveTheme(userTheme);
|
|
228
|
+
};
|
|
229
|
+
const button = (text = "", opt = {}) => {
|
|
230
|
+
return createButtonComponent(k, currentTheme, text, opt);
|
|
231
|
+
};
|
|
232
|
+
const addButton = (text = "", opt = {}) => {
|
|
233
|
+
return createButtonObject(k, currentTheme, text, opt);
|
|
234
|
+
};
|
|
235
|
+
return {
|
|
236
|
+
button,
|
|
237
|
+
addButton,
|
|
238
|
+
setTheme,
|
|
239
|
+
getTheme
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
exports.createButtonComponent = createButtonComponent;
|
|
243
|
+
exports.createButtonObject = createButtonObject;
|
|
244
|
+
exports.uiPlugin = uiPlugin;
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
//# sourceMappingURL=plugin.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.umd.js","names":[],"sources":["../src/button.ts","../src/theme.ts","../src/plugin.ts"],"sourcesContent":["import type { Comp, GameObj, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport type { ButtonComp, ButtonCompOpt, Color, Theme } from './types';\n\nexport function createButtonComponent(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonCompOpt,\n): ButtonComp {\n let currentText = text;\n let currentOpt: ButtonCompOpt = { ...opt };\n\n const readWidth = (): number => {\n return currentOpt.width ?? theme.components.button.width;\n };\n\n const readHeight = (): number => {\n return currentOpt.height ?? theme.components.button.height;\n };\n\n const comp: ButtonComp = {\n id: 'button',\n get text() {\n return currentText;\n },\n set text(value: string) {\n currentText = value;\n },\n get width() {\n return readWidth();\n },\n set width(value: number) {\n currentOpt.width = value;\n },\n get height() {\n return readHeight();\n },\n set height(value: number) {\n currentOpt.height = value;\n },\n renderArea() {\n return new k.Rect(k.vec2(), comp.width, comp.height);\n },\n setStyle(next: Partial<ButtonCompOpt>): void {\n currentOpt = { ...currentOpt, ...next };\n },\n add(): void {\n // No-op: rendering is handled in draw().\n },\n draw(): void {\n const width = comp.width;\n const height = comp.height;\n const radius = currentOpt.radius ?? theme.shape.borderRadius;\n const fill = currentOpt.fill ?? theme.palette.primary;\n const textColor = currentOpt.textColor ?? theme.palette.text;\n const size = currentOpt.size ?? theme.typography.fontSize;\n const font = currentOpt.font ?? theme.typography.fontFamily;\n\n const drawRect = k.drawRect as unknown as\n ((opt: Record<string, unknown>) => void) | undefined;\n drawRect?.({\n pos: k.vec2(),\n width,\n height,\n color: fill,\n radius,\n });\n\n const drawText = k.drawText as unknown as\n ((opt: Record<string, unknown>) => void) | undefined;\n drawText?.({\n text: currentText,\n pos: k.vec2(width / 2, height / 2),\n size,\n font,\n color: textColor,\n anchor: 'center',\n });\n },\n destroy(): void {\n // No resources to release.\n },\n };\n\n return comp;\n}\n\nexport function createButtonObject(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n },\n): GameObj {\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 = opt.color ?? opt.fill ?? theme.palette.primary;\n const hoverColor = opt.hoverColor ?? theme.palette.hover;\n const pressedColor = opt.pressedColor ?? theme.palette.pressed;\n const textColor = 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 interface ButtonGameObj {\n add: (comps: Comp[]) => { text: string; textSize: number };\n onClick: (cb: () => void) => void;\n onHover: (cb: () => void) => void;\n onHoverEnd: (cb: () => void) => void;\n width: number;\n height: number;\n color: unknown;\n scale: { x: number; y: number };\n pos: { x: number; y: number };\n setSize: (w: number, h: number) => void;\n setButtonColor: (color: Color) => void;\n setButtonText: (value: string) => void;\n setButtonTextSize: (value: number) => void;\n setPosition: (x: number, y: number) => void;\n }\n\n const obj = k.add([\n k.rect(width, height, radius > 0 ? { radius } : undefined),\n k.pos(pos as never),\n k.area(),\n k.color(baseColor as never),\n k.anchor('center'),\n ]) as unknown as ButtonGameObj;\n\n const label = obj.add([\n k.text(text, { size, font }),\n k.color(textColor as never),\n k.anchor('center'),\n ]) as GameObj & { text: string; textSize: number };\n\n let currentText = text;\n let currentColor: Color = baseColor;\n\n obj.onClick(() => {\n obj.color = pressedColor;\n opt.onClick?.();\n });\n obj.onHover(() => {\n obj.color = hoverColor;\n obj.scale = k.vec2(1.05, 1.05);\n k.setCursor('pointer');\n });\n obj.onHoverEnd(() => {\n obj.color = currentColor;\n obj.scale = k.vec2(1, 1);\n k.setCursor('default');\n });\n\n obj.setSize = (w: number, h: number): void => {\n obj.width = w;\n obj.height = h;\n };\n\n obj.setButtonColor = (color: Color): void => {\n currentColor = color;\n obj.color = color;\n };\n\n obj.setButtonText = (value: string): void => {\n currentText = value;\n label.text = value;\n };\n\n obj.setButtonTextSize = (value: number): void => {\n label.textSize = value;\n };\n\n obj.setPosition = (x: number, y: number): void => {\n obj.pos = k.vec2(x, y);\n };\n\n label.text = currentText;\n\n return obj as unknown as GameObj;\n}\n","import type { DeepPartial, Theme } from './types';\n\nconst DEFAULT_PRIMARY = '#4f8cff';\nconst DEFAULT_TEXT = '#ffffff';\n\n/** Default theme used when no theme is provided. */\nexport const defaultTheme: Theme = {\n palette: {\n primary: DEFAULT_PRIMARY,\n secondary: DEFAULT_PRIMARY,\n background: '#111827',\n surface: '#1f2937',\n text: DEFAULT_TEXT,\n textSecondary: DEFAULT_TEXT,\n hover: DEFAULT_PRIMARY,\n pressed: DEFAULT_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: DEFAULT_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: { ...defaultTheme.palette, ...input?.palette },\n typography: { ...defaultTheme.typography, ...input?.typography },\n shape: { ...defaultTheme.shape, ...input?.shape },\n spacing: input?.spacing ?? defaultTheme.spacing,\n components: {\n button: {\n ...defaultTheme.components.button,\n ...input?.components?.button,\n width:\n input?.components?.button?.width ??\n input?.components?.button?.minWidth ??\n defaultTheme.components.button.width,\n },\n modal: {\n ...defaultTheme.components.modal,\n ...input?.components?.modal,\n },\n tooltip: {\n ...defaultTheme.components.tooltip,\n ...input?.components?.tooltip,\n },\n },\n };\n}\n","import type { GameObj, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport { createButtonComponent, createButtonObject } from './button';\nimport { resolveTheme } from './theme';\nimport type {\n ButtonComp,\n ButtonCompOpt,\n Color,\n DeepPartial,\n Theme,\n} from './types';\n\nexport { createButtonComponent, createButtonObject } from './button';\nexport type { ButtonComp, ButtonCompOpt, Color, Theme } from './types';\n\ndeclare module 'kaplay' {\n interface KAPLAYCtx {\n button: (text?: string, opt?: ButtonCompOpt) => ButtonComp;\n addButton: (\n text?: string,\n opt?: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n },\n ) => GameObj;\n setTheme: (theme: DeepPartial<Theme>) => void;\n getTheme: () => Theme;\n }\n}\n\n/** KAPLAY UI plugin. */\nexport function uiPlugin(k: KAPLAYCtx, theme: DeepPartial<Theme> = {}) {\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 button = (text = '', opt: ButtonCompOpt = {}): ButtonComp => {\n return createButtonComponent(k, currentTheme, text, opt);\n };\n\n const addButton = (\n text = '',\n opt: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n } = {},\n ): GameObj => {\n return createButtonObject(k, currentTheme, text, opt);\n };\n\n return {\n button,\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,n,r){let i=n,a={...r},o=()=>a.width??t.components.button.width,s=()=>a.height??t.components.button.height,c={id:`button`,get text(){return i},set text(e){i=e},get width(){return o()},set width(e){a.width=e},get height(){return s()},set height(e){a.height=e},renderArea(){return new e.Rect(e.vec2(),c.width,c.height)},setStyle(e){a={...a,...e}},add(){},draw(){let n=c.width,r=c.height,o=a.radius??t.shape.borderRadius,s=a.fill??t.palette.primary,l=a.textColor??t.palette.text,u=a.size??t.typography.fontSize,d=a.font??t.typography.fontFamily,f=e.drawRect;f?.({pos:e.vec2(),width:n,height:r,color:s,radius:o});let p=e.drawText;p?.({text:i,pos:e.vec2(n/2,r/2),size:u,font:d,color:l,anchor:`center`})},destroy(){}};return c}function n(e,t,n,r){let i=r.width??t.components.button.width,a=r.height??t.components.button.height,o=r.radius??t.shape.borderRadius,s=r.color??r.fill??t.palette.primary,c=r.hoverColor??t.palette.hover,l=r.pressedColor??t.palette.pressed,u=r.textColor??t.palette.text,d=r.size??t.typography.fontSize,f=r.font??t.typography.fontFamily,p=r.pos??e.vec2(),m=e.add([e.rect(i,a,o>0?{radius:o}:void 0),e.pos(p),e.area(),e.color(s),e.anchor(`center`)]),h=m.add([e.text(n,{size:d,font:f}),e.color(u),e.anchor(`center`)]),g=n,_=s;return m.onClick(()=>{m.color=l,r.onClick?.()}),m.onHover(()=>{m.color=c,m.scale=e.vec2(1.05,1.05),e.setCursor(`pointer`)}),m.onHoverEnd(()=>{m.color=_,m.scale=e.vec2(1,1),e.setCursor(`default`)}),m.setSize=(e,t)=>{m.width=e,m.height=t},m.setButtonColor=e=>{_=e,m.color=e},m.setButtonText=e=>{g=e,h.text=e},m.setButtonTextSize=e=>{h.textSize=e},m.setPosition=(t,n)=>{m.pos=e.vec2(t,n)},h.text=g,m}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,r={}){let i=r,a=o(i);return{button:(n=``,r={})=>t(e,a,n,r),addButton:(t=``,r={})=>n(e,a,t,r),setTheme:e=>{i={...i,...e},a=o(i)},getTheme:()=>a}}e.createButtonComponent=t,e.createButtonObject=n,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","createButtonComponent","currentText","text","currentOpt","opt","readWidth","theme","readHeight","comp","value","k","next","width","height","radius","fill","textColor","size","font","drawRect","drawText","createButtonObject","baseColor","hoverColor","pressedColor","pos","obj","label","currentColor","w","h","color","x","y","DEFAULT_PRIMARY","DEFAULT_TEXT","defaultTheme","resolveTheme","input","uiPlugin","userTheme","currentTheme"],"sources":["../src/button.ts","../src/theme.ts","../src/plugin.ts"],"sourcesContent":["import type { Comp, GameObj, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport type { ButtonComp, ButtonCompOpt, Color, Theme } from './types';\n\nexport function createButtonComponent(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonCompOpt,\n): ButtonComp {\n let currentText = text;\n let currentOpt: ButtonCompOpt = { ...opt };\n\n const readWidth = (): number => {\n return currentOpt.width ?? theme.components.button.width;\n };\n\n const readHeight = (): number => {\n return currentOpt.height ?? theme.components.button.height;\n };\n\n const comp: ButtonComp = {\n id: 'button',\n get text() {\n return currentText;\n },\n set text(value: string) {\n currentText = value;\n },\n get width() {\n return readWidth();\n },\n set width(value: number) {\n currentOpt.width = value;\n },\n get height() {\n return readHeight();\n },\n set height(value: number) {\n currentOpt.height = value;\n },\n renderArea() {\n return new k.Rect(k.vec2(), comp.width, comp.height);\n },\n setStyle(next: Partial<ButtonCompOpt>): void {\n currentOpt = { ...currentOpt, ...next };\n },\n add(): void {\n // No-op: rendering is handled in draw().\n },\n draw(): void {\n const width = comp.width;\n const height = comp.height;\n const radius = currentOpt.radius ?? theme.shape.borderRadius;\n const fill = currentOpt.fill ?? theme.palette.primary;\n const textColor = currentOpt.textColor ?? theme.palette.text;\n const size = currentOpt.size ?? theme.typography.fontSize;\n const font = currentOpt.font ?? theme.typography.fontFamily;\n\n const drawRect = k.drawRect as unknown as\n ((opt: Record<string, unknown>) => void) | undefined;\n drawRect?.({\n pos: k.vec2(),\n width,\n height,\n color: fill,\n radius,\n });\n\n const drawText = k.drawText as unknown as\n ((opt: Record<string, unknown>) => void) | undefined;\n drawText?.({\n text: currentText,\n pos: k.vec2(width / 2, height / 2),\n size,\n font,\n color: textColor,\n anchor: 'center',\n });\n },\n destroy(): void {\n // No resources to release.\n },\n };\n\n return comp;\n}\n\nexport function createButtonObject(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n },\n): GameObj {\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 = opt.color ?? opt.fill ?? theme.palette.primary;\n const hoverColor = opt.hoverColor ?? theme.palette.hover;\n const pressedColor = opt.pressedColor ?? theme.palette.pressed;\n const textColor = 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 interface ButtonGameObj {\n add: (comps: Comp[]) => { text: string; textSize: number };\n onClick: (cb: () => void) => void;\n onHover: (cb: () => void) => void;\n onHoverEnd: (cb: () => void) => void;\n width: number;\n height: number;\n color: unknown;\n scale: { x: number; y: number };\n pos: { x: number; y: number };\n setSize: (w: number, h: number) => void;\n setButtonColor: (color: Color) => void;\n setButtonText: (value: string) => void;\n setButtonTextSize: (value: number) => void;\n setPosition: (x: number, y: number) => void;\n }\n\n const obj = k.add([\n k.rect(width, height, radius > 0 ? { radius } : undefined),\n k.pos(pos as never),\n k.area(),\n k.color(baseColor as never),\n k.anchor('center'),\n ]) as unknown as ButtonGameObj;\n\n const label = obj.add([\n k.text(text, { size, font }),\n k.color(textColor as never),\n k.anchor('center'),\n ]) as GameObj & { text: string; textSize: number };\n\n let currentText = text;\n let currentColor: Color = baseColor;\n\n obj.onClick(() => {\n obj.color = pressedColor;\n opt.onClick?.();\n });\n obj.onHover(() => {\n obj.color = hoverColor;\n obj.scale = k.vec2(1.05, 1.05);\n k.setCursor('pointer');\n });\n obj.onHoverEnd(() => {\n obj.color = currentColor;\n obj.scale = k.vec2(1, 1);\n k.setCursor('default');\n });\n\n obj.setSize = (w: number, h: number): void => {\n obj.width = w;\n obj.height = h;\n };\n\n obj.setButtonColor = (color: Color): void => {\n currentColor = color;\n obj.color = color;\n };\n\n obj.setButtonText = (value: string): void => {\n currentText = value;\n label.text = value;\n };\n\n obj.setButtonTextSize = (value: number): void => {\n label.textSize = value;\n };\n\n obj.setPosition = (x: number, y: number): void => {\n obj.pos = k.vec2(x, y);\n };\n\n label.text = currentText;\n\n return obj as unknown as GameObj;\n}\n","import type { DeepPartial, Theme } from './types';\n\nconst DEFAULT_PRIMARY = '#4f8cff';\nconst DEFAULT_TEXT = '#ffffff';\n\n/** Default theme used when no theme is provided. */\nexport const defaultTheme: Theme = {\n palette: {\n primary: DEFAULT_PRIMARY,\n secondary: DEFAULT_PRIMARY,\n background: '#111827',\n surface: '#1f2937',\n text: DEFAULT_TEXT,\n textSecondary: DEFAULT_TEXT,\n hover: DEFAULT_PRIMARY,\n pressed: DEFAULT_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: DEFAULT_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: { ...defaultTheme.palette, ...input?.palette },\n typography: { ...defaultTheme.typography, ...input?.typography },\n shape: { ...defaultTheme.shape, ...input?.shape },\n spacing: input?.spacing ?? defaultTheme.spacing,\n components: {\n button: {\n ...defaultTheme.components.button,\n ...input?.components?.button,\n width:\n input?.components?.button?.width ??\n input?.components?.button?.minWidth ??\n defaultTheme.components.button.width,\n },\n modal: {\n ...defaultTheme.components.modal,\n ...input?.components?.modal,\n },\n tooltip: {\n ...defaultTheme.components.tooltip,\n ...input?.components?.tooltip,\n },\n },\n };\n}\n","import type { GameObj, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport { createButtonComponent, createButtonObject } from './button';\nimport { resolveTheme } from './theme';\nimport type {\n ButtonComp,\n ButtonCompOpt,\n Color,\n DeepPartial,\n Theme,\n} from './types';\n\nexport { createButtonComponent, createButtonObject } from './button';\nexport type { ButtonComp, ButtonCompOpt, Color, Theme } from './types';\n\ndeclare module 'kaplay' {\n interface KAPLAYCtx {\n button: (text?: string, opt?: ButtonCompOpt) => ButtonComp;\n addButton: (\n text?: string,\n opt?: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n },\n ) => GameObj;\n setTheme: (theme: DeepPartial<Theme>) => void;\n getTheme: () => Theme;\n }\n}\n\n/** KAPLAY UI plugin. */\nexport function uiPlugin(k: KAPLAYCtx, theme: DeepPartial<Theme> = {}) {\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 button = (text = '', opt: ButtonCompOpt = {}): ButtonComp => {\n return createButtonComponent(k, currentTheme, text, opt);\n };\n\n const addButton = (\n text = '',\n opt: ButtonCompOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: Color;\n hoverColor?: Color;\n pressedColor?: Color;\n textColor?: Color;\n } = {},\n ): GameObj => {\n return createButtonObject(k, currentTheme, text, opt);\n };\n\n return {\n button,\n addButton,\n setTheme,\n getTheme,\n };\n}\n"],"mappings":"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"}
|
package/global.d.ts
ADDED
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.0",
|
|
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.13.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
|
}
|