@mhmo91/schmancy 0.9.24 → 0.9.25

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 (46) hide show
  1. package/custom-elements.json +30 -15
  2. package/dist/agent/schmancy.agent.js +99 -8
  3. package/dist/agent/schmancy.agent.js.map +1 -1
  4. package/dist/agent/schmancy.manifest.json +128 -3
  5. package/dist/area-CFLFXu0Z.cjs.map +1 -1
  6. package/dist/area-CfozaCAZ.js.map +1 -1
  7. package/dist/card-CTUaARLm.js.map +1 -1
  8. package/dist/card-DtN6p1Jq.cjs.map +1 -1
  9. package/dist/chips-B-27tj7O.cjs.map +1 -1
  10. package/dist/chips-DhAWrSgi.js.map +1 -1
  11. package/dist/handover/agent-runtime-followups.md +1 -1
  12. package/dist/handover/agent-runtime-v1.md +3 -3
  13. package/dist/handover/agent-runtime-v2-loopback.md +5 -5
  14. package/dist/lightbox-Cb5-XPWV.js.map +1 -1
  15. package/dist/lightbox-Dk2ICCBB.cjs.map +1 -1
  16. package/dist/radio-group-DYvIgv3P.cjs.map +1 -1
  17. package/dist/radio-group-DchZApJl.js.map +1 -1
  18. package/dist/table-B8H-zioX.js.map +1 -1
  19. package/dist/table-ChHS4xby.cjs.map +1 -1
  20. package/dist/tree.cjs.map +1 -1
  21. package/dist/tree.js.map +1 -1
  22. package/dist/typewriter.cjs.map +1 -1
  23. package/dist/typewriter.js.map +1 -1
  24. package/dist/typography.cjs.map +1 -1
  25. package/dist/typography.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/area/area.component.ts +14 -0
  28. package/src/card/card.ts +1 -0
  29. package/src/chips/assist-chip.ts +11 -2
  30. package/src/chips/suggestion-chip.ts +9 -6
  31. package/src/lightbox/lightbox.ts +11 -0
  32. package/src/radio-group/radio-button.ts +1 -0
  33. package/src/table/table.ts +8 -2
  34. package/src/tree/tree.ts +1 -0
  35. package/src/typewriter/typewriter.ts +12 -0
  36. package/src/typography/typography.ts +1 -0
  37. package/types/src/area/area.component.d.ts +14 -0
  38. package/types/src/card/card.d.ts +1 -0
  39. package/types/src/chips/assist-chip.d.ts +11 -2
  40. package/types/src/chips/suggestion-chip.d.ts +9 -6
  41. package/types/src/lightbox/lightbox.d.ts +11 -0
  42. package/types/src/radio-group/radio-button.d.ts +1 -0
  43. package/types/src/table/table.d.ts +8 -2
  44. package/types/src/tree/tree.d.ts +1 -0
  45. package/types/src/typewriter/typewriter.d.ts +12 -0
  46. package/types/src/typography/typography.d.ts +1 -0
@@ -122,6 +122,13 @@
122
122
  "kind": "class",
123
123
  "name": "SchmancyArea",
124
124
  "tagName": "schmancy-area",
125
+ "description": "Router outlet — renders the active route's component for the named area. Drives the schmancy router via the `area` service.",
126
+ "summary": "Mount once per \"addressable region\" of the app (typically the main content area). Use the imperative `area.push({ area, component, params })` service to navigate. Multiple named areas can coexist on a page (e.g. main content + a sheet).",
127
+ "platformPrimitive": {
128
+ "tag": "div",
129
+ "mode": "-",
130
+ "note": "Routing outlet. Degrades to an empty div if the tag never registers — routing is lost but the page stays accessible."
131
+ },
125
132
  "attributes": [
126
133
  {
127
134
  "name": "name",
@@ -136,6 +143,15 @@
136
143
  "text": "RouteComponent"
137
144
  }
138
145
  }
146
+ ],
147
+ "events": [
148
+ {
149
+ "name": "redirect",
150
+ "description": "When the area resolves a route to a different destination (programmatic redirect). `detail.from` and `detail.to` are the route names."
151
+ }
152
+ ],
153
+ "examples": [
154
+ "<schmancy-area name=\"main\"></schmancy-area>\n<script>\n import { area } from '@mhmo91/schmancy';\n area.push({ area: 'main', component: MyDashboardView, params: { id: 42 } });\n</script>"
139
155
  ]
140
156
  }
141
157
  ]
@@ -1025,6 +1041,12 @@
1025
1041
  "description": "ARIA label for accessibility."
1026
1042
  }
1027
1043
  ],
1044
+ "events": [
1045
+ {
1046
+ "name": "schmancy-click",
1047
+ "description": "When an interactive card is clicked or activated via keyboard. `detail.value` echoes the card's `type`. Only fires when `interactive` is set."
1048
+ }
1049
+ ],
1028
1050
  "examples": [
1029
1051
  "<schmancy-card type=\"elevated\" href=\"/items/42\">\n <schmancy-card-media src=\"/thumb.jpg\" alt=\"Thumbnail\"></schmancy-card-media>\n <schmancy-card-content>\n <h3>Title</h3>\n <p>One-line description of the card's content.</p>\n </schmancy-card-content>\n <schmancy-card-action>\n <schmancy-button variant=\"text\">Open</schmancy-button>\n </schmancy-card-action>\n</schmancy-card>"
1030
1052
  ]
@@ -1403,7 +1425,13 @@
1403
1425
  "kind": "class",
1404
1426
  "name": "SchmancyAssistChip",
1405
1427
  "tagName": "schmancy-assist-chip",
1406
- "description": "Assist chip component - prompts user actions like opening calendar events or sharing content Pure Schmancy implementation with Tailwind CSS and RxJS state management",
1428
+ "description": "Assist chip single-tap trigger for a contextual action (open calendar event, share content, jump to related view). Distinct from filter and input chips: assist chips have no selected state; clicking fires `action`.",
1429
+ "summary": "Use for \"do this thing\" suggestions surfaced in context (next to a date, after a recipient list, near a long description). Pair with schmancy-icon for the leading glyph.",
1430
+ "platformPrimitive": {
1431
+ "tag": "button",
1432
+ "mode": "click",
1433
+ "note": "Material 3 assist-chip semantics. Degrades to a plain `<button>` if the tag never registers."
1434
+ },
1407
1435
  "attributes": [
1408
1436
  {
1409
1437
  "name": "value",
@@ -1453,6 +1481,15 @@
1453
1481
  "default": "true",
1454
1482
  "description": "Elevated style variant - true by default per M3 spec for assist chips"
1455
1483
  }
1484
+ ],
1485
+ "events": [
1486
+ {
1487
+ "name": "action",
1488
+ "description": "When the chip is clicked or activated via keyboard. `detail.value` echoes the chip's `value` attribute."
1489
+ }
1490
+ ],
1491
+ "examples": [
1492
+ "<schmancy-assist-chip @action=${(e) => share(e.detail.value)}>\n <schmancy-icon slot=\"icon\">share</schmancy-icon>\n Share\n</schmancy-assist-chip>"
1456
1493
  ]
1457
1494
  }
1458
1495
  ]
@@ -1601,7 +1638,13 @@
1601
1638
  "kind": "class",
1602
1639
  "name": "SchmancySuggestionChip",
1603
1640
  "tagName": "schmancy-suggestion-chip",
1604
- "description": "Suggestion chip component - provides contextual recommendations to users IMPORTANT: Suggestion chips do NOT have a selected state. They are designed to provide suggestions and recommendations that trigger actions when clicked. Unlike filter chips, they cannot be toggled on/off. Pure Schmancy implementation with Tailwind CSS and RxJS state management",
1641
+ "description": "Suggestion chip single-tap insertion of a recommended value. Distinct from filter chips (no selected state) and assist chips (assist triggers an action; suggestion offers a value the user can pick).",
1642
+ "summary": "Use for \"would you also like to…\" prompts above a search input or below a message thread. Click fires `action` with the chip's `value` so the parent can insert it into a field or trigger a search.",
1643
+ "platformPrimitive": {
1644
+ "tag": "button",
1645
+ "mode": "click",
1646
+ "note": "Material 3 suggestion-chip semantics. Degrades to a plain `<button>` if the tag never registers."
1647
+ },
1605
1648
  "attributes": [
1606
1649
  {
1607
1650
  "name": "value",
@@ -1651,6 +1694,15 @@
1651
1694
  "default": "false",
1652
1695
  "description": "Elevated style variant - flat by default per M3 spec"
1653
1696
  }
1697
+ ],
1698
+ "events": [
1699
+ {
1700
+ "name": "action",
1701
+ "description": "When the chip is clicked or activated via keyboard. `detail.value` echoes the chip's `value` attribute."
1702
+ }
1703
+ ],
1704
+ "examples": [
1705
+ "<schmancy-suggestion-chip value=\"yesterday\" @action=${(e) => setRange(e.detail.value)}>\n Yesterday\n</schmancy-suggestion-chip>"
1654
1706
  ]
1655
1707
  }
1656
1708
  ]
@@ -3334,6 +3386,13 @@
3334
3386
  "kind": "class",
3335
3387
  "name": "SchmancyLightbox",
3336
3388
  "tagName": "schmancy-lightbox",
3389
+ "description": "Image lightbox — thumbnail grid that opens to a full-screen viewer on click, with keyboard navigation between images.",
3390
+ "summary": "Drop-in for galleries / image lists where each thumbnail should expand to fill the viewport. Pass an `images` array of `{ src, alt, caption? }`.",
3391
+ "platformPrimitive": {
3392
+ "tag": "dialog",
3393
+ "mode": "close",
3394
+ "note": "Modal full-screen viewer with keyboard navigation. Degrades to a plain image grid if the tag never registers."
3395
+ },
3337
3396
  "attributes": [
3338
3397
  {
3339
3398
  "name": "src",
@@ -3363,6 +3422,19 @@
3363
3422
  },
3364
3423
  "default": "false"
3365
3424
  }
3425
+ ],
3426
+ "events": [
3427
+ {
3428
+ "name": "change",
3429
+ "description": "When the active image index changes (next/prev). `detail.index` is the new active image's position in the array."
3430
+ },
3431
+ {
3432
+ "name": "close",
3433
+ "description": "When the viewer is dismissed (ESC, backdrop click, close button)."
3434
+ }
3435
+ ],
3436
+ "examples": [
3437
+ "<schmancy-lightbox .images=${[{ src: '/a.jpg', alt: 'A' }, { src: '/b.jpg', alt: 'B' }]}></schmancy-lightbox>"
3366
3438
  ]
3367
3439
  }
3368
3440
  ]
@@ -5207,6 +5279,12 @@
5207
5279
  "default": "''"
5208
5280
  }
5209
5281
  ],
5282
+ "events": [
5283
+ {
5284
+ "name": "radio-button-click",
5285
+ "description": "Internal event consumed by the parent schmancy-radio-group; `detail.value` is the clicked button's value. Listen on schmancy-radio-group for the public `change` event instead of subscribing here."
5286
+ }
5287
+ ],
5210
5288
  "examples": [
5211
5289
  "<schmancy-radio-group name=\"plan\">\n <schmancy-radio-button value=\"free\">Free</schmancy-radio-button>\n <schmancy-radio-button value=\"pro\" checked>Pro</schmancy-radio-button>\n</schmancy-radio-group>"
5212
5290
  ]
@@ -6018,7 +6096,13 @@
6018
6096
  "kind": "class",
6019
6097
  "name": "SchmancyDataTable",
6020
6098
  "tagName": "schmancy-table",
6021
- "description": "SchmancyDataTable is a generic data table component. It supports sorting, filtering, and custom rendering of rows.",
6099
+ "description": "Generic data table typed columns, optional sort, custom renderers per column. Pass `data` (array) and `columns` (TableColumn descriptors).",
6100
+ "summary": "Use for tabular data where each column has a known shape. Pair with `<schmancy-table-row>` for the per-row interaction surface. Sort by setting `sortable: true` on a column descriptor; the table emits `sort-change` so the parent can re-fetch / re-sort in the data layer if needed.",
6101
+ "platformPrimitive": {
6102
+ "tag": "table",
6103
+ "mode": "-",
6104
+ "note": "Renders an accessible table with `<lit-virtualizer>` for large datasets. Degrades to a styled `<table>` if the tag never registers."
6105
+ },
6022
6106
  "attributes": [
6023
6107
  {
6024
6108
  "name": "keyField",
@@ -6041,6 +6125,19 @@
6041
6125
  },
6042
6126
  "default": "false"
6043
6127
  }
6128
+ ],
6129
+ "events": [
6130
+ {
6131
+ "name": "click",
6132
+ "description": "When a data row is activated. `detail.item` is the row's source object, `detail.index` is the position in the data array."
6133
+ },
6134
+ {
6135
+ "name": "sort-change",
6136
+ "description": "When the user toggles a column sort. `detail.column` is the column key, `detail.direction` is `'asc' | 'desc' | null`."
6137
+ }
6138
+ ],
6139
+ "examples": [
6140
+ "<schmancy-table .data=${rows} .columns=${[{ name: 'Name', key: 'name' }, { name: 'Status', key: 'status' }]}></schmancy-table>"
6044
6141
  ]
6045
6142
  }
6046
6143
  ]
@@ -6573,6 +6670,12 @@
6573
6670
  "description": "Whether the tree’s children are visible"
6574
6671
  }
6575
6672
  ],
