@serkonda7/solid-components 0.0.1 → 0.0.3

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
@@ -1,36 +1,41 @@
1
- # solid-components
1
+ # @serkonda7/solid-components
2
+ [![CI][ci-badge]][ci-status]
3
+ [![npm version][npm-badge]][npm-link]
4
+ [![npm updated][npm-date-badge]][npm-link]
2
5
 
3
6
  Reusable components for [SolidJS](https://www.solidjs.com/).
4
7
 
5
- ## Installation
6
8
 
9
+ ## 📦 Installation
7
10
  ```sh
8
- bun add solid-components solid-js
9
- # or: npm install solid-components solid-js
11
+ bun install @serkonda7/solid-components solid-js
10
12
  ```
11
13
 
12
- ## Usage
13
-
14
- Import components from the package root:
15
14
 
15
+ ## 🚀 Usage
16
16
  ```tsx
17
- import { /* Component */ } from 'solid-components';
17
+ import { DataTable } from '@serkonda7/solid-components'
18
+ import '@serkonda7/solid-components/styles.css'
19
+
20
+ <DataTable
21
+ rows={items}
22
+ getRowId={(item) => item.id}
23
+ columns={[{ key: 'name', label: 'Name' }]}
24
+ />
18
25
  ```
19
26
 
20
- The package is currently a foundation for the component library. Components
21
- will be added to `src/` and re-exported from `src/index.ts`.
27
+ These components are available:
28
+ - `DataTable` - generic table with optional sorting, row selection, actions, loading, empty states, and column customizer.
22
29
 
23
- ## Development
30
+ For the full API, examples, and agent notes, see [docs.md](docs.md).
24
31
 
25
- Install [Bun](https://bun.sh/), then run:
26
32
 
27
- ```sh
28
- bun install
29
- bun run test # type-check, build, and run tests
30
- bun run lint:ci # check formatting and lint rules
31
- bun run build # create the production package in dist/
32
- ```
33
+ ## 📜 License
34
+ This repo is licensed under the [MIT License](LICENSE.txt).
33
35
 
34
- ## License
35
36
 
36
- MIT
37
+ [ci-badge]: https://github.com/serkonda7/solid-components/actions/workflows/ci.yml/badge.svg
38
+ [ci-status]: https://github.com/serkonda7/solid-components/actions/workflows/ci.yml
39
+ [npm-badge]: https://nodei.co/npm/@serkonda7/solid-components.png?style=shields&data=v&color=blue
40
+ [npm-date-badge]: https://nodei.co/npm/@serkonda7/solid-components.png?style=shields&data=u&color=blue
41
+ [npm-link]: https://www.npmjs.com/package/@serkonda7/solid-components
@@ -0,0 +1,46 @@
1
+ import type { Accessor, JSX } from 'solid-js';
2
+ export type DataTableSortDirection = 'asc' | 'desc';
3
+ export interface DataTableColumn<TRow> {
4
+ key: string;
5
+ label: string;
6
+ sortable?: boolean;
7
+ class?: string;
8
+ ariaLabel?: string;
9
+ getValue?: (row: TRow) => JSX.Element;
10
+ /** Whether the column is visible by default when the column customizer is used. Defaults to `true`. */
11
+ defaultVisible?: boolean;
12
+ /** Whether the column can be hidden via the column customizer. Defaults to `true`. Non-toggleable columns are always shown. */
13
+ toggleable?: boolean;
14
+ }
15
+ export interface DataTableProps<TRow> {
16
+ rows: TRow[] | Accessor<TRow[]>;
17
+ columns: DataTableColumn<TRow>[];
18
+ getRowId: (row: TRow) => string | number;
19
+ getCell?: (row: TRow, column: DataTableColumn<TRow>) => JSX.Element;
20
+ rowActions?: (row: TRow) => JSX.Element;
21
+ selected?: string[] | number[] | Accessor<string[] | number[]>;
22
+ onSelectionChange?: (ids: (string | number)[]) => void;
23
+ selectionLabel?: string;
24
+ sortKey?: string | Accessor<string | undefined>;
25
+ sortDirection?: DataTableSortDirection | Accessor<DataTableSortDirection>;
26
+ onSort?: (key: string) => void;
27
+ visibleColumns?: string[] | Accessor<string[]>;
28
+ defaultVisibleColumns?: string[];
29
+ onVisibleColumnsChange?: (visibleKeys: string[]) => void;
30
+ showColumnCustomizer?: boolean | Accessor<boolean>;
31
+ columnCustomizerLabel?: string;
32
+ columnCustomizerTitle?: string;
33
+ columnCustomizerShowAllLabel?: string;
34
+ columnCustomizerResetLabel?: string;
35
+ loading?: boolean | Accessor<boolean>;
36
+ empty?: boolean | Accessor<boolean>;
37
+ loadingContent?: JSX.Element;
38
+ emptyContent?: JSX.Element;
39
+ class?: string;
40
+ }
41
+ /**
42
+ * Generic accessible data table. Data fetching, navigation, and cell content
43
+ * stay with the consuming app; this component owns table structure and the
44
+ * repeated selection/sort/loading states.
45
+ */
46
+ export declare function DataTable<TRow>(props: DataTableProps<TRow>): JSX.Element;
package/dist/index.d.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * Add components here as they are implemented so consumers can import them
5
5
  * from the package root.
6
6
  */
7
- export {};
7
+ export { DataTable, type DataTableColumn, type DataTableProps, type DataTableSortDirection, } from './data-table';
package/dist/index.js CHANGED
@@ -1,2 +1,188 @@
1
-
2
- //# debugId=1B152D275122871864756E2164756E21
1
+ import { className as e, createComponent as t, delegateEvents as n, effect as r, insert as i, memo as a, setAttribute as o, template as s, use as c } from "solid-js/web";
2
+ import { For as l, Show as u, createEffect as d, createMemo as f, createSignal as p, createUniqueId as m, onCleanup as h } from "solid-js";
3
+ //#region src/data-table.tsx
4
+ var g = /*#__PURE__*/ s("<div role=dialog class=data-table-customizer-panel><p class=data-table-customizer-title></p><ul class=data-table-customizer-list></ul><div class=data-table-customizer-actions><button type=button></button><button type=button>"), _ = /*#__PURE__*/ s("<div class=data-table-toolbar><div class=data-table-customizer><button type=button class=data-table-customizer-button aria-haspopup=dialog><span aria-hidden=true>⚙</span> "), v = /*#__PURE__*/ s("<th class=data-table-checkbox><span class=data-table-visually-hidden>Select rows</span><input type=checkbox>"), y = /*#__PURE__*/ s("<th>Actions"), b = /*#__PURE__*/ s("<div><div class=data-table-scroll><table class=data-table><thead><tr></tr></thead><tbody>"), x = /*#__PURE__*/ s("<li><label class=data-table-customizer-option><input type=checkbox>"), S = /*#__PURE__*/ s("<button type=button class=data-table-sort>"), C = /*#__PURE__*/ s("<th>"), ee = /*#__PURE__*/ s("<td class=data-table-checkbox><input type=checkbox>"), w = /*#__PURE__*/ s("<td>"), T = /*#__PURE__*/ s("<tr>"), E = /*#__PURE__*/ s("<p class=data-table-status>Loading…"), D = /*#__PURE__*/ s("<p class=data-table-status>No results.");
5
+ function O(e) {
6
+ return typeof e == "function" ? e() : e;
7
+ }
8
+ function k(n) {
9
+ let s = f(() => O(n.rows)), k = () => O(n.loading ?? !1), A = () => O(n.selected ?? []), j = () => O(n.sortKey ?? void 0), M = () => O(n.sortDirection ?? "asc"), N = () => O(n.showColumnCustomizer ?? !1), P = () => n.selected !== void 0 && n.onSelectionChange !== void 0, F = () => {
10
+ let e = A();
11
+ return s().length > 0 && s().every((t) => e.includes(n.getRowId(t)));
12
+ }, I = f(() => n.defaultVisibleColumns ?? n.columns.filter((e) => e.defaultVisible !== !1).map((e) => e.key)), [L, R] = p(void 0), z = () => n.visibleColumns === void 0 ? L() ?? I() : O(n.visibleColumns), B = f(() => new Set(z())), V = f(() => n.columns.filter((e) => e.toggleable === !1 || B().has(e.key))), H = f(() => n.columns.filter((e) => e.toggleable !== !1)), U = f(() => H().map((e) => e.key));
13
+ function W(e) {
14
+ let t = new Map(n.columns.map((e, t) => [e.key, t]));
15
+ return [...e].sort((e, n) => (t.get(e) ?? 0) - (t.get(n) ?? 0));
16
+ }
17
+ function G(e) {
18
+ let t = W(e);
19
+ n.visibleColumns === void 0 && R(t), n.onVisibleColumnsChange?.(t);
20
+ }
21
+ function K(e, t) {
22
+ let n = new Set(z());
23
+ t ? n.add(e) : n.delete(e), G(U().filter((e) => n.has(e)));
24
+ }
25
+ function q() {
26
+ G(U());
27
+ }
28
+ function J() {
29
+ G(I());
30
+ }
31
+ let Y = `${m()}-panel`, [X, Z] = p(!1), Q;
32
+ d(() => {
33
+ if (!X() || !N()) return;
34
+ function e(e) {
35
+ Q && !Q.contains(e.target) && Z(!1);
36
+ }
37
+ function t(e) {
38
+ e.key === "Escape" && Z(!1);
39
+ }
40
+ document.addEventListener("pointerdown", e), document.addEventListener("keydown", t), h(() => {
41
+ document.removeEventListener("pointerdown", e), document.removeEventListener("keydown", t);
42
+ });
43
+ });
44
+ let $;
45
+ d(() => {
46
+ $ && ($.indeterminate = A().length > 0 && !F());
47
+ });
48
+ function te(e) {
49
+ n.onSelectionChange?.(e ? s().map(n.getRowId) : []);
50
+ }
51
+ function ne(e, t) {
52
+ let r = n.getRowId(e), i = A(), a = t ? [...i, r] : i.filter((e) => e !== r);
53
+ n.onSelectionChange?.(a);
54
+ }
55
+ function re(e) {
56
+ return A().includes(n.getRowId(e));
57
+ }
58
+ function ie(e) {
59
+ return e.toggleable === !1 || B().has(e.key);
60
+ }
61
+ function ae(e, t) {
62
+ return n.getCell?.(e, t) ?? t.getValue?.(e) ?? null;
63
+ }
64
+ return (() => {
65
+ var d = b(), f = d.firstChild, p = f.firstChild.firstChild, m = p.firstChild, h = p.nextSibling;
66
+ return i(d, t(u, {
67
+ get when() {
68
+ return N();
69
+ },
70
+ get children() {
71
+ var e = _(), a = e.firstChild, s = a.firstChild;
72
+ s.firstChild.nextSibling;
73
+ var d = Q;
74
+ return typeof d == "function" ? c(d, a) : Q = a, s.$$click = () => Z((e) => !e), o(s, "aria-controls", Y), i(s, () => n.columnCustomizerLabel ?? "Columns", null), i(a, t(u, {
75
+ get when() {
76
+ return X();
77
+ },
78
+ get children() {
79
+ var e = g(), a = e.firstChild, s = a.nextSibling, c = s.nextSibling.firstChild, u = c.nextSibling;
80
+ return o(e, "id", Y), i(a, () => n.columnCustomizerTitle ?? "Shown columns"), i(s, t(l, {
81
+ get each() {
82
+ return n.columns;
83
+ },
84
+ children: (e) => (() => {
85
+ var t = x(), n = t.firstChild, a = n.firstChild;
86
+ return a.addEventListener("change", (t) => K(e.key, t.currentTarget.checked)), i(n, () => e.ariaLabel ?? e.label, null), r(() => a.disabled = e.toggleable === !1), r(() => a.checked = ie(e)), t;
87
+ })()
88
+ })), c.$$click = q, i(c, () => n.columnCustomizerShowAllLabel ?? "Show all"), u.$$click = J, i(u, () => n.columnCustomizerResetLabel ?? "Reset"), r(() => o(e, "aria-label", n.columnCustomizerTitle ?? "Customize columns")), e;
89
+ }
90
+ }), null), r(() => o(s, "aria-expanded", X())), e;
91
+ }
92
+ }), f), i(m, t(u, {
93
+ get when() {
94
+ return P();
95
+ },
96
+ get children() {
97
+ var e = v(), t = e.firstChild.nextSibling;
98
+ t.addEventListener("change", (e) => te(e.currentTarget.checked));
99
+ var i = $;
100
+ return typeof i == "function" ? c(i, t) : $ = t, r(() => o(t, "aria-label", n.selectionLabel ?? "Select all rows")), r(() => t.checked = F()), e;
101
+ }
102
+ }), null), i(m, t(l, {
103
+ get each() {
104
+ return V();
105
+ },
106
+ children: (s) => (() => {
107
+ var c = C();
108
+ return i(c, t(u, {
109
+ get when() {
110
+ return a(() => !!s.sortable)() && n.onSort;
111
+ },
112
+ get fallback() {
113
+ return s.label;
114
+ },
115
+ get children() {
116
+ var e = S();
117
+ return e.$$click = () => n.onSort?.(s.key), i(e, () => s.label, null), i(e, (() => {
118
+ var e = a(() => j() === s.key);
119
+ return () => e() ? M() === "asc" ? " ▲" : " ▼" : "";
120
+ })(), null), e;
121
+ }
122
+ })), r((t) => {
123
+ var n = s.class, r = s.sortable ? j() === s.key ? M() === "asc" ? "ascending" : "descending" : "none" : void 0;
124
+ return n !== t.e && e(c, t.e = n), r !== t.t && o(c, "aria-sort", t.t = r), t;
125
+ }, {
126
+ e: void 0,
127
+ t: void 0
128
+ }), c;
129
+ })()
130
+ }), null), i(m, t(u, {
131
+ get when() {
132
+ return n.rowActions;
133
+ },
134
+ get children() {
135
+ return y();
136
+ }
137
+ }), null), i(h, t(l, {
138
+ get each() {
139
+ return s();
140
+ },
141
+ children: (a) => (() => {
142
+ var s = T();
143
+ return i(s, t(u, {
144
+ get when() {
145
+ return P();
146
+ },
147
+ get children() {
148
+ var e = ee(), t = e.firstChild;
149
+ return t.addEventListener("change", (e) => ne(a, e.currentTarget.checked)), r(() => o(t, "aria-label", `Select row ${n.getRowId(a)}`)), r(() => t.checked = re(a)), e;
150
+ }
151
+ }), null), i(s, t(l, {
152
+ get each() {
153
+ return V();
154
+ },
155
+ children: (t) => (() => {
156
+ var n = w();
157
+ return i(n, () => ae(a, t)), r(() => e(n, t.class)), n;
158
+ })()
159
+ }), null), i(s, t(u, {
160
+ get when() {
161
+ return n.rowActions;
162
+ },
163
+ get children() {
164
+ var e = w();
165
+ return i(e, () => n.rowActions?.(a)), e;
166
+ }
167
+ }), null), s;
168
+ })()
169
+ })), i(d, t(u, {
170
+ get when() {
171
+ return k();
172
+ },
173
+ get children() {
174
+ return n.loadingContent ?? E();
175
+ }
176
+ }), null), i(d, t(u, {
177
+ get when() {
178
+ return a(() => !k())() && (n.empty === void 0 ? s().length === 0 : O(n.empty));
179
+ },
180
+ get children() {
181
+ return n.emptyContent ?? D();
182
+ }
183
+ }), null), r(() => e(d, `data-table-wrap${n.class ? ` ${n.class}` : ""}`)), d;
184
+ })();
185
+ }
186
+ n(["click"]);
187
+ //#endregion
188
+ export { k as DataTable };
@@ -0,0 +1,132 @@
1
+ .data-table-wrap {
2
+ /* `color-scheme` is intentionally inherited so `light-dark()` below follows
3
+ the consumer's theme (e.g. the dark example). */
4
+ }
5
+
6
+ .data-table-scroll {
7
+ overflow-x: auto;
8
+ }
9
+
10
+ .data-table-toolbar {
11
+ display: flex;
12
+ justify-content: flex-end;
13
+ margin-bottom: 0.5rem;
14
+ }
15
+
16
+ .data-table-customizer {
17
+ position: relative;
18
+ }
19
+
20
+ .data-table-customizer-button {
21
+ display: inline-flex;
22
+ align-items: center;
23
+ gap: 0.375rem;
24
+ padding: 0.375rem 0.625rem;
25
+ border: 1px solid
26
+ var(--data-table-border, var(--border, light-dark(#d0d0d0, #3a3e45)));
27
+ border-radius: 0.375rem;
28
+ background: var(
29
+ --data-table-customizer-bg,
30
+ var(--surface, light-dark(#ffffff, #1d2024))
31
+ );
32
+ color: inherit;
33
+ font: inherit;
34
+ cursor: pointer;
35
+ white-space: nowrap;
36
+ }
37
+
38
+ .data-table-customizer-button:hover {
39
+ background: var(
40
+ --data-table-customizer-hover-bg,
41
+ var(--surface-hover, light-dark(#f5f5f5, #292d33))
42
+ );
43
+ }
44
+
45
+ .data-table-customizer-panel {
46
+ position: absolute;
47
+ top: calc(100% + 0.375rem);
48
+ right: 0;
49
+ z-index: 20;
50
+ min-width: 12rem;
51
+ padding: 0.75rem;
52
+ border: 1px solid
53
+ var(--data-table-border, var(--border, light-dark(#d0d0d0, #30343a)));
54
+ border-radius: 0.5rem;
55
+ background: var(
56
+ --data-table-panel-bg,
57
+ var(--surface, light-dark(#ffffff, #1d2024))
58
+ );
59
+ box-shadow: 0 8px 24px rgb(0 0 0 / 12%);
60
+ }
61
+
62
+ .data-table-customizer-title {
63
+ margin: 0 0 0.5rem;
64
+ font-weight: 600;
65
+ }
66
+
67
+ .data-table-customizer-list {
68
+ margin: 0;
69
+ padding: 0;
70
+ list-style: none;
71
+ display: grid;
72
+ gap: 0.375rem;
73
+ }
74
+
75
+ .data-table-customizer-option {
76
+ display: flex;
77
+ align-items: center;
78
+ gap: 0.5rem;
79
+ cursor: pointer;
80
+ }
81
+
82
+ .data-table-customizer-option:has(input:disabled) {
83
+ opacity: 0.6;
84
+ cursor: not-allowed;
85
+ }
86
+
87
+ .data-table-customizer-actions {
88
+ display: flex;
89
+ gap: 0.5rem;
90
+ margin-top: 0.75rem;
91
+ }
92
+
93
+ .data-table {
94
+ width: 100%;
95
+ max-width: 100%;
96
+ border-collapse: collapse;
97
+ }
98
+
99
+ .data-table-checkbox {
100
+ width: 2rem;
101
+ }
102
+
103
+ .data-table-sort {
104
+ padding: 0;
105
+ border: none;
106
+ background: transparent;
107
+ color: inherit;
108
+ font: inherit;
109
+ text-transform: inherit;
110
+ letter-spacing: inherit;
111
+ cursor: pointer;
112
+ white-space: nowrap;
113
+ }
114
+
115
+ .data-table-sort:hover {
116
+ background: transparent;
117
+ color: inherit;
118
+ text-decoration: underline;
119
+ }
120
+
121
+ .data-table-status {
122
+ color: var(--text-secondary, #616161);
123
+ }
124
+
125
+ .data-table-visually-hidden {
126
+ position: absolute;
127
+ width: 1px;
128
+ height: 1px;
129
+ overflow: hidden;
130
+ clip: rect(0 0 0 0);
131
+ white-space: nowrap;
132
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serkonda7/solid-components",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Reusable components for SolidJS",
5
5
  "license": "MIT",
6
6
  "author": "serkonda7",
@@ -18,7 +18,8 @@
18
18
  ".": {
19
19
  "types": "./dist/index.d.ts",
20
20
  "import": "./dist/index.js"
21
- }
21
+ },
22
+ "./styles.css": "./dist/styles.css"
22
23
  },
23
24
  "main": "./dist/index.js",
24
25
  "types": "./dist/index.d.ts",
@@ -27,6 +28,7 @@
27
28
  "lint": "biome check --write",
28
29
  "lint:ci": "biome ci",
29
30
  "check": "tsc --noEmit",
31
+ "examples": "vite --config examples/vite.config.ts",
30
32
  "build:dev": "bun run scripts/build.ts --dev",
31
33
  "build": "bun run check && bun run scripts/build.ts --prod",
32
34
  "prepack": "bun run build"
@@ -42,6 +44,8 @@
42
44
  "@biomejs/biome": "2.5.14",
43
45
  "@types/bun": "1.4.2",
44
46
  "solid-js": "~1.9.15",
45
- "typescript": "~7.0.2"
47
+ "typescript": "~7.0.2",
48
+ "vite": "~8.3.0",
49
+ "vite-plugin-solid": "~2.11.14"
46
50
  }
47
51
  }
package/dist/index.js.map DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [
5
- ],
6
- "mappings": "",
7
- "debugId": "1B152D275122871864756E2164756E21",
8
- "names": []
9
- }