@dimina-kit/devtools 0.4.0-dev.20260624040247 → 0.4.0-dev.20260624084417

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.
@@ -28,7 +28,7 @@
28
28
  overflow: hidden;
29
29
  }
30
30
  </style>
31
- <script type="module" crossorigin src="../../assets/index-PtsdWlGu.js"></script>
31
+ <script type="module" crossorigin src="../../assets/index-BMqriQNr.js"></script>
32
32
  <link rel="modulepreload" crossorigin href="../../assets/chunk-DPI0Y_ll.js">
33
33
  <link rel="modulepreload" crossorigin href="../../assets/ipc-transport-DSBmaWpJ.js">
34
34
  <link rel="modulepreload" crossorigin href="../../assets/editor.api2-BTaYmRq7.js">
@@ -82,8 +82,15 @@ export declare function projectSourceContextFromServiceHostUrl(serviceHostUrl: s
82
82
  /**
83
83
  * Build the DevTools-front-end glue for project source links.
84
84
  *
85
- * It keeps the existing `setOpenResourceHandler` transport, but only forwards
86
- * locations that map to the active project. A DOM observer expands Chromium's
85
+ * Primary transport is a capture-phase click interceptor: a project-source link
86
+ * click is redirected to `InspectorFrontendHost.openInNewTab(<sentinel>)` (which
87
+ * Electron surfaces as `devtools-open-url` on the inspected wc) and the default
88
+ * DevTools Sources reveal is suppressed. This survives current Chromium DevTools,
89
+ * where the legacy `Host.InspectorFrontendHost.setOpenResourceHandler` hook is
90
+ * gone (the host moved to the top-level `InspectorFrontendHost` global and that
91
+ * method no longer exists). The `setOpenResourceHandler` registration below is
92
+ * kept as a no-op-when-absent fallback for older fronts. Only locations that map
93
+ * to the active project are forwarded; a DOM observer expands Chromium's
87
94
  * basename-only console labels to project-relative paths.
88
95
  */
89
96
  export declare function buildDevtoolsProjectSourceLinksScript(context: ProjectSourceContext): string;
@@ -169,11 +169,28 @@ function projectAwareResourcePath(resourceUrl, context) {
169
169
  const raw = resourceUrl.trim();
170
170
  if (!raw)
171
171
  return null;
172
+ // Taro/webpack build + runtime chunks are compiled output, not hand-written
173
+ // source. They also collide: dimina's own service runtime attributes its
174
+ // `log()` helper to a `common.js` on the SAME dev-server origin as the
175
+ // project's compiled `common.js` chunk, so the two are URL-indistinguishable
176
+ // and a dimina-core frame would otherwise open the project's chunk. Drop these
177
+ // well-known chunk basenames so a click falls through to the DevTools Sources
178
+ // panel instead of opening the wrong (or generated) file. Inlined (not a module
179
+ // const) because this function is `.toString()`-injected into the DevTools realm.
180
+ const excludeBuildChunk = (rel) => {
181
+ if (!rel)
182
+ return rel;
183
+ const base = rel.split('/').pop();
184
+ return base === 'common.js' || base === 'vendors.js' || base === 'runtime.js'
185
+ || base === 'taro.js' || base === 'babelHelpers.js'
186
+ ? null
187
+ : rel;
188
+ };
172
189
  // Chromium may hand the open-resource hook a raw absolute filesystem path.
173
190
  const normalizedRaw = normalizeSlashPath(raw);
174
191
  if (projectRoot && (normalizedRaw === projectRoot || normalizedRaw.startsWith(`${projectRoot}/`))) {
175
192
  const relative = normalizedRaw.slice(projectRoot.length).replace(/^\/+/, '');
176
- return safeRelativePath(relative.split('/').filter(Boolean));
193
+ return excludeBuildChunk(safeRelativePath(relative.split('/').filter(Boolean)));
177
194
  }
178
195
  // Sourcemap sources commonly use virtual root paths such as `/pages/x.js`.
179
196
  // Real host filesystem paths use well-known absolute roots; when they are
@@ -199,7 +216,7 @@ function projectAwareResourcePath(resourceUrl, context) {
199
216
  const filePath = normalizeSlashPath(resource.pathname);
200
217
  if (!projectRoot || (filePath !== projectRoot && !filePath.startsWith(`${projectRoot}/`)))
201
218
  return null;
202
- return safeRelativePath(filePath.slice(projectRoot.length).replace(/^\/+/, '').split('/').filter(Boolean));
219
+ return excludeBuildChunk(safeRelativePath(filePath.slice(projectRoot.length).replace(/^\/+/, '').split('/').filter(Boolean)));
203
220
  }
204
221
  if (resource.protocol !== 'http:' && resource.protocol !== 'https:')
205
222
  return null;
@@ -211,7 +228,7 @@ function projectAwareResourcePath(resourceUrl, context) {
211
228
  if (context.outputRoot && segments[0] === context.outputRoot)
212
229
  segments = segments.slice(1);
213
230
  }
214
- return safeRelativePath(segments);
231
+ return excludeBuildChunk(safeRelativePath(segments));
215
232
  }
216
233
  /** Read the project/source routing metadata carried by a service-host spawn URL. */
217
234
  export function projectSourceContextFromServiceHostUrl(serviceHostUrl, activeProjectRoot) {
@@ -245,8 +262,15 @@ export function projectSourceContextFromServiceHostUrl(serviceHostUrl, activePro
245
262
  /**
246
263
  * Build the DevTools-front-end glue for project source links.
247
264
  *
248
- * It keeps the existing `setOpenResourceHandler` transport, but only forwards
249
- * locations that map to the active project. A DOM observer expands Chromium's
265
+ * Primary transport is a capture-phase click interceptor: a project-source link
266
+ * click is redirected to `InspectorFrontendHost.openInNewTab(<sentinel>)` (which
267
+ * Electron surfaces as `devtools-open-url` on the inspected wc) and the default
268
+ * DevTools Sources reveal is suppressed. This survives current Chromium DevTools,
269
+ * where the legacy `Host.InspectorFrontendHost.setOpenResourceHandler` hook is
270
+ * gone (the host moved to the top-level `InspectorFrontendHost` global and that
271
+ * method no longer exists). The `setOpenResourceHandler` registration below is
272
+ * kept as a no-op-when-absent fallback for older fronts. Only locations that map
273
+ * to the active project are forwarded; a DOM observer expands Chromium's
250
274
  * basename-only console labels to project-relative paths.
251
275
  */
252
276
  export function buildDevtoolsProjectSourceLinksScript(context) {
@@ -268,6 +292,7 @@ export function buildDevtoolsProjectSourceLinksScript(context) {
268
292
  const safeRelativePath = ${safeRelativePath.toString()}
269
293
  const observedRoots = new Set()
270
294
  const observers = []
295
+ const clickBindings = []
271
296
  let timer = null
272
297
  const state = {
273
298
  dispose() {
@@ -278,11 +303,106 @@ export function buildDevtoolsProjectSourceLinksScript(context) {
278
303
  for (const observer of observers.splice(0)) {
279
304
  try { observer.disconnect() } catch (_) {}
280
305
  }
306
+ for (const binding of clickBindings.splice(0)) {
307
+ try { binding.target.removeEventListener('click', binding.fn, true) } catch (_) {}
308
+ }
281
309
  observedRoots.clear()
282
310
  },
283
311
  }
284
312
  globalThis[stateKey] = state
285
313
 
314
+ // The InspectorFrontendHost that owns openInNewTab. Across DevTools
315
+ // versions it lives on the top-level \`InspectorFrontendHost\` global, the
316
+ // legacy \`Host.InspectorFrontendHost\`, or \`DevToolsHost\`; resolve at call
317
+ // time so a late-bootstrapped host is still found.
318
+ function resolveOpenInNewTabHost() {
319
+ const candidates = [
320
+ globalThis.InspectorFrontendHost,
321
+ globalThis.Host && globalThis.Host.InspectorFrontendHost,
322
+ globalThis.DevToolsHost,
323
+ ]
324
+ for (const host of candidates) {
325
+ if (host && typeof host.openInNewTab === 'function') return host
326
+ }
327
+ return null
328
+ }
329
+
330
+ // Encode (url, 0-based line, 0-based column) as the sentinel the main
331
+ // process decodes from \`devtools-open-url\` and routes to Monaco.
332
+ function openInEditor(url, line, column) {
333
+ const host = resolveOpenInNewTabHost()
334
+ if (!host) return false
335
+ const p = new URLSearchParams()
336
+ p.set('u', String(url))
337
+ if (typeof line === 'number' && isFinite(line)) p.set('l', String(line))
338
+ if (typeof column === 'number' && isFinite(column)) p.set('c', String(column))
339
+ try { host.openInNewTab(${scheme} + ':?' + p.toString()) } catch (_) { return false }
340
+ return true
341
+ }
342
+
343
+ // Resolve a clicked link element to a project source location. Returns
344
+ // the FULL resource url (the main process re-maps it against the active
345
+ // project) plus its display line/column when present.
346
+ function projectLocationForLink(link) {
347
+ if (!link) return null
348
+ const candidates = [
349
+ link.getAttribute && link.getAttribute('data-url'),
350
+ link.getAttribute && link.getAttribute('href'),
351
+ link.getAttribute && link.getAttribute('title'),
352
+ ]
353
+ for (const candidate of candidates) {
354
+ if (!candidate) continue
355
+ const location = splitLocation(candidate)
356
+ if (!diminaProjectSourcePath(location.url, cfg)) continue
357
+ const suffix = location.suffix
358
+ || ((String(link.textContent || '').match(/(:\\d+(?::\\d+)?)$/) || [])[1] || '')
359
+ return { url: location.url, suffix }
360
+ }
361
+ return null
362
+ }
363
+
364
+ // DevTools shows 1-based line:column in link text; the main process
365
+ // contract expects 0-based (it re-adds 1). Convert here.
366
+ function parseSuffix(suffix) {
367
+ const m = String(suffix || '').match(/^:(\\d+)(?::(\\d+))?$/)
368
+ if (!m) return { line: undefined, column: undefined }
369
+ const line = Math.max(0, parseInt(m[1], 10) - 1)
370
+ const column = m[2] != null ? Math.max(0, parseInt(m[2], 10) - 1) : undefined
371
+ return { line, column }
372
+ }
373
+
374
+ // Capture-phase click handler: route a project-source link click to
375
+ // Monaco instead of the DevTools Sources panel. Plain primary clicks only
376
+ // — modified clicks (cmd/ctrl/shift/alt, middle button) fall through to
377
+ // DevTools so its own "open in new tab" / multi-select still work.
378
+ function onLinkClick(event) {
379
+ if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return
380
+ const path = typeof event.composedPath === 'function' ? event.composedPath() : []
381
+ let link = null
382
+ for (const node of path) {
383
+ if (node && node.nodeType === 1 && node.classList && node.classList.contains('devtools-link')) {
384
+ link = node
385
+ break
386
+ }
387
+ }
388
+ if (!link) return
389
+ const location = projectLocationForLink(link)
390
+ if (!location) return
391
+ const { line, column } = parseSuffix(location.suffix)
392
+ if (!openInEditor(location.url, line, column)) return
393
+ event.preventDefault()
394
+ event.stopImmediatePropagation()
395
+ }
396
+
397
+ function bindClicks(target) {
398
+ if (!target || !target.addEventListener) return
399
+ for (const binding of clickBindings) {
400
+ if (binding.target === target) return
401
+ }
402
+ target.addEventListener('click', onLinkClick, true)
403
+ clickBindings.push({ target, fn: onLinkClick })
404
+ }
405
+
286
406
  function splitLocation(value) {
287
407
  const raw = String(value || '')
288
408
  const match = raw.match(/^(.*?)(?::(\\d+))(?::(\\d+))?$/)
@@ -313,6 +433,7 @@ export function buildDevtoolsProjectSourceLinksScript(context) {
313
433
  function observeRoot(root) {
314
434
  if (!root || !root.querySelectorAll || observedRoots.has(root)) return
315
435
  observedRoots.add(root)
436
+ bindClicks(root)
316
437
 
317
438
  const observer = new MutationObserver((records) => {
318
439
  for (const record of records) {
@@ -347,23 +468,25 @@ export function buildDevtoolsProjectSourceLinksScript(context) {
347
468
 
348
469
  observeRoot(document)
349
470
 
471
+ // Fallback for older DevTools fronts that still expose the
472
+ // setOpenResourceHandler hook. On current Chromium the method is gone,
473
+ // so this poll simply times out and the capture-phase click interceptor
474
+ // is the only live path. When the hook IS present the interceptor still
475
+ // wins (it runs in capture and stops propagation), so the two never
476
+ // double-open the same click.
350
477
  let tries = 0
351
478
  timer = setInterval(() => {
352
479
  tries++
353
480
  try {
354
- const Host = globalThis.Host
355
- const host = Host && Host.InspectorFrontendHost
356
- if (host && typeof host.setOpenResourceHandler === 'function'
357
- && typeof host.openInNewTab === 'function') {
481
+ const host = resolveOpenInNewTabHost()
482
+ if (host && typeof host.setOpenResourceHandler === 'function') {
358
483
  host.setOpenResourceHandler((url, lineNumber, columnNumber) => {
359
- try {
360
- if (!diminaProjectSourcePath(String(url), cfg)) return
361
- const p = new URLSearchParams()
362
- p.set('u', String(url))
363
- if (typeof lineNumber === 'number') p.set('l', String(lineNumber))
364
- if (typeof columnNumber === 'number') p.set('c', String(columnNumber))
365
- host.openInNewTab(${scheme} + ':?' + p.toString())
366
- } catch (_) {}
484
+ if (!diminaProjectSourcePath(String(url), cfg)) return
485
+ openInEditor(
486
+ String(url),
487
+ typeof lineNumber === 'number' ? lineNumber : undefined,
488
+ typeof columnNumber === 'number' ? columnNumber : undefined,
489
+ )
367
490
  })
368
491
  clearInterval(timer)
369
492
  timer = null
@@ -0,0 +1,2 @@
1
+ import{n as e,t}from"./jsx-runtime-P6ZegaOf.js";import{t as n}from"./bridge-channels-BUQ5AbvJ.js";var r=e(),i=new Set([`audioListen`]);function a(e){return i.has(e)}function o(e,t,n,r){let i=e.apiRegistry[t];if(!i)return r({ok:!1,errMsg:`${t}:fail no handler`}),Promise.resolve();let o=a(t)||(n&&typeof n==`object`&&!Array.isArray(n)?n.keep===!0:!1);return new Promise(a=>{let s=!1,c=e=>{if(s){o&&e.ok&&r({...e,keep:!0});return}s=!0,r(o&&e.ok?{...e,keep:!0}:e),a()},l=Symbol(`sim-cb-success`),u=Symbol(`sim-cb-fail`),d=Symbol(`sim-cb-complete`),f=Object.create(e);f.createCallbackFunction=e=>{if(e!=null)return(...n)=>{let r=n[0];e===l?c({ok:!0,result:r}):e===u&&c({ok:!1,errMsg:r&&typeof r==`object`&&`errMsg`in r?String(r.errMsg):`${t}:fail`,result:r})}};let p=n&&typeof n==`object`&&!Array.isArray(n)?{...n}:{},m=p.success!==void 0&&p.success!==null,h=p.fail!==void 0&&p.fail!==null,g=p.complete!==void 0&&p.complete!==null;p.success=l,p.fail=u,g&&(p.complete=d);try{let e=i.call(f,p);if(e&&typeof e.then==`function`){Promise.resolve(e).then(e=>c({ok:!0,result:e}),e=>{c({ok:!1,errMsg:`${t}:fail ${e instanceof Error?e.message:String(e)}`})});return}!m&&!h&&(o?a():c({ok:!0,result:e}))}catch(e){c({ok:!1,errMsg:`${t}:fail ${e instanceof Error?e.message:String(e)}`})}})}var s=t();function c({platform:e,statusBarHeight:t,textStyle:n}){let r=e===`ios`?87:95,i=t+(e===`ios`?4:6),a=e===`ios`?7:10;return(0,s.jsxs)(`div`,{className:`menu-capsule menu-capsule--${n}`,style:{width:r,height:32,top:i,right:a},"aria-hidden":`true`,children:[(0,s.jsxs)(`div`,{className:`menu-capsule__more`,children:[(0,s.jsx)(`span`,{}),(0,s.jsx)(`span`,{}),(0,s.jsx)(`span`,{})]}),(0,s.jsx)(`div`,{className:`menu-capsule__divider`}),(0,s.jsx)(`div`,{className:`menu-capsule__close`,children:(0,s.jsx)(`svg`,{viewBox:`0 0 16 16`,width:`12`,height:`12`,"aria-hidden":`true`,children:(0,s.jsx)(`path`,{d:`M4 4l8 8M12 4l-8 8`,stroke:`currentColor`,strokeWidth:`1.5`,fill:`none`,strokeLinecap:`round`})})})]})}var l={linear:`linear`,easeIn:`ease-in`,easeOut:`ease-out`,easeInOut:`ease-in-out`};function u({state:e,stackDepth:t,platform:n,statusBarHeight:i,navBarHeight:a,onBack:o,onHome:u}){let d=(0,r.useMemo)(()=>{if(!e.colorAnimation||e.colorAnimation.durationMs<=0)return;let t=l[e.colorAnimation.timingFunc]??`linear`;return`background-color ${e.colorAnimation.durationMs}ms ${t}, color ${e.colorAnimation.durationMs}ms ${t}`},[e.colorAnimation]),f=e.style===`custom`,p=t>1,m=!p&&e.homeButtonVisible,h=n===`ios`?`center`:`left`,g={backgroundColor:e.backgroundColor,color:e.textStyle===`white`?`#ffffff`:`#000000`,height:i+a,paddingTop:i,transition:d};return(0,s.jsxs)(`header`,{className:`nav-bar nav-bar--${n} nav-bar--${e.textStyle}${f?` nav-bar--custom`:``}`,style:g,"aria-hidden":f,children:[!f&&(0,s.jsxs)(`div`,{className:`nav-bar__row`,style:{height:a,justifyContent:h===`center`?`center`:`flex-start`},children:[(p||m)&&(0,s.jsxs)(`div`,{className:`nav-bar__leading`,children:[p&&(0,s.jsx)(`button`,{type:`button`,className:`nav-bar__back`,"aria-label":`Back`,onClick:o,children:(0,s.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`24`,height:`24`,"aria-hidden":`true`,children:(0,s.jsx)(`path`,{d:`M15 18l-6-6 6-6`,stroke:`currentColor`,strokeWidth:`2`,fill:`none`,strokeLinecap:`round`,strokeLinejoin:`round`})})}),m&&(0,s.jsx)(`button`,{type:`button`,className:`nav-bar__home`,"aria-label":`Home`,onClick:u,children:(0,s.jsx)(`svg`,{viewBox:`0 0 24 24`,width:`22`,height:`22`,"aria-hidden":`true`,children:(0,s.jsx)(`path`,{d:`M3 12l9-9 9 9M5 10v10h14V10`,stroke:`currentColor`,strokeWidth:`2`,fill:`none`,strokeLinecap:`round`,strokeLinejoin:`round`})})})]}),(0,s.jsxs)(`div`,{className:`nav-bar__title nav-bar__title--${h}`,style:{color:e.textStyle===`white`?`#ffffff`:`#000000`},children:[e.loading&&(0,s.jsx)(`span`,{className:`nav-bar__spinner`,"aria-hidden":`true`}),(0,s.jsx)(`span`,{className:`nav-bar__title-text`,children:e.title})]})]}),(0,s.jsx)(c,{platform:n,statusBarHeight:i,textStyle:e.textStyle})]})}function d(e){return{title:e?.title??``,backgroundColor:e?.backgroundColor??`#000000`,textStyle:e?.textStyle??`white`,style:e?.style??`default`,loading:e?.loading??!1,homeButtonVisible:e?.homeButtonVisible??!1,colorAnimation:e?.colorAnimation}}function f(e){switch(e){case`notch`:return{width:164,height:30,top:0,bottomOnly:!0};case`dynamic-island`:return{width:124,height:36,top:11,bottomOnly:!1};default:return null}}function p({height:e,notchType:t,textStyle:n}){let r=f(t);return(0,s.jsxs)(`div`,{className:`device-statusbar`,style:{height:e,color:n===`black`?`#000000`:`#ffffff`},"aria-hidden":`true`,children:[(0,s.jsx)(`span`,{className:`device-statusbar__time`,children:`9:41`}),r&&(0,s.jsx)(`div`,{className:`device-statusbar__notch`,style:{width:r.width,height:r.height,top:r.top,borderRadius:r.bottomOnly?`0 0 ${Math.round(r.height*.6)}px ${Math.round(r.height*.6)}px`:`${r.height/2}px`}}),(0,s.jsxs)(`div`,{className:`device-statusbar__icons`,children:[(0,s.jsx)(`span`,{className:`device-statusbar__signal`}),(0,s.jsx)(`span`,{className:`device-statusbar__wifi`}),(0,s.jsx)(`span`,{className:`device-statusbar__battery`})]})]})}function m({state:e,currentPath:t,resourceBaseUrl:n,appId:r,onSwitch:i,bottomInset:a=0}){if(!e.config||!e.visible)return null;let{color:o,selectedColor:c,backgroundColor:l,borderStyle:u,list:d}=e.config,f=o||`#999999`,p=c||`#1890ff`;return(0,s.jsx)(`div`,{className:`dmb-tab-bar`,style:{backgroundColor:l||`#ffffff`,borderTopColor:u===`white`?`#ffffff`:`#e0e0e0`,paddingBottom:a},role:`tablist`,"aria-label":`TabBar`,children:d.map((a,o)=>{let c=h(a.pagePath),l=c===t,u=g(l?a.selectedIconPath??a.iconPath:a.iconPath,n,r),d=e.badges[o]??``,m=e.redDots[o]??!1;return(0,s.jsxs)(`button`,{type:`button`,className:`dmb-tab-bar__item${l?` is-selected`:``}`,role:`tab`,"aria-selected":l,onClick:()=>i(c),children:[u&&(0,s.jsx)(`span`,{className:`dmb-tab-bar__icon-slot`,children:(0,s.jsx)(`img`,{className:`dmb-tab-bar__icon`,src:u,alt:``,onError:e=>{e.currentTarget.style.display=`none`}})}),(0,s.jsx)(`span`,{className:`dmb-tab-bar__text`,style:{color:l?p:f},children:a.text||``}),d&&(0,s.jsx)(`span`,{className:`dmb-tab-bar__badge`,children:d}),!d&&m&&(0,s.jsx)(`span`,{className:`dmb-tab-bar__red-dot`})]},`${c}-${o}`)})})}function h(e){return e?e.replace(/^\/+/,``):``}function g(e,t,n){if(!e)return null;let r=e.trim();if(!r)return null;if(/^(?:data:|blob:|https?:|\/\/)/i.test(r))return r;if(!t)return null;let i=r.replace(/^\/+/,``).replace(/^\.\//,``);return i.startsWith(`${n}/`)?_(t,i):_(t,`${n}/main/${i}`)}function _(e,t){return`${e.endsWith(`/`)?e:`${e}/`}${t.replace(/^\/+/,``)}`}function v(e){if(!e)return{config:null,visible:!1,badges:[],redDots:[]};let t=e.list.length;return{config:y(e),visible:!0,badges:Array.from({length:t},()=>``),redDots:Array.from({length:t},()=>!1)}}function y(e){return{...e,list:e.list.map(e=>({...e}))}}function b(e,t){switch(t.kind){case`reset`:return{state:v(t.config),ok:!0,errMsg:`reset:ok`};case`visibility`:return{state:{...e,visible:t.visible},ok:!0,errMsg:t.visible?`showTabBar:ok`:`hideTabBar:ok`};case`apply`:return x(e,t.name,t.params)}}function x(e,t,n){if(!e.config)return{state:e,ok:!1,errMsg:`${t}:fail tabBar not configured`};switch(t){case`setTabBarStyle`:return S(e,n);case`setTabBarItem`:return C(e,n);case`showTabBar`:return{state:{...e,visible:!0},ok:!0,errMsg:`showTabBar:ok`};case`hideTabBar`:return{state:{...e,visible:!1},ok:!0,errMsg:`hideTabBar:ok`};case`setTabBarBadge`:return w(e,n);case`removeTabBarBadge`:return T(e,n);case`showTabBarRedDot`:return E(e,n,!0);case`hideTabBarRedDot`:return E(e,n,!1)}}function S(e,t){if(!e.config)return{state:e,ok:!1,errMsg:`setTabBarStyle:fail tabBar not configured`};let n={...e.config},r=(e,t)=>{let r=O(t);r&&(n[e]=r)};return r(`color`,t.color),r(`selectedColor`,t.selectedColor),r(`backgroundColor`,t.backgroundColor),(t.borderStyle===`black`||t.borderStyle===`white`)&&(n.borderStyle=t.borderStyle),{state:{...e,config:n},ok:!0,errMsg:`setTabBarStyle:ok`}}function C(e,t){let n=D(e,t);if(n.err)return{state:e,ok:!1,errMsg:`setTabBarItem:fail ${n.err}`};if(!e.config)return{state:e,ok:!1,errMsg:`setTabBarItem:fail tabBar not configured`};let r=e.config.list[n.index],i={...r,text:typeof t.text==`string`?t.text:r.text,iconPath:typeof t.iconPath==`string`?t.iconPath:r.iconPath,selectedIconPath:typeof t.selectedIconPath==`string`?t.selectedIconPath:r.selectedIconPath},a=[...e.config.list];return a[n.index]=i,{state:{...e,config:{...e.config,list:a}},ok:!0,errMsg:`setTabBarItem:ok`}}function w(e,t){let n=D(e,t);if(n.err)return{state:e,ok:!1,errMsg:`setTabBarBadge:fail ${n.err}`};let r=[...e.badges];r[n.index]=String(t.text??``);let i=[...e.redDots];return i[n.index]=!1,{state:{...e,badges:r,redDots:i},ok:!0,errMsg:`setTabBarBadge:ok`}}function T(e,t){let n=D(e,t);if(n.err)return{state:e,ok:!1,errMsg:`removeTabBarBadge:fail ${n.err}`};let r=[...e.badges];return r[n.index]=``,{state:{...e,badges:r},ok:!0,errMsg:`removeTabBarBadge:ok`}}function E(e,t,n){let r=D(e,t);if(r.err)return{state:e,ok:!1,errMsg:`${n?`showTabBarRedDot`:`hideTabBarRedDot`}:fail ${r.err}`};let i=[...e.redDots];i[r.index]=n;let a=[...e.badges];return n&&(a[r.index]=``),{state:{...e,redDots:i,badges:a},ok:!0,errMsg:`${n?`showTabBarRedDot`:`hideTabBarRedDot`}:ok`}}function D(e,t){let n=e.config?.list??[],r=t.index,i=Number(r);return n.length?r==null||!Number.isInteger(i)||i<0||i>=n.length?{index:-1,err:`invalid index ${r}`}:{index:i,err:null}:{index:-1,err:`tabBar not configured`}}function O(e){if(typeof e!=`string`)return null;let t=e.trim();return!t||t.length>64?null:/[<>"';{}()\\]/.test(t)?/^(?:rgb|rgba|hsl|hsla)\(\s*[\d.,%\s/-]+\)$/i.test(t)?t:null:t}function k(e){return e?e.replace(/^\/+/,``):``}function A(e){let[t,n]=(typeof e==`string`?e:``).split(`?`),r={};if(n)for(let e of n.split(`&`)){if(!e)continue;let t=e.indexOf(`=`),n=t>=0?e.slice(0,t):e,i=t>=0?e.slice(t+1):``;n&&(r[decodeURIComponent(n)]=decodeURIComponent(i))}return{pagePath:k(t),query:r}}function j(e){let t={};return e.isTab&&(t[e.pagePath]=[e]),{stack:[e],tabStacks:t,currentTabPath:e.isTab?e.pagePath:null}}function M(e){return e.currentTabPath?{...e.tabStacks,[e.currentTabPath]:[...e.stack]}:e.tabStacks}function N(e,t){let n=e.stack[e.stack.length-1],r=[...e.stack,t];return{next:{...e,stack:r,tabStacks:e.currentTabPath?{...e.tabStacks,[e.currentTabPath]:r}:e.tabStacks},effects:n?[{kind:`lifecycle`,bridgeId:n.bridgeId,event:`pageHide`}]:[]}}function P(e,t){if(e.stack.length<=1)return{error:`no page to back`};let n=Math.min(Math.max(1,Number.isFinite(t)?t:1),e.stack.length-1),r=e.stack.slice(e.stack.length-n),i=e.stack.slice(0,e.stack.length-n),a=i[i.length-1],o={...e,stack:i,tabStacks:e.currentTabPath?{...e.tabStacks,[e.currentTabPath]:i}:e.tabStacks,currentTabPath:a.isTab?a.pagePath:e.currentTabPath},s=[];for(let e of r)s.push({kind:`lifecycle`,bridgeId:e.bridgeId,event:`pageUnload`}),s.push({kind:`closePage`,bridgeId:e.bridgeId});return s.push({kind:`lifecycle`,bridgeId:a.bridgeId,event:`pageShow`}),{next:o,effects:s}}function F(e,t){let n=e.stack[e.stack.length-1],r=[...e.stack.slice(0,e.stack.length-1),t],i={...e,stack:r,tabStacks:e.currentTabPath?{...e.tabStacks,[e.currentTabPath]:r}:e.tabStacks},a=[];return n&&(a.push({kind:`lifecycle`,bridgeId:n.bridgeId,event:`pageUnload`}),a.push({kind:`closePage`,bridgeId:n.bridgeId})),{next:i,effects:a}}function I(e,t){let n=new Set;for(let t of e.stack)n.add(t.bridgeId);for(let t of Object.values(e.tabStacks))for(let e of t)n.add(e.bridgeId);n.delete(t.bridgeId);let r=t.isTab?{[t.pagePath]:[t]}:{},i={stack:[t],tabStacks:r,currentTabPath:t.isTab?t.pagePath:null},a=[];for(let e of n)a.push({kind:`lifecycle`,bridgeId:e,event:`pageUnload`}),a.push({kind:`closePage`,bridgeId:e});return{next:i,effects:a}}function L(e,t,n){let r=e.stack[e.stack.length-1],i=M(e),a,o=i[t];if(o&&o.length>0)a=o;else if(n)a=[n];else throw Error(`[page-stack] switchTab to ${t} requires either a cached substack or a freshly-opened entry`);let s={...e,stack:a,tabStacks:{...i,[t]:a},currentTabPath:t},c=a[a.length-1],l=[];return r&&r.bridgeId!==c.bridgeId&&l.push({kind:`lifecycle`,bridgeId:r.bridgeId,event:`pageHide`}),n||l.push({kind:`lifecycle`,bridgeId:c.bridgeId,event:`pageShow`}),{next:s,effects:l}}function R(e){let t=new Map,n=e.stack[e.stack.length-1]?.bridgeId,r=e=>{t.has(e.bridgeId)||t.set(e.bridgeId,{entry:e,visible:e.bridgeId===n})};for(let t of Object.values(e.tabStacks))for(let e of t)r(e);for(let t of e.stack)r(t);return Array.from(t.values())}function z(e,t){let n=e.navigationBarBackgroundColor??`#ffffff`,r=e.navigationBarTextStyle??`black`,i=e.navigationStyle??`default`;return d({title:e.navigationBarTitleText??t,backgroundColor:n,textStyle:r,style:i,homeButtonVisible:e.homeButton===!0})}function B(e,t,n){switch(t){case`setNavigationBarTitle`:return{...e,title:typeof n.title==`string`?n.title:e.title};case`setNavigationBarColor`:return H(e,n);case`showNavigationBarLoading`:return{...e,loading:!0};case`hideNavigationBarLoading`:return{...e,loading:!1};case`hideHomeButton`:return{...e,homeButtonVisible:!1};default:return e}}var V=[`linear`,`easeIn`,`easeOut`,`easeInOut`];function H(e,t){let n=typeof t.frontColor==`string`?t.frontColor.toLowerCase():void 0,r=n===`#ffffff`?`white`:n===`#000000`?`black`:e.textStyle,i=typeof t.backgroundColor==`string`?t.backgroundColor:e.backgroundColor,a=(()=>{let e=t.animation;if(!e||typeof e!=`object`)return;let n=e,r=typeof n.duration==`number`&&Number.isFinite(n.duration)?Math.max(0,n.duration):0,i=typeof n.timingFunc==`string`?n.timingFunc:`linear`;return{durationMs:r,timingFunc:V.includes(i)?i:`linear`}})();return{...e,textStyle:r,backgroundColor:i,colorAnimation:a}}function U(e,t,n){let r=e=>e.bridgeId===t?{...e,navBar:n(e.navBar)}:e,i=e.stack.map(r),a={};for(let[t,n]of Object.entries(e.tabStacks))a[t]=n.map(r);return{...e,stack:i,tabStacks:a}}var W=44,G=24,K=44;function q({miniApp:e,bridgeId:t,platform:i=`ios`}){let[a,c]=(0,r.useState)(()=>e.getInitialDevice());(0,r.useEffect)(()=>e.onSimulatorEvent(n.DEVICE_CHANGE,c),[e]);let l=a?.safeAreaInsets.top??(i===`ios`?W:G),d=a?.safeAreaInsets.bottom??0,f=a?.notchType??`none`,h=(0,r.useMemo)(()=>e.getRenderPreloadUrl(),[e]),g=(0,r.useMemo)(()=>e.getTabBarConfig(),[e]),_=(0,r.useMemo)(()=>({bridgeId:t,pagePath:k(e.pagePath),query:{...e.query},isTab:!!e.getTabBarConfig()?.list.some(t=>k(t.pagePath)===k(e.pagePath)),windowConfig:e.rootWindowConfig??{},navBar:z(e.rootWindowConfig??{},e.appId)}),[e,t]),[{shell:y,tabBar:x},S]=(0,r.useState)(()=>({shell:j(_),tabBar:v(g)})),C=(0,r.useRef)({shell:y,tabBar:x});(0,r.useEffect)(()=>{C.current={shell:y,tabBar:x}},[y,x]);let w=(0,r.useCallback)(t=>{for(let n of t)n.kind===`lifecycle`?e.notifyLifecycle(n.bridgeId,n.event):n.kind===`closePage`&&e.closePage(n.bridgeId)},[e]);(0,r.useEffect)(()=>e.onSimulatorEvent(n.NAV_BAR,e=>{S(t=>({...t,shell:U(t.shell,e.bridgeId,t=>B(t,e.name,e.params))}))}),[e]),(0,r.useEffect)(()=>e.onSimulatorEvent(n.TAB_ACTION,t=>{let n=b(C.current.tabBar,{kind:`apply`,name:t.name,params:t.params});S(e=>({...e,tabBar:n.state})),e.notifyNavCallback({ok:n.ok,errMsg:n.errMsg,callbacks:t.callbacks})}),[e]);let T=(0,r.useCallback)(async t=>{let n=(n,r)=>e.notifyNavCallback({ok:n,errMsg:r,callbacks:t.callbacks});try{switch(t.name){case`navigateTo`:await J(e,C,S,w,t,n);break;case`navigateBack`:Y(C,S,w,t,n);break;case`redirectTo`:await X(e,C,S,w,t,n);break;case`reLaunch`:await Z(e,C,S,w,t,n);break;case`switchTab`:await Q(e,C,S,w,t,n);break}}catch(e){n(!1,`${t.name}:fail ${e instanceof Error?e.message:String(e)}`)}},[e,w]);(0,r.useEffect)(()=>e.onSimulatorEvent(n.NAV_ACTION,e=>{T(e)}),[T,e]),(0,r.useEffect)(()=>e.onSimulatorEvent(n.API_CALL,t=>{o(e,t.name,t.params,n=>{e.notifyApiResponse({requestId:t.requestId,ok:n.ok,result:n.result,errMsg:n.errMsg,keep:n.keep})})}),[e]);let E=(0,r.useCallback)(()=>{if(C.current.shell.stack.length<=1)return;let t=C.current.shell.stack;T({appSessionId:e.appSessionId??``,bridgeId:t[t.length-1].bridgeId,name:`navigateBack`,params:{delta:1},callbacks:{}})},[e,T]),D=(0,r.useCallback)(t=>{let n=C.current.shell;t===n.currentTabPath&&n.stack.length===1||T({appSessionId:e.appSessionId??``,bridgeId:n.stack[n.stack.length-1].bridgeId,name:`switchTab`,params:{url:`/${t}`},callbacks:{}})},[e,T]),O=y.stack[y.stack.length-1],A=R(y);return(0,r.useEffect)(()=>{e.notifyActivePage(O.bridgeId)},[e,O.bridgeId]),(0,r.useEffect)(()=>{e.notifyPageStack(y.stack.map(e=>({pagePath:e.pagePath,query:e.query})))},[e,y.stack]),(0,s.jsx)(`main`,{className:`device-shell-root`,children:(0,s.jsxs)(`section`,{className:`device-shell`,"aria-label":`Dimina simulator`,style:a?{width:a.screenWidth,height:a.screenHeight}:void 0,children:[(0,s.jsx)(p,{height:l,notchType:f,textStyle:O.navBar.textStyle}),(0,s.jsx)(u,{state:O.navBar,stackDepth:y.stack.length,platform:i,statusBarHeight:l,navBarHeight:K,onBack:E}),(0,s.jsx)(`div`,{className:`device-shell__viewport`,children:A.map(({entry:t,visible:n})=>(0,s.jsx)(`webview`,{className:`device-shell__webview`,src:e.createRenderHostUrl(t.bridgeId,t.pagePath,t.isTab),preload:h,allowpopups:`true`,style:{display:n?`flex`:`none`,zIndex:n?100:1}},t.bridgeId))}),O.isTab&&(0,s.jsx)(m,{state:x,currentPath:y.currentTabPath,resourceBaseUrl:e.resourceBaseUrl,appId:e.appId,onSwitch:D,bottomInset:d}),d>0&&(0,s.jsx)(`div`,{className:`device-shell__home-indicator`,style:{height:d},"aria-hidden":`true`})]})})}async function J(e,t,n,r,i,a){let{pagePath:o,query:s}=A(i.params.url);if(!o){a(!1,`navigateTo:fail invalid url`);return}if(e.getTabBarConfig()?.list.some(e=>k(e.pagePath)===o)){a(!1,`navigateTo:fail can not navigateTo a tabbar page`);return}let c=await e.openPage(o,s),l={bridgeId:c.bridgeId,pagePath:c.pagePath,query:s,isTab:c.isTab,windowConfig:c.windowConfig,navBar:z(c.windowConfig,e.appId)},{next:u,effects:d}=N(t.current.shell,l);n(e=>({...e,shell:u})),r(d),a(!0,`navigateTo:ok`)}function Y(e,t,n,r,i){let a=r.params.delta,o=Number.isFinite(Number(a))?Number(a):1,s=P(e.current.shell,o);if(`error`in s){i(!1,`navigateBack:fail ${s.error}`);return}t(e=>({...e,shell:s.next})),n(s.effects),i(!0,`navigateBack:ok`)}async function X(e,t,n,r,i,a){let{pagePath:o,query:s}=A(i.params.url);if(!o){a(!1,`redirectTo:fail invalid url`);return}if(e.getTabBarConfig()?.list.some(e=>k(e.pagePath)===o)){a(!1,`redirectTo:fail can not redirectTo a tabbar page`);return}let c=await e.openPage(o,s),l={bridgeId:c.bridgeId,pagePath:c.pagePath,query:s,isTab:c.isTab,windowConfig:c.windowConfig,navBar:z(c.windowConfig,e.appId)},{next:u,effects:d}=F(t.current.shell,l);n(e=>({...e,shell:u})),r(d),a(!0,`redirectTo:ok`)}async function Z(e,t,n,r,i,a){let{pagePath:o,query:s}=A(i.params.url);if(!o){a(!1,`reLaunch:fail invalid url`);return}let c=await e.openPage(o,s),l={bridgeId:c.bridgeId,pagePath:c.pagePath,query:s,isTab:c.isTab,windowConfig:c.windowConfig,navBar:z(c.windowConfig,e.appId)},{next:u,effects:d}=I(t.current.shell,l);n(e=>({...e,shell:u})),r(d),a(!0,`reLaunch:ok`)}async function Q(e,t,n,r,i,a){let{pagePath:o}=A(i.params.url);if(!o){a(!1,`switchTab:fail invalid url`);return}if(!e.getTabBarConfig()?.list.some(e=>k(e.pagePath)===o)){a(!1,`switchTab:fail not a tabBar page: ${o}`);return}let s=t.current.shell.tabStacks[o],c=null;if(!s||s.length===0){let t=await e.openPage(o,{});c={bridgeId:t.bridgeId,pagePath:t.pagePath,query:{},isTab:!0,windowConfig:t.windowConfig,navBar:z(t.windowConfig,e.appId)}}let{next:l,effects:u}=L(t.current.shell,o,c);n(e=>({...e,shell:l})),r(u),a(!0,`switchTab:ok`)}export{q as DeviceShell};
2
+ //# sourceMappingURL=device-shell-CPCnCp1L.js.map