@versini/ui-liveregion 2.0.6 → 2.0.8
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 +106 -1
- package/dist/components/LiveRegion/LiveRegion.js +32 -32
- package/dist/index.js +3 -3
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -1,3 +1,108 @@
|
|
|
1
1
|
# @versini/ui-liveregion
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@versini/ui-liveregion)
|
|
4
|
+
|
|
5
|
+
> An accessible React live region component for dynamic content announcements.
|
|
6
|
+
|
|
7
|
+
The LiveRegion component provides ARIA live regions for announcing dynamic content changes to screen readers, essential for accessible web applications with real-time updates.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Features](#features)
|
|
13
|
+
- [Installation](#installation)
|
|
14
|
+
- [Usage](#usage)
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **♿ Essential Accessibility**: WCAG compliant ARIA live regions
|
|
19
|
+
- **🔄 Dynamic Updates**: Real-time content announcements for screen readers
|
|
20
|
+
- **🎯 Configurable**: Different politeness levels (polite, assertive)
|
|
21
|
+
- **🌲 Tree-shakeable**: Lightweight and optimized for bundle size
|
|
22
|
+
- **🔧 TypeScript**: Fully typed with comprehensive prop definitions
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @versini/ui-liveregion
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
> **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.
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
### Basic Live Region
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { LiveRegion } from "@versini/ui-liveregion";
|
|
38
|
+
|
|
39
|
+
function App() {
|
|
40
|
+
const [status, setStatus] = useState("");
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<>
|
|
44
|
+
<button onClick={() => setStatus("Form saved successfully!")}>
|
|
45
|
+
Save Form
|
|
46
|
+
</button>
|
|
47
|
+
<LiveRegion>{status}</LiveRegion>
|
|
48
|
+
</>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Assertive Live Region
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
import { LiveRegion } from "@versini/ui-liveregion";
|
|
57
|
+
|
|
58
|
+
function App() {
|
|
59
|
+
const [error, setError] = useState("");
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
<form onSubmit={handleSubmit}>
|
|
64
|
+
{/* form fields */}
|
|
65
|
+
</form>
|
|
66
|
+
<LiveRegion type="assertive">{error}</LiveRegion>
|
|
67
|
+
</>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Examples
|
|
73
|
+
|
|
74
|
+
### Form Status Announcements
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { LiveRegion } from "@versini/ui-liveregion";
|
|
78
|
+
|
|
79
|
+
function ContactForm() {
|
|
80
|
+
const [status, setStatus] = useState("");
|
|
81
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
82
|
+
|
|
83
|
+
const handleSubmit = async (e) => {
|
|
84
|
+
e.preventDefault();
|
|
85
|
+
setIsSubmitting(true);
|
|
86
|
+
setStatus("Submitting form...");
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
await submitForm();
|
|
90
|
+
setStatus("Form submitted successfully!");
|
|
91
|
+
} catch (error) {
|
|
92
|
+
setStatus("Error submitting form. Please try again.");
|
|
93
|
+
} finally {
|
|
94
|
+
setIsSubmitting(false);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<>
|
|
100
|
+
<form onSubmit={handleSubmit}>
|
|
101
|
+
{/* form fields */}
|
|
102
|
+
<button disabled={isSubmitting}>Submit</button>
|
|
103
|
+
</form>
|
|
104
|
+
<LiveRegion>{status}</LiveRegion>
|
|
105
|
+
</>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as O } from "react/jsx-runtime";
|
|
2
2
|
import C from "clsx";
|
|
3
3
|
import { useRef as i, useReducer as L, useEffect as g } from "react";
|
|
4
|
-
const
|
|
4
|
+
const c = "SET_ANNOUNCEMENT", E = "CLEAR_ANNOUNCEMENT", v = {
|
|
5
5
|
alert: null,
|
|
6
6
|
alertdialog: null,
|
|
7
7
|
log: "polite",
|
|
@@ -10,13 +10,13 @@ const E = "SET_ANNOUNCEMENT", f = "CLEAR_ANNOUNCEMENT", v = {
|
|
|
10
10
|
status: "polite",
|
|
11
11
|
timer: "assertive"
|
|
12
12
|
}, y = (t, e) => {
|
|
13
|
-
switch (e
|
|
14
|
-
case
|
|
13
|
+
switch (e?.type) {
|
|
14
|
+
case c:
|
|
15
15
|
return {
|
|
16
16
|
...t,
|
|
17
17
|
announcement: e.payload
|
|
18
18
|
};
|
|
19
|
-
case
|
|
19
|
+
case E:
|
|
20
20
|
return {
|
|
21
21
|
...t,
|
|
22
22
|
announcement: null
|
|
@@ -29,19 +29,19 @@ const E = "SET_ANNOUNCEMENT", f = "CLEAR_ANNOUNCEMENT", v = {
|
|
|
29
29
|
dispatch: e
|
|
30
30
|
}) => {
|
|
31
31
|
e({
|
|
32
|
-
type:
|
|
32
|
+
type: E
|
|
33
33
|
}), typeof t == "function" && t();
|
|
34
34
|
}, N = ({
|
|
35
35
|
children: t,
|
|
36
36
|
clearAnnouncementDelay: e,
|
|
37
|
-
clearAnnouncementTimeoutRef:
|
|
37
|
+
clearAnnouncementTimeoutRef: o,
|
|
38
38
|
onAnnouncementClear: s,
|
|
39
39
|
dispatch: u
|
|
40
40
|
}) => {
|
|
41
|
-
clearTimeout(
|
|
42
|
-
type:
|
|
41
|
+
clearTimeout(o.current), t !== null && u({
|
|
42
|
+
type: c,
|
|
43
43
|
payload: t
|
|
44
|
-
}), e && (
|
|
44
|
+
}), e && (o.current = setTimeout(
|
|
45
45
|
() => R({
|
|
46
46
|
onAnnouncementClear: s,
|
|
47
47
|
dispatch: u
|
|
@@ -51,59 +51,59 @@ const E = "SET_ANNOUNCEMENT", f = "CLEAR_ANNOUNCEMENT", v = {
|
|
|
51
51
|
}, U = ({
|
|
52
52
|
children: t,
|
|
53
53
|
announcementTimeoutRef: e,
|
|
54
|
-
announcementDelay:
|
|
54
|
+
announcementDelay: o,
|
|
55
55
|
clearAnnouncementDelay: s,
|
|
56
56
|
clearAnnouncementTimeoutRef: u,
|
|
57
|
-
onAnnouncementClear:
|
|
58
|
-
dispatch:
|
|
57
|
+
onAnnouncementClear: r,
|
|
58
|
+
dispatch: l
|
|
59
59
|
}) => {
|
|
60
|
-
clearTimeout(e.current),
|
|
60
|
+
clearTimeout(e.current), o ? e.current = setTimeout(N, o, {
|
|
61
61
|
children: t,
|
|
62
62
|
clearAnnouncementDelay: s,
|
|
63
63
|
clearAnnouncementTimeoutRef: u,
|
|
64
|
-
onAnnouncementClear:
|
|
65
|
-
dispatch:
|
|
64
|
+
onAnnouncementClear: r,
|
|
65
|
+
dispatch: l
|
|
66
66
|
}) : N({
|
|
67
67
|
children: t,
|
|
68
68
|
clearAnnouncementDelay: s,
|
|
69
69
|
clearAnnouncementTimeoutRef: u,
|
|
70
|
-
onAnnouncementClear:
|
|
71
|
-
dispatch:
|
|
70
|
+
onAnnouncementClear: r,
|
|
71
|
+
dispatch: l
|
|
72
72
|
});
|
|
73
73
|
};
|
|
74
74
|
function x({
|
|
75
75
|
children: t,
|
|
76
76
|
className: e,
|
|
77
|
-
politeness:
|
|
77
|
+
politeness: o,
|
|
78
78
|
role: s = null,
|
|
79
79
|
announcementDelay: u,
|
|
80
|
-
clearAnnouncementDelay:
|
|
81
|
-
onAnnouncementClear:
|
|
82
|
-
visible:
|
|
83
|
-
...
|
|
80
|
+
clearAnnouncementDelay: r,
|
|
81
|
+
onAnnouncementClear: l,
|
|
82
|
+
visible: f,
|
|
83
|
+
...a
|
|
84
84
|
}) {
|
|
85
|
-
const
|
|
85
|
+
const p = i(null), T = i(null), [m, _] = L(y, {
|
|
86
86
|
announcement: null
|
|
87
87
|
});
|
|
88
|
-
let n =
|
|
88
|
+
let n = o;
|
|
89
89
|
typeof n > "u" && (n = s ? v[s] : "assertive"), g(() => {
|
|
90
90
|
U({
|
|
91
|
-
announcementTimeoutRef:
|
|
91
|
+
announcementTimeoutRef: p,
|
|
92
92
|
announcementDelay: u,
|
|
93
93
|
children: t,
|
|
94
|
-
clearAnnouncementDelay:
|
|
95
|
-
clearAnnouncementTimeoutRef:
|
|
96
|
-
onAnnouncementClear:
|
|
94
|
+
clearAnnouncementDelay: r,
|
|
95
|
+
clearAnnouncementTimeoutRef: T,
|
|
96
|
+
onAnnouncementClear: l,
|
|
97
97
|
dispatch: _
|
|
98
98
|
});
|
|
99
99
|
}, [
|
|
100
100
|
t,
|
|
101
101
|
u,
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
r,
|
|
103
|
+
l
|
|
104
104
|
]);
|
|
105
105
|
const d = C(e, {
|
|
106
|
-
"sr-only": !
|
|
106
|
+
"sr-only": !f
|
|
107
107
|
});
|
|
108
108
|
return /* @__PURE__ */ O(
|
|
109
109
|
"div",
|
|
@@ -111,7 +111,7 @@ function x({
|
|
|
111
111
|
"aria-live": n,
|
|
112
112
|
...s && { role: s },
|
|
113
113
|
className: d,
|
|
114
|
-
...
|
|
114
|
+
...a,
|
|
115
115
|
children: m.announcement
|
|
116
116
|
}
|
|
117
117
|
);
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { LiveRegion as o } from "./components/LiveRegion/LiveRegion.js";
|
|
2
2
|
/*!
|
|
3
|
-
@versini/ui-liveregion v2.0.
|
|
3
|
+
@versini/ui-liveregion v2.0.8
|
|
4
4
|
© 2025 gizmette.com
|
|
5
5
|
*/
|
|
6
6
|
try {
|
|
7
7
|
window.__VERSINI_UI_LIVEREGION__ || (window.__VERSINI_UI_LIVEREGION__ = {
|
|
8
|
-
version: "2.0.
|
|
9
|
-
buildTime: "
|
|
8
|
+
version: "2.0.8",
|
|
9
|
+
buildTime: "08/14/2025 06:04 PM EDT",
|
|
10
10
|
homepage: "https://github.com/aversini/ui-components",
|
|
11
11
|
license: "MIT"
|
|
12
12
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@versini/ui-liveregion",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Arno Versini",
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"dev:types": "tsup --watch src",
|
|
28
28
|
"dev": "npm-run-all clean --parallel dev:js dev:types",
|
|
29
29
|
"lint": "biome lint src",
|
|
30
|
+
"lint:fix": "biome check src --write --no-errors-on-unmatched",
|
|
30
31
|
"prettier": "biome check --write --no-errors-on-unmatched",
|
|
31
32
|
"start": "static-server dist --port 5173",
|
|
32
33
|
"test:coverage:ui": "vitest --coverage --ui",
|
|
@@ -39,11 +40,11 @@
|
|
|
39
40
|
"react-dom": "^18.3.1 || ^19.0.0"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
|
-
"@testing-library/jest-dom": "6.
|
|
43
|
-
"@versini/ui-types": "
|
|
43
|
+
"@testing-library/jest-dom": "6.7.0",
|
|
44
|
+
"@versini/ui-types": "../ui-types"
|
|
44
45
|
},
|
|
45
46
|
"sideEffects": [
|
|
46
47
|
"**/*.css"
|
|
47
48
|
],
|
|
48
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "a2a11904039a5bc55ff17a954e4a16073abbe0bf"
|
|
49
50
|
}
|