@extrachill/components 0.2.0 → 1.0.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 CHANGED
@@ -2,45 +2,36 @@
2
2
 
3
3
  Shared React components for the Extra Chill Platform ecosystem.
4
4
 
5
- ## Overview
5
+ ## Install
6
6
 
7
- This package provides reusable UI components used across multiple Extra Chill WordPress plugins, ensuring consistent design and reducing code duplication.
7
+ ```bash
8
+ npm install @extrachill/components
9
+ ```
8
10
 
9
11
  ## Components
10
12
 
11
- - **DataTable** - Sortable data table with configurable columns
12
- - **Pagination** - Page navigation with configurable items per page
13
- - **SearchBox** - Debounced search input
14
- - **Modal** - Accessible modal dialog
15
- - **Tabs** - Controlled tab navigation for React apps and blocks
16
-
17
- ## Installation
18
-
19
- From a plugin within the Extra Chill Platform:
20
-
21
- ```json
22
- {
23
- "dependencies": {
24
- "@extrachill/components": "file:../../extrachill-components"
25
- }
26
- }
27
- ```
13
+ | Component | Description |
14
+ |-----------|-------------|
15
+ | **DataTable** | Admin table with optional row selection, loading states |
16
+ | **Pagination** | Previous/Next page navigation |
17
+ | **SearchBox** | Search input with clear button |
18
+ | **Modal** | Accessible modal dialog wrapping `@wordpress/components` |
28
19
 
29
20
  ## Usage
30
21
 
31
- ```jsx
32
- import { DataTable, Pagination, SearchBox, Modal, Tabs } from '@extrachill/components';
22
+ ```tsx
23
+ import { DataTable, Pagination, SearchBox, Modal } from '@extrachill/components';
33
24
  import '@extrachill/components/styles/components.scss';
34
25
 
