@trellisjs/react 0.1.0-alpha.1

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,75 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { TrellisAPI, TrellisOptions, ColumnDef, DataRow, SlotContext } from '@trellisjs/core';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+
6
+ /**
7
+ * 在元件間共享 Trellis API 的 Context。
8
+ */
9
+ declare const TrellisContext: react.Context<TrellisAPI<Record<string, unknown>> | null>;
10
+ /**
11
+ * 從 context 取得 Trellis API 的 hook。
12
+ * 必須在 TrellisContext.Provider 內使用。
13
+ */
14
+ declare function useTrellisContext<T = Record<string, unknown>>(): TrellisAPI<T>;
15
+
16
+ /**
17
+ * 建立和管理 Trellis 實例的 hook。
18
+ *
19
+ * - 只建立一次實例(useState lazy initializer)。
20
+ * - 狀態變更時觸發重新渲染。
21
+ * - 相容 React StrictMode 雙重掛載。
22
+ */
23
+ declare function useTrellis<T extends Record<string, unknown>>(options: TrellisOptions<T>): {
24
+ api: TrellisAPI<T>;
25
+ };
26
+
27
+ /**
28
+ * 無頭式 Table 元件。
29
+ * 渲染 <table> 包含 <thead> 和 <tbody>。
30
+ */
31
+ declare function Table(): react_jsx_runtime.JSX.Element;
32
+
33
+ interface TableHeadProps<T = Record<string, unknown>> {
34
+ columns: ColumnDef<T>[];
35
+ }
36
+ declare function TableHead<T>({ columns }: TableHeadProps<T>): react_jsx_runtime.JSX.Element;
37
+
38
+ interface TableBodyProps<T = Record<string, unknown>> {
39
+ data: DataRow<T>[];
40
+ columns: ColumnDef<T>[];
41
+ }
42
+ declare function TableBody<T>({ data, columns }: TableBodyProps<T>): react_jsx_runtime.JSX.Element;
43
+
44
+ interface TableRowProps<T = Record<string, unknown>> {
45
+ row: DataRow<T>;
46
+ columns: ColumnDef<T>[];
47
+ }
48
+ declare function Tr<T>({ row, columns }: TableRowProps<T>): react_jsx_runtime.JSX.Element;
49
+
50
+ interface ThProps<T = Record<string, unknown>> {
51
+ column: ColumnDef<T>;
52
+ }
53
+ declare function Th<T>({ column }: ThProps<T>): react_jsx_runtime.JSX.Element;
54
+
55
+ interface TdProps<T = Record<string, unknown>> {
56
+ row: DataRow<T>;
57
+ column: ColumnDef<T>;
58
+ }
59
+ declare function Td<T>({ row, column }: TdProps<T>): react_jsx_runtime.JSX.Element;
60
+
61
+ interface SlotRendererProps {
62
+ /** 要渲染的插槽名稱 */
63
+ name: string;
64
+ /** 傳遞給插槽渲染器的 context */
65
+ context?: SlotContext;
66
+ /** 插槽未註冊時的備用內容 */
67
+ fallback?: ReactNode;
68
+ }
69
+ /**
70
+ * 從 Trellis 插槽註冊表渲染具名插槽。
71
+ * 若未註冊則使用 `fallback` 屬性或渲染空內容。
72
+ */
73
+ declare function SlotRenderer({ name, context, fallback, }: SlotRendererProps): react_jsx_runtime.JSX.Element;
74
+
75
+ export { SlotRenderer, Table, TableBody, TableHead, Td, Th, Tr, TrellisContext, useTrellis, useTrellisContext };
@@ -0,0 +1,75 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { TrellisAPI, TrellisOptions, ColumnDef, DataRow, SlotContext } from '@trellisjs/core';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+
6
+ /**
7
+ * 在元件間共享 Trellis API 的 Context。
8
+ */
9
+ declare const TrellisContext: react.Context<TrellisAPI<Record<string, unknown>> | null>;
10
+ /**
11
+ * 從 context 取得 Trellis API 的 hook。
12
+ * 必須在 TrellisContext.Provider 內使用。
13
+ */
14
+ declare function useTrellisContext<T = Record<string, unknown>>(): TrellisAPI<T>;
15
+
16
+ /**
17
+ * 建立和管理 Trellis 實例的 hook。
18
+ *
19
+ * - 只建立一次實例(useState lazy initializer)。
20
+ * - 狀態變更時觸發重新渲染。
21
+ * - 相容 React StrictMode 雙重掛載。
22
+ */
23
+ declare function useTrellis<T extends Record<string, unknown>>(options: TrellisOptions<T>): {
24
+ api: TrellisAPI<T>;
25
+ };
26
+
27
+ /**
28
+ * 無頭式 Table 元件。
29
+ * 渲染 <table> 包含 <thead> 和 <tbody>。
30
+ */
31
+ declare function Table(): react_jsx_runtime.JSX.Element;
32
+
33
+ interface TableHeadProps<T = Record<string, unknown>> {
34
+ columns: ColumnDef<T>[];
35
+ }
36
+ declare function TableHead<T>({ columns }: TableHeadProps<T>): react_jsx_runtime.JSX.Element;
37
+
38
+ interface TableBodyProps<T = Record<string, unknown>> {
39
+ data: DataRow<T>[];
40
+ columns: ColumnDef<T>[];
41
+ }
42
+ declare function TableBody<T>({ data, columns }: TableBodyProps<T>): react_jsx_runtime.JSX.Element;
43
+
44
+ interface TableRowProps<T = Record<string, unknown>> {
45
+ row: DataRow<T>;
46
+ columns: ColumnDef<T>[];
47
+ }
48
+ declare function Tr<T>({ row, columns }: TableRowProps<T>): react_jsx_runtime.JSX.Element;
49
+
50
+ interface ThProps<T = Record<string, unknown>> {
51
+ column: ColumnDef<T>;
52
+ }
53
+ declare function Th<T>({ column }: ThProps<T>): react_jsx_runtime.JSX.Element;
54
+
55
+ interface TdProps<T = Record<string, unknown>> {
56
+ row: DataRow<T>;
57
+ column: ColumnDef<T>;
58
+ }
59
+ declare function Td<T>({ row, column }: TdProps<T>): react_jsx_runtime.JSX.Element;
60
+
61
+ interface SlotRendererProps {
62
+ /** 要渲染的插槽名稱 */
63
+ name: string;
64
+ /** 傳遞給插槽渲染器的 context */
65
+ context?: SlotContext;
66
+ /** 插槽未註冊時的備用內容 */
67
+ fallback?: ReactNode;
68
+ }
69
+ /**
70
+ * 從 Trellis 插槽註冊表渲染具名插槽。
71
+ * 若未註冊則使用 `fallback` 屬性或渲染空內容。
72
+ */
73
+ declare function SlotRenderer({ name, context, fallback, }: SlotRendererProps): react_jsx_runtime.JSX.Element;
74
+
75
+ export { SlotRenderer, Table, TableBody, TableHead, Td, Th, Tr, TrellisContext, useTrellis, useTrellisContext };
package/dist/index.js ADDED
@@ -0,0 +1,154 @@
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
+ SlotRenderer: () => SlotRenderer,
24
+ Table: () => Table,
25
+ TableBody: () => TableBody,
26
+ TableHead: () => TableHead,
27
+ Td: () => Td,
28
+ Th: () => Th,
29
+ Tr: () => Tr,
30
+ TrellisContext: () => TrellisContext,
31
+ useTrellis: () => useTrellis,
32
+ useTrellisContext: () => useTrellisContext
33
+ });
34
+ module.exports = __toCommonJS(index_exports);
35
+
36
+ // src/context.tsx
37
+ var import_react = require("react");
38
+ var TrellisContext = (0, import_react.createContext)(null);
39
+ function useTrellisContext() {
40
+ const ctx = (0, import_react.useContext)(TrellisContext);
41
+ if (!ctx) {
42
+ throw new Error("useTrellisContext must be used within a <TrellisProvider>");
43
+ }
44
+ return ctx;
45
+ }
46
+
47
+ // src/hooks/use-trellis.ts
48
+ var import_react2 = require("react");
49
+ var import_core = require("@trellisjs/core");
50
+ function useTrellis(options) {
51
+ const [trellis] = (0, import_react2.useState)(() => new import_core.Trellis(options));
52
+ const [, setVersion] = (0, import_react2.useState)(0);
53
+ (0, import_react2.useEffect)(() => {
54
+ const unsubscribe = trellis.api.subscribe(() => {
55
+ setVersion((v) => v + 1);
56
+ });
57
+ return unsubscribe;
58
+ }, [trellis]);
59
+ return { api: trellis.api };
60
+ }
61
+
62
+ // src/components/th.tsx
63
+ var import_jsx_runtime = require("react/jsx-runtime");
64
+ function Th({ column }) {
65
+ const style = {};
66
+ if (column.width) style.width = column.width;
67
+ if (column.minWidth) style.minWidth = column.minWidth;
68
+ if (column.maxWidth) style.maxWidth = column.maxWidth;
69
+ if (column.align) style.textAlign = column.align;
70
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: Object.keys(style).length > 0 ? style : void 0, children: column.header });
71
+ }
72
+
73
+ // src/components/thead.tsx
74
+ var import_jsx_runtime2 = require("react/jsx-runtime");
75
+ function TableHead({ columns }) {
76
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: columns.filter((col) => col.visible !== false).map((col) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Th, { column: col }, col.id)) }) });
77
+ }
78
+
79
+ // src/components/td.tsx
80
+ var import_jsx_runtime3 = require("react/jsx-runtime");
81
+ function getCellValue(row, column) {
82
+ const { accessor } = column;
83
+ if (typeof accessor === "function") {
84
+ return accessor(row.original);
85
+ }
86
+ return row.original[accessor];
87
+ }
88
+ function Td({ row, column }) {
89
+ const value = getCellValue(row, column);
90
+ const style = {};
91
+ if (column.align) style.textAlign = column.align;
92
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { style: Object.keys(style).length > 0 ? style : void 0, children: value != null ? String(value) : "" });
93
+ }
94
+
95
+ // src/components/tr.tsx
96
+ var import_jsx_runtime4 = require("react/jsx-runtime");
97
+ function Tr({ row, columns }) {
98
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: columns.filter((col) => col.visible !== false).map((col) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Td, { row, column: col }, col.id)) });
99
+ }
100
+
101
+ // src/components/tbody.tsx
102
+ var import_jsx_runtime5 = require("react/jsx-runtime");
103
+ function TableBody({ data, columns }) {
104
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { children: data.map((row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Tr, { row, columns }, row.id)) });
105
+ }
106
+
107
+ // src/components/table.tsx
108
+ var import_jsx_runtime6 = require("react/jsx-runtime");
109
+ function Table() {
110
+ const api = useTrellisContext();
111
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("table", { children: [
112
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TableHead, { columns: api.getState().columns }),
113
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
114
+ TableBody,
115
+ {
116
+ data: api.getState().data,
117
+ columns: api.getState().columns
118
+ }
119
+ )
120
+ ] });
121
+ }
122
+
123
+ // src/slots/slot-renderer.tsx
124
+ var import_jsx_runtime7 = require("react/jsx-runtime");
125
+ function SlotRenderer({
126
+ name,
127
+ context,
128
+ fallback = null
129
+ }) {
130
+ const api = useTrellisContext();
131
+ const renderer = api.getSlot(name);
132
+ if (!renderer) {
133
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: fallback });
134
+ }
135
+ const content = renderer(context ?? {});
136
+ if (content !== null && content !== void 0) {
137
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: content });
138
+ }
139
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: fallback });
140
+ }
141
+ // Annotate the CommonJS export names for ESM import in node:
142
+ 0 && (module.exports = {
143
+ SlotRenderer,
144
+ Table,
145
+ TableBody,
146
+ TableHead,
147
+ Td,
148
+ Th,
149
+ Tr,
150
+ TrellisContext,
151
+ useTrellis,
152
+ useTrellisContext
153
+ });
154
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/context.tsx","../src/hooks/use-trellis.ts","../src/components/th.tsx","../src/components/thead.tsx","../src/components/td.tsx","../src/components/tr.tsx","../src/components/tbody.tsx","../src/components/table.tsx","../src/slots/slot-renderer.tsx"],"sourcesContent":["// Trellis React 適配器\n\n// Context\nexport { TrellisContext, useTrellisContext } from './context';\n\n// Hooks\nexport { useTrellis } from './hooks/use-trellis';\n\n// 元件\nexport {\n Table,\n TableHead,\n TableBody,\n Tr,\n Th,\n Td,\n} from './components';\n\n// 插槽\nexport { SlotRenderer } from './slots/slot-renderer';\n","import { createContext, useContext } from 'react';\nimport type { TrellisAPI } from '@trellisjs/core';\n\n/**\n * 在元件間共享 Trellis API 的 Context。\n */\nexport const TrellisContext = createContext<TrellisAPI | null>(null);\n\n/**\n * 從 context 取得 Trellis API 的 hook。\n * 必須在 TrellisContext.Provider 內使用。\n */\nexport function useTrellisContext<T = Record<string, unknown>>(): TrellisAPI<T> {\n const ctx = useContext(TrellisContext);\n if (!ctx) {\n throw new Error('useTrellisContext must be used within a <TrellisProvider>');\n }\n return ctx as TrellisAPI<T>;\n}\n","import { useState, useEffect } from 'react';\nimport { Trellis } from '@trellisjs/core';\nimport type { TrellisAPI, TrellisOptions } from '@trellisjs/core';\n\n/**\n * 建立和管理 Trellis 實例的 hook。\n *\n * - 只建立一次實例(useState lazy initializer)。\n * - 狀態變更時觸發重新渲染。\n * - 相容 React StrictMode 雙重掛載。\n */\nexport function useTrellis<T extends Record<string, unknown>>(\n options: TrellisOptions<T>,\n): { api: TrellisAPI<T> } {\n // useState initializer 只執行一次,不會被 StrictMode cleanup 重置\n const [trellis] = useState(() => new Trellis(options));\n const [, setVersion] = useState(0);\n\n useEffect(() => {\n const unsubscribe = trellis.api.subscribe(() => {\n setVersion((v) => v + 1);\n });\n\n return unsubscribe;\n }, [trellis]);\n\n return { api: trellis.api };\n}\n","import type { ColumnDef } from '@trellisjs/core';\n\ninterface ThProps<T = Record<string, unknown>> {\n column: ColumnDef<T>;\n}\n\nexport function Th<T>({ column }: ThProps<T>) {\n const style: React.CSSProperties = {};\n if (column.width) style.width = column.width;\n if (column.minWidth) style.minWidth = column.minWidth;\n if (column.maxWidth) style.maxWidth = column.maxWidth;\n if (column.align) style.textAlign = column.align;\n\n return (\n <th style={Object.keys(style).length > 0 ? style : undefined}>\n {column.header}\n </th>\n );\n}\n","import type { ColumnDef } from '@trellisjs/core';\nimport { Th } from './th';\n\ninterface TableHeadProps<T = Record<string, unknown>> {\n columns: ColumnDef<T>[];\n}\n\nexport function TableHead<T>({ columns }: TableHeadProps<T>) {\n return (\n <thead>\n <tr>\n {columns\n .filter((col) => col.visible !== false)\n .map((col) => (\n <Th key={col.id} column={col} />\n ))}\n </tr>\n </thead>\n );\n}\n","import type { ColumnDef, DataRow } from '@trellisjs/core';\n\ninterface TdProps<T = Record<string, unknown>> {\n row: DataRow<T>;\n column: ColumnDef<T>;\n}\n\nfunction getCellValue<T>(row: DataRow<T>, column: ColumnDef<T>): unknown {\n const { accessor } = column;\n if (typeof accessor === 'function') {\n return accessor(row.original);\n }\n return row.original[accessor];\n}\n\nexport function Td<T>({ row, column }: TdProps<T>) {\n const value = getCellValue(row, column);\n const style: React.CSSProperties = {};\n if (column.align) style.textAlign = column.align;\n\n return (\n <td style={Object.keys(style).length > 0 ? style : undefined}>\n {value != null ? String(value) : ''}\n </td>\n );\n}\n","import type { ColumnDef, DataRow } from '@trellisjs/core';\nimport { Td } from './td';\n\ninterface TableRowProps<T = Record<string, unknown>> {\n row: DataRow<T>;\n columns: ColumnDef<T>[];\n}\n\nexport function Tr<T>({ row, columns }: TableRowProps<T>) {\n return (\n <tr>\n {columns\n .filter((col) => col.visible !== false)\n .map((col) => (\n <Td key={col.id} row={row} column={col} />\n ))}\n </tr>\n );\n}\n","import type { ColumnDef, DataRow } from '@trellisjs/core';\nimport { Tr } from './tr';\n\ninterface TableBodyProps<T = Record<string, unknown>> {\n data: DataRow<T>[];\n columns: ColumnDef<T>[];\n}\n\nexport function TableBody<T>({ data, columns }: TableBodyProps<T>) {\n return (\n <tbody>\n {data.map((row) => (\n <Tr key={row.id} row={row} columns={columns} />\n ))}\n </tbody>\n );\n}\n","import { TableHead } from './thead';\nimport { TableBody } from './tbody';\nimport { useTrellisContext } from '../context';\n\n/**\n * 無頭式 Table 元件。\n * 渲染 <table> 包含 <thead> 和 <tbody>。\n */\nexport function Table() {\n const api = useTrellisContext();\n\n return (\n <table>\n <TableHead columns={api.getState().columns} />\n <TableBody\n data={api.getState().data}\n columns={api.getState().columns}\n />\n </table>\n );\n}\n","import type { ReactNode } from 'react';\nimport { useTrellisContext } from '../context';\nimport type { SlotContext } from '@trellisjs/core';\n\ninterface SlotRendererProps {\n /** 要渲染的插槽名稱 */\n name: string;\n /** 傳遞給插槽渲染器的 context */\n context?: SlotContext;\n /** 插槽未註冊時的備用內容 */\n fallback?: ReactNode;\n}\n\n/**\n * 從 Trellis 插槽註冊表渲染具名插槽。\n * 若未註冊則使用 `fallback` 屬性或渲染空內容。\n */\nexport function SlotRenderer({\n name,\n context,\n fallback = null,\n}: SlotRendererProps) {\n const api = useTrellisContext();\n const renderer = api.getSlot(name);\n\n if (!renderer) {\n return <>{fallback}</>;\n }\n\n const content = renderer(context ?? {});\n\n if (content !== null && content !== undefined) {\n return <>{content}</>;\n }\n\n return <>{fallback}</>;\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,118 @@
1
+ // src/context.tsx
2
+ import { createContext, useContext } from "react";
3
+ var TrellisContext = createContext(null);
4
+ function useTrellisContext() {
5
+ const ctx = useContext(TrellisContext);
6
+ if (!ctx) {
7
+ throw new Error("useTrellisContext must be used within a <TrellisProvider>");
8
+ }
9
+ return ctx;
10
+ }
11
+
12
+ // src/hooks/use-trellis.ts
13
+ import { useState, useEffect } from "react";
14
+ import { Trellis } from "@trellisjs/core";
15
+ function useTrellis(options) {
16
+ const [trellis] = useState(() => new Trellis(options));
17
+ const [, setVersion] = useState(0);
18
+ useEffect(() => {
19
+ const unsubscribe = trellis.api.subscribe(() => {
20
+ setVersion((v) => v + 1);
21
+ });
22
+ return unsubscribe;
23
+ }, [trellis]);
24
+ return { api: trellis.api };
25
+ }
26
+
27
+ // src/components/th.tsx
28
+ import { jsx } from "react/jsx-runtime";
29
+ function Th({ column }) {
30
+ const style = {};
31
+ if (column.width) style.width = column.width;
32
+ if (column.minWidth) style.minWidth = column.minWidth;
33
+ if (column.maxWidth) style.maxWidth = column.maxWidth;
34
+ if (column.align) style.textAlign = column.align;
35
+ return /* @__PURE__ */ jsx("th", { style: Object.keys(style).length > 0 ? style : void 0, children: column.header });
36
+ }
37
+
38
+ // src/components/thead.tsx
39
+ import { jsx as jsx2 } from "react/jsx-runtime";
40
+ function TableHead({ columns }) {
41
+ return /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { children: columns.filter((col) => col.visible !== false).map((col) => /* @__PURE__ */ jsx2(Th, { column: col }, col.id)) }) });
42
+ }
43
+
44
+ // src/components/td.tsx
45
+ import { jsx as jsx3 } from "react/jsx-runtime";
46
+ function getCellValue(row, column) {
47
+ const { accessor } = column;
48
+ if (typeof accessor === "function") {
49
+ return accessor(row.original);
50
+ }
51
+ return row.original[accessor];
52
+ }
53
+ function Td({ row, column }) {
54
+ const value = getCellValue(row, column);
55
+ const style = {};
56
+ if (column.align) style.textAlign = column.align;
57
+ return /* @__PURE__ */ jsx3("td", { style: Object.keys(style).length > 0 ? style : void 0, children: value != null ? String(value) : "" });
58
+ }
59
+
60
+ // src/components/tr.tsx
61
+ import { jsx as jsx4 } from "react/jsx-runtime";
62
+ function Tr({ row, columns }) {
63
+ return /* @__PURE__ */ jsx4("tr", { children: columns.filter((col) => col.visible !== false).map((col) => /* @__PURE__ */ jsx4(Td, { row, column: col }, col.id)) });
64
+ }
65
+
66
+ // src/components/tbody.tsx
67
+ import { jsx as jsx5 } from "react/jsx-runtime";
68
+ function TableBody({ data, columns }) {
69
+ return /* @__PURE__ */ jsx5("tbody", { children: data.map((row) => /* @__PURE__ */ jsx5(Tr, { row, columns }, row.id)) });
70
+ }
71
+
72
+ // src/components/table.tsx
73
+ import { jsx as jsx6, jsxs } from "react/jsx-runtime";
74
+ function Table() {
75
+ const api = useTrellisContext();
76
+ return /* @__PURE__ */ jsxs("table", { children: [
77
+ /* @__PURE__ */ jsx6(TableHead, { columns: api.getState().columns }),
78
+ /* @__PURE__ */ jsx6(
79
+ TableBody,
80
+ {
81
+ data: api.getState().data,
82
+ columns: api.getState().columns
83
+ }
84
+ )
85
+ ] });
86
+ }
87
+
88
+ // src/slots/slot-renderer.tsx
89
+ import { Fragment, jsx as jsx7 } from "react/jsx-runtime";
90
+ function SlotRenderer({
91
+ name,
92
+ context,
93
+ fallback = null
94
+ }) {
95
+ const api = useTrellisContext();
96
+ const renderer = api.getSlot(name);
97
+ if (!renderer) {
98
+ return /* @__PURE__ */ jsx7(Fragment, { children: fallback });
99
+ }
100
+ const content = renderer(context ?? {});
101
+ if (content !== null && content !== void 0) {
102
+ return /* @__PURE__ */ jsx7(Fragment, { children: content });
103
+ }
104
+ return /* @__PURE__ */ jsx7(Fragment, { children: fallback });
105
+ }
106
+ export {
107
+ SlotRenderer,
108
+ Table,
109
+ TableBody,
110
+ TableHead,
111
+ Td,
112
+ Th,
113
+ Tr,
114
+ TrellisContext,
115
+ useTrellis,
116
+ useTrellisContext
117
+ };
118
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context.tsx","../src/hooks/use-trellis.ts","../src/components/th.tsx","../src/components/thead.tsx","../src/components/td.tsx","../src/components/tr.tsx","../src/components/tbody.tsx","../src/components/table.tsx","../src/slots/slot-renderer.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\nimport type { TrellisAPI } from '@trellisjs/core';\n\n/**\n * 在元件間共享 Trellis API 的 Context。\n */\nexport const TrellisContext = createContext<TrellisAPI | null>(null);\n\n/**\n * 從 context 取得 Trellis API 的 hook。\n * 必須在 TrellisContext.Provider 內使用。\n */\nexport function useTrellisContext<T = Record<string, unknown>>(): TrellisAPI<T> {\n const ctx = useContext(TrellisContext);\n if (!ctx) {\n throw new Error('useTrellisContext must be used within a <TrellisProvider>');\n }\n return ctx as TrellisAPI<T>;\n}\n","import { useState, useEffect } from 'react';\nimport { Trellis } from '@trellisjs/core';\nimport type { TrellisAPI, TrellisOptions } from '@trellisjs/core';\n\n/**\n * 建立和管理 Trellis 實例的 hook。\n *\n * - 只建立一次實例(useState lazy initializer)。\n * - 狀態變更時觸發重新渲染。\n * - 相容 React StrictMode 雙重掛載。\n */\nexport function useTrellis<T extends Record<string, unknown>>(\n options: TrellisOptions<T>,\n): { api: TrellisAPI<T> } {\n // useState initializer 只執行一次,不會被 StrictMode cleanup 重置\n const [trellis] = useState(() => new Trellis(options));\n const [, setVersion] = useState(0);\n\n useEffect(() => {\n const unsubscribe = trellis.api.subscribe(() => {\n setVersion((v) => v + 1);\n });\n\n return unsubscribe;\n }, [trellis]);\n\n return { api: trellis.api };\n}\n","import type { ColumnDef } from '@trellisjs/core';\n\ninterface ThProps<T = Record<string, unknown>> {\n column: ColumnDef<T>;\n}\n\nexport function Th<T>({ column }: ThProps<T>) {\n const style: React.CSSProperties = {};\n if (column.width) style.width = column.width;\n if (column.minWidth) style.minWidth = column.minWidth;\n if (column.maxWidth) style.maxWidth = column.maxWidth;\n if (column.align) style.textAlign = column.align;\n\n return (\n <th style={Object.keys(style).length > 0 ? style : undefined}>\n {column.header}\n </th>\n );\n}\n","import type { ColumnDef } from '@trellisjs/core';\nimport { Th } from './th';\n\ninterface TableHeadProps<T = Record<string, unknown>> {\n columns: ColumnDef<T>[];\n}\n\nexport function TableHead<T>({ columns }: TableHeadProps<T>) {\n return (\n <thead>\n <tr>\n {columns\n .filter((col) => col.visible !== false)\n .map((col) => (\n <Th key={col.id} column={col} />\n ))}\n </tr>\n </thead>\n );\n}\n","import type { ColumnDef, DataRow } from '@trellisjs/core';\n\ninterface TdProps<T = Record<string, unknown>> {\n row: DataRow<T>;\n column: ColumnDef<T>;\n}\n\nfunction getCellValue<T>(row: DataRow<T>, column: ColumnDef<T>): unknown {\n const { accessor } = column;\n if (typeof accessor === 'function') {\n return accessor(row.original);\n }\n return row.original[accessor];\n}\n\nexport function Td<T>({ row, column }: TdProps<T>) {\n const value = getCellValue(row, column);\n const style: React.CSSProperties = {};\n if (column.align) style.textAlign = column.align;\n\n return (\n <td style={Object.keys(style).length > 0 ? style : undefined}>\n {value != null ? String(value) : ''}\n </td>\n );\n}\n","import type { ColumnDef, DataRow } from '@trellisjs/core';\nimport { Td } from './td';\n\ninterface TableRowProps<T = Record<string, unknown>> {\n row: DataRow<T>;\n columns: ColumnDef<T>[];\n}\n\nexport function Tr<T>({ row, columns }: TableRowProps<T>) {\n return (\n <tr>\n {columns\n .filter((col) => col.visible !== false)\n .map((col) => (\n <Td key={col.id} row={row} column={col} />\n ))}\n </tr>\n );\n}\n","import type { ColumnDef, DataRow } from '@trellisjs/core';\nimport { Tr } from './tr';\n\ninterface TableBodyProps<T = Record<string, unknown>> {\n data: DataRow<T>[];\n columns: ColumnDef<T>[];\n}\n\nexport function TableBody<T>({ data, columns }: TableBodyProps<T>) {\n return (\n <tbody>\n {data.map((row) => (\n <Tr key={row.id} row={row} columns={columns} />\n ))}\n </tbody>\n );\n}\n","import { TableHead } from './thead';\nimport { TableBody } from './tbody';\nimport { useTrellisContext } from '../context';\n\n/**\n * 無頭式 Table 元件。\n * 渲染 <table> 包含 <thead> 和 <tbody>。\n */\nexport function Table() {\n const api = useTrellisContext();\n\n return (\n <table>\n <TableHead columns={api.getState().columns} />\n <TableBody\n data={api.getState().data}\n columns={api.getState().columns}\n />\n </table>\n );\n}\n","import type { ReactNode } from 'react';\nimport { useTrellisContext } from '../context';\nimport type { SlotContext } from '@trellisjs/core';\n\ninterface SlotRendererProps {\n /** 要渲染的插槽名稱 */\n name: string;\n /** 傳遞給插槽渲染器的 context */\n context?: SlotContext;\n /** 插槽未註冊時的備用內容 */\n fallback?: ReactNode;\n}\n\n/**\n * 從 Trellis 插槽註冊表渲染具名插槽。\n * 若未註冊則使用 `fallback` 屬性或渲染空內容。\n */\nexport function SlotRenderer({\n name,\n context,\n fallback = null,\n}: SlotRendererProps) {\n const api = useTrellisContext();\n const renderer = api.getSlot(name);\n\n if (!renderer) {\n return <>{fallback}</>;\n }\n\n const content = renderer(context ?? {});\n\n if (content !== null && content !== undefined) {\n return <>{content}</>;\n }\n\n return <>{fallback}</>;\n}\n"],"mappings":"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","names":["jsx","jsx","jsx","jsx","jsx","jsx"]}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@trellisjs/react",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "Trellis 的 React 適配器 — 無頭式資料表格元件",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.mts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsup",
25
+ "dev": "tsup --watch",
26
+ "test": "vitest run",
27
+ "test:watch": "vitest",
28
+ "clean": "rm -rf dist *.tsbuildinfo"
29
+ },
30
+ "peerDependencies": {
31
+ "@trellisjs/core": "workspace:*",
32
+ "react": ">=18.0.0",
33
+ "react-dom": ">=18.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@testing-library/jest-dom": "^6.9.1",
37
+ "@testing-library/react": "^16.3.0",
38
+ "@trellisjs/core": "workspace:*",
39
+ "@types/react": "^19.1.0",
40
+ "@types/react-dom": "^19.1.0",
41
+ "jsdom": "^26.1.0",
42
+ "react": "^19.1.0",
43
+ "react-dom": "^19.1.0",
44
+ "tsup": "^8.4.0",
45
+ "typescript": "^5.7.0",
46
+ "vitest": "^3.1.0"
47
+ },
48
+ "license": "MIT",
49
+ "sideEffects": false
50
+ }