@rpgjs/client 5.0.0-beta.23 → 5.0.0-beta.25

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 (47) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/Game/Object.d.ts +5 -0
  3. package/dist/Game/Object.js +48 -2
  4. package/dist/Game/Object.js.map +1 -1
  5. package/dist/Gui/Gui.js +5 -0
  6. package/dist/Gui/Gui.js.map +1 -1
  7. package/dist/components/character.ce.js +9 -2
  8. package/dist/components/character.ce.js.map +1 -1
  9. package/dist/components/gui/dialogbox/index.ce.js +54 -4
  10. package/dist/components/gui/dialogbox/index.ce.js.map +1 -1
  11. package/dist/components/gui/hud/hud.ce.js +2 -2
  12. package/dist/components/gui/hud/hud.ce.js.map +1 -1
  13. package/dist/components/gui/index.d.ts +3 -1
  14. package/dist/components/gui/index.js +2 -0
  15. package/dist/components/gui/input-field.ce.js +123 -0
  16. package/dist/components/gui/input-field.ce.js.map +1 -0
  17. package/dist/components/gui/input.ce.js +40 -0
  18. package/dist/components/gui/input.ce.js.map +1 -0
  19. package/dist/components/gui/menu/items-menu.ce.js +27 -4
  20. package/dist/components/gui/menu/items-menu.ce.js.map +1 -1
  21. package/dist/components/gui/menu/main-menu.ce.js +210 -155
  22. package/dist/components/gui/menu/main-menu.ce.js.map +1 -1
  23. package/dist/components/gui/save-load.ce.js +33 -4
  24. package/dist/components/gui/save-load.ce.js.map +1 -1
  25. package/dist/components/gui/shop/shop.ce.js +47 -4
  26. package/dist/components/gui/shop/shop.ce.js.map +1 -1
  27. package/dist/i18n.d.ts +11 -0
  28. package/dist/i18n.js +11 -0
  29. package/dist/i18n.js.map +1 -1
  30. package/dist/index.js +13 -11
  31. package/package.json +4 -4
  32. package/src/Game/Object.spec.ts +26 -2
  33. package/src/Game/Object.ts +71 -2
  34. package/src/Gui/Gui.spec.ts +5 -0
  35. package/src/Gui/Gui.ts +5 -1
  36. package/src/components/character.ce +12 -6
  37. package/src/components/gui/dialogbox/index.ce +82 -41
  38. package/src/components/gui/hud/hud.ce +2 -2
  39. package/src/components/gui/index.ts +5 -1
  40. package/src/components/gui/input-field.ce +106 -0
  41. package/src/components/gui/input.ce +26 -0
  42. package/src/components/gui/menu/items-menu.ce +12 -2
  43. package/src/components/gui/menu/main-menu.ce +37 -6
  44. package/src/components/gui/save-load.ce +48 -32
  45. package/src/components/gui/shop/shop.ce +28 -3
  46. package/src/i18n.ts +11 -0
  47. package/vite.config.ts +5 -2
