@versini/ui-panel 2.2.7 → 2.2.9

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
@@ -1,17 +1,33 @@
1
1
  # @versini/ui-panel
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@versini/ui-panel?style=flat-square)](https://www.npmjs.com/package/@versini/ui-panel)
4
+ ![npm package minimized gzipped size](<https://img.shields.io/bundlejs/size/%40versini%2Fui-panel?style=flat-square&label=size%20(gzip)>)
4
5
 
5
6
  > An accessible React slide-out panel component built with TypeScript and TailwindCSS.
6
7
 
7
- The Panel component provides slide-out panels and drawers with focus management, keyboard navigation, and customizable positioning.
8
-
8
+ The Panel component provides slide-out panels and drawers with focus management, keyboard navigation, document title management, optional animations, and customizable positioning / sizing.
9
9
 
10
10
  ## Table of Contents
11
11
 
12
+ - [Table of Contents](#table-of-contents)
12
13
  - [Features](#features)
13
14
  - [Installation](#installation)
14
15
  - [Usage](#usage)
16
+ - [Examples](#examples)
17
+ - [Message Box Variant](#message-box-variant)
18
+ - [Animated Panel (Fade)](#animated-panel-fade)
19
+ - [API](#api)
20
+ - [Panel Props](#panel-props)
21
+
22
+ ## Features
23
+
24
+ - **🪟 Versatile Layouts**: Standard panel and message box variants (`kind` prop)
25
+ - **🎯 Focus Management**: Uses underlying modal primitives for proper focus trapping & return
26
+ - **♿ Accessible**: ARIA compliant structure with heading, description, close control
27
+ - **🎬 Optional Animations**: Slide or fade entrance animations (`animation` / `animationType`)
28
+ - **📐 Responsive Sizing**: Predefined max widths (`small`, `medium`, `large`) above md breakpoint
29
+ - **🧩 Composable**: Footer slot for actions / extra content
30
+ - **🧪 Type Safe**: Fully typed props with inline documentation
15
31
 
16
32
  ## Installation
17
33
 
@@ -19,7 +35,7 @@ The Panel component provides slide-out panels and drawers with focus management,
19
35
  npm install @versini/ui-panel
20
36
  ```
21
37
 
22
- > **Note**: This component requires TailwindCSS and the `@versini/ui-styles` plugin for proper styling. See the [root README](../../README.md#tailwindcss-setup) for complete setup instructions.
38
+ > **Note**: This component requires TailwindCSS and the `@versini/ui-styles` plugin for proper styling. See the [installation documentation](https://versini-org.github.io/ui-components/?path=/docs/getting-started-installation--docs) for complete setup instructions.
23
39
 
24
40
  ## Usage
25
41
 
@@ -29,18 +45,87 @@ import { useState } from "react";
29
45
 
30
46
  function App() {
31
47
  const [open, setOpen] = useState(false);
32
-
48
+
33
49
  return (
34
50
  <>
35
51
  <button onClick={() => setOpen(true)}>Open Panel</button>
52
+ <Panel title="Panel Title" open={open} onOpenChange={setOpen}>
53
+ Panel content goes here.
54
+ </Panel>
55
+ </>
56
+ );
57
+ }
58
+ ```
59
+
60
+ ## Examples
61
+
62
+ ### Message Box Variant
63
+
64
+ ```tsx
65
+ import { Panel } from "@versini/ui-panel";
66
+ import { useState } from "react";
67
+
68
+ function MessageBoxExample() {
69
+ const [open, setOpen] = useState(false);
70
+ return (
71
+ <>
72
+ <button onClick={() => setOpen(true)}>Show Message</button>
36
73
  <Panel
37
- title="Panel Title"
74
+ kind="messagebox"
75
+ title="Session Expired"
38
76
  open={open}
39
77
  onOpenChange={setOpen}
78
+ footer={
79
+ <div className="flex justify-end gap-2">
80
+ <button
81
+ className="px-3 py-1 rounded bg-surface-lighter"
82
+ onClick={() => setOpen(false)}
83
+ >
84
+ Dismiss
85
+ </button>
86
+ <button className="px-3 py-1 rounded bg-blue-600 text-white">
87
+ Re‑authenticate
88
+ </button>
89
+ </div>
90
+ }
40
91
  >
41
- Panel content goes here.
92
+ Your session has expired. Please sign in again to continue.
42
93
  </Panel>
43
94
  </>
44
95
  );
45
96
  }
46
97
  ```
98
+
99
+ ### Animated Panel (Fade)
100
+
101
+ ```tsx
102
+ <Panel
103
+ title="Animated Panel"
104
+ open={open}
105
+ onOpenChange={setOpen}
106
+ animation
107
+ animationType="fade"
108
+ >
109
+ Content with fade animation.
110
+ </Panel>
111
+ ```
112
+
113
+ ## API
114
+
115
+ ### Panel Props
116
+
117
+ | Prop | Type | Default | Description |
118
+ | --------------- | ------------------------- | ------------- | ---------------------------------------------------------------------- | ------------------------------------------------ | ------------------------------------------------------- |
119
+ | `open` | `boolean` | - | Whether the panel is open. |
120
+ | `onOpenChange` | `(open: boolean) => void` | - | Callback fired when open state changes. |
121
+ | `title` | `string` | - | Title displayed in the header (also used to augment `document.title`). |
122
+ | `children` | `React.ReactNode` | - | Main content of the panel. |
123
+ | `footer` | `React.ReactNode` | - | Optional footer content (actions, etc.). |
124
+ | `className` | `string` | - | Extra classes applied to width wrapper (overrides default width). |
125
+ | `borderMode` | `"dark" | "light"` | `"light"` | Visual style of border / surface. |
126
+ | `kind` | `"panel" | "messagebox"` | `"panel"` | Layout variant. |
127
+ | `animation` | `boolean` | `false` | Enable entrance animation. |
128
+ | `animationType` | `"slide" | "fade"` | `"slide"` | Animation style (only when `animation` is true). |
129
+ | `maxWidth` | `"small" | "medium" | "large"` | `"medium"` | Max width applied (≥ md breakpoint) for `kind="panel"`. |
130
+
131
+ > Also inherits any valid props for the underlying modal primitives where relevant.
@@ -349,7 +349,7 @@ function $e() {
349
349
  e.current = !1;
350
350
  }), []), me(() => e.current, []);
351
351
  }
352
- function Ae(e) {
352
+ function Oe(e) {
353
353
  return Z(() => e.every((r) => r == null) ? () => {
354
354
  } : (r) => {
355
355
  e.forEach((t) => {
@@ -357,7 +357,7 @@ function Ae(e) {
357
357
  });
358
358
  }, [...e]);
359
359
  }
360
- const Oe = {
360
+ const Ae = {
361
361
  x: 0,
362
362
  y: 0,
363
363
  width: 0,
@@ -367,8 +367,8 @@ const Oe = {
367
367
  bottom: 0,
368
368
  right: 0
369
369
  };
370
- function P(e) {
371
- const r = $e(), t = N(0), a = N(null), [i, o] = Q(Oe), s = Z(() => typeof ResizeObserver > "u" ? null : new ResizeObserver((d) => {
370
+ function z(e) {
371
+ const r = $e(), t = N(0), a = N(null), [i, o] = Q(Ae), s = Z(() => typeof ResizeObserver > "u" ? null : new ResizeObserver((d) => {
372
372
  const c = d[0];
373
373
  c && (cancelAnimationFrame(t.current), t.current = requestAnimationFrame(() => {
374
374
  a.current && r() && o(c.contentRect);
@@ -385,14 +385,14 @@ const M = {
385
385
  // w-8
386
386
  large: 48
387
387
  // w-12
388
- }, ze = {
388
+ }, Pe = {
389
389
  small: 16,
390
390
  // px-2 x 2
391
391
  medium: 24,
392
392
  // px-3 x 2
393
393
  large: 32
394
394
  // px-4 x 2
395
- }, Pe = 2, De = 300, U = F.forwardRef(
395
+ }, ze = 2, De = 300, U = F.forwardRef(
396
396
  ({
397
397
  children: e,
398
398
  disabled: r = !1,
@@ -433,21 +433,21 @@ const M = {
433
433
  radius: I,
434
434
  variant: j,
435
435
  animated: k
436
- }), se = Re({ mode: t, raw: d, iconClassName: ie, variant: j }), G = Me({ animated: k }), ce = "flex items-center justify-center relative w-full h-full overflow-hidden", [v, A] = P(), [p, O] = P(), [S, Y] = P(), z = N(0), x = N(null), E = N(null), de = Ae([ne, x]);
436
+ }), se = Re({ mode: t, raw: d, iconClassName: ie, variant: j }), G = Me({ animated: k }), ce = "flex items-center justify-center relative w-full h-full overflow-hidden", [v, O] = z(), [p, A] = z(), [S, Y] = z(), P = N(0), x = N(null), E = N(null), de = Oe([ne, x]);
437
437
  return H(() => {
438
- S && S.current && k && (z.current = Y.width + ze[m] + (c ? 0 : Pe), x.current && !x.current.style.width && (x.current.style.width = `${M[m]}px`));
438
+ S && S.current && k && (P.current = Y.width + Pe[m] + (c ? 0 : ze), x.current && !x.current.style.width && (x.current.style.width = `${M[m]}px`));
439
439
  }, [Y, S, m, c, k]), H(() => {
440
440
  if (x && x.current && k) {
441
441
  let C = M[m];
442
- u && v && A.width > 0 ? C = A.width + z.current : f && p && O.width > 0 && (C = O.width + z.current), E.current && clearTimeout(E.current), C !== parseInt(x.current.style.width || "0", 10) && (v.current && (v.current.style.opacity = "0"), p.current && (p.current.style.opacity = "0"), x.current.style.width = `${C}px`, C > M[m] && (E.current = setTimeout(() => {
442
+ u && v && O.width > 0 ? C = O.width + P.current : f && p && A.width > 0 && (C = A.width + P.current), E.current && clearTimeout(E.current), C !== parseInt(x.current.style.width || "0", 10) && (v.current && (v.current.style.opacity = "0"), p.current && (p.current.style.opacity = "0"), x.current.style.width = `${C}px`, C > M[m] && (E.current = setTimeout(() => {
443
443
  v.current && u && (v.current.style.opacity = "1"), p.current && f && (p.current.style.opacity = "1"), E.current = null;
444
444
  }, De * 0.8))), C === M[m] && (v.current && (v.current.style.opacity = "0"), p.current && (p.current.style.opacity = "0"));
445
445
  }
446
446
  }, [
447
- A,
447
+ O,
448
448
  u,
449
449
  v,
450
- O,
450
+ A,
451
451
  f,
452
452
  p,
453
453
  m,
@@ -506,13 +506,13 @@ const M = {
506
506
  );
507
507
  U.displayName = "ButtonIcon";
508
508
  /*!
509
- @versini/ui-button v7.1.3
509
+ @versini/ui-button v7.1.5
510
510
  © 2025 gizmette.com
511
511
  */
512
512
  try {
513
513
  window.__VERSINI_UI_BUTTON__ || (window.__VERSINI_UI_BUTTON__ = {
514
- version: "7.1.3",
515
- buildTime: "08/23/2025 09:08 AM EDT",
514
+ version: "7.1.5",
515
+ buildTime: "08/23/2025 12:21 PM EDT",
516
516
  homepage: "https://github.com/aversini/ui-components",
517
517
  license: "MIT"
518
518
  });
@@ -714,13 +714,13 @@ const Ye = h.forwardRef(function(e, r) {
714
714
  }) });
715
715
  });
716
716
  /*!
717
- @versini/ui-modal v2.0.7
717
+ @versini/ui-modal v2.0.9
718
718
  © 2025 gizmette.com
719
719
  */
720
720
  try {
721
721
  window.__VERSINI_UI_MODAL__ || (window.__VERSINI_UI_MODAL__ = {
722
- version: "2.0.7",
723
- buildTime: "08/23/2025 09:08 AM EDT",
722
+ version: "2.0.9",
723
+ buildTime: "08/23/2025 12:22 PM EDT",
724
724
  homepage: "https://github.com/aversini/ui-components",
725
725
  license: "MIT"
726
726
  });
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import { MESSAGEBOX_CLASSNAME as o, PANEL_CLASSNAME as E, Panel as A } from "./components/Panel/Panel.js";
1
+ import { MESSAGEBOX_CLASSNAME as o, PANEL_CLASSNAME as E, Panel as n } from "./components/Panel/Panel.js";
2
2
  /*!
3
- @versini/ui-panel v2.2.7
3
+ @versini/ui-panel v2.2.9
4
4
  © 2025 gizmette.com
5
5
  */
6
6
  try {
7
7
  window.__VERSINI_UI_PANEL__ || (window.__VERSINI_UI_PANEL__ = {
8
- version: "2.2.7",
9
- buildTime: "08/23/2025 09:09 AM EDT",
8
+ version: "2.2.9",
9
+ buildTime: "08/23/2025 12:22 PM EDT",
10
10
  homepage: "https://github.com/aversini/ui-components",
11
11
  license: "MIT"
12
12
  });
@@ -15,5 +15,5 @@ try {
15
15
  export {
16
16
  o as MESSAGEBOX_CLASSNAME,
17
17
  E as PANEL_CLASSNAME,
18
- A as Panel
18
+ n as Panel
19
19
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@versini/ui-panel",
3
- "version": "2.2.7",
3
+ "version": "2.2.9",
4
4
  "license": "MIT",
5
5
  "author": "Arno Versini",
6
6
  "publishConfig": {
@@ -54,5 +54,5 @@
54
54
  "sideEffects": [
55
55
  "**/*.css"
56
56
  ],
57
- "gitHead": "7bbfa99a4441ef5b0828a37d190f694e199b663d"
57
+ "gitHead": "d568e20474c6c87f836c4cb6548f2cc0143a353c"
58
58
  }