@midas-ds/layout 0.1.14 → 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/CHANGELOG.md CHANGED
@@ -1,3 +1,33 @@
1
+ ## 0.2.0 (2026-06-10)
2
+
3
+ ### 🚀 Features
4
+
5
+ - **layout,panel:** visual polish, actions prop, push variant and replace behavior ([1211ac8899c](https://github.com/migrationsverket/midas/commit/1211ac8899c))
6
+
7
+ ### 🩹 Fixes
8
+
9
+ - **layout,panel:** fix push variant on mobile with height transition ([10f74a57f9e](https://github.com/migrationsverket/midas/commit/10f74a57f9e))
10
+ - **layout,panel:** fix header gap, panel width and content padding ([78f682e5400](https://github.com/migrationsverket/midas/commit/78f682e5400))
11
+ - **layout,panel:** a11y improvements and remove data-debug ([b817a0d4a0b](https://github.com/migrationsverket/midas/commit/b817a0d4a0b))
12
+
13
+ ### 📖 Documentation changes
14
+
15
+ - **layout,panel:** document detail view pattern with stable panel id ([dae5474d423](https://github.com/migrationsverket/midas/commit/dae5474d423))
16
+
17
+ ### 🔧 Maintenance
18
+
19
+ - **layout,panel:** reset paragraph margin in scrollable story ([9875af7e685](https://github.com/migrationsverket/midas/commit/9875af7e685))
20
+ - **layout,panel:** fix CI lint errors ([ee2ccb4d122](https://github.com/migrationsverket/midas/commit/ee2ccb4d122))
21
+
22
+ ### 🧪 Tests updated
23
+
24
+ - **layout,panel:** add DetailView story for in-place content updates ([1ca23991169](https://github.com/migrationsverket/midas/commit/1ca23991169))
25
+ - **layout,panel:** add panel stories and spec ([2d5d43a66ec](https://github.com/migrationsverket/midas/commit/2d5d43a66ec))
26
+
27
+ ### 🧱 Updated Dependencies
28
+
29
+ - Updated components to 17.15.2
30
+
1
31
  ## 0.1.14 (2026-06-09)
2
32
 
3
33
  ### 🩹 Fixes
@@ -1 +1 @@
1
- ._layout_4r2tn_1{display:flex;flex-direction:column;font-family:var(--midas-typography-font-family);width:100%;height:100dvh}._skipToContent_yjoos_1{position:absolute;top:0;right:100%;z-index:var(--midas-z-index-skip-to-content)}._skipToContent_yjoos_1[data-focus-visible]{right:auto;left:5px;top:5px}._layoutContent_yqjxz_1{display:flex;position:relative;height:100%;overflow:hidden}
1
+ ._layout_4r2tn_1{display:flex;flex-direction:column;font-family:var(--midas-typography-font-family);width:100%;height:100dvh}._skipToContent_yjoos_1{position:absolute;top:0;right:100%;z-index:var(--midas-z-index-skip-to-content)}._skipToContent_yjoos_1[data-focus-visible]{right:auto;left:5px;top:5px}._layoutContent_rtwdj_1{display:flex;position:relative;height:100%;overflow:hidden}@media not (min-width:800px){._layoutContent_rtwdj_1{flex-direction:column}}
@@ -1 +1 @@
1
- ._panel_kpvat_1{background:var(--midas-background-base);height:100%;overflow:hidden;position:absolute!important;right:0;top:0;width:320px;border-left:1px solid var(--midas-border-color-subtle)}._panel_kpvat_1[data-promoting]{animation:_promote_kpvat_1 var(--midas-transition-duration-fast) ease-out}@media(prefers-reduced-motion:reduce){._panel_kpvat_1[data-promoting]{animation-duration:1ms}}._panel_kpvat_1[data-entering]{animation:_slide-horizontally_kpvat_1 var(--midas-transition-duration-fast)}._panel_kpvat_1[data-exiting]{animation:_slide-horizontally_kpvat_1 var(--midas-transition-duration-fast) reverse ease-in}@media(prefers-reduced-motion:reduce){._panel_kpvat_1[data-entering],._panel_kpvat_1[data-exiting]{animation-duration:1ms}}@media not (min-width:800px){._panel_kpvat_1{bottom:0;width:100%;height:25%;left:0;top:unset;border-left:none;border-top:1px solid var(--midas-border-color-subtle)}._panel_kpvat_1[data-entering]{animation:_slide-vertically_kpvat_1 var(--midas-transition-duration-fast)}._panel_kpvat_1[data-exiting]{animation:_slide-vertically_kpvat_1 var(--midas-transition-duration-fast) reverse ease-in}}._panelTitle_kpvat_59{font-size:var(--midas-typography-font-size-30);font-weight:var(--midas-typography-weight-semi-bold);line-height:var(--midas-typography-line-height-50);display:block}@keyframes _promote_kpvat_1{0%{opacity:.7;transform:scale(.97)}to{opacity:1;transform:scale(1)}}@keyframes _slide-horizontally_kpvat_1{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes _slide-vertically_kpvat_1{0%{transform:translateY(100%)}to{transform:translateY(0)}}
1
+ :root{--panel-width: 300px;--panel-height-mobile: 40vh}._panel_11eci_6{background:var(--midas-background-base);box-shadow:var(--midas-panel-shadow);height:100%;overflow:hidden;position:absolute;right:0;top:0;width:var(--panel-width);border-left:1px solid var(--midas-border-color-subtle)}._panel_11eci_6[data-promoting]{animation:_promote_11eci_1 var(--midas-transition-duration-slow) ease-out}@media(prefers-reduced-motion:reduce){._panel_11eci_6[data-promoting]{animation-duration:1ms}}._panel_11eci_6[data-entering]{animation:_slide-horizontally_11eci_1 var(--midas-transition-duration-slow)}._panel_11eci_6[data-exiting]{animation:_slide-horizontally_11eci_1 var(--midas-transition-duration-slow) reverse ease-in}@media(prefers-reduced-motion:reduce){._panel_11eci_6[data-entering],._panel_11eci_6[data-exiting]{animation-duration:1ms}}@media not (min-width:800px){._panel_11eci_6{bottom:0;width:100%;height:var(--panel-height-mobile);left:0;top:unset;border-left:none;border-top:1px solid var(--midas-border-color-subtle)}._panel_11eci_6[data-entering]{animation:_slide-vertically_11eci_1 var(--midas-transition-duration-slow)}._panel_11eci_6[data-exiting]{animation:_slide-vertically_11eci_1 var(--midas-transition-duration-slow) reverse ease-in}}._panelActions_11eci_63{align-items:center;display:flex;flex-shrink:0}._panelTitle_11eci_69{font-size:var(--midas-typography-font-size-30);font-weight:var(--midas-typography-weight-semi-bold);line-height:var(--midas-typography-line-height-50);display:block}@keyframes _promote_11eci_1{0%{opacity:.7;transform:scale(.97)}to{opacity:1;transform:scale(1)}}@keyframes _slide-horizontally_11eci_1{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes _slide-vertically_11eci_1{0%{transform:translateY(100%)}to{transform:translateY(0)}}._push_a83oo_1{flex-shrink:0;height:100%;overflow:hidden;position:relative;transition:width var(--midas-transition-duration-slow);width:0}._push_a83oo_1[data-open]{width:var(--panel-width)}@media not (min-width:800px){._push_a83oo_1{height:0;width:100%;transition:height var(--midas-transition-duration-slow)}._push_a83oo_1[data-open]{height:var(--panel-height-mobile);width:100%}}
@@ -1 +1 @@
1
- ._panelBody_2cx45_1{background-color:var(--midas-background-base);box-sizing:border-box;display:flex;flex-direction:column;gap:var(--midas-space-medium)}._panelContent_ahpqn_1{padding:var(--midas-space-small) var(--midas-space-medium) var(--midas-space-medium) var(--midas-space-medium)}._panelHeader_xyjgl_1{align-items:center;display:flex;justify-content:space-between;padding:var(--midas-space-small) var(--midas-space-small) var(--midas-space-small) var(--midas-space-medium)}._panelTitle_w7y4m_1{display:block}
1
+ ._panelBody_1p0jk_1{background-color:var(--midas-background-base);box-sizing:border-box;display:flex;flex-direction:column;gap:0}._panelContent_1gfrc_1{flex:1 1 auto;overflow:hidden auto;padding:var(--midas-space-small) var(--midas-space-medium) 0}._panelContent_1gfrc_1:focus-visible{box-shadow:var(--midas-state-focus-inset);outline:none}@media(forced-colors:active){._panelContent_1gfrc_1:focus-visible{outline:var(--midas-state-focus-contrast-mode-outline) solid highlight;outline-offset:calc(var(--midas-state-focus-contrast-mode-outline) * -1)}}._panelHeader_1g1ux_1{align-items:center;display:flex;justify-content:space-between;padding:var(--midas-space-small) var(--midas-space-30) var(--midas-space-small) var(--midas-space-medium)}._panelTitle_w7y4m_1{display:block}
@@ -4,11 +4,11 @@ import { c as a } from "./clsx-OuTLNxxd.js";
4
4
  import { useLocalizedStringFormatter as c, Button as i } from "@midas-ds/components";
5
5
  import '../assets/LayoutContent.css';const l = "_layout_4r2tn_1", u = {
6
6
  layout: l
7
- }, y = { skipToContent: "Skip to main content" }, m = { skipToContent: "Hoppa till huvudinnehåll" }, p = {
8
- en: y,
9
- sv: m
10
- }, C = "_skipToContent_yjoos_1", d = {
11
- skipToContent: C
7
+ }, m = { skipToContent: "Skip to main content" }, p = { skipToContent: "Hoppa till huvudinnehåll" }, y = {
8
+ en: m,
9
+ sv: p
10
+ }, d = "_skipToContent_yjoos_1", C = {
11
+ skipToContent: d
12
12
  }, k = ({
13
13
  selector: t = "main:first-of-type"
14
14
  }) => {
@@ -19,12 +19,12 @@ import '../assets/LayoutContent.css';const l = "_layout_4r2tn_1", u = {
19
19
  () => n.removeAttribute("tabindex"),
20
20
  { once: !0 }
21
21
  ));
22
- }, s = c(p);
22
+ }, s = c(y);
23
23
  return /* @__PURE__ */ e(
24
24
  i,
25
25
  {
26
26
  onPress: o,
27
- className: d.skipToContent,
27
+ className: C.skipToContent,
28
28
  children: s.format("skipToContent")
29
29
  }
30
30
  );
@@ -38,7 +38,7 @@ import '../assets/LayoutContent.css';const l = "_layout_4r2tn_1", u = {
38
38
  t
39
39
  ]
40
40
  }
41
- ), _ = "_layoutContent_yqjxz_1", f = {
41
+ ), _ = "_layoutContent_rtwdj_1", f = {
42
42
  layoutContent: _
43
43
  }, L = ({ className: t, ...o }) => /* @__PURE__ */ e(
44
44
  "div",
@@ -0,0 +1,193 @@
1
+ 'use client';
2
+ import { jsx as f, jsxs as g } from "react/jsx-runtime";
3
+ import { useRef as E, useEffect as b, forwardRef as y, createContext as A, useState as C, useContext as N } from "react";
4
+ import { c as O } from "./clsx-OuTLNxxd.js";
5
+ import { useLocalizedStringFormatter as T, Button as I } from "@midas-ds/components";
6
+ import { useControlledState as R } from "@react-stately/utils";
7
+ import { useExitAnimation as j, useObjectRef as S, useEnterAnimation as k, filterDOMProps as z } from "@react-aria/utils";
8
+ import { P as L, b as M, c as U, a as V } from "./PanelTitle-CSjU7dUj.js";
9
+ import { c as w } from "./createLucideIcon-CP-mMPfa.js";
10
+ import '../assets/PanelRegion.css';const D = [
11
+ ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
12
+ ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
13
+ ], F = w("x", D), H = { closePanel: "Close panel" }, X = { closePanel: "Stäng panel" }, $ = {
14
+ en: H,
15
+ sv: X
16
+ }, q = "_panel_11eci_6", B = "_panelActions_11eci_63", G = "_panelTitle_11eci_69", h = {
17
+ panel: q,
18
+ panelActions: B,
19
+ panelTitle: G
20
+ }, J = (a) => {
21
+ const { onExited: l } = a, [o, d] = R(
22
+ a.isOpen,
23
+ a.defaultOpen || !1,
24
+ a.onOpenChange
25
+ ), r = E(null), s = j(r, o), m = () => d((u) => !u);
26
+ return b(() => {
27
+ !o && !s && l?.();
28
+ }, [o, s, l]), !o && !s ? null : /* @__PURE__ */ f(
29
+ K,
30
+ {
31
+ isExiting: s,
32
+ onPress: m,
33
+ ref: r,
34
+ ...a
35
+ }
36
+ );
37
+ }, K = y(
38
+ ({
39
+ className: a,
40
+ title: l,
41
+ actions: o,
42
+ onPress: d,
43
+ children: r,
44
+ isExiting: s,
45
+ defaultOpen: m,
46
+ promoting: u,
47
+ onPromotionEnd: p,
48
+ "aria-hidden": c,
49
+ ...t
50
+ }, e) => {
51
+ const n = T($), i = S(e), P = k(i, !m), v = (x) => {
52
+ x.target === x.currentTarget && u && p?.();
53
+ };
54
+ return /* @__PURE__ */ g(
55
+ L,
56
+ {
57
+ "aria-hidden": c || void 0,
58
+ "aria-label": l,
59
+ className: O(a, h.panel),
60
+ ref: i,
61
+ "data-entering": P || void 0,
62
+ "data-exiting": s || void 0,
63
+ "data-promoting": u || void 0,
64
+ onAnimationEnd: v,
65
+ ...z(t),
66
+ children: [
67
+ /* @__PURE__ */ g(M, { children: [
68
+ /* @__PURE__ */ f(
69
+ U,
70
+ {
71
+ className: h.panelTitle,
72
+ title: l
73
+ }
74
+ ),
75
+ /* @__PURE__ */ g("div", { className: h.panelActions, children: [
76
+ o,
77
+ /* @__PURE__ */ f(
78
+ I,
79
+ {
80
+ "aria-label": n.format("closePanel"),
81
+ onPress: d,
82
+ size: "medium",
83
+ variant: "icon",
84
+ children: /* @__PURE__ */ f(F, { size: 20 })
85
+ }
86
+ )
87
+ ] })
88
+ ] }),
89
+ /* @__PURE__ */ f(V, { children: r })
90
+ ]
91
+ }
92
+ );
93
+ }
94
+ ), Q = (a) => null;
95
+ Q.displayName = "usePanels";
96
+ const _ = A({
97
+ panels: [],
98
+ panelVariant: "overlay",
99
+ addPanel: () => {
100
+ },
101
+ closePanel: () => {
102
+ },
103
+ removePanel: () => {
104
+ },
105
+ resetPromoting: () => {
106
+ }
107
+ }), re = ({
108
+ children: a,
109
+ defaultPanels: l = [],
110
+ panelBehavior: o = "replace",
111
+ panelVariant: d = "overlay"
112
+ }) => {
113
+ const [r, s] = C(
114
+ l.map((t) => ({ ...t, isOpen: !0, defaultOpen: !0 }))
115
+ ), m = (t) => {
116
+ s((e) => {
117
+ if (o === "replace")
118
+ return [{ ...t, isOpen: !0 }];
119
+ const n = e.findIndex((i) => i.id === t.id);
120
+ if (n === -1)
121
+ return [...e, { ...t, isOpen: !0 }];
122
+ if (o === "bring-to-front") {
123
+ if (n === e.length - 1) return e;
124
+ const i = e[n];
125
+ return [
126
+ ...e.filter((P) => P.id !== t.id),
127
+ { ...i, isOpen: !0, promoting: !0 }
128
+ ];
129
+ }
130
+ return o === "pop-to" ? e.map(
131
+ (i, P) => P > n ? { ...i, isOpen: !1 } : i
132
+ ) : e;
133
+ });
134
+ }, u = (t) => {
135
+ s(
136
+ (e) => e.map((n) => n.id === t ? { ...n, isOpen: !1 } : n)
137
+ );
138
+ }, p = (t) => {
139
+ s((e) => e.filter((n) => n.id !== t));
140
+ }, c = (t) => {
141
+ s(
142
+ (e) => e.map((n) => n.id === t ? { ...n, promoting: !1 } : n)
143
+ );
144
+ };
145
+ return /* @__PURE__ */ f(
146
+ _.Provider,
147
+ {
148
+ value: { panels: r, panelVariant: d, addPanel: m, closePanel: u, removePanel: p, resetPromoting: c },
149
+ children: a
150
+ }
151
+ );
152
+ }, W = () => N(_), Y = "_push_a83oo_1", Z = {
153
+ push: Y
154
+ }, ce = ({
155
+ children: a,
156
+ className: l,
157
+ ...o
158
+ }) => {
159
+ const { panels: d, panelVariant: r, closePanel: s, removePanel: m, resetPromoting: u } = W(), p = d.length > 0;
160
+ return /* @__PURE__ */ g(
161
+ "div",
162
+ {
163
+ className: O(l, r === "push" && Z.push),
164
+ "data-open": r === "push" && p ? !0 : void 0,
165
+ ...o,
166
+ children: [
167
+ d.map(({ id: c, ...t }, e, { length: n }) => /* @__PURE__ */ f(
168
+ J,
169
+ {
170
+ "aria-hidden": e < n - 1 || void 0,
171
+ id: c,
172
+ onOpenChange: (i) => {
173
+ i || s(c);
174
+ },
175
+ onExited: () => m(c),
176
+ onPromotionEnd: () => u(c),
177
+ ...t
178
+ },
179
+ c
180
+ )),
181
+ a
182
+ ]
183
+ }
184
+ );
185
+ };
186
+ export {
187
+ J as P,
188
+ Q as U,
189
+ _ as a,
190
+ re as b,
191
+ ce as c,
192
+ W as u
193
+ };
@@ -1,35 +1,36 @@
1
1
  import { jsx as s } from "react/jsx-runtime";
2
- import { c as l } from "./clsx-OuTLNxxd.js";
3
- import { forwardRef as t } from "react";
2
+ import { c as t } from "./clsx-OuTLNxxd.js";
3
+ import { forwardRef as l } from "react";
4
4
  import { Text as o, clsx as c } from "@midas-ds/components";
5
- import '../assets/PanelTitle.css';const p = "_panelBody_2cx45_1", r = {
5
+ import '../assets/PanelTitle.css';const p = "_panelBody_1p0jk_1", r = {
6
6
  panelBody: p
7
- }, H = t(
7
+ }, H = l(
8
8
  ({ className: e, ...n }, a) => /* @__PURE__ */ s(
9
9
  "aside",
10
10
  {
11
11
  ref: a,
12
- className: l(e, r.panelBody),
12
+ className: t(e, r.panelBody),
13
13
  ...n
14
14
  }
15
15
  )
16
- ), d = "_panelContent_ahpqn_1", i = {
16
+ ), d = "_panelContent_1gfrc_1", i = {
17
17
  panelContent: d
18
- }, P = t(
18
+ }, P = l(
19
19
  ({ className: e, ...n }, a) => /* @__PURE__ */ s(
20
20
  "div",
21
21
  {
22
22
  ref: a,
23
- className: l(e, i.panelContent),
23
+ tabIndex: 0,
24
+ className: t(e, i.panelContent),
24
25
  ...n
25
26
  }
26
27
  )
27
- ), m = "_panelHeader_xyjgl_1", _ = {
28
+ ), m = "_panelHeader_1g1ux_1", _ = {
28
29
  panelHeader: m
29
30
  }, N = ({ className: e, ...n }) => /* @__PURE__ */ s(
30
31
  "div",
31
32
  {
32
- className: l(e, _.panelHeader),
33
+ className: t(e, _.panelHeader),
33
34
  ...n
34
35
  }
35
36
  ), y = "_panelTitle_w7y4m_1", x = {
@@ -8,7 +8,7 @@ import { filterDOMProps as g } from "@react-aria/utils";
8
8
  import { u as y } from "./useIsMobileDevice-D0iMVFPx.js";
9
9
  import { S as P } from "./SidebarContext-CoDRKR2m.js";
10
10
  import { c } from "./createLucideIcon-CP-mMPfa.js";
11
- import { P as z, b as T, c as N, a as k } from "./PanelTitle-j0OTJVF9.js";
11
+ import { P as z, b as T, c as N, a as k } from "./PanelTitle-CSjU7dUj.js";
12
12
  import '../assets/Sidebar.css';const M = [
13
13
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
14
14
  ["path", { d: "M9 3v18", key: "fh3hqa" }],
package/index.js CHANGED
@@ -1,21 +1,21 @@
1
- import { H as o, a as t, b as n, M as r } from "./chunks/Header-Wswx-yQj.js";
2
- import { L as i, a as x } from "./chunks/LayoutContent-jW-93mu7.js";
1
+ import { H as o, a as t, b as n, M as s } from "./chunks/Header-Wswx-yQj.js";
2
+ import { L as i, a as l } from "./chunks/LayoutContent-DDWtDRL5.js";
3
3
  import { M as P } from "./chunks/Main-BVvbCTMX.js";
4
4
  import { N as b, a as d, b as f, c as p, d as M, e as N } from "./chunks/NavigationSubMenu-DabVRyqI.js";
5
- import { P as v, a as g, b as c, c as H, u as S } from "./chunks/PanelRegion-D7EnJBY_.js";
6
- import { S as L } from "./chunks/Sidebar-CjS41s7C.js";
7
- import { S as A } from "./chunks/SidebarContext-CoDRKR2m.js";
5
+ import { P as v, a as g, b as c, c as H, U as S, u as C } from "./chunks/PanelRegion-X9t7HDPS.js";
6
+ import { S as y } from "./chunks/Sidebar-uZAklu0a.js";
7
+ import { S as U } from "./chunks/SidebarContext-CoDRKR2m.js";
8
8
  import { N as B } from "./chunks/Navbar-Do2dFMRr.js";
9
9
  import { M as R } from "./chunks/MobileMenuContext-Coj0sJ0N.js";
10
- import { P as h, a as j, b as q, c as w } from "./chunks/PanelTitle-j0OTJVF9.js";
10
+ import { P as h, a as j, b as q, c as w } from "./chunks/PanelTitle-CSjU7dUj.js";
11
11
  export {
12
12
  o as Header,
13
13
  t as HeaderAction,
14
14
  n as HeaderActions,
15
15
  i as Layout,
16
- x as LayoutContent,
16
+ l as LayoutContent,
17
17
  P as Main,
18
- r as MobileMenu,
18
+ s as MobileMenu,
19
19
  R as MobileMenuContext,
20
20
  B as Navbar,
21
21
  b as Navigation,
@@ -32,7 +32,8 @@ export {
32
32
  c as PanelProvider,
33
33
  H as PanelRegion,
34
34
  w as PanelTitle,
35
- L as Sidebar,
36
- A as SidebarContext,
37
- S as usePanels
35
+ y as Sidebar,
36
+ U as SidebarContext,
37
+ S as UsePanels,
38
+ C as usePanels
38
39
  };
package/layout/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { L as t, a as L } from "../chunks/LayoutContent-jW-93mu7.js";
1
+ import { L as t, a as L } from "../chunks/LayoutContent-DDWtDRL5.js";
2
2
  export {
3
3
  t as Layout,
4
4
  L as LayoutContent
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "description": "Midas Layout components",
15
15
  "homepage": "https://designsystem.migrationsverket.se/",
16
16
  "license": "CC0-1.0",
17
- "version": "0.1.14",
17
+ "version": "0.2.0",
18
18
  "module": "./index.js",
19
19
  "type": "module",
20
20
  "main": "./index.js",
@@ -37,7 +37,7 @@
37
37
  "./*": "./*/index.js"
38
38
  },
39
39
  "dependencies": {
40
- "@midas-ds/components": "17.15.1",
40
+ "@midas-ds/components": "17.15.2",
41
41
  "@react-aria/collections": "^3.0.3",
42
42
  "@react-aria/utils": "^3.33.1",
43
43
  "@react-stately/utils": "^3.11.0"
package/panel/Panel.d.ts CHANGED
@@ -1,12 +1,21 @@
1
+ import { ReactNode } from 'react';
1
2
  import { PanelBodyProps } from './panel-body';
2
- import { PanelTitleProps } from './panel-title';
3
- export interface PanelProps extends PanelBodyProps, Pick<PanelTitleProps, 'title'> {
3
+ export interface PanelProps extends PanelBodyProps {
4
+ /** Required unique id used to manage panel state. */
4
5
  id: string;
6
+ /** Panel title displayed in the header. */
7
+ title: string;
8
+ /** Controlled open state. */
5
9
  isOpen?: boolean;
10
+ /** Uncontrolled initial open state. */
6
11
  defaultOpen?: boolean;
12
+ /** Callback fired when the panel opens or closes. */
7
13
  onOpenChange?: (isOpen: boolean) => void;
14
+ /** Callback fired when the exit animation completes. */
8
15
  onExited?: () => void;
9
16
  promoting?: boolean;
10
17
  onPromotionEnd?: () => void;
18
+ /** Custom actions rendered in the panel header, to the right of the title. */
19
+ actions?: ReactNode;
11
20
  }
12
21
  export declare const Panel: (props: PanelProps) => import("react/jsx-runtime").JSX.Element | null;
@@ -14,12 +14,14 @@ declare const _default: {
14
14
  };
15
15
  decorators: ((Story: import('storybook/internal/csf').PartialStoryFn<import('@storybook/react').ReactRenderer, {
16
16
  id: string;
17
+ title: string;
17
18
  isOpen?: boolean | undefined;
18
19
  defaultOpen?: boolean | undefined;
19
20
  onOpenChange?: ((isOpen: boolean) => void) | undefined;
20
21
  onExited?: (() => void) | undefined;
21
22
  promoting?: boolean | undefined;
22
23
  onPromotionEnd?: (() => void) | undefined;
24
+ actions?: import('react').ReactNode;
23
25
  ref?: import('react').Ref<HTMLElement> | undefined;
24
26
  key?: import('react').Key | null | undefined;
25
27
  defaultChecked?: boolean | undefined | undefined;
@@ -42,7 +44,6 @@ declare const _default: {
42
44
  spellCheck?: (boolean | "true" | "false") | undefined;
43
45
  style?: import('react').CSSProperties | undefined;
44
46
  tabIndex?: number | undefined | undefined;
45
- title?: string | undefined | undefined;
46
47
  translate?: "yes" | "no" | undefined | undefined;
47
48
  radioGroup?: string | undefined | undefined;
48
49
  role?: import('react').AriaRole | undefined;
@@ -306,3 +307,11 @@ declare const _default: {
306
307
  export default _default;
307
308
  export declare const Primary: Story;
308
309
  export declare const Controlled: Story;
310
+ export declare const WithActions: Story;
311
+ export declare const WithScrollableContent: Story;
312
+ export declare const BehaviorReplace: Story;
313
+ export declare const BehaviorBringToFront: Story;
314
+ export declare const BehaviorPopTo: Story;
315
+ export declare const VariantOverlay: Story;
316
+ export declare const VariantPush: Story;
317
+ export declare const DetailView: Story;
@@ -1,12 +1,24 @@
1
1
  import { PanelProps } from './Panel';
2
+ import { PanelVariant } from './PanelProvider';
2
3
  export interface PanelItem extends PanelProps {
3
4
  promoting?: boolean;
4
5
  }
5
6
  export interface PanelContextValue {
7
+ /** The current list of panels. */
6
8
  panels: PanelItem[];
9
+ /** The active panel variant inherited from `PanelProvider`. */
10
+ panelVariant: PanelVariant;
11
+ /** Opens or activates a panel. If a panel with the same id exists, it is updated in place. */
7
12
  addPanel: (panel: Omit<PanelItem, 'isOpen' | 'defaultOpen'>) => void;
13
+ /** Closes a panel, triggering the exit animation. */
8
14
  closePanel: (id: string) => void;
15
+ /** Permanently removes a panel from state. */
9
16
  removePanel: (id: string) => void;
10
17
  resetPromoting: (id: string) => void;
11
18
  }
19
+ /** @internal — exists solely for PropTable introspection of usePanels return value */
20
+ export declare const UsePanels: {
21
+ (_: PanelContextValue): null;
22
+ displayName: string;
23
+ };
12
24
  export declare const PanelContext: import('react').Context<PanelContextValue>;
@@ -1,9 +1,32 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { PanelItem } from './PanelContext';
3
- export type PanelBehavior = 'bring-to-front' | 'pop-to';
3
+ export type PanelBehavior = 'replace' | 'bring-to-front' | 'pop-to';
4
+ export type PanelVariant = 'overlay' | 'push';
4
5
  export interface PanelProviderProps {
5
6
  children: ReactNode;
7
+ /** Panels to open on mount. */
6
8
  defaultPanels?: PanelItem[];
9
+ /**
10
+ * Behaviour when opening a panel that is already open.
11
+ *
12
+ * - `replace` — Replaces all existing panels. Recommended for most use cases.
13
+ * - `bring-to-front` — Panels stack; opening an existing panel moves it to the front.
14
+ * - `pop-to` — Opening an existing panel closes all panels above it.
15
+ *
16
+ * Showing one panel at a time is recommended. `replace` reflects this as the default.
17
+ * Use `bring-to-front` or `pop-to` only when multiple simultaneous panels are justified.
18
+ *
19
+ * @default 'replace'
20
+ */
7
21
  panelBehavior?: PanelBehavior;
22
+ /**
23
+ * How the panel is displayed relative to the main content.
24
+ *
25
+ * - `overlay` — Panel overlays the main content without affecting its width.
26
+ * - `push` — Panel pushes the main content aside, reducing its available width.
27
+ *
28
+ * @default 'overlay'
29
+ */
30
+ panelVariant?: PanelVariant;
8
31
  }
9
- export declare const PanelProvider: ({ children, defaultPanels, panelBehavior, }: PanelProviderProps) => import("react/jsx-runtime").JSX.Element;
32
+ export declare const PanelProvider: ({ children, defaultPanels, panelBehavior, panelVariant, }: PanelProviderProps) => import("react/jsx-runtime").JSX.Element;
package/panel/index.js CHANGED
@@ -1,13 +1,14 @@
1
- import { P as n, a as P, b as s, c as l, u as o } from "../chunks/PanelRegion-D7EnJBY_.js";
2
- import { P as t, a as d, b as i, c as x } from "../chunks/PanelTitle-j0OTJVF9.js";
1
+ import { P as n, a as s, b as P, c as l, U as o, u as r } from "../chunks/PanelRegion-X9t7HDPS.js";
2
+ import { P as d, a as i, b as x, c as b } from "../chunks/PanelTitle-CSjU7dUj.js";
3
3
  export {
4
4
  n as Panel,
5
- t as PanelBody,
6
- d as PanelContent,
7
- P as PanelContext,
8
- i as PanelHeader,
9
- s as PanelProvider,
5
+ d as PanelBody,
6
+ i as PanelContent,
7
+ s as PanelContext,
8
+ x as PanelHeader,
9
+ P as PanelProvider,
10
10
  l as PanelRegion,
11
- x as PanelTitle,
12
- o as usePanels
11
+ b as PanelTitle,
12
+ o as UsePanels,
13
+ r as usePanels
13
14
  };
package/sidebar/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { S as o } from "../chunks/Sidebar-CjS41s7C.js";
1
+ import { S as o } from "../chunks/Sidebar-uZAklu0a.js";
2
2
  import { S as t } from "../chunks/SidebarContext-CoDRKR2m.js";
3
3
  export {
4
4
  o as Sidebar,
@@ -1,178 +0,0 @@
1
- 'use client';
2
- import { jsx as m, jsxs as p } from "react/jsx-runtime";
3
- import { useRef as b, useEffect as v, forwardRef as E, createContext as C, useState as _, useContext as T } from "react";
4
- import { c as k } from "./clsx-OuTLNxxd.js";
5
- import { useLocalizedStringFormatter as I, Button as R } from "@midas-ds/components";
6
- import { useControlledState as j } from "@react-stately/utils";
7
- import { useExitAnimation as y, useObjectRef as A, useEnterAnimation as S, filterDOMProps as z } from "@react-aria/utils";
8
- import { P as N, b as L, c as M, a as w } from "./PanelTitle-j0OTJVF9.js";
9
- import { c as B } from "./createLucideIcon-CP-mMPfa.js";
10
- import '../assets/PanelRegion.css';const D = [
11
- ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
12
- ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
13
- ], F = B("x", D), H = { closePanel: "Close panel" }, X = { closePanel: "Stäng panel" }, q = {
14
- en: H,
15
- sv: X
16
- }, G = "_panel_kpvat_1", J = "_panelTitle_kpvat_59", x = {
17
- panel: G,
18
- panelTitle: J
19
- }, K = (o) => {
20
- const { onExited: l } = o, [a, f] = j(
21
- o.isOpen,
22
- o.defaultOpen || !1,
23
- o.onOpenChange
24
- ), s = b(null), r = y(s, a), d = () => f((i) => !i);
25
- return v(() => {
26
- !a && !r && l?.();
27
- }, [a, r, l]), !a && !r ? null : /* @__PURE__ */ m(
28
- Q,
29
- {
30
- isExiting: r,
31
- onPress: d,
32
- ref: s,
33
- ...o
34
- }
35
- );
36
- }, Q = E(
37
- ({
38
- className: o,
39
- title: l,
40
- onPress: a,
41
- children: f,
42
- isExiting: s,
43
- defaultOpen: r,
44
- promoting: d,
45
- onPromotionEnd: i,
46
- "aria-hidden": u,
47
- ...t
48
- }, e) => {
49
- const n = I(q), c = A(e), P = S(c, !r), h = (g) => {
50
- g.target === g.currentTarget && d && i?.();
51
- };
52
- return /* @__PURE__ */ p(
53
- N,
54
- {
55
- "aria-hidden": u || void 0,
56
- className: k(o, x.panel),
57
- ref: c,
58
- "data-entering": P || void 0,
59
- "data-exiting": s || void 0,
60
- "data-promoting": d || void 0,
61
- onAnimationEnd: h,
62
- ...z(t),
63
- children: [
64
- /* @__PURE__ */ p(L, { children: [
65
- l ? /* @__PURE__ */ m(
66
- M,
67
- {
68
- className: x.panelTitle,
69
- title: l
70
- }
71
- ) : /* @__PURE__ */ m("div", {}),
72
- /* @__PURE__ */ m(
73
- R,
74
- {
75
- "aria-label": n.format("closePanel"),
76
- onPress: a,
77
- size: "medium",
78
- variant: "icon",
79
- children: /* @__PURE__ */ m(F, { size: 20 })
80
- }
81
- )
82
- ] }),
83
- /* @__PURE__ */ m(w, { children: f })
84
- ]
85
- }
86
- );
87
- }
88
- ), O = C({
89
- panels: [],
90
- addPanel: () => {
91
- },
92
- closePanel: () => {
93
- },
94
- removePanel: () => {
95
- },
96
- resetPromoting: () => {
97
- }
98
- }), oe = ({
99
- children: o,
100
- defaultPanels: l = [],
101
- panelBehavior: a = "bring-to-front"
102
- }) => {
103
- const [f, s] = _(
104
- l.map((t) => ({ ...t, isOpen: !0, defaultOpen: !0 }))
105
- ), r = (t) => {
106
- s((e) => {
107
- const n = e.findIndex((c) => c.id === t.id);
108
- if (n === -1)
109
- return [...e, { ...t, isOpen: !0 }];
110
- if (a === "bring-to-front") {
111
- if (n === e.length - 1) return e;
112
- const c = e[n];
113
- return [
114
- ...e.filter((P) => P.id !== t.id),
115
- { ...c, isOpen: !0, promoting: !0 }
116
- ];
117
- }
118
- return a === "pop-to" ? e.map(
119
- (c, P) => P > n ? { ...c, isOpen: !1 } : c
120
- ) : e;
121
- });
122
- }, d = (t) => {
123
- s(
124
- (e) => e.map((n) => n.id === t ? { ...n, isOpen: !1 } : n)
125
- );
126
- }, i = (t) => {
127
- s((e) => e.filter((n) => n.id !== t));
128
- }, u = (t) => {
129
- s(
130
- (e) => e.map((n) => n.id === t ? { ...n, promoting: !1 } : n)
131
- );
132
- };
133
- return /* @__PURE__ */ m(
134
- O.Provider,
135
- {
136
- value: { panels: f, addPanel: r, closePanel: d, removePanel: i, resetPromoting: u },
137
- children: o
138
- }
139
- );
140
- }, U = () => T(O), ae = ({
141
- children: o,
142
- className: l,
143
- ...a
144
- }) => {
145
- const { panels: f, closePanel: s, removePanel: r, resetPromoting: d } = U();
146
- return /* @__PURE__ */ p(
147
- "div",
148
- {
149
- className: l,
150
- ...a,
151
- children: [
152
- f.map(({ id: i, ...u }, t, { length: e }) => /* @__PURE__ */ m(
153
- K,
154
- {
155
- "aria-hidden": t < e - 1 || void 0,
156
- id: i,
157
- "data-debug": "Panel",
158
- onOpenChange: (n) => {
159
- n || s(i);
160
- },
161
- onExited: () => r(i),
162
- onPromotionEnd: () => d(i),
163
- ...u
164
- },
165
- i
166
- )),
167
- o
168
- ]
169
- }
170
- );
171
- };
172
- export {
173
- K as P,
174
- O as a,
175
- oe as b,
176
- ae as c,
177
- U as u
178
- };