@rttui/skin-anocca 1.0.12 → 1.0.14

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,18 @@
1
+ import type { StorybookConfig } from '@storybook/react-vite';
2
+
3
+ const config: StorybookConfig = {
4
+ "stories": [
5
+ "../src/**/*.mdx",
6
+ "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"
7
+ ],
8
+ "addons": [
9
+ "@storybook/addon-essentials",
10
+ "@storybook/addon-onboarding",
11
+ "@storybook/addon-interactions"
12
+ ],
13
+ "framework": {
14
+ "name": "@storybook/react-vite",
15
+ "options": {}
16
+ }
17
+ };
18
+ export default config;
@@ -0,0 +1,14 @@
1
+ import type { Preview } from '@storybook/react'
2
+
3
+ const preview: Preview = {
4
+ parameters: {
5
+ controls: {
6
+ matchers: {
7
+ color: /(background|color)$/i,
8
+ date: /Date$/i,
9
+ },
10
+ },
11
+ },
12
+ };
13
+
14
+ export default preview;
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @rttui/skin-anocca
2
2
 
3
+ ## 1.0.14
4
+
5
+ ### Patch Changes
6
+
7
+ - Add a storybook
8
+ - Updated dependencies
9
+ - @rttui/core@1.0.14
10
+
11
+ ## 1.0.13
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+ - @rttui/core@1.0.13
17
+
3
18
  ## 1.0.12
4
19
 
5
20
  ### Patch Changes
package/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # React + TypeScript + Vite
2
+
3
+ This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4
+
5
+ Currently, two official plugins are available:
6
+
7
+ - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8
+ - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9
+
10
+ ## Expanding the ESLint configuration
11
+
12
+ If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
13
+
14
+ ```js
15
+ export default tseslint.config({
16
+ extends: [
17
+ // Remove ...tseslint.configs.recommended and replace with this
18
+ ...tseslint.configs.recommendedTypeChecked,
19
+ // Alternatively, use this for stricter rules
20
+ ...tseslint.configs.strictTypeChecked,
21
+ // Optionally, add this for stylistic rules
22
+ ...tseslint.configs.stylisticTypeChecked,
23
+ ],
24
+ languageOptions: {
25
+ // other options...
26
+ parserOptions: {
27
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
28
+ tsconfigRootDir: import.meta.dirname,
29
+ },
30
+ },
31
+ })
32
+ ```
33
+
34
+ You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
35
+
36
+ ```js
37
+ // eslint.config.js
38
+ import reactX from 'eslint-plugin-react-x'
39
+ import reactDom from 'eslint-plugin-react-dom'
40
+
41
+ export default tseslint.config({
42
+ plugins: {
43
+ // Add the react-x and react-dom plugins
44
+ 'react-x': reactX,
45
+ 'react-dom': reactDom,
46
+ },
47
+ rules: {
48
+ // other rules...
49
+ // Enable its recommended typescript rules
50
+ ...reactX.configs['recommended-typescript'].rules,
51
+ ...reactDom.configs.recommended.rules,
52
+ },
53
+ })
54
+ ```
package/index.html ADDED
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Vite + React + TS</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@rttui/skin-anocca",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "main": "./dist/cjs/index.cjs",
5
5
  "dependencies": {
6
- "@rttui/core": "^1.0.12"
6
+ "@rttui/core": "^1.0.14"
7
7
  },
8
8
  "module": "./dist/mjs/index.mjs",
9
9
  "types": "./dist/types/index.d.ts",
@@ -16,5 +16,13 @@
16
16
  },
17
17
  "publishConfig": {
18
18
  "access": "public"
19
+ },
20
+ "scripts": {
21
+ "dev": "vite",
22
+ "build": "tsc -b && vite build",
23
+ "lint": "eslint .",
24
+ "preview": "vite preview",
25
+ "storybook": "storybook dev -p 6006",
26
+ "build-storybook": "storybook build"
19
27
  }
20
28
  }
