@featherk/composables 0.0.4
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.
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import { ref as E, onMounted as S, onBeforeUnmount as M, nextTick as p, onUnmounted as N } from "vue";
|
|
2
|
+
const G = (m) => {
|
|
3
|
+
const l = E(null);
|
|
4
|
+
let d = null, u = null;
|
|
5
|
+
const f = [], v = ".k-table-row[data-grid-row-index] [tabindex]", k = () => m?.value?.columns, h = (e) => {
|
|
6
|
+
const o = e.key || e.code;
|
|
7
|
+
[" ", "Spacebar", "Space", "Enter"].includes(o) && (e.preventDefault(), e.stopPropagation(), l.value = e.target, e.target.click());
|
|
8
|
+
}, g = (e) => {
|
|
9
|
+
if (!l.value) return;
|
|
10
|
+
if (e.code === "Escape") {
|
|
11
|
+
e.preventDefault(), e.stopPropagation(), l.value && l.value.focus();
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const o = Array.from(
|
|
15
|
+
document.querySelectorAll(
|
|
16
|
+
".k-animation-container .k-popup .k-column-menu .k-columnmenu-item-wrapper .k-columnmenu-item"
|
|
17
|
+
)
|
|
18
|
+
), t = document.querySelector(".k-filter-menu-container");
|
|
19
|
+
if (t) {
|
|
20
|
+
if (e.code === "Tab") {
|
|
21
|
+
const r = [
|
|
22
|
+
".k-filter-menu-container .k-dropdownlist[tabindex='0']",
|
|
23
|
+
".k-filter-menu-container input.k-input-inner:not([tabindex='-1']):not([disabled])",
|
|
24
|
+
".k-filter-menu-container button:not([tabindex='-1']):not([disabled])"
|
|
25
|
+
], n = Array.from(
|
|
26
|
+
t.querySelectorAll(r.join(","))
|
|
27
|
+
);
|
|
28
|
+
if (n.length === 0) return;
|
|
29
|
+
const a = n.findIndex(
|
|
30
|
+
(s) => s === document.activeElement
|
|
31
|
+
);
|
|
32
|
+
let i;
|
|
33
|
+
a === -1 ? i = 0 : e.shiftKey ? i = (a - 1 + n.length) % n.length : i = (a + 1) % n.length, e.preventDefault(), e.stopPropagation(), n[i]?.focus();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
} else if (e.code === "ArrowUp" || e.code === "ArrowDown") {
|
|
37
|
+
e.preventDefault(), e.stopPropagation();
|
|
38
|
+
const r = o.findIndex(
|
|
39
|
+
(a) => a === document.activeElement
|
|
40
|
+
);
|
|
41
|
+
let n = r;
|
|
42
|
+
e.code === "ArrowUp" ? n = r > 0 ? r - 1 : o.length - 1 : e.code === "ArrowDown" && (n = r < o.length - 1 ? r + 1 : 0), o[n]?.focus();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
e.code === "Tab" && (e.preventDefault(), e.stopPropagation(), e.shiftKey ? (l.value?.previousElementSibling).focus() : (l.value?.nextElementSibling).focus());
|
|
46
|
+
}, x = () => {
|
|
47
|
+
d = new MutationObserver((e) => {
|
|
48
|
+
e.forEach((o) => {
|
|
49
|
+
o.addedNodes.forEach((t) => {
|
|
50
|
+
if (t.nodeType === Node.ELEMENT_NODE) {
|
|
51
|
+
const r = t;
|
|
52
|
+
if (r.classList.contains("k-animation-container")) {
|
|
53
|
+
const a = l.value;
|
|
54
|
+
a && (a.dataset.featherKSortable === "true" || p(() => {
|
|
55
|
+
r.querySelectorAll(
|
|
56
|
+
".k-columnmenu-item-wrapper"
|
|
57
|
+
).forEach((b) => {
|
|
58
|
+
b.textContent?.toLowerCase().includes("sort") && b.remove();
|
|
59
|
+
});
|
|
60
|
+
})), r.addEventListener(
|
|
61
|
+
"keydown",
|
|
62
|
+
g
|
|
63
|
+
), p(() => {
|
|
64
|
+
const i = () => {
|
|
65
|
+
const s = Array.from(
|
|
66
|
+
r.querySelectorAll(
|
|
67
|
+
".k-animation-container .k-popup .k-column-menu .k-columnmenu-item-wrapper .k-columnmenu-item"
|
|
68
|
+
)
|
|
69
|
+
);
|
|
70
|
+
if (s.length === 1)
|
|
71
|
+
s[0].focus(), s[0].click(), i.attempts = 0;
|
|
72
|
+
else if (s.length > 1) {
|
|
73
|
+
i.attempts = 0;
|
|
74
|
+
return;
|
|
75
|
+
} else
|
|
76
|
+
i.attempts === void 0 && (i.attempts = 0), i.attempts++ < 3 && setTimeout(i, 200);
|
|
77
|
+
};
|
|
78
|
+
i();
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
r.querySelectorAll(
|
|
82
|
+
".k-animation-container"
|
|
83
|
+
).forEach((a) => {
|
|
84
|
+
a.addEventListener(
|
|
85
|
+
"keydown",
|
|
86
|
+
g
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}), o.removedNodes.forEach((t) => {
|
|
91
|
+
if (t.nodeType === Node.ELEMENT_NODE) {
|
|
92
|
+
const r = t;
|
|
93
|
+
r.classList.contains("k-animation-container") && r.removeEventListener(
|
|
94
|
+
"keydown",
|
|
95
|
+
g
|
|
96
|
+
), r.querySelectorAll(
|
|
97
|
+
".k-animation-container"
|
|
98
|
+
).forEach((a) => {
|
|
99
|
+
a.removeEventListener(
|
|
100
|
+
"keydown",
|
|
101
|
+
g
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}), d.observe(document.body, {
|
|
108
|
+
childList: !0,
|
|
109
|
+
subtree: !0
|
|
110
|
+
});
|
|
111
|
+
}, L = (e) => {
|
|
112
|
+
if (!e.type || !e)
|
|
113
|
+
return;
|
|
114
|
+
console.log("handleGridKeyDown", e, e.code);
|
|
115
|
+
const o = e.target;
|
|
116
|
+
if (o && [
|
|
117
|
+
"ArrowDown",
|
|
118
|
+
"ArrowLeft",
|
|
119
|
+
"ArrowRight",
|
|
120
|
+
"ArrowUp",
|
|
121
|
+
"Enter",
|
|
122
|
+
"Space"
|
|
123
|
+
].includes(e.code)) {
|
|
124
|
+
if (e.preventDefault(), o.classList.contains("k-grid-header-menu") && o.classList.contains("k-grid-column-menu")) {
|
|
125
|
+
l.value = o;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const t = o.closest(
|
|
129
|
+
".k-table-row[data-grid-row-index]"
|
|
130
|
+
);
|
|
131
|
+
if (t) {
|
|
132
|
+
if (["ArrowDown", "ArrowUp"].includes(e.code)) {
|
|
133
|
+
let r = null;
|
|
134
|
+
e.code === "ArrowDown" ? r = t.nextElementSibling : e.code === "ArrowUp" && (r = t.previousElementSibling), r && r.hasAttribute("tabindex") && (t.setAttribute("tabindex", "-1"), r.setAttribute("tabindex", "0"), r.focus());
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (["ArrowLeft", "ArrowRight"].includes(e.code)) {
|
|
138
|
+
e.preventDefault();
|
|
139
|
+
const r = t.querySelectorAll(
|
|
140
|
+
v
|
|
141
|
+
);
|
|
142
|
+
if (r.length === 0) return;
|
|
143
|
+
let n = Array.from(r).findIndex(
|
|
144
|
+
(a) => a === document.activeElement
|
|
145
|
+
);
|
|
146
|
+
if (n === -1 && document.activeElement === t) {
|
|
147
|
+
r[0].focus();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
e.code === "ArrowRight" ? n = n === r.length - 1 ? 0 : n + 1 : e.code === "ArrowLeft" && (n = n === r.length - 1 ? n - 1 : r.length - 1), r[n].focus();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}, D = () => {
|
|
156
|
+
p(() => {
|
|
157
|
+
const e = m.value.$el.closest(".k-grid");
|
|
158
|
+
e && e.classList.add("fk-grid");
|
|
159
|
+
});
|
|
160
|
+
}, T = () => {
|
|
161
|
+
try {
|
|
162
|
+
const e = () => {
|
|
163
|
+
try {
|
|
164
|
+
const r = Array.from(
|
|
165
|
+
m.value.$el.querySelectorAll(
|
|
166
|
+
".k-table-row[data-grid-row-index]"
|
|
167
|
+
)
|
|
168
|
+
);
|
|
169
|
+
if (!r || r.length === 0 || r.filter(
|
|
170
|
+
(i) => i.getAttribute("tabindex") === "0"
|
|
171
|
+
).length === 1) return;
|
|
172
|
+
const a = r.find(
|
|
173
|
+
(i) => i === document.activeElement || i.contains(document.activeElement)
|
|
174
|
+
);
|
|
175
|
+
if (r.forEach((i) => i.setAttribute("tabindex", "-1")), a) {
|
|
176
|
+
a.setAttribute("tabindex", "0");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
r[0].setAttribute("tabindex", "0");
|
|
180
|
+
} catch (r) {
|
|
181
|
+
console.error("ensureSingleTabindex error:", r);
|
|
182
|
+
}
|
|
183
|
+
}, o = Array.from(
|
|
184
|
+
m.value.$el.querySelectorAll(
|
|
185
|
+
".k-table-row[data-grid-row-index]"
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
|
+
o.length > 0 && o.forEach((r, n) => {
|
|
189
|
+
r.setAttribute("tabindex", n === 0 ? "0" : "-1");
|
|
190
|
+
});
|
|
191
|
+
const t = m.value.$el.querySelector(".k-table-tbody");
|
|
192
|
+
t && (u = new MutationObserver(() => {
|
|
193
|
+
e();
|
|
194
|
+
}), u.observe(t, { childList: !0, subtree: !0 }));
|
|
195
|
+
} catch (e) {
|
|
196
|
+
console.error("Error setting up row navigation:", e);
|
|
197
|
+
}
|
|
198
|
+
}, q = () => {
|
|
199
|
+
p(() => {
|
|
200
|
+
const o = document.querySelectorAll(".k-grid-header .k-grid-header-menu.k-grid-column-menu");
|
|
201
|
+
o && o.forEach((t) => {
|
|
202
|
+
t.setAttribute("role", "button"), t.addEventListener(
|
|
203
|
+
"keydown",
|
|
204
|
+
h
|
|
205
|
+
);
|
|
206
|
+
}), x(), I();
|
|
207
|
+
});
|
|
208
|
+
}, C = () => {
|
|
209
|
+
const o = document.querySelectorAll(".k-grid-header .k-grid-header-menu.k-grid-column-menu");
|
|
210
|
+
o && o.forEach((t) => {
|
|
211
|
+
t.removeEventListener(
|
|
212
|
+
"keydown",
|
|
213
|
+
h
|
|
214
|
+
);
|
|
215
|
+
}), d && (d.disconnect(), d = null), u && (u.disconnect(), u = null), f.forEach((t) => t()), f.length = 0;
|
|
216
|
+
}, I = () => {
|
|
217
|
+
document.querySelectorAll(
|
|
218
|
+
".k-grid-header .k-table-thead th"
|
|
219
|
+
).forEach((t, r) => {
|
|
220
|
+
const n = t.querySelector(
|
|
221
|
+
".k-grid-header-menu.k-grid-column-menu"
|
|
222
|
+
);
|
|
223
|
+
if (!n) return;
|
|
224
|
+
const a = k();
|
|
225
|
+
if (a && a[r]) {
|
|
226
|
+
const c = a[r].field ?? "";
|
|
227
|
+
t.setAttribute("data-feather-k-field", c), t.setAttribute(
|
|
228
|
+
"data-feather-k-filterable",
|
|
229
|
+
a[r].filterable === !1 ? "false" : "true"
|
|
230
|
+
), t.setAttribute(
|
|
231
|
+
"data-feather-k-sortable",
|
|
232
|
+
a[r].sortable === !1 ? "false" : "true"
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
const i = t.dataset.featherKFilterable !== "false", s = t.dataset.featherKSortable !== "false";
|
|
236
|
+
n.setAttribute("tabindex", "-1"), i ? (t.setAttribute("tabindex", "0"), t.setAttribute("role", "button"), t.setAttribute("aria-haspopup", "menu"), t.style.cursor = "pointer") : (t.setAttribute("tabindex", "0"), t.setAttribute("role", "columnheader"), t.removeAttribute("aria-haspopup"), t.style.cursor = "default");
|
|
237
|
+
const b = (c) => {
|
|
238
|
+
c.target?.closest(".k-column-resizer") || (l.value = t, n.click());
|
|
239
|
+
}, w = (c) => {
|
|
240
|
+
if (i)
|
|
241
|
+
l.value = t, c.preventDefault(), c.stopPropagation(), b(c);
|
|
242
|
+
else if (s) {
|
|
243
|
+
l.value = t;
|
|
244
|
+
const y = new KeyboardEvent("keydown", {
|
|
245
|
+
key: "Enter",
|
|
246
|
+
code: "Enter",
|
|
247
|
+
keyCode: 13,
|
|
248
|
+
which: 13,
|
|
249
|
+
bubbles: !0,
|
|
250
|
+
cancelable: !0
|
|
251
|
+
});
|
|
252
|
+
t.dispatchEvent(y);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
t.addEventListener("click", w), f.push(() => {
|
|
256
|
+
t.removeEventListener("click", w);
|
|
257
|
+
});
|
|
258
|
+
const A = (c) => {
|
|
259
|
+
if ((c.code === "Enter" || c.code === "Space") && (i || s)) {
|
|
260
|
+
if (l.value = t, l.value.focus(), i)
|
|
261
|
+
c.preventDefault(), c.stopPropagation(), b(c);
|
|
262
|
+
else if (s) {
|
|
263
|
+
const y = t.querySelector(".k-link");
|
|
264
|
+
y && y.click();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
t.addEventListener("keydown", A, !0), f.push(() => {
|
|
269
|
+
t.removeEventListener("keydown", A, !0);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
const o = document.querySelector(".k-grid-header .k-table-thead");
|
|
273
|
+
if (o) {
|
|
274
|
+
const t = (r) => {
|
|
275
|
+
const n = r.target.closest("th");
|
|
276
|
+
n && (r.code === "Enter" || r.code === "Space") && n.dataset.featherKFilterable === "false" && n.dataset.featherKSortable === "false" && (r.preventDefault(), r.stopImmediatePropagation());
|
|
277
|
+
};
|
|
278
|
+
o.addEventListener(
|
|
279
|
+
"keydown",
|
|
280
|
+
t,
|
|
281
|
+
!0
|
|
282
|
+
// NOTE: capture phase
|
|
283
|
+
), f.push(() => {
|
|
284
|
+
o.removeEventListener(
|
|
285
|
+
"keydown",
|
|
286
|
+
t,
|
|
287
|
+
!0
|
|
288
|
+
);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}, K = function(e, o) {
|
|
292
|
+
const t = e?.event.event.target, r = k();
|
|
293
|
+
if (!t || !r) return;
|
|
294
|
+
const n = t.classList.contains("k-link"), a = t.classList.contains("k-columnmenu-item"), i = r.find((s) => s.field === e.event.field)?.sortable && !0;
|
|
295
|
+
if (!n) {
|
|
296
|
+
if (a && !i) {
|
|
297
|
+
(e.event.sort && void 0)?.filter(
|
|
298
|
+
(b) => b.field !== e.event.field
|
|
299
|
+
);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
typeof o == "function" && p(() => {
|
|
303
|
+
l.value && l.value.focus(), o(e);
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
return S(() => {
|
|
308
|
+
D(), T(), q();
|
|
309
|
+
}), M(() => {
|
|
310
|
+
C();
|
|
311
|
+
}), {
|
|
312
|
+
activeFilterButton: l,
|
|
313
|
+
handleGridKeyDown: L,
|
|
314
|
+
handleSortChange: K
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
function B(m = {}) {
|
|
318
|
+
const { activeByDefault: l = !1, autoActivateDelay: d = 0 } = m, u = E(l);
|
|
319
|
+
function f() {
|
|
320
|
+
u.value = !0;
|
|
321
|
+
}
|
|
322
|
+
function v() {
|
|
323
|
+
u.value = !1;
|
|
324
|
+
}
|
|
325
|
+
function k() {
|
|
326
|
+
u.value = !u.value;
|
|
327
|
+
}
|
|
328
|
+
return S(() => {
|
|
329
|
+
d > 0 && !l && setTimeout(() => {
|
|
330
|
+
f();
|
|
331
|
+
}, d);
|
|
332
|
+
}), N(() => {
|
|
333
|
+
}), {
|
|
334
|
+
isGridActive: u,
|
|
335
|
+
activateGrid: f,
|
|
336
|
+
deactivateGrid: v,
|
|
337
|
+
toggleGrid: k
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
export {
|
|
341
|
+
G as useGridA11y,
|
|
342
|
+
B as useGridComposableEx
|
|
343
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(f,s){typeof exports=="object"&&typeof module<"u"?s(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],s):(f=typeof globalThis<"u"?globalThis:f||self,s(f.FeatherKComposables={},f.Vue))})(this,(function(f,s){"use strict";const S=p=>{const l=s.ref(null);let m=null,d=null;const b=[],h=".k-table-row[data-grid-row-index] [tabindex]",g=()=>p?.value?.columns,v=e=>{const o=e.key||e.code;[" ","Spacebar","Space","Enter"].includes(o)&&(e.preventDefault(),e.stopPropagation(),l.value=e.target,e.target.click())},y=e=>{if(!l.value)return;if(e.code==="Escape"){e.preventDefault(),e.stopPropagation(),l.value&&l.value.focus();return}const o=Array.from(document.querySelectorAll(".k-animation-container .k-popup .k-column-menu .k-columnmenu-item-wrapper .k-columnmenu-item")),t=document.querySelector(".k-filter-menu-container");if(t){if(e.code==="Tab"){const n=[".k-filter-menu-container .k-dropdownlist[tabindex='0']",".k-filter-menu-container input.k-input-inner:not([tabindex='-1']):not([disabled])",".k-filter-menu-container button:not([tabindex='-1']):not([disabled])"],r=Array.from(t.querySelectorAll(n.join(",")));if(r.length===0)return;const a=r.findIndex(c=>c===document.activeElement);let i;a===-1?i=0:e.shiftKey?i=(a-1+r.length)%r.length:i=(a+1)%r.length,e.preventDefault(),e.stopPropagation(),r[i]?.focus();return}}else if(e.code==="ArrowUp"||e.code==="ArrowDown"){e.preventDefault(),e.stopPropagation();const n=o.findIndex(a=>a===document.activeElement);let r=n;e.code==="ArrowUp"?r=n>0?n-1:o.length-1:e.code==="ArrowDown"&&(r=n<o.length-1?n+1:0),o[r]?.focus();return}e.code==="Tab"&&(e.preventDefault(),e.stopPropagation(),e.shiftKey?(l.value?.previousElementSibling).focus():(l.value?.nextElementSibling).focus())},L=()=>{m=new MutationObserver(e=>{e.forEach(o=>{o.addedNodes.forEach(t=>{if(t.nodeType===Node.ELEMENT_NODE){const n=t;if(n.classList.contains("k-animation-container")){const a=l.value;a&&(a.dataset.featherKSortable==="true"||s.nextTick(()=>{n.querySelectorAll(".k-columnmenu-item-wrapper").forEach(k=>{k.textContent?.toLowerCase().includes("sort")&&k.remove()})})),n.addEventListener("keydown",y),s.nextTick(()=>{const i=()=>{const c=Array.from(n.querySelectorAll(".k-animation-container .k-popup .k-column-menu .k-columnmenu-item-wrapper .k-columnmenu-item"));if(c.length===1)c[0].focus(),c[0].click(),i.attempts=0;else if(c.length>1){i.attempts=0;return}else i.attempts===void 0&&(i.attempts=0),i.attempts++<3&&setTimeout(i,200)};i()})}n.querySelectorAll(".k-animation-container").forEach(a=>{a.addEventListener("keydown",y)})}}),o.removedNodes.forEach(t=>{if(t.nodeType===Node.ELEMENT_NODE){const n=t;n.classList.contains("k-animation-container")&&n.removeEventListener("keydown",y),n.querySelectorAll(".k-animation-container").forEach(a=>{a.removeEventListener("keydown",y)})}})})}),m.observe(document.body,{childList:!0,subtree:!0})},T=e=>{if(!e.type||!e)return;console.log("handleGridKeyDown",e,e.code);const o=e.target;if(o&&["ArrowDown","ArrowLeft","ArrowRight","ArrowUp","Enter","Space"].includes(e.code)){if(e.preventDefault(),o.classList.contains("k-grid-header-menu")&&o.classList.contains("k-grid-column-menu")){l.value=o;return}const t=o.closest(".k-table-row[data-grid-row-index]");if(t){if(["ArrowDown","ArrowUp"].includes(e.code)){let n=null;e.code==="ArrowDown"?n=t.nextElementSibling:e.code==="ArrowUp"&&(n=t.previousElementSibling),n&&n.hasAttribute("tabindex")&&(t.setAttribute("tabindex","-1"),n.setAttribute("tabindex","0"),n.focus());return}if(["ArrowLeft","ArrowRight"].includes(e.code)){e.preventDefault();const n=t.querySelectorAll(h);if(n.length===0)return;let r=Array.from(n).findIndex(a=>a===document.activeElement);if(r===-1&&document.activeElement===t){n[0].focus();return}e.code==="ArrowRight"?r=r===n.length-1?0:r+1:e.code==="ArrowLeft"&&(r=r===n.length-1?r-1:n.length-1),n[r].focus();return}}}},D=()=>{s.nextTick(()=>{const e=p.value.$el.closest(".k-grid");e&&e.classList.add("fk-grid")})},q=()=>{try{const e=()=>{try{const n=Array.from(p.value.$el.querySelectorAll(".k-table-row[data-grid-row-index]"));if(!n||n.length===0||n.filter(i=>i.getAttribute("tabindex")==="0").length===1)return;const a=n.find(i=>i===document.activeElement||i.contains(document.activeElement));if(n.forEach(i=>i.setAttribute("tabindex","-1")),a){a.setAttribute("tabindex","0");return}n[0].setAttribute("tabindex","0")}catch(n){console.error("ensureSingleTabindex error:",n)}},o=Array.from(p.value.$el.querySelectorAll(".k-table-row[data-grid-row-index]"));o.length>0&&o.forEach((n,r)=>{n.setAttribute("tabindex",r===0?"0":"-1")});const t=p.value.$el.querySelector(".k-table-tbody");t&&(d=new MutationObserver(()=>{e()}),d.observe(t,{childList:!0,subtree:!0}))}catch(e){console.error("Error setting up row navigation:",e)}},C=()=>{s.nextTick(()=>{const o=document.querySelectorAll(".k-grid-header .k-grid-header-menu.k-grid-column-menu");o&&o.forEach(t=>{t.setAttribute("role","button"),t.addEventListener("keydown",v)}),L(),K()})},I=()=>{const o=document.querySelectorAll(".k-grid-header .k-grid-header-menu.k-grid-column-menu");o&&o.forEach(t=>{t.removeEventListener("keydown",v)}),m&&(m.disconnect(),m=null),d&&(d.disconnect(),d=null),b.forEach(t=>t()),b.length=0},K=()=>{document.querySelectorAll(".k-grid-header .k-table-thead th").forEach((t,n)=>{const r=t.querySelector(".k-grid-header-menu.k-grid-column-menu");if(!r)return;const a=g();if(a&&a[n]){const u=a[n].field??"";t.setAttribute("data-feather-k-field",u),t.setAttribute("data-feather-k-filterable",a[n].filterable===!1?"false":"true"),t.setAttribute("data-feather-k-sortable",a[n].sortable===!1?"false":"true")}const i=t.dataset.featherKFilterable!=="false",c=t.dataset.featherKSortable!=="false";r.setAttribute("tabindex","-1"),i?(t.setAttribute("tabindex","0"),t.setAttribute("role","button"),t.setAttribute("aria-haspopup","menu"),t.style.cursor="pointer"):(t.setAttribute("tabindex","0"),t.setAttribute("role","columnheader"),t.removeAttribute("aria-haspopup"),t.style.cursor="default");const k=u=>{u.target?.closest(".k-column-resizer")||(l.value=t,r.click())},A=u=>{if(i)l.value=t,u.preventDefault(),u.stopPropagation(),k(u);else if(c){l.value=t;const w=new KeyboardEvent("keydown",{key:"Enter",code:"Enter",keyCode:13,which:13,bubbles:!0,cancelable:!0});t.dispatchEvent(w)}};t.addEventListener("click",A),b.push(()=>{t.removeEventListener("click",A)});const E=u=>{if((u.code==="Enter"||u.code==="Space")&&(i||c)){if(l.value=t,l.value.focus(),i)u.preventDefault(),u.stopPropagation(),k(u);else if(c){const w=t.querySelector(".k-link");w&&w.click()}}};t.addEventListener("keydown",E,!0),b.push(()=>{t.removeEventListener("keydown",E,!0)})});const o=document.querySelector(".k-grid-header .k-table-thead");if(o){const t=n=>{const r=n.target.closest("th");r&&(n.code==="Enter"||n.code==="Space")&&r.dataset.featherKFilterable==="false"&&r.dataset.featherKSortable==="false"&&(n.preventDefault(),n.stopImmediatePropagation())};o.addEventListener("keydown",t,!0),b.push(()=>{o.removeEventListener("keydown",t,!0)})}},M=function(e,o){const t=e?.event.event.target,n=g();if(!t||!n)return;const r=t.classList.contains("k-link"),a=t.classList.contains("k-columnmenu-item"),i=n.find(c=>c.field===e.event.field)?.sortable&&!0;if(!r){if(a&&!i){(e.event.sort&&void 0)?.filter(k=>k.field!==e.event.field);return}typeof o=="function"&&s.nextTick(()=>{l.value&&l.value.focus(),o(e)})}};return s.onMounted(()=>{D(),q(),C()}),s.onBeforeUnmount(()=>{I()}),{activeFilterButton:l,handleGridKeyDown:T,handleSortChange:M}};function x(p={}){const{activeByDefault:l=!1,autoActivateDelay:m=0}=p,d=s.ref(l);function b(){d.value=!0}function h(){d.value=!1}function g(){d.value=!d.value}return s.onMounted(()=>{m>0&&!l&&setTimeout(()=>{b()},m)}),s.onUnmounted(()=>{}),{isGridActive:d,activateGrid:b,deactivateGrid:h,toggleGrid:g}}f.useGridA11y=S,f.useGridComposableEx=x,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})}));
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Kendo UI type definitions for FeatherK composables
|
|
3
|
+
* These types are extracted from @progress/kendo-* packages for development use only
|
|
4
|
+
*/
|
|
5
|
+
export interface SortDescriptor {
|
|
6
|
+
field?: string;
|
|
7
|
+
dir?: 'asc' | 'desc';
|
|
8
|
+
}
|
|
9
|
+
export interface GridColumnProps {
|
|
10
|
+
field?: string;
|
|
11
|
+
title?: string;
|
|
12
|
+
sortable?: boolean;
|
|
13
|
+
filterable?: boolean;
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
}
|
|
16
|
+
export interface GridSortChangeEvent {
|
|
17
|
+
event?: {
|
|
18
|
+
event: Event;
|
|
19
|
+
field: string;
|
|
20
|
+
sort: SortDescriptor[];
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useGridA11y
|
|
3
|
+
*
|
|
4
|
+
* Composable that augments a Kendo-based grid with accessible keyboard navigation,
|
|
5
|
+
* focus management, and custom behaviors for column header menus (filter/sort).
|
|
6
|
+
*
|
|
7
|
+
* (Contents preserved from previous grid-keyboard-navigation.ts; only the export name
|
|
8
|
+
* and filename were changed to reflect the new composable name.)
|
|
9
|
+
*/
|
|
10
|
+
import { type Ref } from "vue";
|
|
11
|
+
import type { GridSortChangeEvent } from "./types/kendo";
|
|
12
|
+
export declare const useGridA11y: (gridRef: Ref<any>) => {
|
|
13
|
+
activeFilterButton: Ref<HTMLElement, HTMLElement>;
|
|
14
|
+
handleGridKeyDown: (e: KeyboardEvent) => void;
|
|
15
|
+
handleSortChange: (event?: GridSortChangeEvent, customHandler?: any) => void;
|
|
16
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface GridAccessibilityOptions {
|
|
2
|
+
activeByDefault?: boolean;
|
|
3
|
+
autoActivateDelay?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare function useGridComposableEx(options?: GridAccessibilityOptions): {
|
|
6
|
+
isGridActive: import("vue").Ref<boolean, boolean>;
|
|
7
|
+
activateGrid: () => void;
|
|
8
|
+
deactivateGrid: () => void;
|
|
9
|
+
toggleGrid: () => void;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@featherk/composables",
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"main": "dist/featherk-composables.umd.js",
|
|
5
|
+
"module": "dist/featherk-composables.es.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "vite build && npm run build:types",
|
|
12
|
+
"build:types": "vue-tsc --emitDeclarationOnly --declaration --declarationDir dist",
|
|
13
|
+
"test": "vitest",
|
|
14
|
+
"lint": "eslint src --ext .ts,.vue",
|
|
15
|
+
"clean": "rm -rf dist",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"vue": ">=3.0.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^24.5.2",
|
|
23
|
+
"@vitejs/plugin-vue": "^6.0.1",
|
|
24
|
+
"eslint": "^8.0.0",
|
|
25
|
+
"typescript": "~5.8.3",
|
|
26
|
+
"vite": "^7.1.7",
|
|
27
|
+
"vitest": "^3.2.4",
|
|
28
|
+
"vue-tsc": "^3.0.7"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT"
|
|
34
|
+
}
|