@bitstillery/mithril 3.4.1 → 3.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/api/router.ts CHANGED
@@ -53,7 +53,7 @@ interface MountRedraw {
53
53
  }
54
54
 
55
55
  interface RouteOptions {
56
- /** When true, forces the route component to remount (e.g. for same-route navigation with different query params) */
56
+ /** When true, bumps remountNonce once so the resolver fragment key changes for that navigation (e.g. Link). */
57
57
  remount?: boolean
58
58
  replace?: boolean
59
59
  state?: any
@@ -80,8 +80,8 @@ export default function router($window: any, mountRedraw: MountRedraw) {
80
80
  let currentPath: string | undefined
81
81
  let lastUpdate: ((comp: any) => void) | null = null
82
82
  let routeSetResolve: (() => void) | null = null
83
- let remountPath: string | null = null
84
- let pendingRemount = false
83
+ /** Incremented only when route.set(..., { remount: true }); fragment key is m-route-${remountNonce}. */
84
+ let remountNonce = 0
85
85
 
86
86
  const RouterRoot: ComponentType = {
87
87
  onremove: function () {
@@ -94,21 +94,15 @@ export default function router($window: any, mountRedraw: MountRedraw) {
94
94
  // if (!hasBeenResolved) return
95
95
 
96
96
  // Pass currentPath in attrs so RouteResolver.render can use it for routePath.
97
- // Use remountPath when set (from route.set with remount: true) to force remount
98
- // for same-route navigation; otherwise attrs.key for route param changes.
97
+ // No vnode key on the route component: same resolved component updates in place when path/query
98
+ // changes; apps sync state via attrs/onupdate. Do not use attrs.key from merged query (?key=...).
99
99
  const routeAttrs = {...attrs, routePath: currentPath || attrs.routePath}
100
- const vnodeKey = remountPath ?? attrs.key
101
- const vnode = Vnode(component, vnodeKey, routeAttrs, null, null, null)
100
+ const vnode = Vnode(component, undefined, routeAttrs, null, null, null)
102
101
  if (currentResolver) {
103
102
  const result = currentResolver.render!(vnode as any)
104
- // When remount requested, wrap in keyed fragment so same-route navigation
105
- // (e.g. Stock <-> TBO) forces full remount. Key must change when path changes.
106
- // Always wrap when we have a path so structure is consistent; key drives remount.
107
- const fragmentKey = remountPath ?? currentPath ?? undefined
108
- if (remountPath && fragmentKey != null) {
109
- return hyperscript.fragment({key: fragmentKey}, result)
110
- }
111
- return result
103
+ // Always wrap in a keyed fragment (stable shape). Key only changes when remountNonce bumps
104
+ // (route.set with remount: true), not on ordinary URL updates.
105
+ return hyperscript.fragment({key: 'm-route-' + remountNonce}, result)
112
106
  }
113
107
  // Wrap in a fragment to preserve existing key semantics
114
108
  return [vnode]
@@ -188,7 +182,10 @@ export default function router($window: any, mountRedraw: MountRedraw) {
188
182
  const path = decodeURIComponentSafe(prefix).slice(route.prefix.length)
189
183
  const data = parsePathname(path)
190
184
 
191
- Object.assign(data.params, $window.history.state || {})
185
+ const histState = $window?.history?.state
186
+ if (histState != null && typeof histState === 'object' && !Array.isArray(histState)) {
187
+ Object.assign(data.params, histState)
188
+ }
192
189
 
193
190
  function reject(e: any) {
194
191
  console.error(e)
@@ -248,10 +245,6 @@ export default function router($window: any, mountRedraw: MountRedraw) {
248
245
  }
249
246
  attrs = data.params
250
247
  currentPath = path
251
- if (pendingRemount) {
252
- remountPath = path
253
- pendingRemount = false
254
- }
255
248
  lastUpdate = null
256
249
  routeSetResolve?.()
257
250
  routeSetResolve = null
@@ -339,10 +332,9 @@ export default function router($window: any, mountRedraw: MountRedraw) {
339
332
  }
340
333
  lastUpdate = null
341
334
 
342
- if (!options?.remount) {
343
- remountPath = null
335
+ if (options?.remount) {
336
+ remountNonce++
344
337
  }
345
- pendingRemount = options?.remount ?? false
346
338
 
347
339
  path = buildPathname(path, data || {})
348
340
  if (!ready || !$window) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitstillery/mithril",
3
- "version": "3.4.1",
3
+ "version": "3.4.2",
4
4
  "description": "Mithril + Signals, Store and SSR",
5
5
  "license": "MIT",
6
6
  "author": "Bitstillery",
@@ -1,5 +1,8 @@
1
1
  import parsePathname from './parse'
2
2
 
3
+ /** Path segments, :params, and regexp escapes (shared by compileTemplate). */
4
+ const TEMPLATE_PATH_TO_REGEXP = /:([^/.-]+)(\.{3}|\.(?!\.)|-)?|[\\^$*+.()|[\]{}]/g
5
+
3
6
  interface CompiledTemplate {
4
7
  (data: {path: string; params: Record<string, any>}): boolean
5
8
  }
@@ -20,7 +23,7 @@ export default function compileTemplate(template: string): CompiledTemplate {
20
23
  // `:lang-:locale` in routes. This is all merged into one pass so I
21
24
  // don't also accidentally escape `-` and make it harder to detect it to
22
25
  // ban it from template parameters.
23
- /:([^/.-]+)(\.{3}|\.(?!\.)|-)?|[\\^$*+.()|[\]{}]/g,
26
+ TEMPLATE_PATH_TO_REGEXP,
24
27
  function (m, key, extra) {
25
28
  if (key == null) return '\\' + m
26
29
  keys.push({k: key, r: extra === '...'})