poe-svelte-ui-lib 1.74.0 → 1.74.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.
@@ -19,7 +19,7 @@ const encodeUInt = (input) => {
19
19
  if (value <= 0xffffn)
20
20
  return [0x19, Number(value >> 8n), Number(value & 0xffn)];
21
21
  if (value <= 0xffffffffn)
22
- return [0x1a, Number(value >> 24n), Number(value >> 16n & 0xffn), Number(value >> 8n & 0xffn), Number(value & 0xffn)];
22
+ return [0x1a, Number(value >> 24n), Number((value >> 16n) & 0xffn), Number((value >> 8n) & 0xffn), Number(value & 0xffn)];
23
23
  throw new Error("xPOE-Debug integer is out of range");
24
24
  };
25
25
  export const xPoeDebugCmd = (header, argument) => {
@@ -41,8 +41,13 @@ export const encodeXPoeDebugFrame = (header, argument, value, srcId = 0, freeHea
41
41
  const crc = crc16Kermit(0, prefix);
42
42
  return new Uint8Array([...prefix, ...encodeUInt(crc)]);
43
43
  };
44
- const textItems = (bytes) => decoder.decode(bytes).split("\n").map((line) => line.trim()).filter((line) => line && ![...line].some((char) => char.charCodeAt(0) < 0x20 && char !== "\t")).map((text) => ({ type: "raw", text }));
45
- const readUInt = (value) => typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 0xffff ? value : null;
44
+ const textItems = (bytes) => decoder
45
+ .decode(bytes)
46
+ .split("\n")
47
+ .map((line) => line.trim())
48
+ .filter((line) => line && ![...line].some((char) => char.charCodeAt(0) < 0x20 && char !== "\t"))
49
+ .map((text) => ({ type: "raw", text }));
50
+ const readUInt = (value) => (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 0xffff ? value : null);
46
51
  /* Декодирует одну definite array из начала буфера; null означает неполный или невалидный кадр. */
47
52
  const frameItem = (buffer) => {
48
53
  if (buffer[0] !== ARRAY5)
@@ -63,14 +68,27 @@ const frameItem = (buffer) => {
63
68
  const freeHeapValue = fields.decode();
64
69
  const crcStart = 1 + fields.offset;
65
70
  const crc = readUInt(fields.decode());
66
- if (fields.offset !== length - 1 || crc === null || (freeHeapValue !== null && (typeof freeHeapValue !== "number" || !Number.isInteger(freeHeapValue) || freeHeapValue < 0)))
71
+ if (fields.offset !== length - 1 ||
72
+ crc === null ||
73
+ (freeHeapValue !== null && (typeof freeHeapValue !== "number" || !Number.isInteger(freeHeapValue) || freeHeapValue < 0)))
67
74
  return { status: "garbage" };
68
75
  const valueBytes = buffer.slice(valueStart, valueEnd);
69
76
  const { header, argument } = splitCmd(cmd);
70
77
  return {
71
78
  status: "complete",
72
79
  length,
73
- item: { type: "frame", srcId, cmd, header: Object.entries(HEADER_CODES).find(([, code]) => code === header)?.[0] ?? String(header), argument: nameByCode(DEFAULT_ARGUMENT_CODES, argument), value: Array.from(valueBytes, (byte) => byte.toString(16).padStart(2, "0").toUpperCase()).join(""), valueBytes, crc: crc.toString(16).toUpperCase().padStart(4, "0"), crcOk: crc16Kermit(0, buffer.subarray(0, crcStart)) === crc, freeHeap: typeof freeHeapValue === "number" ? String(freeHeapValue) : "" },
80
+ item: {
81
+ type: "frame",
82
+ srcId,
83
+ cmd,
84
+ header: Object.entries(HEADER_CODES).find(([, code]) => code === header)?.[0] ?? String(header),
85
+ argument: nameByCode(DEFAULT_ARGUMENT_CODES, argument),
86
+ value: Array.from(valueBytes, (byte) => byte.toString(16).padStart(2, "0").toUpperCase()).join(""),
87
+ valueBytes,
88
+ crc: crc.toString(16).toUpperCase().padStart(4, "0"),
89
+ crcOk: crc16Kermit(0, buffer.subarray(0, crcStart)) === crc,
90
+ freeHeap: typeof freeHeapValue === "number" ? String(freeHeapValue) : "",
91
+ },
74
92
  };
75
93
  }
76
94
  catch (error) {
@@ -124,7 +142,9 @@ export const createXPoeDebugParser = () => {
124
142
  }
125
143
  return items;
126
144
  },
127
- reset() { buffer = new Uint8Array(); },
145
+ reset() {
146
+ buffer = new Uint8Array();
147
+ },
128
148
  };
129
149
  };
