hudini 0.18.1 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -140,6 +140,63 @@ import { Column, Row, IconButton } from 'hudini';
140
140
 
141
141
  Check the Storybook for live, interactive examples: [Hudini on Storybook](https://renatocassino.github.io/phaser-toolkit/?path=/story/hudini--index)
142
142
 
143
+ ## 🎯 Access the plugin from your scene
144
+
145
+ Use the `withHudini(scene)` accessor to get a fully typed handle to the plugin. It composes with any base scene, doesn't rely on global module augmentation, and infers your theme's tokens at the call site.
146
+
147
+ ```ts
148
+ import Phaser from 'phaser';
149
+ import { withHudini } from 'hudini';
150
+ import type { ThemeType } from './theme'; // your createTheme() result
151
+
152
+ class MyScene extends Phaser.Scene {
153
+ create(): void {
154
+ const hudini = withHudini<ThemeType>(this);
155
+ const pw = hudini.pw; // phaser-wind API, narrowed to your theme
156
+
157
+ this.cameras.main.setBackgroundColor(pw.color.rgb('background'));
158
+ }
159
+ }
160
+ ```
161
+
162
+ Call `withHudini(this)` inside `create()` / `update()` (after the plugin has mounted). Don't call it in the constructor or `init()` — the plugin isn't attached yet.
163
+
164
+ ### Recommended: wrap it in a project-local helper
165
+
166
+ Passing `<ThemeType>` on every call gets old. Define a one-line helper once in your project so scenes stay short and the theme type stays in one place:
167
+
168
+ ```ts
169
+ // src/theme.ts (in your project)
170
+ import type { Scene } from 'phaser';
171
+ import { createTheme, withHudini, type CreateTheme } from 'hudini';
172
+
173
+ export const theme = createTheme({
174
+ colors: { primary: 'blue-600', danger: 'red-500' },
175
+ // ...
176
+ } satisfies CreateTheme<any>);
177
+
178
+ export type ThemeType = typeof theme;
179
+
180
+ /** Project-local accessor — no need to pass the theme type. */
181
+ export const withHud = (scene: Scene) => withHudini<ThemeType>(scene);
182
+ ```
183
+
184
+ Now every scene is a one-liner:
185
+
186
+ ```ts
187
+ import Phaser from 'phaser';
188
+ import { withHud } from './theme';
189
+
190
+ class MyScene extends Phaser.Scene {
191
+ create(): void {
192
+ const hudini = withHud(this); // fully typed against your theme
193
+ this.cameras.main.setBackgroundColor(hudini.pw.color.rgb('background'));
194
+ }
195
+ }
196
+ ```
197
+
198
+ You can name the helper whatever fits your style — `withHud`, `useHud`, `getHud`, `hud`. The lib intentionally doesn't ship an alias, so you own the naming in your codebase.
199
+
143
200
  ## 🧩 Components
144
201
 
145
202
  ### Column
package/dist/hudini.js CHANGED
@@ -1198,6 +1198,65 @@
1198
1198
  };
1199
1199
  };
1200
1200
 
1201
+ /**
1202
+ * Opacity scale mapping following Tailwind's opacity scale.
1203
+ * Values are in the 0..1 range, ready for Phaser's `setAlpha()`.
1204
+ */
1205
+ const opacityMap = {
1206
+ '0': 0,
1207
+ '5': 0.05,
1208
+ '10': 0.1,
1209
+ '15': 0.15,
1210
+ '20': 0.2,
1211
+ '25': 0.25,
1212
+ '30': 0.3,
1213
+ '35': 0.35,
1214
+ '40': 0.4,
1215
+ '45': 0.45,
1216
+ '50': 0.5,
1217
+ '55': 0.55,
1218
+ '60': 0.6,
1219
+ '65': 0.65,
1220
+ '70': 0.7,
1221
+ '75': 0.75,
1222
+ '80': 0.8,
1223
+ '85': 0.85,
1224
+ '90': 0.9,
1225
+ '95': 0.95,
1226
+ '100': 1,
1227
+ };
1228
+ /**
1229
+ * Create an opacity API bound to an optional theme opacity map.
1230
+ * @example
1231
+ * const o = createOpacity({ faded: 0.35 });
1232
+ * o.value('faded'); // 0.35
1233
+ * o.value('50'); // 0.5
1234
+ */
1235
+ const createOpacity = (themeOpacity) => {
1236
+ const map = {
1237
+ ...opacityMap,
1238
+ ...themeOpacity,
1239
+ };
1240
+ const get = (key) => {
1241
+ return typeof map[key] === 'number' ? map[key] : 0;
1242
+ };
1243
+ return {
1244
+ value: (key) => {
1245
+ return get(key);
1246
+ },
1247
+ percent: (key) => {
1248
+ const ONE_HUNDRED = 100;
1249
+ return get(key) * ONE_HUNDRED;
1250
+ },
1251
+ css: (key) => {
1252
+ const ONE_HUNDRED = 100;
1253
+ return `${get(key) * ONE_HUNDRED}%`;
1254
+ },
1255
+ };
1256
+ };
1257
+ /** Convenience instance using default opacity map (no theme). */
1258
+ const Opacity = createOpacity(undefined);
1259
+
1201
1260
  /**
1202
1261
  * Mapping of radius keys to their pixel values
1203
1262
  */
