hudini 0.17.2 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/components/card/card.d.ts +34 -9
  2. package/dist/components/card/card.d.ts.map +1 -1
  3. package/dist/components/card/card.js +118 -49
  4. package/dist/components/card/card.js.map +1 -1
  5. package/dist/components/card/card.spec.js +28 -1
  6. package/dist/components/card/card.spec.js.map +1 -1
  7. package/dist/components/circular-progress/circular-progress.d.ts +4 -4
  8. package/dist/components/circular-progress/circular-progress.d.ts.map +1 -1
  9. package/dist/components/circular-progress/circular-progress.js +9 -8
  10. package/dist/components/circular-progress/circular-progress.js.map +1 -1
  11. package/dist/components/circular-progress/circular-progress.spec.js +4 -4
  12. package/dist/components/circular-progress/circular-progress.spec.js.map +1 -1
  13. package/dist/components/container-interactive/container-interactive.d.ts +65 -0
  14. package/dist/components/container-interactive/container-interactive.d.ts.map +1 -0
  15. package/dist/components/container-interactive/container-interactive.js +99 -0
  16. package/dist/components/container-interactive/container-interactive.js.map +1 -0
  17. package/dist/components/container-interactive/index.d.ts +2 -0
  18. package/dist/components/container-interactive/index.d.ts.map +1 -0
  19. package/dist/components/container-interactive/index.js +2 -0
  20. package/dist/components/container-interactive/index.js.map +1 -0
  21. package/dist/components/flat-icon-button/flat-icon-button.d.ts +3 -0
  22. package/dist/components/flat-icon-button/flat-icon-button.d.ts.map +1 -1
  23. package/dist/components/flat-icon-button/flat-icon-button.js +111 -20
  24. package/dist/components/flat-icon-button/flat-icon-button.js.map +1 -1
  25. package/dist/components/flat-section-header/flat-section-header.d.ts +143 -0
  26. package/dist/components/flat-section-header/flat-section-header.d.ts.map +1 -0
  27. package/dist/components/flat-section-header/flat-section-header.js +275 -0
  28. package/dist/components/flat-section-header/flat-section-header.js.map +1 -0
  29. package/dist/components/flat-section-header/flat-section-header.spec.d.ts +2 -0
  30. package/dist/components/flat-section-header/flat-section-header.spec.d.ts.map +1 -0
  31. package/dist/components/flat-section-header/flat-section-header.spec.js +255 -0
  32. package/dist/components/flat-section-header/flat-section-header.spec.js.map +1 -0
  33. package/dist/components/flat-section-header/index.d.ts +2 -0
  34. package/dist/components/flat-section-header/index.d.ts.map +1 -0
  35. package/dist/components/flat-section-header/index.js +2 -0
  36. package/dist/components/flat-section-header/index.js.map +1 -0
  37. package/dist/components/flat-text-button/flat-text-button.d.ts +165 -0
  38. package/dist/components/flat-text-button/flat-text-button.d.ts.map +1 -0
  39. package/dist/components/flat-text-button/flat-text-button.js +325 -0
  40. package/dist/components/flat-text-button/flat-text-button.js.map +1 -0
  41. package/dist/components/flat-text-button/flat-text-button.spec.d.ts +2 -0
  42. package/dist/components/flat-text-button/flat-text-button.spec.d.ts.map +1 -0
  43. package/dist/components/flat-text-button/flat-text-button.spec.js +243 -0
  44. package/dist/components/flat-text-button/flat-text-button.spec.js.map +1 -0
  45. package/dist/components/flat-text-button/index.d.ts +2 -0
  46. package/dist/components/flat-text-button/index.d.ts.map +1 -0
  47. package/dist/components/flat-text-button/index.js +2 -0
  48. package/dist/components/flat-text-button/index.js.map +1 -0
  49. package/dist/components/icon-button/icon-button.d.ts +11 -3
  50. package/dist/components/icon-button/icon-button.d.ts.map +1 -1
  51. package/dist/components/icon-button/icon-button.js +126 -71
  52. package/dist/components/icon-button/icon-button.js.map +1 -1
  53. package/dist/components/index.d.ts +4 -0
  54. package/dist/components/index.d.ts.map +1 -1
  55. package/dist/components/index.js +4 -0
  56. package/dist/components/index.js.map +1 -1
  57. package/dist/components/panel/panel.d.ts +0 -1
  58. package/dist/components/panel/panel.d.ts.map +1 -1
  59. package/dist/components/panel/panel.js +7 -10
  60. package/dist/components/panel/panel.js.map +1 -1
  61. package/dist/components/section-header/section-header.d.ts +33 -39
  62. package/dist/components/section-header/section-header.d.ts.map +1 -1
  63. package/dist/components/section-header/section-header.js +124 -155
  64. package/dist/components/section-header/section-header.js.map +1 -1
  65. package/dist/components/section-header/section-header.spec.js +57 -17
  66. package/dist/components/section-header/section-header.spec.js.map +1 -1
  67. package/dist/components/text/index.d.ts +2 -0
  68. package/dist/components/text/index.d.ts.map +1 -0
  69. package/dist/components/text/index.js +2 -0
  70. package/dist/components/text/index.js.map +1 -0
  71. package/dist/components/text/text.d.ts +45 -0
  72. package/dist/components/text/text.d.ts.map +1 -0
  73. package/dist/components/text/text.js +35 -0
  74. package/dist/components/text/text.js.map +1 -0
  75. package/dist/components/text-button/text-button.d.ts +26 -23
  76. package/dist/components/text-button/text-button.d.ts.map +1 -1
  77. package/dist/components/text-button/text-button.js +114 -88
  78. package/dist/components/text-button/text-button.js.map +1 -1
  79. package/dist/components/text-button/text-button.spec.js +108 -9
  80. package/dist/components/text-button/text-button.spec.js.map +1 -1
  81. package/dist/hudini.js +4220 -467
  82. package/dist/hudini.min.js +1 -1
  83. package/dist/index.d.ts +1 -0
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +1 -0
  86. package/dist/index.js.map +1 -1
  87. package/dist/loaders/index.d.ts +2 -0
  88. package/dist/loaders/index.d.ts.map +1 -0
  89. package/dist/loaders/index.js +2 -0
  90. package/dist/loaders/index.js.map +1 -0
  91. package/dist/loaders/load-fonts.d.ts +8 -0
  92. package/dist/loaders/load-fonts.d.ts.map +1 -0
  93. package/dist/loaders/load-fonts.js +41 -0
  94. package/dist/loaders/load-fonts.js.map +1 -0
  95. package/dist/test-setup.js +8 -2
  96. package/dist/test-setup.js.map +1 -1
  97. package/dist/utils/color-variants.d.ts +43 -0
  98. package/dist/utils/color-variants.d.ts.map +1 -0
  99. package/dist/utils/color-variants.js +72 -0
  100. package/dist/utils/color-variants.js.map +1 -0
  101. package/dist/utils/index.d.ts +1 -0
  102. package/dist/utils/index.d.ts.map +1 -1
  103. package/dist/utils/index.js +1 -0
  104. package/dist/utils/index.js.map +1 -1
  105. package/package.json +3 -3