130
150
  /* Value form input: ready CBOR hex passes through; JSON is converted to CBOR. */
@@ -52,6 +52,17 @@ export function formatXPoeDebugValueForTable(rawValue, isCbor = true) {
52
52
  const COPY_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="1.5"><path d="M6 11c0-2.828 0-4.243.879-5.121C7.757 5 9.172 5 12 5h3c2.828 0 4.243 0 5.121.879C21 6.757 21 8.172 21 11v5c0 2.828 0 4.243-.879 5.121C19.243 22 17.828 22 15 22h-3c-2.828 0-4.243 0-5.121-.879C6 20.243 6 18.828 6 16z"/><path d="M6 19a3 3 0 0 1-3-3v-6c0-3.771 0-5.657 1.172-6.828S7.229 2 11 2h4a3 3 0 0 1 3 3"/></g></svg>`;
53
53
  const COPIED_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
54
54
  let copyBindings = 0;
55
+ let copyObserver = null;
56
+ const removeXPoeDebugModalFooters = () => {
57
+ document.querySelectorAll("[data-modal]").forEach((modal) => {
58
+ if (!modal.querySelector("[data-xpoe-debug-modal]"))
59
+ return;
60
+ const footer = modal.lastElementChild;
61
+ if (!footer || modal.children.length < 3)
62
+ return;
63
+ footer.remove();
64
+ });
65
+ };
55
66
  const handleCopyClick = (event) => {
56
67
  if (!(event.target instanceof Element))
57
68
  return;
@@ -79,15 +90,22 @@ const handleCopyClick = (event) => {
79
90
  };
80
91
  /* Делегированный обработчик кнопок модального окна; возвращённую функцию вызывают при уничтожении страницы. */
81
92
  export function bindXPoeDebugCopyButtons() {
82
- if (copyBindings++ === 0)
93
+ if (copyBindings++ === 0) {
83
94
  document.addEventListener("click", handleCopyClick);
95
+ removeXPoeDebugModalFooters();
96
+ copyObserver = new MutationObserver(removeXPoeDebugModalFooters);
97
+ copyObserver.observe(document.documentElement, { childList: true, subtree: true });
98
+ }
84
99
  let isBound = true;
85
100
  return () => {
86
101
  if (!isBound)
87
102
  return;
88
103
  isBound = false;
89
- if (--copyBindings === 0)
104
+ if (--copyBindings === 0) {
90
105
  document.removeEventListener("click", handleCopyClick);
106
+ copyObserver?.disconnect();
107
+ copyObserver = null;
108
+ }
91
109
  };
92
110
  }
93
111
  /* Две прокручиваемые секции модалки; HEX-раздел появляется, если форматтер таблицы добавил исходные байты. */
@@ -103,5 +121,5 @@ export function formatXPoeDebugModal(text) {
103
121
  const buttonClass = "flex size-7 cursor-pointer items-center justify-center rounded-lg border-none bg-transparent text-(--faint-color) transition-colors duration-150 hover:bg-(--container-color) hover:text-(--font-color)";
104
122
  const textStyle = "display:block;min-width:0;max-width:100%;margin:0;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;font:inherit";
105
123
  const pane = (title, target, value) => `<section style="${sectionStyle}"><div style="${headingStyle}"><span>${title}</span><button type="button" class="${buttonClass}" data-xpoe-copy="${target}" aria-label="Копировать ${title}" style="${buttonStyle}">${COPY_ICON}</button></div><pre style="${textStyle}">${value}</pre></section>`;
106
- return `<style>[data-modal]:has([data-xpoe-debug-modal])>div:last-child{display:none!important}</style><div data-xpoe-debug-modal style="${modalStyle}">${pane("Value", "value", decoded)}${hexIndex < 0 ? "" : pane("HEX", "hex", hex)}</div>`;
124
+ return `<div data-xpoe-debug-modal style="${modalStyle}">${pane("Value", "value", decoded)}${hexIndex < 0 ? "" : pane("HEX", "hex", hex)}</div>`;
107
125
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-svelte-ui-lib",
3
- "version": "1.74.0",
3
+ "version": "1.74.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Oleg-Perevyshin/ElementsUI.git"