@crediball/elements 0.3.0 → 0.4.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.
@@ -1,5 +1,30 @@
1
1
  // src/base.ts
2
- import { getCrediballClient } from "@crediball/core";
2
+ import {
3
+ getCrediballClient
4
+ } from "@crediball/core";
5
+ var THEME_VARS = [
6
+ ["accent", "--crediball-accent", String],
7
+ ["onAccent", "--crediball-on-accent", String],
8
+ ["ink", "--crediball-ink", String],
9
+ ["canvas", "--crediball-canvas", String],
10
+ ["hairline", "--crediball-hairline", String],
11
+ ["radius", "--crediball-radius", (v) => `${v}px`],
12
+ ["radiusCard", "--crediball-radius-card", (v) => `${v}px`],
13
+ ["fontStack", "--crediball-font", String]
14
+ ];
15
+ function loadRemoteFont(url) {
16
+ if (typeof document === "undefined") return;
17
+ const existing = document.querySelector("link[data-crediball-font]");
18
+ if (existing?.href === url) return;
19
+ if (existing) existing.href = url;
20
+ else {
21
+ const link = document.createElement("link");
22
+ link.rel = "stylesheet";
23
+ link.href = url;
24
+ link.setAttribute("data-crediball-font", "");
25
+ document.head.appendChild(link);
26
+ }
27
+ }
3
28
  var _CrediballElement = class _CrediballElement extends HTMLElement {
4
29
  constructor() {
5
30
  super(...arguments);
@@ -42,9 +67,30 @@ var _CrediballElement = class _CrediballElement extends HTMLElement {
42
67
  const lowCreditThreshold = thresholdAttr != null ? Number(thresholdAttr) : void 0;
43
68
  this.client = getCrediballClient({ publishableKey, userId, apiUrl, lowCreditThreshold });
44
69
  this.client.start();
45
- this.unsubscribe = this.client.subscribe(() => this.render());
70
+ this.unsubscribe = this.client.subscribe(() => {
71
+ this.applyRemoteTheme();
72
+ this.render();
73
+ });
74
+ this.applyRemoteTheme();
46
75
  this.render();
47
76
  }
77
+ /**
78
+ * Apply the developer-published theme (served alongside packages) as
79
+ * `--crediball-*` custom properties on this element — custom properties pierce
80
+ * the shadow boundary, so the shadow-DOM styles pick them up. On by default;
81
+ * set `apply-remote-theme="false"` to theme from your own CSS instead. The
82
+ * published theme takes precedence over host `--crediball-*` vars (dashboard wins).
83
+ */
84
+ applyRemoteTheme() {
85
+ if (this.getAttribute("apply-remote-theme") === "false") return;
86
+ const theme = this.getSnapshot()?.packages?.ui?.theme;
87
+ if (!theme) return;
88
+ for (const [key, cssVar, fmt] of THEME_VARS) {
89
+ const value = theme[key];
90
+ if (value != null && value !== "") this.style.setProperty(cssVar, fmt(value));
91
+ }
92
+ if (theme.fontUrl) loadRemoteFont(theme.fontUrl);
93
+ }
48
94
  teardownClient() {
49
95
  this.client?.stop();
50
96
  this.unsubscribe?.();
@@ -126,6 +172,8 @@ var CrediballTopUpButtonElement = class extends CrediballElement {
126
172
  this.button.addEventListener("click", () => this.handleClick());
127
173
  }
128
174
  render() {
175
+ const slot = this.button.querySelector("slot");
176
+ if (slot) slot.textContent = this.getSnapshot()?.packages?.ui?.content?.topUpButtonText ?? "Add credits";
129
177
  }
130
178
  handleClick() {
131
179
  const paywall = document.querySelector("crediball-paywall");
@@ -149,10 +197,13 @@ var CrediballLowCreditWarningElement = class extends CrediballElement {
149
197
  }
150
198
  render() {
151
199
  const snapshot = this.getSnapshot();
200
+ const content = snapshot?.packages?.ui?.content;
152
201
  const thresholdAttr = this.getAttribute("threshold");
153
- const threshold = thresholdAttr != null ? Number(thresholdAttr) : void 0;
202
+ const threshold = thresholdAttr != null ? Number(thresholdAttr) : content?.lowCreditThreshold;
154
203
  const isLow = threshold != null && snapshot?.balance != null ? snapshot.balance < threshold : !!snapshot?.isLow;
155
204
  this.style.display = isLow ? "" : "none";
205
+ const slot = this.shadowRoot?.querySelector("slot");
206
+ if (slot) slot.textContent = content?.lowCreditMessage ?? "Low credit balance \u2014 top up to keep going.";
156
207
  }
157
208
  };
158
209
 
@@ -285,9 +336,11 @@ var CrediballPaywallElement = class extends CrediballElement {
285
336
  }
286
337
  const snapshot = this.getSnapshot();
287
338
  const pkgs = snapshot?.packages;
339
+ const uiContent = pkgs?.ui?.content;
288
340
  const currency = pkgs?.currency ?? "EUR";
289
- const title = this.getAttribute("title") ?? "You need more credits to continue.";
290
- const description = this.getAttribute("description") ?? "Top up to keep using this feature.";
341
+ const title = this.getAttribute("title") ?? uiContent?.paywallTitle ?? "You need more credits to continue.";
342
+ const description = this.getAttribute("description") ?? uiContent?.paywallDescription ?? "Top up to keep using this feature.";
343
+ const addButtonText = uiContent?.paywallButtonText ?? "Add";
291
344
  const amountsAttr = this.getAttribute("amounts");
292
345
  const legacyAmounts = amountsAttr ? amountsAttr.split(",").map((s) => Number(s.trim())).filter((n) => Number.isFinite(n)) : [5, 10];
293
346
  const packages = pkgs?.packages ?? [];
@@ -330,7 +383,7 @@ var CrediballPaywallElement = class extends CrediballElement {
330
383
  ${showCustom ? `<div class="custom-row">
331
384
  <span class="sym">${escapeHtml(currencySymbolFor(currency))}</span>
332
385
  <input class="custom-input" inputmode="decimal" placeholder="${custom?.minEur ?? ""}" aria-label="Custom amount" />
333
- <button class="custom-add" type="button">Add</button>
386
+ <button class="custom-add" type="button">${escapeHtml(addButtonText)}</button>
334
387
  </div>` : ""}
335
388
  <p class="error" hidden></p>
336
389
  <button class="close" part="close" type="button">Not now</button>
@@ -69,7 +69,7 @@ var Crediball = (() => {
69
69
  }
70
70
 
71
71
  // ../core/dist/client.js
72
- var DEFAULT_API_URL = "https://crediball.app/api";
72
+ var DEFAULT_API_URL = "https://www.crediball.ai/api";
73
73
  var DEFAULT_POLL_MS = 3e4;
74
74
  var SSE_HEALTHY_POLL_MULTIPLIER = 2;
75
75
  var MAX_SSE_FAILURES = 2;
@@ -304,6 +304,29 @@ var Crediball = (() => {
304
304
  }
305
305
 
306
306
  // src/base.ts
307
+ var THEME_VARS = [
308
+ ["accent", "--crediball-accent", String],
309
+ ["onAccent", "--crediball-on-accent", String],
310
+ ["ink", "--crediball-ink", String],
311
+ ["canvas", "--crediball-canvas", String],
312
+ ["hairline", "--crediball-hairline", String],
313
+ ["radius", "--crediball-radius", (v) => `${v}px`],
314
+ ["radiusCard", "--crediball-radius-card", (v) => `${v}px`],
315
+ ["fontStack", "--crediball-font", String]
316
+ ];
317
+ function loadRemoteFont(url) {
318
+ if (typeof document === "undefined") return;
319
+ const existing = document.querySelector("link[data-crediball-font]");
320
+ if (existing?.href === url) return;
321
+ if (existing) existing.href = url;
322
+ else {
323
+ const link = document.createElement("link");
324
+ link.rel = "stylesheet";
325
+ link.href = url;
326
+ link.setAttribute("data-crediball-font", "");
327
+ document.head.appendChild(link);
328
+ }
329
+ }
307
330
  var _CrediballElement = class _CrediballElement extends HTMLElement {
308
331
  constructor() {
309
332
  super(...arguments);
@@ -346,9 +369,30 @@ var Crediball = (() => {
346
369
  const lowCreditThreshold = thresholdAttr != null ? Number(thresholdAttr) : void 0;
347
370
  this.client = getCrediballClient({ publishableKey, userId, apiUrl, lowCreditThreshold });
348
371
  this.client.start();
349
- this.unsubscribe = this.client.subscribe(() => this.render());
372
+ this.unsubscribe = this.client.subscribe(() => {
373
+ this.applyRemoteTheme();
374
+ this.render();
375
+ });
376
+ this.applyRemoteTheme();
350
377
  this.render();
351
378
  }
379
+ /**
380
+ * Apply the developer-published theme (served alongside packages) as
381
+ * `--crediball-*` custom properties on this element — custom properties pierce
382
+ * the shadow boundary, so the shadow-DOM styles pick them up. On by default;
383
+ * set `apply-remote-theme="false"` to theme from your own CSS instead. The
384
+ * published theme takes precedence over host `--crediball-*` vars (dashboard wins).
385
+ */
386
+ applyRemoteTheme() {
387
+ if (this.getAttribute("apply-remote-theme") === "false") return;
388
+ const theme = this.getSnapshot()?.packages?.ui?.theme;
389
+ if (!theme) return;
390
+ for (const [key, cssVar, fmt] of THEME_VARS) {
391
+ const value = theme[key];
392
+ if (value != null && value !== "") this.style.setProperty(cssVar, fmt(value));
393
+ }
394
+ if (theme.fontUrl) loadRemoteFont(theme.fontUrl);
395
+ }
352
396
  teardownClient() {
353
397
  this.client?.stop();
354
398
  this.unsubscribe?.();
@@ -430,6 +474,8 @@ var Crediball = (() => {
430
474
  this.button.addEventListener("click", () => this.handleClick());
431
475
  }
432
476
  render() {
477
+ const slot = this.button.querySelector("slot");
478
+ if (slot) slot.textContent = this.getSnapshot()?.packages?.ui?.content?.topUpButtonText ?? "Add credits";
433
479
  }
434
480
  handleClick() {
435
481
  const paywall = document.querySelector("crediball-paywall");
@@ -453,10 +499,13 @@ var Crediball = (() => {
453
499
  }
454
500
  render() {
455
501
  const snapshot = this.getSnapshot();
502
+ const content = snapshot?.packages?.ui?.content;
456
503
  const thresholdAttr = this.getAttribute("threshold");
457
- const threshold = thresholdAttr != null ? Number(thresholdAttr) : void 0;
504
+ const threshold = thresholdAttr != null ? Number(thresholdAttr) : content?.lowCreditThreshold;
458
505
  const isLow = threshold != null && snapshot?.balance != null ? snapshot.balance < threshold : !!snapshot?.isLow;
459
506
  this.style.display = isLow ? "" : "none";
507
+ const slot = this.shadowRoot?.querySelector("slot");
508
+ if (slot) slot.textContent = content?.lowCreditMessage ?? "Low credit balance \u2014 top up to keep going.";
460
509
  }
461
510
  };
462
511
 
@@ -589,9 +638,11 @@ var Crediball = (() => {
589
638
  }
590
639
  const snapshot = this.getSnapshot();
591
640
  const pkgs = snapshot?.packages;
641
+ const uiContent = pkgs?.ui?.content;
592
642
  const currency = pkgs?.currency ?? "EUR";
593
- const title = this.getAttribute("title") ?? "You need more credits to continue.";
594
- const description = this.getAttribute("description") ?? "Top up to keep using this feature.";
643
+ const title = this.getAttribute("title") ?? uiContent?.paywallTitle ?? "You need more credits to continue.";
644
+ const description = this.getAttribute("description") ?? uiContent?.paywallDescription ?? "Top up to keep using this feature.";
645
+ const addButtonText = uiContent?.paywallButtonText ?? "Add";
595
646
  const amountsAttr = this.getAttribute("amounts");
596
647
  const legacyAmounts = amountsAttr ? amountsAttr.split(",").map((s) => Number(s.trim())).filter((n) => Number.isFinite(n)) : [5, 10];
597
648
  const packages = pkgs?.packages ?? [];
@@ -634,7 +685,7 @@ var Crediball = (() => {
634
685
  ${showCustom ? `<div class="custom-row">
635
686
  <span class="sym">${escapeHtml(currencySymbolFor(currency))}</span>
636
687
  <input class="custom-input" inputmode="decimal" placeholder="${custom?.minEur ?? ""}" aria-label="Custom amount" />
637
- <button class="custom-add" type="button">Add</button>
688
+ <button class="custom-add" type="button">${escapeHtml(addButtonText)}</button>
638
689
  </div>` : ""}
639
690
  <p class="error" hidden></p>
640
691
  <button class="close" part="close" type="button">Not now</button>
package/dist/index.d.ts CHANGED
@@ -24,6 +24,14 @@ declare abstract class CrediballElement extends HTMLElement {
24
24
  */
25
25
  attributeChangedCallback(name: string): void;
26
26
  private connectClient;
27
+ /**
28
+ * Apply the developer-published theme (served alongside packages) as
29
+ * `--crediball-*` custom properties on this element — custom properties pierce
30
+ * the shadow boundary, so the shadow-DOM styles pick them up. On by default;
31
+ * set `apply-remote-theme="false"` to theme from your own CSS instead. The
32
+ * published theme takes precedence over host `--crediball-*` vars (dashboard wins).
33
+ */
34
+ private applyRemoteTheme;
27
35
  private teardownClient;
28
36
  protected getSnapshot(): CrediballSnapshot | null;
29
37
  /** Called on connect, on relevant attribute changes, and on every data update. */
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  CrediballPaywallElement,
6
6
  CrediballTopUpButtonElement,
7
7
  CrediballUsageElement
8
- } from "./chunk-AEVAHMRY.js";
8
+ } from "./chunk-KXVW7PIU.js";
9
9
  export {
10
10
  CrediballBalanceElement,
11
11
  CrediballElement,
package/dist/register.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  CrediballPaywallElement,
5
5
  CrediballTopUpButtonElement,
6
6
  CrediballUsageElement
7
- } from "./chunk-AEVAHMRY.js";
7
+ } from "./chunk-KXVW7PIU.js";
8
8
 
9
9
  // src/register.ts
10
10
  function define(name, ctor) {
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@crediball/elements",
3
- "version": "0.3.0",
3
+ "version": "0.4.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>",
7
- "homepage": "https://crediball.app",
7
+ "homepage": "https://crediball.ai",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "git+https://github.com/filipporezzadore/Crediball.git",
@@ -56,7 +56,7 @@
56
56
  "prepublishOnly": "npm run build"
57
57
  },
58
58
  "dependencies": {
59
- "@crediball/core": "^0.2.0"
59
+ "@crediball/core": "^0.3.0"
60
60
  },
61
61
  "devDependencies": {
62
62
  "tsup": "^8.3.5",