@statsbygg/layout 0.1.23 → 0.2.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 CHANGED
@@ -25,6 +25,7 @@ npm install @statsbygg/layout
25
25
  ## Peer Dependencies
26
26
 
27
27
  This package requires:
28
+
28
29
  - `next` >= 14.0.0
29
30
  - `react` >= 18.0.0
30
31
  - `react-dom` >= 18.0.0
@@ -71,22 +72,23 @@ The routing system uses **URL-Driven Logic**. You define a single `RouteNode` tr
71
72
  - **Internal Links**: Any relative path (e.g., `/`, `/about`) is treated as internal to your application (relative to your `basePath`).
72
73
 
73
74
  #### Scenario A: Standard Application
74
- *This app sits directly under the main Statsbygg site.*
75
+
76
+ _This app sits directly under the main Statsbygg site._
75
77
 
76
78
  ```tsx
77
79
  // app/layout.tsx
78
- import { RootLayout, RouteNode } from '@statsbygg/layout';
80
+ import { RootLayout, RouteNode } from "@statsbygg/layout";
79
81
 
80
82
  const ROUTES: RouteNode = {
81
- label: 'Hjem',
82
- path: 'https://statsbygg.no', // External Parent
83
+ label: "Hjem",
84
+ path: "https://statsbygg.no", // External Parent
83
85
  children: [
84
86
  {
85
- label: 'My App',
86
- path: '/', // App Root (relative to basePath)
87
+ label: "My App",
88
+ path: "/", // App Root (relative to basePath)
87
89
  children: [
88
- { label: 'Page 1', path: '/page-1' },
89
- { label: 'Page 2', path: '/page-2' },
90
+ { label: "Page 1", path: "/page-1" },
91
+ { label: "Page 2", path: "/page-2" },
90
92
  ],
91
93
  },
92
94
  ],
@@ -101,59 +103,53 @@ export default function Layout({ children }: { children: React.ReactNode }) {
101
103
  </html>
102
104
  );
103
105
  }
104
-
105
106
  ```
106
107
 
107
108
  #### Scenario B: Deeply Nested Microfrontend
108
109
 
109
- *This app sits deep within a hierarchy of other applications.*
110
+ _This app sits deep within a hierarchy of other applications._
110
111
 
111
112
  ```tsx
112
113
  // app/layout.tsx
113
114
  const ROUTES: RouteNode = {
114
- label: 'Hjem',
115
- path: 'https://statsbygg.no',
115
+ label: "Hjem",
116
+ path: "https://statsbygg.no",
116
117
  children: [
117
118
  {
118
- label: 'Parent Route',
119
- path: 'https://statsbygg.no/parent-route', // External Parent 2
119
+ label: "Parent Route",
120
+ path: "https://statsbygg.no/parent-route", // External Parent 2
120
121
  children: [
121
122
  {
122
- label: 'Your App Name',
123
- path: '/', // Your App Root
124
- children: [
125
- { label: 'Your App Route', path: '/your-app-route' }
126
- ]
127
- }
128
- ]
129
- }
130
- ]
123
+ label: "Your App Name",
124
+ path: "/", // Your App Root
125
+ children: [{ label: "Your App Route", path: "/your-app-route" }],
126
+ },
127
+ ],
128
+ },
129
+ ],
131
130
  };
132
-
133
131
  ```
134
132
 
135
133
  ### 2. Handling Dynamic Routes
136
134
 
137
135
  For pages with dynamic IDs (e.g., `/properties/[id]`), use the `useBreadcrumbs` hook.
138
136
 
139
- **Note:** You only need to define the *dynamic* portion of the path. The layout package automatically prepends the static parents (Home, App Root, etc.) defined in your `ROUTES` tree.
137
+ **Note:** You only need to define the _dynamic_ portion of the path. The layout package automatically prepends the static parents (Home, App Root, etc.) defined in your `ROUTES` tree.
140
138
 
