@crediball/elements 0.11.0 → 0.12.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.
@@ -2,22 +2,33 @@
2
2
  import {
3
3
  getCrediballClient,
4
4
  loadRemoteFont,
5
- themeToCssVars
5
+ themeToCssVars,
6
+ getSystemColorScheme,
7
+ watchSystemColorScheme
6
8
  } from "@crediball/core";
7
9
  var _CrediballElement = class _CrediballElement extends HTMLElement {
8
10
  constructor() {
9
11
  super(...arguments);
10
12
  this.client = null;
11
13
  this.unsubscribe = null;
14
+ this.unwatchSystemColorScheme = null;
12
15
  }
13
16
  static get observedAttributes() {
14
- return [..._CrediballElement.CLIENT_ATTRS];
17
+ return [..._CrediballElement.CLIENT_ATTRS, "color-scheme"];
15
18
  }
16
19
  connectedCallback() {
17
20
  this.connectClient();
21
+ this.unwatchSystemColorScheme = watchSystemColorScheme(() => {
22
+ if (!this.explicitColorScheme()) {
23
+ this.applyRemoteTheme();
24
+ this.render();
25
+ }
26
+ });
18
27
  }
19
28
  disconnectedCallback() {
20
29
  this.teardownClient();
30
+ this.unwatchSystemColorScheme?.();
31
+ this.unwatchSystemColorScheme = null;
21
32
  }
22
33
  /**
23
34
  * Only reconnect the shared client when a connection-relevant attribute
@@ -29,10 +40,21 @@ var _CrediballElement = class _CrediballElement extends HTMLElement {
29
40
  if (!this.isConnected) return;
30
41
  if (_CrediballElement.CLIENT_ATTRS.has(name)) {
31
42
  this.connectClient();
43
+ } else if (name === "color-scheme") {
44
+ this.applyRemoteTheme();
45
+ this.render();
32
46
  } else {
33
47
  this.render();
34
48
  }
35
49
  }
50
+ explicitColorScheme() {
51
+ const attr = this.getAttribute("color-scheme");
52
+ return attr === "light" || attr === "dark" ? attr : null;
53
+ }
54
+ /** "light"/"dark" attribute wins; otherwise follows the live OS/browser preference. */
55
+ resolvedColorScheme() {
56
+ return this.explicitColorScheme() ?? getSystemColorScheme();
57
+ }
36
58
  connectClient() {
37
59
  this.teardownClient();
38
60
  const publishableKey = this.getAttribute("publishable-key");
@@ -59,12 +81,18 @@ var _CrediballElement = class _CrediballElement extends HTMLElement {
59
81
  * the shadow boundary, so the shadow-DOM styles pick them up. On by default;
60
82
  * set `apply-remote-theme="false"` to theme from your own CSS instead. The
61
83
  * published theme takes precedence over host `--crediball-*` vars (dashboard wins).
84
+ *
85
+ * If a dark palette is configured on the dashboard, it's applied whenever
86
+ * the resolved color scheme is "dark" — following the OS/browser's
87
+ * `prefers-color-scheme` live, or a `color-scheme="light"|"dark"` attribute
88
+ * you set explicitly (wins over the OS setting, for an app with its own
89
+ * in-app theme toggle).
62
90
  */
63
91
  applyRemoteTheme() {
64
92
  if (this.getAttribute("apply-remote-theme") === "false") return;
65
93
  const theme = this.getSnapshot()?.packages?.ui?.theme;
66
94
  if (!theme) return;
67
- for (const [cssVar, value] of Object.entries(themeToCssVars(theme))) {
95
+ for (const [cssVar, value] of Object.entries(themeToCssVars(theme, this.resolvedColorScheme()))) {
68
96
  this.style.setProperty(cssVar, value);
69
97
  }
70
98
  if (theme.fontUrl) loadRemoteFont(theme.fontUrl);
@@ -480,8 +508,8 @@ var CrediballPaywallElement = class extends CrediballElement {
480
508
  </div>
481
509
  <p class="custom-preview" hidden></p>` : ""}
482
510
  ${this.renderPromoCode(Boolean(pkgs?.hasActiveCheckoutPromotion))}
483
- ${this.renderAutoTopup(packages, pkgs?.autoTopup, currency)}
484
511
  <p class="error" hidden></p>
512
+ ${this.renderAutoTopup(packages, pkgs?.autoTopup, currency)}
485
513
  <button class="close" part="close" type="button">Not now</button>
486
514
  ${this.referral?.link ? `<div class="referral">
487
515
  <div class="referral-label">${escapeHtml(referralLabel)}</div>
@@ -384,6 +384,27 @@ var Crediball = (() => {
384
384
  }
385
385
 
386
386
  // ../core/dist/theme.js
387
+ function getSystemColorScheme() {
388
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function")
389
+ return "light";
390
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
391
+ }
392
+ function watchSystemColorScheme(cb) {
393
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function")
394
+ return () => {
395
+ };
396
+ const mql = window.matchMedia("(prefers-color-scheme: dark)");
397
+ const handler = () => cb(mql.matches ? "dark" : "light");
398
+ mql.addEventListener("change", handler);
399
+ return () => mql.removeEventListener("change", handler);
400
+ }
401
+ function resolveUiTheme(theme, scheme) {
402
+ if (!theme)
403
+ return theme ?? null;
404
+ if (scheme !== "dark" || !theme.dark)
405
+ return theme;
406
+ return { ...theme, ...theme.dark };
407
+ }
387
408
  var THEME_CSS_VAR_ENTRIES = [
388
409
  ["accent", "--crediball-accent", String],
389
410
  ["onAccent", "--crediball-on-accent", String],
@@ -394,12 +415,13 @@ var Crediball = (() => {
394
415
  ["radiusCard", "--crediball-radius-card", (v) => `${v}px`],
395
416
  ["fontStack", "--crediball-font", String]
396
417
  ];
397
- function themeToCssVars(theme) {
418
+ function themeToCssVars(theme, scheme = "light") {
398
419
  const vars = {};
399
- if (!theme)
420
+ const resolved = resolveUiTheme(theme, scheme);
421
+ if (!resolved)
400
422
  return vars;
401
423
  for (const [key, cssVar, fmt] of THEME_CSS_VAR_ENTRIES) {
402
- const value = theme[key];
424
+ const value = resolved[key];
403
425
  if (value != null && value !== "")
404
426
  vars[cssVar] = fmt(value);
405
427
  }
@@ -428,15 +450,24 @@ var Crediball = (() => {
428
450
  super(...arguments);
429
451
  this.client = null;
430
452
  this.unsubscribe = null;
453
+ this.unwatchSystemColorScheme = null;
431
454
  }
432
455
  static get observedAttributes() {
433
- return [..._CrediballElement.CLIENT_ATTRS];
456
+ return [..._CrediballElement.CLIENT_ATTRS, "color-scheme"];
434
457
  }
435
458
  connectedCallback() {
436
459
  this.connectClient();
460
+ this.unwatchSystemColorScheme = watchSystemColorScheme(() => {
461
+ if (!this.explicitColorScheme()) {
462
+ this.applyRemoteTheme();
463
+ this.render();
464
+ }
465
+ });
437
466
  }
438
467
  disconnectedCallback() {
439
468
  this.teardownClient();
469
+ this.unwatchSystemColorScheme?.();
470
+ this.unwatchSystemColorScheme = null;
440
471
  }
441
472
  /**
442
473
  * Only reconnect the shared client when a connection-relevant attribute
@@ -448,10 +479,21 @@ var Crediball = (() => {
448
479
  if (!this.isConnected) return;
449
480
  if (_CrediballElement.CLIENT_ATTRS.has(name)) {
450
481
  this.connectClient();
482
+ } else if (name === "color-scheme") {
483
+ this.applyRemoteTheme();
484
+ this.render();
451
485
  } else {
452
486
  this.render();
453
487
  }
454
488
  }
489
+ explicitColorScheme() {
490
+ const attr = this.getAttribute("color-scheme");
491
+ return attr === "light" || attr === "dark" ? attr : null;
492
+ }
493
+ /** "light"/"dark" attribute wins; otherwise follows the live OS/browser preference. */
494
+ resolvedColorScheme() {
495
+ return this.explicitColorScheme() ?? getSystemColorScheme();
496
+ }
455
497
  connectClient() {
456
498
  this.teardownClient();
457
499
  const publishableKey = this.getAttribute("publishable-key");
@@ -478,12 +520,18 @@ var Crediball = (() => {
478
520
  * the shadow boundary, so the shadow-DOM styles pick them up. On by default;
479
521
  * set `apply-remote-theme="false"` to theme from your own CSS instead. The
480
522
  * published theme takes precedence over host `--crediball-*` vars (dashboard wins).
523
+ *
524
+ * If a dark palette is configured on the dashboard, it's applied whenever
525
+ * the resolved color scheme is "dark" — following the OS/browser's
526
+ * `prefers-color-scheme` live, or a `color-scheme="light"|"dark"` attribute
527
+ * you set explicitly (wins over the OS setting, for an app with its own
528
+ * in-app theme toggle).
481
529
  */
482
530
  applyRemoteTheme() {
483
531
  if (this.getAttribute("apply-remote-theme") === "false") return;
484
532
  const theme = this.getSnapshot()?.packages?.ui?.theme;
485
533
  if (!theme) return;
486
- for (const [cssVar, value] of Object.entries(themeToCssVars(theme))) {
534
+ for (const [cssVar, value] of Object.entries(themeToCssVars(theme, this.resolvedColorScheme()))) {
487
535
  this.style.setProperty(cssVar, value);
488
536
  }
489
537
  if (theme.fontUrl) loadRemoteFont(theme.fontUrl);
@@ -894,8 +942,8 @@ var Crediball = (() => {
894
942
  </div>
895
943
  <p class="custom-preview" hidden></p>` : ""}
896
944
  ${this.renderPromoCode(Boolean(pkgs?.hasActiveCheckoutPromotion))}
897
- ${this.renderAutoTopup(packages, pkgs?.autoTopup, currency)}
898
945
  <p class="error" hidden></p>
946
+ ${this.renderAutoTopup(packages, pkgs?.autoTopup, currency)}
899
947
  <button class="close" part="close" type="button">Not now</button>
900
948
  ${this.referral?.link ? `<div class="referral">
901
949
  <div class="referral-label">${escapeHtml(referralLabel)}</div>
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CrediballClient, CrediballSnapshot } from '@crediball/core';
1
+ import { CrediballClient, ColorScheme, CrediballSnapshot } from '@crediball/core';
2
2
 
3
3
  /**
4
4
  * Shared base for every <crediball-*> element: reads config from attributes,
@@ -12,6 +12,7 @@ import { CrediballClient, CrediballSnapshot } from '@crediball/core';
12
12
  declare abstract class CrediballElement extends HTMLElement {
13
13
  protected client: CrediballClient | null;
14
14
  private unsubscribe;
15
+ private unwatchSystemColorScheme;
15
16
  private static readonly CLIENT_ATTRS;
16
17
  static get observedAttributes(): string[];
17
18
  connectedCallback(): void;
@@ -23,6 +24,9 @@ declare abstract class CrediballElement extends HTMLElement {
23
24
  * those should just re-render, not tear down and refetch the client.
24
25
  */
25
26
  attributeChangedCallback(name: string): void;
27
+ private explicitColorScheme;
28
+ /** "light"/"dark" attribute wins; otherwise follows the live OS/browser preference. */
29
+ protected resolvedColorScheme(): ColorScheme;
26
30
  private connectClient;
27
31
  /**
28
32
  * Apply the developer-published theme (served alongside packages) as
@@ -30,6 +34,12 @@ declare abstract class CrediballElement extends HTMLElement {
30
34
  * the shadow boundary, so the shadow-DOM styles pick them up. On by default;
31
35
  * set `apply-remote-theme="false"` to theme from your own CSS instead. The
32
36
  * published theme takes precedence over host `--crediball-*` vars (dashboard wins).
37
+ *
38
+ * If a dark palette is configured on the dashboard, it's applied whenever
39
+ * the resolved color scheme is "dark" — following the OS/browser's
40
+ * `prefers-color-scheme` live, or a `color-scheme="light"|"dark"` attribute
41
+ * you set explicitly (wins over the OS setting, for an app with its own
42
+ * in-app theme toggle).
33
43
  */
34
44
  private applyRemoteTheme;
35
45
  private teardownClient;
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  CrediballReferralCardElement,
7
7
  CrediballTopUpButtonElement,
8
8
  CrediballUsageElement
9
- } from "./chunk-FOMDJR2B.js";
9
+ } from "./chunk-ELPD754U.js";
10
10
  export {
11
11
  CrediballBalanceElement,
12
12
  CrediballElement,
package/dist/register.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  CrediballReferralCardElement,
6
6
  CrediballTopUpButtonElement,
7
7
  CrediballUsageElement
8
- } from "./chunk-FOMDJR2B.js";
8
+ } from "./chunk-ELPD754U.js";
9
9
 
10
10
  // src/register.ts
11
11
  function define(name, ctor) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crediball/elements",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Framework-agnostic web components for showing Crediball credits inside your AI app.",
5
5
  "license": "MIT",
6
6
  "author": "Filippo Rezzadore <filipporezzadore@gmail.com>",
@@ -56,7 +56,7 @@
56
56
  "prepublishOnly": "npm run build"
57
57
  },
58
58
  "dependencies": {
59
- "@crediball/core": "^0.9.0"
59
+ "@crediball/core": "^0.10.0"
60
60
  },
61
61
  "devDependencies": {
62
62
  "tsup": "^8.3.5",