panel-frame-ui 0.1.0 → 0.1.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # panel-frame-ui
2
+
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 79c6325: Fix field accessibility attributes and mobile navigation drawer focus handling.
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-shell.d.ts","sourceRoot":"","sources":["../src/dashboard-shell.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,EAAE,SAAS,CAAC;IACtB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAKF,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,UAAU,EACV,cAAc,EACd,aAAa,EACb,OAAO,EACP,cAAqB,EACrB,aAAoB,EACpB,QAAQ,GACT,EAAE,mBAAmB,+BA0JrB"}
1
+ {"version":3,"file":"dashboard-shell.d.ts","sourceRoot":"","sources":["../src/dashboard-shell.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,EAAE,SAAS,CAAC;IACtB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAKF,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,UAAU,EACV,cAAc,EACd,aAAa,EACb,OAAO,EACP,cAAqB,EACrB,aAAoB,EACpB,QAAQ,GACT,EAAE,mBAAmB,+BAwLrB"}
@@ -1,12 +1,13 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useRef, useState, } from "react";
4
- const focusableSelector = 'a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])';
4
+ const focusableSelector = 'a[href], button:not(:disabled), input:not([type="hidden"]):not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])';
5
5
  export function DashboardShell({ brand, navigation, sidebarContext, sidebarFooter, toolbar, sidebarVisible = true, contentAsMain = true, children, }) {
6
6
  const [isMobile, setIsMobile] = useState(false);
7
7
  const [mobileOpen, setMobileOpen] = useState(false);
8
8
  const sidebarRef = useRef(null);
9
9
  const triggerRef = useRef(null);
10
+ const wasMobileOpenRef = useRef(false);
10
11
  useEffect(() => {
11
12
  const media = window.matchMedia("(max-width: 780px)");
12
13
  const update = () => {
@@ -18,36 +19,56 @@ export function DashboardShell({ brand, navigation, sidebarContext, sidebarFoote
18
19
  media.addEventListener("change", update);
19
20
  return () => media.removeEventListener("change", update);
20
21
  }, []);
22
+ useEffect(() => {
23
+ if (mobileOpen) {
24
+ wasMobileOpenRef.current = true;
25
+ return;
26
+ }
27
+ if (wasMobileOpenRef.current) {
28
+ wasMobileOpenRef.current = false;
29
+ if (isMobile)
30
+ triggerRef.current?.focus();
31
+ }
32
+ }, [isMobile, mobileOpen]);
21
33
  useEffect(() => {
22
34
  if (!isMobile || !mobileOpen)
23
35
  return;
24
36
  const previousOverflow = document.body.style.overflow;
25
37
  document.body.style.overflow = "hidden";
26
38
  const focusable = () => Array.from(sidebarRef.current?.querySelectorAll(focusableSelector) ??
27
- []).filter((element) => !element.hasAttribute("hidden"));
28
- focusable()[0]?.focus();
39
+ []).filter((element) => !element.closest('[hidden], [inert], [aria-hidden="true"]'));
40
+ const first = focusable()[0];
41
+ (first ?? sidebarRef.current)?.focus();
29
42
  const onKeyDown = (event) => {
30
43
  if (event.key === "Escape") {
31
44
  event.preventDefault();
32
- setMobileOpen(false);
33
- triggerRef.current?.focus();
45
+ closeDrawer();
34
46
  return;
35
47
  }
36
48
  if (event.key !== "Tab")
37
49
  return;
38
50
  const elements = focusable();
39
- const first = elements[0];
40
- const last = elements.at(-1);
41
- if (!first || !last) {
51
+ const firstFocusable = elements[0];
52
+ const lastFocusable = elements.at(-1);
53
+ if (!firstFocusable || !lastFocusable) {
54
+ event.preventDefault();
55
+ sidebarRef.current?.focus();
56
+ }
57
+ else if (!sidebarRef.current?.contains(document.activeElement)) {
58
+ event.preventDefault();
59
+ (event.shiftKey ? lastFocusable : firstFocusable).focus();
60
+ }
61
+ else if (document.activeElement === sidebarRef.current) {
42
62
  event.preventDefault();
63
+ (event.shiftKey ? lastFocusable : firstFocusable).focus();
43
64
  }
44
- else if (event.shiftKey && document.activeElement === first) {
65
+ else if (event.shiftKey && document.activeElement === firstFocusable) {
45
66
  event.preventDefault();
46
- last.focus();
67
+ lastFocusable.focus();
47
68
  }
48
- else if (!event.shiftKey && document.activeElement === last) {
69
+ else if (!event.shiftKey && document.activeElement === lastFocusable) {
49
70
  event.preventDefault();
50
- first.focus();
71
+ firstFocusable.focus();
51
72
  }
52
73
  };
53
74
  document.addEventListener("keydown", onKeyDown);
@@ -60,14 +81,13 @@ export function DashboardShell({ brand, navigation, sidebarContext, sidebarFoote
60
81
  if (isMobile &&
61
82
  event.target instanceof Element &&
62
83
  event.target.closest("a[href]")) {
63
- setMobileOpen(false);
84
+ closeDrawer();
64
85
  }
65
86
  }
66
87
  function closeDrawer() {
67
88
  setMobileOpen(false);
68
- triggerRef.current?.focus();
69
89
  }
70
- return (_jsxs("div", { className: "pf-dashboard-shell", "data-mobile-open": mobileOpen ? "true" : "false", "data-sidebar-visible": sidebarVisible ? "true" : "false", children: [_jsx("a", { className: "pf-skip-link", href: "#pf-main-content", children: "Skip to main content" }), _jsxs("aside", { ref: sidebarRef, "aria-hidden": (isMobile && !mobileOpen) || (!isMobile && !sidebarVisible)
90
+ return (_jsxs("div", { className: "pf-dashboard-shell", "data-mobile-open": mobileOpen ? "true" : "false", "data-sidebar-visible": sidebarVisible ? "true" : "false", children: [_jsx("a", { "aria-hidden": isMobile && mobileOpen ? true : undefined, className: "pf-skip-link", href: "#pf-main-content", inert: isMobile && mobileOpen, children: "Skip to main content" }), _jsxs("aside", { ref: sidebarRef, "aria-hidden": (isMobile && !mobileOpen) || (!isMobile && !sidebarVisible)
71
91
  ? true
72
- : undefined, "aria-label": "Primary navigation", "aria-modal": isMobile && mobileOpen ? true : undefined, className: "pf-sidebar", id: "pf-dashboard-sidebar", inert: (isMobile && !mobileOpen) || (!isMobile && !sidebarVisible), onClick: closeAfterNavigation, role: isMobile && mobileOpen ? "dialog" : undefined, tabIndex: -1, children: [_jsx("div", { className: "pf-sidebar-brand", children: brand }), sidebarContext ? (_jsx("div", { className: "pf-sidebar-context", children: sidebarContext })) : null, _jsx("div", { className: "pf-sidebar-navigation", children: navigation }), _jsx("div", { className: "pf-sidebar-spacer" }), sidebarFooter ? (_jsx("div", { className: "pf-sidebar-footer", children: sidebarFooter })) : null] }), isMobile && mobileOpen ? (_jsx("button", { "aria-label": "Close dashboard navigation", className: "pf-sidebar-backdrop", onClick: closeDrawer, tabIndex: -1, type: "button" })) : null, _jsxs("div", { className: "pf-dashboard-main", children: [_jsxs("header", { className: "pf-dashboard-toolbar", children: [_jsx("button", { "aria-controls": "pf-dashboard-sidebar", "aria-expanded": mobileOpen, "aria-label": mobileOpen ? "Close navigation" : "Open navigation", className: "pf-mobile-menu-button", onClick: () => setMobileOpen((open) => !open), ref: triggerRef, type: "button", children: _jsx("span", { "aria-hidden": "true", children: "\u2630" }) }), toolbar ? _jsx("div", { className: "pf-toolbar-content", children: toolbar }) : null] }), contentAsMain ? (_jsx("main", { className: "pf-dashboard-content", id: "pf-main-content", tabIndex: -1, children: children })) : (_jsx("div", { className: "pf-dashboard-content", id: "pf-main-content", tabIndex: -1, children: children }))] })] }));
92
+ : undefined, "aria-label": "Primary navigation", "aria-modal": isMobile && mobileOpen ? true : undefined, className: "pf-sidebar", id: "pf-dashboard-sidebar", inert: (isMobile && !mobileOpen) || (!isMobile && !sidebarVisible), onClick: closeAfterNavigation, role: isMobile && mobileOpen ? "dialog" : undefined, tabIndex: -1, children: [_jsx("div", { className: "pf-sidebar-brand", children: brand }), sidebarContext ? (_jsx("div", { className: "pf-sidebar-context", children: sidebarContext })) : null, _jsx("div", { className: "pf-sidebar-navigation", children: navigation }), _jsx("div", { className: "pf-sidebar-spacer" }), sidebarFooter ? (_jsx("div", { className: "pf-sidebar-footer", children: sidebarFooter })) : null] }), isMobile && mobileOpen ? (_jsx("button", { "aria-label": "Close dashboard navigation", className: "pf-sidebar-backdrop", onClick: closeDrawer, tabIndex: -1, type: "button" })) : null, _jsxs("div", { "aria-hidden": isMobile && mobileOpen ? true : undefined, className: "pf-dashboard-main", inert: isMobile && mobileOpen, children: [_jsxs("header", { className: "pf-dashboard-toolbar", children: [_jsx("button", { "aria-controls": "pf-dashboard-sidebar", "aria-expanded": mobileOpen, "aria-label": mobileOpen ? "Close navigation" : "Open navigation", className: "pf-mobile-menu-button", onClick: () => setMobileOpen((open) => !open), ref: triggerRef, type: "button", children: _jsx("span", { "aria-hidden": "true", children: "\u2630" }) }), toolbar ? _jsx("div", { className: "pf-toolbar-content", children: toolbar }) : null] }), contentAsMain ? (_jsx("main", { className: "pf-dashboard-content", id: "pf-main-content", tabIndex: -1, children: children })) : (_jsx("div", { className: "pf-dashboard-content", id: "pf-main-content", tabIndex: -1, children: children }))] })] }));
73
93
  }
@@ -21,13 +21,13 @@ export declare function Field({ label, hint, error, id, children, }: {
21
21
  "aria-invalid"?: true;
22
22
  }) => ReactNode;
23
23
  }): import("react").JSX.Element;
24
- export declare function TextField({ label, hint, error, id, ...inputProps }: Omit<InputHTMLAttributes<HTMLInputElement>, "id"> & {
24
+ export declare function TextField({ label, hint, error, id, className, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, ...inputProps }: Omit<InputHTMLAttributes<HTMLInputElement>, "id"> & {
25
25
  label: string;
26
26
  hint?: string;
27
27
  error?: string;
28
28
  id?: string;
29
29
  }): import("react").JSX.Element;
30
- export declare function SelectField({ label, hint, error, id, children, ...selectProps }: Omit<SelectHTMLAttributes<HTMLSelectElement>, "id"> & {
30
+ export declare function SelectField({ label, hint, error, id, children, className, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, ...selectProps }: Omit<SelectHTMLAttributes<HTMLSelectElement>, "id"> & {
31
31
  label: string;
32
32
  hint?: string;
33
33
  error?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../src/primitives.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../src/primitives.tsx"],"names":[],"mappings":"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"}
@@ -24,11 +24,15 @@ export function Field({ label, hint, error, id, children, }) {
24
24
  "aria-invalid": error ? true : undefined,
25
25
  }), hint ? (_jsx("span", { className: "pf-field-hint", id: hintId, children: hint })) : null, error ? (_jsx("span", { className: "pf-field-error", id: errorId, children: error })) : null] }));
26
26
  }
27
- export function TextField({ label, hint, error, id, ...inputProps }) {
28
- return (_jsx(Field, { label: label, hint: hint, error: error, id: id, children: (fieldProps) => (_jsx("input", { className: "pf-input", ...fieldProps, ...inputProps })) }));
27
+ function mergeDescribedBy(...values) {
28
+ const ids = values.flatMap((value) => value?.split(/\s+/) ?? []);
29
+ return [...new Set(ids.filter(Boolean))].join(" ") || undefined;
29
30
  }
30
- export function SelectField({ label, hint, error, id, children, ...selectProps }) {
31
- return (_jsx(Field, { label: label, hint: hint, error: error, id: id, children: (fieldProps) => (_jsx("select", { className: "pf-input pf-select", ...fieldProps, ...selectProps, children: children })) }));
31
+ export function TextField({ label, hint, error, id, className = "", "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, ...inputProps }) {
32
+ return (_jsx(Field, { label: label, hint: hint, error: error, id: id, children: (fieldProps) => (_jsx("input", { ...fieldProps, ...inputProps, "aria-describedby": mergeDescribedBy(fieldProps["aria-describedby"], ariaDescribedBy), "aria-invalid": error ? true : ariaInvalid, className: `pf-input ${className}`.trim() })) }));
33
+ }
34
+ export function SelectField({ label, hint, error, id, children, className = "", "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid, ...selectProps }) {
35
+ return (_jsx(Field, { label: label, hint: hint, error: error, id: id, children: (fieldProps) => (_jsx("select", { ...fieldProps, ...selectProps, "aria-describedby": mergeDescribedBy(fieldProps["aria-describedby"], ariaDescribedBy), "aria-invalid": error ? true : ariaInvalid, className: `pf-input pf-select ${className}`.trim(), children: children })) }));
32
36
  }
33
37
  export function EmptyState({ title, description, action, }) {
34
38
  return (_jsxs("section", { className: "pf-empty-state", children: [_jsx("h2", { children: title }), description ? (_jsx("div", { className: "pf-empty-description", children: description })) : null, action ? _jsx("div", { className: "pf-empty-action", children: action }) : null] }));
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "panel-frame-ui",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Shared dashboard and account UI for Panel Frame projects",
5
5
  "license": "MIT",
6
6
  "engines": {
7
7
  "node": ">=22.14.0"
8
8
  },
9
- "packageManager": "pnpm@12.16.1",
10
9
  "repository": {
11
10
  "type": "git",
12
11
  "url": "git+https://github.com/zakaihamilton/panel-frame-ui.git"
@@ -42,19 +41,6 @@
42
41
  "default": "./styles.css"
43
42
  }
44
43
  },
45
- "scripts": {
46
- "build": "tsc -p tsconfig.json",
47
- "lint": "eslint .",
48
- "format": "prettier --write .",
49
- "format:check": "prettier --check .",
50
- "test": "vitest run",
51
- "prepack": "pnpm run build",
52
- "health": "pnpm run build && pnpm run lint && pnpm run format:check && pnpm run test && repnix check",
53
- "health:dead-code": "knip",
54
- "health:duplication": "jscpd src",
55
- "health:package:publint": "publint",
56
- "health:package:types": "attw --pack ."
57
- },
58
44
  "peerDependencies": {
59
45
  "react": ">=19.0.0 <20.0.0",
60
46
  "react-dom": ">=19.0.0 <20.0.0"
@@ -78,5 +64,17 @@
78
64
  "typescript": "^6.0.3",
79
65
  "typescript-eslint": "^8.72.2",
80
66
  "vitest": "^5.1.0"
67
+ },
68
+ "scripts": {
69
+ "build": "tsc -p tsconfig.json",
70
+ "lint": "eslint .",
71
+ "format": "prettier --write .",
72
+ "format:check": "prettier --check .",
73
+ "test": "vitest run",
74
+ "health": "pnpm run build && pnpm run lint && pnpm run format:check && pnpm run test && repnix check",
75
+ "health:dead-code": "knip",
76
+ "health:duplication": "jscpd src",
77
+ "health:package:publint": "publint",
78
+ "health:package:types": "attw --pack ."
81
79
  }
82
- }
80
+ }