@@ -1370,6 +1429,7 @@
1370
1429
  overlay: 'black',
1371
1430
  },
1372
1431
  spacing: { ...spacingMap },
1432
+ opacity: { ...opacityMap },
1373
1433
  typography: {
1374
1434
  heading: {
1375
1435
  fontSize: '2xl',
@@ -1446,6 +1506,7 @@
1446
1506
  overlay: 'black',
1447
1507
  },
1448
1508
  spacing: { ...spacingMap },
1509
+ opacity: { ...opacityMap },
1449
1510
  typography: {
1450
1511
  heading: {
1451
1512
  fontSize: '2xl',
@@ -1507,6 +1568,7 @@
1507
1568
  fontSizeInstance = null;
1508
1569
  spacingInstance = null;
1509
1570
  radiusInstance = null;
1571
+ opacityInstance = null;
1510
1572
  fontInstance = null;
1511
1573
  shadowInstance = null;
1512
1574
  /** Current theme configuration */
@@ -1553,6 +1615,7 @@
1553
1615
  this.fontSizeInstance = createFontSize(this.theme.fontSizes);
1554
1616
  this.spacingInstance = createSpacing(this.theme.spacing);
1555
1617
  this.radiusInstance = createRadius(this.theme.radius);
1618
+ this.opacityInstance = createOpacity(this.theme.opacity);
1556
1619
  this.fontInstance = createFont(this.theme.fonts, this.theme.fontSizes);
1557
1620
  this.shadowInstance = createShadow(this.theme.effects);
1558
1621
  }
@@ -1575,6 +1638,9 @@
1575
1638
  get radius() {
1576
1639
  return this.radiusInstance;
1577
1640
  }
1641
+ get opacity() {
1642
+ return this.opacityInstance;
1643
+ }
1578
1644
  get font() {
1579
1645
  return this.fontInstance;
1580
1646
  }
@@ -1583,9 +1649,31 @@
1583
1649
  }
1584
1650
  }
1585
1651
 
1652
+ /**
1653
+ * @deprecated Use {@link withPhaserWind} instead.
1654
+ *
1655
+ * Forces single inheritance, which conflicts with any user-defined `BaseScene`
1656
+ * or other libraries that ship their own scene base class. It also relies on a
1657
+ * non-null assertion (`pw!`) that lies to TypeScript about when the plugin is
1658
+ * available — touching `this.pw` before the plugin mounts throws at runtime.
1659
+ *
1660
+ * Prefer the `withPhaserWind(scene)` accessor:
1661
+ *
1662
+ * ```ts
1663
+ * import { withPhaserWind } from 'phaser-wind';
1664
+ * import type { ThemeType } from './theme';
1665
+ *
1666
+ * class MyScene extends Phaser.Scene {
1667
+ * create() {
1668
+ * const pw = withPhaserWind<ThemeType>(this);
1669
+ * }
1670
+ * }
1671
+ * ```
1672
+ *
1673
+ * Kept exported to avoid breaking existing consumers.
1674
+ */
1586
1675
  class SceneWithPhaserWind extends Phaser.Scene {
1587
1676
  /**
1588
- *
1589
1677
  * @param config The scene key or scene specific configuration settings.
1590
1678
  */
1591
1679
  constructor(config) {
@@ -1594,6 +1682,37 @@
1594
1682
  pw;
1595
1683
  }
1596
1684
 
1685
+ /**
1686
+ * Accessor for the Phaser Wind plugin from within a Phaser scene.
1687
+ *
1688
+ * Preferred over {@link SceneWithPhaserWind} (inheritance) and over module
1689
+ * augmentation of `Phaser.Scene`, because it:
1690
+ * - Composes with any existing base scene (no forced inheritance).
1691
+ * - Keeps the theme type explicit at the call site (no silent `any`).
1692
+ * - Doesn't rely on non-null assertions that lie about lifecycle.
1693
+ *
1694
+ * Call it inside `create()` / `update()` (after the plugin has been installed).
1695
+ *
1696
+ * @typeParam T - The theme config type. Pass your `ThemeType` to get
1697
+ * type-narrowed access to your custom tokens.
1698
+ * @param scene - The Phaser scene instance.
1699
+ * @returns The Phaser Wind plugin instance bound to the given theme type.
1700
+ *
1701
+ * @example
1702
+ * ```ts
1703
+ * import { withPhaserWind } from 'phaser-wind';
1704
+ * import type { ThemeType } from './theme';
1705
+ *
1706
+ * class MyScene extends Phaser.Scene {
1707
+ * create() {
1708
+ * const pw = withPhaserWind<ThemeType>(this);
1709
+ * this.cameras.main.setBackgroundColor(pw.color.rgb('background'));
1710
+ * }
1711
+ * }
1712
+ * ```
1713
+ */
1714
+ const withPhaserWind = (scene) => scene.plugins.get(PHASER_WIND_KEY);
1715
+
1597
1716
  var getPWFromScene$1 = function (scene) {
1598
1717
  return scene.pw;
1599
1718
  };
@@ -9522,10 +9641,33 @@
9522
9641
  return HudiniPlugin;
9523
9642
  }(Phaser$1.Plugins.BasePlugin));