@@ -0,0 +1,123 @@
1
+ import { inject } from "../../core/inject.js";
2
+ import { RpgClientEngine } from "../../RpgClientEngine.js";
3
+ import { DOMElement, computed, cond, effect, h, signal, useDefineEmits, useDefineProps, useProps } from "canvasengine";
4
+ //#region src/components/gui/input-field.ce
5
+ function component($$props) {
6
+ useProps($$props);
7
+ const defineProps = useDefineProps($$props);
8
+ const defineEmits = useDefineEmits($$props);
9
+ const { t } = inject(RpgClientEngine).i18n();
10
+ const { data, layout, showMessage } = defineProps({
11
+ layout: "standalone",
12
+ showMessage: true
13
+ });
14
+ const { submit, cancel } = defineEmits();
15
+ const formData = computed(() => data() || {});
16
+ const value = signal(String(formData().defaultValue ?? ""));
17
+ const fieldId = computed(() => `rpg-input-value-${layout()}`);
18
+ const errorText = computed(() => formData().errorKey ? t(formData().errorKey, formData().errorParams || {}) : "");
19
+ const showCancelButton = computed(() => formData().cancelButton !== false);
20
+ let focused = false;
21
+ function submitForm(event, collectedData) {
22
+ const submittedValue = collectedData && Object.prototype.hasOwnProperty.call(collectedData, "value") ? collectedData.value : event?.currentTarget?.elements?.value?.value ?? value();
23
+ value.set(String(submittedValue ?? ""));
24
+ submit({ value: submittedValue ?? "" });
25
+ }
26
+ function cancelForm() {
27
+ cancel();
28
+ }
29
+ function handleKeydown(event) {
30
+ if (event?.key !== "Escape") return;
31
+ event.preventDefault?.();
32
+ event.stopPropagation?.();
33
+ cancelForm();
34
+ }
35
+ effect(() => {
36
+ if (focused) return;
37
+ focused = true;
38
+ setTimeout(() => {
39
+ document.getElementById(fieldId())?.focus?.();
40
+ });
41
+ });
42
+ return h(DOMElement, {
43
+ element: "form",
44
+ attrs: {
45
+ class: "rpg-ui-input-form",
46
+ "data-layout": computed(() => layout()),
47
+ submit: submitForm,
48
+ keydown: handleKeydown
49
+ }
50
+ }, [
51
+ cond(computed(() => showMessage()), () => h(DOMElement, {
52
+ element: "label",
53
+ attrs: {
54
+ class: "rpg-ui-input-message",
55
+ for: computed(() => fieldId())
56
+ },
57
+ textContent: computed(() => formData().message)
58
+ })),
59
+ cond(computed(() => formData().control === "textarea"), () => h(DOMElement, {
60
+ element: "textarea",
61
+ attrs: {
62
+ id: computed(() => fieldId()),
63
+ class: "rpg-ui-input rpg-ui-input-dialog-field",
64
+ name: "value",
65
+ value,
66
+ placeholder: computed(() => formData().placeholder || ""),
67
+ rows: computed(() => formData().rows || 4),
68
+ minlength: computed(() => formData().minLength),
69
+ maxlength: computed(() => formData().maxLength),
70
+ "aria-required": computed(() => formData().required ? "true" : "false")
71
+ }
72
+ }), () => h(DOMElement, {
73
+ element: "input",
74
+ attrs: {
75
+ id: computed(() => fieldId()),
76
+ class: "rpg-ui-input rpg-ui-input-dialog-field",
77
+ name: "value",
78
+ type: computed(() => formData().type || "text"),
79
+ value,
80
+ placeholder: computed(() => formData().placeholder || ""),
81
+ min: computed(() => formData().min),
82
+ max: computed(() => formData().max),
83
+ step: computed(() => formData().step),
84
+ minlength: computed(() => formData().minLength),
85
+ maxlength: computed(() => formData().maxLength),
86
+ "aria-required": computed(() => formData().required ? "true" : "false")
87
+ }
88
+ })),
89
+ cond(computed(() => errorText()), () => h(DOMElement, {
90
+ element: "div",
91
+ attrs: {
92
+ class: "rpg-ui-input-error",
93
+ role: "alert"
94
+ },
95
+ textContent: computed(() => errorText())
96
+ })),
97
+ h(DOMElement, {
98
+ element: "div",
99
+ attrs: { class: "rpg-ui-input-actions" }
100
+ }, [cond(computed(() => showCancelButton()), () => h(DOMElement, {
101
+ element: "button",
102
+ attrs: {
103
+ class: "rpg-ui-btn rpg-ui-input-button rpg-ui-input-button-cancel",
104
+ type: "button",
105
+ click: cancelForm
106
+ },
107
+ textContent: computed(() => formData().cancelText || t("rpg.input.cancel"))
108
+ })), h(DOMElement, {
109
+ element: "button",
110
+ attrs: {
111
+ class: "rpg-ui-btn rpg-ui-input-button rpg-ui-input-button-confirm",
112
+ "data-variant": "primary",
113
+ type: "submit"
114
+ },
115
+ textContent: computed(() => formData().confirmText || t("rpg.input.confirm"))
116
+ })])
117
+ ]);
118
+ }
119
+ var __ce_component = component;
120
+ //#endregion
121
+ export { __ce_component as default };
122
+
123
+ //# sourceMappingURL=input-field.ce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-field.ce.js","names":[],"sources":["../../../src/components/gui/input-field.ce"],"sourcesContent":["<form\n class=\"rpg-ui-input-form\"\n data-layout={layout()}\n submit={submitForm}\n keydown={handleKeydown}\n>\n @if (showMessage()) {\n <label class=\"rpg-ui-input-message\" for={fieldId()}>{formData().message}</label>\n }\n @if (formData().control === \"textarea\") {\n <textarea\n id={fieldId()}\n class=\"rpg-ui-input rpg-ui-input-dialog-field\"\n name=\"value\"\n value={value}\n placeholder={formData().placeholder || \"\"}\n rows={formData().rows || 4}\n minlength={formData().minLength}\n maxlength={formData().maxLength}\n aria-required={formData().required ? \"true\" : \"false\"}\n ></textarea>\n }\n @else {\n <input\n id={fieldId()}\n class=\"rpg-ui-input rpg-ui-input-dialog-field\"\n name=\"value\"\n type={formData().type || \"text\"}\n value={value}\n placeholder={formData().placeholder || \"\"}\n min={formData().min}\n max={formData().max}\n step={formData().step}\n minlength={formData().minLength}\n maxlength={formData().maxLength}\n aria-required={formData().required ? \"true\" : \"false\"}\n />\n }\n @if (errorText()) {\n <div class=\"rpg-ui-input-error\" role=\"alert\">{errorText()}</div>\n }\n <div class=\"rpg-ui-input-actions\">\n @if (showCancelButton()) {\n <button class=\"rpg-ui-btn rpg-ui-input-button rpg-ui-input-button-cancel\" type=\"button\" click={cancelForm}>\n {formData().cancelText || t(\"rpg.input.cancel\")}\n </button>\n }\n <button\n class=\"rpg-ui-btn rpg-ui-input-button rpg-ui-input-button-confirm\"\n data-variant=\"primary\"\n type=\"submit\"\n >\n {formData().confirmText || t(\"rpg.input.confirm\")}\n </button>\n </div>\n</form>\n\n<script>\n import { computed, effect, signal } from \"canvasengine\";\n import { inject } from \"../../core/inject\";\n import { RpgClientEngine } from \"../../RpgClientEngine\";\n\n const engine = inject(RpgClientEngine);\n const { t } = engine.i18n();\n const { data, layout, showMessage } = defineProps({\n layout: \"standalone\",\n showMessage: true,\n });\n const { submit, cancel } = defineEmits();\n const formData = computed(() => data() || {});\n const value = signal(String(formData().defaultValue ?? \"\"));\n const fieldId = computed(() => `rpg-input-value-${layout()}`);\n const errorText = computed(() => formData().errorKey\n ? t(formData().errorKey, formData().errorParams || {})\n : \"\"\n );\n const showCancelButton = computed(() => formData().cancelButton !== false);\n let focused = false;\n\n function submitForm(event, collectedData) {\n const submittedValue = collectedData && Object.prototype.hasOwnProperty.call(collectedData, \"value\")\n ? collectedData.value\n : event?.currentTarget?.elements?.value?.value ?? value();\n value.set(String(submittedValue ?? \"\"));\n submit({ value: submittedValue ?? \"\" });\n }\n\n function cancelForm() {\n cancel();\n }\n\n function handleKeydown(event) {\n if (event?.key !== \"Escape\") return;\n event.preventDefault?.();\n event.stopPropagation?.();\n cancelForm();\n }\n\n effect(() => {\n if (focused) return;\n focused = true;\n setTimeout(() => {\n document.getElementById(fieldId())?.focus?.();\n });\n });\n</script>\n"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import __ce_component$1 from "./input-field.ce.js";
2
+ import { DOMContainer, DOMElement, computed, cond, h, useDefineEmits, useDefineProps, useProps } from "canvasengine";
3
+ //#region src/components/gui/input.ce
4
+ function component($$props) {
5
+ useProps($$props);
6
+ const defineProps = useDefineProps($$props);
7
+ useDefineEmits($$props);
8
+ const { data, onInteraction } = defineProps();
9
+ const title = computed(() => data().title || "");
10
+ function submit(payload) {
11
+ onInteraction?.("submit", payload);
12
+ }
13
+ function cancel() {
14
+ onInteraction?.("cancel");
15
+ }
16
+ return h(DOMContainer, {
17
+ width: "100%",
18
+ height: "100%"
19
+ }, h(DOMElement, {
20
+ element: "div",
21
+ attrs: { class: "rpg-ui-input-layer" }
22
+ }, h(DOMElement, {
23
+ element: "div",
24
+ attrs: { class: "rpg-ui-input-dialog rpg-ui-window rpg-anim-fade-in" }
25
+ }, [cond(computed(() => title()), () => h(DOMElement, {
26
+ element: "div",
27
+ attrs: { class: "rpg-ui-window-title" },
28
+ textContent: computed(() => title())
29
+ })), h(__ce_component$1, {
30
+ data,
31
+ layout: "standalone",
32
+ submit,
33
+ cancel
34
+ })])));
35
+ }
36
+ var __ce_component = component;
37
+ //#endregion
38
+ export { __ce_component as default };
39
+
40
+ //# sourceMappingURL=input.ce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.ce.js","names":[],"sources":["../../../src/components/gui/input.ce"],"sourcesContent":["<DOMContainer width=\"100%\" height=\"100%\">\n <div class=\"rpg-ui-input-layer\">\n <div class=\"rpg-ui-input-dialog rpg-ui-window rpg-anim-fade-in\">\n @if (title()) {\n <div class=\"rpg-ui-window-title\">{title()}</div>\n }\n <InputField data={data} layout=\"standalone\" submit={submit} cancel={cancel} />\n </div>\n </div>\n</DOMContainer>\n\n<script>\n import { computed } from \"canvasengine\";\n import InputField from \"./input-field.ce\";\n\n const { data, onInteraction } = defineProps();\n const title = computed(() => data().title || \"\");\n\n function submit(payload) {\n onInteraction?.(\"submit\", payload);\n }\n\n function cancel() {\n onInteraction?.(\"cancel\");\n }\n</script>\n"],"mappings":";;;AAQI,SAAG,UAAA,SAAA;CACO,SAAA,OAAA;;CAEP,eAAA,OAAA;CACC,MAAG,EAAA,MAAW,kBAAkB,YAAC;CACzC,MAAE,QAAO,eAAmB,KAAM,EAAA,SAAS,EAAA;;EAEzC,gBAAc,UAAc,OAAI;CAClC;;EAEE,gBAAgB,QAAS;CAC3B;QACE,EAAA,cAAA;EAAA,OAAA;EAAA,QAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,qBAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,qDAAA;CAAA,GAAA,CAAA,KAAA,eAAA,MAAA,CAAA,SAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,sBAAA;EAAA,aAAA,eAAA,MAAA,CAAA;CAAA,CAAA,CAAA,GAAA,EAAA,kBAAA;EAAA;EAAA,QAAA;EAAA;EAAA;CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAEA;AAEA,IAAA,iBAAA"}
@@ -105,6 +105,13 @@ function component($$props) {
105
105
  confirmItem.set(null);
106
106
  });