@@ -0,0 +1,243 @@
1
+ /* eslint-disable sonarjs/no-duplicate-string */
2
+ /* eslint-disable max-lines-per-function */
3
+ /* eslint-disable no-magic-numbers */
4
+ import { Scene } from 'phaser';
5
+ import { describe, expect, it, vi } from 'vitest';
6
+ // Mock phaser-wind
7
+ vi.mock('phaser-wind', () => ({
8
+ Color: {
9
+ rgb: vi.fn((color) => `rgb-${color}`),
10
+ hex: vi.fn((color) => `hex-${color}`),
11
+ },
12
+ }));
13
+ // Mock the getPWFromScene utility
14
+ vi.mock('../../utils/get-pw-from-scene', () => ({
15
+ getPWFromScene: vi.fn(() => ({
16
+ fontSize: {
17
+ px: vi.fn((size) => {
18
+ const sizes = { xs: 12, sm: 14, md: 16, lg: 18, xl: 20 };
19
+ return sizes[size] || 16;
20
+ }),
21
+ },
22
+ spacing: {
23
+ px: vi.fn((spacing) => {
24
+ const spacings = { xs: 4, sm: 8, md: 12, lg: 16, xl: 20 };
25
+ return spacings[spacing] || 12;
26
+ }),
27
+ },
28
+ radius: {
29
+ px: vi.fn((radius) => {
30
+ const radiuses = { none: 0, sm: 4, md: 8, lg: 12, xl: 16, full: 9999 };
31
+ return radiuses[radius] || 8;
32
+ }),
33
+ },
34
+ font: {
35
+ family: vi.fn((font) => {
36
+ const fonts = {
37
+ sans: 'Arial, sans-serif',
38
+ serif: 'Georgia, serif',
39
+ mono: 'Courier, monospace',
40
+ };
41
+ return fonts[font] || 'Arial, sans-serif';
42
+ }),
43
+ },
44
+ })),
45
+ }));
46
+ // Mock the Text component
47
+ vi.mock('../text', () => {
48
+ class MockText {
49
+ text;
50
+ style;
51
+ constructor(params) {
52
+ this.text = params.text;
53
+ this.style = {
54
+ fontSize: params.size ?? 22,
55
+ fontFamily: params.fontFamily ?? 'Bebas Neue',
56
+ };
57
+ }
58
+ setText(text) {
59
+ this.text = text;
60
+ return this;
61
+ }
62
+ setOrigin() {
63
+ return this;
64
+ }
65
+ setFontSize(size) {
66
+ this.style['fontSize'] = size;
67
+ return this;
68
+ }
69
+ setFontFamily(family) {
70
+ this.style['fontFamily'] = family;
71
+ return this;
72
+ }
73
+ setColor(color) {
74
+ this.style['color'] = color;
75
+ return this;
76
+ }
77
+ getBounds() {
78
+ return getTextBounds(this.text, this.style['fontSize'] ?? 16);
79
+ }
80
+ }
81
+ return { Text: MockText };
82
+ });
83
+ // Helper function for getBounds
84
+ const getTextBounds = (text, fontSize) => {
85
+ const charWidth = 10;
86
+ const lineHeight = parseInt(String(fontSize)) || 16;
87
+ return {
88
+ width: text.length * charWidth,
89
+ height: lineHeight,
90
+ };
91
+ };
92
+ // Mock Phaser
93
+ vi.mock('phaser', () => {
94
+ class MockText {
95
+ text;
96
+ style;
97
+ constructor(_x, _y, text, style) {
98
+ this.text = text;
99
+ this.style = style;
100
+ }
101
+ setText(text) {
102
+ this.text = text;
103
+ return this;
104
+ }
105
+ setOrigin() {
106
+ return this;
107
+ }
108
+ setFontSize(size) {
109
+ this.style['fontSize'] = size;
110
+ return this;
111
+ }
112
+ setFontFamily(family) {
113
+ this.style['fontFamily'] = family;
114
+ return this;
115
+ }
116
+ setColor(color) {
117
+ this.style['color'] = color;
118
+ return this;
119
+ }
120
+ getBounds() {
121
+ return getTextBounds(this.text, this.style['fontSize'] ?? 16);
122
+ }
123
+ }
124
+ class MockSprite {
125
+ // eslint-disable-next-line no-unused-vars
126
+ constructor(_x, _y, _texture) { }
127
+ setOrigin() {
128
+ return this;
129
+ }
130
+ setInteractive() {
131
+ return this;
132
+ }
133
+ setTexture() {
134
+ return this;
135
+ }
136
+ on() {
137
+ return this;
138
+ }
139
+ }
140
+ class MockGraphics {
141
+ fillStyle() {
142
+ return this;
143
+ }
144
+ fillRoundedRect() {
145
+ return this;
146
+ }
147
+ lineStyle() {
148
+ return this;
149
+ }
150
+ strokeRoundedRect() {
151
+ return this;
152
+ }
153
+ generateTexture() {
154
+ return this;
155
+ }
156
+ destroy() {
157
+ return this;
158
+ }
159
+ }
160
+ class MockContainer {
161
+ // eslint-disable-next-line no-unused-vars
162
+ constructor(_scene, _x, _y) {
163
+ this.scene = _scene;
164
+ }
165
+ add() {
166
+ return this;
167
+ }
168
+ scene;
169
+ }
170
+ class Scene {
171
+ add = {
172
+ text: vi.fn((x, y, text, style) => new MockText(x, y, text, style)),
173
+ sprite: vi.fn((x, y, texture) => new MockSprite(x, y, texture)),
174
+ graphics: vi.fn(() => new MockGraphics()),
175
+ };
176
+ tweens = { add: vi.fn() };
177
+ }
178
+ class BasePlugin {
179
+ constructor() { }
180
+ }
181
+ const GameObjects = { Container: MockContainer };
182
+ const Plugins = { BasePlugin };
183
+ return { GameObjects, Scene, Plugins };
184
+ });
185
+ import { FlatTextButton } from './flat-text-button';
186
+ describe('FlatTextButton', () => {
187
+ it('should create a FlatTextButton instance', () => {
188
+ const scene = new Scene();
189
+ const textButton = new FlatTextButton({
190
+ scene,
191
+ x: 100,
192
+ y: 100,
193
+ text: 'Click Me',
194
+ });
195
+ expect(textButton).toBeInstanceOf(FlatTextButton);
196
+ });
197
+ it('should create with custom properties', () => {
198
+ const scene = new Scene();
199
+ const textButton = new FlatTextButton({
200
+ scene,
201
+ x: 100,
202
+ y: 100,
203
+ text: 'Custom Button',
204
+ fontSize: 'lg',
205
+ color: 'red',
206
+ textColor: 'white',
207
+ borderRadius: 'lg',
208
+ padding: '4',
209
+ });
210
+ expect(textButton).toBeInstanceOf(FlatTextButton);
211
+ });
212
+ it('should support method chaining', () => {
213
+ const scene = new Scene();
214
+ const textButton = new FlatTextButton({
215
+ scene,
216
+ x: 100,
217
+ y: 100,
218
+ text: 'Test',
219
+ });
220
+ const result = textButton
221
+ .setText('Chained')
222
+ .setFontSize('lg')
223
+ .setColor('green')
224
+ .setBorderRadius('lg')
225
+ .setPadding('4');
226
+ expect(result).toBe(textButton);
227
+ });
228
+ it('should handle borderRadius full correctly', () => {
229
+ const scene = new Scene();
230
+ const textButton = new FlatTextButton({
231
+ scene,
232
+ x: 100,
233
+ y: 100,
234
+ text: 'Full Radius Test',
235
+ borderRadius: 'full',
236
+ });
237
+ expect(textButton).toBeInstanceOf(FlatTextButton);
238
+ // Test setBorderRadius with 'full'
239
+ const result = textButton.setBorderRadius('full');
240
+ expect(result).toBe(textButton);
241
+ });
242
+ });
243
+ //# sourceMappingURL=flat-text-button.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flat-text-button.spec.js","sourceRoot":"","sources":["../../../src/components/flat-text-button/flat-text-button.spec.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,2CAA2C;AAC3C,qCAAqC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,mBAAmB;AACnB,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5B,KAAK,EAAE;QACL,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,KAAa,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,CAAC;QAC7C,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,KAAa,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,CAAC;KAC9C;CACF,CAAC,CAAC,CAAC;AAEJ,kCAAkC;AAClC,EAAE,CAAC,IAAI,CAAC,+BAA+B,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9C,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3B,QAAQ,EAAE;YACR,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAY,EAAE,EAAE;gBACzB,MAAM,KAAK,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBACzD,OAAO,KAAK,CAAC,IAA0B,CAAC,IAAI,EAAE,CAAC;YACjD,CAAC,CAAC;SACH;QACD,OAAO,EAAE;YACP,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,OAAe,EAAE,EAAE;gBAC5B,MAAM,QAAQ,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;gBAC1D,OAAO,QAAQ,CAAC,OAAgC,CAAC,IAAI,EAAE,CAAC;YAC1D,CAAC,CAAC;SACH;QACD,MAAM,EAAE;YACN,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,MAAc,EAAE,EAAE;gBAC3B,MAAM,QAAQ,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;gBACvE,OAAO,QAAQ,CAAC,MAA+B,CAAC,IAAI,CAAC,CAAC;YACxD,CAAC,CAAC;SACH;QACD,IAAI,EAAE;YACJ,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,IAAY,EAAE,EAAE;gBAC7B,MAAM,KAAK,GAAG;oBACZ,IAAI,EAAE,mBAAmB;oBACzB,KAAK,EAAE,gBAAgB;oBACvB,IAAI,EAAE,oBAAoB;iBAC3B,CAAC;gBACF,OAAO,KAAK,CAAC,IAA0B,CAAC,IAAI,mBAAmB,CAAC;YAClE,CAAC,CAAC;SACH;KACF,CAAC,CAAC;CACJ,CAAC,CAAC,CAAC;AAEJ,0BAA0B;AAC1B,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;IACtB,MAAM,QAAQ;QACJ,IAAI,CAAS;QACb,KAAK,CAAkC;QAE/C,YAAY,MAAkG;YAC5G,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG;gBACX,QAAQ,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE;gBAC3B,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,YAAY;aAC9C,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,IAAY;YAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,SAAS;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,WAAW,CAAC,IAAY;YACtB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,aAAa,CAAC,MAAc;YAC1B,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC;YAClC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,QAAQ,CAAC,KAAa;YACpB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;YAC5B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,SAAS;YACP,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;KACF;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEH,gCAAgC;AAChC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,QAAyB,EAAqC,EAAE;IACnG,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,MAAM,GAAG,SAAS;QAC9B,MAAM,EAAE,UAAU;KACnB,CAAC;AACJ,CAAC,CAAC;AAEF,cAAc;AACd,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE;IACrB,MAAM,QAAQ;QACJ,IAAI,CAAS;QACb,KAAK,CAAkC;QAE/C,YACE,EAAU,EACV,EAAU,EACV,IAAY,EACZ,KAAsC;YAEtC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,CAAC;QAED,OAAO,CAAC,IAAY;YAClB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,SAAS;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,WAAW,CAAC,IAAY;YACtB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,aAAa,CAAC,MAAc;YAC1B,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC;YAClC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,QAAQ,CAAC,KAAa;YACpB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;YAC5B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,SAAS;YACP,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;KACF;IAED,MAAM,UAAU;QACd,0CAA0C;QAC1C,YAAY,EAAU,EAAE,EAAU,EAAE,QAAgB,IAAI,CAAC;QACzD,SAAS;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,cAAc;YACZ,OAAO,IAAI,CAAC;QACd,CAAC;QACD,UAAU;YACR,OAAO,IAAI,CAAC;QACd,CAAC;QACD,EAAE;YACA,OAAO,IAAI,CAAC;QACd,CAAC;KACF;IAED,MAAM,YAAY;QAChB,SAAS;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,eAAe;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QACD,SAAS;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,iBAAiB;YACf,OAAO,IAAI,CAAC;QACd,CAAC;QACD,eAAe;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO;YACL,OAAO,IAAI,CAAC;QACd,CAAC;KACF;IAED,MAAM,aAAa;QACjB,0CAA0C;QAC1C,YAAY,MAAa,EAAE,EAAU,EAAE,EAAU;YAC/C,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;QACtB,CAAC;QACD,GAAG;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,CAAQ;KACd;IAED,MAAM,KAAK;QACT,GAAG,GAAG;YACJ,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YACnE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;YAC/D,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC;SAC1C,CAAC;QACF,MAAM,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;KAC3B;IAED,MAAM,UAAU;QACd,gBAAgB,CAAC;KAClB;IAED,MAAM,WAAW,GAAG,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC;IACjD,MAAM,OAAO,GAAG,EAAE,UAAU,EAAE,CAAC;IAC/B,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACzC,CAAC,CAAC,CAAC;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QAE1B,MAAM,UAAU,GAAG,IAAI,cAAc,CAAC;YACpC,KAAK;YACL,CAAC,EAAE,GAAG;YACN,CAAC,EAAE,GAAG;YACN,IAAI,EAAE,UAAU;SACjB,CAAC,CAAC;QAEH,MAAM,CAAC,UAAU,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QAE1B,MAAM,UAAU,GAAG,IAAI,cAAc,CAAC;YACpC,KAAK;YACL,CAAC,EAAE,GAAG;YACN,CAAC,EAAE,GAAG;YACN,IAAI,EAAE,eAAe;YACrB,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,KAAK;YACZ,SAAS,EAAE,OAAO;YAClB,YAAY,EAAE,IAAI;YAClB,OAAO,EAAE,GAAG;SACb,CAAC,CAAC;QAEH,MAAM,CAAC,UAAU,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,IAAI,cAAc,CAAC;YACpC,KAAK;YACL,CAAC,EAAE,GAAG;YACN,CAAC,EAAE,GAAG;YACN,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,UAAU;aACtB,OAAO,CAAC,SAAS,CAAC;aAClB,WAAW,CAAC,IAAI,CAAC;aACjB,QAAQ,CAAC,OAAO,CAAC;aACjB,eAAe,CAAC,IAAI,CAAC;aACrB,UAAU,CAAC,GAAG,CAAC,CAAC;QAEnB,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QAE1B,MAAM,UAAU,GAAG,IAAI,cAAc,CAAC;YACpC,KAAK;YACL,CAAC,EAAE,GAAG;YACN,CAAC,EAAE,GAAG;YACN,IAAI,EAAE,kBAAkB;YACxB,YAAY,EAAE,MAAM;SACrB,CAAC,CAAC;QAEH,MAAM,CAAC,UAAU,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;QAElD,mCAAmC;QACnC,MAAM,MAAM,GAAG,UAAU,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './flat-text-button';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/flat-text-button/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './flat-text-button';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/flat-text-button/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC"}
@@ -14,20 +14,28 @@ export type IconButtonParams = {
14
14
  };