9524
9643
 
9644
+ /**
9645
+ * @deprecated Use {@link withHudini} instead.
9646
+ *
9647
+ * Forces single inheritance, which conflicts with any user-defined `BaseScene`
9648
+ * or other libraries that ship their own scene base class. It also relies on a
9649
+ * non-null assertion (`hudini!`) that lies to TypeScript about when the plugin
9650
+ * is available — touching `this.hudini` before the plugin mounts throws at
9651
+ * runtime.
9652
+ *
9653
+ * Prefer the `withHudini(scene)` accessor:
9654
+ *
9655
+ * ```ts
9656
+ * import { withHudini } from 'hudini';
9657
+ * import type { ThemeType } from './theme';
9658
+ *
9659
+ * class MyScene extends Phaser.Scene {
9660
+ * create() {
9661
+ * const hudini = withHudini<ThemeType>(this);
9662
+ * }
9663
+ * }
9664
+ * ```
9665
+ *
9666
+ * Kept exported to avoid breaking existing consumers.
9667
+ */
9525
9668
  var SceneWithHudini = /** @class */ (function (_super) {
9526
9669
  __extends(SceneWithHudini, _super);
9527
9670
  /**
9528
- *
9529
9671
  * @param config The scene key or scene specific configuration settings.
9530
9672
  */
9531
9673
  function SceneWithHudini(config) {
@@ -9534,6 +9676,40 @@
9534
9676
  return SceneWithHudini;
9535
9677
  }(SceneWithPhaserWind));
9536
9678
 
9679
+ /**
9680
+ * Accessor for the Hudini plugin from within a Phaser scene.
9681
+ *
9682
+ * Preferred over {@link SceneWithHudini} (inheritance) and over module
9683
+ * augmentation of `Phaser.Scene`, because it:
9684
+ * - Composes with any existing base scene (no forced inheritance).
9685
+ * - Keeps the theme type explicit at the call site (no silent `any`).
9686
+ * - Doesn't rely on non-null assertions that lie about lifecycle.
9687
+ *
9688
+ * Call it inside `create()` / `update()` (after the plugin has been installed).
9689
+ *
9690
+ * @typeParam T - The theme config type. Pass your `ThemeType` to get
9691
+ * type-narrowed access to your custom tokens (through `hudini.pw`).
9692
+ * @param scene - The Phaser scene instance.
9693
+ * @returns The Hudini plugin instance bound to the given theme type.
9694
+ *
9695
+ * @example
9696
+ * ```ts
9697
+ * import { withHudini } from 'hudini';
9698
+ * import type { ThemeType } from './theme';
9699
+ *
9700
+ * class MyScene extends Phaser.Scene {
9701
+ * create() {
9702
+ * const hudini = withHudini<ThemeType>(this);
9703
+ * const pw = hudini.pw;
9704
+ * this.cameras.main.setBackgroundColor(pw.color.rgb('background'));
9705
+ * }
9706
+ * }
9707
+ * ```
9708
+ */
9709
+ var withHudini = function (scene) {
9710
+ return scene.plugins.get(HUDINI_KEY);
9711
+ };
9712
+
9537
9713
  var getHudini = function (scene) {
9538
9714
  return scene.hudini;
9539
9715
  };
@@ -9552,6 +9728,7 @@
9552
9728
  exports.HudiniPlugin = HudiniPlugin;
9553
9729
  exports.IconButton = IconButton;
9554
9730
  exports.LinearProgress = LinearProgress;
9731
+ exports.Opacity = Opacity;
9555
9732
  exports.PHASER_WIND_KEY = PHASER_WIND_KEY;
9556
9733
  exports.Panel = Panel;
9557
9734
  exports.PhaserWindPlugin = PhaserWindPlugin;
@@ -9569,6 +9746,7 @@
9569
9746
  exports.createColor = createColor;
9570
9747
  exports.createFont = createFont;
9571
9748
  exports.createFontSize = createFontSize;
9749
+ exports.createOpacity = createOpacity;
9572
9750
  exports.createRadius = createRadius;
9573
9751
  exports.createShadow = createShadow;
9574
9752
  exports.createSpacing = createSpacing;
@@ -9588,8 +9766,11 @@
9588
9766
  exports.loadFonts = loadFonts;
9589
9767
  exports.merge = merge;
9590
9768
  exports.mergeDeep = mergeDeep;
9769
+ exports.opacityMap = opacityMap;
9591
9770
  exports.palette = palette;
9592
9771
  exports.radiusMap = radiusMap;
9593
9772
  exports.spacingMap = spacingMap;
9773
+ exports.withHudini = withHudini;
9774
+ exports.withPhaserWind = withPhaserWind;
9594
9775
 
9595
9776
  }));