@excom/spa-route 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.rush/temp/chunked-rush-logs/spa-route.apply-exports.chunks.jsonl +1 -0
  2. package/.rush/temp/chunked-rush-logs/spa-route.build_docs.chunks.jsonl +1 -0
  3. package/.rush/temp/chunked-rush-logs/spa-route.build_package-metas.chunks.jsonl +1 -0
  4. package/.rush/temp/operation/apply-exports/all.log +1 -0
  5. package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
  6. package/.rush/temp/operation/apply-exports/state.json +3 -0
  7. package/.rush/temp/operation/build_docs/all.log +1 -0
  8. package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
  9. package/.rush/temp/operation/build_docs/state.json +3 -0
  10. package/.rush/temp/operation/build_package-metas/all.log +1 -0
  11. package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
  12. package/.rush/temp/operation/build_package-metas/state.json +3 -0
  13. package/.rush/temp/shrinkwrap-deps.json +3 -0
  14. package/config/rig.json +5 -0
  15. package/index.css +5 -0
  16. package/index.ts +29 -0
  17. package/package.json +48 -0
  18. package/rush-logs/spa-route.apply-exports.cache.log +1 -0
  19. package/rush-logs/spa-route.apply-exports.log +1 -0
  20. package/rush-logs/spa-route.build_docs.cache.log +1 -0
  21. package/rush-logs/spa-route.build_docs.log +1 -0
  22. package/rush-logs/spa-route.build_package-metas.cache.log +1 -0
  23. package/rush-logs/spa-route.build_package-metas.log +1 -0
  24. package/spa-a.ts +124 -0
  25. package/spa-manager.ts +605 -0
  26. package/spa-route.ts +322 -0
  27. package/src/spa-route.css +24 -0
  28. package/src/utils.ts +31 -0
  29. package/support/custom-elements.json +953 -0
  30. package/support/dist-docs/spa-a.md +40 -0
  31. package/support/dist-docs/spa-manager.md +66 -0
  32. package/support/dist-docs/spa-route.md +408 -0
  33. package/support/docs/README.md +314 -0
  34. package/support/package-meta.json +789 -0
  35. package/support/tests/spa-navigation.test.ts +1076 -0
  36. package/support/tests/spa-route.test.ts +766 -0
  37. package/support/tests/spa-title.test.ts +225 -0
  38. package/tsconfig.json +5 -0
