@sproutsocial/seeds-react-panel 1.0.11 → 1.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/.turbo/turbo-build.log +11 -11
- package/CHANGELOG.md +17 -0
- package/dist/esm/index.js +445 -164
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +28 -7
- package/dist/index.d.ts +28 -7
- package/dist/index.js +449 -168
- package/dist/index.js.map +1 -1
- package/dist/panel.css +92 -0
- package/package.json +11 -3
- package/src/Panel.stories.tsx +33 -0
- package/src/Panel.tsx +13 -137
- package/src/PanelContent.tsx +67 -1
- package/src/PanelFooter.tsx +48 -1
- package/src/PanelHeader.tsx +66 -17
- package/src/PanelHybrid.tsx +52 -0
- package/src/PanelMobile.tsx +90 -0
- package/src/PanelMobileActionsHeader.tsx +8 -12
- package/src/PanelShared.tsx +189 -0
- package/src/PanelStyled.tsx +62 -0
- package/src/PanelTailwind.tsx +86 -0
- package/src/__tests__/Panel.test.tsx +47 -1
- package/src/css.d.ts +1 -0
- package/src/panel.css +92 -0
|
@@ -192,6 +192,50 @@ describe("Panel (desktop / inline mode)", () => {
|
|
|
192
192
|
});
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
+
describe("Panel (hybrid routing)", () => {
|
|
196
|
+
it("renders the Tailwind path (seeds-panel class, no sc- class) by default", () => {
|
|
197
|
+
renderPanel({ defaultOpen: true });
|
|
198
|
+
|
|
199
|
+
const panel = screen.getByRole("complementary");
|
|
200
|
+
expect(panel).toHaveClass("seeds-panel");
|
|
201
|
+
expect(panel.className).not.toMatch(/\bsc-/);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("stays on the Tailwind path when only the domain width prop is set", () => {
|
|
205
|
+
// `width` is a Panel domain prop whose name also lives in
|
|
206
|
+
// STYLED_SYSTEM_PROPS. It is destructured out before the routing gate, so
|
|
207
|
+
// setting it must NOT force the styled path — it stays Tailwind and the
|
|
208
|
+
// width is applied inline as flex-basis.
|
|
209
|
+
renderPanel({ defaultOpen: true, width: 500 });
|
|
210
|
+
|
|
211
|
+
const panel = screen.getByRole("complementary");
|
|
212
|
+
expect(panel).toHaveClass("seeds-panel");
|
|
213
|
+
expect(panel.className).not.toMatch(/\bsc-/);
|
|
214
|
+
expect(panel).toHaveStyle("flex-basis: 500px");
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("routes to the styled-components path for COMMON styled-system props", () => {
|
|
218
|
+
// A margin prop (COMMON mixin) is a genuine styled-system prop, so the
|
|
219
|
+
// panel must fall back to the styled container: it is not the Tailwind
|
|
220
|
+
// element (no seeds-panel class) and only the styled path produces a
|
|
221
|
+
// styled-components rule (flex-grow: 0 is set statically on PanelContainer).
|
|
222
|
+
renderPanel({ defaultOpen: true, mt: 400 });
|
|
223
|
+
|
|
224
|
+
const panel = screen.getByRole("complementary");
|
|
225
|
+
expect(panel).not.toHaveClass("seeds-panel");
|
|
226
|
+
expect(panel).toHaveStyleRule("flex-grow", "0");
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("merges a forwarded className onto seeds-panel on the Tailwind path", () => {
|
|
230
|
+
renderPanel({ defaultOpen: true, className: "mx-200 p-300" });
|
|
231
|
+
|
|
232
|
+
const panel = screen.getByRole("complementary");
|
|
233
|
+
expect(panel).toHaveClass("seeds-panel");
|
|
234
|
+
expect(panel).toHaveClass("mx-200");
|
|
235
|
+
expect(panel).toHaveClass("p-300");
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
195
239
|
describe("Panel (mobile / drawer mode)", () => {
|
|
196
240
|
let originalMatchMedia: typeof window.matchMedia | undefined;
|
|
197
241
|
|
|
@@ -392,9 +436,11 @@ describe("Panel (mobile / drawer mode)", () => {
|
|
|
392
436
|
|
|
393
437
|
// The footer compensates for the Drawer popup's --bleed (3rem of overscroll
|
|
394
438
|
// below the viewport) so its actions stay fully visible above the fold.
|
|
439
|
+
// The Tailwind footer is a plain <div> with the margin applied inline, so we
|
|
440
|
+
// assert the computed inline style rather than a styled-components rule.
|
|
395
441
|
expect(
|
|
396
442
|
screen.getByText("footer content").closest("[data-panel-footer]")
|
|
397
|
-
).
|
|
443
|
+
).toHaveStyle("margin-bottom: var(--bleed, 0px)");
|
|
398
444
|
});
|
|
399
445
|
});
|
|
400
446
|
|
package/src/css.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module "*.css";
|
package/src/panel.css
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seeds Panel component classes.
|
|
3
|
+
* Component-scoped port of the static styled-components chrome in styles.ts.
|
|
4
|
+
* Used by PanelTailwind.tsx and the Tailwind sub-component paths.
|
|
5
|
+
*
|
|
6
|
+
* Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for the
|
|
7
|
+
* CSS variable definitions (and dark mode support).
|
|
8
|
+
*
|
|
9
|
+
* Runtime geometry (flex-basis, the gap margin, the direction shape, and the
|
|
10
|
+
* inner min-width/min-height) is applied as inline style on the elements, not
|
|
11
|
+
* here — the jsdom tests assert those computed values and CSS is not loaded in
|
|
12
|
+
* that environment. Only static chrome lives in these classes.
|
|
13
|
+
*
|
|
14
|
+
* All rules live in `@layer components` so consumer Tailwind utilities (e.g.
|
|
15
|
+
* mx-200, p-300, inline-flex) win the cascade and can override these component
|
|
16
|
+
* defaults, rather than tying/beating them on specificity. Unlayered rules
|
|
17
|
+
* would outrank any layered utility per the CSS cascade-layers spec.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
@layer components {
|
|
21
|
+
/* Container --------------------------------------------------------------- */
|
|
22
|
+
|
|
23
|
+
.seeds-panel {
|
|
24
|
+
background: var(--color-container-bg-base);
|
|
25
|
+
flex-grow: 0;
|
|
26
|
+
flex-shrink: 0;
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
border-radius: var(--radius-800);
|
|
29
|
+
transition: flex-basis var(--duration-medium) ease-in-out,
|
|
30
|
+
margin var(--duration-medium) ease-in-out;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.seeds-panel-inner {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Header ------------------------------------------------------------------ */
|
|
40
|
+
|
|
41
|
+
.seeds-panel-header {
|
|
42
|
+
display: flex;
|
|
43
|
+
flex: 0 0 auto;
|
|
44
|
+
justify-content: space-between;
|
|
45
|
+
align-items: center;
|
|
46
|
+
padding: var(--space-400);
|
|
47
|
+
border-bottom: 1px solid var(--color-container-border-base);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Content ----------------------------------------------------------------- */
|
|
51
|
+
|
|
52
|
+
/* overflow-y (and, when headerless, display/flex-direction) are set inline
|
|
53
|
+
by PanelContentTailwind because the tests assert them under jsdom. */
|
|
54
|
+
.seeds-panel-content {
|
|
55
|
+
flex: 1 1 auto;
|
|
56
|
+
min-height: 0;
|
|
57
|
+
padding: var(--space-450);
|
|
58
|
+
color: var(--color-text-body);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Headerless content renders flush; the children own all chrome/padding. */
|
|
62
|
+
.seeds-panel-content--headerless {
|
|
63
|
+
padding: 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Footer ------------------------------------------------------------------ */
|
|
67
|
+
|
|
68
|
+
/* margin-bottom (var(--bleed, 0px)) is set inline by PanelFooterTailwind. */
|
|
69
|
+
.seeds-panel-footer {
|
|
70
|
+
flex: 0 0 auto;
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
padding: var(--space-450);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Mobile actions header --------------------------------------------------- */
|
|
76
|
+
|
|
77
|
+
.seeds-panel-mobile-actions-header {
|
|
78
|
+
display: flex;
|
|
79
|
+
flex: 0 0 auto;
|
|
80
|
+
align-items: center;
|
|
81
|
+
justify-content: space-between;
|
|
82
|
+
padding-top: var(--space-400);
|
|
83
|
+
padding-left: var(--space-450);
|
|
84
|
+
padding-right: var(--space-450);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.seeds-panel-mobile-actions-buttons {
|
|
88
|
+
display: flex;
|
|
89
|
+
align-items: center;
|
|
90
|
+
gap: var(--space-200);
|
|
91
|
+
}
|
|
92
|
+
}
|