6673
+ "events": [
6674
+ {
6675
+ "name": "toggle",
6676
+ "description": "When the root toggler or chevron is clicked. Fires before the open state flips; the host's `open` property reflects the new state on the next animation frame."
6677
+ }
6678
+ ],
6576
6679
  "slots": [
6577
6680
  {
6578
6681
  "name": "root",
@@ -6597,6 +6700,13 @@
6597
6700
  "kind": "class",
6598
6701
  "name": "TypewriterElement",
6599
6702
  "tagName": "schmancy-typewriter",
6703
+ "description": "Typewriter effect — animates text typing/deletion with a cursor. Wraps the TypeIt library, lazy-loaded on first render.",
6704
+ "summary": "Drop string content as the default slot or use `<p>` / `<span>` with `cycle=\"A|B|C\"` attribute children for cycling phrases. Set `loop` for infinite cycling, `once` to remember completion across sessions via sessionStorage.",
6705
+ "platformPrimitive": {
6706
+ "tag": "span",
6707
+ "mode": "-",
6708
+ "note": "Animated text container. Degrades to its raw text content if the tag never registers — animation is lost but content stays visible."
6709
+ },
6600
6710
  "attributes": [
6601
6711
  {
6602
6712
  "name": "speed",
@@ -6663,6 +6773,15 @@
6663
6773
  "description": "Default pause duration for cycling (ms)."
6664
6774
  }
6665
6775
  ],
6776
+ "events": [
6777
+ {
6778
+ "name": "typeit-complete",
6779
+ "description": "When the animation finishes typing all content. Fires after the final `afterComplete` callback in the underlying TypeIt instance."
6780
+ }
6781
+ ],
6782
+ "examples": [
6783
+ "<schmancy-typewriter speed=\"35\" cursor-char=\"|\">\n Hello, world.\n</schmancy-typewriter>"
6784
+ ],
6666
6785
  "contexts": [
6667
6786
  {
6668
6787
  "name": "delayContext",
@@ -6821,6 +6940,12 @@
6821
6940
  "description": "Placeholder shown when editable and empty"
6822
6941
  }
6823
6942
  ],
6943
+ "events": [
6944
+ {
6945
+ "name": "change",
6946
+ "description": "When `editable` is true, fires on blur or Enter with `detail.value` set to the new text content. Not fired when `editable` is unset (the default)."
6947
+ }
6948
+ ],
6824
6949
  "slots": [
6825
6950
  {
6826
6951
  "name": "",
@@ -1 +1 @@
1
- {"version":3,"file":"area-CFLFXu0Z.cjs","names":[],"sources":["../src/area/area.service.ts","../src/area/route.component.ts","../src/area/router.types.ts","../src/area/area.component.ts","../src/area/ecrypt.ts","../src/area/utils.ts"],"sourcesContent":["import {\n\tbufferTime,\n\tcatchError,\n\tdistinctUntilChanged,\n\tEMPTY,\n\tfilter,\n\tfromEvent,\n\tmap,\n\tObservable,\n\tof,\n\tReplaySubject,\n\tshareReplay,\n\tskip,\n\tstartWith,\n\tSubject,\n\tSubscription,\n\ttap,\n\ttimeout,\n\tzip\n} from 'rxjs'\nimport { SchmancyTeleportation } from '../teleport'\nimport { ActiveRoute, AreaSubscription, RouteAction } from './router.types'\n\nexport const routerHistory = new Subject<RouteAction>()\n\nexport const FINDING_MORTIES = 'FINDING_MORTIES'\nexport const HERE_RICKY = 'HERE_RICKY'\nexport type HERE_RICKY_EVENT = CustomEvent<{\n\tcomponent: SchmancyTeleportation\n}>\nexport type FINDING_MORTIES_EVENT = CustomEvent<{\n\tcomponent: SchmancyTeleportation\n}>\n\n// WeakMap for better memory management of area subjects\nconst areaSubjectsCache = new WeakMap<AreaService, Map<string, ReplaySubject<ActiveRoute>>>()\n\n// Track navigation source to prevent history conflicts\ntype NavigationSource = 'programmatic' | 'browser' | 'initial'\n\nclass AreaService implements AreaSubscription {\n\tprivate static instance: AreaService\n\tpublic prettyURL = false\n\tpublic mode: 'SILENT' | 'HISTORY' = 'HISTORY'\n\tpublic request = new ReplaySubject<RouteAction>(1)\n\tpublic current = new Map<string, ActiveRoute>()\n\tpublic $current = new ReplaySubject<Map<string, ActiveRoute>>(1)\n\t\n\t// Create a dictionary of ReplaySubjects for area-specific subscriptions\n\tprivate get areaSubjects(): Map<string, ReplaySubject<ActiveRoute>> {\n\t\tlet subjects = areaSubjectsCache.get(this)\n\t\tif (!subjects) {\n\t\t\tsubjects = new Map()\n\t\t\tareaSubjectsCache.set(this, subjects)\n\t\t}\n\t\treturn subjects\n\t}\n\t\n\tpublic enableHistoryMode = true\n\tprivate findingMortiesEvent = new CustomEvent<FINDING_MORTIES_EVENT['detail']>(FINDING_MORTIES)\n\tprivate disposed = false\n\tpublic isProcessingPopstate = false\n\tprivate unloadSubscription?: Subscription\n\n\tconstructor() {\n\t\tthis.$current.next(this.current)\n\t\t\n\t\t// Subscribe to current changes to update area-specific subjects\n\t\tthis.$current.subscribe(currentAreas => {\n\t\t\tif (this.disposed) return\n\t\t\t\n\t\t\t// For each area in the current map\n\t\t\tcurrentAreas.forEach((route, areaName) => {\n\t\t\t\t// Get or create a subject for this area\n\t\t\t\tconst areaSubject = this.getOrCreateAreaSubject(areaName)\n\t\t\t\t// Emit the updated route to area-specific subscribers\n\t\t\t\tareaSubject.next(route)\n\t\t\t})\n\t\t})\n\n\t\t// Initialize from browser state if available\n\t\tthis.initializeFromBrowserState()\n\n\t\t// Setup unload subscription using RxJS\n\t\tif (typeof window !== 'undefined') {\n\t\t\tthis.unloadSubscription = fromEvent(window, 'unload').subscribe(() => {\n\t\t\t\tthis.dispose()\n\t\t\t})\n\t\t}\n\t}\n\n\t/**\n\t * Initialize router state from browser history state\n\t */\n\tprivate initializeFromBrowserState() {\n\t\ttry {\n\t\t\tconst browserState = history.state\n\t\t\tif (browserState && browserState.schmancyAreas) {\n\t\t\t\tObject.entries(browserState.schmancyAreas).forEach(([areaName, route]) => {\n\t\t\t\t\tthis.current.set(areaName, route as ActiveRoute)\n\t\t\t\t})\n\t\t\t\tthis.$current.next(this.current)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('Failed to initialize from browser state:', error)\n\t\t}\n\t}\n\n\t/**\n\t * Get or create a ReplaySubject for a specific area with proper cleanup\n\t */\n\tprivate getOrCreateAreaSubject(areaName: string): ReplaySubject<ActiveRoute> {\n\t\tlet subject = this.areaSubjects.get(areaName)\n\t\t\n\t\tif (!subject || subject.closed) {\n\t\t\tsubject = new ReplaySubject<ActiveRoute>(1)\n\t\t\tthis.areaSubjects.set(areaName, subject)\n\t\t\t\n\t\t\t// If the area already exists in current, emit it immediately\n\t\t\tconst currentRoute = this.current.get(areaName)\n\t\t\tif (currentRoute) {\n\t\t\t\tsubject.next({\n\t\t\t\t\t...currentRoute,\n\t\t\t\t\t// Ensure state, params and props are initialized if undefined\n\t\t\t\t\tstate: currentRoute.state || {},\n\t\t\t\t\tparams: currentRoute.params || {},\n\t\t\t\t\tprops: currentRoute.props || {}\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn subject\n\t}\n\n\t/**\n\t * Subscribe to a specific area with caching\n\t */\n\ton(areaName: string, skipCurrent = false): Observable<ActiveRoute> {\n\t\tif (!areaName) {\n\t\t\tthrow new Error('Area name is required')\n\t\t}\n\n\t\tconst areaSubject = this.getOrCreateAreaSubject(areaName)\n\t\tconst observable = areaSubject.asObservable().pipe(\n\t\t\t// Add distinct to prevent duplicate emissions - includes state, params, and props\n\t\t\tdistinctUntilChanged((a, b) =>\n\t\t\t\ta.component === b.component &&\n\t\t\t\tJSON.stringify(a.state) === JSON.stringify(b.state) &&\n\t\t\t\tJSON.stringify(a.params) === JSON.stringify(b.params) &&\n\t\t\t\tJSON.stringify(a.props) === JSON.stringify(b.props)\n\t\t\t),\n\t\t\t// Share the subscription\n\t\t\tshareReplay(1)\n\t\t)\n\n\t\treturn skipCurrent ? observable.pipe(skip(1)) : observable\n\t}\n\t\n\t/**\n\t * Subscribe to all areas\n\t */\n\tall(skipCurrent = false): Observable<Map<string, ActiveRoute>> {\n\t\tconst observable = this.$current.asObservable().pipe(\n\t\t\tshareReplay(1)\n\t\t)\n\t\treturn skipCurrent ? observable.pipe(skip(1)) : observable\n\t}\n\t\n\t/**\n\t * Get state from an area with type safety\n\t */\n\tgetState<T = unknown>(areaName: string): Observable<T> {\n\t\tif (!areaName) {\n\t\t\tthrow new Error('Area name is required')\n\t\t}\n\t\t\n\t\treturn this.on(areaName).pipe(\n\t\t\tmap(route => route.state),\n\t\t\tfilter((state): state is NonNullable<Record<string, unknown>> => \n\t\t\t\tstate !== undefined && state !== null\n\t\t\t),\n\t\t\tdistinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)),\n\t\t\tmap(state => state as T),\n\t\t\tcatchError(err => {\n\t\t\t\tconsole.error(`Error getting state for area \"${areaName}\":`, err)\n\t\t\t\treturn EMPTY\n\t\t\t})\n\t\t)\n\t}\n\t\n\t/**\n\t * Get params from an area with type safety\n\t * Emits current value immediately on subscription via startWith\n\t * URL query params are MERGED with route params (URL takes precedence for redirects like _rp_oid)\n\t */\n\tparams<T extends Record<string, unknown> = Record<string, unknown>>(areaName: string): Observable<T> {\n\t\tif (!areaName) {\n\t\t\tthrow new Error('Area name is required')\n\t\t}\n\n\t\tconst routeParams = (this.current.get(areaName)?.params ?? {}) as Record<string, unknown>\n\n\t\t// ALWAYS merge URL query params - they take precedence (handles external OAuth-style redirects)\n\t\tlet currentParams = { ...routeParams }\n\t\tif (typeof window !== 'undefined' && window.location.search) {\n\t\t\tconst urlParams = new URLSearchParams(window.location.search)\n\t\t\turlParams.forEach((value, key) => {\n\t\t\t\tcurrentParams[key] = value\n\t\t\t})\n\t\t}\n\n\t\treturn this.on(areaName).pipe(\n\t\t\tmap(route => (route.params ?? {}) as T),\n\t\t\tstartWith(currentParams as T),\n\t\t\tdistinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)),\n\t\t\tcatchError(err => {\n\t\t\t\tconsole.error(`Error getting params for area \"${areaName}\":`, err)\n\t\t\t\treturn EMPTY\n\t\t\t})\n\t\t)\n\t}\n\t\n\t/**\n\t * Get a specific param from an area with null safety\n\t */\n\tparam<T = unknown>(areaName: string, key: string): Observable<T> {\n\t\tif (!areaName || !key) {\n\t\t\tthrow new Error('Area name and key are required')\n\t\t}\n\t\t\n\t\treturn this.params<Record<string, unknown>>(areaName).pipe(\n\t\t\tmap(params => params[key]),\n\t\t\tfilter((value): value is NonNullable<unknown> => value !== undefined),\n\t\t\tdistinctUntilChanged(),\n\t\t\tmap(value => value as T),\n\t\t\tcatchError(err => {\n\t\t\t\tconsole.error(`Error getting param \"${key}\" for area \"${areaName}\":`, err)\n\t\t\t\treturn EMPTY\n\t\t\t})\n\t\t)\n\t}\n\t\n\t/**\n\t * Get props from an area with type safety\n\t */\n\tprops<T extends Record<string, unknown> = Record<string, unknown>>(areaName: string): Observable<T> {\n\t\tif (!areaName) {\n\t\t\tthrow new Error('Area name is required')\n\t\t}\n\t\t\n\t\treturn this.on(areaName).pipe(\n\t\t\tmap(route => route.props),\n\t\t\tfilter((props): props is NonNullable<Record<string, unknown>> => \n\t\t\t\tprops !== undefined && props !== null\n\t\t\t),\n\t\t\tdistinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)),\n\t\t\tmap(props => props as T),\n\t\t\tcatchError(err => {\n\t\t\t\tconsole.error(`Error getting props for area \"${areaName}\":`, err)\n\t\t\t\treturn EMPTY\n\t\t\t})\n\t\t)\n\t}\n\t\n\t/**\n\t * Get a specific prop from an area with null safety\n\t */\n\tprop<T = unknown>(areaName: string, key: string): Observable<T> {\n\t\tif (!areaName || !key) {\n\t\t\tthrow new Error('Area name and key are required')\n\t\t}\n\t\t\n\t\treturn this.props<Record<string, unknown>>(areaName).pipe(\n\t\t\tmap(props => props[key]),\n\t\t\tfilter((value): value is NonNullable<unknown> => value !== undefined),\n\t\t\tdistinctUntilChanged(),\n\t\t\tmap(value => value as T),\n\t\t\tcatchError(err => {\n\t\t\t\tconsole.error(`Error getting prop \"${key}\" for area \"${areaName}\":`, err)\n\t\t\t\treturn EMPTY\n\t\t\t})\n\t\t)\n\t}\n\n\t/**\n\t * Find teleportation components\n\t */\n\tfind() {\n\t\treturn zip([\n\t\t\tfromEvent<HERE_RICKY_EVENT>(window, HERE_RICKY).pipe(\n\t\t\t\tmap(e => e.detail),\n\t\t\t\tbufferTime(0),\n\t\t\t),\n\t\t\tof(1).pipe(tap(() => window.dispatchEvent(this.findingMortiesEvent))),\n\t\t]).pipe(\n\t\t\tmap(([component]) => component),\n\t\t\ttimeout(1),\n\t\t\tcatchError(() => EMPTY)\n\t\t)\n\t}\n\n\t/**\n\t * Push a new route action with validation\n\t */\n\tpush(r: RouteAction) {\n\t\tif (!r.area) {\n\t\t\tthrow new Error('Area is required for route action')\n\t\t}\n\t\t\n\t\t// Prevent processing during popstate handling\n\t\tif (this.isProcessingPopstate) {\n\t\t\treturn\n\t\t}\n\t\t\n\t\t// Ensure state, params and props are initialized\n\t\tconst routeAction: RouteAction = {\n\t\t\t...r,\n\t\t\tstate: r.state || {},\n\t\t\tparams: r.params || {},\n\t\t\tprops: r.props || {},\n\t\t\t_source: 'programmatic' as NavigationSource\n\t\t}\n\t\t\n\t\t// Add to history if enabled\n\t\tif (this.enableHistoryMode) {\n\t\t\trouterHistory.next(routeAction)\n\t\t}\n\t\t\n\t\tthis.request.next(routeAction)\n\t\t// Emit an area-specific event for those who want to listen directly to DOM events\n\t\tthis.dispatchAreaEvent(routeAction.area, routeAction)\n\t}\n\n\t/**\n\t * Internal method to update route from browser navigation\n\t * This should only be called by area components during popstate handling\n\t */\n\t_updateFromBrowser(routeAction: RouteAction) {\n\t\tconst enhancedRoute: RouteAction = {\n\t\t\t...routeAction,\n\t\t\tstate: routeAction.state || {},\n\t\t\tparams: routeAction.params || {},\n\t\t\tprops: routeAction.props || {},\n\t\t\t_source: 'browser' as NavigationSource\n\t\t}\n\t\t\n\t\tthis.isProcessingPopstate = true\n\t\tthis.request.next(enhancedRoute)\n\t\tthis.isProcessingPopstate = false\n\t}\n\n\t/**\n\t * Update browser history state (called by area components)\n\t */\n\t_updateBrowserHistory(areaName: string, route: ActiveRoute, historyStrategy?: string, clearQueryParams?: string[] | boolean | null, customPath?: string) {\n\t\tif (!this.enableHistoryMode) return\n\n\t\ttry {\n\t\t\t// Get current browser state or create new one\n\t\t\tconst currentState = history.state || {}\n\t\t\tconst schmancyAreas = currentState.schmancyAreas || {}\n\n\t\t\t// Update the specific area - only include non-empty state/params/props\n\t\t\tconst areaData: any = {\n\t\t\t\tcomponent: route.component,\n\t\t\t\tarea: route.area\n\t\t\t}\n\n\t\t\t// Only include state if it has content\n\t\t\tif (route.state && Object.keys(route.state).length > 0) {\n\t\t\t\tareaData.state = route.state\n\t\t\t}\n\n\t\t\t// Only include params if it has content\n\t\t\tif (route.params && Object.keys(route.params).length > 0) {\n\t\t\t\tareaData.params = route.params\n\t\t\t}\n\n\t\t\t// Only include props if it has content\n\t\t\tif (route.props && Object.keys(route.props).length > 0) {\n\t\t\t\tareaData.props = route.props\n\t\t\t}\n\n\t\t\tschmancyAreas[areaName] = areaData\n\n\t\t\tconst newState = {\n\t\t\t\t...currentState,\n\t\t\t\tschmancyAreas\n\t\t\t}\n\n\t\t\t// Create clean URL with optional custom path\n\t\t\tconst url = this.createCleanURL(schmancyAreas, clearQueryParams, customPath)\n\n\t\t\t// Update browser history\n\t\t\tif (historyStrategy === 'replace' || historyStrategy === 'pop') {\n\t\t\t\thistory.replaceState(newState, '', url)\n\t\t\t} else if (historyStrategy === 'push' || !historyStrategy) {\n\t\t\t\thistory.pushState(newState, '', url)\n\t\t\t}\n\t\t\t// 'silent' strategy doesn't update browser history\n\n\t\t} catch (error) {\n\t\t\tconsole.error('Failed to update browser history:', error)\n\t\t}\n\t}\n\n\t/**\n\t * Create a clean URL from area states\n\t */\n\tprivate createCleanURL(areas: Record<string, ActiveRoute>, clearQueryParams?: string[] | boolean | null, customPath?: string): string {\n\t\tlet basePath = '/'\n\n\t\t// If custom path is provided, use it directly (completely replaces the path)\n\t\tif (customPath) {\n\t\t\tbasePath = customPath\n\t\t\t// Ensure it starts with /\n\t\t\tif (!basePath.startsWith('/')) {\n\t\t\t\tbasePath = '/' + basePath\n\t\t\t}\n\t\t\t// Ensure base path ends with / for appending encoded state\n\t\t\tif (!basePath.endsWith('/')) {\n\t\t\t\tbasePath += '/'\n\t\t\t}\n\t\t} else {\n\t\t\t// Get the current base path (everything except the last segment which might be encoded state)\n\t\t\tconst currentPath = location.pathname\n\t\t\tconst pathSegments = currentPath.split('/')\n\n\t\t\t// Check if the last segment is encoded state (contains { or %7B)\n\t\t\tconst lastSegment = pathSegments[pathSegments.length - 1]\n\t\t\tif (lastSegment && (lastSegment.includes('{') || lastSegment.includes('%7B'))) {\n\t\t\t\t// Remove the encoded state segment to get the base path\n\t\t\t\tpathSegments.pop()\n\t\t\t\tbasePath = pathSegments.join('/') || '/'\n\t\t\t} else {\n\t\t\t\t// Keep the current path as base path\n\t\t\t\tbasePath = currentPath\n\t\t\t}\n\n\t\t\t// Ensure base path ends properly\n\t\t\tif (basePath !== '/' && !basePath.endsWith('/')) {\n\t\t\t\tbasePath += '/'\n\t\t\t}\n\t\t}\n\n\t\t// Handle query parameters\n\t\tlet queryString = ''\n\n\t\tif (clearQueryParams !== true) {\n\t\t\t// Get current query params\n\t\t\tconst urlParams = new URLSearchParams(location.search)\n\n\t\t\t// Add params from all areas to query string\n\t\t\tObject.values(areas).forEach(route => {\n\t\t\t\tif (route.params && Object.keys(route.params).length > 0) {\n\t\t\t\t\tObject.entries(route.params).forEach(([key, value]) => {\n\t\t\t\t\t\tif (value !== null && value !== undefined) {\n\t\t\t\t\t\t\turlParams.set(key, String(value))\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// Clear specific params if provided\n\t\t\tif (Array.isArray(clearQueryParams)) {\n\t\t\t\tclearQueryParams.forEach(param => urlParams.delete(param))\n\t\t\t}\n\n\t\t\t// Convert back to string\n\t\t\tqueryString = urlParams.toString()\n\t\t\tqueryString = queryString ? `?${queryString}` : ''\n\t\t}\n\t\t// If clearQueryParams === true, queryString remains empty (all params cleared)\n\n\t\tif (this.prettyURL) {\n\t\t\t// Create pretty URLs - customize this based on your routing needs\n\t\t\tconst mainArea = areas.main\n\t\t\tif (mainArea) {\n\t\t\t\tlet path = basePath === '/' ? `/${mainArea.component}` : `${basePath}${mainArea.component}`\n\n\t\t\t\t// Add simple params to URL\n\t\t\t\tconst searchParams = new URLSearchParams(queryString)\n\t\t\t\tif (mainArea.params) {\n\t\t\t\t\tObject.entries(mainArea.params).forEach(([key, value]) => {\n\t\t\t\t\t\tif (typeof value === 'string' || typeof value === 'number') {\n\t\t\t\t\t\t\tsearchParams.set(key, String(value))\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tconst query = searchParams.toString()\n\t\t\t\treturn path + (query ? `?${query}` : '')\n\t\t\t}\n\t\t}\n\n\t\t// Fallback to encoded state in URL (original behavior)\n\t\ttry {\n\t\t\t// Clean up empty objects before encoding\n\t\t\tconst cleanedAreas: Record<string, any> = {}\n\t\t\tObject.entries(areas).forEach(([areaName, route]) => {\n\t\t\t\tconst cleanRoute: any = { component: route.component }\n\n\t\t\t\t// Only include state if it has content\n\t\t\t\tif (route.state && Object.keys(route.state).length > 0) {\n\t\t\t\t\tcleanRoute.state = route.state\n\t\t\t\t}\n\n\t\t\t\t// Only include params if it has content\n\t\t\t\tif (route.params && Object.keys(route.params).length > 0) {\n\t\t\t\t\tcleanRoute.params = route.params\n\t\t\t\t}\n\n\t\t\t\t// Only include props if it has content\n\t\t\t\tif (route.props && Object.keys(route.props).length > 0) {\n\t\t\t\t\tcleanRoute.props = route.props\n\t\t\t\t}\n\n\t\t\t\tcleanedAreas[areaName] = cleanRoute\n\t\t\t})\n\n\t\t\t// If cleanedAreas is empty, preserve the base path\n\t\t\tif (Object.keys(cleanedAreas).length === 0) {\n\t\t\t\tconst cleanBasePath = basePath === '/' ? '' : basePath.replace(/\\/$/, '')\n\t\t\t\treturn `${cleanBasePath}${queryString}`\n\t\t\t}\n\n\t\t\tconst encoded = encodeURIComponent(JSON.stringify(cleanedAreas))\n\t\t\tconst cleanBasePath = basePath === '/' ? '' : basePath.replace(/\\/$/, '')\n\t\t\treturn `${cleanBasePath}/${encoded}${queryString}`\n\t\t} catch (error) {\n\t\t\tconsole.error('Failed to encode URL state:', error)\n\t\t\treturn location.pathname\n\t\t}\n\t}\n\n\t/**\n\t * Restore state from browser history state\n\t */\n\trestoreFromBrowserState(browserState: any): Record<string, ActiveRoute> {\n\t\ttry {\n\t\t\tif (browserState && browserState.schmancyAreas) {\n\t\t\t\treturn browserState.schmancyAreas\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error('Failed to restore from browser state:', error)\n\t\t}\n\t\t\n\t\t// Fallback to URL parsing (original behavior)\n\t\treturn this.parseStateFromURL()\n\t}\n\n\t/**\n\t * Parse state from URL (fallback method)\n\t */\n\tprivate parseStateFromURL(): Record<string, ActiveRoute> {\n\t\tconst pathname = location.pathname.split('/').pop()\n\t\tif (!pathname) return {}\n\t\t\n\t\ttry {\n\t\t\tconst decoded = decodeURIComponent(pathname)\n\t\t\tconst parsed = JSON.parse(decoded)\n\t\t\t\n\t\t\tif (typeof parsed === 'object' && parsed !== null) {\n\t\t\t\treturn parsed\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore parse errors\n\t\t}\n\t\t\n\t\treturn {}\n\t}\n\t\n\t/**\n\t * Dispatch a DOM event for a specific area change\n\t */\n\tprivate dispatchAreaEvent(areaName: string, routeAction: RouteAction) {\n\t\tconst eventName = `schmancy-area-${areaName}-changed`\n\t\tconst event = new CustomEvent(eventName, { \n\t\t\tdetail: { \n\t\t\t\tarea: areaName,\n\t\t\t\tcomponent: routeAction.component,\n\t\t\t\tstate: routeAction.state,\n\t\t\t\tparams: routeAction.params,\n\t\t\t\tprops: routeAction.props,\n\t\t\t\thistoryStrategy: routeAction.historyStrategy\n\t\t\t},\n\t\t\tbubbles: true,\n\t\t\tcomposed: true\n\t\t})\n\t\twindow.dispatchEvent(event)\n\t}\n\n\t/**\n\t * Remove an area from the current state\n\t */\n\tpop(name: string) {\n\t\tif (!name) {\n\t\t\tthrow new Error('Area name is required')\n\t\t}\n\n\t\t// Before removing from current map, emit a clearing signal to the area's subject\n\t\t// This notifies the area component to clear itself\n\t\tconst areaSubject = this.areaSubjects.get(name)\n\t\tif (areaSubject && !areaSubject.closed) {\n\t\t\t// Send a route with null component to signal clearing\n\t\t\tareaSubject.next({\n\t\t\t\tcomponent: null as any,\n\t\t\t\tstate: {},\n\t\t\t\tarea: name,\n\t\t\t\tparams: {},\n\t\t\t\tprops: {}\n\t\t\t})\n\t\t}\n\n\t\t// Send a clearing signal through the request pipeline\n\t\t// This ensures the area component receives the signal to clear\n\t\tthis.request.next({\n\t\t\tarea: name,\n\t\t\tcomponent: null as any,\n\t\t\tstate: {},\n\t\t\tparams: {},\n\t\t\tprops: {},\n\t\t\thistoryStrategy: 'silent' as any,\n\t\t\t_source: 'programmatic' as NavigationSource\n\t\t})\n\n\t\t// Remove from current map\n\t\tthis.current.delete(name)\n\t\tthis.$current.next(this.current)\n\n\t\t// Update browser history\n\t\tif (this.enableHistoryMode) {\n\t\t\ttry {\n\t\t\t\tconst currentState = history.state || {}\n\t\t\t\tconst schmancyAreas = { ...(currentState.schmancyAreas || {}) }\n\t\t\t\tdelete schmancyAreas[name]\n\n\t\t\t\tconst newState = {\n\t\t\t\t\t...currentState,\n\t\t\t\t\tschmancyAreas\n\t\t\t\t}\n\n\t\t\t\tconst url = this.createCleanURL(schmancyAreas)\n\t\t\t\thistory.replaceState(newState, '', url)\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('Failed to update history after pop:', error)\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Clear all areas\n\t */\n\tclear() {\n\t\t// Complete all area subjects\n\t\tthis.areaSubjects.forEach(subject => subject.complete())\n\t\tthis.areaSubjects.clear()\n\n\t\t// Clear current state\n\t\tthis.current.clear()\n\t\tthis.$current.next(this.current)\n\n\t\t// Update URL\n\t\tif (this.enableHistoryMode) {\n\t\t\tconst url = this.createCleanURL({})\n\t\t\thistory.replaceState({ schmancyAreas: {} }, '', url)\n\t\t}\n\t}\n\t\n\t/**\n\t * Dispose of the service and clean up resources\n\t */\n\tdispose() {\n\t\tif (this.disposed) return\n\n\t\tthis.disposed = true\n\n\t\t// Unsubscribe from unload event\n\t\tif (this.unloadSubscription) {\n\t\t\tthis.unloadSubscription.unsubscribe()\n\t\t\tthis.unloadSubscription = undefined\n\t\t}\n\n\t\t// Complete all subjects\n\t\tthis.areaSubjects.forEach(subject => subject.complete())\n\t\tthis.areaSubjects.clear()\n\n\t\tthis.request.complete()\n\t\tthis.$current.complete()\n\t\trouterHistory.complete()\n\n\t\t// Clear references\n\t\tthis.current.clear()\n\t\tareaSubjectsCache.delete(this)\n\t}\n\t\n\t/**\n\t * Get singleton instance\n\t */\n\tstatic getInstance() {\n\t\tif (!AreaService.instance) {\n\t\t\tAreaService.instance = new AreaService()\n\t\t}\n\t\treturn AreaService.instance\n\t}\n\n\t/**\n\t * Get current state from URL (deprecated - use browser state instead)\n\t */\n\tget state(): Record<string, unknown> {\n\t\t// Try browser state first\n\t\ttry {\n\t\t\tconst browserState = history.state\n\t\t\tif (browserState && browserState.schmancyAreas) {\n\t\t\t\treturn browserState.schmancyAreas\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fallback to URL parsing\n\t\t}\n\t\t\n\t\t// Fallback to URL parsing (original behavior)\n\t\treturn this.parseStateFromURL()\n\t}\n\t\n\t/**\n\t * Check if an area exists in current state\n\t */\n\thasArea(areaName: string): boolean {\n\t\treturn this.current.has(areaName)\n\t}\n\t\n\t/**\n\t * Get all active area names\n\t */\n\tgetActiveAreas(): string[] {\n\t\treturn Array.from(this.current.keys())\n\t}\n\t\n\t/**\n\t * Get route for a specific area synchronously\n\t */\n\tgetRoute(areaName: string): ActiveRoute | undefined {\n\t\treturn this.current.get(areaName)\n\t}\n}\n\n/**\n * Area router singleton. Drives named `<schmancy-area>` outlets in the DOM\n * — imperative push / pop, URL-synced, state-restoring. Pair with\n * `lazy(() => import('./view'))` for code-split routes.\n *\n * @service\n * @summary Imperative outlet-based router for `<schmancy-area>` elements.\n * @method push({ area, component, params?, state? }) - Navigate an area to a component.\n * @method pop(areaName) - Pop the top entry off an area's stack.\n * @method current$(areaName) - Observable of the active route state for an area.\n */\nexport const area = AreaService.getInstance()\nexport default area","import { $LitElement } from '@mixins/index';\nimport { css, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { Observable } from 'rxjs';\nimport { LazyComponent } from './lazy';\n\nexport type ObservableGuardResult = Observable<boolean>;\n\n// Component types that can be passed to routes\nexport type RouteComponent =\n | string // Tag name\n | CustomElementConstructor // Constructor function\n | HTMLElement // Existing element\n | LazyComponent<any> \n\nexport interface RouteConfig {\n when: string;\n component: RouteComponent;\n exact?: boolean;\n guard?: ObservableGuardResult;\n}\n\n/**\n * A marker component that holds route configuration.\n * This component doesn't render anything - it's used by schmancy-area\n * to configure routing via slot change detection.\n *\n * @example\n * ```html\n * <schmancy-area>\n * <schmancy-route\n * when=\"users\"\n * .component=${UserComponent}\n * exact\n * ></schmancy-route>\n * </schmancy-area>\n * ```\n */\n@customElement('schmancy-route')\nexport class SchmancyRoute extends $LitElement(css`\n :host {\n display: none;\n }\n`) {\n @property({ type: String })\n when!: string;\n\n @property({ type: Object })\n component!: RouteComponent;\n\n @property({ type: Boolean })\n exact?: boolean = false;\n\n @property({ type: Object })\n guard?:ObservableGuardResult ;\n\n /**\n * Returns the route configuration object\n */\n getConfig(): RouteConfig {\n return {\n when: this.when,\n component: this.component,\n exact: this.exact,\n guard: this.guard\n };\n }\n\n render() {\n // This is a marker component - no visual output\n return html``;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'schmancy-route': SchmancyRoute;\n }\n}","import { LazyComponent } from './lazy'\n\n/**\n * Component type accepted by area router, drawer, and sheet services\n */\nexport type ComponentType = CustomElementConstructor | string | HTMLElement | LazyComponent<any>\n\nexport type RouteAction = {\n\tcomponent: ComponentType\n\tarea: string\n\tstate?: Record<string, unknown>\n\tparams?: Record<string, unknown>\n\tprops?: Record<string, unknown> // Alias for params\n\thistoryStrategy?: THistoryStrategy\n\tclearQueryParams?: string[] | boolean | null\n\tanimationDuration?: number // Animation duration in milliseconds (0 = instant/no animation, default = 150ms)\n\tpath?: string // Override the URL path (e.g., '/order-tracking') - completely replaces the base path\n\t_source?: 'programmatic' | 'browser' | 'initial' // Internal use only\n}\n\nexport type ActiveRoute = {\n\tcomponent: string\n\tarea: string\n\tstate?: Record<string, unknown>\n\tparams?: Record<string, unknown>\n\tprops?: Record<string, unknown>\n}\n\n/**\n * Interface for subscribing to area changes\n */\nexport interface AreaSubscription {\n\t/**\n\t * Subscribe to a specific area\n\t * @param areaName Name of the area to subscribe to\n\t * @param skipCurrent Whether to skip the current value\n\t * @returns Observable of the active route for the specified area\n\t */\n\ton(areaName: string, skipCurrent?: boolean): import('rxjs').Observable<ActiveRoute>\n\t\n\t/**\n\t * Subscribe to all areas\n\t * @param skipCurrent Whether to skip the current value\n\t * @returns Observable of all active routes\n\t */\n\tall(skipCurrent?: boolean): import('rxjs').Observable<Map<string, ActiveRoute>>\n\t\n\t/**\n\t * Get state from an area\n\t * @param areaName Name of the area to subscribe to\n\t * @returns Observable of the area's state\n\t */\n\tgetState<T = unknown>(areaName: string): import('rxjs').Observable<T>\n\t\n\t/**\n\t * Get params from an area\n\t * @param areaName Name of the area to subscribe to\n\t * @returns Observable of the area's params\n\t */\n\tparams<T extends Record<string, unknown> = Record<string, unknown>>(areaName: string): import('rxjs').Observable<T>\n\t\n\t/**\n\t * Get a specific param from an area\n\t * @param areaName Name of the area to subscribe to\n\t * @param key Key of the param to select\n\t * @returns Observable of the param value\n\t */\n\tparam<T = unknown>(areaName: string, key: string): import('rxjs').Observable<T>\n\t\n\t/**\n\t * Get props from an area\n\t * @param areaName Name of the area to subscribe to\n\t * @returns Observable of the area's props\n\t */\n\tprops<T extends Record<string, unknown> = Record<string, unknown>>(areaName: string): import('rxjs').Observable<T>\n\t\n\t/**\n\t * Get a specific prop from an area\n\t * @param areaName Name of the area to subscribe to\n\t * @param key Key of the prop to select\n\t * @returns Observable of the prop value\n\t */\n\tprop<T = unknown>(areaName: string, key: string): import('rxjs').Observable<T>\n}\n\nexport type THistoryStrategy = 'push' | 'replace' | 'pop' | 'silent'\n\nexport enum HISTORY_STRATEGY {\n\tpush = 'push',\n\treplace = 'replace',\n\tpop = 'pop',\n\tsilent = 'silent',\n}\n\n/**\n * Browser history state structure used by Schmancy Area\n */\nexport interface SchmancyHistoryState {\n\tschmancyAreas: Record<string, ActiveRoute>\n\t[key: string]: any // Allow other apps to store additional state\n}","import { $LitElement } from '@mixins/index'\nimport { css, html } from 'lit'\nimport { customElement, property, queryAssignedElements } from 'lit/decorators.js'\nimport {\n\tEMPTY,\n\tcatchError,\n\tdistinctUntilChanged,\n\tfilter,\n\tfromEvent,\n\tmap,\n\tmerge,\n\tof,\n\tshareReplay,\n\tswitchMap,\n\ttake,\n\ttakeUntil,\n\ttap,\n} from 'rxjs'\nimport area from './area.service'\nimport { RouteComponent, SchmancyRoute } from './route.component'\nimport { ActiveRoute, HISTORY_STRATEGY, RouteAction } from './router.types'\n\n@customElement('schmancy-area')\nexport class SchmancyArea extends $LitElement(css`\n\t:host {\n\t\tposition: relative;\n\t\tdisplay: block;\n\t\tinset: 0;\n\t\tcontain: layout style;\n\t}\n`) {\n\t/**\n\t * The name of the router outlet\n\t * @attr\n\t * @type {string}\n\t * @public\n\t * @required\n\t */\n\t@property() name!: string\n\n\t@property() default!: RouteComponent\n\n\t/**\n\t * Query for assigned route elements in the slot\n\t * This will automatically update when slot content changes\n\t */\n\t@queryAssignedElements({ selector: 'schmancy-route', flatten: true })\n\tprivate routes!: SchmancyRoute[]\n\n\tprotected firstUpdated(): void {\n\t\tif (!this.name) throw new Error('Area name is required')\n\n\t\t// Single unified routing pipeline with all logic inline\n\t\tmerge(\n\t\t\t// Source 1: Programmatic navigation from area.request\n\t\t\tarea.request.pipe(\n\t\t\t\tfilter(({ area }) => area === this.name),\n\t\t\t),\n\n\t\t\t// Source 2: Initial page load - parse route from URL\n\t\t\tof(null).pipe(\n\t\t\t\ttake(1),\n\t\t\t\tmap(() => {\n\t\t\t\t\t// Parse route from URL on initial load\n\t\t\t\t\tconst path = location.pathname\n\t\t\t\t\tconst lastSegment = path.split('/').pop() || ''\n\n\t\t\t\t\t// Check for JSON encoded route in URL\n\t\t\t\t\tif (lastSegment && (lastSegment.includes('{') || lastSegment.includes('%7B'))) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst parsed = JSON.parse(decodeURIComponent(lastSegment)) as Record<string, ActiveRoute>\n\t\t\t\t\t\t\tif (parsed[this.name]) {\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\t\t\tcomponent: parsed[this.name].component,\n\t\t\t\t\t\t\t\t\tstate: parsed[this.name].state || {},\n\t\t\t\t\t\t\t\t\tparams: parsed[this.name].params || {},\n\t\t\t\t\t\t\t\t\tprops: parsed[this.name].props || {},\n\t\t\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.replace,\n\t\t\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Segment-based routing\n\t\t\t\t\tconst segments = path.split('/').filter(Boolean)\n\t\t\t\t\tconst matchingSegment = segments.find(seg =>\n\t\t\t\t\t\tthis.routes?.some(r => r.when === seg)\n\t\t\t\t\t)\n\n\t\t\t\t\tif (matchingSegment) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\tcomponent: matchingSegment,\n\t\t\t\t\t\t\tstate: {},\n\t\t\t\t\t\t\tparams: {},\n\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.silent,\n\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use default route if available\n\t\t\t\t\treturn this.default\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\t\tcomponent: this.default,\n\t\t\t\t\t\t\t\tstate: {},\n\t\t\t\t\t\t\t\tparams: {},\n\t\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.silent,\n\t\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t\t: null\n\t\t\t\t})\n\t\t\t),\n\n\t\t\t// Source 3: Browser navigation (back/forward) - parse from browser state\n\t\t\tfromEvent<PopStateEvent>(window, 'popstate').pipe(\n\t\t\t\tmap(() => {\n\t\t\t\t\t// Parse route from browser state during popstate\n\t\t\t\t\t// First check history state\n\t\t\t\t\tif (history.state?.schmancyAreas?.[this.name]) {\n\t\t\t\t\t\tconst stateData = history.state.schmancyAreas[this.name]\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\tcomponent: stateData.component,\n\t\t\t\t\t\t\tstate: stateData.state || {},\n\t\t\t\t\t\t\tparams: stateData.params || {},\n\t\t\t\t\t\t\tprops: stateData.props || {},\n\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.pop,\n\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fallback to URL parsing if no state (e.g., navigating to root)\n\t\t\t\t\tconst path = location.pathname\n\t\t\t\t\tconst lastSegment = path.split('/').pop() || ''\n\n\t\t\t\t\t// Check for JSON encoded route in URL\n\t\t\t\t\tif (lastSegment && (lastSegment.includes('{') || lastSegment.includes('%7B'))) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst parsed = JSON.parse(decodeURIComponent(lastSegment)) as Record<string, ActiveRoute>\n\t\t\t\t\t\t\tif (parsed[this.name]) {\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\t\t\tcomponent: parsed[this.name].component,\n\t\t\t\t\t\t\t\t\tstate: parsed[this.name].state || {},\n\t\t\t\t\t\t\t\t\tparams: parsed[this.name].params || {},\n\t\t\t\t\t\t\t\t\tprops: parsed[this.name].props || {},\n\t\t\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.replace,\n\t\t\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Segment-based routing\n\t\t\t\t\tconst segments = path.split('/').filter(Boolean)\n\t\t\t\t\tconst matchingSegment = segments.find(seg =>\n\t\t\t\t\t\tthis.routes?.some(r => r.when === seg)\n\t\t\t\t\t)\n\n\t\t\t\t\tif (matchingSegment) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\tcomponent: matchingSegment,\n\t\t\t\t\t\t\tstate: {},\n\t\t\t\t\t\t\tparams: {},\n\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.silent,\n\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use default route if available\n\t\t\t\t\treturn this.default\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\t\tcomponent: this.default,\n\t\t\t\t\t\t\t\tstate: {},\n\t\t\t\t\t\t\t\tparams: {},\n\t\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.silent,\n\t\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t\t: null\n\t\t\t\t})\n\t\t\t)\n\t\t).pipe(\n\t\t\t// Filter out null routes\n\t\t\tfilter((route): route is RouteAction => route !== null),\n\n\t\t\t// Performance: mark navigation start\n\t\t\ttap(() => performance.mark(`area-${this.name}-nav-start`)),\n\n\t\t\t// Step 1: Find matching route (resolve lazy only if needed for route matching)\n\t\t\tswitchMap(async action => {\n\t\t\t\tlet component: RouteComponent | null = action.component\n\t\t\t\tlet matchedRoute: SchmancyRoute | undefined\n\n\t\t\t\t// If component is a string, find the matching route\n\t\t\t\tif (typeof component === 'string' && this.routes) {\n\t\t\t\t\tmatchedRoute = this.routes.find(r => r.when === component)\n\t\t\t\t\tif (matchedRoute) {\n\t\t\t\t\t\tcomponent = matchedRoute.component\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If component is a lazy function and we don't have a matched route yet,\n\t\t\t\t// resolve it to find the route by tag name\n\t\t\t\tif (\n\t\t\t\t\t!matchedRoute &&\n\t\t\t\t\ttypeof component === 'function' &&\n\t\t\t\t\t('preload' in component || '_promise' in component || '_module' in component)\n\t\t\t\t) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst module = await (component as unknown as () => Promise<{ default: CustomElementConstructor }>)()\n\t\t\t\t\t\tcomponent = module.default\n\t\t\t\t\t\t// Now find route by tag name\n\t\t\t\t\t\tconst tagName = customElements.getName(component as CustomElementConstructor)\n\t\t\t\t\t\tif (tagName && this.routes) {\n\t\t\t\t\t\t\tmatchedRoute = this.routes.find(r => r.when === tagName)\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tconsole.error(`[${this.name}] Lazy load failed:`, e)\n\t\t\t\t\t\treturn { ...action, component: null, matchedRoute: undefined }\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If component is HTMLElement, find by tag name\n\t\t\t\tif (!matchedRoute && component instanceof HTMLElement && this.routes) {\n\t\t\t\t\tconst tagName = component.tagName.toLowerCase()\n\t\t\t\t\tmatchedRoute = this.routes.find(r => r.when === tagName)\n\t\t\t\t}\n\n\t\t\t\treturn { ...action, component, matchedRoute }\n\t\t\t}),\n\n\t\t\t// Step 2: Check route guards\n\t\t\tswitchMap(route => {\n\t\t\t\tif (!route.matchedRoute?.guard) {\n\t\t\t\t\treturn of(route)\n\t\t\t\t}\n\n\t\t\t\treturn route.matchedRoute.guard.pipe(\n\t\t\t\t\tswitchMap(guardResult => {\n\t\t\t\t\t\tif (guardResult === true) {\n\t\t\t\t\t\t\treturn of(route)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Guard failed, dispatch redirect event\n\t\t\t\t\t\tconst redirectEvent = new CustomEvent('redirect', {\n\t\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\t\tblockedRoute: route.matchedRoute?.when || 'unknown',\n\t\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\t\tparams: route.params || {},\n\t\t\t\t\t\t\t\tstate: route.state || {},\n\t\t\t\t\t\t\t\tredirectTarget: typeof guardResult === 'object' ? guardResult : undefined,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t\t})\n\t\t\t\t\t\troute.matchedRoute.dispatchEvent(redirectEvent)\n\n\t\t\t\t\t\treturn EMPTY\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t}),\n\n\t\t\t// Step 3: Load lazy components (after guard check for performance)\n\t\t\tswitchMap(async route => {\n\t\t\t\tlet component = route.component\n\n\t\t\t\tif (\n\t\t\t\t\ttypeof component === 'function' &&\n\t\t\t\t\t('preload' in component || '_promise' in component || '_module' in component)\n\t\t\t\t) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst module = await (component as unknown as () => Promise<{ default: CustomElementConstructor }>)()\n\t\t\t\t\t\tcomponent = module.default\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tconsole.error(`[${this.name}] Lazy load failed:`, e)\n\t\t\t\t\t\treturn { ...route, component: null }\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn { ...route, component }\n\t\t\t}),\n\n\t\t\t// Step 4: Create unique key for deduplication\n\t\t\tmap(route => {\n\t\t\t\tlet identifier = ''\n\t\t\t\tconst component = route.component\n\n\t\t\t\tif (!component || component === '') {\n\t\t\t\t\tidentifier = 'null'\n\t\t\t\t} else if (typeof component === 'string') {\n\t\t\t\t\tidentifier = component\n\t\t\t\t} else if (component instanceof HTMLElement) {\n\t\t\t\t\tidentifier = component.tagName.toLowerCase()\n\t\t\t\t} else if (typeof component === 'function') {\n\t\t\t\t\tidentifier = component.name || 'CustomElement'\n\t\t\t\t}\n\n\t\t\t\tconst key = `${identifier}${JSON.stringify(route.params)}${JSON.stringify(route.state)}${JSON.stringify(route.props)}`\n\n\t\t\t\treturn { ...route, key, tagName: identifier }\n\t\t\t}),\n\n\t\t\t// Step 5: Deduplicate navigation requests\n\t\t\tdistinctUntilChanged((a, b) => a.key === b.key),\n\n\t\t\t// Step 6: Create DOM element from component\n\t\t\tmap(route => {\n\t\t\t\tlet element: HTMLElement | null = null\n\t\t\t\tconst component = route.component\n\n\t\t\t\tif (!component || component === '') {\n\t\t\t\t\telement = null\n\t\t\t\t} else if (typeof component === 'string') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\telement = document.createElement(component)\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tconsole.error(`[${this.name}] Failed to create element:`, component)\n\t\t\t\t\t}\n\t\t\t\t} else if (component instanceof HTMLElement) {\n\t\t\t\t\telement = component\n\t\t\t\t} else if (typeof component === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\telement = new (component as CustomElementConstructor)()\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tconsole.error(`[${this.name}] Failed to instantiate:`, e)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply properties\n\t\t\t\tif (element) {\n\t\t\t\t\tif (route.params) Object.assign(element, route.params)\n\t\t\t\t\tif (route.props) Object.assign(element, route.props)\n\t\t\t\t\tif (route.state) (element as any).state = route.state\n\t\t\t\t}\n\n\t\t\t\treturn { element, route }\n\t\t\t}),\n\n\t\t\tshareReplay(1),\n\n\t\t\t// Step 7: Swap components in DOM and update history\n\t\t\ttap(({ element, route }) => this.swapComponents(element, route)),\n\n\t\t\t// Performance: measure navigation duration\n\t\t\ttap(() => {\n\t\t\t\tperformance.mark(`area-${this.name}-nav-end`)\n\t\t\t\tperformance.measure(`area-${this.name}-navigation`, `area-${this.name}-nav-start`, `area-${this.name}-nav-end`)\n\t\t\t}),\n\n\t\t\tcatchError(error => {\n\t\t\t\tconsole.error(`[${this.name}] Navigation error:`, error)\n\t\t\t\treturn EMPTY\n\t\t\t}),\n\n\t\t\ttakeUntil(this.disconnecting)\n\t\t)\n\t\t.subscribe()\n\t}\n\n\n\t/**\n\t * Swap components with animation\n\t */\n\tprivate swapComponents(newComponent: HTMLElement | null, routeAction: RouteAction) {\n\t\t// Find current routed component (not route definitions)\n\t\tconst oldComponent = Array.from(this.children).find(\n\t\t\tchild => !(child instanceof SchmancyRoute)\n\t\t) as HTMLElement | undefined\n\n\t\t// Clear if no new component\n\t\tif (!newComponent) {\n\t\t\toldComponent?.remove()\n\t\t\treturn\n\t\t}\n\n\t\t// Get animation duration (0 = instant, default = 150ms)\n\t\tconst duration = routeAction.animationDuration ?? 150\n\n\t\t// Animate transition (or instant swap if duration is 0)\n\t\tif (duration === 0) {\n\t\t\t// Instant swap - no animation\n\t\t\toldComponent?.remove()\n\t\t\tthis.appendChild(newComponent)\n\t\t} else if (oldComponent) {\n\t\t\t// GPU optimization: promote layers before animation\n\t\t\toldComponent.style.willChange = 'opacity'\n\t\t\tnewComponent.style.willChange = 'opacity'\n\t\t\t// Skip paint for outgoing component\n\t\t\toldComponent.style.contentVisibility = 'hidden'\n\n\t\t\t// Animated swap - fade out old, then fade in new\n\t\t\tconst fadeOut = oldComponent.animate([{ opacity: 1 }, { opacity: 0 }], { duration, easing: 'ease-out' })\n\t\t\tfadeOut.onfinish = () => {\n\t\t\t\toldComponent.remove()\n\t\t\t\tthis.appendChild(newComponent)\n\t\t\t\tconst fadeIn = newComponent.animate([{ opacity: 0 }, { opacity: 1 }], { duration, easing: 'ease-in' })\n\t\t\t\tfadeIn.onfinish = () => {\n\t\t\t\t\t// Clean up GPU layer promotion\n\t\t\t\t\tnewComponent.style.willChange = 'auto'\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// No old component - just fade in new\n\t\t\tnewComponent.style.willChange = 'opacity'\n\t\t\tthis.appendChild(newComponent)\n\t\t\tconst fadeInDuration = duration > 100 ? Math.max(100, duration * 0.66) : duration\n\t\t\tconst fadeIn = newComponent.animate([{ opacity: 0 }, { opacity: 1 }], { duration: fadeInDuration, easing: 'ease-in' })\n\t\t\tfadeIn.onfinish = () => {\n\t\t\t\tnewComponent.style.willChange = 'auto'\n\t\t\t}\n\t\t}\n\n\t\t// Update area state\n\t\tconst activeRoute: ActiveRoute = {\n\t\t\tcomponent: newComponent.tagName.toLowerCase(),\n\t\t\tstate: routeAction.state || {},\n\t\t\tarea: this.name,\n\t\t\tparams: routeAction.params || {},\n\t\t\tprops: routeAction.props || {},\n\t\t}\n\n\t\tarea.current.set(this.name, activeRoute)\n\t\tarea.$current.next(area.current)\n\n\t\t// Update browser history\n\t\tif (area.enableHistoryMode) {\n\t\t\tarea._updateBrowserHistory(\n\t\t\t\tthis.name,\n\t\t\t\tactiveRoute,\n\t\t\t\trouteAction.historyStrategy || HISTORY_STRATEGY.push,\n\t\t\t\trouteAction.clearQueryParams,\n\t\t\t\trouteAction.path\n\t\t\t)\n\t\t}\n\t}\n\n\tdisconnectedCallback() {\n\t\tsuper.disconnectedCallback()\n\t\tarea.pop(this.name)\n\t}\n\n\trender() {\n\t\treturn html`<slot></slot>`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-area': SchmancyArea\n\t}\n}\n","export function encodeData(data: string): string {\n\treturn btoa(data)\n}\n\nexport function decodeData(encodedData: string): string {\n\treturn atob(encodedData)\n}\n","import { RouteComponent } from './route.component'\nimport { RouteAction, ActiveRoute } from './router.types'\n\n/**\n * Compare two custom element constructors for equality\n * @param constructor1 First constructor to compare\n * @param constructor2 Second constructor to compare\n * @returns true if constructors are functionally equivalent\n */\nexport function compareCustomElementConstructors(\n\tconstructor1: CustomElementConstructor | Function,\n\tconstructor2: CustomElementConstructor | Function,\n): boolean {\n\t// Quick reference check\n\tif (constructor1 === constructor2) {\n\t\treturn true\n\t}\n\n\t// Check if both are functions\n\tif (typeof constructor1 !== 'function' || typeof constructor2 !== 'function') {\n\t\treturn false\n\t}\n\n\t// Compare by name (handles minification)\n\tif (constructor1.name && constructor2.name && constructor1.name === constructor2.name) {\n\t\treturn true\n\t}\n\n\t// Compare observed attributes if available\n\tconst obs1 = (constructor1 as any).observedAttributes\n\tconst obs2 = (constructor2 as any).observedAttributes\n\n\tif (obs1 && obs2) {\n\t\tif (Array.isArray(obs1) && Array.isArray(obs2)) {\n\t\t\tif (obs1.length !== obs2.length) return false\n\t\t\treturn obs1.every((attr, i) => attr === obs2[i])\n\t\t}\n\t}\n\n\t// Try to compare prototypes\n\ttry {\n\t\tconst proto1 = constructor1.prototype\n\t\tconst proto2 = constructor2.prototype\n\n\t\t// Check if they have the same prototype chain\n\t\tif (Object.getPrototypeOf(proto1) === Object.getPrototypeOf(proto2)) {\n\t\t\t// Check if they have the same property names\n\t\t\tconst keys1 = Object.getOwnPropertyNames(proto1).sort()\n\t\t\tconst keys2 = Object.getOwnPropertyNames(proto2).sort()\n\n\t\t\treturn keys1.length === keys2.length && keys1.every((key, i) => key === keys2[i])\n\t\t}\n\t} catch {\n\t\t// Ignore prototype access errors\n\t}\n\n\treturn false\n}\n\n/**\n * Normalize a component tag name for comparison\n * @param tagName Tag name to normalize\n * @returns Normalized tag name\n */\nexport function normalizeTagName(tagName: string): string {\n\treturn tagName.toLowerCase().replace(/[^a-z0-9]/g, '') // Remove all non-alphanumeric characters\n}\n\n/**\n * Get tag name from a component\n * @param component Component to get tag name from\n * @returns Tag name or null if unable to determine\n */\nexport function getTagName(component: RouteComponent): string | null {\n\tif (typeof component === 'string') {\n\t\treturn component.toLowerCase()\n\t}\n\n\tif (component instanceof HTMLElement) {\n\t\treturn component.tagName.toLowerCase()\n\t}\n\n\tif (typeof component === 'function') {\n\t\t// Try to get custom element name from constructor\n\t\tconst name = component.name\n\t\tif (name) {\n\t\t\t// Convert PascalCase to kebab-case\n\t\t\treturn name\n\t\t\t\t.replace(/([A-Z])/g, '-$1')\n\t\t\t\t.toLowerCase()\n\t\t\t\t.replace(/^-/, '')\n\t\t}\n\t}\n\n\treturn null\n}\n\n/**\n * Deep merge two objects\n * @param target Target object\n * @param source Source object to merge\n * @returns Merged object\n */\nexport function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T {\n\tconst output = { ...target }\n\n\tfor (const key in source) {\n\t\tif (source.hasOwnProperty(key)) {\n\t\t\tconst sourceValue = source[key]\n\t\t\tconst targetValue = output[key]\n\n\t\t\tif (isObject(sourceValue) && isObject(targetValue)) {\n\t\t\t\toutput[key] = deepMerge(targetValue, sourceValue)\n\t\t\t} else {\n\t\t\t\toutput[key] = sourceValue as T[Extract<keyof T, string>]\n\t\t\t}\n\t\t}\n\t}\n\n\treturn output\n}\n\n/**\n * Check if value is a plain object\n * @param obj Value to check\n * @returns true if value is a plain object\n */\nexport function isObject(obj: any): obj is Record<string, any> {\n\treturn (\n\t\tobj !== null &&\n\t\ttypeof obj === 'object' &&\n\t\tobj.constructor === Object &&\n\t\tObject.prototype.toString.call(obj) === '[object Object]'\n\t)\n}\n\n/**\n * Debounce a function\n * @param func Function to debounce\n * @param wait Wait time in milliseconds\n * @returns Debounced function\n */\nexport function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void {\n\tlet timeout: ReturnType<typeof setTimeout> | null = null\n\n\treturn function (this: any, ...args: Parameters<T>) {\n\t\tconst context = this\n\n\t\tif (timeout !== null) {\n\t\t\tclearTimeout(timeout)\n\t\t}\n\n\t\ttimeout = setTimeout(() => {\n\t\t\tfunc.apply(context, args)\n\t\t\ttimeout = null\n\t\t}, wait)\n\t}\n}\n\n/**\n * Create a URL-safe string from route state\n * @param state Route state object\n * @returns URL-safe encoded string\n */\nexport function encodeRouteState(state: Record<string, unknown>): string {\n\ttry {\n\t\tconst json = JSON.stringify(state)\n\t\treturn encodeURIComponent(json)\n\t} catch (error) {\n\t\tconsole.error('Failed to encode route state:', error)\n\t\treturn ''\n\t}\n}\n\n/**\n * Decode a URL-safe string to route state\n * @param encoded Encoded string\n * @returns Decoded route state or empty object\n */\nexport function decodeRouteState(encoded: string): Record<string, unknown> {\n\tif (!encoded) return {}\n\n\ttry {\n\t\tconst decoded = decodeURIComponent(encoded)\n\t\tconst parsed = JSON.parse(decoded)\n\n\t\tif (isObject(parsed)) {\n\t\t\treturn parsed\n\t\t}\n\t} catch (error) {\n\t\tconsole.error('Failed to decode route state:', error)\n\t}\n\n\treturn {}\n}\n\n/**\n * Compare two route actions for equality\n * @param a First route action\n * @param b Second route action\n * @returns true if route actions are equal\n */\nexport function compareRouteActions(a: RouteAction, b: RouteAction): boolean {\n\t// Compare areas\n\tif (a.area !== b.area) return false\n\n\t// Compare components\n\tif (typeof a.component !== typeof b.component) return false\n\n\tif (typeof a.component === 'string' && typeof b.component === 'string') {\n\t\tif (normalizeTagName(a.component) !== normalizeTagName(b.component)) {\n\t\t\treturn false\n\t\t}\n\t} else if (typeof a.component === 'function' && typeof b.component === 'function') {\n\t\tif (!compareCustomElementConstructors(a.component, b.component)) {\n\t\t\treturn false\n\t\t}\n\t} else if (a.component !== b.component) {\n\t\treturn false\n\t}\n\n\t// Compare state\n\tif (JSON.stringify(a.state || {}) !== JSON.stringify(b.state || {})) {\n\t\treturn false\n\t}\n\n\t// Compare params\n\tif (JSON.stringify(a.params || {}) !== JSON.stringify(b.params || {})) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n/**\n * Compare two active routes for equality\n * @param a First active route\n * @param b Second active route\n * @returns true if active routes are equal\n */\nexport function compareActiveRoutes(a: ActiveRoute, b: ActiveRoute): boolean {\n\treturn (\n\t\ta.area === b.area &&\n\t\ta.component === b.component &&\n\t\tJSON.stringify(a.state || {}) === JSON.stringify(b.state || {}) &&\n\t\tJSON.stringify(a.params || {}) === JSON.stringify(b.params || {})\n\t)\n}\n\n/**\n * Create a cache key from a route action\n * @param route Route action\n * @returns Cache key string\n */\nexport function createRouteCacheKey(route: RouteAction): string {\n\tconst tagName = getTagName(route.component) || 'unknown'\n\tconst stateHash = simpleHash(JSON.stringify(route.state || {}))\n\tconst paramsHash = simpleHash(JSON.stringify(route.params || {}))\n\n\treturn `${route.area}:${tagName}:${stateHash}:${paramsHash}`\n}\n\n/**\n * Simple hash function for creating cache keys\n * @param str String to hash\n * @returns Hash string\n */\nfunction simpleHash(str: string): string {\n\tlet hash = 0\n\n\tfor (let i = 0; i < str.length; i++) {\n\t\tconst char = str.charCodeAt(i)\n\t\thash = (hash << 5) - hash + char\n\t\thash = hash & hash // Convert to 32-bit integer\n\t}\n\n\treturn Math.abs(hash).toString(36)\n}\n\n/**\n * Sanitize route state to remove sensitive data\n * @param state Route state\n * @param keysToRemove Keys to remove from state\n * @returns Sanitized state\n */\nexport function sanitizeRouteState(\n\tstate: Record<string, unknown>,\n\tkeysToRemove: string[] = ['password', 'token', 'secret', 'apiKey'],\n): Record<string, unknown> {\n\tconst sanitized: Record<string, unknown> = {}\n\n\tfor (const key in state) {\n\t\tif (state.hasOwnProperty(key) && !keysToRemove.includes(key)) {\n\t\t\tconst value = state[key]\n\n\t\t\tif (isObject(value)) {\n\t\t\t\tsanitized[key] = sanitizeRouteState(value, keysToRemove)\n\t\t\t} else if (Array.isArray(value)) {\n\t\t\t\tsanitized[key] = value.map(item => (isObject(item) ? sanitizeRouteState(item, keysToRemove) : item))\n\t\t\t} else {\n\t\t\t\tsanitized[key] = value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn sanitized\n}\n\n/**\n * Extract query parameters from URL\n * @param url URL string or URLSearchParams\n * @returns Object with query parameters\n */\nexport function extractQueryParams(url?: string | URLSearchParams): Record<string, string> {\n\tconst params: Record<string, string> = {}\n\n\tlet searchParams: URLSearchParams\n\n\tif (url instanceof URLSearchParams) {\n\t\tsearchParams = url\n\t} else if (typeof url === 'string') {\n\t\tconst urlObj = new URL(url, window.location.origin)\n\t\tsearchParams = urlObj.searchParams\n\t} else {\n\t\tsearchParams = new URLSearchParams(window.location.search)\n\t}\n\n\tsearchParams.forEach((value, key) => {\n\t\tparams[key] = value\n\t})\n\n\treturn params\n}\n\n/**\n * Build query string from parameters object\n * @param params Parameters object\n * @returns Query string with leading '?'\n */\nexport function buildQueryString(params: Record<string, string | number | boolean>): string {\n\tconst searchParams = new URLSearchParams()\n\n\tfor (const key in params) {\n\t\tif (params.hasOwnProperty(key)) {\n\t\t\tconst value = params[key]\n\t\t\tif (value !== undefined && value !== null && value !== '') {\n\t\t\t\tsearchParams.set(key, String(value))\n\t\t\t}\n\t\t}\n\t}\n\n\tconst queryString = searchParams.toString()\n\treturn queryString ? `?${queryString}` : ''\n}\n"],"mappings":"sNAuBA,IAAa,EAAgB,IAAI,EAAA,QAEpB,EAAkB,kBAClB,EAAa,aASpB,EAAoB,IAAI,QAktBjB,EA7sBb,MAAM,CAAA,CASL,IAAA,cAAY,CACX,IAAI,EAAW,EAAkB,IAAI,KAAA,CAKrC,OAJK,IACJ,EAAW,IAAI,IACf,EAAkB,IAAI,KAAM,EAAA,EAEtB,EASR,aAAA,CAAA,KAAA,UAAA,CAtBmB,EAAA,KAAA,KACiB,UAAA,KAAA,QACnB,IAAI,EAAA,cAA2B,EAAA,CAAA,KAAA,QAC/B,IAAI,IAAA,KAAA,SACH,IAAI,EAAA,cAAwC,EAAA,CAAA,KAAA,kBAAA,CAYnC,EAAA,KAAA,oBACG,IAAI,YAA6C,EAAA,CAAA,KAAA,SAAA,CAC5D,EAAA,KAAA,qBAAA,CACW,EAI7B,KAAK,SAAS,KAAK,KAAK,QAAA,CAGxB,KAAK,SAAS,UAAU,GAAA,CACnB,KAAK,UAGT,EAAa,SAAS,EAAO,IAAA,CAER,KAAK,uBAAuB,EAAA,CAEpC,KAAK,EAAA,EAAA,EAAA,CAKnB,KAAK,4BAAA,CAGiB,OAAX,OAAW,MACrB,KAAK,oBAAA,EAAA,EAAA,WAA+B,OAAQ,SAAA,CAAU,cAAA,CACrD,KAAK,SAAA,EAAA,EAQR,4BAAA,CACC,GAAA,CACC,IAAM,EAAe,QAAQ,MACzB,GAAgB,EAAa,gBAChC,OAAO,QAAQ,EAAa,cAAA,CAAe,SAAA,CAAU,EAAU,KAAA,CAC9D,KAAK,QAAQ,IAAI,EAAU,EAAA,EAAA,CAE5B,KAAK,SAAS,KAAK,KAAK,QAAA,OAEjB,GAQV,uBAA+B,EAAA,CAC9B,IAAI,EAAU,KAAK,aAAa,IAAI,EAAA,CAEpC,GAAA,CAAK,GAAW,EAAQ,OAAQ,CAC/B,EAAU,IAAI,EAAA,cAA2B,EAAA,CACzC,KAAK,aAAa,IAAI,EAAU,EAAA,CAGhC,IAAM,EAAe,KAAK,QAAQ,IAAI,EAAA,CAClC,GACH,EAAQ,KAAK,CAAA,GACT,EAEH,MAAO,EAAa,OAAS,EAAA,CAC7B,OAAQ,EAAa,QAAU,EAAA,CAC/B,MAAO,EAAa,OAAS,EAAA,CAAA,CAAA,CAKhC,OAAO,EAMR,GAAG,EAAkB,EAAA,CAAc,EAAA,CAClC,GAAA,CAAK,EACJ,MAAU,MAAM,wBAAA,CAIjB,IAAM,EADc,KAAK,uBAAuB,EAAA,CACjB,cAAA,CAAe,MAAA,EAAA,EAAA,uBAEvB,EAAG,IACxB,EAAE,YAAc,EAAE,WAClB,KAAK,UAAU,EAAE,MAAA,GAAW,KAAK,UAAU,EAAE,MAAA,EAC7C,KAAK,UAAU,EAAE,OAAA,GAAY,KAAK,UAAU,EAAE,OAAA,EAC9C,KAAK,UAAU,EAAE,MAAA,GAAW,KAAK,UAAU,EAAE,MAAA,CAAA,EAC7C,EAAA,EAAA,aAEW,EAAA,CAAA,CAGb,OAAO,EAAc,EAAW,MAAA,EAAA,EAAA,MAAU,EAAA,CAAA,CAAM,EAMjD,IAAI,EAAA,CAAc,EAAA,CACjB,IAAM,EAAa,KAAK,SAAS,cAAA,CAAe,MAAA,EAAA,EAAA,aACnC,EAAA,CAAA,CAEb,OAAO,EAAc,EAAW,MAAA,EAAA,EAAA,MAAU,EAAA,CAAA,CAAM,EAMjD,SAAsB,EAAA,CACrB,GAAA,CAAK,EACJ,MAAU,MAAM,wBAAA,CAGjB,OAAO,KAAK,GAAG,EAAA,CAAU,MAAA,EAAA,EAAA,KACpB,GAAS,EAAM,MAAA,EAAM,EAAA,EAAA,QACjB,GACP,GAAA,KAAA,EACA,EAAA,EAAA,uBACqB,EAAG,IAAM,KAAK,UAAU,EAAA,GAAO,KAAK,UAAU,EAAA,CAAA,EAAG,EAAA,EAAA,KACnE,GAAS,EAAA,EAAW,EAAA,EAAA,YACb,GAEH,EAAA,MAAA,CAAA,CAUV,OAAoE,EAAA,CACnE,GAAA,CAAK,EACJ,MAAU,MAAM,wBAAA,CAMjB,IAAI,EAAgB,CAAA,GAHC,KAAK,QAAQ,IAAI,EAAA,EAAW,QAAU,EAAA,CAAA,CAW3D,OAPsB,OAAX,OAAW,KAAe,OAAO,SAAS,QAEpD,IADsB,gBAAgB,OAAO,SAAS,OAAA,CAC5C,SAAS,EAAO,IAAA,CACzB,EAAc,GAAO,GAAA,CAIhB,KAAK,GAAG,EAAA,CAAU,MAAA,EAAA,EAAA,KACpB,GAAU,EAAM,QAAU,EAAA,CAAA,EAAS,EAAA,EAAA,WAC7B,EAAA,EAAmB,EAAA,EAAA,uBACP,EAAG,IAAM,KAAK,UAAU,EAAA,GAAO,KAAK,UAAU,EAAA,CAAA,EAAG,EAAA,EAAA,YAC5D,GAEH,EAAA,MAAA,CAAA,CAQV,MAAmB,EAAkB,EAAA,CACpC,GAAA,CAAK,GAAA,CAAa,EACjB,MAAU,MAAM,iCAAA,CAGjB,OAAO,KAAK,OAAgC,EAAA,CAAU,MAAA,EAAA,EAAA,KACjD,GAAU,EAAO,GAAA,EAAK,EAAA,EAAA,QAClB,GAAyC,IAAzC,IAAmD,GAAV,EAAoB,EAAA,EAAA,uBAAA,EAC/C,EAAA,EAAA,KAClB,GAAS,EAAA,EAAW,EAAA,EAAA,YACb,GAEH,EAAA,MAAA,CAAA,CAQV,MAAmE,EAAA,CAClE,GAAA,CAAK,EACJ,MAAU,MAAM,wBAAA,CAGjB,OAAO,KAAK,GAAG,EAAA,CAAU,MAAA,EAAA,EAAA,KACpB,GAAS,EAAM,MAAA,EAAM,EAAA,EAAA,QACjB,GACP,GAAA,KAAA,EACA,EAAA,EAAA,uBACqB,EAAG,IAAM,KAAK,UAAU,EAAA,GAAO,KAAK,UAAU,EAAA,CAAA,EAAG,EAAA,EAAA,KACnE,GAAS,EAAA,EAAW,EAAA,EAAA,YACb,GAEH,EAAA,MAAA,CAAA,CAQV,KAAkB,EAAkB,EAAA,CACnC,GAAA,CAAK,GAAA,CAAa,EACjB,MAAU,MAAM,iCAAA,CAGjB,OAAO,KAAK,MAA+B,EAAA,CAAU,MAAA,EAAA,EAAA,KAChD,GAAS,EAAM,GAAA,EAAK,EAAA,EAAA,QAChB,GAAyC,IAAzC,IAAmD,GAAV,EAAoB,EAAA,EAAA,uBAAA,EAC/C,EAAA,EAAA,KAClB,GAAS,EAAA,EAAW,EAAA,EAAA,YACb,GAEH,EAAA,MAAA,CAAA,CAQV,MAAA,CACC,OAAA,EAAA,EAAA,KAAW,EAAA,EAAA,EAAA,WACkB,OAAQ,EAAA,CAAY,MAAA,EAAA,EAAA,KAC3C,GAAK,EAAE,OAAA,EAAO,EAAA,EAAA,YACP,EAAA,CAAA,EACX,EAAA,EAAA,IACE,EAAA,CAAG,MAAA,EAAA,EAAA,SAAe,OAAO,cAAc,KAAK,oBAAA,CAAA,CAAA,CAAA,CAAA,CAC7C,MAAA,EAAA,EAAA,MAAA,CACI,KAAe,EAAA,EAAU,EAAA,EAAA,SACvB,EAAA,EAAE,EAAA,EAAA,gBACO,EAAA,MAAA,CAAA,CAOnB,KAAK,EAAA,CACJ,GAAA,CAAK,EAAE,KACN,MAAU,MAAM,oCAAA,CAIjB,GAAI,KAAK,qBACR,OAID,IAAM,EAA2B,CAAA,GAC7B,EACH,MAAO,EAAE,OAAS,EAAA,CAClB,OAAQ,EAAE,QAAU,EAAA,CACpB,MAAO,EAAE,OAAS,EAAA,CAClB,QAAS,eAAA,CAIN,KAAK,mBACR,EAAc,KAAK,EAAA,CAGpB,KAAK,QAAQ,KAAK,EAAA,CAElB,KAAK,kBAAkB,EAAY,KAAM,EAAA,CAO1C,mBAAmB,EAAA,CAClB,IAAM,EAA6B,CAAA,GAC/B,EACH,MAAO,EAAY,OAAS,EAAA,CAC5B,OAAQ,EAAY,QAAU,EAAA,CAC9B,MAAO,EAAY,OAAS,EAAA,CAC5B,QAAS,UAAA,CAGV,KAAK,qBAAA,CAAuB,EAC5B,KAAK,QAAQ,KAAK,EAAA,CAClB,KAAK,qBAAA,CAAuB,EAM7B,sBAAsB,EAAkB,EAAoB,EAA0B,EAA8C,EAAA,CACnI,GAAK,KAAK,kBAEV,GAAA,CAEC,IAAM,EAAe,QAAQ,OAAS,EAAA,CAChC,EAAgB,EAAa,eAAiB,EAAA,CAG9C,EAAgB,CACrB,UAAW,EAAM,UACjB,KAAM,EAAM,KAAA,CAIT,EAAM,OAAS,OAAO,KAAK,EAAM,MAAA,CAAO,OAAS,IACpD,EAAS,MAAQ,EAAM,OAIpB,EAAM,QAAU,OAAO,KAAK,EAAM,OAAA,CAAQ,OAAS,IACtD,EAAS,OAAS,EAAM,QAIrB,EAAM,OAAS,OAAO,KAAK,EAAM,MAAA,CAAO,OAAS,IACpD,EAAS,MAAQ,EAAM,OAGxB,EAAc,GAAY,EAE1B,IAAM,EAAW,CAAA,GACb,EACH,cAAA,EAAA,CAIK,EAAM,KAAK,eAAe,EAAe,EAAkB,EAAA,CAG7D,IAAoB,WAAa,IAAoB,MACxD,QAAQ,aAAa,EAAU,GAAI,EAAA,CACzB,IAAoB,QAAW,GACzC,QAAQ,UAAU,EAAU,GAAI,EAAA,MAIzB,GAQV,eAAuB,EAAoC,EAA8C,EAAA,CACxG,IAAI,EAAW,IAGf,GAAI,EACH,EAAW,EAEN,EAAS,WAAW,IAAA,GACxB,EAAW,IAAM,GAGb,EAAS,SAAS,IAAA,GACtB,GAAY,SAEP,CAEN,IAAM,EAAc,SAAS,SACvB,EAAe,EAAY,MAAM,IAAA,CAGjC,EAAc,EAAa,EAAa,OAAS,GACnD,IAAgB,EAAY,SAAS,IAAA,EAAQ,EAAY,SAAS,MAAA,GAErE,EAAa,KAAA,CACb,EAAW,EAAa,KAAK,IAAA,EAAQ,KAGrC,EAAW,EAIR,IAAa,KAAQ,EAAS,SAAS,IAAA,GAC1C,GAAY,KAKd,IAAI,EAAc,GAElB,GAAA,CAAyB,IAArB,EAA2B,CAE9B,IAAM,EAAY,IAAI,gBAAgB,SAAS,OAAA,CAG/C,OAAO,OAAO,EAAA,CAAO,QAAQ,GAAA,CACxB,EAAM,QAAU,OAAO,KAAK,EAAM,OAAA,CAAQ,OAAS,GACtD,OAAO,QAAQ,EAAM,OAAA,CAAQ,SAAA,CAAU,EAAK,KAAA,CACvC,GAAA,MACH,EAAU,IAAI,EAAK,OAAO,EAAA,CAAA,EAAA,EAAA,CAO1B,MAAM,QAAQ,EAAA,EACjB,EAAiB,QAAQ,GAAS,EAAU,OAAO,EAAA,CAAA,CAIpD,EAAc,EAAU,UAAA,CACxB,EAAc,EAAc,IAAI,IAAgB,GAIjD,GAAI,KAAK,UAAW,CAEnB,IAAM,EAAW,EAAM,KACvB,GAAI,EAAU,CACb,IAAI,EAAO,IAAa,IAAM,IAAI,EAAS,YAAc,GAAG,IAAW,EAAS,YAG1E,EAAe,IAAI,gBAAgB,EAAA,CACrC,EAAS,QACZ,OAAO,QAAQ,EAAS,OAAA,CAAQ,SAAA,CAAU,EAAK,KAAA,CACzB,OAAV,GAAU,UAA6B,OAAV,GAAU,UACjD,EAAa,IAAI,EAAK,OAAO,EAAA,CAAA,EAAA,CAKhC,IAAM,EAAQ,EAAa,UAAA,CAC3B,OAAO,GAAQ,EAAQ,IAAI,IAAU,KAKvC,GAAA,CAEC,IAAM,EAAoC,EAAA,CAuB1C,GAtBA,OAAO,QAAQ,EAAA,CAAO,SAAA,CAAU,EAAU,KAAA,CACzC,IAAM,EAAkB,CAAE,UAAW,EAAM,UAAA,CAGvC,EAAM,OAAS,OAAO,KAAK,EAAM,MAAA,CAAO,OAAS,IACpD,EAAW,MAAQ,EAAM,OAItB,EAAM,QAAU,OAAO,KAAK,EAAM,OAAA,CAAQ,OAAS,IACtD,EAAW,OAAS,EAAM,QAIvB,EAAM,OAAS,OAAO,KAAK,EAAM,MAAA,CAAO,OAAS,IACpD,EAAW,MAAQ,EAAM,OAG1B,EAAa,GAAY,GAAA,CAItB,OAAO,KAAK,EAAA,CAAc,SAAW,EAExC,MAAO,GADe,IAAa,IAAM,GAAK,EAAS,QAAQ,MAAO,GAAA,GAC5C,IAG3B,IAAM,EAAU,mBAAmB,KAAK,UAAU,EAAA,CAAA,CAElD,MAAO,GADe,IAAa,IAAM,GAAK,EAAS,QAAQ,MAAO,GAAA,CAAA,GAC3C,IAAU,SAC7B,CAER,OAAO,SAAS,UAOlB,wBAAwB,EAAA,CACvB,GAAA,CACC,GAAI,GAAgB,EAAa,cAChC,OAAO,EAAa,mBAEb,EAKT,OAAO,KAAK,mBAAA,CAMb,mBAAA,CACC,IAAM,EAAW,SAAS,SAAS,MAAM,IAAA,CAAK,KAAA,CAC9C,GAAA,CAAK,EAAU,MAAO,EAAA,CAEtB,GAAA,CAEC,IAAM,EAAS,KAAK,MADJ,mBAAmB,EAAA,CAAA,CAGnC,GAAsB,OAAX,GAAW,UAAY,EACjC,OAAO,OAAA,EAMT,MAAO,EAAA,CAMR,kBAA0B,EAAkB,EAAA,CAC3C,IACM,EAAQ,IAAI,YADA,iBAAiB,EAAA,UACM,CACxC,OAAQ,CACP,KAAM,EACN,UAAW,EAAY,UACvB,MAAO,EAAY,MACnB,OAAQ,EAAY,OACpB,MAAO,EAAY,MACnB,gBAAiB,EAAY,gBAAA,CAE9B,QAAA,CAAS,EACT,SAAA,CAAU,EAAA,CAAA,CAEX,OAAO,cAAc,EAAA,CAMtB,IAAI,EAAA,CACH,GAAA,CAAK,EACJ,MAAU,MAAM,wBAAA,CAKjB,IAAM,EAAc,KAAK,aAAa,IAAI,EAAA,CA6B1C,GA5BI,GAAA,CAAgB,EAAY,QAE/B,EAAY,KAAK,CAChB,UAAW,KACX,MAAO,EAAA,CACP,KAAM,EACN,OAAQ,EAAA,CACR,MAAO,EAAA,CAAA,CAAA,CAMT,KAAK,QAAQ,KAAK,CACjB,KAAM,EACN,UAAW,KACX,MAAO,EAAA,CACP,OAAQ,EAAA,CACR,MAAO,EAAA,CACP,gBAAiB,SACjB,QAAS,eAAA,CAAA,CAIV,KAAK,QAAQ,OAAO,EAAA,CACpB,KAAK,SAAS,KAAK,KAAK,QAAA,CAGpB,KAAK,kBACR,GAAA,CACC,IAAM,EAAe,QAAQ,OAAS,EAAA,CAChC,EAAgB,CAAA,GAAM,EAAa,eAAiB,EAAA,CAAA,CAAA,OACnD,EAAc,GAErB,IAAM,EAAW,CAAA,GACb,EACH,cAAA,EAAA,CAGK,EAAM,KAAK,eAAe,EAAA,CAChC,QAAQ,aAAa,EAAU,GAAI,EAAA,MAC3B,GASX,OAAA,CAUC,GARA,KAAK,aAAa,QAAQ,GAAW,EAAQ,UAAA,CAAA,CAC7C,KAAK,aAAa,OAAA,CAGlB,KAAK,QAAQ,OAAA,CACb,KAAK,SAAS,KAAK,KAAK,QAAA,CAGpB,KAAK,kBAAmB,CAC3B,IAAM,EAAM,KAAK,eAAe,EAAA,CAAA,CAChC,QAAQ,aAAa,CAAE,cAAe,EAAA,CAAA,CAAM,GAAI,EAAA,EAOlD,SAAA,CACK,KAAK,WAET,KAAK,SAAA,CAAW,EAGZ,AAEH,KAAK,sBADL,KAAK,mBAAmB,aAAA,CACnB,IAAqB,IAI3B,KAAK,aAAa,QAAQ,GAAW,EAAQ,UAAA,CAAA,CAC7C,KAAK,aAAa,OAAA,CAElB,KAAK,QAAQ,UAAA,CACb,KAAK,SAAS,UAAA,CACd,EAAc,UAAA,CAGd,KAAK,QAAQ,OAAA,CACb,EAAkB,OAAO,KAAA,EAM1B,OAAA,aAAO,CAIN,MAHK,CACJ,EAAY,WAAW,IAAI,EAErB,EAAY,SAMpB,IAAA,OAAI,CAEH,GAAA,CACC,IAAM,EAAe,QAAQ,MAC7B,GAAI,GAAgB,EAAa,cAChC,OAAO,EAAa,mBAAA,EAOtB,OAAO,KAAK,mBAAA,CAMb,QAAQ,EAAA,CACP,OAAO,KAAK,QAAQ,IAAI,EAAA,CAMzB,gBAAA,CACC,OAAO,MAAM,KAAK,KAAK,QAAQ,MAAA,CAAA,CAMhC,SAAS,EAAA,CACR,OAAO,KAAK,QAAQ,IAAI,EAAA,GAeM,aAAA,CC9sBzB,EAAA,cAA4B,EAAA,EAAY,EAAA,GAAG;;;;6CAY9B,EAQlB,WAAA,CACE,MAAO,CACL,KAAM,KAAK,KACX,UAAW,KAAK,UAChB,MAAO,KAAK,MACZ,MAAO,KAAK,MAAA,CAIhB,QAAA,CAEE,MAAO,GAAA,IAAI,KAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UA1BH,CAAE,KAAM,OAAA,CAAA,CAAA,CAAS,EAAA,UAAA,OAAA,IAAA,GAAA,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAGjB,CAAE,KAAM,OAAA,CAAA,CAAA,CAAS,EAAA,UAAA,YAAA,IAAA,GAAA,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAGjB,CAAE,KAAM,QAAA,CAAA,CAAA,CAAU,EAAA,UAAA,QAAA,IAAA,GAAA,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,UAGlB,CAAE,KAAM,OAAA,CAAA,CAAA,CAAS,EAAA,UAAA,QAAA,IAAA,GAAA,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,eAfd,iBAAA,CAAA,CAAiB,EAAA,CCiDhC,IAAY,EAAL,SAAA,EAAA,CAAA,MACN,GAAA,KAAO,OACP,EAAA,QAAU,UACV,EAAA,IAAM,MACN,EAAA,OAAS,SAAA,GAJH,EAAA,CAAA,CChEA,EAAA,cAA2B,EAAA,EAAY,EAAA,GAAG;;;;;;;GA0BhD,cAAA,CACC,GAAA,CAAK,KAAK,KAAM,MAAU,MAAM,wBAAA,EAGhC,EAAA,EAAA,OAEC,EAAK,QAAQ,MAAA,EAAA,EAAA,SAAA,CACF,KAAA,KAAW,IAAS,KAAK,KAAA,CAAA,EACnC,EAAA,EAAA,IAGE,KAAA,CAAM,MAAA,EAAA,EAAA,MACH,EAAA,EAAE,EAAA,EAAA,SAAA,CAGN,IAAM,EAAO,SAAS,SAChB,EAAc,EAAK,MAAM,IAAA,CAAK,KAAA,EAAS,GAG7C,GAAI,IAAgB,EAAY,SAAS,IAAA,EAAQ,EAAY,SAAS,MAAA,EACrE,GAAA,CACC,IAAM,EAAS,KAAK,MAAM,mBAAmB,EAAA,CAAA,CAC7C,GAAI,EAAO,KAAK,MACf,MAAO,CACN,KAAM,KAAK,KACX,UAAW,EAAO,KAAK,MAAM,UAC7B,MAAO,EAAO,KAAK,MAAM,OAAS,EAAA,CAClC,OAAQ,EAAO,KAAK,MAAM,QAAU,EAAA,CACpC,MAAO,EAAO,KAAK,MAAM,OAAS,EAAA,CAClC,gBAAiB,EAAiB,QAAA,MAAA,EAQtC,IAAM,EADW,EAAK,MAAM,IAAA,CAAK,OAAO,QAAA,CACP,KAAK,GACrC,KAAK,QAAQ,KAAK,GAAK,EAAE,OAAS,EAAA,CAAA,CAGnC,OAAI,EACI,CACN,KAAM,KAAK,KACX,UAAW,EACX,MAAO,EAAA,CACP,OAAQ,EAAA,CACR,gBAAiB,EAAiB,OAAA,CAK7B,KAAK,QACT,CACA,KAAM,KAAK,KACX,UAAW,KAAK,QAChB,MAAO,EAAA,CACP,OAAQ,EAAA,CACR,gBAAiB,EAAiB,OAAA,CAElC,MAAA,CAAA,EAEJ,EAAA,EAAA,WAGwB,OAAQ,WAAA,CAAY,MAAA,EAAA,EAAA,SAAA,CAI3C,GAAI,QAAQ,OAAO,gBAAgB,KAAK,MAAO,CAC9C,IAAM,EAAY,QAAQ,MAAM,cAAc,KAAK,MACnD,MAAO,CACN,KAAM,KAAK,KACX,UAAW,EAAU,UACrB,MAAO,EAAU,OAAS,EAAA,CAC1B,OAAQ,EAAU,QAAU,EAAA,CAC5B,MAAO,EAAU,OAAS,EAAA,CAC1B,gBAAiB,EAAiB,IAAA,CAKpC,IAAM,EAAO,SAAS,SAChB,EAAc,EAAK,MAAM,IAAA,CAAK,KAAA,EAAS,GAG7C,GAAI,IAAgB,EAAY,SAAS,IAAA,EAAQ,EAAY,SAAS,MAAA,EACrE,GAAA,CACC,IAAM,EAAS,KAAK,MAAM,mBAAmB,EAAA,CAAA,CAC7C,GAAI,EAAO,KAAK,MACf,MAAO,CACN,KAAM,KAAK,KACX,UAAW,EAAO,KAAK,MAAM,UAC7B,MAAO,EAAO,KAAK,MAAM,OAAS,EAAA,CAClC,OAAQ,EAAO,KAAK,MAAM,QAAU,EAAA,CACpC,MAAO,EAAO,KAAK,MAAM,OAAS,EAAA,CAClC,gBAAiB,EAAiB,QAAA,MAAA,EAQtC,IAAM,EADW,EAAK,MAAM,IAAA,CAAK,OAAO,QAAA,CACP,KAAK,GACrC,KAAK,QAAQ,KAAK,GAAK,EAAE,OAAS,EAAA,CAAA,CAGnC,OAAI,EACI,CACN,KAAM,KAAK,KACX,UAAW,EACX,MAAO,EAAA,CACP,OAAQ,EAAA,CACR,gBAAiB,EAAiB,OAAA,CAK7B,KAAK,QACT,CACA,KAAM,KAAK,KACX,UAAW,KAAK,QAChB,MAAO,EAAA,CACP,OAAQ,EAAA,CACR,gBAAiB,EAAiB,OAAA,CAElC,MAAA,CAAA,CAAA,CAGJ,MAAA,EAAA,EAAA,QAEO,GAAgC,IAAU,KAAV,EAAe,EAAA,EAAA,SAG7C,YAAY,KAAK,QAAQ,KAAK,KAAA,YAAA,CAAA,EAAkB,EAAA,EAAA,WAGhD,KAAM,IAAA,CACf,IACI,EADA,EAAmC,EAAO,UAa9C,GATyB,OAAd,GAAc,UAAY,KAAK,SACzC,EAAe,KAAK,OAAO,KAAK,GAAK,EAAE,OAAS,EAAA,CAC5C,IACH,EAAY,EAAa,YAAA,CAOzB,GACoB,OAAd,GAAc,aACpB,YAAa,GAAa,aAAc,GAAa,YAAa,GAEnE,GAAA,CAEC,GAAA,MADsB,GAAA,EACH,QAEnB,IAAM,EAAU,eAAe,QAAQ,EAAA,CACnC,GAAW,KAAK,SACnB,EAAe,KAAK,OAAO,KAAK,GAAK,EAAE,OAAS,EAAA,OAEzC,CAER,MAAO,CAAA,GAAK,EAAQ,UAAW,KAAM,aAAA,IAAc,GAAA,CAKrD,GAAA,CAAK,GAAgB,aAAqB,aAAe,KAAK,OAAQ,CACrE,IAAM,EAAU,EAAU,QAAQ,aAAA,CAClC,EAAe,KAAK,OAAO,KAAK,GAAK,EAAE,OAAS,EAAA,CAGjD,MAAO,CAAA,GAAK,EAAQ,UAAA,EAAW,aAAA,EAAA,EAAA,EAC9B,EAAA,EAAA,WAGQ,GACJ,EAAM,cAAc,MAIlB,EAAM,aAAa,MAAM,MAAA,EAAA,EAAA,WACrB,GAAA,CACT,GAAA,CAAoB,IAAhB,EACH,OAAA,EAAA,EAAA,IAAU,EAAA,CAIX,IAAM,EAAgB,IAAI,YAAY,WAAY,CACjD,OAAQ,CACP,aAAc,EAAM,cAAc,MAAQ,UAC1C,KAAM,KAAK,KACX,OAAQ,EAAM,QAAU,EAAA,CACxB,MAAO,EAAM,OAAS,EAAA,CACtB,eAAuC,OAAhB,GAAgB,SAAW,EAAA,IAAc,GAAA,CAEjE,QAAA,CAAS,EACT,SAAA,CAAU,EAAA,CAAA,CAIX,OAFA,EAAM,aAAa,cAAc,EAAA,CAE1B,EAAA,OAAA,CAAA,EAvBR,EAAA,EAAA,IAAU,EAAA,CAAA,EA0BV,EAAA,EAAA,WAGQ,KAAM,IAAA,CACf,IAAI,EAAY,EAAM,UAEtB,GACsB,OAAd,GAAc,aACpB,YAAa,GAAa,aAAc,GAAa,YAAa,GAEnE,GAAA,CAEC,GAAA,MADsB,GAAA,EACH,aACX,CAER,MAAO,CAAA,GAAK,EAAO,UAAW,KAAA,CAIhC,MAAO,CAAA,GAAK,EAAO,UAAA,EAAA,EAAA,EAClB,EAAA,EAAA,KAGE,GAAA,CACH,IAAI,EAAa,GACX,EAAY,EAAM,UAEnB,GAAa,IAAc,GAEA,OAAd,GAAc,SAC/B,EAAa,EACH,aAAqB,YAC/B,EAAa,EAAU,QAAQ,aAAA,CACA,OAAd,GAAc,aAC/B,EAAa,EAAU,MAAQ,iBAN/B,EAAa,OASd,IAAM,EAAM,GAAG,IAAa,KAAK,UAAU,EAAM,OAAA,GAAU,KAAK,UAAU,EAAM,MAAA,GAAS,KAAK,UAAU,EAAM,MAAA,GAE9G,MAAO,CAAA,GAAK,EAAO,IAAA,EAAK,QAAS,EAAA,EAAA,EAChC,EAAA,EAAA,uBAGoB,EAAG,IAAM,EAAE,MAAQ,EAAE,IAAA,EAAI,EAAA,EAAA,KAG3C,GAAA,CACH,IAAI,EAA8B,KAC5B,EAAY,EAAM,UAExB,GAAK,GAAa,IAAc,GAAd,IAEc,OAAd,GAAc,SAC/B,GAAA,CACC,EAAU,SAAS,cAAc,EAAA,MAAA,UAIxB,aAAqB,YAC/B,EAAU,UACqB,OAAd,GAAc,WAC/B,GAAA,CACC,EAAU,IAAK,OACP,QAZT,EAAU,KAwBX,OANI,IACC,EAAM,QAAQ,OAAO,OAAO,EAAS,EAAM,OAAA,CAC3C,EAAM,OAAO,OAAO,OAAO,EAAS,EAAM,MAAA,CAC1C,EAAM,QAAQ,EAAgB,MAAQ,EAAM,QAG1C,CAAE,QAAA,EAAS,MAAA,EAAA,EAAA,EACjB,EAAA,EAAA,aAEU,EAAA,EAAE,EAAA,EAAA,MAAA,CAGP,QAAA,EAAS,MAAA,KAAY,KAAK,eAAe,EAAS,EAAA,CAAA,EAAO,EAAA,EAAA,SAAA,CAI/D,YAAY,KAAK,QAAQ,KAAK,KAAA,UAAA,CAC9B,YAAY,QAAQ,QAAQ,KAAK,KAAA,aAAmB,QAAQ,KAAK,KAAA,YAAkB,QAAQ,KAAK,KAAA,UAAA,EAAA,EAC/F,EAAA,EAAA,YAES,GAEH,EAAA,MAAA,EACN,EAAA,EAAA,WAEQ,KAAK,cAAA,CAAA,CAEf,WAAA,CAOF,eAAuB,EAAkC,EAAA,CAExD,IAAM,EAAe,MAAM,KAAK,KAAK,SAAA,CAAU,KAC9C,GAAA,EAAW,aAAiB,GAAA,CAI7B,GAAA,CAAK,EAEJ,OAAA,KADA,GAAc,QAAA,CAKf,IAAM,EAAW,EAAY,mBAAqB,IAGlD,GAAI,IAAa,EAEhB,GAAc,QAAA,CACd,KAAK,YAAY,EAAA,SACP,EAEV,EAAa,MAAM,WAAa,UAChC,EAAa,MAAM,WAAa,UAEhC,EAAa,MAAM,kBAAoB,SAGvB,EAAa,QAAQ,CAAC,CAAE,QAAS,EAAA,CAAK,CAAE,QAAS,EAAA,CAAA,CAAM,CAAE,SAAA,EAAU,OAAQ,WAAA,CAAA,CACnF,aAAA,CACP,EAAa,QAAA,CACb,KAAK,YAAY,EAAA,CACF,EAAa,QAAQ,CAAC,CAAE,QAAS,EAAA,CAAK,CAAE,QAAS,EAAA,CAAA,CAAM,CAAE,SAAA,EAAU,OAAQ,UAAA,CAAA,CACnF,aAAA,CAEN,EAAa,MAAM,WAAa,aAG5B,CAEN,EAAa,MAAM,WAAa,UAChC,KAAK,YAAY,EAAA,CACjB,IAAM,EAAiB,EAAW,IAAM,KAAK,IAAI,IAAgB,IAAX,EAAA,CAAmB,EAC1D,EAAa,QAAQ,CAAC,CAAE,QAAS,EAAA,CAAK,CAAE,QAAS,EAAA,CAAA,CAAM,CAAE,SAAU,EAAgB,OAAQ,UAAA,CAAA,CACnG,aAAA,CACN,EAAa,MAAM,WAAa,QAKlC,IAAM,EAA2B,CAChC,UAAW,EAAa,QAAQ,aAAA,CAChC,MAAO,EAAY,OAAS,EAAA,CAC5B,KAAM,KAAK,KACX,OAAQ,EAAY,QAAU,EAAA,CAC9B,MAAO,EAAY,OAAS,EAAA,CAAA,CAG7B,EAAK,QAAQ,IAAI,KAAK,KAAM,EAAA,CAC5B,EAAK,SAAS,KAAK,EAAK,QAAA,CAGpB,EAAK,mBACR,EAAK,sBACJ,KAAK,KACL,EACA,EAAY,iBAAmB,EAAiB,KAChD,EAAY,iBACZ,EAAY,KAAA,CAKf,sBAAA,CACC,MAAM,sBAAA,CACN,EAAK,IAAI,KAAK,KAAA,CAGf,QAAA,CACC,MAAO,GAAA,IAAI,kBCxbb,SAAgB,EAAW,EAAA,CAC1B,OAAO,KAAK,EAAA,CAGb,SAAgB,EAAW,EAAA,CAC1B,OAAO,KAAK,EAAA,CCIb,SAAgB,EACf,EACA,EAAA,CAGA,GAAI,IAAiB,EACpB,MAAA,CAAO,EAIR,GAA4B,OAAjB,GAAiB,YAAsC,OAAjB,GAAiB,WACjE,MAAA,CAAO,EAIR,GAAI,EAAa,MAAQ,EAAa,MAAQ,EAAa,OAAS,EAAa,KAChF,MAAA,CAAO,EAIR,IAAM,EAAQ,EAAqB,mBAC7B,EAAQ,EAAqB,mBAEnC,GAAI,GAAQ,GACP,MAAM,QAAQ,EAAA,EAAS,MAAM,QAAQ,EAAA,CACxC,OAAI,EAAK,SAAW,EAAK,QAClB,EAAK,OAAO,EAAM,IAAM,IAAS,EAAK,GAAA,CAK/C,GAAA,CACC,IAAM,EAAS,EAAa,UACtB,EAAS,EAAa,UAG5B,GAAI,OAAO,eAAe,EAAA,GAAY,OAAO,eAAe,EAAA,CAAS,CAEpE,IAAM,EAAQ,OAAO,oBAAoB,EAAA,CAAQ,MAAA,CAC3C,EAAQ,OAAO,oBAAoB,EAAA,CAAQ,MAAA,CAEjD,OAAO,EAAM,SAAW,EAAM,QAAU,EAAM,OAAO,EAAK,IAAM,IAAQ,EAAM,GAAA,OAAA,EAMhF,MAAA,CAAO,EAQR,SAAgB,EAAiB,EAAA,CAChC,OAAO,EAAQ,aAAA,CAAc,QAAQ,aAAc,GAAA,CAQpD,SAAgB,EAAW,EAAA,CAC1B,GAAyB,OAAd,GAAc,SACxB,OAAO,EAAU,aAAA,CAGlB,GAAI,aAAqB,YACxB,OAAO,EAAU,QAAQ,aAAA,CAG1B,GAAyB,OAAd,GAAc,WAAY,CAEpC,IAAM,EAAO,EAAU,KACvB,GAAI,EAEH,OAAO,EACL,QAAQ,WAAY,MAAA,CACpB,aAAA,CACA,QAAQ,KAAM,GAAA,CAIlB,OAAO,KASR,SAAgB,EAAyC,EAAW,EAAA,CACnE,IAAM,EAAS,CAAA,GAAK,EAAA,CAEpB,IAAK,IAAM,KAAO,EACjB,GAAI,EAAO,eAAe,EAAA,CAAM,CAC/B,IAAM,EAAc,EAAO,GACrB,EAAc,EAAO,GAEvB,EAAS,EAAA,EAAgB,EAAS,EAAA,CACrC,EAAO,GAAO,EAAU,EAAa,EAAA,CAErC,EAAO,GAAO,EAKjB,OAAO,EAQR,SAAgB,EAAS,EAAA,CACxB,OAEgB,OAAR,GAAQ,YADf,GAEA,EAAI,cAAgB,QACpB,OAAO,UAAU,SAAS,KAAK,EAAA,GAAS,kBAU1C,SAAgB,EAA4C,EAAS,EAAA,CACpE,IAAI,EAAgD,KAEpD,OAAO,SAAA,GAAwB,EAAA,CAC9B,IAAM,EAAU,KAEZ,IAAY,MACf,aAAa,EAAA,CAGd,EAAU,eAAA,CACT,EAAK,MAAM,EAAS,EAAA,CACpB,EAAU,MACR,EAAA,EASL,SAAgB,EAAiB,EAAA,CAChC,GAAA,CACC,IAAM,EAAO,KAAK,UAAU,EAAA,CAC5B,OAAO,mBAAmB,EAAA,MAClB,CAER,MAAO,IAST,SAAgB,EAAiB,EAAA,CAChC,GAAA,CAAK,EAAS,MAAO,EAAA,CAErB,GAAA,CAEC,IAAM,EAAS,KAAK,MADJ,mBAAmB,EAAA,CAAA,CAGnC,GAAI,EAAS,EAAA,CACZ,OAAO,OAEA,EAIT,MAAO,EAAA,CASR,SAAgB,EAAoB,EAAgB,EAAA,CAKnD,GAHI,EAAE,OAAS,EAAE,MAGjB,OAAW,EAAE,WAAA,OAAqB,EAAE,UAAW,MAAA,CAAO,EAEtD,GAA2B,OAAhB,EAAE,WAAc,UAAmC,OAAhB,EAAE,WAAc,SAAd,IAC3C,EAAiB,EAAE,UAAA,GAAe,EAAiB,EAAE,UAAA,CACxD,MAAA,CAAO,UAEyB,OAAhB,EAAE,WAAc,YAAqC,OAAhB,EAAE,WAAc,WAAd,IAAA,CACnD,EAAiC,EAAE,UAAW,EAAE,UAAA,CACpD,MAAA,CAAO,UAEE,EAAE,YAAc,EAAE,UAC5B,MAAA,CAAO,EAIR,OAAI,KAAK,UAAU,EAAE,OAAS,EAAA,CAAA,GAAQ,KAAK,UAAU,EAAE,OAAS,EAAA,CAAA,EAK5D,KAAK,UAAU,EAAE,QAAU,EAAA,CAAA,GAAQ,KAAK,UAAU,EAAE,QAAU,EAAA,CAAA,CAanE,SAAgB,EAAoB,EAAgB,EAAA,CACnD,OACC,EAAE,OAAS,EAAE,MACb,EAAE,YAAc,EAAE,WAClB,KAAK,UAAU,EAAE,OAAS,EAAA,CAAA,GAAQ,KAAK,UAAU,EAAE,OAAS,EAAA,CAAA,EAC5D,KAAK,UAAU,EAAE,QAAU,EAAA,CAAA,GAAQ,KAAK,UAAU,EAAE,QAAU,EAAA,CAAA,CAShE,SAAgB,EAAoB,EAAA,CACnC,IAAM,EAAU,EAAW,EAAM,UAAA,EAAc,UACzC,EAAY,EAAW,KAAK,UAAU,EAAM,OAAS,EAAA,CAAA,CAAA,CACrD,EAAa,EAAW,KAAK,UAAU,EAAM,QAAU,EAAA,CAAA,CAAA,CAE7D,MAAO,GAAG,EAAM,KAAA,GAAQ,EAAA,GAAW,EAAA,GAAa,IAQjD,SAAS,EAAW,EAAA,CACnB,IAAI,EAAO,EAEX,IAAK,IAAI,EAAI,EAAG,EAAI,EAAI,OAAQ,IAE/B,GAAQ,GAAQ,GAAK,EADR,EAAI,WAAW,EAAA,CAE5B,GAAc,EAGf,OAAO,KAAK,IAAI,EAAA,CAAM,SAAS,GAAA,CAShC,SAAgB,EACf,EACA,EAAyB,CAAC,WAAY,QAAS,SAAU,SAAA,CAAA,CAEzD,IAAM,EAAqC,EAAA,CAE3C,IAAK,IAAM,KAAO,EACjB,GAAI,EAAM,eAAe,EAAA,EAAA,CAAS,EAAa,SAAS,EAAA,CAAM,CAC7D,IAAM,EAAQ,EAAM,GAEhB,EAAS,EAAA,CACZ,EAAU,GAAO,EAAmB,EAAO,EAAA,CACjC,MAAM,QAAQ,EAAA,CACxB,EAAU,GAAO,EAAM,IAAI,GAAS,EAAS,EAAA,CAAQ,EAAmB,EAAM,EAAA,CAAgB,EAAA,CAE9F,EAAU,GAAO,EAKpB,OAAO,EAQR,SAAgB,EAAmB,EAAA,CAClC,IAAM,EAAiC,EAAA,CAEnC,EAeJ,MAZC,GADG,aAAe,gBACH,EACU,OAAR,GAAQ,SAEV,IADI,IAAI,EAAK,OAAO,SAAS,OAAA,CACtB,aAEP,IAAI,gBAAgB,OAAO,SAAS,OAAA,CAGpD,EAAa,SAAS,EAAO,IAAA,CAC5B,EAAO,GAAO,GAAA,CAGR,EAQR,SAAgB,EAAiB,EAAA,CAChC,IAAM,EAAe,IAAI,gBAEzB,IAAK,IAAM,KAAO,EACjB,GAAI,EAAO,eAAe,EAAA,CAAM,CAC/B,IAAM,EAAQ,EAAO,GACjB,GAAA,MAAyC,IAAU,IACtD,EAAa,IAAI,EAAK,OAAO,EAAA,CAAA,CAKhC,IAAM,EAAc,EAAa,UAAA,CACjC,OAAO,EAAc,IAAI,IAAgB,GAAA,EAAA,EAAA,EAAA,EAAA,EAAA,WAAA,CAAA,CF1T9B,EAAA,UAAA,OAAA,IAAA,GAAA,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,WAAA,CAAA,CAEA,EAAA,UAAA,UAAA,IAAA,GAAA,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,uBAMY,CAAE,SAAU,iBAAkB,QAAA,CAAS,EAAA,CAAA,CAAA,CAAO,EAAA,UAAA,SAAA,IAAA,GAAA,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,eAxBvD,gBAAA,CAAA,CAAgB,EAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA"}
1
+ {"version":3,"file":"area-CFLFXu0Z.cjs","names":[],"sources":["../src/area/area.service.ts","../src/area/route.component.ts","../src/area/router.types.ts","../src/area/area.component.ts","../src/area/ecrypt.ts","../src/area/utils.ts"],"sourcesContent":["import {\n\tbufferTime,\n\tcatchError,\n\tdistinctUntilChanged,\n\tEMPTY,\n\tfilter,\n\tfromEvent,\n\tmap,\n\tObservable,\n\tof,\n\tReplaySubject,\n\tshareReplay,\n\tskip,\n\tstartWith,\n\tSubject,\n\tSubscription,\n\ttap,\n\ttimeout,\n\tzip\n} from 'rxjs'\nimport { SchmancyTeleportation } from '../teleport'\nimport { ActiveRoute, AreaSubscription, RouteAction } from './router.types'\n\nexport const routerHistory = new Subject<RouteAction>()\n\nexport const FINDING_MORTIES = 'FINDING_MORTIES'\nexport const HERE_RICKY = 'HERE_RICKY'\nexport type HERE_RICKY_EVENT = CustomEvent<{\n\tcomponent: SchmancyTeleportation\n}>\nexport type FINDING_MORTIES_EVENT = CustomEvent<{\n\tcomponent: SchmancyTeleportation\n}>\n\n// WeakMap for better memory management of area subjects\nconst areaSubjectsCache = new WeakMap<AreaService, Map<string, ReplaySubject<ActiveRoute>>>()\n\n// Track navigation source to prevent history conflicts\ntype NavigationSource = 'programmatic' | 'browser' | 'initial'\n\nclass AreaService implements AreaSubscription {\n\tprivate static instance: AreaService\n\tpublic prettyURL = false\n\tpublic mode: 'SILENT' | 'HISTORY' = 'HISTORY'\n\tpublic request = new ReplaySubject<RouteAction>(1)\n\tpublic current = new Map<string, ActiveRoute>()\n\tpublic $current = new ReplaySubject<Map<string, ActiveRoute>>(1)\n\t\n\t// Create a dictionary of ReplaySubjects for area-specific subscriptions\n\tprivate get areaSubjects(): Map<string, ReplaySubject<ActiveRoute>> {\n\t\tlet subjects = areaSubjectsCache.get(this)\n\t\tif (!subjects) {\n\t\t\tsubjects = new Map()\n\t\t\tareaSubjectsCache.set(this, subjects)\n\t\t}\n\t\treturn subjects\n\t}\n\t\n\tpublic enableHistoryMode = true\n\tprivate findingMortiesEvent = new CustomEvent<FINDING_MORTIES_EVENT['detail']>(FINDING_MORTIES)\n\tprivate disposed = false\n\tpublic isProcessingPopstate = false\n\tprivate unloadSubscription?: Subscription\n\n\tconstructor() {\n\t\tthis.$current.next(this.current)\n\t\t\n\t\t// Subscribe to current changes to update area-specific subjects\n\t\tthis.$current.subscribe(currentAreas => {\n\t\t\tif (this.disposed) return\n\t\t\t\n\t\t\t// For each area in the current map\n\t\t\tcurrentAreas.forEach((route, areaName) => {\n\t\t\t\t// Get or create a subject for this area\n\t\t\t\tconst areaSubject = this.getOrCreateAreaSubject(areaName)\n\t\t\t\t// Emit the updated route to area-specific subscribers\n\t\t\t\tareaSubject.next(route)\n\t\t\t})\n\t\t})\n\n\t\t// Initialize from browser state if available\n\t\tthis.initializeFromBrowserState()\n\n\t\t// Setup unload subscription using RxJS\n\t\tif (typeof window !== 'undefined') {\n\t\t\tthis.unloadSubscription = fromEvent(window, 'unload').subscribe(() => {\n\t\t\t\tthis.dispose()\n\t\t\t})\n\t\t}\n\t}\n\n\t/**\n\t * Initialize router state from browser history state\n\t */\n\tprivate initializeFromBrowserState() {\n\t\ttry {\n\t\t\tconst browserState = history.state\n\t\t\tif (browserState && browserState.schmancyAreas) {\n\t\t\t\tObject.entries(browserState.schmancyAreas).forEach(([areaName, route]) => {\n\t\t\t\t\tthis.current.set(areaName, route as ActiveRoute)\n\t\t\t\t})\n\t\t\t\tthis.$current.next(this.current)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('Failed to initialize from browser state:', error)\n\t\t}\n\t}\n\n\t/**\n\t * Get or create a ReplaySubject for a specific area with proper cleanup\n\t */\n\tprivate getOrCreateAreaSubject(areaName: string): ReplaySubject<ActiveRoute> {\n\t\tlet subject = this.areaSubjects.get(areaName)\n\t\t\n\t\tif (!subject || subject.closed) {\n\t\t\tsubject = new ReplaySubject<ActiveRoute>(1)\n\t\t\tthis.areaSubjects.set(areaName, subject)\n\t\t\t\n\t\t\t// If the area already exists in current, emit it immediately\n\t\t\tconst currentRoute = this.current.get(areaName)\n\t\t\tif (currentRoute) {\n\t\t\t\tsubject.next({\n\t\t\t\t\t...currentRoute,\n\t\t\t\t\t// Ensure state, params and props are initialized if undefined\n\t\t\t\t\tstate: currentRoute.state || {},\n\t\t\t\t\tparams: currentRoute.params || {},\n\t\t\t\t\tprops: currentRoute.props || {}\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn subject\n\t}\n\n\t/**\n\t * Subscribe to a specific area with caching\n\t */\n\ton(areaName: string, skipCurrent = false): Observable<ActiveRoute> {\n\t\tif (!areaName) {\n\t\t\tthrow new Error('Area name is required')\n\t\t}\n\n\t\tconst areaSubject = this.getOrCreateAreaSubject(areaName)\n\t\tconst observable = areaSubject.asObservable().pipe(\n\t\t\t// Add distinct to prevent duplicate emissions - includes state, params, and props\n\t\t\tdistinctUntilChanged((a, b) =>\n\t\t\t\ta.component === b.component &&\n\t\t\t\tJSON.stringify(a.state) === JSON.stringify(b.state) &&\n\t\t\t\tJSON.stringify(a.params) === JSON.stringify(b.params) &&\n\t\t\t\tJSON.stringify(a.props) === JSON.stringify(b.props)\n\t\t\t),\n\t\t\t// Share the subscription\n\t\t\tshareReplay(1)\n\t\t)\n\n\t\treturn skipCurrent ? observable.pipe(skip(1)) : observable\n\t}\n\t\n\t/**\n\t * Subscribe to all areas\n\t */\n\tall(skipCurrent = false): Observable<Map<string, ActiveRoute>> {\n\t\tconst observable = this.$current.asObservable().pipe(\n\t\t\tshareReplay(1)\n\t\t)\n\t\treturn skipCurrent ? observable.pipe(skip(1)) : observable\n\t}\n\t\n\t/**\n\t * Get state from an area with type safety\n\t */\n\tgetState<T = unknown>(areaName: string): Observable<T> {\n\t\tif (!areaName) {\n\t\t\tthrow new Error('Area name is required')\n\t\t}\n\t\t\n\t\treturn this.on(areaName).pipe(\n\t\t\tmap(route => route.state),\n\t\t\tfilter((state): state is NonNullable<Record<string, unknown>> => \n\t\t\t\tstate !== undefined && state !== null\n\t\t\t),\n\t\t\tdistinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)),\n\t\t\tmap(state => state as T),\n\t\t\tcatchError(err => {\n\t\t\t\tconsole.error(`Error getting state for area \"${areaName}\":`, err)\n\t\t\t\treturn EMPTY\n\t\t\t})\n\t\t)\n\t}\n\t\n\t/**\n\t * Get params from an area with type safety\n\t * Emits current value immediately on subscription via startWith\n\t * URL query params are MERGED with route params (URL takes precedence for redirects like _rp_oid)\n\t */\n\tparams<T extends Record<string, unknown> = Record<string, unknown>>(areaName: string): Observable<T> {\n\t\tif (!areaName) {\n\t\t\tthrow new Error('Area name is required')\n\t\t}\n\n\t\tconst routeParams = (this.current.get(areaName)?.params ?? {}) as Record<string, unknown>\n\n\t\t// ALWAYS merge URL query params - they take precedence (handles external OAuth-style redirects)\n\t\tlet currentParams = { ...routeParams }\n\t\tif (typeof window !== 'undefined' && window.location.search) {\n\t\t\tconst urlParams = new URLSearchParams(window.location.search)\n\t\t\turlParams.forEach((value, key) => {\n\t\t\t\tcurrentParams[key] = value\n\t\t\t})\n\t\t}\n\n\t\treturn this.on(areaName).pipe(\n\t\t\tmap(route => (route.params ?? {}) as T),\n\t\t\tstartWith(currentParams as T),\n\t\t\tdistinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)),\n\t\t\tcatchError(err => {\n\t\t\t\tconsole.error(`Error getting params for area \"${areaName}\":`, err)\n\t\t\t\treturn EMPTY\n\t\t\t})\n\t\t)\n\t}\n\t\n\t/**\n\t * Get a specific param from an area with null safety\n\t */\n\tparam<T = unknown>(areaName: string, key: string): Observable<T> {\n\t\tif (!areaName || !key) {\n\t\t\tthrow new Error('Area name and key are required')\n\t\t}\n\t\t\n\t\treturn this.params<Record<string, unknown>>(areaName).pipe(\n\t\t\tmap(params => params[key]),\n\t\t\tfilter((value): value is NonNullable<unknown> => value !== undefined),\n\t\t\tdistinctUntilChanged(),\n\t\t\tmap(value => value as T),\n\t\t\tcatchError(err => {\n\t\t\t\tconsole.error(`Error getting param \"${key}\" for area \"${areaName}\":`, err)\n\t\t\t\treturn EMPTY\n\t\t\t})\n\t\t)\n\t}\n\t\n\t/**\n\t * Get props from an area with type safety\n\t */\n\tprops<T extends Record<string, unknown> = Record<string, unknown>>(areaName: string): Observable<T> {\n\t\tif (!areaName) {\n\t\t\tthrow new Error('Area name is required')\n\t\t}\n\t\t\n\t\treturn this.on(areaName).pipe(\n\t\t\tmap(route => route.props),\n\t\t\tfilter((props): props is NonNullable<Record<string, unknown>> => \n\t\t\t\tprops !== undefined && props !== null\n\t\t\t),\n\t\t\tdistinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)),\n\t\t\tmap(props => props as T),\n\t\t\tcatchError(err => {\n\t\t\t\tconsole.error(`Error getting props for area \"${areaName}\":`, err)\n\t\t\t\treturn EMPTY\n\t\t\t})\n\t\t)\n\t}\n\t\n\t/**\n\t * Get a specific prop from an area with null safety\n\t */\n\tprop<T = unknown>(areaName: string, key: string): Observable<T> {\n\t\tif (!areaName || !key) {\n\t\t\tthrow new Error('Area name and key are required')\n\t\t}\n\t\t\n\t\treturn this.props<Record<string, unknown>>(areaName).pipe(\n\t\t\tmap(props => props[key]),\n\t\t\tfilter((value): value is NonNullable<unknown> => value !== undefined),\n\t\t\tdistinctUntilChanged(),\n\t\t\tmap(value => value as T),\n\t\t\tcatchError(err => {\n\t\t\t\tconsole.error(`Error getting prop \"${key}\" for area \"${areaName}\":`, err)\n\t\t\t\treturn EMPTY\n\t\t\t})\n\t\t)\n\t}\n\n\t/**\n\t * Find teleportation components\n\t */\n\tfind() {\n\t\treturn zip([\n\t\t\tfromEvent<HERE_RICKY_EVENT>(window, HERE_RICKY).pipe(\n\t\t\t\tmap(e => e.detail),\n\t\t\t\tbufferTime(0),\n\t\t\t),\n\t\t\tof(1).pipe(tap(() => window.dispatchEvent(this.findingMortiesEvent))),\n\t\t]).pipe(\n\t\t\tmap(([component]) => component),\n\t\t\ttimeout(1),\n\t\t\tcatchError(() => EMPTY)\n\t\t)\n\t}\n\n\t/**\n\t * Push a new route action with validation\n\t */\n\tpush(r: RouteAction) {\n\t\tif (!r.area) {\n\t\t\tthrow new Error('Area is required for route action')\n\t\t}\n\t\t\n\t\t// Prevent processing during popstate handling\n\t\tif (this.isProcessingPopstate) {\n\t\t\treturn\n\t\t}\n\t\t\n\t\t// Ensure state, params and props are initialized\n\t\tconst routeAction: RouteAction = {\n\t\t\t...r,\n\t\t\tstate: r.state || {},\n\t\t\tparams: r.params || {},\n\t\t\tprops: r.props || {},\n\t\t\t_source: 'programmatic' as NavigationSource\n\t\t}\n\t\t\n\t\t// Add to history if enabled\n\t\tif (this.enableHistoryMode) {\n\t\t\trouterHistory.next(routeAction)\n\t\t}\n\t\t\n\t\tthis.request.next(routeAction)\n\t\t// Emit an area-specific event for those who want to listen directly to DOM events\n\t\tthis.dispatchAreaEvent(routeAction.area, routeAction)\n\t}\n\n\t/**\n\t * Internal method to update route from browser navigation\n\t * This should only be called by area components during popstate handling\n\t */\n\t_updateFromBrowser(routeAction: RouteAction) {\n\t\tconst enhancedRoute: RouteAction = {\n\t\t\t...routeAction,\n\t\t\tstate: routeAction.state || {},\n\t\t\tparams: routeAction.params || {},\n\t\t\tprops: routeAction.props || {},\n\t\t\t_source: 'browser' as NavigationSource\n\t\t}\n\t\t\n\t\tthis.isProcessingPopstate = true\n\t\tthis.request.next(enhancedRoute)\n\t\tthis.isProcessingPopstate = false\n\t}\n\n\t/**\n\t * Update browser history state (called by area components)\n\t */\n\t_updateBrowserHistory(areaName: string, route: ActiveRoute, historyStrategy?: string, clearQueryParams?: string[] | boolean | null, customPath?: string) {\n\t\tif (!this.enableHistoryMode) return\n\n\t\ttry {\n\t\t\t// Get current browser state or create new one\n\t\t\tconst currentState = history.state || {}\n\t\t\tconst schmancyAreas = currentState.schmancyAreas || {}\n\n\t\t\t// Update the specific area - only include non-empty state/params/props\n\t\t\tconst areaData: any = {\n\t\t\t\tcomponent: route.component,\n\t\t\t\tarea: route.area\n\t\t\t}\n\n\t\t\t// Only include state if it has content\n\t\t\tif (route.state && Object.keys(route.state).length > 0) {\n\t\t\t\tareaData.state = route.state\n\t\t\t}\n\n\t\t\t// Only include params if it has content\n\t\t\tif (route.params && Object.keys(route.params).length > 0) {\n\t\t\t\tareaData.params = route.params\n\t\t\t}\n\n\t\t\t// Only include props if it has content\n\t\t\tif (route.props && Object.keys(route.props).length > 0) {\n\t\t\t\tareaData.props = route.props\n\t\t\t}\n\n\t\t\tschmancyAreas[areaName] = areaData\n\n\t\t\tconst newState = {\n\t\t\t\t...currentState,\n\t\t\t\tschmancyAreas\n\t\t\t}\n\n\t\t\t// Create clean URL with optional custom path\n\t\t\tconst url = this.createCleanURL(schmancyAreas, clearQueryParams, customPath)\n\n\t\t\t// Update browser history\n\t\t\tif (historyStrategy === 'replace' || historyStrategy === 'pop') {\n\t\t\t\thistory.replaceState(newState, '', url)\n\t\t\t} else if (historyStrategy === 'push' || !historyStrategy) {\n\t\t\t\thistory.pushState(newState, '', url)\n\t\t\t}\n\t\t\t// 'silent' strategy doesn't update browser history\n\n\t\t} catch (error) {\n\t\t\tconsole.error('Failed to update browser history:', error)\n\t\t}\n\t}\n\n\t/**\n\t * Create a clean URL from area states\n\t */\n\tprivate createCleanURL(areas: Record<string, ActiveRoute>, clearQueryParams?: string[] | boolean | null, customPath?: string): string {\n\t\tlet basePath = '/'\n\n\t\t// If custom path is provided, use it directly (completely replaces the path)\n\t\tif (customPath) {\n\t\t\tbasePath = customPath\n\t\t\t// Ensure it starts with /\n\t\t\tif (!basePath.startsWith('/')) {\n\t\t\t\tbasePath = '/' + basePath\n\t\t\t}\n\t\t\t// Ensure base path ends with / for appending encoded state\n\t\t\tif (!basePath.endsWith('/')) {\n\t\t\t\tbasePath += '/'\n\t\t\t}\n\t\t} else {\n\t\t\t// Get the current base path (everything except the last segment which might be encoded state)\n\t\t\tconst currentPath = location.pathname\n\t\t\tconst pathSegments = currentPath.split('/')\n\n\t\t\t// Check if the last segment is encoded state (contains { or %7B)\n\t\t\tconst lastSegment = pathSegments[pathSegments.length - 1]\n\t\t\tif (lastSegment && (lastSegment.includes('{') || lastSegment.includes('%7B'))) {\n\t\t\t\t// Remove the encoded state segment to get the base path\n\t\t\t\tpathSegments.pop()\n\t\t\t\tbasePath = pathSegments.join('/') || '/'\n\t\t\t} else {\n\t\t\t\t// Keep the current path as base path\n\t\t\t\tbasePath = currentPath\n\t\t\t}\n\n\t\t\t// Ensure base path ends properly\n\t\t\tif (basePath !== '/' && !basePath.endsWith('/')) {\n\t\t\t\tbasePath += '/'\n\t\t\t}\n\t\t}\n\n\t\t// Handle query parameters\n\t\tlet queryString = ''\n\n\t\tif (clearQueryParams !== true) {\n\t\t\t// Get current query params\n\t\t\tconst urlParams = new URLSearchParams(location.search)\n\n\t\t\t// Add params from all areas to query string\n\t\t\tObject.values(areas).forEach(route => {\n\t\t\t\tif (route.params && Object.keys(route.params).length > 0) {\n\t\t\t\t\tObject.entries(route.params).forEach(([key, value]) => {\n\t\t\t\t\t\tif (value !== null && value !== undefined) {\n\t\t\t\t\t\t\turlParams.set(key, String(value))\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// Clear specific params if provided\n\t\t\tif (Array.isArray(clearQueryParams)) {\n\t\t\t\tclearQueryParams.forEach(param => urlParams.delete(param))\n\t\t\t}\n\n\t\t\t// Convert back to string\n\t\t\tqueryString = urlParams.toString()\n\t\t\tqueryString = queryString ? `?${queryString}` : ''\n\t\t}\n\t\t// If clearQueryParams === true, queryString remains empty (all params cleared)\n\n\t\tif (this.prettyURL) {\n\t\t\t// Create pretty URLs - customize this based on your routing needs\n\t\t\tconst mainArea = areas.main\n\t\t\tif (mainArea) {\n\t\t\t\tlet path = basePath === '/' ? `/${mainArea.component}` : `${basePath}${mainArea.component}`\n\n\t\t\t\t// Add simple params to URL\n\t\t\t\tconst searchParams = new URLSearchParams(queryString)\n\t\t\t\tif (mainArea.params) {\n\t\t\t\t\tObject.entries(mainArea.params).forEach(([key, value]) => {\n\t\t\t\t\t\tif (typeof value === 'string' || typeof value === 'number') {\n\t\t\t\t\t\t\tsearchParams.set(key, String(value))\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tconst query = searchParams.toString()\n\t\t\t\treturn path + (query ? `?${query}` : '')\n\t\t\t}\n\t\t}\n\n\t\t// Fallback to encoded state in URL (original behavior)\n\t\ttry {\n\t\t\t// Clean up empty objects before encoding\n\t\t\tconst cleanedAreas: Record<string, any> = {}\n\t\t\tObject.entries(areas).forEach(([areaName, route]) => {\n\t\t\t\tconst cleanRoute: any = { component: route.component }\n\n\t\t\t\t// Only include state if it has content\n\t\t\t\tif (route.state && Object.keys(route.state).length > 0) {\n\t\t\t\t\tcleanRoute.state = route.state\n\t\t\t\t}\n\n\t\t\t\t// Only include params if it has content\n\t\t\t\tif (route.params && Object.keys(route.params).length > 0) {\n\t\t\t\t\tcleanRoute.params = route.params\n\t\t\t\t}\n\n\t\t\t\t// Only include props if it has content\n\t\t\t\tif (route.props && Object.keys(route.props).length > 0) {\n\t\t\t\t\tcleanRoute.props = route.props\n\t\t\t\t}\n\n\t\t\t\tcleanedAreas[areaName] = cleanRoute\n\t\t\t})\n\n\t\t\t// If cleanedAreas is empty, preserve the base path\n\t\t\tif (Object.keys(cleanedAreas).length === 0) {\n\t\t\t\tconst cleanBasePath = basePath === '/' ? '' : basePath.replace(/\\/$/, '')\n\t\t\t\treturn `${cleanBasePath}${queryString}`\n\t\t\t}\n\n\t\t\tconst encoded = encodeURIComponent(JSON.stringify(cleanedAreas))\n\t\t\tconst cleanBasePath = basePath === '/' ? '' : basePath.replace(/\\/$/, '')\n\t\t\treturn `${cleanBasePath}/${encoded}${queryString}`\n\t\t} catch (error) {\n\t\t\tconsole.error('Failed to encode URL state:', error)\n\t\t\treturn location.pathname\n\t\t}\n\t}\n\n\t/**\n\t * Restore state from browser history state\n\t */\n\trestoreFromBrowserState(browserState: any): Record<string, ActiveRoute> {\n\t\ttry {\n\t\t\tif (browserState && browserState.schmancyAreas) {\n\t\t\t\treturn browserState.schmancyAreas\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error('Failed to restore from browser state:', error)\n\t\t}\n\t\t\n\t\t// Fallback to URL parsing (original behavior)\n\t\treturn this.parseStateFromURL()\n\t}\n\n\t/**\n\t * Parse state from URL (fallback method)\n\t */\n\tprivate parseStateFromURL(): Record<string, ActiveRoute> {\n\t\tconst pathname = location.pathname.split('/').pop()\n\t\tif (!pathname) return {}\n\t\t\n\t\ttry {\n\t\t\tconst decoded = decodeURIComponent(pathname)\n\t\t\tconst parsed = JSON.parse(decoded)\n\t\t\t\n\t\t\tif (typeof parsed === 'object' && parsed !== null) {\n\t\t\t\treturn parsed\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore parse errors\n\t\t}\n\t\t\n\t\treturn {}\n\t}\n\t\n\t/**\n\t * Dispatch a DOM event for a specific area change\n\t */\n\tprivate dispatchAreaEvent(areaName: string, routeAction: RouteAction) {\n\t\tconst eventName = `schmancy-area-${areaName}-changed`\n\t\tconst event = new CustomEvent(eventName, { \n\t\t\tdetail: { \n\t\t\t\tarea: areaName,\n\t\t\t\tcomponent: routeAction.component,\n\t\t\t\tstate: routeAction.state,\n\t\t\t\tparams: routeAction.params,\n\t\t\t\tprops: routeAction.props,\n\t\t\t\thistoryStrategy: routeAction.historyStrategy\n\t\t\t},\n\t\t\tbubbles: true,\n\t\t\tcomposed: true\n\t\t})\n\t\twindow.dispatchEvent(event)\n\t}\n\n\t/**\n\t * Remove an area from the current state\n\t */\n\tpop(name: string) {\n\t\tif (!name) {\n\t\t\tthrow new Error('Area name is required')\n\t\t}\n\n\t\t// Before removing from current map, emit a clearing signal to the area's subject\n\t\t// This notifies the area component to clear itself\n\t\tconst areaSubject = this.areaSubjects.get(name)\n\t\tif (areaSubject && !areaSubject.closed) {\n\t\t\t// Send a route with null component to signal clearing\n\t\t\tareaSubject.next({\n\t\t\t\tcomponent: null as any,\n\t\t\t\tstate: {},\n\t\t\t\tarea: name,\n\t\t\t\tparams: {},\n\t\t\t\tprops: {}\n\t\t\t})\n\t\t}\n\n\t\t// Send a clearing signal through the request pipeline\n\t\t// This ensures the area component receives the signal to clear\n\t\tthis.request.next({\n\t\t\tarea: name,\n\t\t\tcomponent: null as any,\n\t\t\tstate: {},\n\t\t\tparams: {},\n\t\t\tprops: {},\n\t\t\thistoryStrategy: 'silent' as any,\n\t\t\t_source: 'programmatic' as NavigationSource\n\t\t})\n\n\t\t// Remove from current map\n\t\tthis.current.delete(name)\n\t\tthis.$current.next(this.current)\n\n\t\t// Update browser history\n\t\tif (this.enableHistoryMode) {\n\t\t\ttry {\n\t\t\t\tconst currentState = history.state || {}\n\t\t\t\tconst schmancyAreas = { ...(currentState.schmancyAreas || {}) }\n\t\t\t\tdelete schmancyAreas[name]\n\n\t\t\t\tconst newState = {\n\t\t\t\t\t...currentState,\n\t\t\t\t\tschmancyAreas\n\t\t\t\t}\n\n\t\t\t\tconst url = this.createCleanURL(schmancyAreas)\n\t\t\t\thistory.replaceState(newState, '', url)\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('Failed to update history after pop:', error)\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Clear all areas\n\t */\n\tclear() {\n\t\t// Complete all area subjects\n\t\tthis.areaSubjects.forEach(subject => subject.complete())\n\t\tthis.areaSubjects.clear()\n\n\t\t// Clear current state\n\t\tthis.current.clear()\n\t\tthis.$current.next(this.current)\n\n\t\t// Update URL\n\t\tif (this.enableHistoryMode) {\n\t\t\tconst url = this.createCleanURL({})\n\t\t\thistory.replaceState({ schmancyAreas: {} }, '', url)\n\t\t}\n\t}\n\t\n\t/**\n\t * Dispose of the service and clean up resources\n\t */\n\tdispose() {\n\t\tif (this.disposed) return\n\n\t\tthis.disposed = true\n\n\t\t// Unsubscribe from unload event\n\t\tif (this.unloadSubscription) {\n\t\t\tthis.unloadSubscription.unsubscribe()\n\t\t\tthis.unloadSubscription = undefined\n\t\t}\n\n\t\t// Complete all subjects\n\t\tthis.areaSubjects.forEach(subject => subject.complete())\n\t\tthis.areaSubjects.clear()\n\n\t\tthis.request.complete()\n\t\tthis.$current.complete()\n\t\trouterHistory.complete()\n\n\t\t// Clear references\n\t\tthis.current.clear()\n\t\tareaSubjectsCache.delete(this)\n\t}\n\t\n\t/**\n\t * Get singleton instance\n\t */\n\tstatic getInstance() {\n\t\tif (!AreaService.instance) {\n\t\t\tAreaService.instance = new AreaService()\n\t\t}\n\t\treturn AreaService.instance\n\t}\n\n\t/**\n\t * Get current state from URL (deprecated - use browser state instead)\n\t */\n\tget state(): Record<string, unknown> {\n\t\t// Try browser state first\n\t\ttry {\n\t\t\tconst browserState = history.state\n\t\t\tif (browserState && browserState.schmancyAreas) {\n\t\t\t\treturn browserState.schmancyAreas\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fallback to URL parsing\n\t\t}\n\t\t\n\t\t// Fallback to URL parsing (original behavior)\n\t\treturn this.parseStateFromURL()\n\t}\n\t\n\t/**\n\t * Check if an area exists in current state\n\t */\n\thasArea(areaName: string): boolean {\n\t\treturn this.current.has(areaName)\n\t}\n\t\n\t/**\n\t * Get all active area names\n\t */\n\tgetActiveAreas(): string[] {\n\t\treturn Array.from(this.current.keys())\n\t}\n\t\n\t/**\n\t * Get route for a specific area synchronously\n\t */\n\tgetRoute(areaName: string): ActiveRoute | undefined {\n\t\treturn this.current.get(areaName)\n\t}\n}\n\n/**\n * Area router singleton. Drives named `<schmancy-area>` outlets in the DOM\n * — imperative push / pop, URL-synced, state-restoring. Pair with\n * `lazy(() => import('./view'))` for code-split routes.\n *\n * @service\n * @summary Imperative outlet-based router for `<schmancy-area>` elements.\n * @method push({ area, component, params?, state? }) - Navigate an area to a component.\n * @method pop(areaName) - Pop the top entry off an area's stack.\n * @method current$(areaName) - Observable of the active route state for an area.\n */\nexport const area = AreaService.getInstance()\nexport default area","import { $LitElement } from '@mixins/index';\nimport { css, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { Observable } from 'rxjs';\nimport { LazyComponent } from './lazy';\n\nexport type ObservableGuardResult = Observable<boolean>;\n\n// Component types that can be passed to routes\nexport type RouteComponent =\n | string // Tag name\n | CustomElementConstructor // Constructor function\n | HTMLElement // Existing element\n | LazyComponent<any> \n\nexport interface RouteConfig {\n when: string;\n component: RouteComponent;\n exact?: boolean;\n guard?: ObservableGuardResult;\n}\n\n/**\n * A marker component that holds route configuration.\n * This component doesn't render anything - it's used by schmancy-area\n * to configure routing via slot change detection.\n *\n * @example\n * ```html\n * <schmancy-area>\n * <schmancy-route\n * when=\"users\"\n * .component=${UserComponent}\n * exact\n * ></schmancy-route>\n * </schmancy-area>\n * ```\n */\n@customElement('schmancy-route')\nexport class SchmancyRoute extends $LitElement(css`\n :host {\n display: none;\n }\n`) {\n @property({ type: String })\n when!: string;\n\n @property({ type: Object })\n component!: RouteComponent;\n\n @property({ type: Boolean })\n exact?: boolean = false;\n\n @property({ type: Object })\n guard?:ObservableGuardResult ;\n\n /**\n * Returns the route configuration object\n */\n getConfig(): RouteConfig {\n return {\n when: this.when,\n component: this.component,\n exact: this.exact,\n guard: this.guard\n };\n }\n\n render() {\n // This is a marker component - no visual output\n return html``;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'schmancy-route': SchmancyRoute;\n }\n}","import { LazyComponent } from './lazy'\n\n/**\n * Component type accepted by area router, drawer, and sheet services\n */\nexport type ComponentType = CustomElementConstructor | string | HTMLElement | LazyComponent<any>\n\nexport type RouteAction = {\n\tcomponent: ComponentType\n\tarea: string\n\tstate?: Record<string, unknown>\n\tparams?: Record<string, unknown>\n\tprops?: Record<string, unknown> // Alias for params\n\thistoryStrategy?: THistoryStrategy\n\tclearQueryParams?: string[] | boolean | null\n\tanimationDuration?: number // Animation duration in milliseconds (0 = instant/no animation, default = 150ms)\n\tpath?: string // Override the URL path (e.g., '/order-tracking') - completely replaces the base path\n\t_source?: 'programmatic' | 'browser' | 'initial' // Internal use only\n}\n\nexport type ActiveRoute = {\n\tcomponent: string\n\tarea: string\n\tstate?: Record<string, unknown>\n\tparams?: Record<string, unknown>\n\tprops?: Record<string, unknown>\n}\n\n/**\n * Interface for subscribing to area changes\n */\nexport interface AreaSubscription {\n\t/**\n\t * Subscribe to a specific area\n\t * @param areaName Name of the area to subscribe to\n\t * @param skipCurrent Whether to skip the current value\n\t * @returns Observable of the active route for the specified area\n\t */\n\ton(areaName: string, skipCurrent?: boolean): import('rxjs').Observable<ActiveRoute>\n\t\n\t/**\n\t * Subscribe to all areas\n\t * @param skipCurrent Whether to skip the current value\n\t * @returns Observable of all active routes\n\t */\n\tall(skipCurrent?: boolean): import('rxjs').Observable<Map<string, ActiveRoute>>\n\t\n\t/**\n\t * Get state from an area\n\t * @param areaName Name of the area to subscribe to\n\t * @returns Observable of the area's state\n\t */\n\tgetState<T = unknown>(areaName: string): import('rxjs').Observable<T>\n\t\n\t/**\n\t * Get params from an area\n\t * @param areaName Name of the area to subscribe to\n\t * @returns Observable of the area's params\n\t */\n\tparams<T extends Record<string, unknown> = Record<string, unknown>>(areaName: string): import('rxjs').Observable<T>\n\t\n\t/**\n\t * Get a specific param from an area\n\t * @param areaName Name of the area to subscribe to\n\t * @param key Key of the param to select\n\t * @returns Observable of the param value\n\t */\n\tparam<T = unknown>(areaName: string, key: string): import('rxjs').Observable<T>\n\t\n\t/**\n\t * Get props from an area\n\t * @param areaName Name of the area to subscribe to\n\t * @returns Observable of the area's props\n\t */\n\tprops<T extends Record<string, unknown> = Record<string, unknown>>(areaName: string): import('rxjs').Observable<T>\n\t\n\t/**\n\t * Get a specific prop from an area\n\t * @param areaName Name of the area to subscribe to\n\t * @param key Key of the prop to select\n\t * @returns Observable of the prop value\n\t */\n\tprop<T = unknown>(areaName: string, key: string): import('rxjs').Observable<T>\n}\n\nexport type THistoryStrategy = 'push' | 'replace' | 'pop' | 'silent'\n\nexport enum HISTORY_STRATEGY {\n\tpush = 'push',\n\treplace = 'replace',\n\tpop = 'pop',\n\tsilent = 'silent',\n}\n\n/**\n * Browser history state structure used by Schmancy Area\n */\nexport interface SchmancyHistoryState {\n\tschmancyAreas: Record<string, ActiveRoute>\n\t[key: string]: any // Allow other apps to store additional state\n}","import { $LitElement } from '@mixins/index'\nimport { css, html } from 'lit'\nimport { customElement, property, queryAssignedElements } from 'lit/decorators.js'\nimport {\n\tEMPTY,\n\tcatchError,\n\tdistinctUntilChanged,\n\tfilter,\n\tfromEvent,\n\tmap,\n\tmerge,\n\tof,\n\tshareReplay,\n\tswitchMap,\n\ttake,\n\ttakeUntil,\n\ttap,\n} from 'rxjs'\nimport area from './area.service'\nimport { RouteComponent, SchmancyRoute } from './route.component'\nimport { ActiveRoute, HISTORY_STRATEGY, RouteAction } from './router.types'\n\n/**\n * Router outlet — renders the active route's component for the named area. Drives the schmancy router via the `area` service.\n *\n * @element schmancy-area\n * @summary Mount once per \"addressable region\" of the app (typically the main content area). Use the imperative `area.push({ area, component, params })` service to navigate. Multiple named areas can coexist on a page (e.g. main content + a sheet).\n * @example\n * <schmancy-area name=\"main\"></schmancy-area>\n * <script>\n * import { area } from '@mhmo91/schmancy';\n * area.push({ area: 'main', component: MyDashboardView, params: { id: 42 } });\n * </script>\n * @platform div - Routing outlet. Degrades to an empty div if the tag never registers — routing is lost but the page stays accessible.\n * @fires redirect - When the area resolves a route to a different destination (programmatic redirect). `detail.from` and `detail.to` are the route names.\n */\n@customElement('schmancy-area')\nexport class SchmancyArea extends $LitElement(css`\n\t:host {\n\t\tposition: relative;\n\t\tdisplay: block;\n\t\tinset: 0;\n\t\tcontain: layout style;\n\t}\n`) {\n\t/**\n\t * The name of the router outlet\n\t * @attr\n\t * @type {string}\n\t * @public\n\t * @required\n\t */\n\t@property() name!: string\n\n\t@property() default!: RouteComponent\n\n\t/**\n\t * Query for assigned route elements in the slot\n\t * This will automatically update when slot content changes\n\t */\n\t@queryAssignedElements({ selector: 'schmancy-route', flatten: true })\n\tprivate routes!: SchmancyRoute[]\n\n\tprotected firstUpdated(): void {\n\t\tif (!this.name) throw new Error('Area name is required')\n\n\t\t// Single unified routing pipeline with all logic inline\n\t\tmerge(\n\t\t\t// Source 1: Programmatic navigation from area.request\n\t\t\tarea.request.pipe(\n\t\t\t\tfilter(({ area }) => area === this.name),\n\t\t\t),\n\n\t\t\t// Source 2: Initial page load - parse route from URL\n\t\t\tof(null).pipe(\n\t\t\t\ttake(1),\n\t\t\t\tmap(() => {\n\t\t\t\t\t// Parse route from URL on initial load\n\t\t\t\t\tconst path = location.pathname\n\t\t\t\t\tconst lastSegment = path.split('/').pop() || ''\n\n\t\t\t\t\t// Check for JSON encoded route in URL\n\t\t\t\t\tif (lastSegment && (lastSegment.includes('{') || lastSegment.includes('%7B'))) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst parsed = JSON.parse(decodeURIComponent(lastSegment)) as Record<string, ActiveRoute>\n\t\t\t\t\t\t\tif (parsed[this.name]) {\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\t\t\tcomponent: parsed[this.name].component,\n\t\t\t\t\t\t\t\t\tstate: parsed[this.name].state || {},\n\t\t\t\t\t\t\t\t\tparams: parsed[this.name].params || {},\n\t\t\t\t\t\t\t\t\tprops: parsed[this.name].props || {},\n\t\t\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.replace,\n\t\t\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Segment-based routing\n\t\t\t\t\tconst segments = path.split('/').filter(Boolean)\n\t\t\t\t\tconst matchingSegment = segments.find(seg =>\n\t\t\t\t\t\tthis.routes?.some(r => r.when === seg)\n\t\t\t\t\t)\n\n\t\t\t\t\tif (matchingSegment) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\tcomponent: matchingSegment,\n\t\t\t\t\t\t\tstate: {},\n\t\t\t\t\t\t\tparams: {},\n\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.silent,\n\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use default route if available\n\t\t\t\t\treturn this.default\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\t\tcomponent: this.default,\n\t\t\t\t\t\t\t\tstate: {},\n\t\t\t\t\t\t\t\tparams: {},\n\t\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.silent,\n\t\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t\t: null\n\t\t\t\t})\n\t\t\t),\n\n\t\t\t// Source 3: Browser navigation (back/forward) - parse from browser state\n\t\t\tfromEvent<PopStateEvent>(window, 'popstate').pipe(\n\t\t\t\tmap(() => {\n\t\t\t\t\t// Parse route from browser state during popstate\n\t\t\t\t\t// First check history state\n\t\t\t\t\tif (history.state?.schmancyAreas?.[this.name]) {\n\t\t\t\t\t\tconst stateData = history.state.schmancyAreas[this.name]\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\tcomponent: stateData.component,\n\t\t\t\t\t\t\tstate: stateData.state || {},\n\t\t\t\t\t\t\tparams: stateData.params || {},\n\t\t\t\t\t\t\tprops: stateData.props || {},\n\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.pop,\n\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fallback to URL parsing if no state (e.g., navigating to root)\n\t\t\t\t\tconst path = location.pathname\n\t\t\t\t\tconst lastSegment = path.split('/').pop() || ''\n\n\t\t\t\t\t// Check for JSON encoded route in URL\n\t\t\t\t\tif (lastSegment && (lastSegment.includes('{') || lastSegment.includes('%7B'))) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst parsed = JSON.parse(decodeURIComponent(lastSegment)) as Record<string, ActiveRoute>\n\t\t\t\t\t\t\tif (parsed[this.name]) {\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\t\t\tcomponent: parsed[this.name].component,\n\t\t\t\t\t\t\t\t\tstate: parsed[this.name].state || {},\n\t\t\t\t\t\t\t\t\tparams: parsed[this.name].params || {},\n\t\t\t\t\t\t\t\t\tprops: parsed[this.name].props || {},\n\t\t\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.replace,\n\t\t\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Segment-based routing\n\t\t\t\t\tconst segments = path.split('/').filter(Boolean)\n\t\t\t\t\tconst matchingSegment = segments.find(seg =>\n\t\t\t\t\t\tthis.routes?.some(r => r.when === seg)\n\t\t\t\t\t)\n\n\t\t\t\t\tif (matchingSegment) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\tcomponent: matchingSegment,\n\t\t\t\t\t\t\tstate: {},\n\t\t\t\t\t\t\tparams: {},\n\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.silent,\n\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use default route if available\n\t\t\t\t\treturn this.default\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\t\tcomponent: this.default,\n\t\t\t\t\t\t\t\tstate: {},\n\t\t\t\t\t\t\t\tparams: {},\n\t\t\t\t\t\t\t\thistoryStrategy: HISTORY_STRATEGY.silent,\n\t\t\t\t\t\t\t} as RouteAction\n\t\t\t\t\t\t: null\n\t\t\t\t})\n\t\t\t)\n\t\t).pipe(\n\t\t\t// Filter out null routes\n\t\t\tfilter((route): route is RouteAction => route !== null),\n\n\t\t\t// Performance: mark navigation start\n\t\t\ttap(() => performance.mark(`area-${this.name}-nav-start`)),\n\n\t\t\t// Step 1: Find matching route (resolve lazy only if needed for route matching)\n\t\t\tswitchMap(async action => {\n\t\t\t\tlet component: RouteComponent | null = action.component\n\t\t\t\tlet matchedRoute: SchmancyRoute | undefined\n\n\t\t\t\t// If component is a string, find the matching route\n\t\t\t\tif (typeof component === 'string' && this.routes) {\n\t\t\t\t\tmatchedRoute = this.routes.find(r => r.when === component)\n\t\t\t\t\tif (matchedRoute) {\n\t\t\t\t\t\tcomponent = matchedRoute.component\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If component is a lazy function and we don't have a matched route yet,\n\t\t\t\t// resolve it to find the route by tag name\n\t\t\t\tif (\n\t\t\t\t\t!matchedRoute &&\n\t\t\t\t\ttypeof component === 'function' &&\n\t\t\t\t\t('preload' in component || '_promise' in component || '_module' in component)\n\t\t\t\t) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst module = await (component as unknown as () => Promise<{ default: CustomElementConstructor }>)()\n\t\t\t\t\t\tcomponent = module.default\n\t\t\t\t\t\t// Now find route by tag name\n\t\t\t\t\t\tconst tagName = customElements.getName(component as CustomElementConstructor)\n\t\t\t\t\t\tif (tagName && this.routes) {\n\t\t\t\t\t\t\tmatchedRoute = this.routes.find(r => r.when === tagName)\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tconsole.error(`[${this.name}] Lazy load failed:`, e)\n\t\t\t\t\t\treturn { ...action, component: null, matchedRoute: undefined }\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If component is HTMLElement, find by tag name\n\t\t\t\tif (!matchedRoute && component instanceof HTMLElement && this.routes) {\n\t\t\t\t\tconst tagName = component.tagName.toLowerCase()\n\t\t\t\t\tmatchedRoute = this.routes.find(r => r.when === tagName)\n\t\t\t\t}\n\n\t\t\t\treturn { ...action, component, matchedRoute }\n\t\t\t}),\n\n\t\t\t// Step 2: Check route guards\n\t\t\tswitchMap(route => {\n\t\t\t\tif (!route.matchedRoute?.guard) {\n\t\t\t\t\treturn of(route)\n\t\t\t\t}\n\n\t\t\t\treturn route.matchedRoute.guard.pipe(\n\t\t\t\t\tswitchMap(guardResult => {\n\t\t\t\t\t\tif (guardResult === true) {\n\t\t\t\t\t\t\treturn of(route)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Guard failed, dispatch redirect event\n\t\t\t\t\t\tconst redirectEvent = new CustomEvent('redirect', {\n\t\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\t\tblockedRoute: route.matchedRoute?.when || 'unknown',\n\t\t\t\t\t\t\t\tarea: this.name,\n\t\t\t\t\t\t\t\tparams: route.params || {},\n\t\t\t\t\t\t\t\tstate: route.state || {},\n\t\t\t\t\t\t\t\tredirectTarget: typeof guardResult === 'object' ? guardResult : undefined,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\t\tcomposed: true,\n\t\t\t\t\t\t})\n\t\t\t\t\t\troute.matchedRoute.dispatchEvent(redirectEvent)\n\n\t\t\t\t\t\treturn EMPTY\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t}),\n\n\t\t\t// Step 3: Load lazy components (after guard check for performance)\n\t\t\tswitchMap(async route => {\n\t\t\t\tlet component = route.component\n\n\t\t\t\tif (\n\t\t\t\t\ttypeof component === 'function' &&\n\t\t\t\t\t('preload' in component || '_promise' in component || '_module' in component)\n\t\t\t\t) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst module = await (component as unknown as () => Promise<{ default: CustomElementConstructor }>)()\n\t\t\t\t\t\tcomponent = module.default\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tconsole.error(`[${this.name}] Lazy load failed:`, e)\n\t\t\t\t\t\treturn { ...route, component: null }\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn { ...route, component }\n\t\t\t}),\n\n\t\t\t// Step 4: Create unique key for deduplication\n\t\t\tmap(route => {\n\t\t\t\tlet identifier = ''\n\t\t\t\tconst component = route.component\n\n\t\t\t\tif (!component || component === '') {\n\t\t\t\t\tidentifier = 'null'\n\t\t\t\t} else if (typeof component === 'string') {\n\t\t\t\t\tidentifier = component\n\t\t\t\t} else if (component instanceof HTMLElement) {\n\t\t\t\t\tidentifier = component.tagName.toLowerCase()\n\t\t\t\t} else if (typeof component === 'function') {\n\t\t\t\t\tidentifier = component.name || 'CustomElement'\n\t\t\t\t}\n\n\t\t\t\tconst key = `${identifier}${JSON.stringify(route.params)}${JSON.stringify(route.state)}${JSON.stringify(route.props)}`\n\n\t\t\t\treturn { ...route, key, tagName: identifier }\n\t\t\t}),\n\n\t\t\t// Step 5: Deduplicate navigation requests\n\t\t\tdistinctUntilChanged((a, b) => a.key === b.key),\n\n\t\t\t// Step 6: Create DOM element from component\n\t\t\tmap(route => {\n\t\t\t\tlet element: HTMLElement | null = null\n\t\t\t\tconst component = route.component\n\n\t\t\t\tif (!component || component === '') {\n\t\t\t\t\telement = null\n\t\t\t\t} else if (typeof component === 'string') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\telement = document.createElement(component)\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tconsole.error(`[${this.name}] Failed to create element:`, component)\n\t\t\t\t\t}\n\t\t\t\t} else if (component instanceof HTMLElement) {\n\t\t\t\t\telement = component\n\t\t\t\t} else if (typeof component === 'function') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\telement = new (component as CustomElementConstructor)()\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tconsole.error(`[${this.name}] Failed to instantiate:`, e)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply properties\n\t\t\t\tif (element) {\n\t\t\t\t\tif (route.params) Object.assign(element, route.params)\n\t\t\t\t\tif (route.props) Object.assign(element, route.props)\n\t\t\t\t\tif (route.state) (element as any).state = route.state\n\t\t\t\t}\n\n\t\t\t\treturn { element, route }\n\t\t\t}),\n\n\t\t\tshareReplay(1),\n\n\t\t\t// Step 7: Swap components in DOM and update history\n\t\t\ttap(({ element, route }) => this.swapComponents(element, route)),\n\n\t\t\t// Performance: measure navigation duration\n\t\t\ttap(() => {\n\t\t\t\tperformance.mark(`area-${this.name}-nav-end`)\n\t\t\t\tperformance.measure(`area-${this.name}-navigation`, `area-${this.name}-nav-start`, `area-${this.name}-nav-end`)\n\t\t\t}),\n\n\t\t\tcatchError(error => {\n\t\t\t\tconsole.error(`[${this.name}] Navigation error:`, error)\n\t\t\t\treturn EMPTY\n\t\t\t}),\n\n\t\t\ttakeUntil(this.disconnecting)\n\t\t)\n\t\t.subscribe()\n\t}\n\n\n\t/**\n\t * Swap components with animation\n\t */\n\tprivate swapComponents(newComponent: HTMLElement | null, routeAction: RouteAction) {\n\t\t// Find current routed component (not route definitions)\n\t\tconst oldComponent = Array.from(this.children).find(\n\t\t\tchild => !(child instanceof SchmancyRoute)\n\t\t) as HTMLElement | undefined\n\n\t\t// Clear if no new component\n\t\tif (!newComponent) {\n\t\t\toldComponent?.remove()\n\t\t\treturn\n\t\t}\n\n\t\t// Get animation duration (0 = instant, default = 150ms)\n\t\tconst duration = routeAction.animationDuration ?? 150\n\n\t\t// Animate transition (or instant swap if duration is 0)\n\t\tif (duration === 0) {\n\t\t\t// Instant swap - no animation\n\t\t\toldComponent?.remove()\n\t\t\tthis.appendChild(newComponent)\n\t\t} else if (oldComponent) {\n\t\t\t// GPU optimization: promote layers before animation\n\t\t\toldComponent.style.willChange = 'opacity'\n\t\t\tnewComponent.style.willChange = 'opacity'\n\t\t\t// Skip paint for outgoing component\n\t\t\toldComponent.style.contentVisibility = 'hidden'\n\n\t\t\t// Animated swap - fade out old, then fade in new\n\t\t\tconst fadeOut = oldComponent.animate([{ opacity: 1 }, { opacity: 0 }], { duration, easing: 'ease-out' })\n\t\t\tfadeOut.onfinish = () => {\n\t\t\t\toldComponent.remove()\n\t\t\t\tthis.appendChild(newComponent)\n\t\t\t\tconst fadeIn = newComponent.animate([{ opacity: 0 }, { opacity: 1 }], { duration, easing: 'ease-in' })\n\t\t\t\tfadeIn.onfinish = () => {\n\t\t\t\t\t// Clean up GPU layer promotion\n\t\t\t\t\tnewComponent.style.willChange = 'auto'\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// No old component - just fade in new\n\t\t\tnewComponent.style.willChange = 'opacity'\n\t\t\tthis.appendChild(newComponent)\n\t\t\tconst fadeInDuration = duration > 100 ? Math.max(100, duration * 0.66) : duration\n\t\t\tconst fadeIn = newComponent.animate([{ opacity: 0 }, { opacity: 1 }], { duration: fadeInDuration, easing: 'ease-in' })\n\t\t\tfadeIn.onfinish = () => {\n\t\t\t\tnewComponent.style.willChange = 'auto'\n\t\t\t}\n\t\t}\n\n\t\t// Update area state\n\t\tconst activeRoute: ActiveRoute = {\n\t\t\tcomponent: newComponent.tagName.toLowerCase(),\n\t\t\tstate: routeAction.state || {},\n\t\t\tarea: this.name,\n\t\t\tparams: routeAction.params || {},\n\t\t\tprops: routeAction.props || {},\n\t\t}\n\n\t\tarea.current.set(this.name, activeRoute)\n\t\tarea.$current.next(area.current)\n\n\t\t// Update browser history\n\t\tif (area.enableHistoryMode) {\n\t\t\tarea._updateBrowserHistory(\n\t\t\t\tthis.name,\n\t\t\t\tactiveRoute,\n\t\t\t\trouteAction.historyStrategy || HISTORY_STRATEGY.push,\n\t\t\t\trouteAction.clearQueryParams,\n\t\t\t\trouteAction.path\n\t\t\t)\n\t\t}\n\t}\n\n\tdisconnectedCallback() {\n\t\tsuper.disconnectedCallback()\n\t\tarea.pop(this.name)\n\t}\n\n\trender() {\n\t\treturn html`<slot></slot>`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-area': SchmancyArea\n\t}\n}\n","export function encodeData(data: string): string {\n\treturn btoa(data)\n}\n\nexport function decodeData(encodedData: string): string {\n\treturn atob(encodedData)\n}\n","import { RouteComponent } from './route.component'\nimport { RouteAction, ActiveRoute } from './router.types'\n\n/**\n * Compare two custom element constructors for equality\n * @param constructor1 First constructor to compare\n * @param constructor2 Second constructor to compare\n * @returns true if constructors are functionally equivalent\n */\nexport function compareCustomElementConstructors(\n\tconstructor1: CustomElementConstructor | Function,\n\tconstructor2: CustomElementConstructor | Function,\n): boolean {\n\t// Quick reference check\n\tif (constructor1 === constructor2) {\n\t\treturn true\n\t}\n\n\t// Check if both are functions\n\tif (typeof constructor1 !== 'function' || typeof constructor2 !== 'function') {\n\t\treturn false\n\t}\n\n\t// Compare by name (handles minification)\n\tif (constructor1.name && constructor2.name && constructor1.name === constructor2.name) {\n\t\treturn true\n\t}\n\n\t// Compare observed attributes if available\n\tconst obs1 = (constructor1 as any).observedAttributes\n\tconst obs2 = (constructor2 as any).observedAttributes\n\n\tif (obs1 && obs2) {\n\t\tif (Array.isArray(obs1) && Array.isArray(obs2)) {\n\t\t\tif (obs1.length !== obs2.length) return false\n\t\t\treturn obs1.every((attr, i) => attr === obs2[i])\n\t\t}\n\t}\n\n\t// Try to compare prototypes\n\ttry {\n\t\tconst proto1 = constructor1.prototype\n\t\tconst proto2 = constructor2.prototype\n\n\t\t// Check if they have the same prototype chain\n\t\tif (Object.getPrototypeOf(proto1) === Object.getPrototypeOf(proto2)) {\n\t\t\t// Check if they have the same property names\n\t\t\tconst keys1 = Object.getOwnPropertyNames(proto1).sort()\n\t\t\tconst keys2 = Object.getOwnPropertyNames(proto2).sort()\n\n\t\t\treturn keys1.length === keys2.length && keys1.every((key, i) => key === keys2[i])\n\t\t}\n\t} catch {\n\t\t// Ignore prototype access errors\n\t}\n\n\treturn false\n}\n\n/**\n * Normalize a component tag name for comparison\n * @param tagName Tag name to normalize\n * @returns Normalized tag name\n */\nexport function normalizeTagName(tagName: string): string {\n\treturn tagName.toLowerCase().replace(/[^a-z0-9]/g, '') // Remove all non-alphanumeric characters\n}\n\n/**\n * Get tag name from a component\n * @param component Component to get tag name from\n * @returns Tag name or null if unable to determine\n */\nexport function getTagName(component: RouteComponent): string | null {\n\tif (typeof component === 'string') {\n\t\treturn component.toLowerCase()\n\t}\n\n\tif (component instanceof HTMLElement) {\n\t\treturn component.tagName.toLowerCase()\n\t}\n\n\tif (typeof component === 'function') {\n\t\t// Try to get custom element name from constructor\n\t\tconst name = component.name\n\t\tif (name) {\n\t\t\t// Convert PascalCase to kebab-case\n\t\t\treturn name\n\t\t\t\t.replace(/([A-Z])/g, '-$1')\n\t\t\t\t.toLowerCase()\n\t\t\t\t.replace(/^-/, '')\n\t\t}\n\t}\n\n\treturn null\n}\n\n/**\n * Deep merge two objects\n * @param target Target object\n * @param source Source object to merge\n * @returns Merged object\n */\nexport function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T {\n\tconst output = { ...target }\n\n\tfor (const key in source) {\n\t\tif (source.hasOwnProperty(key)) {\n\t\t\tconst sourceValue = source[key]\n\t\t\tconst targetValue = output[key]\n\n\t\t\tif (isObject(sourceValue) && isObject(targetValue)) {\n\t\t\t\toutput[key] = deepMerge(targetValue, sourceValue)\n\t\t\t} else {\n\t\t\t\toutput[key] = sourceValue as T[Extract<keyof T, string>]\n\t\t\t}\n\t\t}\n\t}\n\n\treturn output\n}\n\n/**\n * Check if value is a plain object\n * @param obj Value to check\n * @returns true if value is a plain object\n */\nexport function isObject(obj: any): obj is Record<string, any> {\n\treturn (\n\t\tobj !== null &&\n\t\ttypeof obj === 'object' &&\n\t\tobj.constructor === Object &&\n\t\tObject.prototype.toString.call(obj) === '[object Object]'\n\t)\n}\n\n/**\n * Debounce a function\n * @param func Function to debounce\n * @param wait Wait time in milliseconds\n * @returns Debounced function\n */\nexport function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void {\n\tlet timeout: ReturnType<typeof setTimeout> | null = null\n\n\treturn function (this: any, ...args: Parameters<T>) {\n\t\tconst context = this\n\n\t\tif (timeout !== null) {\n\t\t\tclearTimeout(timeout)\n\t\t}\n\n\t\ttimeout = setTimeout(() => {\n\t\t\tfunc.apply(context, args)\n\t\t\ttimeout = null\n\t\t}, wait)\n\t}\n}\n\n/**\n * Create a URL-safe string from route state\n * @param state Route state object\n * @returns URL-safe encoded string\n */\nexport function encodeRouteState(state: Record<string, unknown>): string {\n\ttry {\n\t\tconst json = JSON.stringify(state)\n\t\treturn encodeURIComponent(json)\n\t} catch (error) {\n\t\tconsole.error('Failed to encode route state:', error)\n\t\treturn ''\n\t}\n}\n\n/**\n * Decode a URL-safe string to route state\n * @param encoded Encoded string\n * @returns Decoded route state or empty object\n */\nexport function decodeRouteState(encoded: string): Record<string, unknown> {\n\tif (!encoded) return {}\n\n\ttry {\n\t\tconst decoded = decodeURIComponent(encoded)\n\t\tconst parsed = JSON.parse(decoded)\n\n\t\tif (isObject(parsed)) {\n\t\t\treturn parsed\n\t\t}\n\t} catch (error) {\n\t\tconsole.error('Failed to decode route state:', error)\n\t}\n\n\treturn {}\n}\n\n/**\n * Compare two route actions for equality\n * @param a First route action\n * @param b Second route action\n * @returns true if route actions are equal\n */\nexport function compareRouteActions(a: RouteAction, b: RouteAction): boolean {\n\t// Compare areas\n\tif (a.area !== b.area) return false\n\n\t// Compare components\n\tif (typeof a.component !== typeof b.component) return false\n\n\tif (typeof a.component === 'string' && typeof b.component === 'string') {\n\t\tif (normalizeTagName(a.component) !== normalizeTagName(b.component)) {\n\t\t\treturn false\n\t\t}\n\t} else if (typeof a.component === 'function' && typeof b.component === 'function') {\n\t\tif (!compareCustomElementConstructors(a.component, b.component)) {\n\t\t\treturn false\n\t\t}\n\t} else if (a.component !== b.component) {\n\t\treturn false\n\t}\n\n\t// Compare state\n\tif (JSON.stringify(a.state || {}) !== JSON.stringify(b.state || {})) {\n\t\treturn false\n\t}\n\n\t// Compare params\n\tif (JSON.stringify(a.params || {}) !== JSON.stringify(b.params || {})) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n/**\n * Compare two active routes for equality\n * @param a First active route\n * @param b Second active route\n * @returns true if active routes are equal\n */\nexport function compareActiveRoutes(a: ActiveRoute, b: ActiveRoute): boolean {\n\treturn (\n\t\ta.area === b.area &&\n\t\ta.component === b.component &&\n\t\tJSON.stringify(a.state || {}) === JSON.stringify(b.state || {}) &&\n\t\tJSON.stringify(a.params || {}) === JSON.stringify(b.params || {})\n\t)\n}\n\n/**\n * Create a cache key from a route action\n * @param route Route action\n * @returns Cache key string\n */\nexport function createRouteCacheKey(route: RouteAction): string {\n\tconst tagName = getTagName(route.component) || 'unknown'\n\tconst stateHash = simpleHash(JSON.stringify(route.state || {}))\n\tconst paramsHash = simpleHash(JSON.stringify(route.params || {}))\n\n\treturn `${route.area}:${tagName}:${stateHash}:${paramsHash}`\n}\n\n/**\n * Simple hash function for creating cache keys\n * @param str String to hash\n * @returns Hash string\n */\nfunction simpleHash(str: string): string {\n\tlet hash = 0\n\n\tfor (let i = 0; i < str.length; i++) {\n\t\tconst char = str.charCodeAt(i)\n\t\thash = (hash << 5) - hash + char\n\t\thash = hash & hash // Convert to 32-bit integer\n\t}\n\n\treturn Math.abs(hash).toString(36)\n}\n\n/**\n * Sanitize route state to remove sensitive data\n * @param state Route state\n * @param keysToRemove Keys to remove from state\n * @returns Sanitized state\n */\nexport function sanitizeRouteState(\n\tstate: Record<string, unknown>,\n\tkeysToRemove: string[] = ['password', 'token', 'secret', 'apiKey'],\n): Record<string, unknown> {\n\tconst sanitized: Record<string, unknown> = {}\n\n\tfor (const key in state) {\n\t\tif (state.hasOwnProperty(key) && !keysToRemove.includes(key)) {\n\t\t\tconst value = state[key]\n\n\t\t\tif (isObject(value)) {\n\t\t\t\tsanitized[key] = sanitizeRouteState(value, keysToRemove)\n\t\t\t} else if (Array.isArray(value)) {\n\t\t\t\tsanitized[key] = value.map(item => (isObject(item) ? sanitizeRouteState(item, keysToRemove) : item))\n\t\t\t} else {\n\t\t\t\tsanitized[key] = value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn sanitized\n}\n\n/**\n * Extract query parameters from URL\n * @param url URL string or URLSearchParams\n * @returns Object with query parameters\n */\nexport function extractQueryParams(url?: string | URLSearchParams): Record<string, string> {\n\tconst params: Record<string, string> = {}\n\n\tlet searchParams: URLSearchParams\n\n\tif (url instanceof URLSearchParams) {\n\t\tsearchParams = url\n\t} else if (typeof url === 'string') {\n\t\tconst urlObj = new URL(url, window.location.origin)\n\t\tsearchParams = urlObj.searchParams\n\t} else {\n\t\tsearchParams = new URLSearchParams(window.location.search)\n\t}\n\n\tsearchParams.forEach((value, key) => {\n\t\tparams[key] = value\n\t})\n\n\treturn params\n}\n\n/**\n * Build query string from parameters object\n * @param params Parameters object\n * @returns Query string with leading '?'\n */\nexport function buildQueryString(params: Record<string, string | number | boolean>): string {\n\tconst searchParams = new URLSearchParams()\n\n\tfor (const key in params) {\n\t\tif (params.hasOwnProperty(key)) {\n\t\t\tconst value = params[key]\n\t\t\tif (value !== undefined && value !== null && value !== '') {\n\t\t\t\tsearchParams.set(key, String(value))\n\t\t\t}\n\t\t}\n\t}\n\n\tconst queryString = searchParams.toString()\n\treturn queryString ? `?${queryString}` : ''\n}\n"],"mappings":"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AAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA,CAAA,OAAA,eAAA,QAAA,IAAA,CAAA,WAAA,CAAA,EAAA,IAAA,UAAA,CAAA,OAAA,GAAA,CAAA"}