@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 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":"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","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"]}
@@ -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 };
@@ -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
+ }