141
139
  ```tsx
142
140
  // app/properties/[id]/page.tsx
143
- 'use client';
144
- import { useBreadcrumbs } from '@statsbygg/layout';
141
+ "use client";
142
+ import { useBreadcrumbs } from "@statsbygg/layout";
145
143
 
146
144
  export default function PropertyPage({ params, propertyName }) {
147
-
148
145
  useBreadcrumbs([
149
- { label: 'Properties', href: '/properties' },
146
+ { label: "Properties", href: "/properties" },
150
147
  { label: propertyName, href: `/properties/${params.id}` },
151
148
  ]);
152
149
 
153
150
  return <div>...</div>;
154
151
  }
155
152
  // Resulting Breadcrumbs: Home > My App > Properties > [Property Name]
156
-
157
153
  ```
158
154
 
159
155
  ### Using the Global Store
@@ -161,17 +157,17 @@ export default function PropertyPage({ params, propertyName }) {
161
157
  The package exports a zustand store for managing global state:
162
158
 
163
159
  ```tsx
164
- import { useGlobalStore } from '@statsbygg/layout';
160
+ import { useGlobalStore } from "@statsbygg/layout";
165
161
 
166
162
  function MyComponent() {
167
163
  const { user, theme, setUser, setTheme } = useGlobalStore();
168
164
 
169
165
  function handleLogin() {
170
- setUser({ name: 'John Doe', email: 'john@statsbygg.no' });
166
+ setUser({ name: "John Doe", email: "john@statsbygg.no" });
171
167
  }
172
168
 
173
169
  function toggleTheme() {
174
- setTheme(theme === 'light' ? 'dark' : 'light');
170
+ setTheme(theme === "light" ? "dark" : "light");
175
171
  }
176
172
 
177
173
  return (
@@ -183,6 +179,7 @@ function MyComponent() {
183
179
  );
184
180
  }
185
181
  ```
182
+
186
183
  ## API Reference
187
184
 
188
185
  ### RootLayout
@@ -204,16 +201,15 @@ Zustand store hook for global state management.
204
201
  ```tsx
205
202
  interface GlobalState {
206
203
  user: { name: string; email: string } | null;
207
- theme: 'light' | 'dark';
208
- locale: 'no' | 'en';
204
+ theme: "light" | "dark";
205
+ locale: "no" | "en";
209
206
  setUser: (user: { name: string; email: string } | null) => void;
210
- setTheme: (theme: 'light' | 'dark') => void;
211
- setLocale: (locale: 'no' | 'en') => void;
207
+ setTheme: (theme: "light" | "dark") => void;
208
+ setLocale: (locale: "no" | "en") => void;
212
209
  initialize: () => Promise<void>;
213
210
  }
214
211
  ```
215
212
 
216
-
217
213
  ## Breadcrumbs Behavior
218
214
 
219
215
  The Breadcrumbs component uses Designsystemet's responsive behavior:
@@ -241,6 +237,7 @@ This package uses [DigDir Designsystemet](https://designsystemet.no) components:
241
237
  - `Paragraph`
242
238
 
243
239
  All styling uses Designsystemet design tokens:
240
+
244
241
  - `--ds-spacing-*` for spacing
245
242
  - `--ds-color-*` for colors
246
243
  - `--ds-font-size-*` for typography
@@ -249,24 +246,25 @@ All styling uses Designsystemet design tokens:
249
246
 
250
247
  ```bash
251
248
  # Install dependencies
252
- npm install
249
+ pnpm install
253
250
 
254
251
  # Build the package
255
- npm run build
252
+ pnpm build
256
253
 
257
254
  # Watch mode for development
258
- npm run dev
255
+ pnpm dev
259
256
 
260
257
  # Type checking
261
- npm run type-check
258
+ pnpm type-check
262
259
 
263
260
  # Linting
264
- npm run lint
261
+ pnpm lint
265
262
  ```
266
263
 
267
264
  ## Dependencies
268
265
 
269
266
  This package includes:
267
+
270
268
  - `@digdir/designsystemet-react` 1.12.1
271
269
  - `@statsbygg/design-tokens` ^0.2.0
272
270
  - `clsx` ^2.0.0
@@ -274,4 +272,4 @@ This package includes:
274
272
 
275
273
  ## License
276
274
 
277
- Internal use only - Statsbygg
275
+ Internal use only - Statsbygg
@@ -1,6 +1,6 @@
1
1
  .wrapper {
2
2
  width: 100%;
3
- background-color: var(--ds-color-background-tinted);
3
+ background-color: var(--layout-background, var(--ds-color-background-tinted));
4
4
  }
5
5
 
6
6
  .inner {
@@ -9,10 +9,6 @@
9
9
  margin: 0 auto;
10
10
  }
11
11
 
12
- .whiteBackground {
13
- background-color: white;
14
- }
15
-
16
12
  .breadcrumbs {
17
13
  --dsc-breadcrumbs-color: var(--ds-color-text-default);
18
14
  }
@@ -64,8 +60,7 @@
64
60
  color: var(--ds-color-text-default);
65
61
  }
66
62
 
67
- .link:hover
68
- .link:visited{
63
+ .link:hover .link:visited {
69
64
  color: var(--ds-color-text-default);
70
65
  }
71
66
 
@@ -85,4 +80,4 @@
85
80
  .inner {
86
81
  padding: var(--ds-size-6) var(--ds-size-4) 0;
87
82
  }
88
- }
83
+ }
@@ -86,6 +86,11 @@
86
86
  font-weight: 500;
