kaplay-plugin-ui 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -6
- package/dist/plugin.cjs +17 -10
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +23 -18
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.mts +23 -18
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +17 -10
- package/dist/plugin.mjs.map +1 -1
- package/dist/plugin.umd.js +17 -10
- package/dist/plugin.umd.js.map +1 -1
- package/dist/plugin.umd.min.js +1 -1
- package/dist/plugin.umd.min.js.map +1 -1
- package/global.d.ts +6 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
🦖 KAPLAY plugin UI (see [API](#api)):
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
11
|
+
- [addButton](#addButton)
|
|
12
|
+
- [getTheme](#getTheme)
|
|
13
|
+
- [setTheme](#setTheme)
|
|
14
14
|
|
|
15
15
|
## Prerequisites
|
|
16
16
|
|
|
@@ -53,7 +53,7 @@ Import the plugin's global TypeScript definitions:
|
|
|
53
53
|
import 'kaplay-plugin-ui/global';
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
Load the plugin using a script:
|
|
57
57
|
|
|
58
58
|
```html
|
|
59
59
|
<script src="https://unpkg.com/kaplay@latest/dist/kaplay.js"></script>
|
|
@@ -86,7 +86,7 @@ k.addButton('Start', {
|
|
|
86
86
|
|
|
87
87
|
## API
|
|
88
88
|
|
|
89
|
-
###
|
|
89
|
+
### addButton
|
|
90
90
|
|
|
91
91
|
Add button game object:
|
|
92
92
|
|
|
@@ -94,6 +94,8 @@ Add button game object:
|
|
|
94
94
|
addButton(text, opt);
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
+
Buttons auto-size to their label. Width uses `components.button.paddingX` and `components.button.minWidth`; height uses `components.button.paddingY`. Pass `width` or `height` to override either dimension.
|
|
98
|
+
|
|
97
99
|
Update button text:
|
|
98
100
|
|
|
99
101
|
```ts
|
|
@@ -101,7 +103,9 @@ const button = addButton(text);
|
|
|
101
103
|
button.label.text = 'Hello';
|
|
102
104
|
```
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
The button resizes automatically when the label text or font changes.
|
|
107
|
+
|
|
108
|
+
### getTheme
|
|
105
109
|
|
|
106
110
|
Retrieve theme:
|
|
107
111
|
|
|
@@ -109,6 +113,8 @@ Retrieve theme:
|
|
|
109
113
|
getTheme();
|
|
110
114
|
```
|
|
111
115
|
|
|
116
|
+
### setTheme
|
|
117
|
+
|
|
112
118
|
Customize theme:
|
|
113
119
|
|
|
114
120
|
```ts
|
package/dist/plugin.cjs
CHANGED
|
@@ -12,9 +12,8 @@ function toColor(k, color) {
|
|
|
12
12
|
}
|
|
13
13
|
// src/button.ts
|
|
14
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
15
|
const radius = opt.radius ?? theme.shape.borderRadius;
|
|
16
|
+
const { minWidth, paddingX, paddingY } = theme.components.button;
|
|
18
17
|
const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);
|
|
19
18
|
const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);
|
|
20
19
|
const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);
|
|
@@ -22,6 +21,12 @@ function createButton(k, theme, text, opt) {
|
|
|
22
21
|
const size = opt.size ?? theme.typography.fontSize;
|
|
23
22
|
const font = opt.font ?? theme.typography.fontFamily;
|
|
24
23
|
const pos = opt.pos ?? k.vec2();
|
|
24
|
+
const textComp = k.text(text, {
|
|
25
|
+
size,
|
|
26
|
+
font
|
|
27
|
+
});
|
|
28
|
+
const width = opt.width ?? Math.max(textComp.width + paddingX * 2, minWidth);
|
|
29
|
+
const height = opt.height ?? textComp.height + paddingY * 2;
|
|
25
30
|
const button = k.add([
|
|
26
31
|
k.rect(width, height, radius > 0 ? { radius } : void 0),
|
|
27
32
|
k.pos(pos),
|
|
@@ -31,13 +36,18 @@ function createButton(k, theme, text, opt) {
|
|
|
31
36
|
k.anchor("center")
|
|
32
37
|
]);
|
|
33
38
|
const label = button.add([
|
|
34
|
-
|
|
35
|
-
size,
|
|
36
|
-
font
|
|
37
|
-
}),
|
|
39
|
+
textComp,
|
|
38
40
|
k.color(textColor),
|
|
39
41
|
k.anchor("center")
|
|
40
42
|
]);
|
|
43
|
+
function resize() {
|
|
44
|
+
const nextWidth = opt.width ?? Math.max(label.width + paddingX * 2, minWidth);
|
|
45
|
+
const nextHeight = opt.height ?? label.height + paddingY * 2;
|
|
46
|
+
if (button.width !== nextWidth) button.width = nextWidth;
|
|
47
|
+
if (button.height !== nextHeight) button.height = nextHeight;
|
|
48
|
+
}
|
|
49
|
+
resize();
|
|
50
|
+
if (opt.width === void 0 || opt.height === void 0) button.onUpdate(resize);
|
|
41
51
|
button.onClick(() => {
|
|
42
52
|
button.color = toColor(k, pressedColor);
|
|
43
53
|
opt.onClick?.();
|
|
@@ -84,8 +94,6 @@ const theme = {
|
|
|
84
94
|
spacing: 8,
|
|
85
95
|
components: {
|
|
86
96
|
button: {
|
|
87
|
-
width: 120,
|
|
88
|
-
height: 40,
|
|
89
97
|
minWidth: 120,
|
|
90
98
|
paddingX: 12,
|
|
91
99
|
paddingY: 8,
|
|
@@ -121,8 +129,7 @@ function resolveTheme(input) {
|
|
|
121
129
|
components: {
|
|
122
130
|
button: {
|
|
123
131
|
...theme.components.button,
|
|
124
|
-
...input?.components?.button
|
|
125
|
-
width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? theme.components.button.width
|
|
132
|
+
...input?.components?.button
|
|
126
133
|
},
|
|
127
134
|
modal: {
|
|
128
135
|
...theme.components.modal,
|
package/dist/plugin.cjs.map
CHANGED
|
@@ -1 +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
|
|
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 radius = opt.radius ?? theme.shape.borderRadius;\n const { minWidth, paddingX, paddingY } = theme.components.button;\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 textComp = k.text(text, { size, font });\n const width = opt.width ?? Math.max(textComp.width + paddingX * 2, minWidth);\n const height = opt.height ?? textComp.height + paddingY * 2;\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 textComp,\n k.color(textColor as never),\n k.anchor('center'),\n ]);\n\n function resize() {\n const nextWidth =\n opt.width ?? Math.max(label.width + paddingX * 2, minWidth);\n const nextHeight = opt.height ?? label.height + paddingY * 2;\n\n if (button.width !== nextWidth) {\n button.width = nextWidth;\n }\n\n if (button.height !== nextHeight) {\n button.height = nextHeight;\n }\n }\n\n resize();\n\n if (opt.width === undefined || opt.height === undefined) {\n button.onUpdate(resize);\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 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 },\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 { KAPLAYCtx } from 'kaplay';\n\nimport { createButton } from './button';\nimport { resolveTheme } from './theme';\nimport type {\n AddButton,\n DeepPartial,\n GetTheme,\n SetTheme,\n Theme,\n} from './types';\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: GetTheme = () => currentTheme;\n\n const setTheme: SetTheme = (next) => {\n userTheme = { ...userTheme, ...next };\n currentTheme = resolveTheme(userTheme);\n };\n\n const addButton: AddButton = (text = '', opt = {}) => {\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/dist/plugin.d.cts
CHANGED
|
@@ -7,7 +7,7 @@ declare function createButton(k: KAPLAYCtx, theme: Theme, text: string, opt: But
|
|
|
7
7
|
pressedColor?: string | Color;
|
|
8
8
|
textColor?: string | Color;
|
|
9
9
|
}): {
|
|
10
|
-
label: import("kaplay").GameObj<import("kaplay").
|
|
10
|
+
label: import("kaplay").GameObj<import("kaplay").TextComp | import("kaplay").ColorComp | import("kaplay").AnchorComp>;
|
|
11
11
|
add<T>(comps?: import("kaplay").CompList<T> | import("kaplay").GameObj<T>): import("kaplay").GameObj<T>;
|
|
12
12
|
readd<T>(obj: import("kaplay").GameObj<T>): import("kaplay").GameObj<T>;
|
|
13
13
|
remove(obj: import("kaplay").GameObj): void;
|
|
@@ -143,23 +143,26 @@ declare function createButton(k: KAPLAYCtx, theme: Theme, text: string, opt: But
|
|
|
143
143
|
color: Color;
|
|
144
144
|
anchor: import("kaplay").Anchor | Vec2;
|
|
145
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
146
|
declare module 'kaplay' {
|
|
159
|
-
interface KAPLAYCtx
|
|
147
|
+
interface KAPLAYCtx {
|
|
148
|
+
addButton: AddButton;
|
|
149
|
+
getTheme: GetTheme;
|
|
150
|
+
setTheme: SetTheme;
|
|
151
|
+
}
|
|
160
152
|
}
|
|
153
|
+
type AddButton = (text?: string, opt?: ButtonOpt & {
|
|
154
|
+
pos?: Vec2;
|
|
155
|
+
onClick?: () => void;
|
|
156
|
+
color?: string | Color;
|
|
157
|
+
hoverColor?: string | Color;
|
|
158
|
+
pressedColor?: string | Color;
|
|
159
|
+
textColor?: string | Color;
|
|
160
|
+
}) => ReturnType<typeof createButton>;
|
|
161
|
+
type GetTheme = () => Theme;
|
|
162
|
+
type SetTheme = (theme: DeepPartial<Theme>) => void;
|
|
161
163
|
/** Recursively partial version of a type. */
|
|
162
164
|
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; };
|
|
165
|
+
/** Theme config. */
|
|
163
166
|
interface Theme {
|
|
164
167
|
palette: {
|
|
165
168
|
primary: string | Color;
|
|
@@ -185,8 +188,6 @@ interface Theme {
|
|
|
185
188
|
spacing: number;
|
|
186
189
|
components: {
|
|
187
190
|
button: {
|
|
188
|
-
width: number;
|
|
189
|
-
height: number;
|
|
190
191
|
minWidth: number;
|
|
191
192
|
paddingX: number;
|
|
192
193
|
paddingY: number;
|
|
@@ -216,6 +217,10 @@ interface ButtonOpt {
|
|
|
216
217
|
pressedFill?: string | Color;
|
|
217
218
|
}
|
|
218
219
|
/** KAPLAY UI plugin. */
|
|
219
|
-
export declare function uiPlugin(k: KAPLAYCtx, theme?: DeepPartial<Theme>):
|
|
220
|
-
|
|
220
|
+
export declare function uiPlugin(k: KAPLAYCtx, theme?: DeepPartial<Theme>): {
|
|
221
|
+
addButton: AddButton;
|
|
222
|
+
setTheme: SetTheme;
|
|
223
|
+
getTheme: GetTheme;
|
|
224
|
+
};
|
|
225
|
+
export {};
|
|
221
226
|
//# sourceMappingURL=plugin.d.cts.map
|
package/dist/plugin.d.cts.map
CHANGED
|
@@ -1 +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;;;;;;;;;;;;;;;;;;;;;;;;
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;EA0EigzM,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;;;;;;;;;;;;;;;;;;;;;;;;;;YCpFrtyD;IACR,WAAW;IACX,UAAU;IACV,UAAU;;;KAIF,aACV,eACA,MAAM;EACJ,MAAM;EACN;EACA,iBAAiB;EACjB,sBAAsB;EACtB,wBAAwB;EACxB,qBAAqB;MAEpB,kBAAkB;KAEX,iBAAiB;KAEjB,YAAY,OAAO,YAAY;;KAG/B,YAAY,QACrB,WAAW,KAAK,EAAE,oBAAoB,YAAY,EAAE,MAAM,EAAE;;UAI9C;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;;IAEF;MACE;MACA;;IAEF;MACE,qBAAqB;MACrB,oBAAoB;MACpB;;;;;UAMW;EACf;EACA;EACA;EACA;EACA,gBAAgB;EAChB,qBAAqB;EACrB;EACA,qBAAqB;EACrB,uBAAuB;;;wBCzET,SAAS,GAAG,WAAW,QAAO,YAAY"}
|
package/dist/plugin.d.mts
CHANGED
|
@@ -7,7 +7,7 @@ declare function createButton(k: KAPLAYCtx, theme: Theme, text: string, opt: But
|
|
|
7
7
|
pressedColor?: string | Color;
|
|
8
8
|
textColor?: string | Color;
|
|
9
9
|
}): {
|
|
10
|
-
label: import("kaplay").GameObj<import("kaplay").
|
|
10
|
+
label: import("kaplay").GameObj<import("kaplay").TextComp | import("kaplay").ColorComp | import("kaplay").AnchorComp>;
|
|
11
11
|
add<T>(comps?: import("kaplay").CompList<T> | import("kaplay").GameObj<T>): import("kaplay").GameObj<T>;
|
|
12
12
|
readd<T>(obj: import("kaplay").GameObj<T>): import("kaplay").GameObj<T>;
|
|
13
13
|
remove(obj: import("kaplay").GameObj): void;
|
|
@@ -143,23 +143,26 @@ declare function createButton(k: KAPLAYCtx, theme: Theme, text: string, opt: But
|
|
|
143
143
|
color: Color;
|
|
144
144
|
anchor: import("kaplay").Anchor | Vec2;
|
|
145
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
146
|
declare module 'kaplay' {
|
|
159
|
-
interface KAPLAYCtx
|
|
147
|
+
interface KAPLAYCtx {
|
|
148
|
+
addButton: AddButton;
|
|
149
|
+
getTheme: GetTheme;
|
|
150
|
+
setTheme: SetTheme;
|
|
151
|
+
}
|
|
160
152
|
}
|
|
153
|
+
type AddButton = (text?: string, opt?: ButtonOpt & {
|
|
154
|
+
pos?: Vec2;
|
|
155
|
+
onClick?: () => void;
|
|
156
|
+
color?: string | Color;
|
|
157
|
+
hoverColor?: string | Color;
|
|
158
|
+
pressedColor?: string | Color;
|
|
159
|
+
textColor?: string | Color;
|
|
160
|
+
}) => ReturnType<typeof createButton>;
|
|
161
|
+
type GetTheme = () => Theme;
|
|
162
|
+
type SetTheme = (theme: DeepPartial<Theme>) => void;
|
|
161
163
|
/** Recursively partial version of a type. */
|
|
162
164
|
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; };
|
|
165
|
+
/** Theme config. */
|
|
163
166
|
interface Theme {
|
|
164
167
|
palette: {
|
|
165
168
|
primary: string | Color;
|
|
@@ -185,8 +188,6 @@ interface Theme {
|
|
|
185
188
|
spacing: number;
|
|
186
189
|
components: {
|
|
187
190
|
button: {
|
|
188
|
-
width: number;
|
|
189
|
-
height: number;
|
|
190
191
|
minWidth: number;
|
|
191
192
|
paddingX: number;
|
|
192
193
|
paddingY: number;
|
|
@@ -216,6 +217,10 @@ interface ButtonOpt {
|
|
|
216
217
|
pressedFill?: string | Color;
|
|
217
218
|
}
|
|
218
219
|
/** KAPLAY UI plugin. */
|
|
219
|
-
export declare function uiPlugin(k: KAPLAYCtx, theme?: DeepPartial<Theme>):
|
|
220
|
-
|
|
220
|
+
export declare function uiPlugin(k: KAPLAYCtx, theme?: DeepPartial<Theme>): {
|
|
221
|
+
addButton: AddButton;
|
|
222
|
+
setTheme: SetTheme;
|
|
223
|
+
getTheme: GetTheme;
|
|
224
|
+
};
|
|
225
|
+
export {};
|
|
221
226
|
//# sourceMappingURL=plugin.d.mts.map
|
package/dist/plugin.d.mts.map
CHANGED
|
@@ -1 +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;;;;;;;;;;;;;;;;;;;;;;;;
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;EA0EigzM,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;;;;;;;;;;;;;;;;;;;;;;;;;;YCpFrtyD;IACR,WAAW;IACX,UAAU;IACV,UAAU;;;KAIF,aACV,eACA,MAAM;EACJ,MAAM;EACN;EACA,iBAAiB;EACjB,sBAAsB;EACtB,wBAAwB;EACxB,qBAAqB;MAEpB,kBAAkB;KAEX,iBAAiB;KAEjB,YAAY,OAAO,YAAY;;KAG/B,YAAY,QACrB,WAAW,KAAK,EAAE,oBAAoB,YAAY,EAAE,MAAM,EAAE;;UAI9C;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;;IAEF;MACE;MACA;;IAEF;MACE,qBAAqB;MACrB,oBAAoB;MACpB;;;;;UAMW;EACf;EACA;EACA;EACA;EACA,gBAAgB;EAChB,qBAAqB;EACrB;EACA,qBAAqB;EACrB,uBAAuB;;;wBCzET,SAAS,GAAG,WAAW,QAAO,YAAY"}
|
package/dist/plugin.mjs
CHANGED
|
@@ -11,9 +11,8 @@ function toColor(k, color) {
|
|
|
11
11
|
}
|
|
12
12
|
// src/button.ts
|
|
13
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
14
|
const radius = opt.radius ?? theme.shape.borderRadius;
|
|
15
|
+
const { minWidth, paddingX, paddingY } = theme.components.button;
|
|
17
16
|
const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);
|
|
18
17
|
const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);
|
|
19
18
|
const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);
|
|
@@ -21,6 +20,12 @@ function createButton(k, theme, text, opt) {
|
|
|
21
20
|
const size = opt.size ?? theme.typography.fontSize;
|
|
22
21
|
const font = opt.font ?? theme.typography.fontFamily;
|
|
23
22
|
const pos = opt.pos ?? k.vec2();
|
|
23
|
+
const textComp = k.text(text, {
|
|
24
|
+
size,
|
|
25
|
+
font
|
|
26
|
+
});
|
|
27
|
+
const width = opt.width ?? Math.max(textComp.width + paddingX * 2, minWidth);
|
|
28
|
+
const height = opt.height ?? textComp.height + paddingY * 2;
|
|
24
29
|
const button = k.add([
|
|
25
30
|
k.rect(width, height, radius > 0 ? { radius } : void 0),
|
|
26
31
|
k.pos(pos),
|
|
@@ -30,13 +35,18 @@ function createButton(k, theme, text, opt) {
|
|
|
30
35
|
k.anchor("center")
|
|
31
36
|
]);
|
|
32
37
|
const label = button.add([
|
|
33
|
-
|
|
34
|
-
size,
|
|
35
|
-
font
|
|
36
|
-
}),
|
|
38
|
+
textComp,
|
|
37
39
|
k.color(textColor),
|
|
38
40
|
k.anchor("center")
|
|
39
41
|
]);
|
|
42
|
+
function resize() {
|
|
43
|
+
const nextWidth = opt.width ?? Math.max(label.width + paddingX * 2, minWidth);
|
|
44
|
+
const nextHeight = opt.height ?? label.height + paddingY * 2;
|
|
45
|
+
if (button.width !== nextWidth) button.width = nextWidth;
|
|
46
|
+
if (button.height !== nextHeight) button.height = nextHeight;
|
|
47
|
+
}
|
|
48
|
+
resize();
|
|
49
|
+
if (opt.width === void 0 || opt.height === void 0) button.onUpdate(resize);
|
|
40
50
|
button.onClick(() => {
|
|
41
51
|
button.color = toColor(k, pressedColor);
|
|
42
52
|
opt.onClick?.();
|
|
@@ -83,8 +93,6 @@ const theme = {
|
|
|
83
93
|
spacing: 8,
|
|
84
94
|
components: {
|
|
85
95
|
button: {
|
|
86
|
-
width: 120,
|
|
87
|
-
height: 40,
|
|
88
96
|
minWidth: 120,
|
|
89
97
|
paddingX: 12,
|
|
90
98
|
paddingY: 8,
|
|
@@ -120,8 +128,7 @@ function resolveTheme(input) {
|
|
|
120
128
|
components: {
|
|
121
129
|
button: {
|
|
122
130
|
...theme.components.button,
|
|
123
|
-
...input?.components?.button
|
|
124
|
-
width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? theme.components.button.width
|
|
131
|
+
...input?.components?.button
|
|
125
132
|
},
|
|
126
133
|
modal: {
|
|
127
134
|
...theme.components.modal,
|
package/dist/plugin.mjs.map
CHANGED
|
@@ -1 +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
|
|
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 radius = opt.radius ?? theme.shape.borderRadius;\n const { minWidth, paddingX, paddingY } = theme.components.button;\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 textComp = k.text(text, { size, font });\n const width = opt.width ?? Math.max(textComp.width + paddingX * 2, minWidth);\n const height = opt.height ?? textComp.height + paddingY * 2;\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 textComp,\n k.color(textColor as never),\n k.anchor('center'),\n ]);\n\n function resize() {\n const nextWidth =\n opt.width ?? Math.max(label.width + paddingX * 2, minWidth);\n const nextHeight = opt.height ?? label.height + paddingY * 2;\n\n if (button.width !== nextWidth) {\n button.width = nextWidth;\n }\n\n if (button.height !== nextHeight) {\n button.height = nextHeight;\n }\n }\n\n resize();\n\n if (opt.width === undefined || opt.height === undefined) {\n button.onUpdate(resize);\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 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 },\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 { KAPLAYCtx } from 'kaplay';\n\nimport { createButton } from './button';\nimport { resolveTheme } from './theme';\nimport type {\n AddButton,\n DeepPartial,\n GetTheme,\n SetTheme,\n Theme,\n} from './types';\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: GetTheme = () => currentTheme;\n\n const setTheme: SetTheme = (next) => {\n userTheme = { ...userTheme, ...next };\n currentTheme = resolveTheme(userTheme);\n };\n\n const addButton: AddButton = (text = '', opt = {}) => {\n return createButton(k, currentTheme, text, opt);\n };\n\n return {\n addButton,\n setTheme,\n getTheme,\n };\n}\n"],"mappings":";;;;;;;;AASA,SAAgB,QAAQ,GAAc,OAA8B;CAClE,OAAO,OAAO,UAAU,WAAW,EAAE,IAAI,KAAK,IAAI;AACpD;;ACNA,SAAgB,aACd,GACA,OACA,MACA,KAQA;CACA,MAAM,SAAS,IAAI,UAAU,MAAM,MAAM;CACzC,MAAM,EAAE,UAAU,UAAU,aAAa,MAAM,WAAW;CAC1D,MAAM,YAAY,QAAQ,GAAG,IAAI,SAAS,IAAI,QAAQ,MAAM,QAAQ,OAAO;CAC3E,MAAM,aAAa,QAAQ,GAAG,IAAI,cAAc,MAAM,QAAQ,KAAK;CACnE,MAAM,eAAe,QAAQ,GAAG,IAAI,gBAAgB,MAAM,QAAQ,OAAO;CACzE,MAAM,YAAY,QAAQ,GAAG,IAAI,aAAa,MAAM,QAAQ,IAAI;CAChE,MAAM,OAAO,IAAI,QAAQ,MAAM,WAAW;CAC1C,MAAM,OAAO,IAAI,QAAQ,MAAM,WAAW;CAC1C,MAAM,MAAM,IAAI,OAAO,EAAE,KAAK;CAE9B,MAAM,WAAW,EAAE,KAAK,MAAM;EAAE;EAAM;CAAK,CAAC;CAC5C,MAAM,QAAQ,IAAI,SAAS,KAAK,IAAI,SAAS,QAAQ,WAAW,GAAG,QAAQ;CAC3E,MAAM,SAAS,IAAI,UAAU,SAAS,SAAS,WAAW;CAE1D,MAAM,SAAS,EAAE,IAAI;EACnB,EAAE,KAAK,OAAO,QAAQ,SAAS,IAAI,EAAE,OAAO,IAAI,KAAA,CAAS;EACzD,EAAE,IAAI,GAAG;EACT,EAAE,KAAK;EACP,EAAE,MAAM;EACR,EAAE,MAAM,SAAS;EACjB,EAAE,OAAO,QAAQ;CACnB,CAAC;CAED,MAAM,QAAQ,OAAO,IAAI;EACvB;EACA,EAAE,MAAM,SAAkB;EAC1B,EAAE,OAAO,QAAQ;CACnB,CAAC;CAED,SAAS,SAAS;EAChB,MAAM,YACJ,IAAI,SAAS,KAAK,IAAI,MAAM,QAAQ,WAAW,GAAG,QAAQ;EAC5D,MAAM,aAAa,IAAI,UAAU,MAAM,SAAS,WAAW;EAE3D,IAAI,OAAO,UAAU,WACnB,OAAO,QAAQ;EAGjB,IAAI,OAAO,WAAW,YACpB,OAAO,SAAS;CAEpB;CAEA,OAAO;CAEP,IAAI,IAAI,UAAU,KAAA,KAAa,IAAI,WAAW,KAAA,GAC5C,OAAO,SAAS,MAAM;CAGxB,OAAO,cAAc;EACnB,OAAO,QAAQ,QAAQ,GAAG,YAAY;EACtC,IAAI,UAAU;CAChB,CAAC;CAED,OAAO,cAAc;EACnB,OAAO,QAAQ,QAAQ,GAAG,UAAU;EACpC,OAAO,QAAQ,EAAE,KAAK,MAAM,IAAI;EAChC,EAAE,UAAU,SAAS;CACvB,CAAC;CAED,OAAO,iBAAiB;EACtB,OAAO,QAAQ;EACf,OAAO,QAAQ,EAAE,KAAK,GAAG,CAAC;EAC1B,EAAE,UAAU,SAAS;CACvB,CAAC;CAED,OAAO;EACL,GAAG;EACH;CACF;AACF;;ACtFA,MAAM,UAAU;AAChB,MAAM,OAAO;;AAGb,MAAM,QAAe;CACnB,SAAS;EACP,SAAS;EACT,WAAW;EACX,YAAY;EACZ,SAAS;EACT,MAAM;EACN,eAAe;EACf,OAAO;EACP,SAAS;EACT,UAAU;EACV,OAAO;CACT;CACA,YAAY;EACV,YAAY;EACZ,UAAU;EACV,YAAY;EACZ,YAAY;CACd;CACA,OAAO,EACL,cAAc,EAChB;CACA,SAAS;CACT,YAAY;EACV,QAAQ;GACN,UAAU;GACV,UAAU;GACV,UAAU;GACV,eAAe;EACjB;EACA,OAAO;GACL,iBAAiB;GACjB,cAAc;EAChB;EACA,SAAS;GACP,YAAY;GACZ,WAAW;GACX,OAAO;EACT;CACF;AACF;;AAGA,SAAgB,aAAa,OAAmC;CAC9D,OAAO;EACL,SAAS;GAAE,GAAG,MAAM;GAAS,GAAG,OAAO;EAAQ;EAC/C,YAAY;GAAE,GAAG,MAAM;GAAY,GAAG,OAAO;EAAW;EACxD,OAAO;GAAE,GAAG,MAAM;GAAO,GAAG,OAAO;EAAM;EACzC,SAAS,OAAO,WAAW,MAAM;EACjC,YAAY;GACV,QAAQ;IACN,GAAG,MAAM,WAAW;IACpB,GAAG,OAAO,YAAY;GACxB;GACA,OAAO;IACL,GAAG,MAAM,WAAW;IACpB,GAAG,OAAO,YAAY;GACxB;GACA,SAAS;IACP,GAAG,MAAM,WAAW;IACpB,GAAG,OAAO,YAAY;GACxB;EACF;CACF;AACF;;;ACzDA,SAAgB,SAAS,GAAc,QAA4B,CAAC,GAAG;CACrE,IAAI,YAAgC;CACpC,IAAI,eAAsB,aAAa,SAAS;CAEhD,MAAM,iBAA2B;CAEjC,MAAM,YAAsB,SAAS;EACnC,YAAY;GAAE,GAAG;GAAW,GAAG;EAAK;EACpC,eAAe,aAAa,SAAS;CACvC;CAEA,MAAM,aAAwB,OAAO,IAAI,MAAM,CAAC,MAAM;EACpD,OAAO,aAAa,GAAG,cAAc,MAAM,GAAG;CAChD;CAEA,OAAO;EACL;EACA;EACA;CACF;AACF"}
|
package/dist/plugin.umd.js
CHANGED
|
@@ -15,9 +15,8 @@
|
|
|
15
15
|
}
|
|
16
16
|
// src/button.ts
|
|
17
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
18
|
const radius = opt.radius ?? theme.shape.borderRadius;
|
|
19
|
+
const { minWidth, paddingX, paddingY } = theme.components.button;
|
|
21
20
|
const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);
|
|
22
21
|
const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);
|
|
23
22
|
const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);
|
|
@@ -25,6 +24,12 @@
|
|
|
25
24
|
const size = opt.size ?? theme.typography.fontSize;
|
|
26
25
|
const font = opt.font ?? theme.typography.fontFamily;
|
|
27
26
|
const pos = opt.pos ?? k.vec2();
|
|
27
|
+
const textComp = k.text(text, {
|
|
28
|
+
size,
|
|
29
|
+
font
|
|
30
|
+
});
|
|
31
|
+
const width = opt.width ?? Math.max(textComp.width + paddingX * 2, minWidth);
|
|
32
|
+
const height = opt.height ?? textComp.height + paddingY * 2;
|
|
28
33
|
const button = k.add([
|
|
29
34
|
k.rect(width, height, radius > 0 ? { radius } : void 0),
|
|
30
35
|
k.pos(pos),
|
|
@@ -34,13 +39,18 @@
|
|
|
34
39
|
k.anchor("center")
|
|
35
40
|
]);
|
|
36
41
|
const label = button.add([
|
|
37
|
-
|
|
38
|
-
size,
|
|
39
|
-
font
|
|
40
|
-
}),
|
|
42
|
+
textComp,
|
|
41
43
|
k.color(textColor),
|
|
42
44
|
k.anchor("center")
|
|
43
45
|
]);
|
|
46
|
+
function resize() {
|
|
47
|
+
const nextWidth = opt.width ?? Math.max(label.width + paddingX * 2, minWidth);
|
|
48
|
+
const nextHeight = opt.height ?? label.height + paddingY * 2;
|
|
49
|
+
if (button.width !== nextWidth) button.width = nextWidth;
|
|
50
|
+
if (button.height !== nextHeight) button.height = nextHeight;
|
|
51
|
+
}
|
|
52
|
+
resize();
|
|
53
|
+
if (opt.width === void 0 || opt.height === void 0) button.onUpdate(resize);
|
|
44
54
|
button.onClick(() => {
|
|
45
55
|
button.color = toColor(k, pressedColor);
|
|
46
56
|
opt.onClick?.();
|
|
@@ -87,8 +97,6 @@
|
|
|
87
97
|
spacing: 8,
|
|
88
98
|
components: {
|
|
89
99
|
button: {
|
|
90
|
-
width: 120,
|
|
91
|
-
height: 40,
|
|
92
100
|
minWidth: 120,
|
|
93
101
|
paddingX: 12,
|
|
94
102
|
paddingY: 8,
|
|
@@ -124,8 +132,7 @@
|
|
|
124
132
|
components: {
|
|
125
133
|
button: {
|
|
126
134
|
...theme.components.button,
|
|
127
|
-
...input?.components?.button
|
|
128
|
-
width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? theme.components.button.width
|
|
135
|
+
...input?.components?.button
|
|
129
136
|
},
|
|
130
137
|
modal: {
|
|
131
138
|
...theme.components.modal,
|
package/dist/plugin.umd.js.map
CHANGED
|
@@ -1 +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
|
|
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 radius = opt.radius ?? theme.shape.borderRadius;\n const { minWidth, paddingX, paddingY } = theme.components.button;\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 textComp = k.text(text, { size, font });\n const width = opt.width ?? Math.max(textComp.width + paddingX * 2, minWidth);\n const height = opt.height ?? textComp.height + paddingY * 2;\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 textComp,\n k.color(textColor as never),\n k.anchor('center'),\n ]);\n\n function resize() {\n const nextWidth =\n opt.width ?? Math.max(label.width + paddingX * 2, minWidth);\n const nextHeight = opt.height ?? label.height + paddingY * 2;\n\n if (button.width !== nextWidth) {\n button.width = nextWidth;\n }\n\n if (button.height !== nextHeight) {\n button.height = nextHeight;\n }\n }\n\n resize();\n\n if (opt.width === undefined || opt.height === undefined) {\n button.onUpdate(resize);\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 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 },\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 { KAPLAYCtx } from 'kaplay';\n\nimport { createButton } from './button';\nimport { resolveTheme } from './theme';\nimport type {\n AddButton,\n DeepPartial,\n GetTheme,\n SetTheme,\n Theme,\n} from './types';\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: GetTheme = () => currentTheme;\n\n const setTheme: SetTheme = (next) => {\n userTheme = { ...userTheme, ...next };\n currentTheme = resolveTheme(userTheme);\n };\n\n const addButton: AddButton = (text = '', opt = {}) => {\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/dist/plugin.umd.min.js
CHANGED
|
@@ -1,2 +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.
|
|
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.radius??n.shape.borderRadius,{minWidth:o,paddingX:s,paddingY:c}=n.components.button,l=t(e,i.color??i.fill??n.palette.primary),u=t(e,i.hoverColor??n.palette.hover),d=t(e,i.pressedColor??n.palette.pressed),f=t(e,i.textColor??n.palette.text),p=i.size??n.typography.fontSize,m=i.font??n.typography.fontFamily,h=i.pos??e.vec2(),g=e.text(r,{size:p,font:m}),_=i.width??Math.max(g.width+s*2,o),v=i.height??g.height+c*2,y=e.add([e.rect(_,v,a>0?{radius:a}:void 0),e.pos(h),e.area(),e.scale(),e.color(l),e.anchor(`center`)]),b=y.add([g,e.color(f),e.anchor(`center`)]);function x(){let e=i.width??Math.max(b.width+s*2,o),t=i.height??b.height+c*2;y.width!==e&&(y.width=e),y.height!==t&&(y.height=t)}return x(),(i.width===void 0||i.height===void 0)&&y.onUpdate(x),y.onClick(()=>{y.color=t(e,d),i.onClick?.()}),y.onHover(()=>{y.color=t(e,u),y.scale=e.vec2(1.05,1.05),e.setCursor(`pointer`)}),y.onHoverEnd(()=>{y.color=l,y.scale=e.vec2(1,1),e.setCursor(`default`)}),{...y,label:b}}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:{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},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
2
|
//# sourceMappingURL=plugin.umd.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.umd.min.js","names":["factory","global","exports","toColor","color","k","createButton","
|
|
1
|
+
{"version":3,"file":"plugin.umd.min.js","names":["factory","global","exports","toColor","color","k","createButton","radius","opt","theme","baseColor","hoverColor","pressedColor","textColor","size","font","pos","textComp","text","width","paddingX","minWidth","height","paddingY","button","label","resize","nextWidth","nextHeight","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 radius = opt.radius ?? theme.shape.borderRadius;\n const { minWidth, paddingX, paddingY } = theme.components.button;\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 textComp = k.text(text, { size, font });\n const width = opt.width ?? Math.max(textComp.width + paddingX * 2, minWidth);\n const height = opt.height ?? textComp.height + paddingY * 2;\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 textComp,\n k.color(textColor as never),\n k.anchor('center'),\n ]);\n\n function resize() {\n const nextWidth =\n opt.width ?? Math.max(label.width + paddingX * 2, minWidth);\n const nextHeight = opt.height ?? label.height + paddingY * 2;\n\n if (button.width !== nextWidth) {\n button.width = nextWidth;\n }\n\n if (button.height !== nextHeight) {\n button.height = nextHeight;\n }\n }\n\n resize();\n\n if (opt.width === undefined || opt.height === undefined) {\n button.onUpdate(resize);\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 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 },\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 { KAPLAYCtx } from 'kaplay';\n\nimport { createButton } from './button';\nimport { resolveTheme } from './theme';\nimport type {\n AddButton,\n DeepPartial,\n GetTheme,\n SetTheme,\n Theme,\n} from './types';\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: GetTheme = () => currentTheme;\n\n const setTheme: SetTheme = (next) => {\n userTheme = { ...userTheme, ...next };\n currentTheme = resolveTheme(userTheme);\n };\n\n const addButton: AddButton = (text = '', opt = {}) => {\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
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { uiPlugin } from './dist/plugin.cjs';
|
|
2
|
+
|
|
3
|
+
type Plugin = ReturnType<typeof uiPlugin>;
|
|
2
4
|
|
|
3
5
|
declare global {
|
|
4
6
|
/**
|
|
@@ -18,7 +20,7 @@ declare global {
|
|
|
18
20
|
*
|
|
19
21
|
* @returns The button object.
|
|
20
22
|
*/
|
|
21
|
-
var addButton:
|
|
23
|
+
var addButton: Plugin['addButton'];
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* Retrieve the theme.
|
|
@@ -30,7 +32,7 @@ declare global {
|
|
|
30
32
|
*
|
|
31
33
|
* @returns The theme config.
|
|
32
34
|
*/
|
|
33
|
-
var getTheme:
|
|
35
|
+
var getTheme: Plugin['getTheme'];
|
|
34
36
|
|
|
35
37
|
/**
|
|
36
38
|
* Customize the theme.
|
|
@@ -50,7 +52,7 @@ declare global {
|
|
|
50
52
|
* });
|
|
51
53
|
* ```
|
|
52
54
|
*/
|
|
53
|
-
var setTheme:
|
|
55
|
+
var setTheme: Plugin['setTheme'];
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
export {};
|