@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"})}));
@@ -0,0 +1,2 @@
1
+ export { useGridA11y } from './useGridA11y';
2
+ export { useGridComposableEx } from './useGridComposableEx';
@@ -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
+ }