kaplay-plugin-ui 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/plugin.mjs CHANGED
@@ -1,92 +1,35 @@
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;
1
+ // src/utils.ts
2
+ /**
3
+ * Convert hex string to color or return color.
4
+ *
5
+ * @param k - The Kaplay context.
6
+ * @param color - The hex string or color.
7
+ * @returns The color.
8
+ */
9
+ function toColor(k, color) {
10
+ return typeof color === "string" ? k.rgb(color) : color;
70
11
  }
71
- function createButtonObject(k, theme, text, opt) {
12
+ // src/button.ts
13
+ function createButton(k, theme, text, opt) {
72
14
  const width = opt.width ?? theme.components.button.width;
73
15
  const height = opt.height ?? theme.components.button.height;
74
16
  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;
17
+ const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);
18
+ const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);
19
+ const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);
20
+ const textColor = toColor(k, opt.textColor ?? theme.palette.text);
79
21
  const size = opt.size ?? theme.typography.fontSize;
80
22
  const font = opt.font ?? theme.typography.fontFamily;
81
23
  const pos = opt.pos ?? k.vec2();
82
- const obj = k.add([
24
+ const button = k.add([
83
25
  k.rect(width, height, radius > 0 ? { radius } : void 0),
84
26
  k.pos(pos),
85
27
  k.area(),
28
+ k.scale(),
86
29
  k.color(baseColor),
87
30
  k.anchor("center")
88
31
  ]);
89
- const label = obj.add([
32
+ const label = button.add([
90
33
  k.text(text, {
91
34
  size,
92
35
  font
@@ -94,57 +37,39 @@ function createButtonObject(k, theme, text, opt) {
94
37
  k.color(textColor),
95
38
  k.anchor("center")
96
39
  ]);
97
- let currentText = text;
98
- let currentColor = baseColor;
99
- obj.onClick(() => {
100
- obj.color = pressedColor;
40
+ button.onClick(() => {
41
+ button.color = toColor(k, pressedColor);
101
42
  opt.onClick?.();
102
43
  });
103
- obj.onHover(() => {
104
- obj.color = hoverColor;
105
- obj.scale = k.vec2(1.05, 1.05);
44
+ button.onHover(() => {
45
+ button.color = toColor(k, hoverColor);
46
+ button.scale = k.vec2(1.05, 1.05);
106
47
  k.setCursor("pointer");
107
48
  });
108
- obj.onHoverEnd(() => {
109
- obj.color = currentColor;
110
- obj.scale = k.vec2(1, 1);
49
+ button.onHoverEnd(() => {
50
+ button.color = baseColor;
51
+ button.scale = k.vec2(1, 1);
111
52
  k.setCursor("default");
112
53
  });
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);
54
+ return {
55
+ ...button,
56
+ label
130
57
  };
131
- label.text = currentText;
132
- return obj;
133
58
  }
134
59
  // 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 = {
60
+ const PRIMARY = "#4f8cff";
61
+ const TEXT = "#ffffff";
62
+ /** Default theme. */
63
+ const theme = {
139
64
  palette: {
140
- primary: DEFAULT_PRIMARY,
141
- secondary: DEFAULT_PRIMARY,
65
+ primary: PRIMARY,
66
+ secondary: PRIMARY,
142
67
  background: "#111827",
143
68
  surface: "#1f2937",
144
- text: DEFAULT_TEXT,
145
- textSecondary: DEFAULT_TEXT,
146
- hover: DEFAULT_PRIMARY,
147
- pressed: DEFAULT_PRIMARY,
69
+ text: TEXT,
70
+ textSecondary: TEXT,
71
+ hover: PRIMARY,
72
+ pressed: PRIMARY,
148
73
  disabled: "#6b7280",
149
74
  error: "#ef4444"
150
75
  },
@@ -171,7 +96,7 @@ const defaultTheme = {
171
96
  },
172
97
  tooltip: {
173
98
  background: "#111827",
174
- textColor: DEFAULT_TEXT,
99
+ textColor: TEXT,
175
100
  delay: 300
176
101
  }
177
102
  }
@@ -180,30 +105,30 @@ const defaultTheme = {
180
105
  function resolveTheme(input) {
181
106
  return {
182
107
  palette: {
183
- ...defaultTheme.palette,
108
+ ...theme.palette,
184
109
  ...input?.palette
185
110
  },
186
111
  typography: {
187
- ...defaultTheme.typography,
112
+ ...theme.typography,
188
113
  ...input?.typography
189
114
  },
190
115
  shape: {
191
- ...defaultTheme.shape,
116
+ ...theme.shape,
192
117
  ...input?.shape
193
118
  },
194
- spacing: input?.spacing ?? defaultTheme.spacing,
119
+ spacing: input?.spacing ?? theme.spacing,
195
120
  components: {
196
121
  button: {
197
- ...defaultTheme.components.button,
122
+ ...theme.components.button,
198
123
  ...input?.components?.button,
199
- width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? defaultTheme.components.button.width
124
+ width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? theme.components.button.width
200
125
  },
201
126
  modal: {
202
- ...defaultTheme.components.modal,
127
+ ...theme.components.modal,
203
128
  ...input?.components?.modal
204
129
  },
205
130
  tooltip: {
206
- ...defaultTheme.components.tooltip,
131
+ ...theme.components.tooltip,
207
132
  ...input?.components?.tooltip
208
133
  }
209
134
  }
@@ -222,19 +147,15 @@ function uiPlugin(k, theme = {}) {
222
147
  };
223
148
  currentTheme = resolveTheme(userTheme);
224
149
  };
225
- const button = (text = "", opt = {}) => {
226
- return createButtonComponent(k, currentTheme, text, opt);
227
- };
228
150
  const addButton = (text = "", opt = {}) => {
229
- return createButtonObject(k, currentTheme, text, opt);
151
+ return createButton(k, currentTheme, text, opt);
230
152
  };
231
153
  return {
232
- button,
233
154
  addButton,
234
155
  setTheme,
235
156
  getTheme
236
157
  };
237
158
  }
238
- export { createButtonComponent, createButtonObject, uiPlugin };
159
+ export { uiPlugin };
239
160
 
240
161
  //# sourceMappingURL=plugin.mjs.map
@@ -1 +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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"}
1
+ {"version":3,"file":"plugin.mjs","names":[],"sources":["../src/utils.ts","../src/button.ts","../src/theme.ts","../src/plugin.ts"],"sourcesContent":["import type { Color, KAPLAYCtx } from 'kaplay';\n\n/**\n * Convert hex string to color or return color.\n *\n * @param k - The Kaplay context.\n * @param color - The hex string or color.\n * @returns The color.\n */\nexport function toColor(k: KAPLAYCtx, color: string | Color): Color {\n return typeof color === 'string' ? k.rgb(color) : color;\n}\n","import type { Color, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport type { ButtonOpt, Theme } from './types';\nimport { toColor } from './utils';\n\nexport function createButton(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: string | Color;\n hoverColor?: string | Color;\n pressedColor?: string | Color;\n textColor?: string | Color;\n },\n) {\n const width = opt.width ?? theme.components.button.width;\n const height = opt.height ?? theme.components.button.height;\n const radius = opt.radius ?? theme.shape.borderRadius;\n const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);\n const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);\n const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);\n const textColor = toColor(k, opt.textColor ?? theme.palette.text);\n const size = opt.size ?? theme.typography.fontSize;\n const font = opt.font ?? theme.typography.fontFamily;\n const pos = opt.pos ?? k.vec2();\n\n const button = k.add([\n k.rect(width, height, radius > 0 ? { radius } : undefined),\n k.pos(pos),\n k.area(),\n k.scale(),\n k.color(baseColor),\n k.anchor('center'),\n ]);\n\n const label = button.add([\n k.text(text, { size, font }),\n k.color(textColor as never),\n k.anchor('center'),\n ]);\n\n button.onClick(() => {\n button.color = toColor(k, pressedColor);\n opt.onClick?.();\n });\n\n button.onHover(() => {\n button.color = toColor(k, hoverColor);\n button.scale = k.vec2(1.05, 1.05);\n k.setCursor('pointer');\n });\n\n button.onHoverEnd(() => {\n button.color = baseColor;\n button.scale = k.vec2(1, 1);\n k.setCursor('default');\n });\n\n return {\n ...button,\n label,\n };\n}\n","import type { DeepPartial, Theme } from './types';\n\nconst PRIMARY = '#4f8cff';\nconst TEXT = '#ffffff';\n\n/** Default theme. */\nconst theme: Theme = {\n palette: {\n primary: PRIMARY,\n secondary: PRIMARY,\n background: '#111827',\n surface: '#1f2937',\n text: TEXT,\n textSecondary: TEXT,\n hover: PRIMARY,\n pressed: PRIMARY,\n disabled: '#6b7280',\n error: '#ef4444',\n },\n typography: {\n fontFamily: 'sans-serif',\n fontSize: 18,\n fontWeight: 400,\n lineHeight: 1.2,\n },\n shape: {\n borderRadius: 0,\n },\n spacing: 8,\n components: {\n button: {\n width: 120,\n height: 40,\n minWidth: 120,\n paddingX: 12,\n paddingY: 8,\n textTransform: 'none',\n },\n modal: {\n backdropOpacity: 0.5,\n borderRadius: 8,\n },\n tooltip: {\n background: '#111827',\n textColor: TEXT,\n delay: 300,\n },\n },\n};\n\n/** Resolve a partial theme into a fully resolved theme. */\nexport function resolveTheme(input?: DeepPartial<Theme>): Theme {\n return {\n palette: { ...theme.palette, ...input?.palette },\n typography: { ...theme.typography, ...input?.typography },\n shape: { ...theme.shape, ...input?.shape },\n spacing: input?.spacing ?? theme.spacing,\n components: {\n button: {\n ...theme.components.button,\n ...input?.components?.button,\n width:\n input?.components?.button?.width ??\n input?.components?.button?.minWidth ??\n theme.components.button.width,\n },\n modal: {\n ...theme.components.modal,\n ...input?.components?.modal,\n },\n tooltip: {\n ...theme.components.tooltip,\n ...input?.components?.tooltip,\n },\n },\n };\n}\n","import type { 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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"}
@@ -2,95 +2,38 @@
2
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
3
  })(this, function(exports) {
4
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;
5
+ // src/utils.ts
6
+ /**
7
+ * Convert hex string to color or return color.
8
+ *
9
+ * @param k - The Kaplay context.
10
+ * @param color - The hex string or color.
11
+ * @returns The color.
12
+ */
13
+ function toColor(k, color) {
14
+ return typeof color === "string" ? k.rgb(color) : color;
74
15
  }
75
- function createButtonObject(k, theme, text, opt) {
16
+ // src/button.ts
17
+ function createButton(k, theme, text, opt) {
76
18
  const width = opt.width ?? theme.components.button.width;
77
19
  const height = opt.height ?? theme.components.button.height;
78
20
  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;
21
+ const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);
22
+ const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);
23
+ const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);
24
+ const textColor = toColor(k, opt.textColor ?? theme.palette.text);
83
25
  const size = opt.size ?? theme.typography.fontSize;
84
26
  const font = opt.font ?? theme.typography.fontFamily;
85
27
  const pos = opt.pos ?? k.vec2();
86
- const obj = k.add([
28
+ const button = k.add([
87
29
  k.rect(width, height, radius > 0 ? { radius } : void 0),
88
30
  k.pos(pos),
89
31
  k.area(),
32
+ k.scale(),
90
33
  k.color(baseColor),
91
34
  k.anchor("center")
92
35
  ]);
93
- const label = obj.add([
36
+ const label = button.add([
94
37
  k.text(text, {
95
38
  size,
96
39
  font
@@ -98,57 +41,39 @@
98
41
  k.color(textColor),
99
42
  k.anchor("center")
100
43
  ]);
101
- let currentText = text;
102
- let currentColor = baseColor;
103
- obj.onClick(() => {
104
- obj.color = pressedColor;
44
+ button.onClick(() => {
45
+ button.color = toColor(k, pressedColor);
105
46
  opt.onClick?.();
106
47
  });
107
- obj.onHover(() => {
108
- obj.color = hoverColor;
109
- obj.scale = k.vec2(1.05, 1.05);
48
+ button.onHover(() => {
49
+ button.color = toColor(k, hoverColor);
50
+ button.scale = k.vec2(1.05, 1.05);
110
51
  k.setCursor("pointer");
111
52
  });
112
- obj.onHoverEnd(() => {
113
- obj.color = currentColor;
114
- obj.scale = k.vec2(1, 1);
53
+ button.onHoverEnd(() => {
54
+ button.color = baseColor;
55
+ button.scale = k.vec2(1, 1);
115
56
  k.setCursor("default");
116
57
  });
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);
58
+ return {
59
+ ...button,
60
+ label
134
61
  };
135
- label.text = currentText;
136
- return obj;
137
62
  }
138
63
  // 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 = {
64
+ const PRIMARY = "#4f8cff";
65
+ const TEXT = "#ffffff";
66
+ /** Default theme. */
67
+ const theme = {
143
68
  palette: {
144
- primary: DEFAULT_PRIMARY,
145
- secondary: DEFAULT_PRIMARY,
69
+ primary: PRIMARY,
70
+ secondary: PRIMARY,
146
71
  background: "#111827",
147
72
  surface: "#1f2937",
148
- text: DEFAULT_TEXT,
149
- textSecondary: DEFAULT_TEXT,
150
- hover: DEFAULT_PRIMARY,
151
- pressed: DEFAULT_PRIMARY,
73
+ text: TEXT,
74
+ textSecondary: TEXT,
75
+ hover: PRIMARY,
76
+ pressed: PRIMARY,
152
77
  disabled: "#6b7280",
153
78
  error: "#ef4444"
154
79
  },
@@ -175,7 +100,7 @@
175
100
  },
176
101
  tooltip: {
177
102
  background: "#111827",
178
- textColor: DEFAULT_TEXT,
103
+ textColor: TEXT,
179
104
  delay: 300
180
105
  }
181
106
  }
@@ -184,30 +109,30 @@
184
109
  function resolveTheme(input) {
185
110
  return {
186
111
  palette: {
187
- ...defaultTheme.palette,
112
+ ...theme.palette,
188
113
  ...input?.palette
189
114
  },
190
115
  typography: {
191
- ...defaultTheme.typography,
116
+ ...theme.typography,
192
117
  ...input?.typography
193
118
  },
194
119
  shape: {
195
- ...defaultTheme.shape,
120
+ ...theme.shape,
196
121
  ...input?.shape
197
122
  },
198
- spacing: input?.spacing ?? defaultTheme.spacing,
123
+ spacing: input?.spacing ?? theme.spacing,
199
124
  components: {
200
125
  button: {
201
- ...defaultTheme.components.button,
126
+ ...theme.components.button,
202
127
  ...input?.components?.button,
203
- width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? defaultTheme.components.button.width
128
+ width: input?.components?.button?.width ?? input?.components?.button?.minWidth ?? theme.components.button.width
204
129
  },
205
130
  modal: {
206
- ...defaultTheme.components.modal,
131
+ ...theme.components.modal,
207
132
  ...input?.components?.modal
208
133
  },
209
134
  tooltip: {
210
- ...defaultTheme.components.tooltip,
135
+ ...theme.components.tooltip,
211
136
  ...input?.components?.tooltip
212
137
  }
213
138
  }
@@ -226,21 +151,15 @@
226
151
  };
227
152
  currentTheme = resolveTheme(userTheme);
228
153
  };
229
- const button = (text = "", opt = {}) => {
230
- return createButtonComponent(k, currentTheme, text, opt);
231
- };
232
154
  const addButton = (text = "", opt = {}) => {
233
- return createButtonObject(k, currentTheme, text, opt);
155
+ return createButton(k, currentTheme, text, opt);
234
156
  };
235
157
  return {
236
- button,
237
158
  addButton,
238
159
  setTheme,
239
160
  getTheme
240
161
  };
241
162
  }
242
- exports.createButtonComponent = createButtonComponent;
243
- exports.createButtonObject = createButtonObject;
244
163
  exports.uiPlugin = uiPlugin;
245
164
  });
246
165
 
@@ -1 +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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"}
1
+ {"version":3,"file":"plugin.umd.js","names":[],"sources":["../src/utils.ts","../src/button.ts","../src/theme.ts","../src/plugin.ts"],"sourcesContent":["import type { Color, KAPLAYCtx } from 'kaplay';\n\n/**\n * Convert hex string to color or return color.\n *\n * @param k - The Kaplay context.\n * @param color - The hex string or color.\n * @returns The color.\n */\nexport function toColor(k: KAPLAYCtx, color: string | Color): Color {\n return typeof color === 'string' ? k.rgb(color) : color;\n}\n","import type { Color, KAPLAYCtx, Vec2 } from 'kaplay';\n\nimport type { ButtonOpt, Theme } from './types';\nimport { toColor } from './utils';\n\nexport function createButton(\n k: KAPLAYCtx,\n theme: Theme,\n text: string,\n opt: ButtonOpt & {\n pos?: Vec2;\n onClick?: () => void;\n color?: string | Color;\n hoverColor?: string | Color;\n pressedColor?: string | Color;\n textColor?: string | Color;\n },\n) {\n const width = opt.width ?? theme.components.button.width;\n const height = opt.height ?? theme.components.button.height;\n const radius = opt.radius ?? theme.shape.borderRadius;\n const baseColor = toColor(k, opt.color ?? opt.fill ?? theme.palette.primary);\n const hoverColor = toColor(k, opt.hoverColor ?? theme.palette.hover);\n const pressedColor = toColor(k, opt.pressedColor ?? theme.palette.pressed);\n const textColor = toColor(k, opt.textColor ?? theme.palette.text);\n const size = opt.size ?? theme.typography.fontSize;\n const font = opt.font ?? theme.typography.fontFamily;\n const pos = opt.pos ?? k.vec2();\n\n const button = k.add([\n k.rect(width, height, radius > 0 ? { radius } : undefined),\n k.pos(pos),\n k.area(),\n k.scale(),\n k.color(baseColor),\n k.anchor('center'),\n ]);\n\n const label = button.add([\n k.text(text, { size, font }),\n k.color(textColor as never),\n k.anchor('center'),\n ]);\n\n button.onClick(() => {\n button.color = toColor(k, pressedColor);\n opt.onClick?.();\n });\n\n button.onHover(() => {\n button.color = toColor(k, hoverColor);\n button.scale = k.vec2(1.05, 1.05);\n k.setCursor('pointer');\n });\n\n button.onHoverEnd(() => {\n button.color = baseColor;\n button.scale = k.vec2(1, 1);\n k.setCursor('default');\n });\n\n return {\n ...button,\n label,\n };\n}\n","import type { DeepPartial, Theme } from './types';\n\nconst PRIMARY = '#4f8cff';\nconst TEXT = '#ffffff';\n\n/** Default theme. */\nconst theme: Theme = {\n palette: {\n primary: PRIMARY,\n secondary: PRIMARY,\n background: '#111827',\n surface: '#1f2937',\n text: TEXT,\n textSecondary: TEXT,\n hover: PRIMARY,\n pressed: PRIMARY,\n disabled: '#6b7280',\n error: '#ef4444',\n },\n typography: {\n fontFamily: 'sans-serif',\n fontSize: 18,\n fontWeight: 400,\n lineHeight: 1.2,\n },\n shape: {\n borderRadius: 0,\n },\n spacing: 8,\n components: {\n button: {\n width: 120,\n height: 40,\n minWidth: 120,\n paddingX: 12,\n paddingY: 8,\n textTransform: 'none',\n },\n modal: {\n backdropOpacity: 0.5,\n borderRadius: 8,\n },\n tooltip: {\n background: '#111827',\n textColor: TEXT,\n delay: 300,\n },\n },\n};\n\n/** Resolve a partial theme into a fully resolved theme. */\nexport function resolveTheme(input?: DeepPartial<Theme>): Theme {\n return {\n palette: { ...theme.palette, ...input?.palette },\n typography: { ...theme.typography, ...input?.typography },\n shape: { ...theme.shape, ...input?.shape },\n spacing: input?.spacing ?? theme.spacing,\n components: {\n button: {\n ...theme.components.button,\n ...input?.components?.button,\n width:\n input?.components?.button?.width ??\n input?.components?.button?.minWidth ??\n theme.components.button.width,\n },\n modal: {\n ...theme.components.modal,\n ...input?.components?.modal,\n },\n tooltip: {\n ...theme.components.tooltip,\n ...input?.components?.tooltip,\n },\n },\n };\n}\n","import type { 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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"}
@@ -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,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});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.KaplayPluginUI={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e,t){return typeof t==`string`?e.rgb(t):t}function n(e,n,r,i){let a=i.width??n.components.button.width,o=i.height??n.components.button.height,s=i.radius??n.shape.borderRadius,c=t(e,i.color??i.fill??n.palette.primary),l=t(e,i.hoverColor??n.palette.hover),u=t(e,i.pressedColor??n.palette.pressed),d=t(e,i.textColor??n.palette.text),f=i.size??n.typography.fontSize,p=i.font??n.typography.fontFamily,m=i.pos??e.vec2(),h=e.add([e.rect(a,o,s>0?{radius:s}:void 0),e.pos(m),e.area(),e.scale(),e.color(c),e.anchor(`center`)]),g=h.add([e.text(r,{size:f,font:p}),e.color(d),e.anchor(`center`)]);return h.onClick(()=>{h.color=t(e,u),i.onClick?.()}),h.onHover(()=>{h.color=t(e,l),h.scale=e.vec2(1.05,1.05),e.setCursor(`pointer`)}),h.onHoverEnd(()=>{h.color=c,h.scale=e.vec2(1,1),e.setCursor(`default`)}),{...h,label:g}}let r=`#4f8cff`,i=`#ffffff`,a={palette:{primary:r,secondary:r,background:`#111827`,surface:`#1f2937`,text:i,textSecondary:i,hover:r,pressed:r,disabled:`#6b7280`,error:`#ef4444`},typography:{fontFamily:`sans-serif`,fontSize:18,fontWeight:400,lineHeight:1.2},shape:{borderRadius:0},spacing:8,components:{button:{width:120,height:40,minWidth:120,paddingX:12,paddingY:8,textTransform:`none`},modal:{backdropOpacity:.5,borderRadius:8},tooltip:{background:`#111827`,textColor:i,delay:300}}};function o(e){return{palette:{...a.palette,...e?.palette},typography:{...a.typography,...e?.typography},shape:{...a.shape,...e?.shape},spacing:e?.spacing??a.spacing,components:{button:{...a.components.button,...e?.components?.button,width:e?.components?.button?.width??e?.components?.button?.minWidth??a.components.button.width},modal:{...a.components.modal,...e?.components?.modal},tooltip:{...a.components.tooltip,...e?.components?.tooltip}}}}function s(e,t={}){let r=t,i=o(r);return{addButton:(t=``,r={})=>n(e,i,t,r),setTheme:e=>{r={...r,...e},i=o(r)},getTheme:()=>i}}e.uiPlugin=s});
2
2
  //# sourceMappingURL=plugin.umd.min.js.map