@featherk/composables 0.10.6 → 0.10.8

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.
@@ -1,2 +1,4 @@
1
1
  export { useGridA11y } from "./useGridA11y";
2
2
  export { useGridActiveFilter } from "./useGridActiveFilter";
3
+ export { useGridRowAction } from "./useGridRowAction";
4
+ export type { UseGridRowActionOptions, UseGridRowActionReturn, RowActionContext, } from "./useGridRowAction";
@@ -0,0 +1,86 @@
1
+ /**
2
+ * useGridRowAction
3
+ *
4
+ * Composable that provides safe, accessible row click and keyboard activation
5
+ * handlers for Kendo UI for Vue Grid instances.
6
+ *
7
+ * Highlights:
8
+ * - Guards against triggers when clicking interactive elements (buttons, links, inputs, checkboxes).
9
+ * - Suppresses activation when the user is highlighting/selecting text inside a cell.
10
+ * - Restricts mouse actions to primary (left) click.
11
+ * - Provides keyboard activation (Enter / Space) for focused grid rows.
12
+ * - Action-agnostic: executes consumer-supplied `onRowAction` callback with `dataItem` and context.
13
+ */
14
+ import type { Ref } from "vue";
15
+ import type { GridRowClickEvent } from "../types/kendo";
16
+ export interface RowActionContext<T = any> {
17
+ /**
18
+ * Data item associated with the activated row.
19
+ */
20
+ dataItem: T;
21
+ /**
22
+ * Row index if provided by Kendo event or row DOM attribute.
23
+ */
24
+ rowIndex?: number;
25
+ /**
26
+ * Field name if click originated on a specific column cell.
27
+ */
28
+ field?: string;
29
+ /**
30
+ * Original native browser event.
31
+ */
32
+ event: Event;
33
+ /**
34
+ * Interaction trigger type ('click' | 'keyboard').
35
+ */
36
+ triggerType: "click" | "keyboard";
37
+ /**
38
+ * Modifier key states during activation.
39
+ */
40
+ ctrlKey: boolean;
41
+ shiftKey: boolean;
42
+ metaKey: boolean;
43
+ altKey: boolean;
44
+ }
45
+ export interface UseGridRowActionOptions<T = any> {
46
+ /**
47
+ * Action callback invoked when a row is clicked or activated via keyboard.
48
+ */
49
+ onRowAction: (dataItem: T, context: RowActionContext<T>) => void;
50
+ /**
51
+ * Optional ref to Kendo Grid component instance or array/ref of data items.
52
+ * Used to resolve the row `dataItem` when row is activated via grid-level `@keydown`.
53
+ */
54
+ gridRef?: Ref<any>;
55
+ dataItems?: Ref<T[]> | T[];
56
+ /**
57
+ * Additional CSS selectors inside row cells that should prevent the row action.
58
+ */
59
+ ignoreSelectors?: string[];
60
+ /**
61
+ * Custom predicate function to check if an event target should be ignored.
62
+ * Return `true` to ignore row action, `false` to proceed.
63
+ */
64
+ shouldIgnoreTarget?: (target: HTMLElement, event: Event) => boolean;
65
+ /**
66
+ * Whether to enable Enter/Space keyboard activation on focused grid rows.
67
+ * Default: true
68
+ */
69
+ enableKeyboardAction?: boolean;
70
+ }
71
+ export interface UseGridRowActionReturn<T = any> {
72
+ /**
73
+ * Grid row click handler to bind to Kendo Grid's `@rowclick` event.
74
+ */
75
+ handleRowClick: (event: GridRowClickEvent<T>) => void;
76
+ /**
77
+ * Grid keyboard handler to bind to Kendo Grid's `@keydown` event.
78
+ * Optionally accepts explicit `dataItem` if bound at the row/slot level.
79
+ */
80
+ handleRowKeyDown: (event: KeyboardEvent, explicitDataItem?: T) => void;
81
+ /**
82
+ * Helper function to test if a given DOM element is an ignored target.
83
+ */
84
+ isIgnoredTarget: (target: HTMLElement, event?: Event) => boolean;
85
+ }
86
+ export declare const useGridRowAction: <T = any>(options: UseGridRowActionOptions<T>) => UseGridRowActionReturn<T>;
@@ -0,0 +1 @@
1
+ export {};
@@ -20,3 +20,10 @@ export interface GridSortChangeEvent {
20
20
  sort: SortDescriptor[];
21
21
  };
22
22
  }