@@ -0,0 +1,81 @@
1
+ import { useVirtualHeader } from "@rttui/core";
2
+ import { MdChevronLeft, MdChevronRight, MdClose } from "react-icons/md";
3
+
4
+ export const HeaderPinButtons = () => {
5
+ const vHeader = useVirtualHeader();
6
+ const header = vHeader.header;
7
+ if (!header) {
8
+ return null;
9
+ }
10
+ const isPinned = vHeader.isPinned;
11
+ return (
12
+ <div style={{ display: "flex", gap: "-4px", justifyContent: "flex-start" }}>
13
+ {isPinned !== "start" ? (
14
+ <button
15
+ style={{
16
+ border: "none",
17
+ background: "transparent",
18
+ cursor: "pointer",
19
+ padding: "2px",
20
+ borderRadius: "4px",
21
+ display: "flex",
22
+ alignItems: "center",
23
+ opacity: 0.5,
24
+ }}
25
+ onClick={() => {
26
+ if (!header) {
27
+ return;
28
+ }
29
+ header.column.pin("left");
30
+ }}
31
+ >
32
+ <MdChevronLeft />
33
+ </button>
34
+ ) : null}
35
+ {isPinned ? (
36
+ <button
37
+ style={{
38
+ border: "none",
39
+ background: "transparent",
40
+ cursor: "pointer",
41
+ padding: "2px",
42
+ borderRadius: "4px",
43
+ display: "flex",
44
+ alignItems: "center",
45
+ opacity: 0.7,
46
+ }}
47
+ onClick={() => {
48
+ if (!header) {
49
+ return;
50
+ }
51
+ header.column.pin(false);
52
+ }}
53
+ >
54
+ <MdClose />
55
+ </button>
56
+ ) : null}
57
+ {isPinned !== "end" ? (
58
+ <button
59
+ style={{
60
+ border: "none",
61
+ background: "transparent",
62
+ cursor: "pointer",
63
+ padding: "2px",
64
+ borderRadius: "4px",
65
+ display: "flex",
66
+ alignItems: "center",
67
+ opacity: 0.5,
68
+ }}
69
+ onClick={() => {
70
+ if (!header) {
71
+ return;
72
+ }
73
+ header.column.pin("right");
74
+ }}
75
+ >
76
+ <MdChevronRight />
77
+ </button>
78
+ ) : null}
79
+ </div>
80
+ );
81
+ };
package/src/index.tsx CHANGED
@@ -31,7 +31,6 @@ const AnoccaSkin: Skin = {
31
31
  className="rttui-overlay-container"
32
32
  style={{
33
33
  position: "relative",
34
- overflow: "hidden",
35
34
  width: width + "px",
36
35
  height: height + "px",
37
36
  ...cssVars,
@@ -88,6 +87,10 @@ const AnoccaSkin: Skin = {
88
87
  zIndex: 2,
89
88
  backgroundColor: (theme) => theme.palette.background.paper,
90
89
  boxShadow: (theme) => `0 1px 0 ${theme.palette.divider}`,
90
+ display: "flex",
91
+ flexDirection: "column",
92
+ justifyContent: "flex-start",
93
+ alignItems: "stretch",
91
94
  }}
92
95
  >
93
96
  {children}
@@ -121,7 +124,14 @@ const AnoccaSkin: Skin = {
121
124
  <TableBody
122
125
  component="div"
123
126
  className="table-body"
124
- sx={{ position: "relative", width: "var(--table-width)" }}
127
+ sx={{
128
+ position: "relative",
129
+ width: "var(--table-width)",
130
+ display: "flex",
131
+ flexDirection: "column",
132
+ justifyContent: "flex-start",
133
+ alignItems: "stretch",
134
+ }}
125
135
  >
126
136
  {children}
127
137
  </TableBody>
@@ -206,6 +216,11 @@ const AnoccaSkin: Skin = {
206
216
  sx={{
207
217
  ...dndStyle,
208
218
  ...vars,
219
+ width: "var(--table-width)",
220
+ display: "flex",
221
+ flexDirection: "column",
222
+ justifyContent: "flex-start",
223
+ alignItems: "stretch",
209
224
  }}
210
225
  data-index={flatIndex}
211
226
  ref={ref}
@@ -228,6 +243,14 @@ const AnoccaSkin: Skin = {
228
243
  zIndex: 1,
229
244
  boxSizing: "border-box",
230
245
  backgroundColor: "var(--row-background-color)",
246
+ "&:hover": {
247
+ backgroundColor: (theme) => {
248
+ // Always use solid background colors for all cells on hover
249
+ return theme.palette.mode === "dark"
250
+ ? "#1e1e52" // Dark blue solid color
251
+ : "#E3F2FD"; // Light blue solid color
252
+ },
253
+ },
231
254
  }}
232
255
  >
233
256
  {children}
@@ -257,47 +280,62 @@ const AnoccaSkin: Skin = {
257
280
  </TableRow>
258
281
  );
259
282
  },
260
- Cell: React.forwardRef(({ children, header, isMeasuring }, ref) => {
261
- const { isPinned } = header;
262
- return (
263
- <TableCell
264
- className="td"
265
- component="div"
266
- ref={ref}
267
- sx={{
268
- height: "var(--row-height)",
269
- width: isMeasuring ? "auto" : header.width,
270
- overflow: "hidden",
271
- textOverflow: "ellipsis",
272
- whiteSpace: "nowrap",
273
- zIndex: isPinned ? 5 : 0,
274
- boxSizing: "border-box",
275
- alignItems: "center",
276
- gap: "8px",
277
- display: "flex",
278
- justifyContent: "flex-start",
279
- alignContent: "center",
280
- padding: "6px 12px",
281
- backgroundColor: "var(--row-background-color)",
282
- borderBottom: "none",
283
- flexShrink: 0,
284
- position: "relative",
285
- borderRight: (theme) => `1px solid ${theme.palette.divider}`,
286
- ".table-row:hover &": {
287
- backgroundColor: (theme) => {
288
- // Always use solid background colors for all cells on hover
289
- return theme.palette.mode === "dark"
290
- ? "#1e1e52" // Dark blue solid color
291
- : "#E3F2FD"; // Light blue solid color
283
+ Cell: React.forwardRef(
284
+ (
285
+ { children, header, isMeasuring, isLastPinned, isLast, isLastCenter },
286
+ ref,
287
+ ) => {
288
+ const { isPinned } = header;
289
+ const { table } = useTableContext();
290
+ return (
291
+ <TableCell
292
+ className="td"
293
+ component="div"
294
+ ref={ref}
295
+ sx={{
296
+ height: "var(--row-height)",
297
+ width: isMeasuring ? "auto" : header.width,
298
+ overflow: "hidden",
299
+ textOverflow: "ellipsis",
300
+ whiteSpace: "nowrap",
301
+ zIndex: isPinned ? 5 : 0,
302
+ boxSizing: "border-box",
303
+ alignItems: "center",
304
+ gap: "8px",
305
+ display: "flex",
306
+ justifyContent: "flex-start",
307
+ alignContent: "center",
308
+ padding: "6px 12px",
309
+ backgroundColor: "var(--row-background-color)",
310
+ borderBottom: "none",
311
+ flexShrink: 0,
312
+ position: "relative",
313
+ borderRight:
314
+ ((isPinned === "start" && !isLastPinned) || !isPinned) &&
315
+ !isLast &&
316
+ !(isLastCenter && table.getIsSomeColumnsPinned("right"))
317
+ ? (theme) => `1px solid ${theme.palette.divider}`
318
+ : undefined,
319
+ borderLeft:
320
+ isPinned === "end" && !isLastPinned
321
+ ? (theme) => `1px solid ${theme.palette.divider}`
322
+ : undefined,
323
+ ".table-row:hover &": {
324
+ backgroundColor: (theme) => {
325
+ // Always use solid background colors for all cells on hover
326
+ return theme.palette.mode === "dark"
327
+ ? "#1e1e52" // Dark blue solid color
328
+ : "#E3F2FD"; // Light blue solid color
329
+ },
330
+ zIndex: isPinned ? 2 : 0,
292
331
  },
293
- zIndex: isPinned ? 2 : 0,
294
- },
295
- }}
296
- >
297
- {children}
298
- </TableCell>
299
- );
300
- }),
332
+ }}
333
+ >
334
+ {children}
335
+ </TableCell>
336
+ );
337
+ },
338
+ ),
301
339
  PinnedColsOverlay: ({ position }) => {
302
340
  const { table } = useTableContext();
303
341
  if (!table.getIsSomeColumnsPinned(position)) {
@@ -321,7 +359,6 @@ const AnoccaSkin: Skin = {
321
359
  if (position === "left") {
322
360
  style.boxShadow =
323
361
  "4px 0 8px -4px rgba(0, 0, 0, 0.15), 6px 0 12px -6px rgba(0, 0, 0, 0.1)";
324
- style.borderRight = "1px solid var(--table-border-color)";
325
362
  } else if (position === "right") {
326
363
  style.boxShadow =
327
364
  "-4px 0 8px -4px rgba(0, 0, 0, 0.15), -6px 0 12px -6px rgba(0, 0, 0, 0.1)";
@@ -336,9 +373,19 @@ function TableHeaderCell({
336
373
  width,
337
374
  header,
338
375
  type,
376
+ isLast,
377
+ isLastPinned,
378
+ isLastCenter,
339
379
  }: VirtualHeader & {
340
380
  type: "header" | "footer";
381
+ isLast: boolean;
382
+ isFirst: boolean;
383
+ isLastPinned: boolean;
384
+ isFirstPinned: boolean;
385
+ isFirstCenter: boolean;
386
+ isLastCenter: boolean;
341
387
  }) {
388
+ const { table } = useTableContext();
342
389
  return (
343
390
  <TableCell
344
391
  component="div"
@@ -364,7 +411,16 @@ function TableHeaderCell({
364
411
  backgroundColor: isPinned
365
412
  ? (theme) => theme.palette.background.paper
366
413
  : "transparent",
367
- borderRight: (theme) => `1px solid ${theme.palette.divider}`,
414
+ borderRight:
415
+ ((isPinned === "start" && !isLastPinned) || !isPinned) &&
416
+ !isLast &&
417
+ !(isLastCenter && table.getIsSomeColumnsPinned("right"))
418
+ ? (theme) => `1px solid ${theme.palette.divider}`
419
+ : undefined,
420
+ borderLeft:
421
+ isPinned === "end" && !isLastPinned
422
+ ? (theme) => `1px solid ${theme.palette.divider}`
423
+ : undefined,
368
424
  }}
369
425
  >
370
426
  <div style={{ flex: 1, display: "flex", justifyContent: "flex-start" }}>
@@ -0,0 +1,189 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+
3
+ import { Box } from "@mui/material";
4
+ import { decorateColumnHelper } from "@rttui/core";
5
+ import { createColumnHelper, getCoreRowModel } from "@tanstack/react-table";
6
+ import { AnoccaSkin } from "..";
7
+ import { HeaderPinButtons } from "../HeaderPinButtons";
8
+ import { ReactTanstackTableUi } from "./ReactTanstackTableUiStoryComponent";
9
+
10
+ type Person = {
11
+ id: string;
12
+ name: string;
13
+ age: number;
14
+ city: string;
15
+ };
16
+
17
+ const data: Person[] = [
18
+ { id: "1", name: "John", age: 20, city: "New York" },
19
+ { id: "2", name: "Jane", age: 21, city: "Los Angeles" },
20
+ { id: "3", name: "Jim", age: 22, city: "Chicago" },
21
+ ];
22
+
23
+ const bigData: Person[] = Array.from({ length: 1000 }, (_, i) => ({
24
+ id: i.toString(),
25
+ name: `Person ${i}`,
26
+ age: 20 + i,
27
+ city: `City ${i}`,
28
+ }));
29
+
30
+ // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
31
+ const meta = {
32
+ title: "ReactTanstackTableUi",
33
+ component: ReactTanstackTableUi,
34
+ parameters: {
35
+ // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
36
+ layout: "centered",
37
+ },
38
+ // More on argTypes: https://storybook.js.org/docs/api/argtypes
39
+ argTypes: {
40
+ tableOptions: { control: "object" },
41
+ uiOptions: { control: "object" },
42
+ },
43
+ // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
44
+ args: {
45
+ uiOptions: {
46
+ width: 600,
47
+ height: 400,
48
+ skin: AnoccaSkin,
49
+ autoSizeColumns: true,
50
+ },
51
+ tableOptions: {
52
+ columns: [],
53
+ data: [],
54
+ getCoreRowModel: getCoreRowModel(),
55
+ },
56
+ },
57
+ } satisfies Meta<typeof ReactTanstackTableUi>;
58
+
59
+ export default meta;
60
+ type Story = StoryObj<typeof meta>;
61
+
62
+ const columnHelper = decorateColumnHelper(createColumnHelper<Person>(), {
63
+ header: (original) => (
64
+ <Box sx={{ display: "flex", gap: 2 }}>
65
+ {original}
66
+ <HeaderPinButtons />
67
+ </Box>
68
+ ),
69
+ });
70
+
71
+ const columns = [
72
+ columnHelper.accessor("name", {
73
+ header: "Name",
74
+ }),
75
+ columnHelper.accessor("age", {
76
+ header: "Age",
77
+ }),
78
+ columnHelper.accessor("city", {
79
+ header: "City",
80
+ }),
81
+ ];
82
+
83
+ // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
84
+ export const AutoSizeColumns: Story = {
85
+ args: {
86
+ tableOptions: {
87
+ columns,
88
+ data,
89
+ getCoreRowModel: getCoreRowModel(),
90
+ enableColumnResizing: true,
91
+ enableColumnPinning: true,
92
+ },
93
+ uiOptions: {
94
+ width: 600,
95
+ height: 400,
96
+ skin: AnoccaSkin,
97
+ autoSizeColumns: true,
98
+ },
99
+ },
100
+ };
101
+
102
+ // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
103
+ export const AutoSizeColumnsPinRelativeToCols: Story = {
104
+ args: {
105
+ tableOptions: {
106
+ columns,
107
+ data,
108
+ getCoreRowModel: getCoreRowModel(),
109
+ enableColumnResizing: true,
110
+ enableColumnPinning: true,
111
+ },
112
+ uiOptions: {
113
+ width: 600,
114
+ height: 400,
115
+ skin: AnoccaSkin,
116
+ autoSizeColumns: true,
117
+ pinColsRelativeTo: "cols",
118
+ },
119
+ },
120
+ };
121
+
122
+ // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
123
+ export const PinRelativeToCols: Story = {
124
+ args: {
125
+ tableOptions: {
126
+ columns,
127
+ data,
128
+ getCoreRowModel: getCoreRowModel(),
129
+ enableColumnResizing: true,
130
+ enableColumnPinning: true,
131
+ initialState: {
132
+ columnPinning: {
133
+ right: ["city"],
134
+ },
135
+ },
136
+ },
137
+ uiOptions: {
138
+ width: 600,
139
+ height: 400,
140
+ skin: AnoccaSkin,
141
+ },
142
+ },
143
+ };
144
+
145
+ export const PinRelativeToTable: Story = {
146
+ args: {
147
+ tableOptions: {
148
+ columns,
149
+ data,
150
+ getCoreRowModel: getCoreRowModel(),
151
+ enableColumnResizing: true,
152
+ enableColumnPinning: true,
153
+ initialState: {
154
+ columnPinning: {
155
+ right: ["city"],
156
+ },
157
+ },
158
+ },
159
+ uiOptions: {
160
+ width: 600,
161
+ height: 400,
162
+ skin: AnoccaSkin,
163
+ pinColsRelativeTo: "table",
164
+ },
165
+ },
166
+ };
167
+
168
+ export const PinRelativeToTableWithBigData: Story = {
169
+ args: {
170
+ tableOptions: {
171
+ columns,
172
+ data: bigData,
173
+ getCoreRowModel: getCoreRowModel(),
174
+ enableColumnResizing: true,
175
+ enableColumnPinning: true,
176
+ initialState: {
177
+ columnPinning: {
178
+ right: ["city"],
179
+ },
180
+ },
181
+ },
182
+ uiOptions: {
183
+ width: 600,
184
+ height: 400,
185
+ skin: AnoccaSkin,
186
+ pinColsRelativeTo: "table",
187
+ },
188
+ },
189
+ };
@@ -0,0 +1,23 @@
1
+ import { ScopedCssBaseline, ThemeProvider } from "@mui/material";
2
+ import { useTheme } from "@mui/material/styles";
3
+ import { ReactTanstackTableUi as Table } from "@rttui/core";
4
+ import { TableOptions, useReactTable } from "@tanstack/react-table";
5
+
6
+ export const ReactTanstackTableUi = ({
7
+ tableOptions,
8
+ uiOptions,
9
+ }: {
10
+ tableOptions: TableOptions<any>;
11
+ uiOptions: Omit<React.ComponentProps<typeof Table>, "table">;
12
+ }) => {
13
+ const table = useReactTable(tableOptions);
14
+ const theme = useTheme();
15
+
16
+ return (
17
+ <ScopedCssBaseline>
18
+ <ThemeProvider theme={theme}>
19
+ <Table table={table} {...uiOptions} />
20
+ </ThemeProvider>
21
+ </ScopedCssBaseline>
22
+ );
23
+ };
package/vite.config.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ // https://vite.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ })