@aigne/afs-ui 1.11.0-beta.12

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 (196) hide show
  1. package/LICENSE.md +26 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
  4. package/dist/aup-protocol.cjs +235 -0
  5. package/dist/aup-protocol.d.cts +78 -0
  6. package/dist/aup-protocol.d.cts.map +1 -0
  7. package/dist/aup-protocol.d.mts +78 -0
  8. package/dist/aup-protocol.d.mts.map +1 -0
  9. package/dist/aup-protocol.mjs +235 -0
  10. package/dist/aup-protocol.mjs.map +1 -0
  11. package/dist/aup-registry.cjs +2489 -0
  12. package/dist/aup-registry.mjs +2487 -0
  13. package/dist/aup-registry.mjs.map +1 -0
  14. package/dist/aup-spec.cjs +1467 -0
  15. package/dist/aup-spec.mjs +1466 -0
  16. package/dist/aup-spec.mjs.map +1 -0
  17. package/dist/aup-types.cjs +165 -0
  18. package/dist/aup-types.d.cts +157 -0
  19. package/dist/aup-types.d.cts.map +1 -0
  20. package/dist/aup-types.d.mts +157 -0
  21. package/dist/aup-types.d.mts.map +1 -0
  22. package/dist/aup-types.mjs +157 -0
  23. package/dist/aup-types.mjs.map +1 -0
  24. package/dist/backend.cjs +14 -0
  25. package/dist/backend.d.cts +104 -0
  26. package/dist/backend.d.cts.map +1 -0
  27. package/dist/backend.d.mts +104 -0
  28. package/dist/backend.d.mts.map +1 -0
  29. package/dist/backend.mjs +13 -0
  30. package/dist/backend.mjs.map +1 -0
  31. package/dist/degradation.cjs +85 -0
  32. package/dist/degradation.d.cts +17 -0
  33. package/dist/degradation.d.cts.map +1 -0
  34. package/dist/degradation.d.mts +17 -0
  35. package/dist/degradation.d.mts.map +1 -0
  36. package/dist/degradation.mjs +84 -0
  37. package/dist/degradation.mjs.map +1 -0
  38. package/dist/index.cjs +36 -0
  39. package/dist/index.d.cts +12 -0
  40. package/dist/index.d.mts +12 -0
  41. package/dist/index.mjs +13 -0
  42. package/dist/runtime.cjs +117 -0
  43. package/dist/runtime.d.cts +59 -0
  44. package/dist/runtime.d.cts.map +1 -0
  45. package/dist/runtime.d.mts +59 -0
  46. package/dist/runtime.d.mts.map +1 -0
  47. package/dist/runtime.mjs +118 -0
  48. package/dist/runtime.mjs.map +1 -0
  49. package/dist/session.cjs +159 -0
  50. package/dist/session.d.cts +80 -0
  51. package/dist/session.d.cts.map +1 -0
  52. package/dist/session.d.mts +80 -0
  53. package/dist/session.d.mts.map +1 -0
  54. package/dist/session.mjs +159 -0
  55. package/dist/session.mjs.map +1 -0
  56. package/dist/snapshot.cjs +162 -0
  57. package/dist/snapshot.mjs +163 -0
  58. package/dist/snapshot.mjs.map +1 -0
  59. package/dist/term-page.cjs +264 -0
  60. package/dist/term-page.mjs +264 -0
  61. package/dist/term-page.mjs.map +1 -0
  62. package/dist/term.cjs +295 -0
  63. package/dist/term.d.cts +84 -0
  64. package/dist/term.d.cts.map +1 -0
  65. package/dist/term.d.mts +84 -0
  66. package/dist/term.d.mts.map +1 -0
  67. package/dist/term.mjs +296 -0
  68. package/dist/term.mjs.map +1 -0
  69. package/dist/tty.cjs +136 -0
  70. package/dist/tty.d.cts +53 -0
  71. package/dist/tty.d.cts.map +1 -0
  72. package/dist/tty.d.mts +53 -0
  73. package/dist/tty.d.mts.map +1 -0
  74. package/dist/tty.mjs +135 -0
  75. package/dist/tty.mjs.map +1 -0
  76. package/dist/ui-provider.cjs +4615 -0
  77. package/dist/ui-provider.d.cts +307 -0
  78. package/dist/ui-provider.d.cts.map +1 -0
  79. package/dist/ui-provider.d.mts +307 -0
  80. package/dist/ui-provider.d.mts.map +1 -0
  81. package/dist/ui-provider.mjs +4616 -0
  82. package/dist/ui-provider.mjs.map +1 -0
  83. package/dist/web-page/core.cjs +1388 -0
  84. package/dist/web-page/core.mjs +1387 -0
  85. package/dist/web-page/core.mjs.map +1 -0
  86. package/dist/web-page/css.cjs +1699 -0
  87. package/dist/web-page/css.mjs +1698 -0
  88. package/dist/web-page/css.mjs.map +1 -0
  89. package/dist/web-page/icons.cjs +248 -0
  90. package/dist/web-page/icons.mjs +248 -0
  91. package/dist/web-page/icons.mjs.map +1 -0
  92. package/dist/web-page/overlay-themes.cjs +514 -0
  93. package/dist/web-page/overlay-themes.mjs +513 -0
  94. package/dist/web-page/overlay-themes.mjs.map +1 -0
  95. package/dist/web-page/renderers/action.cjs +72 -0
  96. package/dist/web-page/renderers/action.mjs +72 -0
  97. package/dist/web-page/renderers/action.mjs.map +1 -0
  98. package/dist/web-page/renderers/broadcast.cjs +160 -0
  99. package/dist/web-page/renderers/broadcast.mjs +160 -0
  100. package/dist/web-page/renderers/broadcast.mjs.map +1 -0
  101. package/dist/web-page/renderers/calendar.cjs +137 -0
  102. package/dist/web-page/renderers/calendar.mjs +137 -0
  103. package/dist/web-page/renderers/calendar.mjs.map +1 -0
  104. package/dist/web-page/renderers/canvas.cjs +173 -0
  105. package/dist/web-page/renderers/canvas.mjs +173 -0
  106. package/dist/web-page/renderers/canvas.mjs.map +1 -0
  107. package/dist/web-page/renderers/cdn-loader.cjs +25 -0
  108. package/dist/web-page/renderers/cdn-loader.mjs +25 -0
  109. package/dist/web-page/renderers/cdn-loader.mjs.map +1 -0
  110. package/dist/web-page/renderers/chart.cjs +101 -0
  111. package/dist/web-page/renderers/chart.mjs +101 -0
  112. package/dist/web-page/renderers/chart.mjs.map +1 -0
  113. package/dist/web-page/renderers/deck.cjs +390 -0
  114. package/dist/web-page/renderers/deck.mjs +390 -0
  115. package/dist/web-page/renderers/deck.mjs.map +1 -0
  116. package/dist/web-page/renderers/device.cjs +1015 -0
  117. package/dist/web-page/renderers/device.mjs +1015 -0
  118. package/dist/web-page/renderers/device.mjs.map +1 -0
  119. package/dist/web-page/renderers/editor.cjs +127 -0
  120. package/dist/web-page/renderers/editor.mjs +127 -0
  121. package/dist/web-page/renderers/editor.mjs.map +1 -0
  122. package/dist/web-page/renderers/finance-chart.cjs +178 -0
  123. package/dist/web-page/renderers/finance-chart.mjs +178 -0
  124. package/dist/web-page/renderers/finance-chart.mjs.map +1 -0
  125. package/dist/web-page/renderers/frame.cjs +274 -0
  126. package/dist/web-page/renderers/frame.mjs +274 -0
  127. package/dist/web-page/renderers/frame.mjs.map +1 -0
  128. package/dist/web-page/renderers/globe.cjs +119 -0
  129. package/dist/web-page/renderers/globe.mjs +119 -0
  130. package/dist/web-page/renderers/globe.mjs.map +1 -0
  131. package/dist/web-page/renderers/input.cjs +137 -0
  132. package/dist/web-page/renderers/input.mjs +137 -0
  133. package/dist/web-page/renderers/input.mjs.map +1 -0
  134. package/dist/web-page/renderers/list.cjs +1243 -0
  135. package/dist/web-page/renderers/list.mjs +1243 -0
  136. package/dist/web-page/renderers/list.mjs.map +1 -0
  137. package/dist/web-page/renderers/map.cjs +126 -0
  138. package/dist/web-page/renderers/map.mjs +126 -0
  139. package/dist/web-page/renderers/map.mjs.map +1 -0
  140. package/dist/web-page/renderers/media.cjs +106 -0
  141. package/dist/web-page/renderers/media.mjs +106 -0
  142. package/dist/web-page/renderers/media.mjs.map +1 -0
  143. package/dist/web-page/renderers/moonphase.cjs +105 -0
  144. package/dist/web-page/renderers/moonphase.mjs +105 -0
  145. package/dist/web-page/renderers/moonphase.mjs.map +1 -0
  146. package/dist/web-page/renderers/natal-chart.cjs +222 -0
  147. package/dist/web-page/renderers/natal-chart.mjs +222 -0
  148. package/dist/web-page/renderers/natal-chart.mjs.map +1 -0
  149. package/dist/web-page/renderers/overlay.cjs +531 -0
  150. package/dist/web-page/renderers/overlay.mjs +531 -0
  151. package/dist/web-page/renderers/overlay.mjs.map +1 -0
  152. package/dist/web-page/renderers/table.cjs +74 -0
  153. package/dist/web-page/renderers/table.mjs +74 -0
  154. package/dist/web-page/renderers/table.mjs.map +1 -0
  155. package/dist/web-page/renderers/terminal.cjs +30 -0
  156. package/dist/web-page/renderers/terminal.mjs +30 -0
  157. package/dist/web-page/renderers/terminal.mjs.map +1 -0
  158. package/dist/web-page/renderers/text.cjs +109 -0
  159. package/dist/web-page/renderers/text.mjs +109 -0
  160. package/dist/web-page/renderers/text.mjs.map +1 -0
  161. package/dist/web-page/renderers/ticker.cjs +133 -0
  162. package/dist/web-page/renderers/ticker.mjs +133 -0
  163. package/dist/web-page/renderers/ticker.mjs.map +1 -0
  164. package/dist/web-page/renderers/time.cjs +69 -0
  165. package/dist/web-page/renderers/time.mjs +69 -0
  166. package/dist/web-page/renderers/time.mjs.map +1 -0
  167. package/dist/web-page/renderers/unknown.cjs +20 -0
  168. package/dist/web-page/renderers/unknown.mjs +20 -0
  169. package/dist/web-page/renderers/unknown.mjs.map +1 -0
  170. package/dist/web-page/renderers/view.cjs +161 -0
  171. package/dist/web-page/renderers/view.mjs +161 -0
  172. package/dist/web-page/renderers/view.mjs.map +1 -0
  173. package/dist/web-page/renderers/wm.cjs +669 -0
  174. package/dist/web-page/renderers/wm.mjs +669 -0
  175. package/dist/web-page/renderers/wm.mjs.map +1 -0
  176. package/dist/web-page/skeleton.cjs +103 -0
  177. package/dist/web-page/skeleton.mjs +103 -0
  178. package/dist/web-page/skeleton.mjs.map +1 -0
  179. package/dist/web-page.cjs +114 -0
  180. package/dist/web-page.d.cts +19 -0
  181. package/dist/web-page.d.cts.map +1 -0
  182. package/dist/web-page.d.mts +19 -0
  183. package/dist/web-page.d.mts.map +1 -0
  184. package/dist/web-page.mjs +115 -0
  185. package/dist/web-page.mjs.map +1 -0
  186. package/dist/web.cjs +827 -0
  187. package/dist/web.d.cts +144 -0
  188. package/dist/web.d.cts.map +1 -0
  189. package/dist/web.d.mts +144 -0
  190. package/dist/web.d.mts.map +1 -0
  191. package/dist/web.mjs +828 -0
  192. package/dist/web.mjs.map +1 -0
  193. package/dist/wm-state.cjs +172 -0
  194. package/dist/wm-state.mjs +171 -0
  195. package/dist/wm-state.mjs.map +1 -0
  196. package/package.json +59 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.mjs","names":[],"sources":["../../../src/web-page/renderers/list.ts"],"sourcesContent":["export const LIST_JS = `\n // ── AFS List Primitive ──\n // Universal data view bound to AFS paths.\n // Two orthogonal dimensions: layout (how items arrange) × itemStyle (how each renders).\n // Pipeline: fetch → filter → sort → transform → render.\n\n // ── Kind Rendering Strategies ──\n var _listKindStrategies = {\n \"fs:directory\": function(entry) {\n var name = (entry.path || entry.id || \"\").split(\"/\").filter(Boolean).pop() || entry.id || \"\";\n return {\n icon: \"folder\",\n label: name,\n badge: entry.meta && entry.meta.childrenCount >= 0 ? String(entry.meta.childrenCount) : null,\n description: null,\n image: null,\n cssClass: \"aup-list-dir\"\n };\n },\n \"fs:file\": function(entry) {\n var name = (entry.path || entry.id || \"\").split(\"/\").filter(Boolean).pop() || entry.id || \"\";\n var ext = name.split(\".\").pop() || \"\";\n var iconMap = { ts: \"code\", js: \"code\", tsx: \"code\", jsx: \"code\", md: \"scroll\", json: \"code\", yaml: \"code\", yml: \"code\", png: \"image\", jpg: \"image\", svg: \"image\", css: \"code\", html: \"code\" };\n return {\n icon: iconMap[ext] || \"edit\",\n label: name,\n badge: entry.meta && entry.meta.size ? _listFormatSize(entry.meta.size) : null,\n description: entry.meta && entry.meta.mimeType ? entry.meta.mimeType : null,\n image: null,\n cssClass: \"aup-list-file\"\n };\n },\n \"ts:task-group\": function(entry) {\n var count = entry.meta && entry.meta.childrenCount;\n return {\n icon: \"grid\",\n label: entry.id,\n badge: count != null && count >= 0 ? String(count) : null,\n description: null,\n image: null,\n cssClass: \"aup-list-group aup-list-group--\" + (entry.id || \"\").replace(/[^a-z0-9]/gi, \"-\")\n };\n },\n \"ts:task\": function(entry) {\n var c = entry.content || {};\n var status = c.status || \"\";\n var parts = [];\n if (c.phase) parts.push(c.phase);\n if (c.assignee && c.assignee !== \"null\") parts.push(c.assignee);\n return {\n icon: status === \"done\" ? \"check\" : status === \"in_progress\" ? \"play\" : status === \"review\" ? \"search\" : status === \"blocked\" ? \"x\" : \"clock\",\n label: entry.id,\n badge: status || null,\n description: parts.length > 0 ? parts.join(\" \\\\u00b7 \") : null,\n image: null,\n cssClass: \"aup-list-task aup-list-task--\" + (status || \"unknown\")\n };\n },\n \"ts:queue-item\": function(entry) {\n var c = entry.content || {};\n return {\n icon: \"clock\",\n label: c.taskPath || entry.id,\n badge: c.role || null,\n description: c.addedAt ? \"Added \" + c.addedAt : null,\n image: null,\n cssClass: \"aup-list-queue\"\n };\n },\n \"ts:intent-group\": function(entry) {\n var count = entry.meta && entry.meta.childrenCount;\n return {\n icon: \"layers\",\n label: entry.id,\n badge: count != null && count >= 0 ? String(count) : null,\n description: null,\n image: null,\n cssClass: \"aup-list-group\"\n };\n },\n \"ts:daemon\": function(entry) {\n var c = entry.content || {};\n return {\n icon: \"cpu\",\n label: \"Daemon\",\n badge: c.version || null,\n description: c.pid ? \"PID \" + c.pid + \" \\\\u00b7 port \" + c.port : null,\n image: null,\n cssClass: \"aup-list-daemon\"\n };\n },\n \"_default\": function(entry) {\n var isDir = _listIsDirectory(entry);\n var desc = entry.meta && entry.meta.description;\n var name = (entry.path || entry.id || \"\").split(\"/\").filter(Boolean).pop() || entry.id || \"\";\n return {\n icon: isDir ? \"folder\" : \"edit\",\n label: name,\n badge: isDir && entry.meta.childrenCount >= 0 ? String(entry.meta.childrenCount) : null,\n description: desc ? String(desc).slice(0, 100) : null,\n image: null,\n cssClass: isDir ? \"aup-list-dir\" : \"aup-list-item\"\n };\n }\n };\n\n function _listResolveStrategy(entry) {\n var kind = (entry.meta && entry.meta.kind) || \"\";\n if (_listKindStrategies[kind]) return _listKindStrategies[kind](entry);\n var parts = kind.split(\":\");\n if (parts.length > 1) {\n var withSeg = parts[0] + \":\" + kind.split(\":\")[1].split(\"-\")[0];\n if (_listKindStrategies[withSeg]) return _listKindStrategies[withSeg](entry);\n }\n return _listKindStrategies._default(entry);\n }\n\n function _listResolveField(obj, dotPath) {\n if (!dotPath) return null;\n var parts = dotPath.split(\".\");\n var val = obj;\n for (var i = 0; i < parts.length; i++) {\n if (val == null) return null;\n val = val[parts[i]];\n }\n return val != null ? String(val) : null;\n }\n\n function _listIsDirectory(entry) {\n if (!entry.meta) return false;\n var cc = entry.meta.childrenCount;\n return cc != null;\n }\n\n function _listFormatSize(bytes) {\n if (bytes == null) return \"\";\n if (bytes < 1024) return bytes + \" B\";\n if (bytes < 1048576) return (bytes / 1024).toFixed(1) + \" KB\";\n return (bytes / 1048576).toFixed(1) + \" MB\";\n }\n\n function _listMakeIcon(name) {\n if (!name || !_ICON_PATHS[name]) return null;\n var svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n svg.setAttribute(\"viewBox\", \"0 0 24 24\");\n svg.setAttribute(\"fill\", \"none\");\n svg.setAttribute(\"stroke\", \"currentColor\");\n svg.setAttribute(\"stroke-width\", \"2\");\n svg.setAttribute(\"stroke-linecap\", \"round\");\n svg.setAttribute(\"stroke-linejoin\", \"round\");\n svg.classList.add(\"aup-icon-svg\");\n svg.innerHTML = _ICON_PATHS[name];\n return svg;\n }\n\n // ── Filter/Sort/Transform helpers ──\n function _listApplyFilter(entries, filter) {\n if (!filter) return entries;\n if (typeof filter === \"string\") {\n var q = filter.toLowerCase();\n return entries.filter(function(e) {\n return (e.id || \"\").toLowerCase().indexOf(q) >= 0;\n });\n }\n if (filter.kind) {\n var kindFilter = filter.kind;\n return entries.filter(function(e) {\n var k = (e.meta && e.meta.kind) || \"\";\n return k === kindFilter || k.indexOf(kindFilter) === 0;\n });\n }\n if (filter.field && filter.match != null) {\n return entries.filter(function(e) {\n var val = _listResolveField(e, filter.field);\n if (typeof filter.match === \"string\") return val === filter.match;\n return val != null;\n });\n }\n if (filter.exclude) {\n var excl = Array.isArray(filter.exclude) ? filter.exclude : [filter.exclude];\n return entries.filter(function(e) {\n return excl.indexOf(e.id) < 0;\n });\n }\n return entries;\n }\n\n function _listApplySort(entries, sort) {\n if (!sort) return entries;\n var field = typeof sort === \"string\" ? sort : sort.field || \"id\";\n var desc = sort.desc === true;\n return entries.slice().sort(function(a, b) {\n var va = _listResolveField(a, field) || \"\";\n var vb = _listResolveField(b, field) || \"\";\n var cmp = va < vb ? -1 : va > vb ? 1 : 0;\n return desc ? -cmp : cmp;\n });\n }\n\n function _listApplyTransform(entries, transform) {\n if (!transform) return entries;\n return entries.map(function(e) {\n var t = Object.assign({}, e);\n if (!t._transform) t._transform = {};\n if (transform.label) t._transform.label = _listResolveField(e, transform.label);\n if (transform.description) t._transform.description = _listResolveField(e, transform.description);\n if (transform.badge) t._transform.badge = _listResolveField(e, transform.badge);\n if (transform.icon) t._transform.icon = transform.icon;\n if (transform.image) t._transform.image = _listResolveField(e, transform.image);\n return t;\n });\n }\n\n function renderAupList(node) {\n var el = document.createElement(\"div\");\n el.className = \"aup-list\";\n var p = node.props || {};\n\n // ── Two orthogonal dimensions ──\n // layout: how items are arranged in space\n // itemStyle: how each individual item renders\n var layout = p.layout || p.variant || \"list\";\n // Backward compat: variant \"flat\" → layout \"list\", \"grouped\" → \"list\" with grouped behavior\n if (layout === \"flat\") layout = \"list\";\n var isGrouped = layout === \"grouped\" || (p.variant === \"grouped\");\n if (isGrouped) layout = \"list\";\n\n var itemStyle = p.itemStyle || \"row\";\n var clickMode = p.clickMode || \"select\";\n var labelField = p.labelField || \"id\";\n var descField = p.descriptionField != null ? p.descriptionField : \"meta.description\";\n var emptyText = p.emptyText || \"No items\";\n var showBreadcrumb = p.showBreadcrumb !== false;\n var kindIconOverrides = p.kindIcons || {};\n var maxDepth = typeof p.maxDepth === \"number\" ? p.maxDepth : 3;\n var fields = p.fields || null;\n var filter = p.filter || null;\n var sort = p.sort || null;\n var transform = p.transform || null;\n var columns = p.columns || null;\n var gridCols = p.gridCols || null;\n var minItemWidth = p.minItemWidth || null;\n var imageFit = p.imageFit || \"cover\"; // cover (aspect-fill) | contain (aspect-fit) | fill\n var imageHeight = p.imageHeight || null; // e.g. \"200px\", \"50%\", number (px)\n var imageShape = p.imageShape || \"rect\"; // rect (default) | circle (avatar-friendly)\n var pageSize = typeof p.pageSize === \"number\" && p.pageSize > 0 ? p.pageSize : 0;\n var _virtual = !!p.virtual;\n var _estimatedHeight = typeof p.estimatedItemHeight === \"number\" ? p.estimatedItemHeight : 48;\n var _bufferItems = typeof p.bufferItems === \"number\" ? p.bufferItems : 5;\n\n el.setAttribute(\"data-layout\", layout);\n el.setAttribute(\"data-item-style\", itemStyle);\n if (isGrouped) el.setAttribute(\"data-grouped\", \"true\");\n\n // Self-sizing grid: set CSS variables for grid-template-columns\n if (layout === \"grid\" || layout === \"masonry\") {\n if (gridCols) {\n el.style.setProperty(\"--list-cols\", String(gridCols));\n } else if (minItemWidth) {\n el.style.setProperty(\"--list-min-width\", minItemWidth);\n el.setAttribute(\"data-auto-fill\", \"true\");\n }\n }\n\n // ── Internal State ──\n var _currentPath = node.src || \"\";\n var _pathStack = [_currentPath];\n var _entries = [];\n var _expanded = {};\n var _childCache = {};\n var _selectedId = (node.state && node.state.selected) || null;\n var _unsubscribe = null;\n var _total = 0;\n var _loadedCount = 0;\n var _loadingMore = false;\n var _filterQuery = \"\";\n var _slideIndex = 0;\n var _itemHeights = [];\n var _virtualRenderedRange = null;\n var _srcRoot = node.src || \"\";\n\n // Build the full AFS path for an entry.\n // Prefer entry.path (full mount-aware path from AFS core) when available.\n // Fall back to constructing from entry.id + parent for legacy providers.\n function _buildEntryPath(entry, parentPath) {\n if (entry.path) return entry.path;\n var eid = entry.id || \"\";\n if (eid.charAt(0) === \"/\") {\n // Absolute provider path — join with src root\n return _srcRoot + eid;\n }\n // Relative id — join with parent\n return parentPath + (parentPath.endsWith(\"/\") ? \"\" : \"/\") + eid;\n }\n\n // ── Template Detection ──\n var _itemTemplate = null;\n var _headerTemplate = null;\n var _emptyTemplate = null;\n if (node.children && node.children.length) {\n for (var ci = 0; ci < node.children.length; ci++) {\n var ch = node.children[ci];\n var chRole = ch.props && ch.props.role;\n if (chRole === \"item\") _itemTemplate = ch;\n else if (chRole === \"header\") _headerTemplate = ch;\n else if (chRole === \"empty\") _emptyTemplate = ch;\n }\n }\n\n // ── Template Binding ──\n function _bindFieldPath(entry, dotPath) {\n var parts = dotPath.split(\".\");\n var val = entry;\n for (var bi = 0; bi < parts.length; bi++) {\n if (val == null) return null;\n // Auto-parse JSON strings when more path parts remain\n if (typeof val === \"string\" && bi < parts.length) {\n try { val = JSON.parse(val); } catch(_) { return null; }\n }\n val = val[parts[bi]];\n }\n return val != null ? String(val) : null;\n }\n\n function _bindStringsDeep(obj, entry) {\n for (var bk in obj) {\n var bv = obj[bk];\n if (typeof bv === \"string\") {\n obj[bk] = bv.replace(/\\\\$\\\\{entry\\\\.([^}]+)\\\\}/g, function(_, fp) {\n return _bindFieldPath(entry, fp) || \"\";\n });\n } else if (Array.isArray(bv)) {\n for (var ai = 0; ai < bv.length; ai++) {\n if (bv[ai] && typeof bv[ai] === \"object\") {\n _bindStringsDeep(bv[ai], entry);\n }\n }\n } else if (bv && typeof bv === \"object\") {\n _bindStringsDeep(bv, entry);\n }\n }\n }\n\n function _bindTemplate(tplNode, entry) {\n var bound = JSON.parse(JSON.stringify(tplNode));\n _bindStringsDeep(bound, entry);\n bound.id = tplNode.id + \"--\" + entry.id;\n return bound;\n }\n\n // ── DOM Structure ──\n\n // Search bar\n var searchEl = null;\n if (p.searchable) {\n searchEl = document.createElement(\"div\");\n searchEl.className = \"aup-list-search\";\n var searchInput = document.createElement(\"input\");\n searchInput.type = \"text\";\n searchInput.placeholder = p.searchPlaceholder || \"Search...\";\n searchInput.className = \"aup-list-search-input\";\n searchInput.oninput = function() {\n _filterQuery = searchInput.value;\n renderEntries();\n };\n searchEl.appendChild(searchInput);\n el.appendChild(searchEl);\n }\n\n // Breadcrumb\n var breadcrumbEl = null;\n if (showBreadcrumb && (clickMode === \"navigate\" || clickMode === \"both\")) {\n breadcrumbEl = document.createElement(\"div\");\n breadcrumbEl.className = \"aup-list-breadcrumb\";\n el.appendChild(breadcrumbEl);\n }\n\n var loadingEl = document.createElement(\"div\");\n loadingEl.className = \"aup-list-loading\";\n loadingEl.textContent = \"Loading...\";\n el.appendChild(loadingEl);\n\n var bodyEl = document.createElement(\"div\");\n bodyEl.className = \"aup-list-body\";\n if (gridCols) bodyEl.style.setProperty(\"--list-cols\", String(gridCols));\n el.appendChild(bodyEl);\n\n // Slideshow controls\n var slideshowNav = null;\n if (layout === \"slideshow\") {\n slideshowNav = document.createElement(\"div\");\n slideshowNav.className = \"aup-list-slideshow-nav\";\n var prevBtn = document.createElement(\"button\");\n prevBtn.className = \"aup-list-slide-btn\";\n prevBtn.textContent = \"\\\\u25C0\";\n prevBtn.onclick = function() { slideTo(_slideIndex - 1); };\n var nextBtn = document.createElement(\"button\");\n nextBtn.className = \"aup-list-slide-btn\";\n nextBtn.textContent = \"\\\\u25B6\";\n nextBtn.onclick = function() { slideTo(_slideIndex + 1); };\n var slideCounter = document.createElement(\"span\");\n slideCounter.className = \"aup-list-slide-counter\";\n slideshowNav.appendChild(prevBtn);\n slideshowNav.appendChild(slideCounter);\n slideshowNav.appendChild(nextBtn);\n el.appendChild(slideshowNav);\n }\n\n // ── Fields → Transform mapping ──\n // Semantic slot names → internal _transform keys\n // Agent writes: fields: { title: \"content.name\", image: \"content.src\" }\n // Internally: _transform.label = resolve(\"content.name\"), _transform.image = resolve(\"content.src\")\n var _fieldsSlotMap = {\n title: \"label\",\n subtitle: \"description\",\n image: \"image\",\n badge: \"badge\",\n icon: \"icon\",\n alt: \"alt\",\n footer: \"footer\"\n };\n\n function _listApplyFields(entries, fieldsSpec) {\n if (!fieldsSpec) return entries;\n return entries.map(function(e) {\n var t = Object.assign({}, e);\n if (!t._transform) t._transform = {};\n for (var slot in fieldsSpec) {\n var internalKey = _fieldsSlotMap[slot] || slot;\n var dotPath = fieldsSpec[slot];\n if (internalKey === \"icon\") {\n // Resolve dot-path to get icon name from entry data\n var iconVal = _bindFieldPath(e, dotPath);\n if (iconVal != null) t._transform.icon = iconVal;\n } else {\n // Use _bindFieldPath which auto-parses JSON strings in content\n var resolved = _bindFieldPath(e, dotPath);\n if (resolved != null) t._transform[internalKey] = resolved;\n }\n }\n return t;\n });\n }\n\n // ── Pipeline ──\n function processPipeline(entries) {\n var result = entries;\n result = _listApplyFilter(result, filter);\n if (_filterQuery) result = _listApplyFilter(result, _filterQuery);\n result = _listApplySort(result, sort);\n result = _listApplyTransform(result, transform);\n // fields overrides transform (more specific, agent-friendly API)\n result = _listApplyFields(result, fields);\n return result;\n }\n\n // ── Breadcrumb ──\n function renderBreadcrumb() {\n if (!breadcrumbEl) return;\n breadcrumbEl.innerHTML = \"\";\n for (var i = 0; i < _pathStack.length; i++) {\n if (i > 0) {\n var sep = document.createElement(\"span\");\n sep.className = \"aup-list-breadcrumb-sep\";\n sep.textContent = \" / \";\n breadcrumbEl.appendChild(sep);\n }\n var seg = document.createElement(\"span\");\n var segPath = _pathStack[i];\n var segName = segPath.split(\"/\").filter(Boolean).pop() || \"/\";\n if (i < _pathStack.length - 1) {\n seg.className = \"aup-list-breadcrumb-seg\";\n seg.textContent = segName;\n (function(targetPath, targetIdx) {\n seg.onclick = function() { navigateTo(targetPath, targetIdx); };\n })(segPath, i);\n } else {\n seg.className = \"aup-list-breadcrumb-cur\";\n seg.textContent = segName;\n }\n breadcrumbEl.appendChild(seg);\n }\n }\n\n // ── Item Style Renderers ──\n // Each returns a DOM element for one entry.\n\n function renderItemRow(entry, strategy, t) {\n var row = document.createElement(\"div\");\n row.className = \"aup-list-row \" + (strategy.cssClass || \"\");\n\n var iconName = t.icon || kindIconOverrides[(entry.meta && entry.meta.kind) || \"\"] || strategy.icon;\n var iconWrap = document.createElement(\"span\");\n iconWrap.className = \"aup-list-icon\";\n var svgIcon = _listMakeIcon(iconName);\n if (svgIcon) iconWrap.appendChild(svgIcon);\n row.appendChild(iconWrap);\n\n var textWrap = document.createElement(\"div\");\n textWrap.className = \"aup-list-text\";\n var labelText = t.label || strategy.label || _listResolveField(entry, labelField) || entry.id || \"\";\n var label = document.createElement(\"div\");\n label.className = \"aup-list-label\";\n label.textContent = labelText;\n textWrap.appendChild(label);\n var desc = t.description || (descField ? _listResolveField(entry, descField) : null) || strategy.description || null;\n if (desc) {\n var descEl = document.createElement(\"div\");\n descEl.className = \"aup-list-desc\";\n descEl.textContent = desc;\n textWrap.appendChild(descEl);\n }\n row.appendChild(textWrap);\n\n var badgeText = t.badge || strategy.badge;\n if (badgeText) {\n var badge = document.createElement(\"span\");\n badge.className = \"aup-list-badge\";\n badge.textContent = badgeText;\n row.appendChild(badge);\n }\n return row;\n }\n\n function renderItemCard(entry, strategy, t) {\n var card = document.createElement(\"div\");\n card.className = \"aup-list-card \" + (strategy.cssClass || \"\");\n\n var imgSrc = t.image || strategy.image;\n if (imgSrc) {\n if (imageShape === \"circle\") {\n var imgWrap = document.createElement(\"div\");\n imgWrap.className = \"aup-list-card-avatar-area\";\n var imgEl = document.createElement(\"div\");\n imgEl.className = \"aup-list-card-avatar\";\n imgEl.style.backgroundImage = \"url(\" + _escapeHtml(imgSrc) + \")\";\n if (t.alt) imgEl.setAttribute(\"role\", \"img\");\n if (t.alt) imgEl.setAttribute(\"aria-label\", t.alt);\n imgWrap.appendChild(imgEl);\n card.appendChild(imgWrap);\n } else {\n var img = document.createElement(\"div\");\n img.className = \"aup-list-card-image\";\n img.style.backgroundImage = \"url(\" + _escapeHtml(imgSrc) + \")\";\n img.style.backgroundSize = imageFit;\n if (imageHeight) img.style.height = typeof imageHeight === \"number\" ? imageHeight + \"px\" : imageHeight;\n if (t.alt) img.setAttribute(\"role\", \"img\");\n if (t.alt) img.setAttribute(\"aria-label\", t.alt);\n card.appendChild(img);\n }\n } else {\n var iconName = t.icon || kindIconOverrides[(entry.meta && entry.meta.kind) || \"\"] || strategy.icon;\n var iconArea = document.createElement(\"div\");\n iconArea.className = \"aup-list-card-icon-area\";\n var svgIcon = _listMakeIcon(iconName);\n if (svgIcon) iconArea.appendChild(svgIcon);\n card.appendChild(iconArea);\n }\n\n var body = document.createElement(\"div\");\n body.className = \"aup-list-card-body\";\n var labelText = t.label || strategy.label || _listResolveField(entry, labelField) || entry.id || \"\";\n var label = document.createElement(\"div\");\n label.className = \"aup-list-card-title\";\n label.textContent = labelText;\n body.appendChild(label);\n var desc = t.description || (descField ? _listResolveField(entry, descField) : null) || strategy.description || null;\n if (desc) {\n var descEl = document.createElement(\"div\");\n descEl.className = \"aup-list-card-desc\";\n descEl.textContent = desc;\n body.appendChild(descEl);\n }\n var badgeText = t.badge || strategy.badge;\n if (badgeText) {\n var badge = document.createElement(\"span\");\n badge.className = \"aup-list-badge\";\n badge.textContent = badgeText;\n body.appendChild(badge);\n }\n var footerText = t.footer || null;\n if (footerText) {\n var footerEl = document.createElement(\"div\");\n footerEl.className = \"aup-list-card-footer\";\n footerEl.textContent = footerText;\n body.appendChild(footerEl);\n }\n card.appendChild(body);\n return card;\n }\n\n function renderItemCompact(entry, strategy, t) {\n var row = document.createElement(\"div\");\n row.className = \"aup-list-compact \" + (strategy.cssClass || \"\");\n var iconName = t.icon || kindIconOverrides[(entry.meta && entry.meta.kind) || \"\"] || strategy.icon;\n var svgIcon = _listMakeIcon(iconName);\n if (svgIcon) {\n var iconWrap = document.createElement(\"span\");\n iconWrap.className = \"aup-list-icon\";\n iconWrap.appendChild(svgIcon);\n row.appendChild(iconWrap);\n }\n var label = document.createElement(\"span\");\n label.className = \"aup-list-label\";\n label.textContent = t.label || strategy.label || _listResolveField(entry, labelField) || entry.id || \"\";\n row.appendChild(label);\n return row;\n }\n\n function renderItemMedia(entry, strategy, t) {\n var card = document.createElement(\"div\");\n card.className = \"aup-list-media \" + (strategy.cssClass || \"\");\n\n var imgSrc = t.image || strategy.image;\n if (imgSrc) {\n var img = document.createElement(\"img\");\n img.className = \"aup-list-media-img\";\n img.src = imgSrc;\n img.alt = t.alt || entry.id || \"\";\n img.loading = \"lazy\";\n img.style.objectFit = imageFit;\n card.appendChild(img);\n } else {\n var placeholder = document.createElement(\"div\");\n placeholder.className = \"aup-list-media-placeholder\";\n var svgIcon = _listMakeIcon(t.icon || strategy.icon || \"image\");\n if (svgIcon) placeholder.appendChild(svgIcon);\n card.appendChild(placeholder);\n }\n\n var overlay = document.createElement(\"div\");\n overlay.className = \"aup-list-media-overlay\";\n var labelText = t.label || strategy.label || _listResolveField(entry, labelField) || entry.id || \"\";\n if (labelText) {\n var label = document.createElement(\"div\");\n label.className = \"aup-list-media-title\";\n label.textContent = labelText;\n overlay.appendChild(label);\n }\n var subtitleText = t.description || (descField ? _listResolveField(entry, descField) : null) || strategy.description || null;\n if (subtitleText) {\n var subtitle = document.createElement(\"div\");\n subtitle.className = \"aup-list-media-subtitle\";\n subtitle.textContent = subtitleText;\n overlay.appendChild(subtitle);\n }\n var footerText = t.footer || null;\n if (footerText) {\n var footer = document.createElement(\"div\");\n footer.className = \"aup-list-media-footer\";\n footer.textContent = footerText;\n overlay.appendChild(footer);\n }\n card.appendChild(overlay);\n return card;\n }\n\n function renderItemHero(entry, strategy, t) {\n var hero = document.createElement(\"div\");\n hero.className = \"aup-list-hero \" + (strategy.cssClass || \"\");\n\n var imgSrc = t.image || strategy.image;\n if (imgSrc) {\n hero.style.backgroundImage = \"url(\" + _escapeHtml(imgSrc) + \")\";\n hero.style.backgroundSize = imageFit;\n }\n\n var content = document.createElement(\"div\");\n content.className = \"aup-list-hero-content\";\n var label = document.createElement(\"div\");\n label.className = \"aup-list-hero-title\";\n label.textContent = t.label || strategy.label || _listResolveField(entry, labelField) || entry.id || \"\";\n content.appendChild(label);\n var desc = t.description || (descField ? _listResolveField(entry, descField) : null) || strategy.description || null;\n if (desc) {\n var descEl = document.createElement(\"div\");\n descEl.className = \"aup-list-hero-desc\";\n descEl.textContent = desc;\n content.appendChild(descEl);\n }\n var footerText = t.footer || null;\n if (footerText) {\n var footerEl = document.createElement(\"div\");\n footerEl.className = \"aup-list-hero-footer\";\n footerEl.textContent = footerText;\n content.appendChild(footerEl);\n }\n hero.appendChild(content);\n return hero;\n }\n\n function renderStyledItem(entry, strategy, t) {\n switch (itemStyle) {\n case \"card\": return renderItemCard(entry, strategy, t);\n case \"compact\": return renderItemCompact(entry, strategy, t);\n case \"media\": return renderItemMedia(entry, strategy, t);\n case \"hero\": return renderItemHero(entry, strategy, t);\n default: return renderItemRow(entry, strategy, t);\n }\n }\n\n // ── Table Rendering ──\n function renderTable(entries, expandable) {\n var table = document.createElement(\"table\");\n table.className = \"aup-list-table\";\n var thead = document.createElement(\"thead\");\n var headerRow = document.createElement(\"tr\");\n var cols = columns || [{ key: \"id\", label: \"Name\" }];\n if (expandable) {\n var thExpand = document.createElement(\"th\");\n thExpand.style.width = \"28px\";\n headerRow.appendChild(thExpand);\n }\n for (var ci = 0; ci < cols.length; ci++) {\n var th = document.createElement(\"th\");\n th.textContent = cols[ci].label || cols[ci].key;\n if (cols[ci].width) th.style.width = cols[ci].width;\n if (cols[ci].align) th.style.textAlign = cols[ci].align;\n headerRow.appendChild(th);\n }\n thead.appendChild(headerRow);\n table.appendChild(thead);\n var tbody = document.createElement(\"tbody\");\n renderTableRows(entries, tbody, cols, 0, expandable);\n table.appendChild(tbody);\n return table;\n }\n\n function renderTableRows(entries, tbody, cols, depth, expandable) {\n for (var ri = 0; ri < entries.length; ri++) {\n var entry = entries[ri];\n var tr = document.createElement(\"tr\");\n tr.className = \"aup-list-table-row\";\n tr.setAttribute(\"data-depth\", String(depth));\n var entryPath = _buildEntryPath(entry, _currentPath);\n var isDir = _listIsDirectory(entry);\n if (_selectedId === entry.id) tr.setAttribute(\"data-selected\", \"true\");\n\n if (expandable) {\n var tdExp = document.createElement(\"td\");\n tdExp.className = \"aup-list-table-expand\";\n tdExp.style.paddingLeft = (8 + depth * 16) + \"px\";\n if (isDir && depth < maxDepth) {\n var chevron = document.createElement(\"span\");\n chevron.className = \"aup-list-chevron\";\n chevron.textContent = _expanded[entryPath] ? \"\\\\u25BC\" : \"\\\\u25B6\";\n tdExp.appendChild(chevron);\n (function(ent, ep, d) {\n tdExp.onclick = function(e) {\n e.stopPropagation();\n toggleGroup(ent, ep, d);\n };\n })(entry, entryPath, depth);\n }\n tr.appendChild(tdExp);\n }\n\n for (var cj = 0; cj < cols.length; cj++) {\n var td = document.createElement(\"td\");\n var cellVal = _listResolveField(entry, cols[cj].key) || \"\";\n td.textContent = cellVal;\n if (cols[cj].align) td.style.textAlign = cols[cj].align;\n tr.appendChild(td);\n }\n\n (function(ent, ep) {\n tr.onclick = function(e) {\n if (e.target.closest && e.target.closest(\".aup-list-table-expand\")) return;\n _selectedId = ent.id;\n renderEntries();\n emitEvent(\"select\", { path: ep, id: ent.id, meta: ent.meta || {}, content: ent.content || {} });\n };\n })(entry, entryPath);\n\n tbody.appendChild(tr);\n\n // Expanded children rows (tree-table)\n if (expandable && isDir && _expanded[entryPath] && _childCache[entryPath]) {\n var childEntries = processPipeline(_childCache[entryPath]);\n renderTableRows(childEntries, tbody, cols, depth + 1, expandable);\n }\n }\n }\n\n // ── Grouped Item Rendering ──\n function renderGroupedItem(entry, parentPath, parentEl, depth) {\n var strategy = _listResolveStrategy(entry);\n var t = entry._transform || {};\n var isDir = _listIsDirectory(entry);\n var canExpand = isDir && depth < maxDepth;\n var entryPath = _buildEntryPath(entry, parentPath);\n\n var wrap = document.createElement(\"div\");\n wrap.className = \"aup-list-grouped-item\";\n wrap.setAttribute(\"data-depth\", String(depth));\n\n var header = document.createElement(\"div\");\n header.className = \"aup-list-row \" + (strategy.cssClass || \"\");\n header.setAttribute(\"data-kind\", (entry.meta && entry.meta.kind) || \"\");\n\n if (canExpand) {\n var chevron = document.createElement(\"span\");\n chevron.className = \"aup-list-chevron\";\n chevron.textContent = _expanded[entryPath] ? \"\\\\u25BC\" : \"\\\\u25B6\";\n header.appendChild(chevron);\n }\n\n // Reuse the chosen item style but within the grouped row\n var styledEl = renderStyledItem(entry, strategy, t);\n // Extract inner content from styled element to flatten into header\n while (styledEl.firstChild) header.appendChild(styledEl.firstChild);\n\n if (_selectedId === entry.id) header.setAttribute(\"data-selected\", \"true\");\n\n header.onclick = function(e) {\n e.stopPropagation();\n if (canExpand) {\n toggleGroup(entry, entryPath, depth);\n } else {\n var shouldNavigate = (clickMode === \"navigate\" && isDir) || (clickMode === \"both\" && isDir);\n var shouldSelect = (clickMode === \"select\") || (clickMode === \"both\" && !isDir);\n if (shouldNavigate) {\n navigateTo(entryPath + \"/\", _pathStack.length);\n emitEvent(\"navigate\", { path: entryPath, id: entry.id, meta: entry.meta || {}, previousPath: _currentPath });\n }\n if (shouldSelect || (!shouldNavigate && clickMode !== \"navigate\")) {\n _selectedId = entry.id;\n renderEntries();\n emitEvent(\"select\", { path: entryPath, id: entry.id, meta: entry.meta || {}, content: entry.content || {} });\n }\n }\n };\n\n wrap.appendChild(header);\n\n if (canExpand) {\n var childrenEl = document.createElement(\"div\");\n childrenEl.className = \"aup-list-children\";\n childrenEl.setAttribute(\"data-expanded\", String(!!_expanded[entryPath]));\n if (_expanded[entryPath] && _childCache[entryPath]) {\n var childEntries = processPipeline(_childCache[entryPath]);\n for (var ci = 0; ci < childEntries.length; ci++) {\n renderGroupedItem(childEntries[ci], entryPath, childrenEl, depth + 1);\n }\n }\n wrap.appendChild(childrenEl);\n }\n\n parentEl.appendChild(wrap);\n }\n\n // ── Flat Item Rendering ──\n function renderFlatItem(entry, parentPath, parentEl) {\n var strategy = _listResolveStrategy(entry);\n var t = entry._transform || {};\n var kind = (entry.meta && entry.meta.kind) || \"\";\n var isDir = _listIsDirectory(entry);\n var entryPath = _buildEntryPath(entry, parentPath);\n\n var item = renderStyledItem(entry, strategy, t);\n item.setAttribute(\"data-kind\", kind);\n item.style.cursor = \"pointer\";\n if (_selectedId === entry.id) item.setAttribute(\"data-selected\", \"true\");\n\n item.onclick = function(e) {\n e.stopPropagation();\n var shouldNavigate = (clickMode === \"navigate\" && isDir) || (clickMode === \"both\" && isDir);\n var shouldSelect = (clickMode === \"select\") || (clickMode === \"both\" && !isDir);\n if (shouldNavigate) {\n navigateTo(entryPath + \"/\", _pathStack.length);\n emitEvent(\"navigate\", { path: entryPath, id: entry.id, meta: entry.meta || {}, previousPath: _currentPath });\n }\n if (shouldSelect || (!shouldNavigate && clickMode !== \"navigate\")) {\n _selectedId = entry.id;\n renderEntries();\n emitEvent(\"select\", { path: entryPath, id: entry.id, meta: entry.meta || {}, content: entry.content || {} });\n }\n };\n\n parentEl.appendChild(item);\n }\n\n // ── Slideshow ──\n function slideTo(idx) {\n var items = bodyEl.children;\n if (!items.length) return;\n _slideIndex = Math.max(0, Math.min(idx, items.length - 1));\n for (var i = 0; i < items.length; i++) {\n items[i].style.display = i === _slideIndex ? \"\" : \"none\";\n }\n if (slideshowNav) {\n var counter = slideshowNav.querySelector(\".aup-list-slide-counter\");\n if (counter) counter.textContent = (_slideIndex + 1) + \" / \" + items.length;\n }\n }\n\n // ── Virtual Scroll Math ──\n function _vsFindStartIndex(scrollTop) {\n var acc = 0;\n for (var i = 0; i < _entries.length; i++) {\n var h = _itemHeights[i] || _estimatedHeight;\n if (acc + h > scrollTop) return i;\n acc += h;\n }\n return Math.max(0, _entries.length - 1);\n }\n\n function _vsSumHeights(from, to) {\n var sum = 0;\n for (var i = from; i < to; i++) {\n sum += _itemHeights[i] || _estimatedHeight;\n }\n return sum;\n }\n\n var _vsTopSpacer = null;\n var _vsBottomSpacer = null;\n var _vsContentEl = null;\n var _vsScrollHandler = null;\n\n if (_virtual) {\n bodyEl.style.overflow = \"auto\";\n bodyEl.style.position = \"relative\";\n _vsTopSpacer = document.createElement(\"div\");\n _vsTopSpacer.className = \"aup-list-virtual-spacer\";\n _vsBottomSpacer = document.createElement(\"div\");\n _vsBottomSpacer.className = \"aup-list-virtual-spacer\";\n _vsContentEl = document.createElement(\"div\");\n _vsContentEl.className = \"aup-list-virtual-content\";\n\n _vsScrollHandler = function() {\n _renderVirtualRange();\n };\n bodyEl.addEventListener(\"scroll\", _vsScrollHandler);\n }\n\n function _renderVirtualRange() {\n if (!_virtual || !_vsContentEl) return;\n var processed = processPipeline(_entries);\n if (processed.length === 0) return;\n\n var scrollTop = bodyEl.scrollTop;\n var viewportH = bodyEl.clientHeight;\n\n var rawStart = _vsFindStartIndex(scrollTop);\n var rawEnd = rawStart;\n var acc = 0;\n for (var i = rawStart; i < processed.length; i++) {\n acc += _itemHeights[i] || _estimatedHeight;\n rawEnd = i;\n if (acc >= viewportH) break;\n }\n\n var startIdx = Math.max(0, rawStart - _bufferItems);\n var endIdx = Math.min(processed.length - 1, rawEnd + _bufferItems);\n\n // Check if range changed\n if (_virtualRenderedRange &&\n _virtualRenderedRange[0] === startIdx &&\n _virtualRenderedRange[1] === endIdx) {\n return;\n }\n _virtualRenderedRange = [startIdx, endIdx];\n\n // Update spacers\n _vsTopSpacer.style.height = _vsSumHeights(0, startIdx) + \"px\";\n _vsBottomSpacer.style.height = _vsSumHeights(endIdx + 1, processed.length) + \"px\";\n\n // Render visible items\n _vsContentEl.innerHTML = \"\";\n for (var vi = startIdx; vi <= endIdx; vi++) {\n var vEntry = processed[vi];\n renderFlatItem(vEntry, _currentPath, _vsContentEl);\n // Measure item height after render\n var lastChild = _vsContentEl.lastElementChild;\n if (lastChild) {\n _itemHeights[vi] = lastChild.offsetHeight || _estimatedHeight;\n }\n }\n\n // Pagination: trigger fetch when near end\n if (pageSize > 0 && endIdx >= _loadedCount - _bufferItems && _loadedCount < _total && !_loadingMore) {\n fetchPage(_currentPath, _loadedCount, false);\n }\n }\n\n // ── Main Render ──\n function renderEntries() {\n bodyEl.innerHTML = \"\";\n\n // Header template\n if (_headerTemplate && typeof renderAupNode === \"function\") {\n var headerBound = JSON.parse(JSON.stringify(_headerTemplate));\n headerBound.id = (_headerTemplate.id || \"header\") + \"--header\";\n var headerEl = renderAupNode(headerBound);\n if (headerEl) {\n headerEl.classList.add(\"aup-list-template-header\");\n bodyEl.appendChild(headerEl);\n }\n }\n\n var processed = processPipeline(_entries);\n if (processed.length === 0) {\n // Empty template or default\n if (_emptyTemplate && typeof renderAupNode === \"function\") {\n var emptyBound = JSON.parse(JSON.stringify(_emptyTemplate));\n emptyBound.id = (_emptyTemplate.id || \"empty\") + \"--empty\";\n var emptyNodeEl = renderAupNode(emptyBound);\n if (emptyNodeEl) {\n emptyNodeEl.classList.add(\"aup-list-template-empty\");\n bodyEl.appendChild(emptyNodeEl);\n }\n } else {\n var empty = document.createElement(\"div\");\n empty.className = \"aup-list-empty\";\n empty.textContent = _filterQuery ? \"No matches\" : emptyText;\n bodyEl.appendChild(empty);\n }\n if (slideshowNav) slideshowNav.style.display = \"none\";\n return;\n }\n\n // Virtual scroll mode\n if (_virtual && _vsTopSpacer && _vsBottomSpacer && _vsContentEl) {\n bodyEl.appendChild(_vsTopSpacer);\n bodyEl.appendChild(_vsContentEl);\n bodyEl.appendChild(_vsBottomSpacer);\n _virtualRenderedRange = null;\n _renderVirtualRange();\n return;\n }\n\n // Three-layer template resolution: role=\"item\" > kind registry > built-in\n // _resolveTemplate returns a template node or null (null = use built-in)\n function _resolveTemplate(entry) {\n // Priority 1: explicit role=\"item\" child\n if (_itemTemplate) return _itemTemplate;\n // Priority 2: kind registry\n if (window.aup && window.aup.getKindTemplate) {\n var entryKind = (entry.meta && entry.meta.kind) || \"\";\n var kindTpl = window.aup.getKindTemplate(entryKind);\n if (kindTpl) return kindTpl;\n }\n // Priority 3: built-in\n return null;\n }\n\n // Check if ANY entry has a template (to decide render path)\n var _useTemplateMode = false;\n if (typeof renderAupNode === \"function\") {\n if (_itemTemplate) {\n _useTemplateMode = true;\n } else if (window.aup && window.aup.getKindTemplate) {\n for (var ci = 0; ci < processed.length; ci++) {\n if (_resolveTemplate(processed[ci])) { _useTemplateMode = true; break; }\n }\n }\n }\n\n if (_useTemplateMode) {\n for (var ti = 0; ti < processed.length; ti++) {\n var tEntry = processed[ti];\n var tpl = _resolveTemplate(tEntry);\n if (tpl) {\n var boundNode = _bindTemplate(tpl, tEntry);\n var tplEl = renderAupNode(boundNode);\n if (tplEl) {\n tplEl.classList.add(\"aup-list-template-item\");\n (function(entry) {\n tplEl.addEventListener(\"click\", function() {\n _selectedId = entry.id;\n emitEvent(\"select\", { path: entry.path, id: entry.id, meta: entry.meta, content: entry.content });\n });\n })(tEntry);\n bodyEl.appendChild(tplEl);\n }\n } else {\n // Fallback to built-in for entries without template\n renderFlatItem(tEntry, _currentPath, bodyEl);\n }\n }\n } else if (layout === \"table\") {\n bodyEl.appendChild(renderTable(processed, isGrouped));\n } else if (isGrouped) {\n for (var i = 0; i < processed.length; i++) {\n renderGroupedItem(processed[i], _currentPath, bodyEl, 0);\n }\n } else {\n for (var i = 0; i < processed.length; i++) {\n renderFlatItem(processed[i], _currentPath, bodyEl);\n }\n }\n\n if (layout === \"slideshow\") {\n slideTo(_slideIndex);\n if (slideshowNav) slideshowNav.style.display = \"\";\n }\n\n // Pagination: \"Load more\" button\n if (pageSize > 0 && _loadedCount < _total) {\n var moreEl = document.createElement(\"div\");\n moreEl.className = \"aup-list-load-more\";\n moreEl.textContent = \"Load more (\" + _loadedCount + \" of \" + _total + \")\";\n moreEl.addEventListener(\"click\", function() {\n if (!_loadingMore) {\n moreEl.textContent = \"Loading...\";\n fetchPage(_currentPath, _loadedCount, false);\n }\n });\n bodyEl.appendChild(moreEl);\n }\n }\n\n // ── Navigation ──\n function navigateTo(path, stackIdx) {\n _currentPath = path;\n if (stackIdx != null && stackIdx < _pathStack.length) {\n _pathStack = _pathStack.slice(0, stackIdx);\n }\n _pathStack.push(path);\n _selectedId = null;\n _expanded = {};\n _childCache = {};\n _slideIndex = 0;\n fetchAndRender(path);\n subscribePath(path);\n renderBreadcrumb();\n }\n\n // ── Group Toggle ──\n function toggleGroup(entry, entryPath, depth) {\n var wasExpanded = !!_expanded[entryPath];\n _expanded[entryPath] = !wasExpanded;\n\n if (!wasExpanded && !_childCache[entryPath]) {\n window.afs.list(entryPath + \"/\").then(function(result) {\n var data = result && result.data ? result.data : (Array.isArray(result) ? result : []);\n _childCache[entryPath] = Array.isArray(data) ? data : [];\n renderEntries();\n }).catch(function() {\n _childCache[entryPath] = [];\n renderEntries();\n });\n emitEvent(\"expand\", { path: entryPath, id: entry.id, childrenCount: entry.meta && entry.meta.childrenCount });\n } else {\n renderEntries();\n emitEvent(wasExpanded ? \"collapse\" : \"expand\", { path: entryPath, id: entry.id });\n }\n }\n\n // ── Data Fetching ──\n function fetchAndRender(path) {\n _entries = [];\n _total = 0;\n _loadedCount = 0;\n fetchPage(path, 0, true);\n }\n\n function fetchPage(path, offset, isInitial) {\n if (isInitial) {\n loadingEl.style.display = \"block\";\n bodyEl.style.display = \"none\";\n }\n _loadingMore = true;\n var opts = pageSize > 0 ? { offset: offset, limit: pageSize } : {};\n window.afs.list(path, opts).then(function(result) {\n // Handle both new { data, total } format and legacy array format\n var data = result && result.data ? result.data : (Array.isArray(result) ? result : []);\n var newEntries = Array.isArray(data) ? data : [];\n if (offset === 0) {\n _entries = newEntries;\n } else {\n _entries = _entries.concat(newEntries);\n }\n _total = result && result.total != null ? result.total : _entries.length;\n _loadedCount = _entries.length;\n _loadingMore = false;\n if (isInitial) {\n loadingEl.style.display = \"none\";\n bodyEl.style.display = \"\";\n }\n renderEntries();\n }).catch(function(e) {\n _loadingMore = false;\n if (isInitial) {\n var errStr = String(e && e.message || e || \"\");\n if (errStr.indexOf(\"not found\") >= 0 || errStr.indexOf(\"Not found\") >= 0 || errStr.indexOf(\"Path not found\") >= 0) {\n loadingEl.textContent = \"This entry cannot be browsed as a directory\";\n } else {\n loadingEl.textContent = \"Unable to list: \" + (errStr || \"unknown error\");\n }\n bodyEl.style.display = \"none\";\n }\n });\n }\n\n // ── Live Subscription ──\n function subscribePath(path) {\n if (_unsubscribe) _unsubscribe();\n if (window.afs && window.afs.subscribe) {\n _unsubscribe = window.afs.subscribe(\n { type: \"afs:write\", path: path },\n function() { fetchAndRender(_currentPath); }\n );\n }\n }\n\n // ── Event Emission ──\n function emitEvent(eventName, data) {\n if (ws && ws.readyState === 1) {\n ws.send(JSON.stringify({\n type: \"aup_event\",\n nodeId: node.id,\n event: eventName,\n data: data\n }));\n }\n // Also dispatch DOM CustomEvent for client-side listeners (e.g., device surface)\n el.dispatchEvent(new CustomEvent(\"aup-list:\" + eventName, { detail: data, bubbles: true }));\n }\n\n // ── Initial Load ──\n if (node.src && window.afs) {\n fetchAndRender(_currentPath);\n subscribePath(_currentPath);\n renderBreadcrumb();\n } else {\n loadingEl.style.display = \"none\";\n bodyEl.style.display = \"\";\n var empty = document.createElement(\"div\");\n empty.className = \"aup-list-empty\";\n empty.textContent = node.src ? \"Connecting...\" : emptyText;\n bodyEl.appendChild(empty);\n }\n\n return el;\n }\n`;\n"],"mappings":";AAAA,MAAa,UAAU"}