107
107
  };
108
+ const stopEvent = (event) => {
109
+ event?.stopPropagation?.();
110
+ };
111
+ const cancelConfirmFromPointer = (event) => {
112
+ stopEvent(event);
113
+ cancelConfirm();
114
+ };
108
115
  function confirmSelect(index) {
109
116
  return function() {
110
117
  selectedConfirm.set(index);
@@ -296,10 +303,26 @@ function component($$props) {
296
303
  })])))])]),
297
304
  cond(confirmOpen, () => h(DOMElement, {
298
305
  element: "div",
299
- attrs: { class: "rpg-ui-menu-confirm" }
300
- }, h(DOMElement, {
306
+ attrs: {
307
+ class: "rpg-ui-menu-confirm",
308
+ click: cancelConfirmFromPointer
309
+ }
310
+ }, [h(DOMElement, {
311
+ element: "button",
312
+ attrs: {
313
+ class: "rpg-ui-close-button",
314
+ type: "button",
315
+ title: "Close",
316
+ "aria-label": "Close confirmation",
317
+ click: cancelConfirmFromPointer
318
+ },
319
+ textContent: "x"
320
+ }), h(DOMElement, {
301
321
  element: "div",
302
- attrs: { class: "rpg-ui-menu-confirm-card" }
322
+ attrs: {
323
+ class: "rpg-ui-menu-confirm-card",
324
+ click: stopEvent
325
+ }
303
326
  }, [h(DOMElement, {
304
327
  element: "div",
305
328
  attrs: { class: "rpg-ui-menu-confirm-title" },
@@ -319,7 +342,7 @@ function component($$props) {
319
342
  click: confirmSelect(index)
320
343
  },
321
344
  textContent: option.label
322
- }))))])))
345
+ }))))])]))
323
346
  ]));
