@the-portland-company/shell 0.6.0 → 0.8.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,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.0 — 2026-07-02
4
+
5
+ ### Added (backward-compatible)
6
+
7
+ - **Host-driven auth for non-Supabase apps**: `ShellProviderProps.supabaseClient` is now optional, and a new optional `auth: ShellInjectedAuth` prop (`{ status, user, signOut }`, exported type) takes precedence over Supabase session tracking. This lets OIDC apps (e.g. the standalone Contacts app) mount the full Chakra chrome — `ShellProvider` → `ShellChrome` → `AppLayout` — with their own identity feeding `useShellAuth`/`UserMenu`. The host builds a Supabase-shaped `user.raw` (`id`/`email`/`user_metadata.full_name`) so chrome components render identically. With neither prop, auth resolves to `unauthenticated`. Existing `supabaseClient` consumers are unaffected.
8
+
9
+ ### Tests
10
+
11
+ - Injected auth: precedence over Supabase (no `getSession`/`onAuthStateChange`/`auth.signOut` calls), client-less mounting, neither-prop fallback (3 tests).
12
+
13
+ ## 0.7.0 — 2026-07-01
14
+
15
+ ### Added (native chrome — all backward-compatible)
16
+
17
+ - **Expandable nav groups**: `NavItem` gains optional `children?: NavItem[]`. A parent with children renders as an accordion group header — clicking toggles (never navigates, even with `href`; the href only feeds active detection), a right-aligned chevron rotates 180° when open, the sidebar keeps a single group open at a time, and the group containing the active route auto-expands on route change. Sub-items render as smaller nav rows on a lighter panel through the same injected `LinkComponent` (with `onClick` button support), with the main app's exact treatments: parent solid race-red when itself-or-a-child is active, active sub-item on elevated panel with race-red text, inactive rows keep the orange→red hover gradient sweep. Flat menus are byte-identical to before.
18
+ - **`standardPolitogyNav`** (new export, with `StandardNavOptions` / `StandardNavIconKey`): the canonical Politogy VRM menu — Dashboard, Contacts, Email Broadcast, SMS/MMS Blast, Calls to Action, Forms & Surveys, Support — encoded once in the shell with core-relative routes absolutized against `coreBaseUrl`. Apps map icon slots to their own icon library, and an app that owns an item nests its local pages via `contactsItem: { href, children }` (used verbatim, not absolutized) while everything else links out to VRM core. `supportItem` supplies the Support handler (`onClick`/`href`) or omits the row.
19
+
20
+ ### Tests
21
+
22
+ - Group behavior: render-when-expanded, toggle, auto-expand on active child, single-open accordion (6 tests).
23
+ - `standardPolitogyNav`: order/wording, absolutization, href-less CTA/Forms parents, default vs local Contacts children, Support variants, icon mapping (7 tests).
24
+
3
25
  ## 0.6.0 — 2026-07-01
4
26
 
5
27
  ### Added (native chrome — all backward-compatible)
package/dist/index.cjs CHANGED
@@ -1126,6 +1126,7 @@ function toShellUser(session) {
1126
1126
  function ShellProvider({
1127
1127
  children,
1128
1128
  supabaseClient,
1129
+ auth,
1129
1130
  currentApp,
1130
1131
  appRegistry,
1131
1132
  basename,
@@ -1139,6 +1140,11 @@ function ShellProvider({
1139
1140
  const [status, setStatus] = react$1.useState("loading");
1140
1141
  const [session, setSession] = react$1.useState(null);
1141
1142
  react$1.useEffect(() => {
1143
+ if (auth || !supabaseClient) {
1144
+ setSession(null);
1145
+ if (!auth) setStatus("unauthenticated");
1146
+ return;
1147
+ }
1142
1148
  let cancelled = false;
1143
1149
  supabaseClient.auth.getSession().then(({ data }) => {
1144
1150
  if (cancelled) return;
@@ -1153,18 +1159,27 @@ function ShellProvider({
1153
1159
  cancelled = true;
1154
1160
  sub.data.subscription.unsubscribe();
1155
1161
  };
1156
- }, [supabaseClient]);
1157
- const value = react$1.useMemo(
1158
- () => ({
1162
+ }, [supabaseClient, auth]);
1163
+ const value = react$1.useMemo(() => {
1164
+ if (auth) {
1165
+ return {
1166
+ status: auth.status,
1167
+ session: null,
1168
+ user: auth.user,
1169
+ signOut: async () => {
1170
+ await auth.signOut();
1171
+ }
1172
+ };
1173
+ }
1174
+ return {
1159
1175
  status,
1160
1176
  session,
1161
1177
  user: toShellUser(session),
1162
1178
  signOut: async () => {
1163
- await supabaseClient.auth.signOut();
1179
+ await supabaseClient?.auth.signOut();
1164
1180
  }
1165
- }),
1166
- [status, session, supabaseClient]
1167
- );
1181
+ };
1182
+ }, [auth, status, session, supabaseClient]);
1168
1183
  const meta = react$1.useMemo(
1169
1184
  () => ({
1170
1185
  currentApp,