@radix-solid-js/announce 0.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/dist/index.cjs +95 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var solidJs = require('solid-js');
|
|
4
|
+
var web = require('solid-js/web');
|
|
5
|
+
var primitiveComponent = require('@radix-solid-js/primitive-component');
|
|
6
|
+
var composeRefs = require('@radix-solid-js/compose-refs');
|
|
7
|
+
|
|
8
|
+
// src/announce.tsx
|
|
9
|
+
var ROLES = {
|
|
10
|
+
polite: "status",
|
|
11
|
+
assertive: "alert",
|
|
12
|
+
off: "none"
|
|
13
|
+
};
|
|
14
|
+
var listenerMap = /* @__PURE__ */ new Map();
|
|
15
|
+
function Announce(inProps) {
|
|
16
|
+
const [local, rest] = solidJs.splitProps(inProps, [
|
|
17
|
+
"aria-atomic",
|
|
18
|
+
"aria-relevant",
|
|
19
|
+
"children",
|
|
20
|
+
"type",
|
|
21
|
+
"role",
|
|
22
|
+
"regionIdentifier",
|
|
23
|
+
"ref"
|
|
24
|
+
]);
|
|
25
|
+
const type = () => local.type ?? "polite";
|
|
26
|
+
const role = () => local.role ?? ROLES[type()];
|
|
27
|
+
const ariaAtomic = () => ["true", true].includes(local["aria-atomic"]);
|
|
28
|
+
let ownerDocument = document;
|
|
29
|
+
const [region, setRegion] = solidJs.createSignal();
|
|
30
|
+
const getOrCreateRegion = () => {
|
|
31
|
+
const config = { type: type(), role: role(), atomic: ariaAtomic(), id: local.regionIdentifier };
|
|
32
|
+
const selector = buildSelector(config);
|
|
33
|
+
const existing = ownerDocument.querySelector(selector);
|
|
34
|
+
if (existing) return existing;
|
|
35
|
+
return buildLiveRegionElement(ownerDocument, config);
|
|
36
|
+
};
|
|
37
|
+
solidJs.onMount(() => {
|
|
38
|
+
setRegion(getOrCreateRegion());
|
|
39
|
+
});
|
|
40
|
+
solidJs.createEffect(() => {
|
|
41
|
+
const regionEl = getOrCreateRegion();
|
|
42
|
+
if (!regionEl) return;
|
|
43
|
+
function updateOnVisibilityChange() {
|
|
44
|
+
regionEl.setAttribute("role", ownerDocument.hidden ? "none" : role());
|
|
45
|
+
regionEl.setAttribute("aria-live", ownerDocument.hidden ? "off" : type());
|
|
46
|
+
}
|
|
47
|
+
if (!listenerMap.get(regionEl)) {
|
|
48
|
+
ownerDocument.addEventListener("visibilitychange", updateOnVisibilityChange);
|
|
49
|
+
listenerMap.set(regionEl, 1);
|
|
50
|
+
} else {
|
|
51
|
+
listenerMap.set(regionEl, (listenerMap.get(regionEl) ?? 0) + 1);
|
|
52
|
+
}
|
|
53
|
+
solidJs.onCleanup(() => {
|
|
54
|
+
const count = listenerMap.get(regionEl) ?? 0;
|
|
55
|
+
listenerMap.set(regionEl, count - 1);
|
|
56
|
+
if (count === 1) {
|
|
57
|
+
ownerDocument.removeEventListener("visibilitychange", updateOnVisibilityChange);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
62
|
+
primitiveComponent.Primitive.div,
|
|
63
|
+
{
|
|
64
|
+
...rest,
|
|
65
|
+
ref: composeRefs.mergeRefs(local.ref, (node) => {
|
|
66
|
+
if (node) ownerDocument = node.ownerDocument;
|
|
67
|
+
})
|
|
68
|
+
},
|
|
69
|
+
local.children
|
|
70
|
+
), region() && /* @__PURE__ */ React.createElement(web.Portal, { mount: region() }, /* @__PURE__ */ React.createElement("div", null, local.children)));
|
|
71
|
+
}
|
|
72
|
+
function buildLiveRegionElement(ownerDocument, { type, role, atomic, id }) {
|
|
73
|
+
const el = ownerDocument.createElement("div");
|
|
74
|
+
el.setAttribute(getLiveRegionPartDataAttr(id), "");
|
|
75
|
+
el.setAttribute("style", "position: absolute; top: -1px; width: 1px; height: 1px; overflow: hidden;");
|
|
76
|
+
ownerDocument.body.appendChild(el);
|
|
77
|
+
el.setAttribute("aria-live", type);
|
|
78
|
+
el.setAttribute("aria-atomic", String(atomic || false));
|
|
79
|
+
el.setAttribute("role", role);
|
|
80
|
+
return el;
|
|
81
|
+
}
|
|
82
|
+
function buildSelector({ type, role, atomic, id }) {
|
|
83
|
+
return `[${getLiveRegionPartDataAttr(id)}]${[
|
|
84
|
+
["aria-live", type],
|
|
85
|
+
["aria-atomic", atomic],
|
|
86
|
+
["role", role]
|
|
87
|
+
].filter(([, val]) => !!val).map(([attr, val]) => `[${attr}=${val}]`).join("")}`;
|
|
88
|
+
}
|
|
89
|
+
function getLiveRegionPartDataAttr(id) {
|
|
90
|
+
return "data-radix-announce-region" + (id ? `-${id}` : "");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
exports.Announce = Announce;
|
|
94
|
+
//# sourceMappingURL=index.cjs.map
|
|
95
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/announce.tsx"],"names":["splitProps","createSignal","onMount","createEffect","onCleanup","Primitive","mergeRefs","Portal"],"mappings":";;;;;;;;AAQA,IAAM,KAAA,GAA6C;AAAA,EACjD,MAAA,EAAQ,QAAA;AAAA,EACR,SAAA,EAAW,OAAA;AAAA,EACX,GAAA,EAAK;AACP,CAAA;AAEA,IAAM,WAAA,uBAAkB,GAAA,EAAqB;AAY7C,SAAS,SAAS,OAAA,EAAwB;AACxC,EAAA,MAAM,CAAC,KAAA,EAAO,IAAI,CAAA,GAAIA,mBAAW,OAAA,EAAS;AAAA,IACxC,aAAA;AAAA,IAAe,eAAA;AAAA,IAAiB,UAAA;AAAA,IAAY,MAAA;AAAA,IAAQ,MAAA;AAAA,IAAQ,kBAAA;AAAA,IAAoB;AAAA,GACjF,CAAA;AAED,EAAA,MAAM,IAAA,GAAO,MAAM,KAAA,CAAM,IAAA,IAAQ,QAAA;AACjC,EAAA,MAAM,OAAO,MAAM,KAAA,CAAM,IAAA,IAAQ,KAAA,CAAM,MAAM,CAAA;AAC7C,EAAA,MAAM,UAAA,GAAa,MAAM,CAAC,MAAA,EAAQ,IAAI,CAAA,CAAE,QAAA,CAAS,KAAA,CAAM,aAAa,CAAQ,CAAA;AAE5E,EAAA,IAAI,aAAA,GAAgB,QAAA;AACpB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIC,oBAAA,EAA0B;AAEtD,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,MAAM,MAAA,GAAS,EAAE,IAAA,EAAM,IAAA,EAAK,EAAG,IAAA,EAAM,IAAA,EAAK,EAAG,MAAA,EAAQ,UAAA,EAAW,EAAG,EAAA,EAAI,MAAM,gBAAA,EAAiB;AAC9F,IAAA,MAAM,QAAA,GAAW,cAAc,MAAM,CAAA;AACrC,IAAA,MAAM,QAAA,GAAW,aAAA,CAAc,aAAA,CAAc,QAAQ,CAAA;AACrD,IAAA,IAAI,UAAU,OAAO,QAAA;AACrB,IAAA,OAAO,sBAAA,CAAuB,eAAe,MAAM,CAAA;AAAA,EACrD,CAAA;AAEA,EAAAC,eAAA,CAAQ,MAAM;AACZ,IAAA,SAAA,CAAU,mBAAmB,CAAA;AAAA,EAC/B,CAAC,CAAA;AAED,EAAAC,oBAAA,CAAa,MAAM;AACjB,IAAA,MAAM,WAAW,iBAAA,EAAkB;AACnC,IAAA,IAAI,CAAC,QAAA,EAAU;AAEf,IAAA,SAAS,wBAAA,GAA2B;AAClC,MAAA,QAAA,CAAS,aAAa,MAAA,EAAQ,aAAA,CAAc,MAAA,GAAS,MAAA,GAAS,MAAM,CAAA;AACpE,MAAA,QAAA,CAAS,aAAa,WAAA,EAAa,aAAA,CAAc,MAAA,GAAS,KAAA,GAAQ,MAAM,CAAA;AAAA,IAC1E;AAEA,IAAA,IAAI,CAAC,WAAA,CAAY,GAAA,CAAI,QAAQ,CAAA,EAAG;AAC9B,MAAA,aAAA,CAAc,gBAAA,CAAiB,oBAAoB,wBAAwB,CAAA;AAC3E,MAAA,WAAA,CAAY,GAAA,CAAI,UAAU,CAAC,CAAA;AAAA,IAC7B,CAAA,MAAO;AACL,MAAA,WAAA,CAAY,IAAI,QAAA,EAAA,CAAW,WAAA,CAAY,IAAI,QAAQ,CAAA,IAAK,KAAK,CAAC,CAAA;AAAA,IAChE;AAEA,IAAAC,iBAAA,CAAU,MAAM;AACd,MAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,GAAA,CAAI,QAAQ,CAAA,IAAK,CAAA;AAC3C,MAAA,WAAA,CAAY,GAAA,CAAI,QAAA,EAAU,KAAA,GAAQ,CAAC,CAAA;AACnC,MAAA,IAAI,UAAU,CAAA,EAAG;AACf,QAAA,aAAA,CAAc,mBAAA,CAAoB,oBAAoB,wBAAwB,CAAA;AAAA,MAChF;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AAED,EAAA,uBACE,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBACE,KAAA,CAAA,aAAA;AAAA,IAACC,4BAAA,CAAU,GAAA;AAAA,IAAV;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,GAAA,EAAKC,qBAAA,CAAU,KAAA,CAAM,GAAA,EAAK,CAAC,IAAA,KAAsB;AAC/C,QAAA,IAAI,IAAA,kBAAsB,IAAA,CAAK,aAAA;AAAA,MACjC,CAAC;AAAA,KAAA;AAAA,IAEA,KAAA,CAAM;AAAA,GACT,EACC,MAAA,EAAO,oBACN,KAAA,CAAA,aAAA,CAACC,UAAA,EAAA,EAAO,KAAA,EAAO,MAAA,EAAO,EAAA,kBACpB,KAAA,CAAA,aAAA,CAAC,KAAA,EAAA,IAAA,EAAK,KAAA,CAAM,QAAS,CACvB,CAEJ,CAAA;AAEJ;AASA,SAAS,uBAAuB,aAAA,EAAyB,EAAE,MAAM,IAAA,EAAM,MAAA,EAAQ,IAAG,EAAsB;AACtG,EAAA,MAAM,EAAA,GAAK,aAAA,CAAc,aAAA,CAAc,KAAK,CAAA;AAC5C,EAAA,EAAA,CAAG,YAAA,CAAa,yBAAA,CAA0B,EAAE,CAAA,EAAG,EAAE,CAAA;AACjD,EAAA,EAAA,CAAG,YAAA,CAAa,SAAS,2EAA2E,CAAA;AACpG,EAAA,aAAA,CAAc,IAAA,CAAK,YAAY,EAAE,CAAA;AACjC,EAAA,EAAA,CAAG,YAAA,CAAa,aAAa,IAAI,CAAA;AACjC,EAAA,EAAA,CAAG,YAAA,CAAa,aAAA,EAAe,MAAA,CAAO,MAAA,IAAU,KAAK,CAAC,CAAA;AACtD,EAAA,EAAA,CAAG,YAAA,CAAa,QAAQ,IAAI,CAAA;AAC5B,EAAA,OAAO,EAAA;AACT;AAEA,SAAS,cAAc,EAAE,IAAA,EAAM,IAAA,EAAM,MAAA,EAAQ,IAAG,EAAsB;AACpE,EAAA,OAAO,CAAA,CAAA,EAAI,yBAAA,CAA0B,EAAE,CAAC,CAAA,CAAA,EAAI;AAAA,IAC1C,CAAC,aAAa,IAAI,CAAA;AAAA,IAAG,CAAC,eAAe,MAAM,CAAA;AAAA,IAAG,CAAC,QAAQ,IAAI;AAAA,GAC7D,CAAE,MAAA,CAAO,CAAC,GAAG,GAAG,CAAA,KAAM,CAAC,CAAC,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,GAAG,CAAA,KAAM,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,CAAG,CAAA,CAAE,IAAA,CAAK,EAAE,CAAC,CAAA,CAAA;AAChF;AAEA,SAAS,0BAA0B,EAAA,EAAa;AAC9C,EAAA,OAAO,4BAAA,IAAgC,EAAA,GAAK,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,GAAK,EAAA,CAAA;AACzD","file":"index.cjs","sourcesContent":["import { type JSX, createSignal, createEffect, onMount, onCleanup, splitProps } from 'solid-js';\nimport { Portal } from 'solid-js/web';\nimport { Primitive } from '@radix-solid-js/primitive-component';\nimport { mergeRefs } from '@radix-solid-js/compose-refs';\n\ntype RegionType = 'polite' | 'assertive' | 'off';\ntype RegionRole = 'status' | 'alert' | 'log' | 'none';\n\nconst ROLES: { [key in RegionType]: RegionRole } = {\n polite: 'status',\n assertive: 'alert',\n off: 'none',\n};\n\nconst listenerMap = new Map<Element, number>();\n\ninterface AnnounceProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, 'aria-atomic' | 'aria-relevant' | 'children' | 'role' | 'type' | 'ref'> {\n 'aria-atomic'?: boolean;\n 'aria-relevant'?: string;\n children: JSX.Element;\n regionIdentifier?: string;\n role?: RegionRole;\n type?: RegionType;\n ref?: (el: HTMLElement) => void;\n}\n\nfunction Announce(inProps: AnnounceProps) {\n const [local, rest] = splitProps(inProps, [\n 'aria-atomic', 'aria-relevant', 'children', 'type', 'role', 'regionIdentifier', 'ref',\n ]);\n\n const type = () => local.type ?? 'polite';\n const role = () => local.role ?? ROLES[type()];\n const ariaAtomic = () => ['true', true].includes(local['aria-atomic'] as any);\n\n let ownerDocument = document;\n const [region, setRegion] = createSignal<HTMLElement>();\n\n const getOrCreateRegion = () => {\n const config = { type: type(), role: role(), atomic: ariaAtomic(), id: local.regionIdentifier };\n const selector = buildSelector(config);\n const existing = ownerDocument.querySelector(selector);\n if (existing) return existing as HTMLElement;\n return buildLiveRegionElement(ownerDocument, config);\n };\n\n onMount(() => {\n setRegion(getOrCreateRegion());\n });\n\n createEffect(() => {\n const regionEl = getOrCreateRegion();\n if (!regionEl) return;\n\n function updateOnVisibilityChange() {\n regionEl.setAttribute('role', ownerDocument.hidden ? 'none' : role());\n regionEl.setAttribute('aria-live', ownerDocument.hidden ? 'off' : type());\n }\n\n if (!listenerMap.get(regionEl)) {\n ownerDocument.addEventListener('visibilitychange', updateOnVisibilityChange);\n listenerMap.set(regionEl, 1);\n } else {\n listenerMap.set(regionEl, (listenerMap.get(regionEl) ?? 0) + 1);\n }\n\n onCleanup(() => {\n const count = listenerMap.get(regionEl) ?? 0;\n listenerMap.set(regionEl, count - 1);\n if (count === 1) {\n ownerDocument.removeEventListener('visibilitychange', updateOnVisibilityChange);\n }\n });\n });\n\n return (\n <>\n <Primitive.div\n {...rest}\n ref={mergeRefs(local.ref, (node: HTMLElement) => {\n if (node) ownerDocument = node.ownerDocument;\n })}\n >\n {local.children}\n </Primitive.div>\n {region() && (\n <Portal mount={region()}>\n <div>{local.children}</div>\n </Portal>\n )}\n </>\n );\n}\n\ntype LiveRegionOptions = {\n type: string;\n role: string;\n atomic?: boolean;\n id?: string;\n};\n\nfunction buildLiveRegionElement(ownerDocument: Document, { type, role, atomic, id }: LiveRegionOptions) {\n const el = ownerDocument.createElement('div');\n el.setAttribute(getLiveRegionPartDataAttr(id), '');\n el.setAttribute('style', 'position: absolute; top: -1px; width: 1px; height: 1px; overflow: hidden;');\n ownerDocument.body.appendChild(el);\n el.setAttribute('aria-live', type);\n el.setAttribute('aria-atomic', String(atomic || false));\n el.setAttribute('role', role);\n return el;\n}\n\nfunction buildSelector({ type, role, atomic, id }: LiveRegionOptions) {\n return `[${getLiveRegionPartDataAttr(id)}]${[\n ['aria-live', type], ['aria-atomic', atomic], ['role', role],\n ].filter(([, val]) => !!val).map(([attr, val]) => `[${attr}=${val}]`).join('')}`;\n}\n\nfunction getLiveRegionPartDataAttr(id?: string) {\n return 'data-radix-announce-region' + (id ? `-${id}` : '');\n}\n\nexport { Announce };\nexport type { AnnounceProps };\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { JSX } from 'solid-js';
|
|
2
|
+
|
|
3
|
+
type RegionType = 'polite' | 'assertive' | 'off';
|
|
4
|
+
type RegionRole = 'status' | 'alert' | 'log' | 'none';
|
|
5
|
+
interface AnnounceProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, 'aria-atomic' | 'aria-relevant' | 'children' | 'role' | 'type' | 'ref'> {
|
|
6
|
+
'aria-atomic'?: boolean;
|
|
7
|
+
'aria-relevant'?: string;
|
|
8
|
+
children: JSX.Element;
|
|
9
|
+
regionIdentifier?: string;
|
|
10
|
+
role?: RegionRole;
|
|
11
|
+
type?: RegionType;
|
|
12
|
+
ref?: (el: HTMLElement) => void;
|
|
13
|
+
}
|
|
14
|
+
declare function Announce(inProps: AnnounceProps): JSX.Element;
|
|
15
|
+
|
|
16
|
+
export { Announce, type AnnounceProps };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { JSX } from 'solid-js';
|
|
2
|
+
|
|
3
|
+
type RegionType = 'polite' | 'assertive' | 'off';
|
|
4
|
+
type RegionRole = 'status' | 'alert' | 'log' | 'none';
|
|
5
|
+
interface AnnounceProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, 'aria-atomic' | 'aria-relevant' | 'children' | 'role' | 'type' | 'ref'> {
|
|
6
|
+
'aria-atomic'?: boolean;
|
|
7
|
+
'aria-relevant'?: string;
|
|
8
|
+
children: JSX.Element;
|
|
9
|
+
regionIdentifier?: string;
|
|
10
|
+
role?: RegionRole;
|
|
11
|
+
type?: RegionType;
|
|
12
|
+
ref?: (el: HTMLElement) => void;
|
|
13
|
+
}
|
|
14
|
+
declare function Announce(inProps: AnnounceProps): JSX.Element;
|
|
15
|
+
|
|
16
|
+
export { Announce, type AnnounceProps };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { splitProps, createSignal, onMount, createEffect, onCleanup } from 'solid-js';
|
|
2
|
+
import { Portal } from 'solid-js/web';
|
|
3
|
+
import { Primitive } from '@radix-solid-js/primitive-component';
|
|
4
|
+
import { mergeRefs } from '@radix-solid-js/compose-refs';
|
|
5
|
+
|
|
6
|
+
// src/announce.tsx
|
|
7
|
+
var ROLES = {
|
|
8
|
+
polite: "status",
|
|
9
|
+
assertive: "alert",
|
|
10
|
+
off: "none"
|
|
11
|
+
};
|
|
12
|
+
var listenerMap = /* @__PURE__ */ new Map();
|
|
13
|
+
function Announce(inProps) {
|
|
14
|
+
const [local, rest] = splitProps(inProps, [
|
|
15
|
+
"aria-atomic",
|
|
16
|
+
"aria-relevant",
|
|
17
|
+
"children",
|
|
18
|
+
"type",
|
|
19
|
+
"role",
|
|
20
|
+
"regionIdentifier",
|
|
21
|
+
"ref"
|
|
22
|
+
]);
|
|
23
|
+
const type = () => local.type ?? "polite";
|
|
24
|
+
const role = () => local.role ?? ROLES[type()];
|
|
25
|
+
const ariaAtomic = () => ["true", true].includes(local["aria-atomic"]);
|
|
26
|
+
let ownerDocument = document;
|
|
27
|
+
const [region, setRegion] = createSignal();
|
|
28
|
+
const getOrCreateRegion = () => {
|
|
29
|
+
const config = { type: type(), role: role(), atomic: ariaAtomic(), id: local.regionIdentifier };
|
|
30
|
+
const selector = buildSelector(config);
|
|
31
|
+
const existing = ownerDocument.querySelector(selector);
|
|
32
|
+
if (existing) return existing;
|
|
33
|
+
return buildLiveRegionElement(ownerDocument, config);
|
|
34
|
+
};
|
|
35
|
+
onMount(() => {
|
|
36
|
+
setRegion(getOrCreateRegion());
|
|
37
|
+
});
|
|
38
|
+
createEffect(() => {
|
|
39
|
+
const regionEl = getOrCreateRegion();
|
|
40
|
+
if (!regionEl) return;
|
|
41
|
+
function updateOnVisibilityChange() {
|
|
42
|
+
regionEl.setAttribute("role", ownerDocument.hidden ? "none" : role());
|
|
43
|
+
regionEl.setAttribute("aria-live", ownerDocument.hidden ? "off" : type());
|
|
44
|
+
}
|
|
45
|
+
if (!listenerMap.get(regionEl)) {
|
|
46
|
+
ownerDocument.addEventListener("visibilitychange", updateOnVisibilityChange);
|
|
47
|
+
listenerMap.set(regionEl, 1);
|
|
48
|
+
} else {
|
|
49
|
+
listenerMap.set(regionEl, (listenerMap.get(regionEl) ?? 0) + 1);
|
|
50
|
+
}
|
|
51
|
+
onCleanup(() => {
|
|
52
|
+
const count = listenerMap.get(regionEl) ?? 0;
|
|
53
|
+
listenerMap.set(regionEl, count - 1);
|
|
54
|
+
if (count === 1) {
|
|
55
|
+
ownerDocument.removeEventListener("visibilitychange", updateOnVisibilityChange);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
60
|
+
Primitive.div,
|
|
61
|
+
{
|
|
62
|
+
...rest,
|
|
63
|
+
ref: mergeRefs(local.ref, (node) => {
|
|
64
|
+
if (node) ownerDocument = node.ownerDocument;
|
|
65
|
+
})
|
|
66
|
+
},
|
|
67
|
+
local.children
|
|
68
|
+
), region() && /* @__PURE__ */ React.createElement(Portal, { mount: region() }, /* @__PURE__ */ React.createElement("div", null, local.children)));
|
|
69
|
+
}
|
|
70
|
+
function buildLiveRegionElement(ownerDocument, { type, role, atomic, id }) {
|
|
71
|
+
const el = ownerDocument.createElement("div");
|
|
72
|
+
el.setAttribute(getLiveRegionPartDataAttr(id), "");
|
|
73
|
+
el.setAttribute("style", "position: absolute; top: -1px; width: 1px; height: 1px; overflow: hidden;");
|
|
74
|
+
ownerDocument.body.appendChild(el);
|
|
75
|
+
el.setAttribute("aria-live", type);
|
|
76
|
+
el.setAttribute("aria-atomic", String(atomic || false));
|
|
77
|
+
el.setAttribute("role", role);
|
|
78
|
+
return el;
|
|
79
|
+
}
|
|
80
|
+
function buildSelector({ type, role, atomic, id }) {
|
|
81
|
+
return `[${getLiveRegionPartDataAttr(id)}]${[
|
|
82
|
+
["aria-live", type],
|
|
83
|
+
["aria-atomic", atomic],
|
|
84
|
+
["role", role]
|
|
85
|
+
].filter(([, val]) => !!val).map(([attr, val]) => `[${attr}=${val}]`).join("")}`;
|
|
86
|
+
}
|
|
87
|
+
function getLiveRegionPartDataAttr(id) {
|
|
88
|
+
return "data-radix-announce-region" + (id ? `-${id}` : "");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { Announce };
|
|
92
|
+
//# sourceMappingURL=index.js.map
|
|
93
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/announce.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { type JSX, createSignal, createEffect, onMount, onCleanup, splitProps } from 'solid-js';\nimport { Portal } from 'solid-js/web';\nimport { Primitive } from '@radix-solid-js/primitive-component';\nimport { mergeRefs } from '@radix-solid-js/compose-refs';\n\ntype RegionType = 'polite' | 'assertive' | 'off';\ntype RegionRole = 'status' | 'alert' | 'log' | 'none';\n\nconst ROLES: { [key in RegionType]: RegionRole } = {\n polite: 'status',\n assertive: 'alert',\n off: 'none',\n};\n\nconst listenerMap = new Map<Element, number>();\n\ninterface AnnounceProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, 'aria-atomic' | 'aria-relevant' | 'children' | 'role' | 'type' | 'ref'> {\n 'aria-atomic'?: boolean;\n 'aria-relevant'?: string;\n children: JSX.Element;\n regionIdentifier?: string;\n role?: RegionRole;\n type?: RegionType;\n ref?: (el: HTMLElement) => void;\n}\n\nfunction Announce(inProps: AnnounceProps) {\n const [local, rest] = splitProps(inProps, [\n 'aria-atomic', 'aria-relevant', 'children', 'type', 'role', 'regionIdentifier', 'ref',\n ]);\n\n const type = () => local.type ?? 'polite';\n const role = () => local.role ?? ROLES[type()];\n const ariaAtomic = () => ['true', true].includes(local['aria-atomic'] as any);\n\n let ownerDocument = document;\n const [region, setRegion] = createSignal<HTMLElement>();\n\n const getOrCreateRegion = () => {\n const config = { type: type(), role: role(), atomic: ariaAtomic(), id: local.regionIdentifier };\n const selector = buildSelector(config);\n const existing = ownerDocument.querySelector(selector);\n if (existing) return existing as HTMLElement;\n return buildLiveRegionElement(ownerDocument, config);\n };\n\n onMount(() => {\n setRegion(getOrCreateRegion());\n });\n\n createEffect(() => {\n const regionEl = getOrCreateRegion();\n if (!regionEl) return;\n\n function updateOnVisibilityChange() {\n regionEl.setAttribute('role', ownerDocument.hidden ? 'none' : role());\n regionEl.setAttribute('aria-live', ownerDocument.hidden ? 'off' : type());\n }\n\n if (!listenerMap.get(regionEl)) {\n ownerDocument.addEventListener('visibilitychange', updateOnVisibilityChange);\n listenerMap.set(regionEl, 1);\n } else {\n listenerMap.set(regionEl, (listenerMap.get(regionEl) ?? 0) + 1);\n }\n\n onCleanup(() => {\n const count = listenerMap.get(regionEl) ?? 0;\n listenerMap.set(regionEl, count - 1);\n if (count === 1) {\n ownerDocument.removeEventListener('visibilitychange', updateOnVisibilityChange);\n }\n });\n });\n\n return (\n <>\n <Primitive.div\n {...rest}\n ref={mergeRefs(local.ref, (node: HTMLElement) => {\n if (node) ownerDocument = node.ownerDocument;\n })}\n >\n {local.children}\n </Primitive.div>\n {region() && (\n <Portal mount={region()}>\n <div>{local.children}</div>\n </Portal>\n )}\n </>\n );\n}\n\ntype LiveRegionOptions = {\n type: string;\n role: string;\n atomic?: boolean;\n id?: string;\n};\n\nfunction buildLiveRegionElement(ownerDocument: Document, { type, role, atomic, id }: LiveRegionOptions) {\n const el = ownerDocument.createElement('div');\n el.setAttribute(getLiveRegionPartDataAttr(id), '');\n el.setAttribute('style', 'position: absolute; top: -1px; width: 1px; height: 1px; overflow: hidden;');\n ownerDocument.body.appendChild(el);\n el.setAttribute('aria-live', type);\n el.setAttribute('aria-atomic', String(atomic || false));\n el.setAttribute('role', role);\n return el;\n}\n\nfunction buildSelector({ type, role, atomic, id }: LiveRegionOptions) {\n return `[${getLiveRegionPartDataAttr(id)}]${[\n ['aria-live', type], ['aria-atomic', atomic], ['role', role],\n ].filter(([, val]) => !!val).map(([attr, val]) => `[${attr}=${val}]`).join('')}`;\n}\n\nfunction getLiveRegionPartDataAttr(id?: string) {\n return 'data-radix-announce-region' + (id ? `-${id}` : '');\n}\n\nexport { Announce };\nexport type { AnnounceProps };\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@radix-solid-js/announce",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"clean": "rm -rf dist",
|
|
28
|
+
"typecheck": "tsc --noEmit"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@radix-solid-js/compose-refs": "workspace:*",
|
|
32
|
+
"@radix-solid-js/primitive-component": "workspace:*"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"solid-js": "^1.8.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@repo/tsconfig": "workspace:*",
|
|
39
|
+
"tsup": "^8.3.6",
|
|
40
|
+
"typescript": "^5.7.3",
|
|
41
|
+
"solid-js": "^1.9.3"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/ljho01/shadcn-solid-js.git",
|
|
49
|
+
"directory": "packages/solid/announce"
|
|
50
|
+
}
|
|
51
|
+
}
|