@@ -0,0 +1,126 @@
1
+
2
+ //#region src/web-page/renderers/map.ts
3
+ const MAP_JS = `
4
+ // ── Map Primitive (Leaflet v1) ──
5
+ // ── Map tile style presets ──
6
+ var _mapTileStyles = {
7
+ "carto-light": { url: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://carto.com">CARTO</a>' },
8
+ "carto-dark": { url: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://carto.com">CARTO</a>' },
9
+ "carto-voyager": { url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://carto.com">CARTO</a>' },
10
+ "osm": { url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attr: '&copy; <a href="https://openstreetmap.org">OpenStreetMap</a>' },
11
+ "stamen-toner": { url: "https://tiles.stadiamaps.com/tiles/stamen_toner_lite/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://stadiamaps.com">Stadia</a>' },
12
+ "stamen-watercolor": { url: "https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://stadiamaps.com">Stadia</a>' },
13
+ "alidade-smooth": { url: "https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://stadiamaps.com">Stadia</a>' },
14
+ "alidade-dark": { url: "https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://stadiamaps.com">Stadia</a>' }
15
+ };
16
+
17
+ var _markerIntentColors = {
18
+ primary: "#6366f1",
19
+ success: "#10b981",
20
+ warning: "#f59e0b",
21
+ danger: "#ef4444",
22
+ info: "#06b6d4",
23
+ accent: "#8b5cf6",
24
+ neutral: "#64748b"
25
+ };
26
+
27
+ function renderAupMap(node) {
28
+ var el = document.createElement("div");
29
+ el.className = "aup-map";
30
+ var p = node.props || {};
31
+ var center = p.center || [0, 0];
32
+ var zoom = p.zoom || 2;
33
+ var tileStyle = p.tileStyle || "carto-voyager";
34
+ var mapDiv = document.createElement("div");
35
+ mapDiv.style.width = "100%";
36
+ if (p.height) el.style.height = p.height;
37
+ mapDiv.style.height = "100%";
38
+ el.appendChild(mapDiv);
39
+
40
+ function initMap() {
41
+ if (typeof L === "undefined") {
42
+ loadCSS("https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.min.css");
43
+ var loading = document.createElement("div");
44
+ loading.className = "aup-map-loading";
45
+ loading.textContent = "Loading map...";
46
+ el.insertBefore(loading, mapDiv);
47
+ loadScript("https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.min.js", function() {
48
+ if (loading.parentNode) loading.parentNode.removeChild(loading);
49
+ createMap();
50
+ });
51
+ } else {
52
+ createMap();
53
+ }
54
+ }
55
+
56
+ function createMap() {
57
+ try {
58
+ var map = L.map(mapDiv, { zoomControl: false }).setView(center, zoom);
59
+
60
+ // Add zoom control to bottom-right for cleaner look
61
+ L.control.zoom({ position: "bottomright" }).addTo(map);
62
+
63
+ // Apply tile style
64
+ var tile = _mapTileStyles[tileStyle] || _mapTileStyles["carto-voyager"];
65
+ L.tileLayer(tile.url, { attribution: tile.attr, maxZoom: 19 }).addTo(map);
66
+
67
+ // Add markers
68
+ var markers = p.markers || [];
69
+ var markerLayer = L.featureGroup();
70
+ for (var i = 0; i < markers.length; i++) {
71
+ var m = markers[i];
72
+ var color = m.color || _markerIntentColors[m.intent || "primary"] || m.intent || "#6366f1";
73
+ var radius = m.radius || m.size || 7;
74
+ var cm = L.circleMarker([m.lat, m.lng], {
75
+ radius: radius,
76
+ fillColor: color,
77
+ color: "rgba(255,255,255,0.9)",
78
+ weight: 2,
79
+ opacity: 1,
80
+ fillOpacity: 0.85
81
+ }).addTo(markerLayer);
82
+ if (m.label) cm.bindPopup(_escapeHtml(String(m.label)));
83
+ }
84
+ markerLayer.addTo(map);
85
+
86
+ // Auto-fit if requested
87
+ if (p.fitMarkers && markers.length > 1) {
88
+ map.fitBounds(markerLayer.getBounds().pad(0.1));
89
+ }
90
+
91
+ // src binding for live marker updates
92
+ if (node.src && window.afs) {
93
+ window.afs.read(node.src).then(function(res) {
94
+ if (res && res.content) updateMarkers(map, markerLayer, res.content);
95
+ }).catch(function() {});
96
+ window.afs.subscribe({ type: "afs:write", path: node.src }, function(event) {
97
+ if (event && event.data) updateMarkers(map, markerLayer, event.data.content || event.data);
98
+ });
99
+ }
100
+ } catch(e) { mapDiv.textContent = "Map error: " + e.message; }
101
+ }
102
+
103
+ function updateMarkers(map, layer, data) {
104
+ layer.clearLayers();
105
+ var markers = data.markers || data || [];
106
+ if (!Array.isArray(markers)) return;
107
+ for (var i = 0; i < markers.length; i++) {
108
+ var m = markers[i];
109
+ var color = m.color || _markerIntentColors[m.intent || "primary"] || "#6366f1";
110
+ var radius = m.radius || m.size || 7;
111
+ var cm = L.circleMarker([m.lat, m.lng], {
112
+ radius: radius, fillColor: color, color: "rgba(255,255,255,0.9)",
113
+ weight: 2, opacity: 1, fillOpacity: 0.85
114
+ }).addTo(layer);
115
+ if (m.label) cm.bindPopup(_escapeHtml(String(m.label)));
116
+ }
117
+ }
118
+
119
+ setTimeout(initMap, 0);
120
+ return el;
121
+ }
122
+
123
+ `;
124
+
125
+ //#endregion
126
+ exports.MAP_JS = MAP_JS;
@@ -0,0 +1,126 @@
1
+ //#region src/web-page/renderers/map.ts
2
+ const MAP_JS = `
3
+ // ── Map Primitive (Leaflet v1) ──
4
+ // ── Map tile style presets ──
5
+ var _mapTileStyles = {
6
+ "carto-light": { url: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://carto.com">CARTO</a>' },
7
+ "carto-dark": { url: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://carto.com">CARTO</a>' },
8
+ "carto-voyager": { url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://carto.com">CARTO</a>' },
9
+ "osm": { url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attr: '&copy; <a href="https://openstreetmap.org">OpenStreetMap</a>' },
10
+ "stamen-toner": { url: "https://tiles.stadiamaps.com/tiles/stamen_toner_lite/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://stadiamaps.com">Stadia</a>' },
11
+ "stamen-watercolor": { url: "https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://stadiamaps.com">Stadia</a>' },
12
+ "alidade-smooth": { url: "https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://stadiamaps.com">Stadia</a>' },
13
+ "alidade-dark": { url: "https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png", attr: '&copy; <a href="https://openstreetmap.org">OSM</a> &copy; <a href="https://stadiamaps.com">Stadia</a>' }
14
+ };
15
+
16
+ var _markerIntentColors = {
17
+ primary: "#6366f1",
18
+ success: "#10b981",
19
+ warning: "#f59e0b",
20
+ danger: "#ef4444",
21
+ info: "#06b6d4",
22
+ accent: "#8b5cf6",
23
+ neutral: "#64748b"
24
+ };
25
+
26
+ function renderAupMap(node) {
27
+ var el = document.createElement("div");
28
+ el.className = "aup-map";
29
+ var p = node.props || {};
30
+ var center = p.center || [0, 0];
31
+ var zoom = p.zoom || 2;
32
+ var tileStyle = p.tileStyle || "carto-voyager";
33
+ var mapDiv = document.createElement("div");
34
+ mapDiv.style.width = "100%";
35
+ if (p.height) el.style.height = p.height;
36
+ mapDiv.style.height = "100%";
37
+ el.appendChild(mapDiv);
38
+
39
+ function initMap() {
40
+ if (typeof L === "undefined") {
41
+ loadCSS("https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.min.css");
42
+ var loading = document.createElement("div");
43
+ loading.className = "aup-map-loading";
44
+ loading.textContent = "Loading map...";
45
+ el.insertBefore(loading, mapDiv);
46
+ loadScript("https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.min.js", function() {
47
+ if (loading.parentNode) loading.parentNode.removeChild(loading);
48
+ createMap();
49
+ });
50
+ } else {
51
+ createMap();
52
+ }
53
+ }
54
+
55
+ function createMap() {
56
+ try {
57
+ var map = L.map(mapDiv, { zoomControl: false }).setView(center, zoom);
58
+
59
+ // Add zoom control to bottom-right for cleaner look
60
+ L.control.zoom({ position: "bottomright" }).addTo(map);
61
+
62
+ // Apply tile style
63
+ var tile = _mapTileStyles[tileStyle] || _mapTileStyles["carto-voyager"];
64
+ L.tileLayer(tile.url, { attribution: tile.attr, maxZoom: 19 }).addTo(map);
65
+
66
+ // Add markers
67
+ var markers = p.markers || [];
68
+ var markerLayer = L.featureGroup();
69
+ for (var i = 0; i < markers.length; i++) {
70
+ var m = markers[i];
71
+ var color = m.color || _markerIntentColors[m.intent || "primary"] || m.intent || "#6366f1";
72
+ var radius = m.radius || m.size || 7;
73
+ var cm = L.circleMarker([m.lat, m.lng], {
74
+ radius: radius,
75
+ fillColor: color,
76
+ color: "rgba(255,255,255,0.9)",
77
+ weight: 2,
78
+ opacity: 1,
79
+ fillOpacity: 0.85
80
+ }).addTo(markerLayer);
81
+ if (m.label) cm.bindPopup(_escapeHtml(String(m.label)));
82
+ }
83
+ markerLayer.addTo(map);
84
+
85
+ // Auto-fit if requested
86
+ if (p.fitMarkers && markers.length > 1) {
87
+ map.fitBounds(markerLayer.getBounds().pad(0.1));
88
+ }
89
+
90
+ // src binding for live marker updates
91
+ if (node.src && window.afs) {
92
+ window.afs.read(node.src).then(function(res) {
93
+ if (res && res.content) updateMarkers(map, markerLayer, res.content);
94
+ }).catch(function() {});
95
+ window.afs.subscribe({ type: "afs:write", path: node.src }, function(event) {
96
+ if (event && event.data) updateMarkers(map, markerLayer, event.data.content || event.data);
97
+ });
98
+ }
99
+ } catch(e) { mapDiv.textContent = "Map error: " + e.message; }
100
+ }
101
+
102
+ function updateMarkers(map, layer, data) {
103
+ layer.clearLayers();
104
+ var markers = data.markers || data || [];
105
+ if (!Array.isArray(markers)) return;
106
+ for (var i = 0; i < markers.length; i++) {
107
+ var m = markers[i];
108
+ var color = m.color || _markerIntentColors[m.intent || "primary"] || "#6366f1";
109
+ var radius = m.radius || m.size || 7;
110
+ var cm = L.circleMarker([m.lat, m.lng], {
111
+ radius: radius, fillColor: color, color: "rgba(255,255,255,0.9)",
112
+ weight: 2, opacity: 1, fillOpacity: 0.85
113
+ }).addTo(layer);
114
+ if (m.label) cm.bindPopup(_escapeHtml(String(m.label)));
115
+ }
116
+ }
117
+
118
+ setTimeout(initMap, 0);
119
+ return el;
120
+ }
121
+
122
+ `;
123
+
124
+ //#endregion
125
+ export { MAP_JS };
126
+ //# sourceMappingURL=map.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map.mjs","names":[],"sources":["../../../src/web-page/renderers/map.ts"],"sourcesContent":["export const MAP_JS = `\n // ── Map Primitive (Leaflet v1) ──\n // ── Map tile style presets ──\n var _mapTileStyles = {\n \"carto-light\": { url: \"https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png\", attr: '&copy; <a href=\"https://openstreetmap.org\">OSM</a> &copy; <a href=\"https://carto.com\">CARTO</a>' },\n \"carto-dark\": { url: \"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png\", attr: '&copy; <a href=\"https://openstreetmap.org\">OSM</a> &copy; <a href=\"https://carto.com\">CARTO</a>' },\n \"carto-voyager\": { url: \"https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png\", attr: '&copy; <a href=\"https://openstreetmap.org\">OSM</a> &copy; <a href=\"https://carto.com\">CARTO</a>' },\n \"osm\": { url: \"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\", attr: '&copy; <a href=\"https://openstreetmap.org\">OpenStreetMap</a>' },\n \"stamen-toner\": { url: \"https://tiles.stadiamaps.com/tiles/stamen_toner_lite/{z}/{x}/{y}{r}.png\", attr: '&copy; <a href=\"https://openstreetmap.org\">OSM</a> &copy; <a href=\"https://stadiamaps.com\">Stadia</a>' },\n \"stamen-watercolor\": { url: \"https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg\", attr: '&copy; <a href=\"https://openstreetmap.org\">OSM</a> &copy; <a href=\"https://stadiamaps.com\">Stadia</a>' },\n \"alidade-smooth\": { url: \"https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png\", attr: '&copy; <a href=\"https://openstreetmap.org\">OSM</a> &copy; <a href=\"https://stadiamaps.com\">Stadia</a>' },\n \"alidade-dark\": { url: \"https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png\", attr: '&copy; <a href=\"https://openstreetmap.org\">OSM</a> &copy; <a href=\"https://stadiamaps.com\">Stadia</a>' }\n };\n\n var _markerIntentColors = {\n primary: \"#6366f1\",\n success: \"#10b981\",\n warning: \"#f59e0b\",\n danger: \"#ef4444\",\n info: \"#06b6d4\",\n accent: \"#8b5cf6\",\n neutral: \"#64748b\"\n };\n\n function renderAupMap(node) {\n var el = document.createElement(\"div\");\n el.className = \"aup-map\";\n var p = node.props || {};\n var center = p.center || [0, 0];\n var zoom = p.zoom || 2;\n var tileStyle = p.tileStyle || \"carto-voyager\";\n var mapDiv = document.createElement(\"div\");\n mapDiv.style.width = \"100%\";\n if (p.height) el.style.height = p.height;\n mapDiv.style.height = \"100%\";\n el.appendChild(mapDiv);\n\n function initMap() {\n if (typeof L === \"undefined\") {\n loadCSS(\"https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.min.css\");\n var loading = document.createElement(\"div\");\n loading.className = \"aup-map-loading\";\n loading.textContent = \"Loading map...\";\n el.insertBefore(loading, mapDiv);\n loadScript(\"https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.min.js\", function() {\n if (loading.parentNode) loading.parentNode.removeChild(loading);\n createMap();\n });\n } else {\n createMap();\n }\n }\n\n function createMap() {\n try {\n var map = L.map(mapDiv, { zoomControl: false }).setView(center, zoom);\n\n // Add zoom control to bottom-right for cleaner look\n L.control.zoom({ position: \"bottomright\" }).addTo(map);\n\n // Apply tile style\n var tile = _mapTileStyles[tileStyle] || _mapTileStyles[\"carto-voyager\"];\n L.tileLayer(tile.url, { attribution: tile.attr, maxZoom: 19 }).addTo(map);\n\n // Add markers\n var markers = p.markers || [];\n var markerLayer = L.featureGroup();\n for (var i = 0; i < markers.length; i++) {\n var m = markers[i];\n var color = m.color || _markerIntentColors[m.intent || \"primary\"] || m.intent || \"#6366f1\";\n var radius = m.radius || m.size || 7;\n var cm = L.circleMarker([m.lat, m.lng], {\n radius: radius,\n fillColor: color,\n color: \"rgba(255,255,255,0.9)\",\n weight: 2,\n opacity: 1,\n fillOpacity: 0.85\n }).addTo(markerLayer);\n if (m.label) cm.bindPopup(_escapeHtml(String(m.label)));\n }\n markerLayer.addTo(map);\n\n // Auto-fit if requested\n if (p.fitMarkers && markers.length > 1) {\n map.fitBounds(markerLayer.getBounds().pad(0.1));\n }\n\n // src binding for live marker updates\n if (node.src && window.afs) {\n window.afs.read(node.src).then(function(res) {\n if (res && res.content) updateMarkers(map, markerLayer, res.content);\n }).catch(function() {});\n window.afs.subscribe({ type: \"afs:write\", path: node.src }, function(event) {\n if (event && event.data) updateMarkers(map, markerLayer, event.data.content || event.data);\n });\n }\n } catch(e) { mapDiv.textContent = \"Map error: \" + e.message; }\n }\n\n function updateMarkers(map, layer, data) {\n layer.clearLayers();\n var markers = data.markers || data || [];\n if (!Array.isArray(markers)) return;\n for (var i = 0; i < markers.length; i++) {\n var m = markers[i];\n var color = m.color || _markerIntentColors[m.intent || \"primary\"] || \"#6366f1\";\n var radius = m.radius || m.size || 7;\n var cm = L.circleMarker([m.lat, m.lng], {\n radius: radius, fillColor: color, color: \"rgba(255,255,255,0.9)\",\n weight: 2, opacity: 1, fillOpacity: 0.85\n }).addTo(layer);\n if (m.label) cm.bindPopup(_escapeHtml(String(m.label)));\n }\n }\n\n setTimeout(initMap, 0);\n return el;\n }\n\n`;\n"],"mappings":";AAAA,MAAa,SAAS"}
@@ -0,0 +1,106 @@
1
+
2
+ //#region src/web-page/renderers/media.ts
3
+ const MEDIA_JS = `
4
+ function renderAupMedia(node) {
5
+ var el = document.createElement("div");
6
+ el.className = "aup-media";
7
+ var p = node.props || {};
8
+ var mediaType = p.type || "image";
9
+
10
+ if (mediaType === "avatar") {
11
+ var avatar = document.createElement("div");
12
+ avatar.className = "aup-avatar";
13
+ if (p.size) avatar.setAttribute("data-size", p.size);
14
+ var avatarSrc = String(p.src || "");
15
+ if (avatarSrc && !avatarSrc.toLowerCase().startsWith("javascript:")) {
16
+ var avatarImg = document.createElement("img");
17
+ avatarImg.src = avatarSrc;
18
+ avatarImg.alt = _escapeHtml(String(p.alt || p.name || ""));
19
+ avatar.appendChild(avatarImg);
20
+ } else {
21
+ // Initials fallback
22
+ var name = String(p.name || p.alt || "?");
23
+ var initials = name.split(/\\s+/).map(function(w) { return w[0]; }).join("").slice(0, 2).toUpperCase();
24
+ avatar.textContent = initials;
25
+ }
26
+ el.appendChild(avatar);
27
+ } else if (mediaType === "icon") {
28
+ var iconName = p.name || p.content || "";
29
+ var svgPath = _ICON_PATHS[iconName];
30
+ if (svgPath) {
31
+ var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
32
+ svg.setAttribute("viewBox", "0 0 24 24");
33
+ svg.setAttribute("fill", "none");
34
+ svg.setAttribute("stroke", "currentColor");
35
+ svg.setAttribute("stroke-width", "2");
36
+ svg.setAttribute("stroke-linecap", "round");
37
+ svg.setAttribute("stroke-linejoin", "round");
38
+ svg.classList.add("aup-icon-svg");
39
+ svg.innerHTML = svgPath;
40
+ el.appendChild(svg);
41
+ } else {
42
+ // Fallback: single letter/emoji avatar
43
+ var icon = document.createElement("span");
44
+ icon.className = "aup-icon";
45
+ icon.textContent = String(iconName).slice(0, 2);
46
+ el.appendChild(icon);
47
+ }
48
+ } else if (mediaType === "video") {
49
+ var video = document.createElement("video");
50
+ var src = String(p.src || "");
51
+ if (src && !src.toLowerCase().startsWith("javascript:")) {
52
+ video.src = src;
53
+ }
54
+ video.controls = p.controls !== false;
55
+ if (p.autoPlay) { video.autoplay = true; video.muted = true; } // autoplay requires muted
56
+ if (p.loop) video.loop = true;
57
+ if (p.muted) video.muted = true;
58
+ if (p.poster) video.poster = String(p.poster);
59
+ if (p.fit) video.style.objectFit = p.fit;
60
+ if (typeof p.volume === "number") video.volume = Math.max(0, Math.min(1, p.volume));
61
+ video.playsInline = true;
62
+ var svw = (p.size && p.size.width) || p.width;
63
+ var svh = (p.size && p.size.height) || p.height;
64
+ if (svw) video.style.width = typeof svw === "number" ? svw + "px" : svw;
65
+ if (svh) video.style.height = typeof svh === "number" ? svh + "px" : svh;
66
+ if ((svw || svh) && !p.fit) video.style.objectFit = "contain";
67
+ el.appendChild(video);
68
+ } else if (mediaType === "audio") {
69
+ var audio = document.createElement("audio");
70
+ var audioSrc = String(p.src || "");
71
+ if (audioSrc && !audioSrc.toLowerCase().startsWith("javascript:")) {
72
+ audio.src = audioSrc;
73
+ }
74
+ audio.controls = p.controls !== false;
75
+ if (p.autoPlay) audio.autoplay = true;
76
+ if (p.loop) audio.loop = true;
77
+ if (p.muted) audio.muted = true;
78
+ if (typeof p.volume === "number") audio.volume = Math.max(0, Math.min(1, p.volume));
79
+ el.appendChild(audio);
80
+ } else {
81
+ // image
82
+ var src = String(p.src || "");
83
+ if (src && !src.toLowerCase().startsWith("javascript:")) {
84
+ var img = document.createElement("img");
85
+ img.src = src;
86
+ img.alt = _escapeHtml(String(p.alt || ""));
87
+ var sw = (p.size && p.size.width) || p.width;
88
+ var sh = (p.size && p.size.height) || p.height;
89
+ if (sw) img.style.width = typeof sw === "number" ? sw + "px" : sw;
90
+ if (sh) img.style.height = typeof sh === "number" ? sh + "px" : sh;
91
+ if (sw || sh) img.style.objectFit = "contain";
92
+ el.appendChild(img);
93
+ } else {
94
+ var ph = document.createElement("div");
95
+ ph.className = "aup-placeholder";
96
+ ph.textContent = p.alt ? _escapeHtml(String(p.alt)) : "No image";
97
+ el.appendChild(ph);
98
+ }
99
+ }
100
+ return el;
101
+ }
102
+
103
+ `;
104
+
105
+ //#endregion
106
+ exports.MEDIA_JS = MEDIA_JS;
@@ -0,0 +1,106 @@
1
+ //#region src/web-page/renderers/media.ts
2
+ const MEDIA_JS = `
3
+ function renderAupMedia(node) {
4
+ var el = document.createElement("div");
5
+ el.className = "aup-media";
6
+ var p = node.props || {};
7
+ var mediaType = p.type || "image";
8
+
9
+ if (mediaType === "avatar") {
10
+ var avatar = document.createElement("div");
11
+ avatar.className = "aup-avatar";
12
+ if (p.size) avatar.setAttribute("data-size", p.size);
13
+ var avatarSrc = String(p.src || "");
14
+ if (avatarSrc && !avatarSrc.toLowerCase().startsWith("javascript:")) {
15
+ var avatarImg = document.createElement("img");
16
+ avatarImg.src = avatarSrc;
17
+ avatarImg.alt = _escapeHtml(String(p.alt || p.name || ""));
18
+ avatar.appendChild(avatarImg);
19
+ } else {
20
+ // Initials fallback
21
+ var name = String(p.name || p.alt || "?");
22
+ var initials = name.split(/\\s+/).map(function(w) { return w[0]; }).join("").slice(0, 2).toUpperCase();
23
+ avatar.textContent = initials;
24
+ }
25
+ el.appendChild(avatar);
26
+ } else if (mediaType === "icon") {
27
+ var iconName = p.name || p.content || "";
28
+ var svgPath = _ICON_PATHS[iconName];
29
+ if (svgPath) {
30
+ var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
31
+ svg.setAttribute("viewBox", "0 0 24 24");
32
+ svg.setAttribute("fill", "none");
33
+ svg.setAttribute("stroke", "currentColor");
34
+ svg.setAttribute("stroke-width", "2");
35
+ svg.setAttribute("stroke-linecap", "round");
36
+ svg.setAttribute("stroke-linejoin", "round");
37
+ svg.classList.add("aup-icon-svg");
38
+ svg.innerHTML = svgPath;
39
+ el.appendChild(svg);
40
+ } else {
41
+ // Fallback: single letter/emoji avatar
42
+ var icon = document.createElement("span");
43
+ icon.className = "aup-icon";
44
+ icon.textContent = String(iconName).slice(0, 2);
45
+ el.appendChild(icon);
46
+ }
47
+ } else if (mediaType === "video") {
48
+ var video = document.createElement("video");
49
+ var src = String(p.src || "");
50
+ if (src && !src.toLowerCase().startsWith("javascript:")) {
51
+ video.src = src;
52
+ }
53
+ video.controls = p.controls !== false;
54
+ if (p.autoPlay) { video.autoplay = true; video.muted = true; } // autoplay requires muted
55
+ if (p.loop) video.loop = true;
56
+ if (p.muted) video.muted = true;
57
+ if (p.poster) video.poster = String(p.poster);
58
+ if (p.fit) video.style.objectFit = p.fit;
59
+ if (typeof p.volume === "number") video.volume = Math.max(0, Math.min(1, p.volume));
60
+ video.playsInline = true;
61
+ var svw = (p.size && p.size.width) || p.width;
62
+ var svh = (p.size && p.size.height) || p.height;
63
+ if (svw) video.style.width = typeof svw === "number" ? svw + "px" : svw;
64
+ if (svh) video.style.height = typeof svh === "number" ? svh + "px" : svh;
65
+ if ((svw || svh) && !p.fit) video.style.objectFit = "contain";
66
+ el.appendChild(video);
67
+ } else if (mediaType === "audio") {
68
+ var audio = document.createElement("audio");
69
+ var audioSrc = String(p.src || "");
70
+ if (audioSrc && !audioSrc.toLowerCase().startsWith("javascript:")) {
71
+ audio.src = audioSrc;
72
+ }
73
+ audio.controls = p.controls !== false;
74
+ if (p.autoPlay) audio.autoplay = true;
75
+ if (p.loop) audio.loop = true;
76
+ if (p.muted) audio.muted = true;
77
+ if (typeof p.volume === "number") audio.volume = Math.max(0, Math.min(1, p.volume));
78
+ el.appendChild(audio);
79
+ } else {
80
+ // image
81
+ var src = String(p.src || "");
82
+ if (src && !src.toLowerCase().startsWith("javascript:")) {
83
+ var img = document.createElement("img");
84
+ img.src = src;
85
+ img.alt = _escapeHtml(String(p.alt || ""));
86
+ var sw = (p.size && p.size.width) || p.width;
87
+ var sh = (p.size && p.size.height) || p.height;
88
+ if (sw) img.style.width = typeof sw === "number" ? sw + "px" : sw;
89
+ if (sh) img.style.height = typeof sh === "number" ? sh + "px" : sh;
90
+ if (sw || sh) img.style.objectFit = "contain";
91
+ el.appendChild(img);
92
+ } else {
93
+ var ph = document.createElement("div");
94
+ ph.className = "aup-placeholder";
95
+ ph.textContent = p.alt ? _escapeHtml(String(p.alt)) : "No image";
96
+ el.appendChild(ph);
97
+ }
98
+ }
99
+ return el;
100
+ }
101
+
102
+ `;
103
+
104
+ //#endregion
105
+ export { MEDIA_JS };
106
+ //# sourceMappingURL=media.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.mjs","names":[],"sources":["../../../src/web-page/renderers/media.ts"],"sourcesContent":["export const MEDIA_JS = `\n function renderAupMedia(node) {\n var el = document.createElement(\"div\");\n el.className = \"aup-media\";\n var p = node.props || {};\n var mediaType = p.type || \"image\";\n\n if (mediaType === \"avatar\") {\n var avatar = document.createElement(\"div\");\n avatar.className = \"aup-avatar\";\n if (p.size) avatar.setAttribute(\"data-size\", p.size);\n var avatarSrc = String(p.src || \"\");\n if (avatarSrc && !avatarSrc.toLowerCase().startsWith(\"javascript:\")) {\n var avatarImg = document.createElement(\"img\");\n avatarImg.src = avatarSrc;\n avatarImg.alt = _escapeHtml(String(p.alt || p.name || \"\"));\n avatar.appendChild(avatarImg);\n } else {\n // Initials fallback\n var name = String(p.name || p.alt || \"?\");\n var initials = name.split(/\\\\s+/).map(function(w) { return w[0]; }).join(\"\").slice(0, 2).toUpperCase();\n avatar.textContent = initials;\n }\n el.appendChild(avatar);\n } else if (mediaType === \"icon\") {\n var iconName = p.name || p.content || \"\";\n var svgPath = _ICON_PATHS[iconName];\n if (svgPath) {\n var svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n svg.setAttribute(\"viewBox\", \"0 0 24 24\");\n svg.setAttribute(\"fill\", \"none\");\n svg.setAttribute(\"stroke\", \"currentColor\");\n svg.setAttribute(\"stroke-width\", \"2\");\n svg.setAttribute(\"stroke-linecap\", \"round\");\n svg.setAttribute(\"stroke-linejoin\", \"round\");\n svg.classList.add(\"aup-icon-svg\");\n svg.innerHTML = svgPath;\n el.appendChild(svg);\n } else {\n // Fallback: single letter/emoji avatar\n var icon = document.createElement(\"span\");\n icon.className = \"aup-icon\";\n icon.textContent = String(iconName).slice(0, 2);\n el.appendChild(icon);\n }\n } else if (mediaType === \"video\") {\n var video = document.createElement(\"video\");\n var src = String(p.src || \"\");\n if (src && !src.toLowerCase().startsWith(\"javascript:\")) {\n video.src = src;\n }\n video.controls = p.controls !== false;\n if (p.autoPlay) { video.autoplay = true; video.muted = true; } // autoplay requires muted\n if (p.loop) video.loop = true;\n if (p.muted) video.muted = true;\n if (p.poster) video.poster = String(p.poster);\n if (p.fit) video.style.objectFit = p.fit;\n if (typeof p.volume === \"number\") video.volume = Math.max(0, Math.min(1, p.volume));\n video.playsInline = true;\n var svw = (p.size && p.size.width) || p.width;\n var svh = (p.size && p.size.height) || p.height;\n if (svw) video.style.width = typeof svw === \"number\" ? svw + \"px\" : svw;\n if (svh) video.style.height = typeof svh === \"number\" ? svh + \"px\" : svh;\n if ((svw || svh) && !p.fit) video.style.objectFit = \"contain\";\n el.appendChild(video);\n } else if (mediaType === \"audio\") {\n var audio = document.createElement(\"audio\");\n var audioSrc = String(p.src || \"\");\n if (audioSrc && !audioSrc.toLowerCase().startsWith(\"javascript:\")) {\n audio.src = audioSrc;\n }\n audio.controls = p.controls !== false;\n if (p.autoPlay) audio.autoplay = true;\n if (p.loop) audio.loop = true;\n if (p.muted) audio.muted = true;\n if (typeof p.volume === \"number\") audio.volume = Math.max(0, Math.min(1, p.volume));\n el.appendChild(audio);\n } else {\n // image\n var src = String(p.src || \"\");\n if (src && !src.toLowerCase().startsWith(\"javascript:\")) {\n var img = document.createElement(\"img\");\n img.src = src;\n img.alt = _escapeHtml(String(p.alt || \"\"));\n var sw = (p.size && p.size.width) || p.width;\n var sh = (p.size && p.size.height) || p.height;\n if (sw) img.style.width = typeof sw === \"number\" ? sw + \"px\" : sw;\n if (sh) img.style.height = typeof sh === \"number\" ? sh + \"px\" : sh;\n if (sw || sh) img.style.objectFit = \"contain\";\n el.appendChild(img);\n } else {\n var ph = document.createElement(\"div\");\n ph.className = \"aup-placeholder\";\n ph.textContent = p.alt ? _escapeHtml(String(p.alt)) : \"No image\";\n el.appendChild(ph);\n }\n }\n return el;\n }\n\n`;\n"],"mappings":";AAAA,MAAa,WAAW"}