23
+ export interface GridRowClickEvent<T = any> {
24
+ dataItem: T;
25
+ rowIndex?: number;
26
+ field?: string;
27
+ htmlEvent?: MouseEvent;
28
+ [key: string]: any;
29
+ }
@@ -0,0 +1,169 @@
1
+ # useGridRowAction
2
+
3
+ [← Back to Composables README](https://github.com/NantHealth/featherk/blob/integration/packages/composables/README.md)
4
+
5
+ Composable that provides safe, accessible row click and keyboard activation handlers for Kendo UI for Vue `Grid` components.
6
+
7
+ ## Features
8
+
9
+ - **Safe Row Clicks**: Ignores clicks originating on interactive child elements (`button`, `a`, `input`, `.k-checkbox`, kebab menus, etc.).
10
+ - **Text Selection Protection**: Automatically suppresses row actions when the user is highlighting/selecting text inside a cell within the row.
11
+ - **Primary Mouse Button**: Restricts click activation to primary (left) mouse clicks.
12
+ - **Keyboard Accessibility**: Supports keyboard row activation (`Enter` / `Space`) when focus is on a data row.
13
+ - **Action Decoupled**: Provides normalized row event context (`dataItem`, `rowIndex`, `field`, `triggerType`, modifier keys) while leaving action logic (dialog, route navigation, context menu) to the consumer.
14
+ - **Composable Combination**: Integrates seamlessly with `useGridA11y` for combined row navigation and row action handling.
15
+
16
+ ## Prerequisites
17
+
18
+ - Vue 3 Composition API
19
+ - `@progress/kendo-vue-grid`
20
+ - `@featherk/composables`
21
+
22
+ Install:
23
+
24
+ ```bash
25
+ npm install @featherk/composables
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ### Implementation Checklist
31
+
32
+ 1. Import `useGridRowAction` and configure `onRowAction` with your action handler.
33
+ 2. Bind `@rowclick` on the Kendo Grid to `handleRowClick`.
34
+ 3. Bind `@keydown` on the Kendo Grid to `handleRowKeyDown`.
35
+
36
+ ```vue
37
+ <template>
38
+ <!-- Step 2: Wire @rowclick to handleRowClick -->
39
+ <!-- Step 3: Wire @keydown to handleRowKeyDown -->
40
+ <Grid
41
+ :data-items="gridData"
42
+ :columns="columns"
43
+ @rowclick="handleRowClick"
44
+ @keydown="handleRowKeyDown"
45
+ />
46
+ </template>
47
+
48
+ <script setup lang="ts">
49
+ import { ref } from "vue";
50
+ import { Grid } from "@progress/kendo-vue-grid";
51
+ import { useGridRowAction, type RowActionContext } from "@featherk/composables";
52
+
53
+ interface Patient {
54
+ id: number;
55
+ name: string;
56
+ status: string;
57
+ }
58
+
59
+ const gridData = ref<Patient[]>([
60
+ { id: 1, name: "Jane Doe", status: "Active" },
61
+ { id: 2, name: "John Smith", status: "Pending" },
62
+ ]);
63
+
64
+ const columns = [
65
+ { field: "id", title: "ID", width: "80px" },
66
+ { field: "name", title: "Patient Name" },
67
+ { field: "status", title: "Status" },
68
+ ];
69
+
70
+ // Step 1: Initialize useGridRowAction with options and action handler
71
+ const { handleRowClick, handleRowKeyDown } = useGridRowAction<Patient>({
72
+ dataItems: gridData,
73
+ onRowAction: (dataItem: Patient, context: RowActionContext<Patient>) => {
74
+ console.log(`Row activated (${context.triggerType}):`, dataItem);
75
+ // Execute consumer action (e.g., open dialog, router.push, etc.)
76
+ },
77
+ });
78
+ </script>
79
+ ```
80
+
81
+ ## Integrating with `useGridA11y`
82
+
83
+ When combining `useGridA11y` (for `ArrowUp`/`ArrowDown` row focus navigation) with `useGridRowAction` (for `Enter`/`Space` row activation), delegate both handlers in a single `@keydown` listener:
84
+
85
+ ```vue
86
+ <template>
87
+ <Grid
88
+ ref="gridRef"
89
+ :data-items="patients"
90
+ :columns="columns"
91
+ @rowclick="handleRowClick"
92
+ @keydown="handleKeyDown"
93
+ />
94
+ </template>
95
+
96
+ <script setup lang="ts">
97
+ import { onMounted, ref } from "vue";
98
+ import { Grid } from "@progress/kendo-vue-grid";
99
+ import { useGridA11y, useGridRowAction } from "@featherk/composables";
100
+
101
+ const gridRef = ref(null);
102
+ const patients = ref([{ id: 1, name: "Alice Johnson" }]);
103
+
104
+ const { handleGridKeyDown, initA11y } = useGridA11y(gridRef);
105
+ const { handleRowClick, handleRowKeyDown } = useGridRowAction({
106
+ dataItems: patients,
107
+ onRowAction: (patient) => {
108
+ // Perform row action
109
+ },
110
+ });
111
+
112
+ // Delegate keydown to both composable handlers
113
+ const handleKeyDown = (event: KeyboardEvent) => {
114
+ handleGridKeyDown(event);
115
+ handleRowKeyDown(event);
116
+ };
117
+
118
+ onMounted(() => {
119
+ initA11y();
120
+ });
121
+ </script>
122
+ ```
123
+
124
+ ## Options Reference
125
+
126
+ `useGridRowAction(options: UseGridRowActionOptions<T>)` accepts the following configuration:
127
+
128
+ | Option | Type | Default | Description |
129
+ | :--- | :--- | :--- | :--- |
130
+ | `onRowAction` | `(dataItem: T, context: RowActionContext<T>) => void` | **Required** | Callback executed when a valid row click or keyboard activation occurs. |
131
+ | `dataItems` | `Ref<T[]> \| T[]` | `undefined` | Grid data array or ref used to resolve the `dataItem` on grid-level `@keydown` activation. |
132
+ | `gridRef` | `Ref<any>` | `undefined` | Optional ref to Kendo Grid instance as an alternative `dataItem` lookup source. |
133
+ | `ignoreSelectors` | `string[]` | `[]` | Additional CSS selectors inside row cells that should prevent triggering row actions. |
134
+ | `shouldIgnoreTarget` | `(target: HTMLElement, event: Event) => boolean` | `undefined` | Custom predicate function for advanced target element filtering. |
135
+ | `enableKeyboardAction` | `boolean` | `true` | Whether to enable `Enter`/`Space` key activation on focused rows. |
136
+
137
+ ## Returns Reference
138
+
139
+ `useGridRowAction` returns an object containing:
140
+
141
+ | Property | Type | Description |
142
+ | :--- | :--- | :--- |
143
+ | `handleRowClick` | `(event: GridRowClickEvent) => void` | Primary click handler to bind to Kendo Grid's `@rowclick`. |
144
+ | `handleRowKeyDown` | `(event: KeyboardEvent, explicitDataItem?: T) => void` | Primary keyboard handler to bind to Kendo Grid's `@keydown`. Accepts optional `explicitDataItem` if bound at slot/row level. |
145
+ | `isIgnoredTarget` | `(target: HTMLElement, event?: Event) => boolean` | Utility function to test if a given DOM element matches default or custom ignore selectors. |
146
+
147
+ ## Callback Context Reference
148
+
149
+ The `onRowAction` callback receives `(dataItem, context)` where `context` contains:
150
+
151
+ | Property | Type | Description |
152
+ | :--- | :--- | :--- |
153
+ | `dataItem` | `T` | The row's data item. |
154
+ | `rowIndex` | `number \| undefined` | Row index in the grid data. |
155
+ | `field` | `string \| undefined` | Column field name if clicked on a specific cell. |
156
+ | `event` | `Event` | Original native browser DOM event. |
157
+ | `triggerType` | `'click' \| 'keyboard'` | Interaction source that triggered the action (`click` or `keyboard`). |
158
+ | `ctrlKey` | `boolean` | `true` if Ctrl key was held down during activation. |
159
+ | `shiftKey` | `boolean` | `true` if Shift key was held down during activation. |
160
+ | `metaKey` | `boolean` | `true` if Cmd / Meta key was held down during activation. |
161
+ | `altKey` | `boolean` | `true` if Alt key was held down during activation. |
162
+
163
+ ## Default Ignored Selectors
164
+
165
+ The following elements and interactive controls are automatically ignored by default:
166
+
167
+ - `button`, `a`, `input`, `select`, `textarea`
168
+ - `[role="button"]`, `[role="checkbox"]`, `[role="link"]`, `[role="menuitem"]`, `[role="option"]`
169
+ - `.k-checkbox`, `.k-button`, `.k-dropdown`, `.k-picker`, `.k-hierarchy-cell`, `.k-grid-header-menu`, `.k-column-menu`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@featherk/composables",
3
- "version": "0.10.6",
3
+ "version": "0.10.8",
4
4
  "main": "dist/featherk-composables.umd.js",
5
5
  "module": "dist/featherk-composables.es.js",
6
6
  "types": "dist/index.d.ts",