tref-block 0.1.0 → 0.2.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.
package/LICENSE CHANGED
@@ -1,5 +1,5 @@
1
1
  TREF - Traceable Reference Blocks
2
- Copyright (C) 2026 lpm
2
+ Copyright (C) 2026 lpmwfx
3
3
 
4
4
  This program is free software: you can redistribute it and/or modify
5
5
  it under the terms of the GNU Affero General Public License as published by
package/README.md CHANGED
@@ -144,6 +144,7 @@ doc/
144
144
 
145
145
  - [Project & Architecture](doc/project.md) – vision, principles, single-source architecture
146
146
  - [UI/UX Specification](doc/TrefBlockUIUX.md) – complete UI/UX design guide
147
+ - [Auto TREF Block Generation](doc/auto-tref-blocks.md) – build TREF blocks from markdown at commit time
147
148
 
148
149
  ## Status
149
150
 
@@ -36,19 +36,17 @@ var u=".tref",g=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" w
36
36
  --tref-receiver-error-bg: #fef2f2;
37
37
  --tref-receiver-block-bg: #ffffff;
38
38
  }
39
- @media (prefers-color-scheme: dark) {
40
- :root {
41
- --tref-menu-bg: #1f2937;
42
- --tref-menu-text: #e5e7eb;
43
- --tref-menu-hover: #374151;
44
- --tref-menu-shadow: 0 4px 12px rgba(0,0,0,0.4);
45
- --tref-receiver-bg: #1f2937;
46
- --tref-receiver-text: #9ca3af;
47
- --tref-receiver-active-bg: #3b2d5e;
48
- --tref-receiver-success-bg: #064e3b;
49
- --tref-receiver-error-bg: #450a0a;
50
- --tref-receiver-block-bg: #111827;
51
- }
39
+ .dark {
40
+ --tref-menu-bg: #1f2937;
41
+ --tref-menu-text: #e5e7eb;
42
+ --tref-menu-hover: #374151;
43
+ --tref-menu-shadow: 0 4px 12px rgba(0,0,0,0.4);
44
+ --tref-receiver-bg: #1f2937;
45
+ --tref-receiver-text: #9ca3af;
46
+ --tref-receiver-active-bg: #3b2d5e;
47
+ --tref-receiver-success-bg: #064e3b;
48
+ --tref-receiver-error-bg: #450a0a;
49
+ --tref-receiver-block-bg: #111827;
52
50
  }
53
51
  .tref-wrapper {
54
52
  display: inline-block;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/wrapper/wrapper.js"],
4
- "sourcesContent": ["/**\n * @fileoverview TREF Block wrapper for display and interaction\n * Self-contained - no external dependencies\n */\n\n/* global btoa, navigator, Blob, URL, document */\n\n/** File extension for TREF files */\nconst TREF_EXTENSION = '.tref';\n\n/**\n * @typedef {object} TrefBlock\n * @property {1} v\n * @property {string} id\n * @property {string} content\n * @property {{ author?: string, created: string, modified?: string, license: string, lang?: string }} meta\n * @property {Array<{ type: string, url?: string, title?: string, snippet?: string, query?: string }>} [refs]\n * @property {string} [parent]\n */\n\n/**\n * SVG icon for TREF (purple-mint theme with chain link)\n */\nexport const TREF_ICON_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" width=\"24\" height=\"24\">\n <rect x=\"6\" y=\"6\" width=\"88\" height=\"88\" rx=\"12\" ry=\"12\" fill=\"#2D1B4E\" stroke=\"#5CCCCC\" stroke-width=\"5\"/>\n <g transform=\"translate(50 50) scale(0.022) translate(-1125 -1125)\">\n <g transform=\"translate(0,2250) scale(1,-1)\" fill=\"#5CCCCC\">\n <path d=\"M1515 2244 c-66 -10 -144 -38 -220 -77 -67 -35 -106 -67 -237 -195 -155 -152 -188 -195 -188 -247 0 -41 30 -95 64 -116 39 -24 113 -25 146 -3 14 9 90 81 170 160 183 181 216 199 350 199 83 0 103 -4 155 -28 78 -36 146 -104 182 -181 24 -53 28 -73 28 -151 0 -137 -21 -175 -199 -355 -79 -80 -151 -156 -160 -170 -39 -59 -8 -162 58 -194 81 -38 113 -22 284 147 165 163 230 252 268 370 24 71 28 99 28 202 0 106 -3 130 -28 200 -91 261 -310 428 -579 439 -50 3 -105 2 -122 0z\"/>\n <path d=\"M1395 1585 c-17 -9 -189 -174 -382 -368 -377 -378 -383 -385 -362 -461 21 -76 87 -116 166 -101 33 6 80 49 386 353 191 191 358 362 369 381 26 42 28 109 4 146 -39 59 -118 81 -181 50z\"/>\n <path d=\"M463 1364 c-47 -24 -323 -310 -365 -379 -20 -33 -49 -96 -64 -140 -24 -69 -28 -96 -28 -195 0 -127 14 -190 66 -294 63 -126 157 -220 284 -284 104 -52 167 -66 294 -66 99 0 126 4 195 28 44 15 107 44 140 64 65 39 348 309 371 354 41 78 -10 184 -96 203 -61 13 -98 -11 -256 -166 -186 -183 -222 -204 -359 -204 -77 0 -98 4 -147 27 -79 37 -142 98 -181 177 -29 59 -32 74 -32 156 0 136 21 174 199 355 79 80 150 156 159 170 23 33 22 107 -2 146 -35 57 -115 79 -178 48z\"/>\n </g>\n </g>\n</svg>`;\n\n/** MIME type for TREF files */\nexport const TREF_MIME_TYPE = 'application/vnd.tref+json';\n\n/** Icon as data URL for embedding */\nexport const TREF_ICON_DATA_URL = 'data:image/svg+xml,' + encodeURIComponent(TREF_ICON_SVG);\n\n/**\n * Escape HTML special characters\n * @param {string} str\n * @returns {string}\n */\nfunction _escapeHtml(str) {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n// Reserved for future use (content escaping)\nvoid _escapeHtml;\n\n/**\n * Validate block structure\n * @param {unknown} block\n * @returns {block is TrefBlock}\n */\nfunction isValidBlock(block) {\n if (!block || typeof block !== 'object') {\n return false;\n }\n const b = /** @type {Record<string, unknown>} */ (block);\n if (b.v !== 1) {\n return false;\n }\n if (typeof b.id !== 'string') {\n return false;\n }\n if (!b.id.startsWith('sha256:')) {\n return false;\n }\n if (typeof b.content !== 'string') {\n return false;\n }\n if (!b.meta || typeof b.meta !== 'object') {\n return false;\n }\n return true;\n}\n\n/**\n * TrefWrapper - displays a TREF block with drag/copy/download actions\n *\n * Design:\n * - Icon is the drag handle (only icon is draggable)\n * - Hover shows action buttons (copy, download)\n * - Status feedback in the ID badge\n */\nexport class TrefWrapper {\n /** @type {TrefBlock} */\n #block;\n\n /**\n * @param {TrefBlock} block\n */\n constructor(block) {\n if (!isValidBlock(block)) {\n throw new Error('Invalid TREF block');\n }\n this.#block = block;\n }\n\n get block() {\n return this.#block;\n }\n\n get id() {\n return this.#block.id;\n }\n\n get shortId() {\n return this.#block.id.replace('sha256:', '').slice(0, 8);\n }\n\n get content() {\n return this.#block.content;\n }\n\n /**\n * @param {{ pretty?: boolean }} [options]\n */\n toJSON(options = {}) {\n return options.pretty ? JSON.stringify(this.#block, null, 2) : JSON.stringify(this.#block);\n }\n\n getFilename() {\n return this.#block.id.replace('sha256:', '') + TREF_EXTENSION;\n }\n\n toBlob() {\n return new Blob([this.toJSON()], { type: TREF_MIME_TYPE });\n }\n\n toDataURL() {\n const json = this.toJSON();\n const base64 = btoa(unescape(encodeURIComponent(json)));\n return `data:${TREF_MIME_TYPE};base64,${base64}`;\n }\n\n toObjectURL() {\n return URL.createObjectURL(this.toBlob());\n }\n\n async copyToClipboard() {\n await navigator.clipboard.writeText(this.toJSON());\n }\n\n async copyContentToClipboard() {\n await navigator.clipboard.writeText(this.#block.content);\n }\n\n getDragData() {\n const json = this.toJSON();\n return [\n { type: TREF_MIME_TYPE, data: json },\n { type: 'application/json', data: json },\n { type: 'text/plain', data: json },\n ];\n }\n\n /** @param {DataTransfer} dataTransfer */\n setDragData(dataTransfer) {\n for (const { type, data } of this.getDragData()) {\n dataTransfer.setData(type, data);\n }\n }\n\n /**\n * Generate HTML - icon only with hover actions\n * @param {{ interactive?: boolean }} [options]\n */\n toHTML(options = {}) {\n const { interactive = true } = options;\n\n // SVG icons for actions\n const iconCopy = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg>`;\n const iconJson = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5a2 2 0 0 0 2 2h1\"></path><path d=\"M16 3h1a2 2 0 0 1 2 2v5a2 2 0 0 0 2 2 2 2 0 0 0-2 2v5a2 2 0 0 1-2 2h-1\"></path><circle cx=\"12\" cy=\"12\" r=\"1\" fill=\"currentColor\"></circle><circle cx=\"8\" cy=\"12\" r=\"1\" fill=\"currentColor\"></circle><circle cx=\"16\" cy=\"12\" r=\"1\" fill=\"currentColor\"></circle></svg>`;\n const iconDownload = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"></path><polyline points=\"7 10 12 15 17 10\"></polyline><line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"></line></svg>`;\n\n // Hover actions appear on hover\n const actionsHtml = interactive\n ? `<div class=\"tref-actions\" role=\"group\" aria-label=\"Block actions\">\n <button class=\"tref-action\" data-action=\"copy-content\" title=\"Copy content\" aria-label=\"Copy content to clipboard\">${iconCopy}</button>\n <button class=\"tref-action\" data-action=\"copy-json\" title=\"Copy JSON\" aria-label=\"Copy JSON to clipboard\">${iconJson}</button>\n <button class=\"tref-action\" data-action=\"download\" title=\"Download .tref\" aria-label=\"Download as .tref file\">${iconDownload}</button>\n </div>`\n : '';\n\n return `<div class=\"tref-wrapper\" data-tref-id=\"${this.#block.id}\">\n <span class=\"tref-icon\"\n role=\"button\"\n aria-label=\"TREF block - drag to share\"\n tabindex=\"0\"\n draggable=\"true\"\n title=\"Drag to share\">${TREF_ICON_SVG}</span>\n ${actionsHtml}\n</div>`;\n }\n\n /**\n * Toggle actions visibility (for keyboard/touch)\n * @param {HTMLElement} element\n */\n #toggleActions(element) {\n const actions = element.querySelector('.tref-actions');\n if (actions) {\n const actionsEl = /** @type {HTMLElement} */ (actions);\n const isVisible = actionsEl.style.opacity === '1';\n actionsEl.style.opacity = isVisible ? '0' : '1';\n if (!isVisible) {\n // Focus first action button\n const firstBtn = actionsEl.querySelector('button');\n if (firstBtn) {\n /** @type {HTMLElement} */ (firstBtn).focus();\n }\n }\n }\n }\n\n /**\n * Attach event listeners to a rendered wrapper\n * @param {HTMLElement} element\n */\n attachEvents(element) {\n const iconEl = element.querySelector('.tref-icon');\n\n // Icon is drag handle\n if (iconEl) {\n const icon = /** @type {HTMLElement} */ (iconEl);\n\n icon.addEventListener('dragstart', e => {\n const de = /** @type {DragEvent} */ (e);\n if (de.dataTransfer) {\n this.setDragData(de.dataTransfer);\n de.dataTransfer.effectAllowed = 'copy';\n }\n });\n\n // Keyboard: Enter/Space shows actions or triggers default action\n icon.addEventListener('keydown', e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this.#toggleActions(element);\n }\n });\n\n // Touch: tap toggles actions\n icon.addEventListener('touchend', e => {\n // Only handle if not dragging\n if (!icon.dataset.dragging) {\n e.preventDefault();\n this.#toggleActions(element);\n }\n });\n\n // Touch: long-press (500ms) to start drag indication\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let longPressTimer;\n icon.addEventListener('touchstart', () => {\n longPressTimer = setTimeout(() => {\n icon.dataset.dragging = 'true';\n icon.style.transform = 'scale(1.15)';\n }, 500);\n });\n icon.addEventListener('touchend', () => {\n clearTimeout(longPressTimer);\n delete icon.dataset.dragging;\n icon.style.transform = '';\n });\n icon.addEventListener('touchcancel', () => {\n clearTimeout(longPressTimer);\n delete icon.dataset.dragging;\n icon.style.transform = '';\n });\n }\n\n // Action buttons (visible on hover via CSS)\n const handleAction = async (/** @type {Event} */ e) => {\n e.stopPropagation();\n const btn = /** @type {HTMLElement} */ (e.currentTarget);\n const action = btn.dataset.action;\n const originalHtml = btn.innerHTML;\n\n const iconCheck = `<svg class=\"tref-icon-success\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>`;\n const iconError = `<svg class=\"tref-icon-error\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>`;\n\n try {\n if (action === 'copy-content') {\n await this.copyContentToClipboard();\n btn.innerHTML = iconCheck;\n } else if (action === 'copy-json') {\n await this.copyToClipboard();\n btn.innerHTML = iconCheck;\n } else if (action === 'download') {\n const url = this.toObjectURL();\n const a = document.createElement('a');\n a.href = url;\n a.download = this.getFilename();\n a.click();\n URL.revokeObjectURL(url);\n btn.innerHTML = iconCheck;\n }\n setTimeout(() => {\n btn.innerHTML = originalHtml;\n }, 1000);\n } catch {\n btn.innerHTML = iconError;\n setTimeout(() => {\n btn.innerHTML = originalHtml;\n }, 1000);\n }\n };\n\n element.querySelectorAll('.tref-action').forEach(btn => {\n btn.addEventListener('click', e => void handleAction(e));\n });\n }\n\n static getStyles() {\n return `\n:root {\n --tref-accent: #5CCCCC;\n --tref-accent-hover: #8B5CF6;\n --tref-success: #10B981;\n --tref-error: #ef4444;\n --tref-menu-bg: #ffffff;\n --tref-menu-text: #374151;\n --tref-menu-hover: #f3f4f6;\n --tref-menu-shadow: 0 4px 12px rgba(0,0,0,0.15);\n --tref-receiver-bg: #f9fafb;\n --tref-receiver-text: #6b7280;\n --tref-receiver-active-bg: #f3e8ff;\n --tref-receiver-success-bg: #ecfdf5;\n --tref-receiver-error-bg: #fef2f2;\n --tref-receiver-block-bg: #ffffff;\n}\n@media (prefers-color-scheme: dark) {\n :root {\n --tref-menu-bg: #1f2937;\n --tref-menu-text: #e5e7eb;\n --tref-menu-hover: #374151;\n --tref-menu-shadow: 0 4px 12px rgba(0,0,0,0.4);\n --tref-receiver-bg: #1f2937;\n --tref-receiver-text: #9ca3af;\n --tref-receiver-active-bg: #3b2d5e;\n --tref-receiver-success-bg: #064e3b;\n --tref-receiver-error-bg: #450a0a;\n --tref-receiver-block-bg: #111827;\n }\n}\n.tref-wrapper {\n display: inline-block;\n position: relative;\n}\n.tref-icon {\n display: inline-flex;\n width: 32px;\n height: 32px;\n cursor: grab;\n transition: transform 0.15s;\n}\n.tref-icon:hover { transform: scale(1.1); }\n.tref-icon:active { cursor: grabbing; }\n.tref-icon svg { width: 100%; height: 100%; }\n.tref-actions {\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 4px;\n background: var(--tref-menu-bg);\n border-radius: 6px;\n box-shadow: var(--tref-menu-shadow);\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.15s, visibility 0.15s;\n z-index: 100;\n margin-top: 4px;\n}\n.tref-wrapper:hover .tref-actions {\n opacity: 1;\n visibility: visible;\n}\n.tref-action {\n background: transparent;\n border: none;\n outline: none;\n padding: 8px;\n border-radius: 4px;\n cursor: pointer;\n color: var(--tref-menu-text);\n transition: background 0.15s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n.tref-action svg {\n width: 16px;\n height: 16px;\n}\n.tref-action:hover { background: var(--tref-menu-hover); }\n.tref-action:focus { outline: none; }\n.tref-action:focus-visible {\n outline: 2px solid var(--tref-accent);\n outline-offset: 1px;\n}\n.tref-icon:focus { outline: none; }\n.tref-icon:focus-visible {\n outline: 2px solid var(--tref-accent);\n outline-offset: 2px;\n border-radius: 4px;\n}\n.tref-icon-success { color: var(--tref-success); }\n.tref-icon-error { color: var(--tref-error); }\n`;\n }\n}\n\n/**\n * TrefReceiver - drop zone for TREF blocks\n */\nexport class TrefReceiver {\n /** @type {HTMLElement} */\n #element;\n /** @type {(wrapper: TrefWrapper) => void} */\n #onReceive;\n /** @type {(error: Error) => void} */\n #onError;\n /** @type {boolean} */\n #compact;\n\n /**\n * @param {HTMLElement} element\n * @param {{ onReceive?: (wrapper: TrefWrapper) => void, onError?: (error: Error) => void, compact?: boolean }} [options]\n */\n constructor(element, options = {}) {\n this.#element = element;\n this.#onReceive = options.onReceive || (() => {});\n this.#onError = options.onError || (() => {});\n this.#compact = options.compact || false;\n this.#setup();\n }\n\n #setup() {\n const el = this.#element;\n el.classList.add('tref-receiver');\n if (this.#compact) {\n el.classList.add('tref-receiver-compact');\n }\n el.setAttribute('role', 'region');\n el.setAttribute('aria-label', 'Drop zone for TREF blocks');\n el.setAttribute('aria-dropeffect', 'copy');\n\n el.addEventListener('dragover', e => {\n e.preventDefault();\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = 'copy';\n }\n el.classList.add('tref-receiver-active');\n });\n\n el.addEventListener('dragleave', () => {\n el.classList.remove('tref-receiver-active');\n });\n\n el.addEventListener('drop', e => {\n e.preventDefault();\n el.classList.remove('tref-receiver-active');\n\n if (!e.dataTransfer) {\n this.#onError(new Error('No data'));\n return;\n }\n\n const wrapper = unwrap(e.dataTransfer);\n if (wrapper) {\n el.classList.add('tref-receiver-success');\n setTimeout(() => el.classList.remove('tref-receiver-success'), 1000);\n this.#onReceive(wrapper);\n } else {\n el.classList.add('tref-receiver-error');\n setTimeout(() => el.classList.remove('tref-receiver-error'), 1000);\n this.#onError(new Error('Invalid TREF data'));\n }\n });\n }\n\n get element() {\n return this.#element;\n }\n\n /**\n * Display a block in the receiver\n * @param {TrefWrapper} wrapper\n */\n showBlock(wrapper) {\n this.#element.innerHTML = wrapper.toHTML();\n this.#element.classList.add('tref-receiver-has-block');\n }\n\n clear() {\n this.#element.innerHTML = this.#element.dataset.placeholder || 'Drop TREF here';\n this.#element.classList.remove('tref-receiver-has-block');\n }\n\n static getStyles() {\n return `\n.tref-receiver {\n border: 2px dashed var(--tref-accent);\n border-radius: 8px;\n padding: 20px;\n min-height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--tref-receiver-text);\n background: var(--tref-receiver-bg);\n transition: all 0.2s;\n}\n.tref-receiver-active {\n border-color: var(--tref-accent-hover);\n background: var(--tref-receiver-active-bg);\n color: var(--tref-accent-hover);\n}\n.tref-receiver-success {\n border-color: var(--tref-success);\n background: var(--tref-receiver-success-bg);\n}\n.tref-receiver-error {\n border-color: var(--tref-error);\n background: var(--tref-receiver-error-bg);\n}\n.tref-receiver-has-block {\n border-style: solid;\n background: var(--tref-receiver-block-bg);\n}\n.tref-receiver-compact {\n width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0;\n border-radius: 4px;\n}\n/* Touch devices - larger hit areas */\n@media (pointer: coarse) {\n .tref-icon {\n min-width: 44px;\n min-height: 44px;\n }\n .tref-action {\n min-width: 44px;\n min-height: 44px;\n padding: 10px;\n }\n .tref-receiver-compact {\n width: 48px;\n height: 48px;\n min-height: 48px;\n }\n}\n`;\n }\n}\n\n/**\n * Create wrapper from block data\n * @param {unknown} data\n * @returns {TrefWrapper}\n */\nexport function wrap(data) {\n return new TrefWrapper(/** @type {TrefBlock} */ (data));\n}\n\n/**\n * Parse TREF from DataTransfer or string\n * @param {DataTransfer | string} source\n * @returns {TrefWrapper | null}\n */\nexport function unwrap(source) {\n try {\n let json;\n if (typeof source === 'string') {\n json = source;\n } else if (source && typeof source.getData === 'function') {\n json =\n source.getData(TREF_MIME_TYPE) ||\n source.getData('application/json') ||\n source.getData('text/plain');\n } else {\n return null;\n }\n\n if (!json) {\n return null;\n }\n return wrap(JSON.parse(json));\n } catch {\n return null;\n }\n}\n"],
5
- "mappings": "AAQA,IAAMA,EAAiB,QAeVC,EAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAYhBC,EAAiB,4BAGjBC,EAAqB,sBAAwB,mBAAmBF,CAAa,EAsB1F,SAASG,EAAaC,EAAO,CAC3B,GAAI,CAACA,GAAS,OAAOA,GAAU,SAC7B,MAAO,GAET,IAAMC,EAA4CD,EAalD,MAZI,EAAAC,EAAE,IAAM,GAGR,OAAOA,EAAE,IAAO,UAGhB,CAACA,EAAE,GAAG,WAAW,SAAS,GAG1B,OAAOA,EAAE,SAAY,UAGrB,CAACA,EAAE,MAAQ,OAAOA,EAAE,MAAS,SAInC,CAUO,IAAMC,EAAN,KAAkB,CAEvBC,GAKA,YAAYH,EAAO,CACjB,GAAI,CAACD,EAAaC,CAAK,EACrB,MAAM,IAAI,MAAM,oBAAoB,EAEtC,KAAKG,GAASH,CAChB,CAEA,IAAI,OAAQ,CACV,OAAO,KAAKG,EACd,CAEA,IAAI,IAAK,CACP,OAAO,KAAKA,GAAO,EACrB,CAEA,IAAI,SAAU,CACZ,OAAO,KAAKA,GAAO,GAAG,QAAQ,UAAW,EAAE,EAAE,MAAM,EAAG,CAAC,CACzD,CAEA,IAAI,SAAU,CACZ,OAAO,KAAKA,GAAO,OACrB,CAKA,OAAOC,EAAU,CAAC,EAAG,CACnB,OAAOA,EAAQ,OAAS,KAAK,UAAU,KAAKD,GAAQ,KAAM,CAAC,EAAI,KAAK,UAAU,KAAKA,EAAM,CAC3F,CAEA,aAAc,CACZ,OAAO,KAAKA,GAAO,GAAG,QAAQ,UAAW,EAAE,EAAIE,CACjD,CAEA,QAAS,CACP,OAAO,IAAI,KAAK,CAAC,KAAK,OAAO,CAAC,EAAG,CAAE,KAAMC,CAAe,CAAC,CAC3D,CAEA,WAAY,CACV,IAAMC,EAAO,KAAK,OAAO,EACnBC,EAAS,KAAK,SAAS,mBAAmBD,CAAI,CAAC,CAAC,EACtD,MAAO,QAAQD,CAAc,WAAWE,CAAM,EAChD,CAEA,aAAc,CACZ,OAAO,IAAI,gBAAgB,KAAK,OAAO,CAAC,CAC1C,CAEA,MAAM,iBAAkB,CACtB,MAAM,UAAU,UAAU,UAAU,KAAK,OAAO,CAAC,CACnD,CAEA,MAAM,wBAAyB,CAC7B,MAAM,UAAU,UAAU,UAAU,KAAKL,GAAO,OAAO,CACzD,CAEA,aAAc,CACZ,IAAMI,EAAO,KAAK,OAAO,EACzB,MAAO,CACL,CAAE,KAAMD,EAAgB,KAAMC,CAAK,EACnC,CAAE,KAAM,mBAAoB,KAAMA,CAAK,EACvC,CAAE,KAAM,aAAc,KAAMA,CAAK,CACnC,CACF,CAGA,YAAYE,EAAc,CACxB,OAAW,CAAE,KAAAC,EAAM,KAAAC,CAAK,IAAK,KAAK,YAAY,EAC5CF,EAAa,QAAQC,EAAMC,CAAI,CAEnC,CAMA,OAAOP,EAAU,CAAC,EAAG,CACnB,GAAM,CAAE,YAAAQ,EAAc,EAAK,EAAIR,EAQzBS,EAAcD,EAChB;AAAA;AAAA;AAAA;AAAA,gBAKA,GAEJ,MAAO,2CAA2C,KAAKT,GAAO,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCAMpCW,CAAa;AAAA,IACzCD,CAAW;AAAA,OAEb,CAMAE,GAAeC,EAAS,CACtB,IAAMC,EAAUD,EAAQ,cAAc,eAAe,EACrD,GAAIC,EAAS,CACX,IAAMC,EAAwCD,EACxCE,EAAYD,EAAU,MAAM,UAAY,IAE9C,GADAA,EAAU,MAAM,QAAUC,EAAY,IAAM,IACxC,CAACA,EAAW,CAEd,IAAMC,EAAWF,EAAU,cAAc,QAAQ,EAC7CE,GAC0BA,EAAU,MAAM,CAEhD,CACF,CACF,CAMA,aAAaJ,EAAS,CACpB,IAAMK,EAASL,EAAQ,cAAc,YAAY,EAGjD,GAAIK,EAAQ,CACV,IAAMC,EAAmCD,EAEzCC,EAAK,iBAAiB,YAAaC,GAAK,CACtC,IAAMC,EAA+BD,EACjCC,EAAG,eACL,KAAK,YAAYA,EAAG,YAAY,EAChCA,EAAG,aAAa,cAAgB,OAEpC,CAAC,EAGDF,EAAK,iBAAiB,UAAWC,GAAK,EAChCA,EAAE,MAAQ,SAAWA,EAAE,MAAQ,OACjCA,EAAE,eAAe,EACjB,KAAKR,GAAeC,CAAO,EAE/B,CAAC,EAGDM,EAAK,iBAAiB,WAAYC,GAAK,CAEhCD,EAAK,QAAQ,WAChBC,EAAE,eAAe,EACjB,KAAKR,GAAeC,CAAO,EAE/B,CAAC,EAID,IAAIS,EACJH,EAAK,iBAAiB,aAAc,IAAM,CACxCG,EAAiB,WAAW,IAAM,CAChCH,EAAK,QAAQ,SAAW,OACxBA,EAAK,MAAM,UAAY,aACzB,EAAG,GAAG,CACR,CAAC,EACDA,EAAK,iBAAiB,WAAY,IAAM,CACtC,aAAaG,CAAc,EAC3B,OAAOH,EAAK,QAAQ,SACpBA,EAAK,MAAM,UAAY,EACzB,CAAC,EACDA,EAAK,iBAAiB,cAAe,IAAM,CACzC,aAAaG,CAAc,EAC3B,OAAOH,EAAK,QAAQ,SACpBA,EAAK,MAAM,UAAY,EACzB,CAAC,CACH,CAGA,IAAMI,EAAe,MAA4BH,GAAM,CACrDA,EAAE,gBAAgB,EAClB,IAAMI,EAAkCJ,EAAE,cACpCK,EAASD,EAAI,QAAQ,OACrBE,EAAeF,EAAI,UAEnBG,EAAY,qQACZC,EAAY,4SAElB,GAAI,CACF,GAAIH,IAAW,eACb,MAAM,KAAK,uBAAuB,EAClCD,EAAI,UAAYG,UACPF,IAAW,YACpB,MAAM,KAAK,gBAAgB,EAC3BD,EAAI,UAAYG,UACPF,IAAW,WAAY,CAChC,IAAMI,EAAM,KAAK,YAAY,EACvBC,EAAI,SAAS,cAAc,GAAG,EACpCA,EAAE,KAAOD,EACTC,EAAE,SAAW,KAAK,YAAY,EAC9BA,EAAE,MAAM,EACR,IAAI,gBAAgBD,CAAG,EACvBL,EAAI,UAAYG,CAClB,CACA,WAAW,IAAM,CACfH,EAAI,UAAYE,CAClB,EAAG,GAAI,CACT,MAAQ,CACNF,EAAI,UAAYI,EAChB,WAAW,IAAM,CACfJ,EAAI,UAAYE,CAClB,EAAG,GAAI,CACT,CACF,EAEAb,EAAQ,iBAAiB,cAAc,EAAE,QAAQW,GAAO,CACtDA,EAAI,iBAAiB,QAASJ,GAAE,CAAQG,EAAaH,CAAC,EAAC,CACzD,CAAC,CACH,CAEA,OAAO,WAAY,CACjB,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAmGT,CACF,EAKaW,EAAN,KAAmB,CAExBC,GAEAC,GAEAC,GAEAC,GAMA,YAAYtB,EAASZ,EAAU,CAAC,EAAG,CACjC,KAAK+B,GAAWnB,EAChB,KAAKoB,GAAahC,EAAQ,YAAc,IAAM,CAAC,GAC/C,KAAKiC,GAAWjC,EAAQ,UAAY,IAAM,CAAC,GAC3C,KAAKkC,GAAWlC,EAAQ,SAAW,GACnC,KAAKmC,GAAO,CACd,CAEAA,IAAS,CACP,IAAMC,EAAK,KAAKL,GAChBK,EAAG,UAAU,IAAI,eAAe,EAC5B,KAAKF,IACPE,EAAG,UAAU,IAAI,uBAAuB,EAE1CA,EAAG,aAAa,OAAQ,QAAQ,EAChCA,EAAG,aAAa,aAAc,2BAA2B,EACzDA,EAAG,aAAa,kBAAmB,MAAM,EAEzCA,EAAG,iBAAiB,WAAYjB,GAAK,CACnCA,EAAE,eAAe,EACbA,EAAE,eACJA,EAAE,aAAa,WAAa,QAE9BiB,EAAG,UAAU,IAAI,sBAAsB,CACzC,CAAC,EAEDA,EAAG,iBAAiB,YAAa,IAAM,CACrCA,EAAG,UAAU,OAAO,sBAAsB,CAC5C,CAAC,EAEDA,EAAG,iBAAiB,OAAQjB,GAAK,CAI/B,GAHAA,EAAE,eAAe,EACjBiB,EAAG,UAAU,OAAO,sBAAsB,EAEtC,CAACjB,EAAE,aAAc,CACnB,KAAKc,GAAS,IAAI,MAAM,SAAS,CAAC,EAClC,MACF,CAEA,IAAMI,EAAUC,EAAOnB,EAAE,YAAY,EACjCkB,GACFD,EAAG,UAAU,IAAI,uBAAuB,EACxC,WAAW,IAAMA,EAAG,UAAU,OAAO,uBAAuB,EAAG,GAAI,EACnE,KAAKJ,GAAWK,CAAO,IAEvBD,EAAG,UAAU,IAAI,qBAAqB,EACtC,WAAW,IAAMA,EAAG,UAAU,OAAO,qBAAqB,EAAG,GAAI,EACjE,KAAKH,GAAS,IAAI,MAAM,mBAAmB,CAAC,EAEhD,CAAC,CACH,CAEA,IAAI,SAAU,CACZ,OAAO,KAAKF,EACd,CAMA,UAAUM,EAAS,CACjB,KAAKN,GAAS,UAAYM,EAAQ,OAAO,EACzC,KAAKN,GAAS,UAAU,IAAI,yBAAyB,CACvD,CAEA,OAAQ,CACN,KAAKA,GAAS,UAAY,KAAKA,GAAS,QAAQ,aAAe,iBAC/D,KAAKA,GAAS,UAAU,OAAO,yBAAyB,CAC1D,CAEA,OAAO,WAAY,CACjB,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAuDT,CACF,EAOO,SAASQ,EAAKhC,EAAM,CACzB,OAAO,IAAIT,EAAsCS,CAAK,CACxD,CAOO,SAAS+B,EAAOE,EAAQ,CAC7B,GAAI,CACF,IAAIrC,EACJ,GAAI,OAAOqC,GAAW,SACpBrC,EAAOqC,UACEA,GAAU,OAAOA,EAAO,SAAY,WAC7CrC,EACEqC,EAAO,QAAQtC,CAAc,GAC7BsC,EAAO,QAAQ,kBAAkB,GACjCA,EAAO,QAAQ,YAAY,MAE7B,QAAO,KAGT,OAAKrC,EAGEoC,EAAK,KAAK,MAAMpC,CAAI,CAAC,EAFnB,IAGX,MAAQ,CACN,OAAO,IACT,CACF",
4
+ "sourcesContent": ["/**\n * @fileoverview TREF Block wrapper for display and interaction\n * Self-contained - no external dependencies\n */\n\n/* global btoa, navigator, Blob, URL, document */\n\n/** File extension for TREF files */\nconst TREF_EXTENSION = '.tref';\n\n/**\n * @typedef {object} TrefBlock\n * @property {1} v\n * @property {string} id\n * @property {string} content\n * @property {{ author?: string, created: string, modified?: string, license: string, lang?: string }} meta\n * @property {Array<{ type: string, url?: string, title?: string, snippet?: string, query?: string }>} [refs]\n * @property {string} [parent]\n */\n\n/**\n * SVG icon for TREF (purple-mint theme with chain link)\n */\nexport const TREF_ICON_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" width=\"24\" height=\"24\">\n <rect x=\"6\" y=\"6\" width=\"88\" height=\"88\" rx=\"12\" ry=\"12\" fill=\"#2D1B4E\" stroke=\"#5CCCCC\" stroke-width=\"5\"/>\n <g transform=\"translate(50 50) scale(0.022) translate(-1125 -1125)\">\n <g transform=\"translate(0,2250) scale(1,-1)\" fill=\"#5CCCCC\">\n <path d=\"M1515 2244 c-66 -10 -144 -38 -220 -77 -67 -35 -106 -67 -237 -195 -155 -152 -188 -195 -188 -247 0 -41 30 -95 64 -116 39 -24 113 -25 146 -3 14 9 90 81 170 160 183 181 216 199 350 199 83 0 103 -4 155 -28 78 -36 146 -104 182 -181 24 -53 28 -73 28 -151 0 -137 -21 -175 -199 -355 -79 -80 -151 -156 -160 -170 -39 -59 -8 -162 58 -194 81 -38 113 -22 284 147 165 163 230 252 268 370 24 71 28 99 28 202 0 106 -3 130 -28 200 -91 261 -310 428 -579 439 -50 3 -105 2 -122 0z\"/>\n <path d=\"M1395 1585 c-17 -9 -189 -174 -382 -368 -377 -378 -383 -385 -362 -461 21 -76 87 -116 166 -101 33 6 80 49 386 353 191 191 358 362 369 381 26 42 28 109 4 146 -39 59 -118 81 -181 50z\"/>\n <path d=\"M463 1364 c-47 -24 -323 -310 -365 -379 -20 -33 -49 -96 -64 -140 -24 -69 -28 -96 -28 -195 0 -127 14 -190 66 -294 63 -126 157 -220 284 -284 104 -52 167 -66 294 -66 99 0 126 4 195 28 44 15 107 44 140 64 65 39 348 309 371 354 41 78 -10 184 -96 203 -61 13 -98 -11 -256 -166 -186 -183 -222 -204 -359 -204 -77 0 -98 4 -147 27 -79 37 -142 98 -181 177 -29 59 -32 74 -32 156 0 136 21 174 199 355 79 80 150 156 159 170 23 33 22 107 -2 146 -35 57 -115 79 -178 48z\"/>\n </g>\n </g>\n</svg>`;\n\n/** MIME type for TREF files */\nexport const TREF_MIME_TYPE = 'application/vnd.tref+json';\n\n/** Icon as data URL for embedding */\nexport const TREF_ICON_DATA_URL = 'data:image/svg+xml,' + encodeURIComponent(TREF_ICON_SVG);\n\n/**\n * Escape HTML special characters\n * @param {string} str\n * @returns {string}\n */\nfunction _escapeHtml(str) {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n// Reserved for future use (content escaping)\nvoid _escapeHtml;\n\n/**\n * Validate block structure\n * @param {unknown} block\n * @returns {block is TrefBlock}\n */\nfunction isValidBlock(block) {\n if (!block || typeof block !== 'object') {\n return false;\n }\n const b = /** @type {Record<string, unknown>} */ (block);\n if (b.v !== 1) {\n return false;\n }\n if (typeof b.id !== 'string') {\n return false;\n }\n if (!b.id.startsWith('sha256:')) {\n return false;\n }\n if (typeof b.content !== 'string') {\n return false;\n }\n if (!b.meta || typeof b.meta !== 'object') {\n return false;\n }\n return true;\n}\n\n/**\n * TrefWrapper - displays a TREF block with drag/copy/download actions\n *\n * Design:\n * - Icon is the drag handle (only icon is draggable)\n * - Hover shows action buttons (copy, download)\n * - Status feedback in the ID badge\n */\nexport class TrefWrapper {\n /** @type {TrefBlock} */\n #block;\n\n /**\n * @param {TrefBlock} block\n */\n constructor(block) {\n if (!isValidBlock(block)) {\n throw new Error('Invalid TREF block');\n }\n this.#block = block;\n }\n\n get block() {\n return this.#block;\n }\n\n get id() {\n return this.#block.id;\n }\n\n get shortId() {\n return this.#block.id.replace('sha256:', '').slice(0, 8);\n }\n\n get content() {\n return this.#block.content;\n }\n\n /**\n * @param {{ pretty?: boolean }} [options]\n */\n toJSON(options = {}) {\n return options.pretty ? JSON.stringify(this.#block, null, 2) : JSON.stringify(this.#block);\n }\n\n getFilename() {\n return this.#block.id.replace('sha256:', '') + TREF_EXTENSION;\n }\n\n toBlob() {\n return new Blob([this.toJSON()], { type: TREF_MIME_TYPE });\n }\n\n toDataURL() {\n const json = this.toJSON();\n const base64 = btoa(unescape(encodeURIComponent(json)));\n return `data:${TREF_MIME_TYPE};base64,${base64}`;\n }\n\n toObjectURL() {\n return URL.createObjectURL(this.toBlob());\n }\n\n async copyToClipboard() {\n await navigator.clipboard.writeText(this.toJSON());\n }\n\n async copyContentToClipboard() {\n await navigator.clipboard.writeText(this.#block.content);\n }\n\n getDragData() {\n const json = this.toJSON();\n return [\n { type: TREF_MIME_TYPE, data: json },\n { type: 'application/json', data: json },\n { type: 'text/plain', data: json },\n ];\n }\n\n /** @param {DataTransfer} dataTransfer */\n setDragData(dataTransfer) {\n for (const { type, data } of this.getDragData()) {\n dataTransfer.setData(type, data);\n }\n }\n\n /**\n * Generate HTML - icon only with hover actions\n * @param {{ interactive?: boolean }} [options]\n */\n toHTML(options = {}) {\n const { interactive = true } = options;\n\n // SVG icons for actions\n const iconCopy = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg>`;\n const iconJson = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5a2 2 0 0 0 2 2h1\"></path><path d=\"M16 3h1a2 2 0 0 1 2 2v5a2 2 0 0 0 2 2 2 2 0 0 0-2 2v5a2 2 0 0 1-2 2h-1\"></path><circle cx=\"12\" cy=\"12\" r=\"1\" fill=\"currentColor\"></circle><circle cx=\"8\" cy=\"12\" r=\"1\" fill=\"currentColor\"></circle><circle cx=\"16\" cy=\"12\" r=\"1\" fill=\"currentColor\"></circle></svg>`;\n const iconDownload = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"></path><polyline points=\"7 10 12 15 17 10\"></polyline><line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"></line></svg>`;\n\n // Hover actions appear on hover\n const actionsHtml = interactive\n ? `<div class=\"tref-actions\" role=\"group\" aria-label=\"Block actions\">\n <button class=\"tref-action\" data-action=\"copy-content\" title=\"Copy content\" aria-label=\"Copy content to clipboard\">${iconCopy}</button>\n <button class=\"tref-action\" data-action=\"copy-json\" title=\"Copy JSON\" aria-label=\"Copy JSON to clipboard\">${iconJson}</button>\n <button class=\"tref-action\" data-action=\"download\" title=\"Download .tref\" aria-label=\"Download as .tref file\">${iconDownload}</button>\n </div>`\n : '';\n\n return `<div class=\"tref-wrapper\" data-tref-id=\"${this.#block.id}\">\n <span class=\"tref-icon\"\n role=\"button\"\n aria-label=\"TREF block - drag to share\"\n tabindex=\"0\"\n draggable=\"true\"\n title=\"Drag to share\">${TREF_ICON_SVG}</span>\n ${actionsHtml}\n</div>`;\n }\n\n /**\n * Toggle actions visibility (for keyboard/touch)\n * @param {HTMLElement} element\n */\n #toggleActions(element) {\n const actions = element.querySelector('.tref-actions');\n if (actions) {\n const actionsEl = /** @type {HTMLElement} */ (actions);\n const isVisible = actionsEl.style.opacity === '1';\n actionsEl.style.opacity = isVisible ? '0' : '1';\n if (!isVisible) {\n // Focus first action button\n const firstBtn = actionsEl.querySelector('button');\n if (firstBtn) {\n /** @type {HTMLElement} */ (firstBtn).focus();\n }\n }\n }\n }\n\n /**\n * Attach event listeners to a rendered wrapper\n * @param {HTMLElement} element\n */\n attachEvents(element) {\n const iconEl = element.querySelector('.tref-icon');\n\n // Icon is drag handle\n if (iconEl) {\n const icon = /** @type {HTMLElement} */ (iconEl);\n\n icon.addEventListener('dragstart', e => {\n const de = /** @type {DragEvent} */ (e);\n if (de.dataTransfer) {\n this.setDragData(de.dataTransfer);\n de.dataTransfer.effectAllowed = 'copy';\n }\n });\n\n // Keyboard: Enter/Space shows actions or triggers default action\n icon.addEventListener('keydown', e => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this.#toggleActions(element);\n }\n });\n\n // Touch: tap toggles actions\n icon.addEventListener('touchend', e => {\n // Only handle if not dragging\n if (!icon.dataset.dragging) {\n e.preventDefault();\n this.#toggleActions(element);\n }\n });\n\n // Touch: long-press (500ms) to start drag indication\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let longPressTimer;\n icon.addEventListener('touchstart', () => {\n longPressTimer = setTimeout(() => {\n icon.dataset.dragging = 'true';\n icon.style.transform = 'scale(1.15)';\n }, 500);\n });\n icon.addEventListener('touchend', () => {\n clearTimeout(longPressTimer);\n delete icon.dataset.dragging;\n icon.style.transform = '';\n });\n icon.addEventListener('touchcancel', () => {\n clearTimeout(longPressTimer);\n delete icon.dataset.dragging;\n icon.style.transform = '';\n });\n }\n\n // Action buttons (visible on hover via CSS)\n const handleAction = async (/** @type {Event} */ e) => {\n e.stopPropagation();\n const btn = /** @type {HTMLElement} */ (e.currentTarget);\n const action = btn.dataset.action;\n const originalHtml = btn.innerHTML;\n\n const iconCheck = `<svg class=\"tref-icon-success\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>`;\n const iconError = `<svg class=\"tref-icon-error\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>`;\n\n try {\n if (action === 'copy-content') {\n await this.copyContentToClipboard();\n btn.innerHTML = iconCheck;\n } else if (action === 'copy-json') {\n await this.copyToClipboard();\n btn.innerHTML = iconCheck;\n } else if (action === 'download') {\n const url = this.toObjectURL();\n const a = document.createElement('a');\n a.href = url;\n a.download = this.getFilename();\n a.click();\n URL.revokeObjectURL(url);\n btn.innerHTML = iconCheck;\n }\n setTimeout(() => {\n btn.innerHTML = originalHtml;\n }, 1000);\n } catch {\n btn.innerHTML = iconError;\n setTimeout(() => {\n btn.innerHTML = originalHtml;\n }, 1000);\n }\n };\n\n element.querySelectorAll('.tref-action').forEach(btn => {\n btn.addEventListener('click', e => void handleAction(e));\n });\n }\n\n static getStyles() {\n return `\n:root {\n --tref-accent: #5CCCCC;\n --tref-accent-hover: #8B5CF6;\n --tref-success: #10B981;\n --tref-error: #ef4444;\n --tref-menu-bg: #ffffff;\n --tref-menu-text: #374151;\n --tref-menu-hover: #f3f4f6;\n --tref-menu-shadow: 0 4px 12px rgba(0,0,0,0.15);\n --tref-receiver-bg: #f9fafb;\n --tref-receiver-text: #6b7280;\n --tref-receiver-active-bg: #f3e8ff;\n --tref-receiver-success-bg: #ecfdf5;\n --tref-receiver-error-bg: #fef2f2;\n --tref-receiver-block-bg: #ffffff;\n}\n.dark {\n --tref-menu-bg: #1f2937;\n --tref-menu-text: #e5e7eb;\n --tref-menu-hover: #374151;\n --tref-menu-shadow: 0 4px 12px rgba(0,0,0,0.4);\n --tref-receiver-bg: #1f2937;\n --tref-receiver-text: #9ca3af;\n --tref-receiver-active-bg: #3b2d5e;\n --tref-receiver-success-bg: #064e3b;\n --tref-receiver-error-bg: #450a0a;\n --tref-receiver-block-bg: #111827;\n}\n.tref-wrapper {\n display: inline-block;\n position: relative;\n}\n.tref-icon {\n display: inline-flex;\n width: 32px;\n height: 32px;\n cursor: grab;\n transition: transform 0.15s;\n}\n.tref-icon:hover { transform: scale(1.1); }\n.tref-icon:active { cursor: grabbing; }\n.tref-icon svg { width: 100%; height: 100%; }\n.tref-actions {\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 4px;\n background: var(--tref-menu-bg);\n border-radius: 6px;\n box-shadow: var(--tref-menu-shadow);\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.15s, visibility 0.15s;\n z-index: 100;\n margin-top: 4px;\n}\n.tref-wrapper:hover .tref-actions {\n opacity: 1;\n visibility: visible;\n}\n.tref-action {\n background: transparent;\n border: none;\n outline: none;\n padding: 8px;\n border-radius: 4px;\n cursor: pointer;\n color: var(--tref-menu-text);\n transition: background 0.15s;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n.tref-action svg {\n width: 16px;\n height: 16px;\n}\n.tref-action:hover { background: var(--tref-menu-hover); }\n.tref-action:focus { outline: none; }\n.tref-action:focus-visible {\n outline: 2px solid var(--tref-accent);\n outline-offset: 1px;\n}\n.tref-icon:focus { outline: none; }\n.tref-icon:focus-visible {\n outline: 2px solid var(--tref-accent);\n outline-offset: 2px;\n border-radius: 4px;\n}\n.tref-icon-success { color: var(--tref-success); }\n.tref-icon-error { color: var(--tref-error); }\n`;\n }\n}\n\n/**\n * TrefReceiver - drop zone for TREF blocks\n */\nexport class TrefReceiver {\n /** @type {HTMLElement} */\n #element;\n /** @type {(wrapper: TrefWrapper) => void} */\n #onReceive;\n /** @type {(error: Error) => void} */\n #onError;\n /** @type {boolean} */\n #compact;\n\n /**\n * @param {HTMLElement} element\n * @param {{ onReceive?: (wrapper: TrefWrapper) => void, onError?: (error: Error) => void, compact?: boolean }} [options]\n */\n constructor(element, options = {}) {\n this.#element = element;\n this.#onReceive = options.onReceive || (() => {});\n this.#onError = options.onError || (() => {});\n this.#compact = options.compact || false;\n this.#setup();\n }\n\n #setup() {\n const el = this.#element;\n el.classList.add('tref-receiver');\n if (this.#compact) {\n el.classList.add('tref-receiver-compact');\n }\n el.setAttribute('role', 'region');\n el.setAttribute('aria-label', 'Drop zone for TREF blocks');\n el.setAttribute('aria-dropeffect', 'copy');\n\n el.addEventListener('dragover', e => {\n e.preventDefault();\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = 'copy';\n }\n el.classList.add('tref-receiver-active');\n });\n\n el.addEventListener('dragleave', () => {\n el.classList.remove('tref-receiver-active');\n });\n\n el.addEventListener('drop', e => {\n e.preventDefault();\n el.classList.remove('tref-receiver-active');\n\n if (!e.dataTransfer) {\n this.#onError(new Error('No data'));\n return;\n }\n\n const wrapper = unwrap(e.dataTransfer);\n if (wrapper) {\n el.classList.add('tref-receiver-success');\n setTimeout(() => el.classList.remove('tref-receiver-success'), 1000);\n this.#onReceive(wrapper);\n } else {\n el.classList.add('tref-receiver-error');\n setTimeout(() => el.classList.remove('tref-receiver-error'), 1000);\n this.#onError(new Error('Invalid TREF data'));\n }\n });\n }\n\n get element() {\n return this.#element;\n }\n\n /**\n * Display a block in the receiver\n * @param {TrefWrapper} wrapper\n */\n showBlock(wrapper) {\n this.#element.innerHTML = wrapper.toHTML();\n this.#element.classList.add('tref-receiver-has-block');\n }\n\n clear() {\n this.#element.innerHTML = this.#element.dataset.placeholder || 'Drop TREF here';\n this.#element.classList.remove('tref-receiver-has-block');\n }\n\n static getStyles() {\n return `\n.tref-receiver {\n border: 2px dashed var(--tref-accent);\n border-radius: 8px;\n padding: 20px;\n min-height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--tref-receiver-text);\n background: var(--tref-receiver-bg);\n transition: all 0.2s;\n}\n.tref-receiver-active {\n border-color: var(--tref-accent-hover);\n background: var(--tref-receiver-active-bg);\n color: var(--tref-accent-hover);\n}\n.tref-receiver-success {\n border-color: var(--tref-success);\n background: var(--tref-receiver-success-bg);\n}\n.tref-receiver-error {\n border-color: var(--tref-error);\n background: var(--tref-receiver-error-bg);\n}\n.tref-receiver-has-block {\n border-style: solid;\n background: var(--tref-receiver-block-bg);\n}\n.tref-receiver-compact {\n width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0;\n border-radius: 4px;\n}\n/* Touch devices - larger hit areas */\n@media (pointer: coarse) {\n .tref-icon {\n min-width: 44px;\n min-height: 44px;\n }\n .tref-action {\n min-width: 44px;\n min-height: 44px;\n padding: 10px;\n }\n .tref-receiver-compact {\n width: 48px;\n height: 48px;\n min-height: 48px;\n }\n}\n`;\n }\n}\n\n/**\n * Create wrapper from block data\n * @param {unknown} data\n * @returns {TrefWrapper}\n */\nexport function wrap(data) {\n return new TrefWrapper(/** @type {TrefBlock} */ (data));\n}\n\n/**\n * Parse TREF from DataTransfer or string\n * @param {DataTransfer | string} source\n * @returns {TrefWrapper | null}\n */\nexport function unwrap(source) {\n try {\n let json;\n if (typeof source === 'string') {\n json = source;\n } else if (source && typeof source.getData === 'function') {\n json =\n source.getData(TREF_MIME_TYPE) ||\n source.getData('application/json') ||\n source.getData('text/plain');\n } else {\n return null;\n }\n\n if (!json) {\n return null;\n }\n return wrap(JSON.parse(json));\n } catch {\n return null;\n }\n}\n"],
5
+ "mappings": "AAQA,IAAMA,EAAiB,QAeVC,EAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAYhBC,EAAiB,4BAGjBC,EAAqB,sBAAwB,mBAAmBF,CAAa,EAsB1F,SAASG,EAAaC,EAAO,CAC3B,GAAI,CAACA,GAAS,OAAOA,GAAU,SAC7B,MAAO,GAET,IAAMC,EAA4CD,EAalD,MAZI,EAAAC,EAAE,IAAM,GAGR,OAAOA,EAAE,IAAO,UAGhB,CAACA,EAAE,GAAG,WAAW,SAAS,GAG1B,OAAOA,EAAE,SAAY,UAGrB,CAACA,EAAE,MAAQ,OAAOA,EAAE,MAAS,SAInC,CAUO,IAAMC,EAAN,KAAkB,CAEvBC,GAKA,YAAYH,EAAO,CACjB,GAAI,CAACD,EAAaC,CAAK,EACrB,MAAM,IAAI,MAAM,oBAAoB,EAEtC,KAAKG,GAASH,CAChB,CAEA,IAAI,OAAQ,CACV,OAAO,KAAKG,EACd,CAEA,IAAI,IAAK,CACP,OAAO,KAAKA,GAAO,EACrB,CAEA,IAAI,SAAU,CACZ,OAAO,KAAKA,GAAO,GAAG,QAAQ,UAAW,EAAE,EAAE,MAAM,EAAG,CAAC,CACzD,CAEA,IAAI,SAAU,CACZ,OAAO,KAAKA,GAAO,OACrB,CAKA,OAAOC,EAAU,CAAC,EAAG,CACnB,OAAOA,EAAQ,OAAS,KAAK,UAAU,KAAKD,GAAQ,KAAM,CAAC,EAAI,KAAK,UAAU,KAAKA,EAAM,CAC3F,CAEA,aAAc,CACZ,OAAO,KAAKA,GAAO,GAAG,QAAQ,UAAW,EAAE,EAAIE,CACjD,CAEA,QAAS,CACP,OAAO,IAAI,KAAK,CAAC,KAAK,OAAO,CAAC,EAAG,CAAE,KAAMC,CAAe,CAAC,CAC3D,CAEA,WAAY,CACV,IAAMC,EAAO,KAAK,OAAO,EACnBC,EAAS,KAAK,SAAS,mBAAmBD,CAAI,CAAC,CAAC,EACtD,MAAO,QAAQD,CAAc,WAAWE,CAAM,EAChD,CAEA,aAAc,CACZ,OAAO,IAAI,gBAAgB,KAAK,OAAO,CAAC,CAC1C,CAEA,MAAM,iBAAkB,CACtB,MAAM,UAAU,UAAU,UAAU,KAAK,OAAO,CAAC,CACnD,CAEA,MAAM,wBAAyB,CAC7B,MAAM,UAAU,UAAU,UAAU,KAAKL,GAAO,OAAO,CACzD,CAEA,aAAc,CACZ,IAAMI,EAAO,KAAK,OAAO,EACzB,MAAO,CACL,CAAE,KAAMD,EAAgB,KAAMC,CAAK,EACnC,CAAE,KAAM,mBAAoB,KAAMA,CAAK,EACvC,CAAE,KAAM,aAAc,KAAMA,CAAK,CACnC,CACF,CAGA,YAAYE,EAAc,CACxB,OAAW,CAAE,KAAAC,EAAM,KAAAC,CAAK,IAAK,KAAK,YAAY,EAC5CF,EAAa,QAAQC,EAAMC,CAAI,CAEnC,CAMA,OAAOP,EAAU,CAAC,EAAG,CACnB,GAAM,CAAE,YAAAQ,EAAc,EAAK,EAAIR,EAQzBS,EAAcD,EAChB;AAAA;AAAA;AAAA;AAAA,gBAKA,GAEJ,MAAO,2CAA2C,KAAKT,GAAO,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCAMpCW,CAAa;AAAA,IACzCD,CAAW;AAAA,OAEb,CAMAE,GAAeC,EAAS,CACtB,IAAMC,EAAUD,EAAQ,cAAc,eAAe,EACrD,GAAIC,EAAS,CACX,IAAMC,EAAwCD,EACxCE,EAAYD,EAAU,MAAM,UAAY,IAE9C,GADAA,EAAU,MAAM,QAAUC,EAAY,IAAM,IACxC,CAACA,EAAW,CAEd,IAAMC,EAAWF,EAAU,cAAc,QAAQ,EAC7CE,GAC0BA,EAAU,MAAM,CAEhD,CACF,CACF,CAMA,aAAaJ,EAAS,CACpB,IAAMK,EAASL,EAAQ,cAAc,YAAY,EAGjD,GAAIK,EAAQ,CACV,IAAMC,EAAmCD,EAEzCC,EAAK,iBAAiB,YAAaC,GAAK,CACtC,IAAMC,EAA+BD,EACjCC,EAAG,eACL,KAAK,YAAYA,EAAG,YAAY,EAChCA,EAAG,aAAa,cAAgB,OAEpC,CAAC,EAGDF,EAAK,iBAAiB,UAAWC,GAAK,EAChCA,EAAE,MAAQ,SAAWA,EAAE,MAAQ,OACjCA,EAAE,eAAe,EACjB,KAAKR,GAAeC,CAAO,EAE/B,CAAC,EAGDM,EAAK,iBAAiB,WAAYC,GAAK,CAEhCD,EAAK,QAAQ,WAChBC,EAAE,eAAe,EACjB,KAAKR,GAAeC,CAAO,EAE/B,CAAC,EAID,IAAIS,EACJH,EAAK,iBAAiB,aAAc,IAAM,CACxCG,EAAiB,WAAW,IAAM,CAChCH,EAAK,QAAQ,SAAW,OACxBA,EAAK,MAAM,UAAY,aACzB,EAAG,GAAG,CACR,CAAC,EACDA,EAAK,iBAAiB,WAAY,IAAM,CACtC,aAAaG,CAAc,EAC3B,OAAOH,EAAK,QAAQ,SACpBA,EAAK,MAAM,UAAY,EACzB,CAAC,EACDA,EAAK,iBAAiB,cAAe,IAAM,CACzC,aAAaG,CAAc,EAC3B,OAAOH,EAAK,QAAQ,SACpBA,EAAK,MAAM,UAAY,EACzB,CAAC,CACH,CAGA,IAAMI,EAAe,MAA4BH,GAAM,CACrDA,EAAE,gBAAgB,EAClB,IAAMI,EAAkCJ,EAAE,cACpCK,EAASD,EAAI,QAAQ,OACrBE,EAAeF,EAAI,UAEnBG,EAAY,qQACZC,EAAY,4SAElB,GAAI,CACF,GAAIH,IAAW,eACb,MAAM,KAAK,uBAAuB,EAClCD,EAAI,UAAYG,UACPF,IAAW,YACpB,MAAM,KAAK,gBAAgB,EAC3BD,EAAI,UAAYG,UACPF,IAAW,WAAY,CAChC,IAAMI,EAAM,KAAK,YAAY,EACvBC,EAAI,SAAS,cAAc,GAAG,EACpCA,EAAE,KAAOD,EACTC,EAAE,SAAW,KAAK,YAAY,EAC9BA,EAAE,MAAM,EACR,IAAI,gBAAgBD,CAAG,EACvBL,EAAI,UAAYG,CAClB,CACA,WAAW,IAAM,CACfH,EAAI,UAAYE,CAClB,EAAG,GAAI,CACT,MAAQ,CACNF,EAAI,UAAYI,EAChB,WAAW,IAAM,CACfJ,EAAI,UAAYE,CAClB,EAAG,GAAI,CACT,CACF,EAEAb,EAAQ,iBAAiB,cAAc,EAAE,QAAQW,GAAO,CACtDA,EAAI,iBAAiB,QAASJ,GAAE,CAAQG,EAAaH,CAAC,EAAC,CACzD,CAAC,CACH,CAEA,OAAO,WAAY,CACjB,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAiGT,CACF,EAKaW,EAAN,KAAmB,CAExBC,GAEAC,GAEAC,GAEAC,GAMA,YAAYtB,EAASZ,EAAU,CAAC,EAAG,CACjC,KAAK+B,GAAWnB,EAChB,KAAKoB,GAAahC,EAAQ,YAAc,IAAM,CAAC,GAC/C,KAAKiC,GAAWjC,EAAQ,UAAY,IAAM,CAAC,GAC3C,KAAKkC,GAAWlC,EAAQ,SAAW,GACnC,KAAKmC,GAAO,CACd,CAEAA,IAAS,CACP,IAAMC,EAAK,KAAKL,GAChBK,EAAG,UAAU,IAAI,eAAe,EAC5B,KAAKF,IACPE,EAAG,UAAU,IAAI,uBAAuB,EAE1CA,EAAG,aAAa,OAAQ,QAAQ,EAChCA,EAAG,aAAa,aAAc,2BAA2B,EACzDA,EAAG,aAAa,kBAAmB,MAAM,EAEzCA,EAAG,iBAAiB,WAAYjB,GAAK,CACnCA,EAAE,eAAe,EACbA,EAAE,eACJA,EAAE,aAAa,WAAa,QAE9BiB,EAAG,UAAU,IAAI,sBAAsB,CACzC,CAAC,EAEDA,EAAG,iBAAiB,YAAa,IAAM,CACrCA,EAAG,UAAU,OAAO,sBAAsB,CAC5C,CAAC,EAEDA,EAAG,iBAAiB,OAAQjB,GAAK,CAI/B,GAHAA,EAAE,eAAe,EACjBiB,EAAG,UAAU,OAAO,sBAAsB,EAEtC,CAACjB,EAAE,aAAc,CACnB,KAAKc,GAAS,IAAI,MAAM,SAAS,CAAC,EAClC,MACF,CAEA,IAAMI,EAAUC,EAAOnB,EAAE,YAAY,EACjCkB,GACFD,EAAG,UAAU,IAAI,uBAAuB,EACxC,WAAW,IAAMA,EAAG,UAAU,OAAO,uBAAuB,EAAG,GAAI,EACnE,KAAKJ,GAAWK,CAAO,IAEvBD,EAAG,UAAU,IAAI,qBAAqB,EACtC,WAAW,IAAMA,EAAG,UAAU,OAAO,qBAAqB,EAAG,GAAI,EACjE,KAAKH,GAAS,IAAI,MAAM,mBAAmB,CAAC,EAEhD,CAAC,CACH,CAEA,IAAI,SAAU,CACZ,OAAO,KAAKF,EACd,CAMA,UAAUM,EAAS,CACjB,KAAKN,GAAS,UAAYM,EAAQ,OAAO,EACzC,KAAKN,GAAS,UAAU,IAAI,yBAAyB,CACvD,CAEA,OAAQ,CACN,KAAKA,GAAS,UAAY,KAAKA,GAAS,QAAQ,aAAe,iBAC/D,KAAKA,GAAS,UAAU,OAAO,yBAAyB,CAC1D,CAEA,OAAO,WAAY,CACjB,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAuDT,CACF,EAOO,SAASQ,EAAKhC,EAAM,CACzB,OAAO,IAAIT,EAAsCS,CAAK,CACxD,CAOO,SAAS+B,EAAOE,EAAQ,CAC7B,GAAI,CACF,IAAIrC,EACJ,GAAI,OAAOqC,GAAW,SACpBrC,EAAOqC,UACEA,GAAU,OAAOA,EAAO,SAAY,WAC7CrC,EACEqC,EAAO,QAAQtC,CAAc,GAC7BsC,EAAO,QAAQ,kBAAkB,GACjCA,EAAO,QAAQ,YAAY,MAE7B,QAAO,KAGT,OAAKrC,EAGEoC,EAAK,KAAK,MAAMpC,CAAI,CAAC,EAFnB,IAGX,MAAQ,CACN,OAAO,IACT,CACF",
6
6
  "names": ["TREF_EXTENSION", "TREF_ICON_SVG", "TREF_MIME_TYPE", "TREF_ICON_DATA_URL", "isValidBlock", "block", "b", "TrefWrapper", "#block", "options", "TREF_EXTENSION", "TREF_MIME_TYPE", "json", "base64", "dataTransfer", "type", "data", "interactive", "actionsHtml", "TREF_ICON_SVG", "#toggleActions", "element", "actions", "actionsEl", "isVisible", "firstBtn", "iconEl", "icon", "e", "de", "longPressTimer", "handleAction", "btn", "action", "originalHtml", "iconCheck", "iconError", "url", "a", "TrefReceiver", "#element", "#onReceive", "#onError", "#compact", "#setup", "el", "wrapper", "unwrap", "wrap", "source"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tref-block",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "TREF - Traceable Reference Format for knowledge with origin",
5
5
  "type": "module",
6
6
  "main": "dist/tref-block.js",
@@ -46,8 +46,16 @@
46
46
  "provenance",
47
47
  "citation"
48
48
  ],
49
- "author": "lpm",
49
+ "author": "lpmwfx",
50
50
  "license": "AGPL-3.0-or-later",
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "git+https://github.com/lpmwfx/tref.git"
54
+ },
55
+ "bugs": {
56
+ "url": "https://github.com/lpmwfx/tref/issues"
57
+ },
58
+ "homepage": "https://tref.lpmwfx.com",
51
59
  "devDependencies": {
52
60
  "@eslint/js": "^9.39.2",
53
61
  "@types/node": "^25.0.3",
@@ -337,19 +337,17 @@ export class TrefWrapper {
337
337
  --tref-receiver-error-bg: #fef2f2;
338
338
  --tref-receiver-block-bg: #ffffff;
339
339
  }
340
- @media (prefers-color-scheme: dark) {
341
- :root {
342
- --tref-menu-bg: #1f2937;
343
- --tref-menu-text: #e5e7eb;
344
- --tref-menu-hover: #374151;
345
- --tref-menu-shadow: 0 4px 12px rgba(0,0,0,0.4);
346
- --tref-receiver-bg: #1f2937;
347
- --tref-receiver-text: #9ca3af;
348
- --tref-receiver-active-bg: #3b2d5e;
349
- --tref-receiver-success-bg: #064e3b;
350
- --tref-receiver-error-bg: #450a0a;
351
- --tref-receiver-block-bg: #111827;
352
- }
340
+ .dark {
341
+ --tref-menu-bg: #1f2937;
342
+ --tref-menu-text: #e5e7eb;
343
+ --tref-menu-hover: #374151;
344
+ --tref-menu-shadow: 0 4px 12px rgba(0,0,0,0.4);
345
+ --tref-receiver-bg: #1f2937;
346
+ --tref-receiver-text: #9ca3af;
347
+ --tref-receiver-active-bg: #3b2d5e;
348
+ --tref-receiver-success-bg: #064e3b;
349
+ --tref-receiver-error-bg: #450a0a;
350
+ --tref-receiver-block-bg: #111827;
353
351
  }
354
352
  .tref-wrapper {
355
353
  display: inline-block;