@carmaclouds/core 2.3.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 (118) hide show
  1. package/dist/cache/CacheManager.d.ts.map +1 -0
  2. package/dist/cache/CacheManager.js +131 -0
  3. package/dist/cache/CacheManager.js.map +1 -0
  4. package/dist/index.d.ts +18 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +22 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/ir/index.d.ts +11 -0
  9. package/dist/ir/index.d.ts.map +1 -0
  10. package/dist/ir/index.js +9 -0
  11. package/dist/ir/index.js.map +1 -0
  12. package/dist/ir/normalize.d.ts +10 -0
  13. package/dist/ir/normalize.d.ts.map +1 -0
  14. package/dist/ir/normalize.js +207 -0
  15. package/dist/ir/normalize.js.map +1 -0
  16. package/dist/ir/persistence.d.ts +26 -0
  17. package/dist/ir/persistence.d.ts.map +1 -0
  18. package/dist/ir/persistence.js +21 -0
  19. package/dist/ir/persistence.js.map +1 -0
  20. package/dist/ir/sync.d.ts +12 -0
  21. package/dist/ir/sync.d.ts.map +1 -0
  22. package/dist/ir/sync.js +36 -0
  23. package/dist/ir/sync.js.map +1 -0
  24. package/dist/ir/types.d.ts +143 -0
  25. package/dist/ir/types.d.ts.map +1 -0
  26. package/dist/ir/types.js +13 -0
  27. package/dist/ir/types.js.map +1 -0
  28. package/dist/ir/views/dnd5e.d.ts +40 -0
  29. package/dist/ir/views/dnd5e.d.ts.map +1 -0
  30. package/dist/ir/views/dnd5e.js +50 -0
  31. package/dist/ir/views/dnd5e.js.map +1 -0
  32. package/dist/render/character.d.ts +19 -0
  33. package/dist/render/character.d.ts.map +1 -0
  34. package/dist/render/character.js +156 -0
  35. package/dist/render/character.js.map +1 -0
  36. package/dist/render/h.d.ts +27 -0
  37. package/dist/render/h.d.ts.map +1 -0
  38. package/dist/render/h.js +64 -0
  39. package/dist/render/h.js.map +1 -0
  40. package/dist/render/index.d.ts +11 -0
  41. package/dist/render/index.d.ts.map +1 -0
  42. package/dist/render/index.js +8 -0
  43. package/dist/render/index.js.map +1 -0
  44. package/dist/render/mount.d.ts +31 -0
  45. package/dist/render/mount.d.ts.map +1 -0
  46. package/dist/render/mount.js +63 -0
  47. package/dist/render/mount.js.map +1 -0
  48. package/dist/supabase/fields.d.ts.map +1 -0
  49. package/dist/supabase/fields.js +120 -0
  50. package/dist/supabase/fields.js.map +1 -0
  51. package/dist/types/character.d.ts.map +1 -0
  52. package/dist/types/character.js +5 -0
  53. package/dist/types/character.js.map +1 -0
  54. package/package.json +73 -0
  55. package/src/browser.js +51 -0
  56. package/src/cache/CacheManager.ts +174 -0
  57. package/src/common/browser-polyfill.js +319 -0
  58. package/src/common/debug.js +123 -0
  59. package/src/common/html-utils.js +134 -0
  60. package/src/common/theme-manager.js +265 -0
  61. package/src/index.ts +25 -0
  62. package/src/ir/__fixtures__/dnd5e-character.json +75962 -0
  63. package/src/ir/__fixtures__/non-dnd-character.json +14218 -0
  64. package/src/ir/index.ts +10 -0
  65. package/src/ir/normalize.ts +245 -0
  66. package/src/ir/persistence.ts +37 -0
  67. package/src/ir/sync.ts +49 -0
  68. package/src/ir/types.ts +161 -0
  69. package/src/ir/views/dnd5e.ts +94 -0
  70. package/src/lib/indexeddb-cache.js +320 -0
  71. package/src/modules/action-announcements.js +102 -0
  72. package/src/modules/action-display.js +1557 -0
  73. package/src/modules/action-executor.js +860 -0
  74. package/src/modules/action-filters.js +167 -0
  75. package/src/modules/action-options.js +117 -0
  76. package/src/modules/card-creator.js +142 -0
  77. package/src/modules/character-portrait.js +169 -0
  78. package/src/modules/character-trait-popups.js +959 -0
  79. package/src/modules/character-traits.js +814 -0
  80. package/src/modules/class-feature-edge-cases.js +1320 -0
  81. package/src/modules/color-utils.js +69 -0
  82. package/src/modules/combat-maneuver-edge-cases.js +660 -0
  83. package/src/modules/companions-manager.js +178 -0
  84. package/src/modules/concentration-tracker.js +178 -0
  85. package/src/modules/data-manager.js +514 -0
  86. package/src/modules/dice-roller.js +719 -0
  87. package/src/modules/effects-manager.js +743 -0
  88. package/src/modules/feature-modals.js +1264 -0
  89. package/src/modules/formula-resolver.js +444 -0
  90. package/src/modules/gm-mode.js +184 -0
  91. package/src/modules/health-modals.js +399 -0
  92. package/src/modules/hp-management.js +752 -0
  93. package/src/modules/inventory-manager.js +242 -0
  94. package/src/modules/macro-system.js +825 -0
  95. package/src/modules/notification-system.js +92 -0
  96. package/src/modules/racial-feature-edge-cases.js +746 -0
  97. package/src/modules/resource-manager.js +775 -0
  98. package/src/modules/sheet-builder.js +654 -0
  99. package/src/modules/spell-action-modals.js +583 -0
  100. package/src/modules/spell-cards.js +602 -0
  101. package/src/modules/spell-casting.js +723 -0
  102. package/src/modules/spell-display.js +314 -0
  103. package/src/modules/spell-edge-cases.js +509 -0
  104. package/src/modules/spell-macros.js +201 -0
  105. package/src/modules/spell-modals.js +1221 -0
  106. package/src/modules/spell-slots.js +224 -0
  107. package/src/modules/status-bar-bridge.js +101 -0
  108. package/src/modules/ui-utilities.js +284 -0
  109. package/src/modules/warlock-invocations.js +219 -0
  110. package/src/modules/window-management.js +211 -0
  111. package/src/render/character.ts +234 -0
  112. package/src/render/h.ts +74 -0
  113. package/src/render/index.ts +10 -0
  114. package/src/render/mount.ts +94 -0
  115. package/src/supabase/client.js +1383 -0
  116. package/src/supabase/config.js +60 -0
  117. package/src/supabase/fields.ts +129 -0
  118. package/src/types/character.ts +85 -0
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Tiny DOM builder - the rebuild's render primitive. Replaces innerHTML template
3
+ * strings with safe DOM construction: text and attribute values go through
4
+ * textContent / setAttribute, so interpolated character data (now arbitrary,
5
+ * user-named attributes from any system) can never be parsed as HTML.
6
+ *
7
+ * h('div', { class: 'box', onClick: () => roll() },
8
+ * h('span', { class: 'label', text: name }), // text -> textContent (safe)
9
+ * score) // primitives -> text node
10
+ */
11
+
12
+ export type HChild = Node | string | number | null | undefined | boolean | HChild[];
13
+
14
+ export interface HProps {
15
+ /** textContent - use for any dynamic / character data. */
16
+ text?: string | number;
17
+ /** className. */
18
+ class?: string;
19
+ /** Inline style as a string (cssText) or a property map. */
20
+ style?: string | Partial<Record<string, string>>;
21
+ /** data-* attributes. */
22
+ dataset?: Record<string, string>;
23
+ /** onClick / onInput / onChange / ... -> addEventListener. */
24
+ [key: string]: unknown;
25
+ }
26
+
27
+ function append(el: Node, child: HChild): void {
28
+ if (child == null || child === false || child === true) return;
29
+ if (Array.isArray(child)) {
30
+ for (const c of child) append(el, c);
31
+ } else if (child instanceof Node) {
32
+ el.appendChild(child);
33
+ } else {
34
+ el.appendChild(document.createTextNode(String(child)));
35
+ }
36
+ }
37
+
38
+ export function h(tag: string, props?: HProps | null, ...children: HChild[]): HTMLElement {
39
+ const el = document.createElement(tag);
40
+
41
+ if (props) {
42
+ for (const [key, value] of Object.entries(props)) {
43
+ if (value == null || value === false) continue;
44
+
45
+ if (key === 'text') {
46
+ el.textContent = String(value);
47
+ } else if (key === 'class') {
48
+ el.className = value as string;
49
+ } else if (key === 'style') {
50
+ if (typeof value === 'string') el.style.cssText = value;
51
+ else Object.assign(el.style, value);
52
+ } else if (key === 'dataset') {
53
+ Object.assign(el.dataset, value as Record<string, string>);
54
+ } else if (
55
+ key.length > 2 && key[0] === 'o' && key[1] === 'n' &&
56
+ key[2] === key[2].toUpperCase() && typeof value === 'function'
57
+ ) {
58
+ el.addEventListener(key.slice(2).toLowerCase(), value as EventListener);
59
+ } else {
60
+ el.setAttribute(key, String(value));
61
+ }
62
+ }
63
+ }
64
+
65
+ append(el, children);
66
+ return el;
67
+ }
68
+
69
+ /** Replace all children of `el` with the given nodes/values. */
70
+ export function setChildren(el: Element, ...children: HChild[]): Element {
71
+ el.replaceChildren();
72
+ append(el, children);
73
+ return el;
74
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * System-agnostic render layer for the rebuild. DOM construction only (no
3
+ * innerHTML); adapters mount the returned elements. See REBUILD.md.
4
+ */
5
+ export { h, setChildren } from './h';
6
+ export type { HChild, HProps } from './h';
7
+ export { renderCharacterSheet } from './character';
8
+ export type { RenderOpts } from './character';
9
+ export { fetchCharacterIR, mountCharacterIR, mountIRToggle } from './mount';
10
+ export type { IRTarget } from './mount';
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Fetch a character's IR from clouds_character_ir and render it into a container.
3
+ * Shared by every adapter surface (Owlbear popover, RollCloud popup-sheet, ...)
4
+ * so each one is a couple of lines and the fetch/render/empty-state logic lives
5
+ * in one place.
6
+ */
7
+ import type { IRCharacter } from '../ir/types';
8
+ import { renderCharacterSheet, type RenderOpts } from './character';
9
+ import { h } from './h';
10
+
11
+ export interface IRTarget {
12
+ url: string;
13
+ anonKey: string;
14
+ }
15
+
16
+ /** GET the stored IR for a character, or null if there isn't one yet. */
17
+ export async function fetchCharacterIR(
18
+ charId: string,
19
+ target: IRTarget,
20
+ ): Promise<IRCharacter | null> {
21
+ const res = await fetch(
22
+ `${target.url}/rest/v1/clouds_character_ir?dicecloud_character_id=eq.${encodeURIComponent(charId)}&select=ir`,
23
+ { headers: { apikey: target.anonKey, Authorization: `Bearer ${target.anonKey}` } },
24
+ );
25
+ if (!res.ok) return null;
26
+ const rows = await res.json().catch(() => []);
27
+ return rows?.[0]?.ir ?? null;
28
+ }
29
+
30
+ /**
31
+ * Fetch + render into `container`. Returns the IR (or null). On no-IR / error it
32
+ * renders a small message rather than throwing, so callers can fire-and-forget.
33
+ */
34
+ export async function mountCharacterIR(
35
+ container: Element,
36
+ charId: string,
37
+ target: IRTarget,
38
+ opts: RenderOpts = {},
39
+ ): Promise<IRCharacter | null> {
40
+ try {
41
+ const ir = await fetchCharacterIR(charId, target);
42
+ if (!ir) {
43
+ container.replaceChildren(h('div', {
44
+ class: 'cc-empty', style: 'padding: 10px; font-size: 12px; opacity: 0.7;',
45
+ text: 'No IR stored yet - re-sync this character from DiceCloud.',
46
+ }));
47
+ return null;
48
+ }
49
+ container.replaceChildren(renderCharacterSheet(ir, opts));
50
+ return ir;
51
+ } catch (e) {
52
+ container.replaceChildren(h('div', {
53
+ class: 'cc-empty', style: 'padding: 10px; font-size: 12px; opacity: 0.7;',
54
+ text: 'Failed to load IR view.',
55
+ }));
56
+ return null;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Append a "⚗️ IR view (beta)" toggle + collapsible panel to `host`. The IR is
62
+ * lazily fetched and rendered the first time the panel opens, using `getCharId()`
63
+ * (read live, so it picks up whichever character is currently active).
64
+ *
65
+ * This is the whole per-adapter integration: one call.
66
+ */
67
+ export function mountIRToggle(
68
+ host: Element,
69
+ getCharId: () => string | null | undefined,
70
+ target: IRTarget,
71
+ opts: RenderOpts = {},
72
+ label = '⚗️ IR view (beta)',
73
+ ): { panel: HTMLElement; reload: () => void } {
74
+ const btn = h('button', { class: 'cc-ir-toggle', text: label });
75
+ const panel = h('div', { class: 'cc-ir-panel', style: 'display:none; margin-top:8px;' });
76
+ let loaded = false;
77
+
78
+ btn.addEventListener('click', async () => {
79
+ const open = panel.style.display === 'none';
80
+ panel.style.display = open ? 'block' : 'none';
81
+ if (open && !loaded) {
82
+ const id = getCharId();
83
+ if (!id) {
84
+ panel.replaceChildren(h('div', { class: 'cc-empty', text: 'No character loaded yet.' }));
85
+ return;
86
+ }
87
+ loaded = true;
88
+ await mountCharacterIR(panel, id, target, opts);
89
+ }
90
+ });
91
+
92
+ host.append(btn, panel);
93
+ return { panel, reload: () => { loaded = false; } };
94
+ }