15
15
  export declare class IconButton extends GameObjects.Container {
16
16
  backgroundSprite: GameObjects.Sprite;
17
- shadowSprite: GameObjects.Sprite;
17
+ whiteBorderSprite: GameObjects.Sprite;
18
18
  iconText: IconText;
19
19
  private pw;
20
20
  private baseColor;
21
+ private colorButton;
22
+ private lightColorButton;
23
+ private darkColorButton;
21
24
  private sizePx;
22
25
  private borderRadiusPx;
23
26
  constructor({ scene, x, y, icon, size, color, onClick, borderRadius, }: IconButtonParams);
24
27
  setBorderRadius(borderRadius: RadiusKey | number): this;
25
28
  setButtonSize(size: FontSizeKey | number): this;
26
- private createShadowSprite;
27
- private createShadowTexture;
28
29
  private updateSize;
30
+ private createWhiteBorderSprite;
29
31
  private createBackgroundSprite;
32
+ private createWhiteBorderTexture;
30
33
  private createBackgroundTexture;
34
+ /**
35
+ * Draws gradient using a centered light overlay on CSS color.
36
+ * For round buttons, uses a smaller centered graphic with light color.
37
+ */
38
+ private drawCssColorGradient;
31
39
  private createIconText;
32
40
  private setupContainer;
33
41
  private setupInteractivity;
@@ -1 +1 @@
1
- {"version":3,"file":"icon-button.d.ts","sourceRoot":"","sources":["../../../src/components/icon-button/icon-button.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAIrB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,+FAA+F;IAC/F,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CACnC,CAAC;AAkBF,qBAAa,UAAW,SAAQ,WAAW,CAAC,SAAS;IAC5C,gBAAgB,EAAG,WAAW,CAAC,MAAM,CAAC;IACtC,YAAY,EAAG,WAAW,CAAC,MAAM,CAAC;IAClC,QAAQ,EAAG,QAAQ,CAAC;IAE3B,OAAO,CAAC,EAAE,CAAuB;IACjC,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,cAAc,CAAU;gBAEpB,EACV,KAAK,EACL,CAAC,EACD,CAAC,EACD,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,OAAO,EACP,YAAY,GACb,EAAE,gBAAgB;IA2BZ,eAAe,CAAC,YAAY,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI;IA0BvD,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IA0BtD,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,mBAAmB;IAuC3B,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,sBAAsB;IAgB9B,OAAO,CAAC,uBAAuB;IAwC/B,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,kBAAkB;IAyC1B;;;OAGG;IACH,IAAW,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,GAAG,KAAK,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,MAAM,CAAC,CAQ9G;IAED;;;;OAIG;IACa,SAAS,CACvB,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,GAC7B,MAAM,CAAC,IAAI,CAAC,SAAS;CAoBzB"}
1
+ {"version":3,"file":"icon-button.d.ts","sourceRoot":"","sources":["../../../src/components/icon-button/icon-button.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AAKrB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,+FAA+F;IAC/F,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CACnC,CAAC;AAmCF,qBAAa,UAAW,SAAQ,WAAW,CAAC,SAAS;IAC5C,gBAAgB,EAAG,WAAW,CAAC,MAAM,CAAC;IACtC,iBAAiB,EAAG,WAAW,CAAC,MAAM,CAAC;IACvC,QAAQ,EAAG,QAAQ,CAAC;IAE3B,OAAO,CAAC,EAAE,CAAuB;IACjC,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,gBAAgB,CAAU;IAClC,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,cAAc,CAAU;gBAEpB,EACV,KAAK,EACL,CAAC,EACD,CAAC,EACD,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,OAAO,EACP,YAAY,GACb,EAAE,gBAAgB;IA+BZ,eAAe,CAAC,YAAY,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI;IAyBvD,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IA0BtD,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,uBAAuB;IAc/B,OAAO,CAAC,sBAAsB;IAgB9B,OAAO,CAAC,wBAAwB;IAkChC,OAAO,CAAC,uBAAuB;IAyB/B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAyC5B,OAAO,CAAC,cAAc;IAoCtB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,kBAAkB;IA+C1B;;;OAGG;IACH,IAAW,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,GAAG,KAAK,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,MAAM,CAAC,CAQ9G;IAED;;;;OAIG;IACa,SAAS,CACvB,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,GAC7B,MAAM,CAAC,IAAI,CAAC,SAAS;CAoBzB"}
@@ -1,28 +1,45 @@
1
+ /* eslint-disable max-lines-per-function */
1
2
  /* eslint-disable max-lines */
2
3
  import { IconText } from 'font-awesome-for-phaser';
3
4
  import { GameObjects } from 'phaser';
4
5
  import { Color, } from 'phaser-wind';
6
+ import { getColorVariant } from '../../utils/color-variants';
5
7
  import { getPWFromScene } from '../../utils/get-pw-from-scene';
6
8
  const durations = {
7
- click: 100,
8
- hover: 150,
9
+ click: 60,
10
+ hover: 100,
9
11
  };
10
12
  const BUTTON_SCALE = 2.2;
11
13
  const CENTER_OFFSET = 1.1;
12
- const SHADOW_OFFSET = 4;
13
- const SHADOW_OPACITY = 0.1;
14
- const MAIN_SHADOW_OPACITY = 0.9;
15
- const INNER_OVERLAY_OPACITY = 0.7;
16
- const HOVER_SCALE = 1.07;
17
- const CLICK_OFFSET = 2;
18
- const MAIN_OVERLAY_SCALE = 0.9;
19
- const INNER_OVERLAY_SCALE = 0.7;
14
+ const HOVER_SCALE = 1.05;
15
+ const POINTER_DOWN_SCALE = 0.95;
16
+ const TOKEN_LIGHTER_DIFF = -100;
17
+ const COLOR_LIGHTER_AMOUNT = 30;
18
+ // Border constants
19
+ const BLACK_BORDER_THICKNESS = 2;
20
+ const WHITE_BORDER_EXTRA_PIXELS_PER_SIDE = 2;
21
+ // eslint-disable-next-line no-magic-numbers
22
+ const WHITE_BORDER_TOTAL_EXTRA_PIXELS = WHITE_BORDER_EXTRA_PIXELS_PER_SIDE * 3; // 5 pixels total
23
+ const WHITE_BORDER_RADIUS_EXTRA = 2;
24
+ // Overlay constants
25
+ const LIGHT_OVERLAY_SCALE = 0.6;
26
+ // Icon constants
27
+ const ICON_STROKE_THICKNESS = 3;
28
+ const ICON_SHADOW_OFFSET_X = 0;
29
+ const ICON_SHADOW_OFFSET_Y = 3;
30
+ const ICON_SHADOW_BLUR = 0;
31
+ const ICON_OFFSET_Y = -1.5; // Half of shadow offset to keep visually centered
32
+ // Origin constants
33
+ const SPRITE_ORIGIN = 0.5;
20
34
  export class IconButton extends GameObjects.Container {
21
35
  backgroundSprite;
22
- shadowSprite;
36
+ whiteBorderSprite;
23
37
  iconText;
24
38
  pw;
25
39
  baseColor;
40
+ colorButton;
41
+ lightColorButton;
42
+ darkColorButton;
26
43
  sizePx;
27
44
  borderRadiusPx;
28
45
  constructor({ scene, x, y, icon, size, color, onClick, borderRadius, }) {
@@ -31,17 +48,21 @@ export class IconButton extends GameObjects.Container {
31
48
  const sizePx = typeof size === 'number'
32
49
  ? size
33
50
  : this.pw.fontSize.px(size ?? 'md');
34
- const baseColor = color ?? 'gray';
51
+ const baseColor = color ?? 'blue-500';
35
52
  this.sizePx = sizePx;
36
53
  this.updateSize();
37
54
  this.baseColor = baseColor;
55
+ this.colorButton = Color.rgb(baseColor);
56
+ this.lightColorButton = getColorVariant(baseColor, TOKEN_LIGHTER_DIFF, COLOR_LIGHTER_AMOUNT);
57
+ // this.darkColorButton = getColorVariant(baseColor as string, TOKEN_DARKER_DIFF, COLOR_DARKER_AMOUNT);
58
+ this.darkColorButton = Color.blackHex();
38
59
  this.borderRadiusPx =
39
60
  typeof borderRadius === 'number'
40
61
  ? borderRadius
41
62
  : this.pw.radius.px((borderRadius ?? 'full'));
42
- this.createShadowSprite(scene, sizePx, baseColor, this.borderRadiusPx);
63
+ this.createWhiteBorderSprite(scene, sizePx, this.borderRadiusPx);
43
64
  this.createBackgroundSprite(scene, sizePx, baseColor, this.borderRadiusPx);
44
- this.createIconText(scene, icon, sizePx, baseColor);
65
+ this.createIconText(scene, icon, sizePx);
45
66
  this.setupContainer();
46
67
  this.setupInteractivity(onClick);
47
68
  }
@@ -52,10 +73,10 @@ export class IconButton extends GameObjects.Container {
52
73
  if (this.borderRadiusPx === newRadiusPx)
53
74
  return this;
54
75
  this.borderRadiusPx = newRadiusPx;
55
- // Regenerate textures for background and shadow
56
- const shadowTexture = this.createShadowTexture(this.scene, this.sizePx, this.baseColor, this.borderRadiusPx);
76
+ // Regenerate textures for white border and background
77
+ const whiteBorderTexture = this.createWhiteBorderTexture(this.scene, this.sizePx, this.borderRadiusPx);
57
78
  const backgroundTexture = this.createBackgroundTexture(this.scene, this.sizePx, this.baseColor, this.borderRadiusPx);
58
- this.shadowSprite.setTexture(shadowTexture);
79
+ this.whiteBorderSprite.setTexture(whiteBorderTexture);
59
80
  this.backgroundSprite.setTexture(backgroundTexture);
60
81
  return this;
61
82
  }
@@ -66,42 +87,43 @@ export class IconButton extends GameObjects.Container {
66
87
  : this.pw.fontSize.px(size ?? 'md');
67
88
  this.iconText.setFontSize(`${this.sizePx}px`);
68
89
  this.updateSize();
69
- const shadowTexture = this.createShadowTexture(this.scene, this.sizePx, this.baseColor, this.borderRadiusPx);
90
+ const whiteBorderTexture = this.createWhiteBorderTexture(this.scene, this.sizePx, this.borderRadiusPx);
70
91
  const backgroundTexture = this.createBackgroundTexture(this.scene, this.sizePx, this.baseColor, this.borderRadiusPx);
71
- this.shadowSprite.setTexture(shadowTexture);
92
+ this.whiteBorderSprite.setTexture(whiteBorderTexture);
72
93
  this.backgroundSprite.setTexture(backgroundTexture);
73
94
  return this;
74
95
  }
75
- createShadowSprite(scene, size, baseColor, borderRadiusPx) {
76
- const shadowTexture = this.createShadowTexture(scene, size, baseColor, borderRadiusPx);
77
- this.shadowSprite = scene.add.sprite(1, SHADOW_OFFSET, shadowTexture);
78
- this.shadowSprite.setOrigin(0.5, 0.5);
79
- }
80
- createShadowTexture(scene, size, baseColor, borderRadiusPx) {
81
- const textureKey = `iconButton_shadow_r${borderRadiusPx}_${baseColor}_${size}`;
82
- const textureSize = size * BUTTON_SCALE;
83
- const centerX = size * CENTER_OFFSET;
84
- const centerY = size * CENTER_OFFSET;
85
- const graphics = scene.add.graphics();
86
- const sideOuter = size * 2 * CENTER_OFFSET;
87
- const side = size * 2;
88
- const radiusOuter = Math.min(borderRadiusPx, sideOuter / 2);
89
- const radius = Math.min(borderRadiusPx, side / 2);
90
- graphics.fillStyle(Color.hex('black'), SHADOW_OPACITY);
91
- graphics.fillRoundedRect(centerX + 1 - sideOuter / 2, centerY - sideOuter / 2, sideOuter, sideOuter, radiusOuter);
92
- graphics.fillStyle(Color.hex(`${baseColor}-900`), MAIN_SHADOW_OPACITY);
93
- graphics.fillRoundedRect(centerX - side / 2, centerY - CLICK_OFFSET - side / 2, side, side, radius);
94
- graphics.generateTexture(textureKey, textureSize, textureSize);
95
- graphics.destroy();
96
- return textureKey;
97
- }
98
96
  updateSize() {
99
97
  this.setSize(this.sizePx * BUTTON_SCALE, this.sizePx * BUTTON_SCALE);
100
98
  }
99
+ createWhiteBorderSprite(scene, size, borderRadiusPx) {
100
+ const whiteBorderTexture = this.createWhiteBorderTexture(scene, size, borderRadiusPx);
101
+ this.whiteBorderSprite = scene.add.sprite(0, 0, whiteBorderTexture);
102
+ this.whiteBorderSprite.setOrigin(SPRITE_ORIGIN, SPRITE_ORIGIN);
103
+ }
101
104
  createBackgroundSprite(scene, size, baseColor, borderRadiusPx) {
102
105
  const backgroundTexture = this.createBackgroundTexture(scene, size, baseColor, borderRadiusPx);
103
- this.backgroundSprite = scene.add.sprite(1, 0, backgroundTexture);
104
- this.backgroundSprite.setOrigin(0.5, 0.5);
106
+ this.backgroundSprite = scene.add.sprite(0, 0, backgroundTexture);
107
+ this.backgroundSprite.setOrigin(SPRITE_ORIGIN, SPRITE_ORIGIN);
108
+ }
109
+ createWhiteBorderTexture(scene, size, borderRadiusPx) {
110
+ const textureKey = `iconButton_whiteBorder_r${borderRadiusPx}_${size}`;
111
+ // White border is larger on each side
112
+ const side = size * 2 + WHITE_BORDER_TOTAL_EXTRA_PIXELS;
113
+ // Increase texture size to accommodate the larger border
114
+ const textureSize = size * BUTTON_SCALE + WHITE_BORDER_TOTAL_EXTRA_PIXELS;
115
+ const centerX = textureSize / 2;
116
+ const centerY = textureSize / 2;
117
+ const graphics = scene.add.graphics();
118
+ const maxRadius = Math.floor(Math.min(side / 2, side / 2));
119
+ const effectiveRadius = Math.min(borderRadiusPx + WHITE_BORDER_RADIUS_EXTRA, maxRadius);
120
+ const finalRadius = Math.max(0, effectiveRadius);
121
+ // White border (outer)
122
+ graphics.fillStyle(Color.hex('white'), 1);
123
+ graphics.fillRoundedRect(centerX - side / 2, centerY - side / 2, side, side, finalRadius);
124
+ graphics.generateTexture(textureKey, textureSize, textureSize);
125
+ graphics.destroy();
126
+ return textureKey;
105
127
  }
106
128
  createBackgroundTexture(scene, size, baseColor, borderRadiusPx) {
107
129
  const textureKey = `iconButton_r${borderRadiusPx}_${baseColor}_${size}`;
@@ -110,67 +132,100 @@ export class IconButton extends GameObjects.Container {
110
132
  const centerY = size * CENTER_OFFSET;
111
133
  const graphics = scene.add.graphics();
112
134
  const side = size * 2;
113
- const mainSide = side * MAIN_OVERLAY_SCALE;
114
- const innerSide = side * INNER_OVERLAY_SCALE;
115
- const mainRadius = Math.min(borderRadiusPx, mainSide / 2);
116
- const innerRadius = Math.min(borderRadiusPx, innerSide / 2);
117
- graphics.fillStyle(Color.hex(`${baseColor}-600`), 1);
118
- graphics.fillRoundedRect(centerX - mainSide / 2, centerY - mainSide / 2, mainSide, mainSide, mainRadius);
119
- graphics.fillStyle(Color.hex(`${baseColor}-500`), INNER_OVERLAY_OPACITY);
120
- graphics.fillRoundedRect(centerX - innerSide / 2, centerY - innerSide / 2, innerSide, innerSide, innerRadius);
135
+ const maxRadius = Math.floor(Math.min(side / 2, side / 2));
136
+ const effectiveRadius = Math.min(borderRadiusPx, maxRadius);
137
+ const finalRadius = Math.max(0, effectiveRadius);
138
+ this.drawCssColorGradient(graphics, centerX, centerY, side, finalRadius);
121
139
  graphics.generateTexture(textureKey, textureSize, textureSize);
122
140
  graphics.destroy();
123
141
  return textureKey;
124
142
  }
125
- createIconText(scene, icon, size, baseColor) {
143
+ /**
144
+ * Draws gradient using a centered light overlay on CSS color.
145
+ * For round buttons, uses a smaller centered graphic with light color.
146
+ */
147
+ drawCssColorGradient(graphics, centerX, centerY, side, effectiveRadius) {
148
+ // Main background
149
+ graphics.fillStyle(Color.hex(this.colorButton), 1);
150
+ graphics.fillRoundedRect(centerX - side / 2, centerY - side / 2, side, side, effectiveRadius);
151
+ // Centered light overlay (smaller, circular/rounded)
152
+ const overlaySide = side * LIGHT_OVERLAY_SCALE;
153
+ const overlayRadius = Math.min(effectiveRadius, overlaySide / 2);
154
+ graphics.fillStyle(this.lightColorButton, 1);
155
+ graphics.fillRoundedRect(centerX - overlaySide / 2, centerY - overlaySide / 2, overlaySide, overlaySide, overlayRadius);
156
+ // Black stroke border
157
+ graphics.lineStyle(BLACK_BORDER_THICKNESS, Color.hex('black'), 1);
158
+ graphics.strokeRoundedRect(centerX - side / 2, centerY - side / 2, side, side, effectiveRadius);
159
+ }
160
+ createIconText(scene, icon, size) {
161
+ // Convert darkColorButton (number) to RGB string
162
+ const darkColorObj = Phaser.Display.Color.ValueToColor(this.darkColorButton);
163
+ const RGB_MASK = 0xff;
164
+ const RGB_SHIFT_R = 16;
165
+ const RGB_SHIFT_G = 8;
166
+ const darkColorString = `rgb(${darkColorObj.color32 >> RGB_SHIFT_R & RGB_MASK}, ${darkColorObj.color32 >> RGB_SHIFT_G & RGB_MASK}, ${darkColorObj.color32 & RGB_MASK})`;
126
167
  this.iconText = new IconText({
127
168
  scene,
128
- x: 1,
129
- y: 1,
169
+ x: 0,
170
+ y: ICON_OFFSET_Y,
130
171
  icon,
131
172
  size,
132
173
  style: {
133
174
  color: Color.rgb('white'),
134
- strokeThickness: 3,
135
- stroke: Color.rgb(`${baseColor}-900`),
175
+ strokeThickness: ICON_STROKE_THICKNESS,
176
+ stroke: darkColorString,
177
+ shadow: {
178
+ offsetX: ICON_SHADOW_OFFSET_X,
179
+ offsetY: ICON_SHADOW_OFFSET_Y,
180
+ color: darkColorString,
181
+ blur: ICON_SHADOW_BLUR,
182
+ stroke: true,
183
+ fill: true,
184
+ },
136
185
  },
137
186
  });
138
187
  this.iconText.setFontStyle('900');
139
- this.iconText.setOrigin(0.5, 0.5);
188
+ this.iconText.setOrigin(SPRITE_ORIGIN, SPRITE_ORIGIN);
140
189
  }
141
190
  setupContainer() {
142
- this.add([this.shadowSprite, this.backgroundSprite, this.iconText]);
191
+ this.add([this.whiteBorderSprite, this.backgroundSprite, this.iconText]);
143
192
  }
144
193
  setupInteractivity(onClick) {
145
194
  this.backgroundSprite.setInteractive({ useHandCursor: true });
195
+ // Hover effects
146
196
  this.backgroundSprite.on('pointerover', () => {
147
197
  this.scene.tweens.add({
148
- targets: this.iconText,
149
- scale: HOVER_SCALE,
198
+ targets: this,
150
199
  duration: durations.hover,
151
- ease: 'Linear',
200
+ scaleX: HOVER_SCALE,
201
+ scaleY: HOVER_SCALE,
202
+ ease: 'Back.easeOut',
152
203
  });
153
204
  });
154
205
  this.backgroundSprite.on('pointerout', () => {
155
206
  this.scene.tweens.add({
156
- targets: this.iconText,
157
- scale: 1,
207
+ targets: this,
158
208
  duration: durations.hover,
159
- ease: 'Linear',
209
+ scaleX: 1,
210
+ scaleY: 1,
211
+ ease: 'Back.easeOut',
160
212
  });
161
213
  });
214
+ // Click effects
162
215
  this.backgroundSprite.on('pointerdown', () => {
163
216
  this.scene.tweens.add({
164
- targets: [this.backgroundSprite, this.iconText],
165
- y: CLICK_OFFSET,
217
+ targets: [this.whiteBorderSprite, this.backgroundSprite, this.iconText],
218
+ scaleX: POINTER_DOWN_SCALE,
219
+ scaleY: POINTER_DOWN_SCALE,
166
220
  duration: durations.click,
167
221
  ease: 'Linear',
168
222
  });
169
223
  });
170
224
  this.backgroundSprite.on('pointerup', () => {
171
225
  this.scene.tweens.add({
172
- targets: [this.backgroundSprite, this.iconText],
173
- y: 0,
226
+ targets: [this.whiteBorderSprite, this.backgroundSprite, this.iconText],
227
+ scaleX: 1,
228
+ scaleY: 1,
174
229
  duration: durations.click,
175
230
  ease: 'Linear',
176
231
  });
@@ -196,8 +251,8 @@ export class IconButton extends GameObjects.Container {
196
251
  * @returns Rectangle with the button bounds
197
252
  */
198
253
  getBounds(output) {
199
- const width = this.shadowSprite.displayWidth ?? this.shadowSprite.width;
200
- const height = this.shadowSprite.displayHeight ?? this.shadowSprite.height;
254
+ const width = this.backgroundSprite.displayWidth ?? this.backgroundSprite.width;
255
+ const height = this.backgroundSprite.displayHeight ?? this.backgroundSprite.height;
201
256
  if (output) {
202
257
  return output.setTo(this.x - width / 2, this.y - height / 2, width, height);
203
258
  }