@asd20/ui-next 2.32.2 → 2.33.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ # [2.33.0](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.32.2...ui-next-v2.33.0) (2026-10-20)
4
+
5
+
6
+ ### Features
7
+
8
+ * breadcrumbs now reflect previous wayfinding page if applicable; otherwise use current heirarchy ([d48b8ac](https://github.com/academydistrict20/asd20-ui-next/commit/d48b8ac0057c5a73b3f358f250025be822e78ef1))
9
+
3
10
  ## [2.32.2](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.32.1...ui-next-v2.32.2) (2026-10-14)
4
11
 
5
12
 
package/README.md CHANGED
@@ -35,6 +35,27 @@ multi-repo contract, not as an app-local component folder.
35
35
  - Unit test runner: Vitest
36
36
  - Component development: Storybook 8 with its retained webpack 5 builder
37
37
 
38
+ ## Breadcrumb Navigation
39
+
40
+ Website templates accept an optional `breadcrumbContext` page reference supplied
41
+ by the website's client navigation tracker. A visitor arriving from a wayfinding
42
+ page sees that section in the breadcrumb when the destination is one of its
43
+ message detail links or related pages. The context can continue between related
44
+ detail pages and is cleared when the visitor leaves that section.
45
+
46
+ Context is stored with the browser history entry, so refresh and Back/Forward
47
+ can restore the context of that visit. Native same-tab links can also carry a short-lived
48
+ arrival record when the referring page confirms the transition. Direct visits,
49
+ unknown origins, unavailable browser storage, and discarded history state fall
50
+ back to existing breadcrumbs. Context is restored after hydration.
51
+
52
+ Only the header links change. URLs, Related Pages, `parentPage`, dates,
53
+ categories, and the existing announcement/story navigation retain their behavior.
54
+ There is no per-page editor setting or additional breadcrumb data request.
55
+
56
+ Rollout requires releasing this UI package, updating the website's UI dependency,
57
+ and deploying the website integration. CommCenter and the database need no changes.
58
+
38
59
  ## Public Entry Points
39
60
 
40
61
  Supported import paths are defined in `package.json` and guarded by
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asd20/ui-next",
3
- "version": "2.32.2",
3
+ "version": "2.33.0",
4
4
  "private": false,
5
5
  "description": "ASD20 UI component library for Vue 3.",
6
6
  "license": "MIT",
@@ -0,0 +1,42 @@
1
+ function localPath(value) {
2
+ if (typeof value !== 'string' || !value.startsWith('/') ||
3
+ value.startsWith('//') || /[\\\s]/.test(value)) return null
4
+ try {
5
+ return new URL(value, 'https://breadcrumb.local').pathname.replace(/\/+$/, '') || '/'
6
+ } catch { return null }
7
+ }
8
+
9
+ function isBreadcrumbContext(page, { id, path, organization }) {
10
+ const parentPath = localPath(page?.path?.path)
11
+ return Boolean(parentPath && typeof (page.name || page.title) === 'string' && (page.name || page.title) &&
12
+ (!id || page.id !== id) && (!path || parentPath !== localPath(path)) &&
13
+ (!page.status || page.status === 'Published') &&
14
+ (!organization?.id || !page.ownerOrganizationId ||
15
+ organization.id === page.ownerOrganizationId))
16
+ }
17
+
18
+ function textLabel(value) {
19
+ return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
20
+ }
21
+
22
+ // Visit-specific context affects only the links displayed in the page header.
23
+ export function buildBreadcrumbLinks({
24
+ breadcrumbContext,
25
+ parentPage,
26
+ id,
27
+ path,
28
+ organization,
29
+ } = {}) {
30
+ const parent = isBreadcrumbContext(breadcrumbContext, { id, path, organization })
31
+ ? breadcrumbContext
32
+ : parentPage
33
+ if (!parent?.path?.path) return []
34
+
35
+ const links = parent.path.path === '/' ? [] : [{ url: '/', label: 'Home' }]
36
+ const label = parent.name || parent.title
37
+ links.push({
38
+ url: parent.path.path,
39
+ label: parent === breadcrumbContext ? textLabel(label) : label,
40
+ })
41
+ return links
42
+ }
@@ -214,6 +214,7 @@ export default function mapPageQueryResultToPageTemplateProps(
214
214
  pageTypeId: pageData.pageTypeId,
215
215
  factoids: pageData.factoids,
216
216
  parentPage: pageData.parentPage,
217
+ breadcrumbContext: pageData.breadcrumbContext || null,
217
218
  relatedPages: pageData.relatedPages
218
219
  ? pageData.relatedPages.map(p => {
219
220
  const page = _get(p, 'page[0]')
@@ -1,4 +1,5 @@
1
1
  import responsiveBreakpointMixin from './responsiveBreakpointMixin'
2
+ import { buildBreadcrumbLinks } from '../helpers/breadcrumbLinks'
2
3
 
3
4
  function getMessageBodyHtml(message) {
4
5
  return (message && (message.bodyContent || message.bodyHtml)) || ''
@@ -81,6 +82,7 @@ export default {
81
82
  navigation: { type: Array, default: () => [] },
82
83
  actionItems: { type: Array, default: () => [] },
83
84
  parentPage: { type: Object, default: null },
85
+ breadcrumbContext: { type: Object, default: null },
84
86
  quickLinks: { type: Array, default: () => [] },
85
87
  socialLinks: { type: Array, default: () => [] },
86
88
  disclosureLinks: { type: Array, default: () => [] },
@@ -434,18 +436,13 @@ export default {
434
436
  },
435
437
 
436
438
  breadcrumbLinks() {
437
- let links =
438
- this.parentPage && this.parentPage.path.path !== '/'
439
- ? [{ url: '/', label: 'Home' }]
440
- : []
441
- if (this.parentPage) {
442
- links.push({
443
- url: this.parentPage.path.path,
444
- label: this.parentPage.name || this.parentPage.title,
445
- })
446
- }
447
-
448
- return links
439
+ return buildBreadcrumbLinks({
440
+ breadcrumbContext: this.breadcrumbContext,
441
+ parentPage: this.parentPage,
442
+ id: this.id,
443
+ path: this.path,
444
+ organization: this.organization,
445
+ })
449
446
  },
450
447
 
451
448
  publishDateTime() {