324
347
  }
325
348
  var __ce_component = component;
@@ -1 +1 @@
1
- {"version":3,"file":"items-menu.ce.js","names":[],"sources":["../../../../src/components/gui/menu/items-menu.ce"],"sourcesContent":["<DOMContainer width=\"100%\" height=\"100%\">\n <div class=\"rpg-ui-menu-panel rpg-ui-panel\">\n <div class=\"rpg-ui-menu-panel-header\">{t(\"rpg.menu.items\")}</div>\n <div class=\"rpg-ui-menu-panel-body rpg-ui-menu-panel-body-stacked\">\n <div>\n @if (currentItem) {\n <div class=\"rpg-ui-menu-panel-details rpg-ui-panel\">\n <div class=\"rpg-ui-menu-panel-hero\">\n <div class=\"rpg-ui-menu-panel-hero-icon\">\n <DOMSprite \n sheet={iconSheet(currentItem()?.icon)} \n playing=\"default\" \n width=\"48px\"\n height=\"48px\"\n objectFit=\"contain\"\n />\n </div>\n <div>\n <div class=\"rpg-ui-menu-panel-details-title\">{currentItem()?.name}</div>\n <div class=\"rpg-ui-menu-panel-details-desc\">{currentItem()?.description || \"\"}</div>\n </div>\n </div>\n </div>\n }\n </div>\n \n <div class=\"rpg-ui-menu-panel-list rpg-ui-menu rpg-ui-menu-panel-list-full\">\n <div class=\"rpg-ui-menu-tabs\">\n @for ((tab,tabIndex) of tabs) {\n <div\n class=\"rpg-ui-menu-tab\"\n class={{active: selectedTab() === tabIndex}}\n tabindex={tabIndex}\n click={selectTab(tabIndex)}\n >{tab.label}</div>\n }\n </div>\n <Navigation tabindex={selectedItem} controls={controls}>\n @for ((item,index) of filteredItems) {\n <div\n class=\"rpg-ui-menu-item rpg-ui-menu-row\"\n class={{disabled: !item.usable}}\n data-selected={selectedItem() === index ? \"true\" : \"false\"}\n tabindex={index}\n click={selectItem(index)}\n >\n <div class=\"rpg-ui-menu-row-main\">\n <div class=\"rpg-ui-menu-row-icon\">\n <DOMSprite \n sheet={iconSheet(item.icon)} \n playing=\"default\" \n width=\"28px\"\n height=\"28px\"\n objectFit=\"contain\"\n />\n </div>\n <span>{item.name}</span>\n </div>\n <span class=\"rpg-ui-menu-row-end\">x{item.quantity ?? 1}</span>\n </div>\n }\n </Navigation>\n </div>\n </div>\n @if (confirmOpen) {\n <div class=\"rpg-ui-menu-confirm\">\n <div class=\"rpg-ui-menu-confirm-card\">\n <div class=\"rpg-ui-menu-confirm-title\">{t(\"rpg.menu.use\")} {confirmItem()?.name}?</div>\n <Navigation tabindex={selectedConfirm} controls={confirmControls}>\n <div class=\"rpg-ui-menu-confirm-actions\">\n @for ((option,index) of confirmOptions) {\n <button\n class=\"rpg-ui-menu-confirm-btn\"\n class={{\"rpg-ui-menu-confirm-btn-secondary\": option.id === \"cancel\"}}\n data-selected={selectedConfirm() === index ? \"true\" : \"false\"}\n tabindex={index}\n click={confirmSelect(index)}\n >{option.label}</button>\n }\n </div>\n </Navigation>\n </div>\n </div>\n }\n </div>\n</DOMContainer>\n\n<script>\n import { signal, computed, createTabindexNavigator, effect } from \"canvasengine\";\n import { inject } from \"../../../core/inject\";\n import { RpgClientEngine } from \"../../../RpgClientEngine\";\n import { delay } from \"@rpgjs/common\";\n import { getKeyboardControlBind } from \"../../../services/actionInput\";\n\n const engine = inject(RpgClientEngine);\n const { t } = engine.i18n();\n const keyboardControls = engine.globalConfig.keyboardControls;\n\n const selectedItem = signal(0);\n const selectedTab = signal(0);\n const selectedConfirm = signal(0);\n const confirmOpen = signal(false);\n const confirmItem = signal(null);\n\n const { data, onInteraction, onBack } = defineProps();\n\n const items = computed(() => data().items);\n\n const tabs = [\n { id: \"item\", label: t(\"rpg.menu.items\") },\n { id: \"weapon\", label: t(\"rpg.menu.weapons\") },\n { id: \"armor\", label: t(\"rpg.menu.armor\") }\n ];\n\n const resolveProp = (value) => typeof value === \"function\" ? value() : value;\n const safeItems = computed(() => {\n const value = resolveProp(items);\n return Array.isArray(value) ? value : [];\n });\n\n const filteredItems = computed(() => {\n const items = safeItems();\n const tab = tabs[selectedTab()];\n if (!tab) return [];\n return items.filter((item) => item.type === tab.id && (item.quantity ?? 1) > 0);\n });\n\n const confirmOptions = [\n { id: \"use\", label: t(\"rpg.menu.use\") },\n { id: \"cancel\", label: t(\"rpg.menu.cancel\") }\n ];\n\n const nav = createTabindexNavigator(selectedItem, { count: () => filteredItems().length }, \"wrap\");\n const navConfirm = createTabindexNavigator(selectedConfirm, { count: () => confirmOptions.length }, \"wrap\");\n const currentItem = computed(() => filteredItems()[selectedItem()]);\n const iconSheet = (iconId) => ({\n definition: engine.getSpriteSheet(iconId)\n });\n\n const clampSelection = () => {\n const count = filteredItems().length;\n if (count === 0) {\n selectedItem.set(0);\n return;\n }\n if (selectedItem() >= count) {\n selectedItem.set(count - 1);\n }\n };\n\n function selectItem(index) {\n return function() {\n selectedItem.set(index);\n requestUseItem(index);\n }\n }\n\n function selectTab(index) {\n return function() {\n selectedItem.set(0);\n selectedTab.set(index);\n }\n }\n\n const useItem = (index) => {\n const item = filteredItems()[index];\n if (!item || !item.usable) return;\n if (onInteraction) onInteraction(\"useItem\", { id: item.id });\n };\n\n const requestUseItem = (index) => {\n const item = filteredItems()[index];\n if (!item || !item.usable) return;\n if (item.consumable) {\n confirmItem.set(item);\n confirmOpen.set(true);\n selectedConfirm.set(0);\n return;\n }\n useItem(index);\n };\n\n const confirmUse = () => {\n const item = confirmItem();\n if (!item) return;\n delay(() => {\n if (onInteraction) onInteraction(\"useItem\", { id: item.id });\n confirmOpen.set(false);\n confirmItem.set(null);\n });\n };\n\n const cancelConfirm = () => {\n delay(() => {\n confirmOpen.set(false);\n confirmItem.set(null);\n });\n };\n\n function confirmSelect(index) {\n return function() {\n selectedConfirm.set(index);\n if (index === 0) {\n confirmUse();\n return;\n }\n cancelConfirm();\n }\n }\n\n const confirmControls = signal({\n left: {\n repeat: true,\n bind: keyboardControls.left,\n throttle: 150,\n keyDown() {\n if (!confirmOpen()) return;\n navConfirm.next(-1);\n }\n },\n right: {\n repeat: true,\n bind: keyboardControls.right,\n throttle: 150,\n keyDown() {\n if (!confirmOpen()) return;\n navConfirm.next(1);\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (!confirmOpen()) return;\n confirmSelect(selectedConfirm())();\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n if (!confirmOpen()) return;\n cancelConfirm();\n }\n }\n });\n\n const controls = signal({\n up: {\n repeat: true,\n bind: keyboardControls.up,\n throttle: 150,\n keyDown() {\n if (confirmOpen()) {\n return;\n }\n nav.next(-1);\n }\n },\n left: {\n repeat: true,\n bind: keyboardControls.left,\n throttle: 150,\n keyDown() {\n if (confirmOpen()) {\n return;\n }\n selectedTab.update((value) => (value - 1 + tabs.length) % tabs.length);\n selectedItem.set(0);\n }\n },\n right: {\n repeat: true,\n bind: keyboardControls.right,\n throttle: 150,\n keyDown() {\n if (confirmOpen()) {\n return;\n }\n selectedTab.update((value) => (value + 1) % tabs.length);\n selectedItem.set(0);\n }\n },\n down: {\n repeat: true,\n bind: keyboardControls.down,\n throttle: 150,\n keyDown() {\n if (confirmOpen()) {\n return;\n }\n nav.next(1);\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (confirmOpen()) {\n confirmSelect(selectedConfirm())();\n return;\n }\n requestUseItem(selectedItem());\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n if (confirmOpen()) {\n cancelConfirm();\n return;\n }\n if (onBack) onBack();\n }\n },\n gamepad: {\n enabled: true\n }\n });\n\n clampSelection();\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"items-menu.ce.js","names":[],"sources":["../../../../src/components/gui/menu/items-menu.ce"],"sourcesContent":["<DOMContainer width=\"100%\" height=\"100%\">\n <div class=\"rpg-ui-menu-panel rpg-ui-panel\">\n <div class=\"rpg-ui-menu-panel-header\">{t(\"rpg.menu.items\")}</div>\n <div class=\"rpg-ui-menu-panel-body rpg-ui-menu-panel-body-stacked\">\n <div>\n @if (currentItem) {\n <div class=\"rpg-ui-menu-panel-details rpg-ui-panel\">\n <div class=\"rpg-ui-menu-panel-hero\">\n <div class=\"rpg-ui-menu-panel-hero-icon\">\n <DOMSprite \n sheet={iconSheet(currentItem()?.icon)} \n playing=\"default\" \n width=\"48px\"\n height=\"48px\"\n objectFit=\"contain\"\n />\n </div>\n <div>\n <div class=\"rpg-ui-menu-panel-details-title\">{currentItem()?.name}</div>\n <div class=\"rpg-ui-menu-panel-details-desc\">{currentItem()?.description || \"\"}</div>\n </div>\n </div>\n </div>\n }\n </div>\n \n <div class=\"rpg-ui-menu-panel-list rpg-ui-menu rpg-ui-menu-panel-list-full\">\n <div class=\"rpg-ui-menu-tabs\">\n @for ((tab,tabIndex) of tabs) {\n <div\n class=\"rpg-ui-menu-tab\"\n class={{active: selectedTab() === tabIndex}}\n tabindex={tabIndex}\n click={selectTab(tabIndex)}\n >{tab.label}</div>\n }\n </div>\n <Navigation tabindex={selectedItem} controls={controls}>\n @for ((item,index) of filteredItems) {\n <div\n class=\"rpg-ui-menu-item rpg-ui-menu-row\"\n class={{disabled: !item.usable}}\n data-selected={selectedItem() === index ? \"true\" : \"false\"}\n tabindex={index}\n click={selectItem(index)}\n >\n <div class=\"rpg-ui-menu-row-main\">\n <div class=\"rpg-ui-menu-row-icon\">\n <DOMSprite \n sheet={iconSheet(item.icon)} \n playing=\"default\" \n width=\"28px\"\n height=\"28px\"\n objectFit=\"contain\"\n />\n </div>\n <span>{item.name}</span>\n </div>\n <span class=\"rpg-ui-menu-row-end\">x{item.quantity ?? 1}</span>\n </div>\n }\n </Navigation>\n </div>\n </div>\n @if (confirmOpen) {\n <div class=\"rpg-ui-menu-confirm\" click={cancelConfirmFromPointer}>\n <button class=\"rpg-ui-close-button\" type=\"button\" title=\"Close\" aria-label=\"Close confirmation\" click={cancelConfirmFromPointer}>x</button>\n <div class=\"rpg-ui-menu-confirm-card\" click={stopEvent}>\n <div class=\"rpg-ui-menu-confirm-title\">{t(\"rpg.menu.use\")} {confirmItem()?.name}?</div>\n <Navigation tabindex={selectedConfirm} controls={confirmControls}>\n <div class=\"rpg-ui-menu-confirm-actions\">\n @for ((option,index) of confirmOptions) {\n <button\n class=\"rpg-ui-menu-confirm-btn\"\n class={{\"rpg-ui-menu-confirm-btn-secondary\": option.id === \"cancel\"}}\n data-selected={selectedConfirm() === index ? \"true\" : \"false\"}\n tabindex={index}\n click={confirmSelect(index)}\n >{option.label}</button>\n }\n </div>\n </Navigation>\n </div>\n </div>\n }\n </div>\n</DOMContainer>\n\n<script>\n import { signal, computed, createTabindexNavigator, effect } from \"canvasengine\";\n import { inject } from \"../../../core/inject\";\n import { RpgClientEngine } from \"../../../RpgClientEngine\";\n import { delay } from \"@rpgjs/common\";\n import { getKeyboardControlBind } from \"../../../services/actionInput\";\n\n const engine = inject(RpgClientEngine);\n const { t } = engine.i18n();\n const keyboardControls = engine.globalConfig.keyboardControls;\n\n const selectedItem = signal(0);\n const selectedTab = signal(0);\n const selectedConfirm = signal(0);\n const confirmOpen = signal(false);\n const confirmItem = signal(null);\n\n const { data, onInteraction, onBack } = defineProps();\n\n const items = computed(() => data().items);\n\n const tabs = [\n { id: \"item\", label: t(\"rpg.menu.items\") },\n { id: \"weapon\", label: t(\"rpg.menu.weapons\") },\n { id: \"armor\", label: t(\"rpg.menu.armor\") }\n ];\n\n const resolveProp = (value) => typeof value === \"function\" ? value() : value;\n const safeItems = computed(() => {\n const value = resolveProp(items);\n return Array.isArray(value) ? value : [];\n });\n\n const filteredItems = computed(() => {\n const items = safeItems();\n const tab = tabs[selectedTab()];\n if (!tab) return [];\n return items.filter((item) => item.type === tab.id && (item.quantity ?? 1) > 0);\n });\n\n const confirmOptions = [\n { id: \"use\", label: t(\"rpg.menu.use\") },\n { id: \"cancel\", label: t(\"rpg.menu.cancel\") }\n ];\n\n const nav = createTabindexNavigator(selectedItem, { count: () => filteredItems().length }, \"wrap\");\n const navConfirm = createTabindexNavigator(selectedConfirm, { count: () => confirmOptions.length }, \"wrap\");\n const currentItem = computed(() => filteredItems()[selectedItem()]);\n const iconSheet = (iconId) => ({\n definition: engine.getSpriteSheet(iconId)\n });\n\n const clampSelection = () => {\n const count = filteredItems().length;\n if (count === 0) {\n selectedItem.set(0);\n return;\n }\n if (selectedItem() >= count) {\n selectedItem.set(count - 1);\n }\n };\n\n function selectItem(index) {\n return function() {\n selectedItem.set(index);\n requestUseItem(index);\n }\n }\n\n function selectTab(index) {\n return function() {\n selectedItem.set(0);\n selectedTab.set(index);\n }\n }\n\n const useItem = (index) => {\n const item = filteredItems()[index];\n if (!item || !item.usable) return;\n if (onInteraction) onInteraction(\"useItem\", { id: item.id });\n };\n\n const requestUseItem = (index) => {\n const item = filteredItems()[index];\n if (!item || !item.usable) return;\n if (item.consumable) {\n confirmItem.set(item);\n confirmOpen.set(true);\n selectedConfirm.set(0);\n return;\n }\n useItem(index);\n };\n\n const confirmUse = () => {\n const item = confirmItem();\n if (!item) return;\n delay(() => {\n if (onInteraction) onInteraction(\"useItem\", { id: item.id });\n confirmOpen.set(false);\n confirmItem.set(null);\n });\n };\n\n const cancelConfirm = () => {\n delay(() => {\n confirmOpen.set(false);\n confirmItem.set(null);\n });\n };\n\n const stopEvent = (event) => {\n event?.stopPropagation?.();\n };\n\n const cancelConfirmFromPointer = (event) => {\n stopEvent(event);\n cancelConfirm();\n };\n\n function confirmSelect(index) {\n return function() {\n selectedConfirm.set(index);\n if (index === 0) {\n confirmUse();\n return;\n }\n cancelConfirm();\n }\n }\n\n const confirmControls = signal({\n left: {\n repeat: true,\n bind: keyboardControls.left,\n throttle: 150,\n keyDown() {\n if (!confirmOpen()) return;\n navConfirm.next(-1);\n }\n },\n right: {\n repeat: true,\n bind: keyboardControls.right,\n throttle: 150,\n keyDown() {\n if (!confirmOpen()) return;\n navConfirm.next(1);\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (!confirmOpen()) return;\n confirmSelect(selectedConfirm())();\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n if (!confirmOpen()) return;\n cancelConfirm();\n }\n }\n });\n\n const controls = signal({\n up: {\n repeat: true,\n bind: keyboardControls.up,\n throttle: 150,\n keyDown() {\n if (confirmOpen()) {\n return;\n }\n nav.next(-1);\n }\n },\n left: {\n repeat: true,\n bind: keyboardControls.left,\n throttle: 150,\n keyDown() {\n if (confirmOpen()) {\n return;\n }\n selectedTab.update((value) => (value - 1 + tabs.length) % tabs.length);\n selectedItem.set(0);\n }\n },\n right: {\n repeat: true,\n bind: keyboardControls.right,\n throttle: 150,\n keyDown() {\n if (confirmOpen()) {\n return;\n }\n selectedTab.update((value) => (value + 1) % tabs.length);\n selectedItem.set(0);\n }\n },\n down: {\n repeat: true,\n bind: keyboardControls.down,\n throttle: 150,\n keyDown() {\n if (confirmOpen()) {\n return;\n }\n nav.next(1);\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (confirmOpen()) {\n confirmSelect(selectedConfirm())();\n return;\n }\n requestUseItem(selectedItem());\n }\n },\n escape: {\n bind: keyboardControls.escape,\n keyDown() {\n if (confirmOpen()) {\n cancelConfirm();\n return;\n }\n if (onBack) onBack();\n }\n },\n gamepad: {\n enabled: true\n }\n });\n\n clampSelection();\n</script>\n"],"mappings":"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"}