@@ -0,0 +1,314 @@
1
+ # spa-route
2
+
3
+ Build a full SPA from HTML alone — screens, links, and view transitions.
4
+
5
+ > This site is a live demo... inspect its HTML! Other live demos of spa-route coming soon.
6
+
7
+ ```html
8
+ <spa-manager>
9
+ <spa-route route-href="/" template-ref="/views/home.html"></spa-route>
10
+ <spa-route route-href="/about" template-ref="/views/about.html"></spa-route>
11
+ </spa-manager>
12
+
13
+ <nav>
14
+ <spa-a route-href="/">Home</spa-a>
15
+ <spa-a route-href="/about">About</spa-a>
16
+ </nav>
17
+ ```
18
+
19
+ ## Features
20
+
21
+ - **Pure CSS View Transitions** Write CSS, get beautiful animations between routes
22
+ - **Active / was-active** Style current and outgoing links & screens (nav chrome, card expansion)
23
+ - **Same-route reuse / refresh** Keep or rebuild the view when only params change
24
+ - **Scroll reset / restore** Per-axis control for push, replace, back, forward
25
+ - **Nested layouts** Keep a parent route mounted under child paths
26
+ - **404 fallbacks** Catch-alls that only fire when nothing else matched
27
+ - **Per-route document title** `document.title` follows the active route
28
+ - **History actions** Push, replace, back, forward from a link
29
+
30
+ ## Installation
31
+
32
+ <include-content is-active template-ref="/views/install-section/install-section.html"></include-content>
33
+
34
+ ## Usage
35
+
36
+ Wrap screens in `<spa-manager>`, give each `<spa-route>` a `route-href`, and link with `<spa-a>`.
37
+
38
+ ```html
39
+ <!-- Optional SPA manager for View Transitions and batched router config -->
40
+ <spa-manager>
41
+ <!-- SPA routing -->
42
+ <spa-route route-href="/" template-ref="/views/home.html"></spa-route>
43
+ <spa-route route-href="/about" template-ref="/views/about.html"></spa-route>
44
+ </spa-manager>
45
+ <nav>
46
+ <!-- SPA links -->
47
+ <spa-a route-href="/">Home</spa-a>
48
+ <spa-a route-href="/about">About</spa-a>
49
+ </nav>
50
+ ```
51
+
52
+ ### API Reference
53
+
54
+ <include-content is-active template-ref="/views/api-reference/api-reference.html"></include-content>
55
+
56
+ ### Examples
57
+
58
+ #### Minimal SPA
59
+
60
+ Three routes, three links. Active links style via `spa-a[is-active]`.
61
+
62
+ ```html
63
+ <spa-manager>
64
+ <nav>
65
+ <spa-a route-href="/home">Home</spa-a>
66
+ <spa-a route-href="/users">Users</spa-a>
67
+ <spa-a route-href="/about">About</spa-a>
68
+ <spa-a route-href="/contact">Contact</spa-a>
69
+ </nav>
70
+ <spa-route route-href="/home">
71
+ <template>
72
+ <h3>Welcome</h3>
73
+ <p>Mounted because the URL matched <code>/home</code>.</p>
74
+ </template>
75
+ </spa-route>
76
+ <spa-route route-href="/users">
77
+ <template>
78
+ <h3>Users</h3>
79
+ <ul>
80
+ <li>Adam</li>
81
+ <li>Linus</li>
82
+ <li>Grace</li>
83
+ </ul>
84
+ </template>
85
+ </spa-route>
86
+ <spa-route route-href="/about" template-ref="/this/view/is/remote.html"></spa-route>
87
+ <spa-route route-href="/contact" template-ref="#this-view-is-dom-selected"></spa-route>
88
+ </spa-manager>
89
+
90
+ <template id="this-view-is-dom-selected">foo@bar.com</template>
91
+ ```
92
+
93
+ ```css
94
+ spa-a[is-active] {
95
+ font-weight: bold;
96
+ pointer-events: none;
97
+ text-decoration: none;
98
+ }
99
+ ```
100
+
101
+ #### Nested layout & 404
102
+
103
+ `match-nested` keeps a layout mounted under child paths. `is-fallback` with `route-regex=".*"` is a 404 that only activates when no preceding sibling matched.
104
+
105
+ ```html
106
+ <spa-manager>
107
+ <nav>
108
+ <spa-a route-href="/users">Users list</spa-a>
109
+ <spa-a route-href="/users/42">User 42</spa-a>
110
+ <spa-a route-href="/missing">Missing page</spa-a>
111
+ </nav>
112
+ <spa-route route-href="/users" match-nested>
113
+ <template>
114
+ <section>
115
+ <h3>Users layout</h3>
116
+ <spa-manager>
117
+ <spa-route route-href="/users">
118
+ <template><p>List of users.</p></template>
119
+ </spa-route>
120
+ <spa-route route-href="/users/:id">
121
+ <template><p>Detail for a single user.</p></template>
122
+ </spa-route>
123
+ </spa-manager>
124
+ </section>
125
+ </template>
126
+ </spa-route>
127
+ <spa-route route-regex=".*?view=admin.*" template-ref="/views/admin-sidebar.html"></spa-route>
128
+ <spa-route route-regex=".*" is-fallback>
129
+ <template>
130
+ <section>
131
+ <h3>404</h3>
132
+ <p>Catch-all — only when no preceding sibling matched.</p>
133
+ </section>
134
+ </template>
135
+ </spa-route>
136
+ </spa-manager>
137
+ ```
138
+
139
+ #### Document title
140
+
141
+ `document-title` sets `document.title` while its route is active. It keys off
142
+ activation, not clicks, so cold loads and back / forward retitle too. The
143
+ outermost `<spa-manager>` applies the last active route carrying one — a
144
+ nested route beats its ancestor — and restores the page's own `<title>` once
145
+ no active route has a title.
146
+
147
+ ```html
148
+ <title>Nucleus · docs</title>
149
+
150
+ <spa-manager>
151
+ <spa-route route-href="/" document-title="My company">
152
+ <template><p>The company page.</p></template>
153
+ </spa-route>
154
+ <!-- untitled: the page's own <title> comes back -->
155
+ <spa-route route-href="/docs">
156
+ <template><p>The docs.</p></template>
157
+ </spa-route>
158
+ </spa-manager>
159
+ ```
160
+
161
+ #### History actions
162
+
163
+ `route-action="back"` / `"forward"` walk history; `"replace"` swaps the current entry instead of pushing.
164
+
165
+ ```html
166
+ <spa-manager>
167
+ <nav>
168
+ <spa-a route-action="back">‹ Back</spa-a>
169
+ <spa-a route-action="forward">Forward ›</spa-a>
170
+ <spa-a route-href="/one">Push /one</spa-a>
171
+ <spa-a route-href="/two">Push /two</spa-a>
172
+ <spa-a route-href="/login" route-action="replace">
173
+ Replace with /login
174
+ </spa-a>
175
+ </nav>
176
+ <spa-route route-href="/one">
177
+ <template><p>You're on <code>/one</code>.</p></template>
178
+ </spa-route>
179
+ <spa-route route-href="/two">
180
+ <template><p>You're on <code>/two</code>.</p></template>
181
+ </spa-route>
182
+ <spa-route route-href="/login">
183
+ <template>
184
+ <p>You're on <code>/login</code> — this entry replaced the
185
+ previous one in history.</p>
186
+ </template>
187
+ </spa-route>
188
+ </spa-manager>
189
+ ```
190
+
191
+ #### View Transitions
192
+
193
+ `<spa-manager>` wraps each navigation in `document.startViewTransition()` (when supported). Style with `::view-transition-*`; set per-link types via `transition-types` (e.g. card expansion); opt a route out with `no-transition`.
194
+
195
+ ```css
196
+ ::view-transition-old(root),
197
+ ::view-transition-new(root) {
198
+ animation-duration: 0.25s;
199
+ }
200
+ ```
201
+
202
+ #### View Transitions - Localized
203
+ If you had a list of cards, and clicking on one expanded it to the detail view (and vice versa, contracting), you would achieve it similarly to the code example below. This technique relies on styling the `<spa-a>` with its `[is-active]` (incoming view) and `[was-active]` (outgoing view).
204
+
205
+ ```html
206
+ <spa-manager>
207
+ <spa-route id="route-list" route-href="/list">
208
+ <template>
209
+ <spa-a route-href="/detail/123" transition-types="card-morph" class="mini-card">
210
+ Go to detail
211
+ </spa-a>
212
+ </template>
213
+ </spa-route>
214
+ <spa-route id="route-detail" route-href="/detail/:id">
215
+ <template>
216
+ <article id="detail-card" class="card">
217
+ <!-- other content here -->
218
+ </article>
219
+ </template>
220
+ </spa-route>
221
+ </spa-manager>
222
+ ```
223
+
224
+ ```css
225
+ html:active-view-transition-type(card-morph) {
226
+ #route-list spa-a[transition-types="card-morph"][was-active], /* outgoing list card (forward) */
227
+ #route-list spa-a[transition-types="card-morph"][is-active], /* incoming list card (back) */
228
+ #detail-card /* detail card (forward & back) */ {
229
+ contain: layout;
230
+ height: fit-content;
231
+ view-transition-name: card-morph;
232
+ }
233
+ }
234
+ ::view-transition-old(card-morph),
235
+ ::view-transition-new(card-morph) {
236
+ mix-blend-mode: normal;
237
+ height: 100%;
238
+ width: 100%;
239
+ will-change: opacity;
240
+ animation-fill-mode: both;
241
+ }
242
+ ::view-transition-old(card-morph) {
243
+ animation-name: fade-out 1s ease;
244
+ }
245
+ ::view-transition-new(card-morph) {
246
+ animation-name: fade-in 1s ease;
247
+ }
248
+ @keyframes fade-in {
249
+ from { opacity: 0; }
250
+ to { opacity: 1; }
251
+ }
252
+ @keyframes fade-out {
253
+ from { opacity: 1; }
254
+ to { opacity: 0; }
255
+ }
256
+ ```
257
+
258
+ #### Touch edge-swipe
259
+ On touch devices, horizontal drags from within `overscroll-x-threshold` of an edge trigger back / forward. Use `"none"` to block overscroll without navigating. Useful for preventing native swipes in Safari, which visually break SPAs.
260
+
261
+ ```html
262
+ <spa-manager overscroll-behavior-x="navigate"></spa-manager>
263
+ ```
264
+
265
+
266
+ #### Scroll reset / restore
267
+
268
+ By default, `<spa-route>`:
269
+ - resets scroll to top-left on `push` / `replace`
270
+ - restores the saved scroll position on `back` / `forward`
271
+
272
+ Override per axis with `scroll-reset-y` / `scroll-reset-x` — space-separated moves that should reset to `0` (omitted moves restore instead):
273
+
274
+ ```html
275
+ <!-- also reset Y when the user hits back -->
276
+ <spa-route
277
+ route-href="/article/:id"
278
+ scroll-reset-y="push replace back"
279
+ ></spa-route>
280
+ ```
281
+
282
+ Animate with `scroll-reset-behavior="smooth"`. Disable all scroll handling with `scroll-set-disabled`.
283
+
284
+ #### Same-route params
285
+
286
+ When the matched route stays the same but params change (e.g. `/users/1` → `/users/2`):
287
+
288
+ - `same-route="reuse"` (default) — keep the rendered tree, update route data, and let `<spa-manager>` run a View Transition
289
+ - `same-route="refresh"` — tear down and re-render the view
290
+
291
+ ```html
292
+ <spa-route route-href="/users/:id" same-route="refresh">
293
+ <template><!-- fresh tree per user id --></template>
294
+ </spa-route>
295
+
296
+ <spa-route
297
+ route-href="/logs/:view"
298
+ same-route="reuse"
299
+ scroll-set-disabled
300
+ >
301
+ <template><!-- preserve content + scroll across view tabs --></template>
302
+ </spa-route>
303
+ ```
304
+
305
+ #### Transition delay
306
+
307
+ `transition-delay` on `<spa-manager>` waits N ms before starting the batched View Transition — useful when sibling routes need a beat to queue their render/unrender callbacks, or for last-second DOM work.
308
+
309
+ ```html
310
+ <spa-manager transition-delay="50">
311
+ <!-- routes -->
312
+ </spa-manager>
313
+ ```
314
+