87
87
  }
88
88
 
89
+ .shortcutsContainer .footerList a,
90
+ .socialLinks .footerList a {
91
+ text-decoration: none;
92
+ }
93
+
89
94
  .footerLeft .footerSection a:hover {
90
95
  text-decoration: underline;
91
96
  }
@@ -4,27 +4,21 @@
4
4
  background-color: var(--ds-color-background-tinted);
5
5
  top: 0;
6
6
  z-index: 100;
7
-
7
+ background-color: var(--layout-background, var(--ds-color-background-tinted));
8
8
  }
9
9
 
10
- .header, .headerWrapper{
10
+ .header,
11
+ .headerWrapper {
11
12
  min-height: 128px;
12
13
  }
13
14
 
14
- .whiteBackground,
15
- .whiteBackground .topBarFixedWrapper,
16
- .whiteBackground .headerContainer {
17
- background-color: white;
18
- }
19
-
20
15
  .topBarFixedWrapper {
21
16
  position: relative;
22
17
  left: 0;
23
18
  right: 0;
24
- background: var(--ds-color-background-tinted);
19
+ background: var(--layout-background, var(--ds-color-background-tinted));
25
20
  }
26
21
 
27
-
28
22
  .topBarFixed {
29
23
  position: fixed;
30
24
  top: 0;
@@ -32,7 +26,7 @@
32
26
 
33
27
  .topBarContainer {
34
28
  max-height: 10rem;
35
- max-width: 90rem;
29
+ max-width: 90rem;
36
30
  margin: 0 auto;
37
31
  padding: 0 var(--ds-size-30);
38
32
  }
@@ -58,7 +52,7 @@
58
52
  left: 0;
59
53
  right: 0;
60
54
  top: 0;
61
- background-color: var(--ds-color-background-tinted);
55
+ background-color: var(--layout-background, var(--ds-color-background-tinted));
62
56
  }
63
57
 
64
58
  .topBarInner {
@@ -95,8 +89,8 @@
95
89
  }
96
90
 
97
91
  @media (max-width: 1024px) {
98
-
99
- .header, .headerWrapper{
92
+ .header,
93
+ .headerWrapper {
100
94
  min-height: 112px;
101
95
  }
102
96
 
@@ -110,8 +104,8 @@
110
104
  }
111
105
 
112
106
  @media (max-width: 768px) {
113
-
114
- .header, .headerWrapper {
107
+ .header,
108
+ .headerWrapper {
115
109
  min-height: 96px;
116
110
  }
117
111
 
@@ -138,14 +132,14 @@
138
132
  display: none;
139
133
  }
140
134
 
141
-
142
- .logo { inline-size: 8rem; }
143
-
135
+ .logo {
136
+ inline-size: 8rem;
137
+ }
144
138
  }
145
139
 
146
140
  @media (max-width: 600px) {
147
-
148
- .header, .headerWrapper {
141
+ .header,
142
+ .headerWrapper {
149
143
  min-height: 80px;
150
144
  }
151
145
 
@@ -156,12 +150,11 @@
156
150
  .topBarContainer {
157
151
  padding: 0 var(--ds-size-6);
158
152
  }
159
-
160
153
  }
161
154
 
162
155
  @media (max-width: 360px) {
163
-
164
- .header, .headerWrapper {
156
+ .header,
157
+ .headerWrapper {
165
158
  min-height: 74px;
166
159
  }
167
160
 
@@ -172,5 +165,4 @@
172
165
  .topBarInner {
173
166
  padding: var(--ds-size-4) 0;
174
167
  }
175
-
176
- }
168
+ }
@@ -28,4 +28,4 @@
28
28
  position: static;
29
29
  width: auto;
30
30
  height: auto;
31
- }
31
+ }
File without changes
package/dist/index.d.ts CHANGED
@@ -7,10 +7,9 @@ type GlobalHeaderProps = {
7
7
  className?: string;
8
8
  appBasePath?: string;
9
9
  pathname?: string;
10
- isWhiteBackground?: boolean;
11
10
  };
12
11
 
13
- declare function GlobalHeader({ className, appBasePath, isWhiteBackground }: GlobalHeaderProps): react_jsx_runtime.JSX.Element;
12
+ declare function GlobalHeader({ className, appBasePath }: GlobalHeaderProps): react_jsx_runtime.JSX.Element;
14
13
 
15
14
  type RouteNode = {
16
15
  path: string;
@@ -28,15 +27,20 @@ type AncestorChain = {
28
27
  declare function findAppRootWithAncestors(node: RouteNode, ancestors?: RouteNode[]): AncestorChain;
29
28
  declare function getBreadcrumbs(routes: RouteNode, pathname: string): BreadcrumbItem[];
30
29
 
30
+ /**
31
+ * Available background color schemes for the layout.
32
+ * These map to CSS custom properties in RootLayout.module.css
33
+ */
34
+ type LayoutBackground = "default" | "white" | "alternative";
31
35
  type RootLayoutProps = {
32
36
  children: React.ReactNode;
33
37
  routes: RouteNode;
34
38
  appBasePath?: string;
35
39
  className?: string;
36
- isWhiteBackground?: boolean;
40
+ background?: LayoutBackground;
37
41
  };
38
42
 
39
- declare function RootLayout({ children, routes, appBasePath, className, isWhiteBackground }: RootLayoutProps): react_jsx_runtime.JSX.Element;
43
+ declare function RootLayout({ children, routes, appBasePath, className, background, }: RootLayoutProps): react_jsx_runtime.JSX.Element;
40
44
 
41
45
  interface GlobalFooterProps {
42
46
  className?: string;
@@ -93,10 +97,9 @@ type BreadcrumbsProps = {
93
97
  routes: RouteNode;
94
98
  appBasePath?: string;
95
99
  pathname?: string;
96
- isWhiteBackground?: boolean;
97
100
  };
98
101
 
99
- declare function SbBreadcrumbs({ className, routes, appBasePath, pathname: propPathname, isWhiteBackground }: BreadcrumbsProps): react_jsx_runtime.JSX.Element | null;
102
+ declare function SbBreadcrumbs({ className, routes, appBasePath, pathname: propPathname, }: BreadcrumbsProps): react_jsx_runtime.JSX.Element | null;
100
103
 
101
104
  type SmartLinkProps = {
102
105
  href: string;