monochrome 0.1.0 → 0.2.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/README.md +3 -1
- package/dist/react/index.js +2 -0
- package/package.json +46 -7
- package/dist/client/monochrome.js +0 -498
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Accessible UI component library. Best-in-class performance. HTML-first, React supported.
|
|
4
4
|
|
|
5
|
-
<!-- badges
|
|
5
|
+
<!-- badges -->
|
|
6
|
+
   
|
|
7
|
+
<!-- /badges -->
|
|
6
8
|
|
|
7
9
|
## Install
|
|
8
10
|
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{createContext as Y,useContext as Z,useId as N}from"react";import{jsx as X}from"react/jsx-runtime";var m=(a,t)=>t?`${a}:${t}`:a,i=()=>X("script",{dangerouslySetInnerHTML:{__html:"document.currentScript.parentNode.setAttribute('hidden','until-found')"}});import{jsx as w,jsxs as A}from"react/jsx-runtime";var E=Y(null);function _(){let a=Z(E);if(!a)throw Error("Accordion components must be used within Accordion.Item");return a}function G({children:a,type:t,...b}){let f=N();return w("div",{...b,"data-mode":t??"single",id:`mcr:accordion:${f}`,children:a})}function F({children:a,open:t,disabled:b,...f}){let v=N();return w(E.Provider,{value:{baseId:v,open:t??!1,disabled:b??!1},children:w("div",{...f,children:a})})}function W({children:a,as:t,...b}){return w(t??"h3",{...b,children:a})}function R({children:a,...t}){let b=_(),f=b.baseId,v=b.open;return w("button",{...t,type:"button",id:`mct:accordion:${f}`,"aria-expanded":v,"aria-controls":`mcc:accordion:${f}`,"aria-disabled":b.disabled||void 0,children:a})}function M({children:a,...t}){let b=_(),f=b.baseId,v=b.open;return A("div",{...t,id:`mcc:accordion:${f}`,role:"region","aria-labelledby":`mct:accordion:${f}`,"aria-hidden":!v,hidden:v?void 0:!0,children:[!v&&w(i,{}),a]})}var k={Root:G,Item:F,Header:W,Trigger:R,Panel:M};import{createContext as O,useContext as n,useId as I}from"react";import{jsx as g,jsxs as r}from"react/jsx-runtime";var D=O(null);function P(){let a=n(D);if(!a)throw Error("Collapsible components must be used within Collapsible.Root");return a}function o({children:a,open:t,...b}){let f=I();return g(D.Provider,{value:{baseId:f,open:t??!1},children:g("div",{...b,children:a})})}function l({children:a,...t}){let b=P(),f=b.baseId,v=b.open;return g("button",{...t,type:"button",id:`mct:collapsible:${f}`,"aria-expanded":v,"aria-controls":`mcc:collapsible:${f}`,children:a})}function C({children:a,...t}){let b=P(),f=b.baseId,v=b.open;return r("div",{...t,id:`mcc:collapsible:${f}`,"aria-labelledby":`mct:collapsible:${f}`,"aria-hidden":!v,hidden:v?void 0:!0,children:[!v&&g(i,{}),a]})}var d={Root:o,Trigger:l,Panel:C};import{createContext as q,useContext as J,useId as K,useRef as h}from"react";import{jsx as u}from"react/jsx-runtime";var H=q(null),Q=q(null);function L(){let a=J(H);if(!a)throw Error("Menu components must be used within Menu.Root");return a}function j(){let a=J(Q);if(!a)throw Error("Menu components must be used within Menu.Popover");return a}function c({children:a,menubar:t,...b}){let f=K();return u(H.Provider,{value:{id:f,root:!0,menubar:t},children:u("div",{...b,id:`mcr:menu:${f}`,children:a})})}function s({children:a,...t}){let b=L();return u("button",{...t,type:"button",id:`mct:menu:${b.id}`,"aria-controls":`mcc:menu:${b.id}`,"aria-expanded":"false","aria-haspopup":"menu",tabIndex:b.root||b.first?0:-1,role:b.submenu?"menuitem":"button",children:a})}function e({children:a,...t}){let b=L(),f=h(!1);f.current=!1;let v=u(Q.Provider,{value:{claimFirst:()=>{if(!f.current)return f.current=!0,!0;return!1}},children:a});return b.menubar?u("ul",{...t,role:"menubar",children:v}):u("ul",{...t,role:"menu",id:`mcc:menu:${b.id}`,"aria-labelledby":`mct:menu:${b.id}`,"aria-hidden":"true",popover:"manual",children:v})}function x({children:a,disabled:t,href:b,...f}){return u("li",{role:"none",children:t?u("span",{...f,role:"menuitem","aria-disabled":"true",tabIndex:-1,children:a}):b?u("a",{...f,role:"menuitem",href:b,tabIndex:-1,children:a}):u("button",{...f,type:"button",role:"menuitem",tabIndex:-1,children:a})})}function p({children:a,checked:t,disabled:b,...f}){return u("li",{role:"none",children:b?u("span",{...f,role:"menuitemcheckbox","aria-checked":t??!1,"aria-disabled":"true",tabIndex:-1,children:a}):u("button",{...f,type:"button",role:"menuitemcheckbox","aria-checked":t??!1,tabIndex:-1,children:a})})}function aa({children:a,checked:t,disabled:b,...f}){return u("li",{role:"none",children:b?u("span",{...f,role:"menuitemradio","aria-checked":t??!1,"aria-disabled":"true",tabIndex:-1,children:a}):u("button",{...f,type:"button",role:"menuitemradio","aria-checked":t??!1,tabIndex:-1,children:a})})}function ta({children:a,...t}){return u("li",{...t,role:"presentation",children:a})}function ba(a){return u("li",{...a,role:"separator"})}function fa({children:a,...t}){let b=L(),v=j().claimFirst(),T=K(),y=v&&b.menubar&&!b.submenu;return u(H.Provider,{value:{id:T,submenu:!0,first:y},children:u("li",{...t,role:"none",children:a})})}var va={Root:c,Trigger:s,Popover:e,Item:x,CheckboxItem:p,RadioItem:aa,Label:ta,Separator:ba,Group:fa};import{createContext as ua,isValidElement as Ta,useContext as ya,useId as $a}from"react";import{jsx as V,jsxs as ma}from"react/jsx-runtime";var U=ua(null);function z(){let a=ya(U);if(!a)throw Error("Tabs components must be used within Tabs.Root");return a}function S(a){if(!a||typeof a!=="object")return;if(Ta(a)){let t=a.props;if(t.value!==void 0)return t.value;return S(t.children)}if(Array.isArray(a))for(let t of a){let b=S(t);if(b!==void 0)return b}}function ia({children:a,defaultValue:t,orientation:b,...f}){let v=$a(),T=b??"horizontal";return V(U.Provider,{value:{baseId:v,selected:t??S(a),orientation:T},children:V("div",{...f,"data-orientation":T,id:`mcr:tabs:${v}`,children:a})})}function wa({children:a,...t}){let b=z();return V("div",{...t,role:"tablist","aria-orientation":b.orientation,children:a})}function Ba({children:a,value:t,id:b,selected:f,disabled:v,...T}){let y=z(),B=m(y.baseId,b??t),$=f??t===y.selected;return V("button",{...T,type:"button",role:"tab",id:`mct:tabs:${B}`,"aria-selected":$,"aria-controls":`mcc:tabs:${B}`,tabIndex:$?0:-1,"aria-disabled":v||void 0,children:a})}function Va({children:a,value:t,id:b,selected:f,focusable:v=!0,...T}){let y=z(),B=m(y.baseId,b??t),$=f??t===y.selected;return ma("div",{...T,role:"tabpanel",id:`mcc:tabs:${B}`,"aria-labelledby":`mct:tabs:${B}`,"aria-hidden":!$,hidden:$?void 0:!0,tabIndex:v?$?0:-1:void 0,"data-orientation":y.orientation,children:[!$&&V(i,{}),a]})}var ga={Root:ia,List:wa,Tab:Ba,Panel:Va};export{ga as Tabs,va as Menu,d as Collapsible,k as Accordion};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monochrome",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Accessible UI component library. Best-in-class performance. HTML-first, React supported.",
|
|
5
5
|
"author": "Colin van Eenige",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,9 +10,33 @@
|
|
|
10
10
|
},
|
|
11
11
|
"homepage": "https://github.com/vaneenige/monochrome-ui#readme",
|
|
12
12
|
"bugs": "https://github.com/vaneenige/monochrome-ui/issues",
|
|
13
|
-
"keywords": [
|
|
13
|
+
"keywords": [
|
|
14
|
+
"accessible",
|
|
15
|
+
"a11y",
|
|
16
|
+
"aria",
|
|
17
|
+
"wai-aria",
|
|
18
|
+
"ui",
|
|
19
|
+
"component",
|
|
20
|
+
"components",
|
|
21
|
+
"component-library",
|
|
22
|
+
"library",
|
|
23
|
+
"headless",
|
|
24
|
+
"unstyled",
|
|
25
|
+
"lightweight",
|
|
26
|
+
"keyboard-navigation",
|
|
27
|
+
"html",
|
|
28
|
+
"react",
|
|
29
|
+
"typescript",
|
|
30
|
+
"accordion",
|
|
31
|
+
"collapsible",
|
|
32
|
+
"menu",
|
|
33
|
+
"tabs"
|
|
34
|
+
],
|
|
14
35
|
"type": "module",
|
|
15
|
-
"sideEffects": [
|
|
36
|
+
"sideEffects": [
|
|
37
|
+
"./dist/index.js",
|
|
38
|
+
"./src/index.ts"
|
|
39
|
+
],
|
|
16
40
|
"exports": {
|
|
17
41
|
".": {
|
|
18
42
|
"types": "./src/index.ts",
|
|
@@ -21,17 +45,22 @@
|
|
|
21
45
|
"./src": "./src/index.ts",
|
|
22
46
|
"./react": {
|
|
23
47
|
"types": "./src/react/index.ts",
|
|
24
|
-
"default": "./
|
|
48
|
+
"default": "./dist/react/index.js"
|
|
25
49
|
}
|
|
26
50
|
},
|
|
27
51
|
"typesVersions": {
|
|
28
52
|
"*": {
|
|
29
|
-
"react": [
|
|
53
|
+
"react": [
|
|
54
|
+
"./src/react/index.ts"
|
|
55
|
+
]
|
|
30
56
|
}
|
|
31
57
|
},
|
|
32
|
-
"files": [
|
|
58
|
+
"files": [
|
|
59
|
+
"dist",
|
|
60
|
+
"src"
|
|
61
|
+
],
|
|
33
62
|
"scripts": {
|
|
34
|
-
"build": "bun build.ts",
|
|
63
|
+
"build": "NODE_ENV=production bun build.ts",
|
|
35
64
|
"test": "playwright test",
|
|
36
65
|
"lint": "biome check src tests",
|
|
37
66
|
"lint:fix": "biome check --write src tests",
|
|
@@ -58,5 +87,15 @@
|
|
|
58
87
|
"@types/react-dom": "19.2.3",
|
|
59
88
|
"react": "19.2.4",
|
|
60
89
|
"react-dom": "19.2.4"
|
|
90
|
+
},
|
|
91
|
+
"versionMeta": {
|
|
92
|
+
"gzipSize": 2219,
|
|
93
|
+
"tests": {
|
|
94
|
+
"total": 350,
|
|
95
|
+
"collapsible": 41,
|
|
96
|
+
"accordion": 65,
|
|
97
|
+
"menu": 175,
|
|
98
|
+
"tabs": 69
|
|
99
|
+
}
|
|
61
100
|
}
|
|
62
101
|
}
|
|
@@ -1,498 +0,0 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
if (typeof document !== "undefined") {
|
|
3
|
-
let shouldPreventDefault = null;
|
|
4
|
-
let shouldMatchLetter = null;
|
|
5
|
-
let shouldResetRadio = null;
|
|
6
|
-
let radioHeadDone = null;
|
|
7
|
-
let radioTailChain = [];
|
|
8
|
-
const menuPopovers = [];
|
|
9
|
-
let rovingBoundary = null;
|
|
10
|
-
let safeGroup = null;
|
|
11
|
-
let safeRect = null;
|
|
12
|
-
let safeDir = 0;
|
|
13
|
-
const isElement = (el) => el instanceof HTMLElement;
|
|
14
|
-
const isTrigger = (el, prefix) => el instanceof HTMLButtonElement && (!prefix || el.id.startsWith(prefix));
|
|
15
|
-
const isMenuItem = (el) => isElement(el) && el.role?.startsWith("menuitem") === true && el.ariaDisabled !== "true";
|
|
16
|
-
const getContent = (el) => document.getElementById(el.getAttribute("aria-controls") || "");
|
|
17
|
-
const findAncestor = (el, prefix) => {
|
|
18
|
-
while (el) {
|
|
19
|
-
if (el.id.startsWith(prefix))
|
|
20
|
-
return el;
|
|
21
|
-
el = el.parentElement;
|
|
22
|
-
}
|
|
23
|
-
return null;
|
|
24
|
-
};
|
|
25
|
-
const roving = (focus) => {
|
|
26
|
-
const next = (origin) => origin ? focus(origin.nextElementSibling || origin.parentElement?.firstElementChild, next) : null;
|
|
27
|
-
const previous = (origin) => origin ? focus(origin.previousElementSibling || origin.parentElement?.lastElementChild, previous) : null;
|
|
28
|
-
return [next, previous];
|
|
29
|
-
};
|
|
30
|
-
const menuRoving = (element, fallback) => {
|
|
31
|
-
if (isElement(element)) {
|
|
32
|
-
const menuitem = element.firstElementChild;
|
|
33
|
-
if (shouldResetRadio) {
|
|
34
|
-
if (isElement(menuitem)) {
|
|
35
|
-
if (menuitem === shouldResetRadio) {
|
|
36
|
-
for (const item of radioTailChain)
|
|
37
|
-
item.ariaChecked = "false";
|
|
38
|
-
return menuitem;
|
|
39
|
-
}
|
|
40
|
-
if (menuitem.role === "menuitemradio") {
|
|
41
|
-
if (!radioHeadDone) {
|
|
42
|
-
menuitem.ariaChecked = "false";
|
|
43
|
-
} else {
|
|
44
|
-
radioTailChain.push(menuitem);
|
|
45
|
-
}
|
|
46
|
-
return fallback(element);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
radioHeadDone = true;
|
|
50
|
-
radioTailChain = [];
|
|
51
|
-
return fallback(element);
|
|
52
|
-
}
|
|
53
|
-
if (isMenuItem(menuitem) && (!shouldMatchLetter || menuitem.textContent?.toLowerCase().startsWith(shouldMatchLetter))) {
|
|
54
|
-
menuitem.focus();
|
|
55
|
-
shouldPreventDefault = true;
|
|
56
|
-
return menuitem;
|
|
57
|
-
} else if (rovingBoundary !== element) {
|
|
58
|
-
if (!rovingBoundary)
|
|
59
|
-
rovingBoundary = element;
|
|
60
|
-
return fallback(element);
|
|
61
|
-
} else {
|
|
62
|
-
rovingBoundary = null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return null;
|
|
66
|
-
};
|
|
67
|
-
const accordionRoving = (node, fallback) => {
|
|
68
|
-
if (isElement(node)) {
|
|
69
|
-
if (rovingBoundary === node)
|
|
70
|
-
return null;
|
|
71
|
-
if (!rovingBoundary)
|
|
72
|
-
rovingBoundary = node;
|
|
73
|
-
const trigger = node.firstElementChild?.firstElementChild;
|
|
74
|
-
if (isTrigger(trigger, "mct:a" /* TriggerAccordion */)) {
|
|
75
|
-
if (trigger.ariaDisabled === "true")
|
|
76
|
-
return fallback(node);
|
|
77
|
-
shouldPreventDefault = true;
|
|
78
|
-
trigger.focus();
|
|
79
|
-
return trigger;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return fallback(node);
|
|
83
|
-
};
|
|
84
|
-
const tabsRoving = (node, fallback) => {
|
|
85
|
-
if (isTrigger(node, "mct:t" /* TriggerTabs */)) {
|
|
86
|
-
if (rovingBoundary === node)
|
|
87
|
-
return null;
|
|
88
|
-
if (!rovingBoundary)
|
|
89
|
-
rovingBoundary = node;
|
|
90
|
-
if (node.ariaDisabled === "true")
|
|
91
|
-
return fallback(node);
|
|
92
|
-
shouldPreventDefault = true;
|
|
93
|
-
node.focus();
|
|
94
|
-
return node;
|
|
95
|
-
} else {
|
|
96
|
-
return fallback(node);
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
const [menuNext, menuPrevious] = roving(menuRoving);
|
|
100
|
-
const [accordionNext, accordionPrevious] = roving(accordionRoving);
|
|
101
|
-
const [tabNext, tabPrevious] = roving(tabsRoving);
|
|
102
|
-
const collapsible = (trigger) => {
|
|
103
|
-
const content = getContent(trigger);
|
|
104
|
-
if (content) {
|
|
105
|
-
const isOpen = trigger.ariaExpanded !== "true";
|
|
106
|
-
trigger.ariaExpanded = isOpen ? "true" : "false";
|
|
107
|
-
content.ariaHidden = isOpen ? "false" : "true";
|
|
108
|
-
isOpen ? content.removeAttribute("hidden") : content.setAttribute("hidden", "until-found");
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
const accordion = (trigger) => {
|
|
112
|
-
if (trigger.ariaDisabled === "true")
|
|
113
|
-
return;
|
|
114
|
-
if (trigger.ariaExpanded === "true") {
|
|
115
|
-
collapsible(trigger);
|
|
116
|
-
} else {
|
|
117
|
-
const root = findAncestor(trigger, "mcr:a" /* RootAccordion */);
|
|
118
|
-
if (!root || root.getAttribute("data-mode") !== "single") {
|
|
119
|
-
collapsible(trigger);
|
|
120
|
-
} else {
|
|
121
|
-
let item = root.firstElementChild;
|
|
122
|
-
while (item) {
|
|
123
|
-
const itemTrigger = item.firstElementChild?.firstElementChild;
|
|
124
|
-
if (isElement(itemTrigger) && (itemTrigger === trigger || itemTrigger.ariaExpanded === "true")) {
|
|
125
|
-
collapsible(itemTrigger);
|
|
126
|
-
}
|
|
127
|
-
item = item.nextElementSibling;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
const tabs = (trigger) => {
|
|
133
|
-
if (trigger.ariaDisabled !== "true" && trigger.ariaSelected !== "true") {
|
|
134
|
-
let tab = trigger.parentElement?.firstElementChild;
|
|
135
|
-
while (isElement(tab)) {
|
|
136
|
-
if (tab === trigger || tab.ariaSelected === "true") {
|
|
137
|
-
const content = getContent(tab);
|
|
138
|
-
if (content) {
|
|
139
|
-
const isSelected = tab.ariaSelected !== "true";
|
|
140
|
-
tab.ariaSelected = isSelected ? "true" : "false";
|
|
141
|
-
tab.tabIndex = isSelected ? 0 : -1;
|
|
142
|
-
content.ariaHidden = isSelected ? "false" : "true";
|
|
143
|
-
if (content.hasAttribute("tabindex"))
|
|
144
|
-
content.tabIndex = isSelected ? 0 : -1;
|
|
145
|
-
isSelected ? content.removeAttribute("hidden") : content.setAttribute("hidden", "until-found");
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
tab = tab.nextElementSibling;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
const menu = (trigger, mode = 0 /* Trigger */) => {
|
|
153
|
-
if (trigger?.id.startsWith("mct:m" /* TriggerMenu */)) {
|
|
154
|
-
const content = getContent(trigger);
|
|
155
|
-
if (content) {
|
|
156
|
-
if (trigger.ariaExpanded === "true") {
|
|
157
|
-
if (safeGroup)
|
|
158
|
-
safeGroup.removeAttribute("data-safe");
|
|
159
|
-
safeGroup = null;
|
|
160
|
-
if (mode !== 3 /* None */)
|
|
161
|
-
trigger.focus();
|
|
162
|
-
content.hidePopover();
|
|
163
|
-
trigger.ariaExpanded = "false";
|
|
164
|
-
content.ariaHidden = "true";
|
|
165
|
-
} else {
|
|
166
|
-
menuPopovers.push(trigger);
|
|
167
|
-
content.showPopover();
|
|
168
|
-
trigger.ariaExpanded = "true";
|
|
169
|
-
content.ariaHidden = "false";
|
|
170
|
-
const rect = trigger.getBoundingClientRect();
|
|
171
|
-
content.style.setProperty("--top", `${rect.top}px`);
|
|
172
|
-
content.style.setProperty("--right", `${rect.right}px`);
|
|
173
|
-
content.style.setProperty("--bottom", `${rect.bottom}px`);
|
|
174
|
-
content.style.setProperty("--left", `${rect.left}px`);
|
|
175
|
-
const group = trigger.parentElement;
|
|
176
|
-
if (group) {
|
|
177
|
-
const cr = content.getBoundingClientRect();
|
|
178
|
-
const right = cr.left > rect.right;
|
|
179
|
-
const sx = right ? cr.left : cr.right;
|
|
180
|
-
safeGroup = group;
|
|
181
|
-
safeRect = rect;
|
|
182
|
-
safeDir = right ? -4 : 4;
|
|
183
|
-
group.style.setProperty("--right", `${sx}px`);
|
|
184
|
-
group.style.setProperty("--top", `${cr.top}px`);
|
|
185
|
-
group.style.setProperty("--bottom", `${cr.bottom}px`);
|
|
186
|
-
}
|
|
187
|
-
if (mode === 0 /* Trigger */) {
|
|
188
|
-
trigger.focus();
|
|
189
|
-
} else if (mode === 1 /* First */) {
|
|
190
|
-
menuRoving(content.firstElementChild, menuNext);
|
|
191
|
-
} else if (mode === 2 /* Last */) {
|
|
192
|
-
menuRoving(content.lastElementChild, menuPrevious);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
const menuHideAll = (keep = 0) => {
|
|
199
|
-
while (menuPopovers[keep])
|
|
200
|
-
menu(menuPopovers.pop(), 3 /* None */);
|
|
201
|
-
};
|
|
202
|
-
const menuItemAction = (el) => {
|
|
203
|
-
if (el.role === "menuitemcheckbox") {
|
|
204
|
-
el.ariaChecked = el.ariaChecked === "true" ? "false" : "true";
|
|
205
|
-
} else if (el.role === "menuitemradio") {
|
|
206
|
-
shouldResetRadio = el;
|
|
207
|
-
radioHeadDone = null;
|
|
208
|
-
radioTailChain = [];
|
|
209
|
-
menuNext(el.parentElement);
|
|
210
|
-
shouldResetRadio = null;
|
|
211
|
-
el.ariaChecked = "true";
|
|
212
|
-
} else {
|
|
213
|
-
menuHideAll();
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
addEventListener("click", (event) => {
|
|
217
|
-
shouldPreventDefault = null;
|
|
218
|
-
const keyboard = event.detail === 0;
|
|
219
|
-
const start = isElement(event.target) ? event.target : event.target instanceof Element ? event.target.parentElement : null;
|
|
220
|
-
if (start) {
|
|
221
|
-
let target = start;
|
|
222
|
-
while (target) {
|
|
223
|
-
const id = target.id;
|
|
224
|
-
if (id.startsWith("mct:" /* Trigger */)) {
|
|
225
|
-
if (id.startsWith("mct:m" /* TriggerMenu */)) {
|
|
226
|
-
const focusMode = keyboard ? 1 /* First */ : 3 /* None */;
|
|
227
|
-
const inPopover = findAncestor(target.parentElement, "mcc:m" /* ContentMenu */);
|
|
228
|
-
if (inPopover) {
|
|
229
|
-
if (!menuPopovers.includes(target))
|
|
230
|
-
menu(target, focusMode);
|
|
231
|
-
} else {
|
|
232
|
-
if (menuPopovers[0]) {
|
|
233
|
-
const openTarget = target !== menuPopovers[0];
|
|
234
|
-
menuHideAll();
|
|
235
|
-
if (openTarget)
|
|
236
|
-
menu(target, focusMode);
|
|
237
|
-
} else {
|
|
238
|
-
menu(target, focusMode);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
} else {
|
|
242
|
-
if (menuPopovers[0])
|
|
243
|
-
menuHideAll();
|
|
244
|
-
if (id.startsWith("mct:a" /* TriggerAccordion */))
|
|
245
|
-
accordion(target);
|
|
246
|
-
else if (id.startsWith("mct:c" /* TriggerCollapsible */))
|
|
247
|
-
collapsible(target);
|
|
248
|
-
else if (id.startsWith("mct:t" /* TriggerTabs */))
|
|
249
|
-
tabs(target);
|
|
250
|
-
}
|
|
251
|
-
break;
|
|
252
|
-
} else if (id.startsWith("mcc:m" /* ContentMenu */) && menuPopovers[0]) {
|
|
253
|
-
let el = start;
|
|
254
|
-
while (el && el !== target) {
|
|
255
|
-
if (isMenuItem(el) && !isTrigger(el, "mct:m" /* TriggerMenu */)) {
|
|
256
|
-
menuItemAction(el);
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
el = el.parentElement;
|
|
260
|
-
}
|
|
261
|
-
break;
|
|
262
|
-
}
|
|
263
|
-
target = target.parentElement;
|
|
264
|
-
}
|
|
265
|
-
if (!target && menuPopovers[0])
|
|
266
|
-
menuHideAll();
|
|
267
|
-
}
|
|
268
|
-
if (shouldPreventDefault)
|
|
269
|
-
event.preventDefault();
|
|
270
|
-
});
|
|
271
|
-
addEventListener("pointermove", (event) => {
|
|
272
|
-
if (event.pointerType === "touch")
|
|
273
|
-
return;
|
|
274
|
-
if (menuPopovers[0]) {
|
|
275
|
-
if (menuPopovers[1] && safeGroup && safeRect) {
|
|
276
|
-
if (event.clientX >= safeRect.left && event.clientX <= safeRect.right && event.clientY >= safeRect.top && event.clientY <= safeRect.bottom) {
|
|
277
|
-
safeGroup.style.setProperty("--left", `${event.clientX + safeDir}px`);
|
|
278
|
-
safeGroup.style.setProperty("--center", `${event.clientY}px`);
|
|
279
|
-
if (!safeGroup.hasAttribute("data-safe"))
|
|
280
|
-
safeGroup.setAttribute("data-safe", "");
|
|
281
|
-
} else if (safeGroup.hasAttribute("data-safe") && (event.target !== safeGroup || safeDir * event.movementX > 0)) {
|
|
282
|
-
safeGroup.removeAttribute("data-safe");
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
const el = event.target;
|
|
286
|
-
if (isElement(el)) {
|
|
287
|
-
const popoverTriggers = [];
|
|
288
|
-
let target = el;
|
|
289
|
-
let bail = false;
|
|
290
|
-
let foundItem = false;
|
|
291
|
-
while (target) {
|
|
292
|
-
if (isMenuItem(target)) {
|
|
293
|
-
foundItem = true;
|
|
294
|
-
}
|
|
295
|
-
if (!foundItem && target.id.startsWith("mcc:" /* Content */)) {
|
|
296
|
-
bail = true;
|
|
297
|
-
break;
|
|
298
|
-
}
|
|
299
|
-
const firstChild = target.firstElementChild;
|
|
300
|
-
if (isTrigger(firstChild, "mct:m" /* TriggerMenu */)) {
|
|
301
|
-
popoverTriggers.unshift(firstChild);
|
|
302
|
-
}
|
|
303
|
-
target = target.parentElement;
|
|
304
|
-
}
|
|
305
|
-
if (!bail && popoverTriggers[0]) {
|
|
306
|
-
let i = 0;
|
|
307
|
-
while (menuPopovers[i] && menuPopovers[i] === popoverTriggers[i])
|
|
308
|
-
i++;
|
|
309
|
-
if (i === 0 && popoverTriggers[0].role !== "menuitem")
|
|
310
|
-
return;
|
|
311
|
-
menuHideAll(i);
|
|
312
|
-
menu(popoverTriggers[i], 3 /* None */);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
addEventListener("keydown", (event) => {
|
|
318
|
-
shouldPreventDefault = null;
|
|
319
|
-
shouldMatchLetter = null;
|
|
320
|
-
rovingBoundary = null;
|
|
321
|
-
const target = event.target;
|
|
322
|
-
if (isTrigger(target, "mct:a" /* TriggerAccordion */)) {
|
|
323
|
-
const item = target.parentElement?.parentElement;
|
|
324
|
-
if (item) {
|
|
325
|
-
switch (event.key) {
|
|
326
|
-
case "ArrowDown":
|
|
327
|
-
accordionNext(item);
|
|
328
|
-
break;
|
|
329
|
-
case "ArrowUp":
|
|
330
|
-
accordionPrevious(item);
|
|
331
|
-
break;
|
|
332
|
-
case "Home": {
|
|
333
|
-
const root = item.parentElement;
|
|
334
|
-
if (root)
|
|
335
|
-
accordionRoving(root.firstElementChild, accordionNext);
|
|
336
|
-
break;
|
|
337
|
-
}
|
|
338
|
-
case "End": {
|
|
339
|
-
const root = item.parentElement;
|
|
340
|
-
if (root)
|
|
341
|
-
accordionRoving(root.lastElementChild, accordionPrevious);
|
|
342
|
-
break;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
} else if (isTrigger(target, "mct:t" /* TriggerTabs */)) {
|
|
347
|
-
const vertical = target.parentElement?.ariaOrientation === "vertical";
|
|
348
|
-
switch (event.key) {
|
|
349
|
-
case "ArrowDown":
|
|
350
|
-
if (vertical)
|
|
351
|
-
tabNext(target);
|
|
352
|
-
break;
|
|
353
|
-
case "ArrowUp":
|
|
354
|
-
if (vertical)
|
|
355
|
-
tabPrevious(target);
|
|
356
|
-
break;
|
|
357
|
-
case "ArrowRight":
|
|
358
|
-
if (!vertical)
|
|
359
|
-
tabNext(target);
|
|
360
|
-
break;
|
|
361
|
-
case "ArrowLeft":
|
|
362
|
-
if (!vertical)
|
|
363
|
-
tabPrevious(target);
|
|
364
|
-
break;
|
|
365
|
-
case "Home":
|
|
366
|
-
tabsRoving(target.parentElement?.firstElementChild, tabNext);
|
|
367
|
-
break;
|
|
368
|
-
case "End":
|
|
369
|
-
tabsRoving(target.parentElement?.lastElementChild, tabPrevious);
|
|
370
|
-
break;
|
|
371
|
-
}
|
|
372
|
-
} else {
|
|
373
|
-
if (isTrigger(target, "mct:m" /* TriggerMenu */)) {
|
|
374
|
-
const isRootTrigger = findAncestor(target, "mcc:m" /* ContentMenu */) === null;
|
|
375
|
-
switch (event.key) {
|
|
376
|
-
case "ArrowDown":
|
|
377
|
-
if (isRootTrigger) {
|
|
378
|
-
if (target.ariaExpanded !== "true") {
|
|
379
|
-
menu(target, 1 /* First */);
|
|
380
|
-
} else {
|
|
381
|
-
const content = getContent(target);
|
|
382
|
-
if (content)
|
|
383
|
-
menuRoving(content.firstElementChild, menuNext);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
break;
|
|
387
|
-
case "ArrowUp":
|
|
388
|
-
if (isRootTrigger) {
|
|
389
|
-
if (target.ariaExpanded !== "true") {
|
|
390
|
-
menu(target, 2 /* Last */);
|
|
391
|
-
} else {
|
|
392
|
-
const content = getContent(target);
|
|
393
|
-
if (content)
|
|
394
|
-
menuRoving(content.lastElementChild, menuPrevious);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
break;
|
|
398
|
-
case "ArrowRight":
|
|
399
|
-
if (!isRootTrigger)
|
|
400
|
-
menu(target, 1 /* First */);
|
|
401
|
-
break;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
if (!shouldPreventDefault && isElement(target) && target.role?.startsWith("menuitem") && target.parentElement) {
|
|
405
|
-
const parent = target.parentElement;
|
|
406
|
-
const menubarRoot = menuPopovers[0]?.parentElement || parent;
|
|
407
|
-
const inPopover = findAncestor(target.parentElement, "mcc:m" /* ContentMenu */);
|
|
408
|
-
switch (event.key) {
|
|
409
|
-
case "Tab":
|
|
410
|
-
if (menuPopovers[0])
|
|
411
|
-
menuPopovers[0].focus();
|
|
412
|
-
menuHideAll();
|
|
413
|
-
break;
|
|
414
|
-
case "ArrowDown":
|
|
415
|
-
if (inPopover)
|
|
416
|
-
menuNext(parent);
|
|
417
|
-
break;
|
|
418
|
-
case "ArrowUp":
|
|
419
|
-
if (inPopover)
|
|
420
|
-
menuPrevious(parent);
|
|
421
|
-
break;
|
|
422
|
-
case "ArrowRight": {
|
|
423
|
-
const nextNode = menuNext(menubarRoot);
|
|
424
|
-
if (nextNode) {
|
|
425
|
-
const hadOpenMenu = menuPopovers[0];
|
|
426
|
-
menuHideAll();
|
|
427
|
-
if (hadOpenMenu && isTrigger(nextNode, "mct:m" /* TriggerMenu */)) {
|
|
428
|
-
menu(nextNode, 3 /* None */);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
break;
|
|
432
|
-
}
|
|
433
|
-
case "ArrowLeft":
|
|
434
|
-
if (menuPopovers[1]) {
|
|
435
|
-
menu(menuPopovers.pop(), 0 /* Trigger */);
|
|
436
|
-
} else {
|
|
437
|
-
const nextNode = menuPrevious(menubarRoot);
|
|
438
|
-
if (nextNode) {
|
|
439
|
-
const hadOpenMenu = menuPopovers[0];
|
|
440
|
-
menuHideAll();
|
|
441
|
-
if (hadOpenMenu && isTrigger(nextNode, "mct:m" /* TriggerMenu */)) {
|
|
442
|
-
menu(nextNode, 3 /* None */);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
break;
|
|
447
|
-
case "Home":
|
|
448
|
-
menuRoving(parent.parentElement?.firstElementChild, menuNext);
|
|
449
|
-
break;
|
|
450
|
-
case "End":
|
|
451
|
-
menuRoving(parent.parentElement?.lastElementChild, menuPrevious);
|
|
452
|
-
break;
|
|
453
|
-
default:
|
|
454
|
-
if (/^[a-zA-Z]$/.test(event.key)) {
|
|
455
|
-
shouldMatchLetter = event.key.toLowerCase();
|
|
456
|
-
menuNext(parent);
|
|
457
|
-
}
|
|
458
|
-
break;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
if (event.key === "Escape" && menuPopovers[0]) {
|
|
463
|
-
menu(menuPopovers.pop(), 0 /* Trigger */);
|
|
464
|
-
}
|
|
465
|
-
if (shouldPreventDefault)
|
|
466
|
-
event.preventDefault();
|
|
467
|
-
});
|
|
468
|
-
addEventListener("scroll", (event) => {
|
|
469
|
-
if (menuPopovers[0] && (!isElement(event.target) || !event.target.id.startsWith("mcc:m" /* ContentMenu */))) {
|
|
470
|
-
menuHideAll();
|
|
471
|
-
}
|
|
472
|
-
}, true);
|
|
473
|
-
addEventListener("resize", () => {
|
|
474
|
-
if (menuPopovers[0])
|
|
475
|
-
menuHideAll();
|
|
476
|
-
});
|
|
477
|
-
addEventListener("beforematch", (event) => {
|
|
478
|
-
if (isElement(event.target)) {
|
|
479
|
-
let target = event.target;
|
|
480
|
-
while (target) {
|
|
481
|
-
const triggerId = target.getAttribute("aria-labelledby");
|
|
482
|
-
if (triggerId) {
|
|
483
|
-
const trigger = document.getElementById(triggerId);
|
|
484
|
-
if (isTrigger(trigger, "mct:a" /* TriggerAccordion */)) {
|
|
485
|
-
if (trigger.ariaExpanded !== "true")
|
|
486
|
-
accordion(trigger);
|
|
487
|
-
} else if (isTrigger(trigger, "mct:c" /* TriggerCollapsible */)) {
|
|
488
|
-
if (trigger.ariaExpanded !== "true")
|
|
489
|
-
collapsible(trigger);
|
|
490
|
-
} else if (isTrigger(trigger, "mct:t" /* TriggerTabs */)) {
|
|
491
|
-
tabs(trigger);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
target = target.parentElement;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
}
|