@campminder/components 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.
- package/README.md +198 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +11 -0
- package/dist/menu-tree.upstream.test.d.ts +1 -0
- package/dist/property-B5JHHBCF.js +603 -0
- package/dist/side-nav/MegaMenu.d.ts +50 -0
- package/dist/side-nav/MegaMenu.styles.d.ts +33 -0
- package/dist/side-nav/SideNav.d.ts +89 -0
- package/dist/side-nav/SideNav.styles.d.ts +42 -0
- package/dist/side-nav/Utils/helpers.d.ts +57 -0
- package/dist/side-nav/assets/MegaMenuIcons/AccountsGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/AdminGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/AlumniGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/CampInTouchGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/CamperGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/CommunicationGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/DefaultMMIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/FinancialGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/MedicalGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/OpenInNewIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/ReportsGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/SchedulingGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/StaffGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/TravelGrayIcon.d.ts +2 -0
- package/dist/side-nav/assets/MegaMenuIcons/index.d.ts +16 -0
- package/dist/side-nav/assets/SideNavIcons/AccountsIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/AdminIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/AlumniIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/CampInTouch.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/CamperIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/ChevronRightIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/CloseIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/CommunicationIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/DefaultNavIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/FinancialIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/HomeIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/MedicalIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/MenuCollapseIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/MenuIcon.d.ts +10 -0
- package/dist/side-nav/assets/SideNavIcons/ReportsIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/SchedulingIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/StaffIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/TravelIcon.d.ts +2 -0
- package/dist/side-nav/assets/SideNavIcons/index.d.ts +20 -0
- package/dist/side-nav/icon-map.d.ts +17 -0
- package/dist/side-nav/index.d.ts +5 -0
- package/dist/side-nav/mega-menu-icon-map.d.ts +20 -0
- package/dist/side-nav/mega-menu-layout.d.ts +9 -0
- package/dist/side-nav/mega-menu.test.d.ts +1 -0
- package/dist/side-nav/side-nav.test.d.ts +1 -0
- package/dist/side-nav.d.ts +1 -0
- package/dist/side-nav.js +1198 -0
- package/dist/state-Ns9O6R8g.js +12 -0
- package/dist/super-user-banner/SuperUserBanner.d.ts +43 -0
- package/dist/super-user-banner/SuperUserBanner.styles.d.ts +21 -0
- package/dist/super-user-banner/index.d.ts +2 -0
- package/dist/super-user-banner/super-user-banner.test.d.ts +1 -0
- package/dist/super-user-banner.d.ts +1 -0
- package/dist/super-user-banner.js +178 -0
- package/dist/top-bar/TopBar.d.ts +39 -0
- package/dist/top-bar/TopBar.styles.d.ts +1 -0
- package/dist/top-bar/Utils/helpers.d.ts +3 -0
- package/dist/top-bar/Utils/safe-url.d.ts +56 -0
- package/dist/top-bar/Utils/safe-url.test.d.ts +1 -0
- package/dist/top-bar/Utils/types.d.ts +50 -0
- package/dist/top-bar/assets/TopBarIcons/CheckIcon.d.ts +2 -0
- package/dist/top-bar/assets/TopBarIcons/CrossIcon.d.ts +2 -0
- package/dist/top-bar/assets/TopBarIcons/DropDownIcon.d.ts +2 -0
- package/dist/top-bar/assets/TopBarIcons/InfoIcon.d.ts +2 -0
- package/dist/top-bar/assets/TopBarIcons/OpenInNewIcon.d.ts +2 -0
- package/dist/top-bar/assets/TopBarIcons/index.d.ts +7 -0
- package/dist/top-bar/index.d.ts +3 -0
- package/dist/top-bar/top-bar.test.d.ts +1 -0
- package/dist/top-bar.d.ts +1 -0
- package/dist/top-bar.js +615 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# @campminder/components
|
|
2
|
+
|
|
3
|
+
The Campminder chrome: left nav, top bar, super-user banner. Lit web components,
|
|
4
|
+
composition-agnostic, rendering only what they are handed.
|
|
5
|
+
|
|
6
|
+
## Why one package and not three
|
|
7
|
+
|
|
8
|
+
The lineage verdict on
|
|
9
|
+
[#25854](https://dev.azure.com/CampMinderLLC/CampMinder/_workitems/edit/25854) is explicit
|
|
10
|
+
that side-nav and top-bar are **"one shell, split across two packages by history, not by
|
|
11
|
+
design."** Porting them into three separate packages here would have carried that accident
|
|
12
|
+
forward permanently — three version numbers, three release decisions, and a consumer
|
|
13
|
+
installing three things to get one shell. Merging published packages later is a breaking
|
|
14
|
+
change for everyone; merging them now, before anything publishes, costs nothing.
|
|
15
|
+
|
|
16
|
+
Subpath entries keep the granularity that actually mattered:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import '@campminder/components/side-nav'
|
|
20
|
+
import '@campminder/components/top-bar'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A consumer that only wants the left nav does not pull the top bar's code.
|
|
24
|
+
|
|
25
|
+
### Dependencies are added by the floor that imports them
|
|
26
|
+
|
|
27
|
+
This package declares `lit` and nothing else. `axios`, `@carbon/web-components` and
|
|
28
|
+
`@material/web` were carried over from the `core-js` manifests during the scaffold and
|
|
29
|
+
removed 2026-09-02: nothing in this package imported them — **and nothing in `core-js`'s
|
|
30
|
+
`apps/side-nav`, `apps/top-bar` or `apps/super-user-banner` imports them either**, so they
|
|
31
|
+
were dead weight upstream before they were dead weight here. They sat in `dependencies`,
|
|
32
|
+
not `devDependencies`, so every consumer would have installed two whole design systems to
|
|
33
|
+
render a menu.
|
|
34
|
+
|
|
35
|
+
If the Floor 7 top-bar port or the Floor 8 banner port needs one, the floor that writes
|
|
36
|
+
the `import` adds it back. Do not pre-declare a dependency for a port that has not
|
|
37
|
+
happened — an unused dependency in a published package is a cost paid by every consumer
|
|
38
|
+
for nothing.
|
|
39
|
+
|
|
40
|
+
## Port sources
|
|
41
|
+
|
|
42
|
+
| Entry | Port from | ADO floor |
|
|
43
|
+
| ------------------- | ------------------------------------------------------ | ---------- |
|
|
44
|
+
| `side-nav` | `core-js/apps/side-nav` (`@campminder/side-nav` 1.5.0) | Floors 3–4 |
|
|
45
|
+
| `top-bar` | `core-js/apps/top-bar` (`@campminder/top-bar` 0.0.111) | Floor 7 |
|
|
46
|
+
| `super-user-banner` | `core-js/apps/super-user-banner` (0.8.6) | Floor 8 |
|
|
47
|
+
|
|
48
|
+
`core-js` keeps building its copies for its existing consumers. This is a copy, not a
|
|
49
|
+
move — Rule 2 of the verdict.
|
|
50
|
+
|
|
51
|
+
## Strip on the way in
|
|
52
|
+
|
|
53
|
+
The port is the cheapest moment: there are no consumers here yet, so nothing needs to
|
|
54
|
+
stay backwards-compatible. This is choosing what not to copy, not refactoring live code.
|
|
55
|
+
|
|
56
|
+
**side-nav**
|
|
57
|
+
|
|
58
|
+
- **`BodyPaddingController`** — injects `html body { padding-left: 168px !important; }`
|
|
59
|
+
into `document.head`. The shell's grid owns that space now.
|
|
60
|
+
- **`initSearchIntegration()`** and its `setTimeout(setupSearchBarListener, 100)` re-arm —
|
|
61
|
+
polls the DOM forever in any composition without search.
|
|
62
|
+
- **`document.querySelector('search-bar')`** at `SideNav.ts:129` and `:477`.
|
|
63
|
+
- **`SIDENAV_STORAGE_KEY = 'isSideNavCollapsed'`** — a global key two shells on one origin
|
|
64
|
+
would share. The shell namespaces it per portal.
|
|
65
|
+
- **`src/data/data.ts`** — the base64 fixture. The tree is a property.
|
|
66
|
+
|
|
67
|
+
**top-bar** — ported Floor 7, 2026-09-08. This list is now a record, not a forecast.
|
|
68
|
+
|
|
69
|
+
- **The entire CDN script loader.** `loadWebComponents()`, `getCdnUrl()`,
|
|
70
|
+
`WEB_COMPONENTS_PATH`, `BASE_DOMAIN`, `FALLBACK_CDN_HOST`, the `searchReady` state and
|
|
71
|
+
the `webComponentsUrl` property. It appended a `<script type="module">` to
|
|
72
|
+
`document.head` pointed at a hardcoded `cdn.*.campminder.com` host, purely so that
|
|
73
|
+
`search-bar` would register itself. **The plan did not know about this** — it named the
|
|
74
|
+
registry probe and the render, not the script injection, which is the more serious
|
|
75
|
+
breach of the one rule. Making search a slot removed the whole apparatus.
|
|
76
|
+
- **`customElements.get('search-bar')`** at `TopBar.ts:58`, the `<search-bar>` render at
|
|
77
|
+
`:333`, and the `enableSearchWidget` property. Search is a named
|
|
78
|
+
**`<slot name="search">`**, rendered unconditionally; a shell that wants it fills it,
|
|
79
|
+
and nothing polls for it. `search-bar` is therefore **not ported** in Phase 1.
|
|
80
|
+
- **All search-expansion state** — `searchExpanded`, `handleSearchExpanded`,
|
|
81
|
+
`handleSearchClose`, `renderSearchCloseButton()`, and two
|
|
82
|
+
`document.dispatchEvent(new CustomEvent('search-expanded'))` calls that existed so
|
|
83
|
+
side-nav could hear them. Phase 1 ships no search, so the state could never become
|
|
84
|
+
true. **Owed when search is slotted in:** upstream collapsed the page-info block and
|
|
85
|
+
the user dropdown while search was expanded on mobile. Reintroduce that as something
|
|
86
|
+
the slotted element drives, not as a document-level broadcast.
|
|
87
|
+
- **All positioning.** `topOffsetPx` and `leftOffsetPx`, the `isSideNavCollapsed` state,
|
|
88
|
+
the `calculatedLeftOffset` getter, `syncWithSideNavState()`, `initSideNavIntegration()`,
|
|
89
|
+
`handleSideNavToggle`, and the import of `shared/navigation-constants.ts`
|
|
90
|
+
(`SIDENAV_ANIMATION`, `SIDENAV_DIMENSIONS`, `SIDENAV_STORAGE_KEY`,
|
|
91
|
+
`SIDENAV_TOGGLE_EVENT`). `LAYOUT` in `@campminder/campminder-shell` is the single
|
|
92
|
+
source and the shell's grid applies it. The rendered `<section>` carries no `style`
|
|
93
|
+
attribute at all. Reading side-nav's `localStorage` key was querying for a sibling.
|
|
94
|
+
- **All JS device detection.** `Utils/device-css-classes.ts` and
|
|
95
|
+
`Utils/mobile-detection.ts` are not here. Responsiveness is the media queries that were
|
|
96
|
+
already in `styles.ts` alongside the class-driven duplicates. See
|
|
97
|
+
`TopBar.styles.ts`'s comment on the page-title breakpoint for the one behaviour-neutral
|
|
98
|
+
simplification this exposed.
|
|
99
|
+
- **`data/data.ts`** — the base64 fixture, and `index.css` — page-level `:root` and `body`
|
|
100
|
+
styling, which is a host concern.
|
|
101
|
+
- **`assets/Icons/CloseIcon.ts`** — copied with the other five, then removed: its only
|
|
102
|
+
consumer was the search close button. side-nav carries its own `CloseIcon`, so nothing
|
|
103
|
+
lost it. The remaining five live in `assets/TopBarIcons/` behind a barrel, named
|
|
104
|
+
`XSvgIcon`, matching side-nav's `assets/SideNavIcons/` rather than upstream's
|
|
105
|
+
unprefixed `assets/Icons/` with one lowercase export.
|
|
106
|
+
- Carbon and Material: **nothing to strip.** Verified 2026-09-08 that no file under
|
|
107
|
+
`core-js/apps/top-bar/src` imports `@carbon/web-components` or `@material/web`. The
|
|
108
|
+
standing note that retiring them is separate-and-optional still holds for the estate,
|
|
109
|
+
but this port added neither, so this package still declares `lit` and nothing else.
|
|
110
|
+
- **`@import url(fonts.googleapis.com/...)`** — missed by this floor and stripped on
|
|
111
|
+
Floor 8, matching what side-nav had already done on Floor 4. See the banner section
|
|
112
|
+
below for the measurement.
|
|
113
|
+
|
|
114
|
+
- **Seven upstream security patterns, refused rather than copied** — `link.url` in `href`
|
|
115
|
+
and in `window.open()`; `popup_properties` passed to `window.open()` verbatim, and then
|
|
116
|
+
its UI-suppressing features; `target="_blank"` with no `rel`, and the popup path with no
|
|
117
|
+
`noopener`; `feature.value` through lit's `unsafeHTML`; and `icon_url` / `profile_url` /
|
|
118
|
+
`logo_url` reaching `<img src>` unguarded. **Why each one is refused, and the trust
|
|
119
|
+
boundary that makes them live rather than theoretical, is stated once — in
|
|
120
|
+
[`Utils/safe-url.ts`](src/top-bar/Utils/safe-url.ts)**, with 46 unit tests beside it.
|
|
121
|
+
Floor 8 was expected to inherit the question and did not — see below.
|
|
122
|
+
|
|
123
|
+
**Old → new names**, since this element is consumed by tag name:
|
|
124
|
+
|
|
125
|
+
| Upstream | Here |
|
|
126
|
+
| ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
127
|
+
| `<top-bar>` | `<cm-top-bar>` |
|
|
128
|
+
| `data` (base64 attribute) | unchanged — still `data`, still base64-decoded |
|
|
129
|
+
| `user` | **gone** — its only consumer was `<search-bar>`'s config, which the host now supplies to whatever it slots |
|
|
130
|
+
| `top-offset-px`, `left-offset-px`, `enable-search-widget`, `web-components-url` | **gone** |
|
|
131
|
+
| — | `<slot name="search">` |
|
|
132
|
+
|
|
133
|
+
**super-user-banner**
|
|
134
|
+
|
|
135
|
+
Renaming the element and its attributes **is** allowed. It is emitted as raw markup from
|
|
136
|
+
`ReactAppController.cs:163`, so WebForms consumes it with no package edge — but that
|
|
137
|
+
constrains the Phase 2 _cutover_, not this port: per Rule 2 this is a copy-forward and
|
|
138
|
+
`core-js` keeps building the copy that page actually loads. Ruled 2026-09-02, reversing
|
|
139
|
+
the ban that used to sit here.
|
|
140
|
+
|
|
141
|
+
- **`position: fixed; top: 0; left: 0; width: 100%`**, and **the `ResizeObserver`** that
|
|
142
|
+
compared `scrollWidth` against `window.innerWidth` to toggle an `overflowed` class
|
|
143
|
+
(plus the shadow-root `id` that existed only for its `getElementById`). Both went
|
|
144
|
+
because the shell owns layout. **Why each one is refused, and the latent defect the
|
|
145
|
+
observer was carrying, is stated once — in
|
|
146
|
+
[`SuperUserBanner.styles.ts`](src/super-user-banner/SuperUserBanner.styles.ts)**, which
|
|
147
|
+
is where the replacement lives. Worth knowing at this level: the fixed positioning is
|
|
148
|
+
why `ReactAppController` has to emit a `hasSuperUserBanner` class and prepend container
|
|
149
|
+
markup at all, so deleting four declarations here deletes the reason for two host-side
|
|
150
|
+
workarounds in Phase 2.
|
|
151
|
+
- **`@import url(fonts.googleapis.com/…)`** and **`index.css`** (page-level `:root` and
|
|
152
|
+
`body` styling, a host concern). The `@import` was also still in
|
|
153
|
+
[`TopBar.styles.ts`](src/top-bar/TopBar.styles.ts) — side-nav dropped it on Floor 4,
|
|
154
|
+
Floor 7 missed it, Floor 8 caught it. That file carries the reasoning and the
|
|
155
|
+
measurement.
|
|
156
|
+
|
|
157
|
+
**No URL guard was needed, and that is a finding.** `top-bar`'s
|
|
158
|
+
[`Utils/safe-url.ts`](src/top-bar/Utils/safe-url.ts) was left under `top-bar/` on the
|
|
159
|
+
argument that Floor 8 would be the second caller and would show the right shape. It is
|
|
160
|
+
not: all three of the banner's values are database-sourced and cross the same untrusted
|
|
161
|
+
boundary, but none is a URL and none is markup, so lit escaping text is the entire
|
|
162
|
+
defence. A test asserts the component renders no `a`, `img`, `iframe`, `source` or
|
|
163
|
+
`script` at all. Promoting the guards out of `top-bar/` therefore still has exactly one
|
|
164
|
+
caller and still is not justified.
|
|
165
|
+
|
|
166
|
+
**It did need two fixes of a different kind, both found in review.** A banner whose job
|
|
167
|
+
is to make impersonation and environment unmistakable can fail at that job without any
|
|
168
|
+
injection being involved:
|
|
169
|
+
|
|
170
|
+
- Upstream's badge **failed open** — anything that was not exactly `staging` got the calm
|
|
171
|
+
`local` badge, including the literal `production` and `undefined` that the host's
|
|
172
|
+
`GetEnvironmentName()` really returns. A super-user impersonating in production saw the
|
|
173
|
+
same badge as a laptop. There are now three badges and the unrecognised case is loud;
|
|
174
|
+
`environmentBadgeClass` in
|
|
175
|
+
[`SuperUserBanner.ts`](src/super-user-banner/SuperUserBanner.ts) carries the reasoning.
|
|
176
|
+
- The port had **introduced** a scroll container (`overflow-x: auto`) and hidden its
|
|
177
|
+
scrollbar, with the badge as the last flex child — so a merely long client name pushed
|
|
178
|
+
the badge out of view with no affordance, on a section with no `tabindex`. Upstream had
|
|
179
|
+
no `overflow` rule at all, so this one was a regression, not an inheritance. The names
|
|
180
|
+
now truncate and the scrollbar is no longer suppressed.
|
|
181
|
+
|
|
182
|
+
**Old → new names**, since this element is consumed by tag name:
|
|
183
|
+
|
|
184
|
+
| Upstream | Here |
|
|
185
|
+
| ---------------------------------------------------- | ------------------------------------------------ |
|
|
186
|
+
| `<super-user-banner>` | `<cm-super-user-banner>` |
|
|
187
|
+
| `superUser=` (parsed as `superuser`) | `super-user` |
|
|
188
|
+
| `activeEnvironment=` (parsed as `activeenvironment`) | `active-environment` |
|
|
189
|
+
| `client=` | unchanged — `client` |
|
|
190
|
+
| `id="super-user-banner"` in the shadow root | **gone** — existed only for the `ResizeObserver` |
|
|
191
|
+
|
|
192
|
+
The old spellings are ignored, not aliased, and a test asserts that — so the cutover
|
|
193
|
+
fails loudly rather than silently rendering an empty banner.
|
|
194
|
+
|
|
195
|
+
## The rule
|
|
196
|
+
|
|
197
|
+
> Components render themselves; the shell owns layout. No component may touch
|
|
198
|
+
> `document.body`, `document.head`, or query for a sibling.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The menu-tree structural types are deliberately NOT re-exported here.
|
|
3
|
+
*
|
|
4
|
+
* They lived in this package's `menu-tree.ts` until 2026-09-08 (Floor 5B), when the model
|
|
5
|
+
* moved to `nav` and became `@campminder/menu-tree` on public npm — ADR **D4** assigns the
|
|
6
|
+
* menu data model to the `nav` Domain System, and **D5** wanted the schema published rather
|
|
7
|
+
* than copied. This package now *consumes* those types the way any other host does; it does
|
|
8
|
+
* not own them and does not republish them.
|
|
9
|
+
*
|
|
10
|
+
* Import them from `@campminder/menu-tree` directly. Re-exporting them here would keep alive
|
|
11
|
+
* exactly the framing D4 removed — that the rendering package owns the model — and would give
|
|
12
|
+
* consumers two import paths for one type.
|
|
13
|
+
*/
|
|
14
|
+
export * from './side-nav';
|
|
15
|
+
export * from './top-bar';
|
|
16
|
+
export * from './super-user-banner';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MegaMenu as o, SideNav as a, hasIconFor as n, hasMegaMenuIconFor as p } from "./side-nav.js";
|
|
2
|
+
import { TopBar as f } from "./top-bar.js";
|
|
3
|
+
import { SuperUserBanner as s } from "./super-user-banner.js";
|
|
4
|
+
export {
|
|
5
|
+
o as MegaMenu,
|
|
6
|
+
a as SideNav,
|
|
7
|
+
s as SuperUserBanner,
|
|
8
|
+
f as TopBar,
|
|
9
|
+
n as hasIconFor,
|
|
10
|
+
p as hasMegaMenuIconFor
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|