35
- function MyComponent() {
26
+ function UsersTable() {
36
27
  return (
37
28
  <DataTable
38
29
  columns={[
39
- { key: 'name', label: 'Name', sortable: true },
40
- { key: 'email', label: 'Email' }
30
+ { key: 'name', label: 'Name' },
31
+ { key: 'email', label: 'Email' },
41
32
  ]}
42
33
  data={users}
43
- onSort={handleSort}
34
+ isLoading={isLoading}
44
35
  />
45
36
  );
46
37
  }
@@ -48,17 +39,12 @@ function MyComponent() {
48
39
 
49
40
  ## Peer Dependencies
50
41
 
51
- This package requires the following peer dependencies (provided by `@wordpress/scripts`):
52
-
53
- - `@wordpress/components` ^28.0.0
54
- - `@wordpress/element` ^6.0.0
55
- - `react` ^18.0.0
42
+ Requires `@wordpress/components`, `@wordpress/element`, and `react` all provided by `@wordpress/scripts` in WordPress plugin builds.
56
43
 
57
44
  ## Used By
58
45
 
59
- - `extrachill-admin-tools` - Network administration tools
60
- - `extrachill-analytics` - Analytics dashboard
61
- - `extrachill-studio` - Team collaboration workspace
46
+ - `extrachill-admin-tools` Network admin tools
47
+ - `extrachill-seo` SEO audit dashboard
62
48
 
63
49
  ## License
64
50
 
@@ -0,0 +1,91 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ /**
4
+ * DataTable Component
5
+ *
6
+ * Reusable table for admin interfaces with optional row selection.
7
+ */
8
+ interface DataTableColumn<T = Record<string, unknown>> {
9
+ /** Unique key matching a field in the data row. */
10
+ key: string;
11
+ /** Display label for the column header. */
12
+ label: string;
13
+ /** Fixed column width (CSS value). */
14
+ width?: string;
15
+ /** Custom render function for the cell. */
16
+ render?: (value: unknown, row: T) => React.ReactNode;
17
+ }
18
+ interface DataTableProps<T = Record<string, unknown>> {
19
+ /** Column definitions. */
20
+ columns: DataTableColumn<T>[];
21
+ /** Row data. */
22
+ data: T[];
23
+ /** Show a loading spinner instead of the table. */
24
+ isLoading?: boolean;
25
+ /** Enable row selection checkboxes. */
26
+ selectable?: boolean;
27
+ /** Currently selected row IDs. */
28
+ selectedIds?: Array<string | number>;
29
+ /** Callback when selection changes. */
30
+ onSelectChange?: (ids: Array<string | number>) => void;
31
+ /** Message shown when data is empty. */
32
+ emptyMessage?: string;
33
+ /** Key used to identify each row. */
34
+ rowKey?: string;
35
+ }
36
+ declare function DataTable<T extends Record<string, unknown>>({ columns, data, isLoading, selectable, selectedIds, onSelectChange, emptyMessage, rowKey, }: DataTableProps<T>): react_jsx_runtime.JSX.Element;
37
+
38
+ /**
39
+ * Pagination Component
40
+ *
41
+ * Page navigation for admin interfaces.
42
+ */
43
+ interface PaginationProps {
44
+ /** Current page number (1-indexed). */
45
+ currentPage: number;
46
+ /** Total number of pages. */
47
+ totalPages: number;
48
+ /** Total number of items across all pages. */
49
+ totalItems: number;
50
+ /** Callback when page changes. */
51
+ onPageChange: (page: number) => void;
52
+ }
53
+ declare function Pagination({ currentPage, totalPages, totalItems, onPageChange, }: PaginationProps): react_jsx_runtime.JSX.Element | null;
54
+
55
+ /**
56
+ * SearchBox Component
57
+ *
58
+ * Search input with clear button for admin interfaces.
59
+ */
60
+ interface SearchBoxProps {
61
+ /** Current search value. */
62
+ value?: string;
63
+ /** Callback when search is submitted. */
64
+ onSearch: (value: string) => void;
65
+ /** Placeholder text for the input. */
66
+ placeholder?: string;
67
+ /** Callback when search is cleared. Falls back to onSearch('') if not provided. */
68
+ onClear?: () => void;
69
+ }
70
+ declare function SearchBox({ value, onSearch, placeholder, onClear, }: SearchBoxProps): react_jsx_runtime.JSX.Element;
71
+
72
+ /**
73
+ * Modal Component
74
+ *
75
+ * Accessible modal dialog wrapping @wordpress/components Modal.
76
+ */
77
+ interface ModalProps {
78
+ /** Modal title displayed in the header. */
79
+ title: string;
80
+ /** Whether the modal is currently visible. */
81
+ isOpen: boolean;
82
+ /** Callback when the modal is closed. */
83
+ onClose: () => void;
84
+ /** Modal content. */
85
+ children: React.ReactNode;
86
+ /** Additional CSS class name. */
87
+ className?: string;
88
+ }
89
+ declare function Modal({ title, isOpen, onClose, children, className, }: ModalProps): react_jsx_runtime.JSX.Element | null;
90
+
91
+ export { DataTable, type DataTableColumn, type DataTableProps, Modal, type ModalProps, Pagination, type PaginationProps, SearchBox, type SearchBoxProps };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,91 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
1
3
  /**
2
- * @extrachill/components
4
+ * DataTable Component
3
5
  *
4
- * Shared React components for the Extra Chill Platform.
6
+ * Reusable table for admin interfaces with optional row selection.
5
7
  */
6
- export { DataTable, type DataTableProps, type DataTableColumn } from './DataTable.tsx';
7
- export { Pagination, type PaginationProps } from './Pagination.tsx';
8
- export { SearchBox, type SearchBoxProps } from './SearchBox.tsx';
9
- export { Modal, type ModalProps } from './Modal.tsx';
10
- export { Tabs, type TabsProps, type TabItem } from './Tabs.tsx';
11
- //# sourceMappingURL=index.d.ts.map
8
+ interface DataTableColumn<T = Record<string, unknown>> {
9
+ /** Unique key matching a field in the data row. */
10
+ key: string;
11
+ /** Display label for the column header. */
12
+ label: string;
13
+ /** Fixed column width (CSS value). */
14
+ width?: string;
15
+ /** Custom render function for the cell. */
16
+ render?: (value: unknown, row: T) => React.ReactNode;
17
+ }
18
+ interface DataTableProps<T = Record<string, unknown>> {
19
+ /** Column definitions. */
20
+ columns: DataTableColumn<T>[];
21
+ /** Row data. */
22
+ data: T[];
23
+ /** Show a loading spinner instead of the table. */
24
+ isLoading?: boolean;
25
+ /** Enable row selection checkboxes. */
26
+ selectable?: boolean;
27
+ /** Currently selected row IDs. */
28
+ selectedIds?: Array<string | number>;
29
+ /** Callback when selection changes. */
30
+ onSelectChange?: (ids: Array<string | number>) => void;
31
+ /** Message shown when data is empty. */
32
+ emptyMessage?: string;
33
+ /** Key used to identify each row. */
34
+ rowKey?: string;
35
+ }
36
+ declare function DataTable<T extends Record<string, unknown>>({ columns, data, isLoading, selectable, selectedIds, onSelectChange, emptyMessage, rowKey, }: DataTableProps<T>): react_jsx_runtime.JSX.Element;
37
+
38
+ /**
39
+ * Pagination Component
40
+ *
41
+ * Page navigation for admin interfaces.
42
+ */
43
+ interface PaginationProps {
44
+ /** Current page number (1-indexed). */
45
+ currentPage: number;
46
+ /** Total number of pages. */
47
+ totalPages: number;
48
+ /** Total number of items across all pages. */
49
+ totalItems: number;
50
+ /** Callback when page changes. */
51
+ onPageChange: (page: number) => void;
52
+ }
53
+ declare function Pagination({ currentPage, totalPages, totalItems, onPageChange, }: PaginationProps): react_jsx_runtime.JSX.Element | null;
54
+
55
+ /**
56
+ * SearchBox Component
57
+ *
58
+ * Search input with clear button for admin interfaces.
59
+ */
60
+ interface SearchBoxProps {
61
+ /** Current search value. */
62
+ value?: string;
63
+ /** Callback when search is submitted. */
64
+ onSearch: (value: string) => void;
65
+ /** Placeholder text for the input. */
66
+ placeholder?: string;
67
+ /** Callback when search is cleared. Falls back to onSearch('') if not provided. */
68
+ onClear?: () => void;
69
+ }
70
+ declare function SearchBox({ value, onSearch, placeholder, onClear, }: SearchBoxProps): react_jsx_runtime.JSX.Element;
71
+
72
+ /**
73
+ * Modal Component
74
+ *
75
+ * Accessible modal dialog wrapping @wordpress/components Modal.
76
+ */
77
+ interface ModalProps {
78
+ /** Modal title displayed in the header. */
79
+ title: string;
80
+ /** Whether the modal is currently visible. */
81
+ isOpen: boolean;
82
+ /** Callback when the modal is closed. */
83
+ onClose: () => void;
84
+ /** Modal content. */
85
+ children: React.ReactNode;
86
+ /** Additional CSS class name. */
87
+ className?: string;
88
+ }
89
+ declare function Modal({ title, isOpen, onClose, children, className, }: ModalProps): react_jsx_runtime.JSX.Element | null;
90
+
91
+ export { DataTable, type DataTableColumn, type DataTableProps, Modal, type ModalProps, Pagination, type PaginationProps, SearchBox, type SearchBoxProps };
package/dist/index.js CHANGED
@@ -1,10 +1,213 @@
1
- /**
2
- * @extrachill/components
3
- *
4
- * Shared React components for the Extra Chill Platform.
5
- */
6
- export { DataTable } from "./DataTable.js";
7
- export { Pagination } from "./Pagination.js";
8
- export { SearchBox } from "./SearchBox.js";
9
- export { Modal } from "./Modal.js";
10
- export { Tabs } from "./Tabs.js";
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DataTable: () => DataTable,
24
+ Modal: () => Modal,
25
+ Pagination: () => Pagination,
26
+ SearchBox: () => SearchBox
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+
30
+ // src/components/DataTable.tsx
31
+ var import_components = require("@wordpress/components");
32
+ var import_jsx_runtime = require("react/jsx-runtime");
33
+ function DataTable({
34
+ columns,
35
+ data,
36
+ isLoading = false,
37
+ selectable = false,
38
+ selectedIds = [],
39
+ onSelectChange = () => {
40
+ },
41
+ emptyMessage = "No data found.",
42
+ rowKey = "id"
43
+ }) {
44
+ const allSelected = data.length > 0 && selectedIds.length === data.length;
45
+ const someSelected = selectedIds.length > 0 && selectedIds.length < data.length;
46
+ const handleSelectAll = (checked) => {
47
+ if (checked) {
48
+ onSelectChange(data.map((row) => row[rowKey]));
49
+ } else {
50
+ onSelectChange([]);
51
+ }
52
+ };
53
+ const handleSelectRow = (id, checked) => {
54
+ if (checked) {
55
+ onSelectChange([...selectedIds, id]);
56
+ } else {
57
+ onSelectChange(selectedIds.filter((sid) => sid !== id));
58
+ }
59
+ };
60
+ if (isLoading) {
61
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ec-data-table__loading", children: [
62
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Spinner, {}),
63
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Loading..." })
64
+ ] });
65
+ }
66
+ if (data.length === 0) {
67
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ec-data-table__empty", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: emptyMessage }) });
68
+ }
69
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: "ec-data-table wp-list-table widefat fixed striped", children: [
70
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
71
+ selectable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: "ec-data-table__check-column", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
72
+ import_components.CheckboxControl,
73
+ {
74
+ checked: allSelected,
75
+ indeterminate: someSelected,
76
+ onChange: handleSelectAll,
77
+ __nextHasNoMarginBottom: true
78
+ }
79
+ ) }),
80
+ columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: col.width ? { width: col.width } : {}, children: col.label }, col.key))
81
+ ] }) }),
82
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: data.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
83
+ selectable && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "ec-data-table__check-column", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
84
+ import_components.CheckboxControl,
85
+ {
86
+ checked: selectedIds.includes(row[rowKey]),
87
+ onChange: (checked) => handleSelectRow(row[rowKey], checked),
88
+ __nextHasNoMarginBottom: true
89
+ }
90
+ ) }),
91
+ columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: col.render ? col.render(row[col.key], row) : String(row[col.key] ?? "") }, col.key))
92
+ ] }, String(row[rowKey]))) })
93
+ ] });
94
+ }
95
+
96
+ // src/components/Pagination.tsx
97
+ var import_components2 = require("@wordpress/components");
98
+ var import_jsx_runtime2 = require("react/jsx-runtime");
99
+ function Pagination({
100
+ currentPage,
101
+ totalPages,
102
+ totalItems,
103
+ onPageChange
104
+ }) {
105
+ if (totalPages <= 1) {
106
+ return null;
107
+ }
108
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ec-pagination", children: [
109
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "ec-pagination__info", children: [
110
+ "Page ",
111
+ currentPage,
112
+ " of ",
113
+ totalPages,
114
+ " (",
115
+ totalItems,
116
+ " items)"
117
+ ] }),
118
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ec-pagination__buttons", children: [
119
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
120
+ import_components2.Button,
121
+ {
122
+ variant: "secondary",
123
+ disabled: currentPage <= 1,
124
+ onClick: () => onPageChange(currentPage - 1),
125
+ children: "Previous"
126
+ }
127
+ ),
128
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
129
+ import_components2.Button,
130
+ {
131
+ variant: "secondary",
132
+ disabled: currentPage >= totalPages,
133
+ onClick: () => onPageChange(currentPage + 1),
134
+ children: "Next"
135
+ }
136
+ )
137
+ ] })
138
+ ] });
139
+ }
140
+
141
+ // src/components/SearchBox.tsx
142
+ var import_element = require("@wordpress/element");
143
+ var import_components3 = require("@wordpress/components");
144
+ var import_jsx_runtime3 = require("react/jsx-runtime");
145
+ function SearchBox({
146
+ value = "",
147
+ onSearch,
148
+ placeholder = "Search...",
149
+ onClear
150
+ }) {
151
+ const [inputValue, setInputValue] = (0, import_element.useState)(value);
152
+ const handleSearch = () => {
153
+ onSearch(inputValue);
154
+ };
155
+ const handleClear = () => {
156
+ setInputValue("");
157
+ if (onClear) {
158
+ onClear();
159
+ } else {
160
+ onSearch("");
161
+ }
162
+ };
163
+ const handleKeyDown = (e) => {
164
+ if (e.key === "Enter") {
165
+ handleSearch();
166
+ }
167
+ };
168
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "ec-search-box", children: [
169
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
170
+ import_components3.TextControl,
171
+ {
172
+ value: inputValue,
173
+ onChange: setInputValue,
174
+ placeholder,
175
+ onKeyDown: handleKeyDown,
176
+ __nextHasNoMarginBottom: true
177
+ }
178
+ ),
179
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_components3.Button, { variant: "secondary", onClick: handleSearch, children: "Search" }),
180
+ inputValue && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_components3.Button, { variant: "tertiary", onClick: handleClear, children: "Clear" })
181
+ ] });
182
+ }
183
+
184
+ // src/components/Modal.tsx
185
+ var import_components4 = require("@wordpress/components");
186
+ var import_jsx_runtime4 = require("react/jsx-runtime");
187
+ function Modal({
188
+ title,
189
+ isOpen,
190
+ onClose,
191
+ children,
192
+ className = ""
193
+ }) {
194
+ if (!isOpen) {
195
+ return null;
196
+ }
197
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
198
+ import_components4.Modal,
199
+ {
200
+ title,
201
+ onRequestClose: onClose,
202
+ className: `ec-modal ${className}`.trim(),
203
+ children
204
+ }
205
+ );
206
+ }
207
+ // Annotate the CommonJS export names for ESM import in node:
208
+ 0 && (module.exports = {
209
+ DataTable,
210
+ Modal,
211
+ Pagination,
212
+ SearchBox
213
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,183 @@
1
+ // src/components/DataTable.tsx
2
+ import { CheckboxControl, Spinner } from "@wordpress/components";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ function DataTable({
5
+ columns,
6
+ data,
7
+ isLoading = false,
8
+ selectable = false,
9
+ selectedIds = [],
10
+ onSelectChange = () => {
11
+ },
12
+ emptyMessage = "No data found.",
13
+ rowKey = "id"
14
+ }) {
15
+ const allSelected = data.length > 0 && selectedIds.length === data.length;
16
+ const someSelected = selectedIds.length > 0 && selectedIds.length < data.length;
17
+ const handleSelectAll = (checked) => {
18
+ if (checked) {
19
+ onSelectChange(data.map((row) => row[rowKey]));
20
+ } else {
21
+ onSelectChange([]);
22
+ }
23
+ };
24
+ const handleSelectRow = (id, checked) => {
25
+ if (checked) {
26
+ onSelectChange([...selectedIds, id]);
27
+ } else {
28
+ onSelectChange(selectedIds.filter((sid) => sid !== id));
29
+ }
30
+ };
31
+ if (isLoading) {
32
+ return /* @__PURE__ */ jsxs("div", { className: "ec-data-table__loading", children: [
33
+ /* @__PURE__ */ jsx(Spinner, {}),
34
+ /* @__PURE__ */ jsx("span", { children: "Loading..." })
35
+ ] });
36
+ }
37
+ if (data.length === 0) {
38
+ return /* @__PURE__ */ jsx("div", { className: "ec-data-table__empty", children: /* @__PURE__ */ jsx("p", { children: emptyMessage }) });
39
+ }
40
+ return /* @__PURE__ */ jsxs("table", { className: "ec-data-table wp-list-table widefat fixed striped", children: [
41
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
42
+ selectable && /* @__PURE__ */ jsx("th", { className: "ec-data-table__check-column", children: /* @__PURE__ */ jsx(
43
+ CheckboxControl,
44
+ {
45
+ checked: allSelected,
46
+ indeterminate: someSelected,
47
+ onChange: handleSelectAll,
48
+ __nextHasNoMarginBottom: true
49
+ }
50
+ ) }),
51
+ columns.map((col) => /* @__PURE__ */ jsx("th", { style: col.width ? { width: col.width } : {}, children: col.label }, col.key))
52
+ ] }) }),
53
+ /* @__PURE__ */ jsx("tbody", { children: data.map((row) => /* @__PURE__ */ jsxs("tr", { children: [
54
+ selectable && /* @__PURE__ */ jsx("td", { className: "ec-data-table__check-column", children: /* @__PURE__ */ jsx(
55
+ CheckboxControl,
56
+ {
57
+ checked: selectedIds.includes(row[rowKey]),
58
+ onChange: (checked) => handleSelectRow(row[rowKey], checked),
59
+ __nextHasNoMarginBottom: true
60
+ }
61
+ ) }),
62
+ columns.map((col) => /* @__PURE__ */ jsx("td", { children: col.render ? col.render(row[col.key], row) : String(row[col.key] ?? "") }, col.key))
63
+ ] }, String(row[rowKey]))) })
64
+ ] });
65
+ }
66
+
67
+ // src/components/Pagination.tsx
68
+ import { Button } from "@wordpress/components";
69
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
70
+ function Pagination({
71
+ currentPage,
72
+ totalPages,
73
+ totalItems,
74
+ onPageChange
75
+ }) {
76
+ if (totalPages <= 1) {
77
+ return null;
78
+ }
79
+ return /* @__PURE__ */ jsxs2("div", { className: "ec-pagination", children: [
80
+ /* @__PURE__ */ jsxs2("span", { className: "ec-pagination__info", children: [
81
+ "Page ",
82
+ currentPage,
83
+ " of ",
84
+ totalPages,
85
+ " (",
86
+ totalItems,
87
+ " items)"
88
+ ] }),
89
+ /* @__PURE__ */ jsxs2("div", { className: "ec-pagination__buttons", children: [
90
+ /* @__PURE__ */ jsx2(
91
+ Button,
92
+ {
93
+ variant: "secondary",
94
+ disabled: currentPage <= 1,
95
+ onClick: () => onPageChange(currentPage - 1),
96
+ children: "Previous"
97
+ }
98
+ ),
99
+ /* @__PURE__ */ jsx2(
100
+ Button,
101
+ {
102
+ variant: "secondary",
103
+ disabled: currentPage >= totalPages,
104
+ onClick: () => onPageChange(currentPage + 1),
105
+ children: "Next"
106
+ }
107
+ )
108
+ ] })
109
+ ] });
110
+ }
111
+
112
+ // src/components/SearchBox.tsx
113
+ import { useState } from "@wordpress/element";
114
+ import { TextControl, Button as Button2 } from "@wordpress/components";
115
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
116
+ function SearchBox({
117
+ value = "",
118
+ onSearch,
119
+ placeholder = "Search...",
120
+ onClear
121
+ }) {
122
+ const [inputValue, setInputValue] = useState(value);
123
+ const handleSearch = () => {
124
+ onSearch(inputValue);
125
+ };
126
+ const handleClear = () => {
127
+ setInputValue("");
128
+ if (onClear) {
129
+ onClear();
130
+ } else {
131
+ onSearch("");
132
+ }
133
+ };
134
+ const handleKeyDown = (e) => {
135
+ if (e.key === "Enter") {
136
+ handleSearch();
137
+ }
138
+ };
139
+ return /* @__PURE__ */ jsxs3("div", { className: "ec-search-box", children: [
140
+ /* @__PURE__ */ jsx3(
141
+ TextControl,
142
+ {
143
+ value: inputValue,
144
+ onChange: setInputValue,
145
+ placeholder,
146
+ onKeyDown: handleKeyDown,
147
+ __nextHasNoMarginBottom: true
148
+ }
149
+ ),
150
+ /* @__PURE__ */ jsx3(Button2, { variant: "secondary", onClick: handleSearch, children: "Search" }),
151
+ inputValue && /* @__PURE__ */ jsx3(Button2, { variant: "tertiary", onClick: handleClear, children: "Clear" })
152
+ ] });
153
+ }
154
+
155
+ // src/components/Modal.tsx
156
+ import { Modal as WPModal } from "@wordpress/components";
157
+ import { jsx as jsx4 } from "react/jsx-runtime";
158
+ function Modal({
159
+ title,
160
+ isOpen,
161
+ onClose,
162
+ children,
163
+ className = ""
164
+ }) {
165
+ if (!isOpen) {
166
+ return null;
167
+ }
168
+ return /* @__PURE__ */ jsx4(
169
+ WPModal,
170
+ {
171
+ title,
172
+ onRequestClose: onClose,
173
+ className: `ec-modal ${className}`.trim(),
174
+ children
175
+ }
176
+ );
177
+ }
178
+ export {
179
+ DataTable,
180
+ Modal,
181
+ Pagination,
182
+ SearchBox
183
+ };