@rttui/skin-anocca 1.0.13 → 1.0.15

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,21 @@
1
1
  # @rttui/skin-anocca
2
2
 
3
+ ## 1.0.15
4
+
5
+ ### Patch Changes
6
+
7
+ - Improve column sizing API
8
+ - Updated dependencies
9
+ - @rttui/core@1.0.15
10
+
11
+ ## 1.0.14
12
+
13
+ ### Patch Changes
14
+
15
+ - Add a storybook
16
+ - Updated dependencies
17
+ - @rttui/core@1.0.14
18
+
3
19
  ## 1.0.13
4
20
 
5
21
  ### 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.13",
3
+ "version": "1.0.15",
4
4
  "main": "./dist/cjs/index.cjs",
5
5
  "dependencies": {
6
- "@rttui/core": "^1.0.13"
6
+ "@rttui/core": "^1.0.15"
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
+ };
@@ -0,0 +1,40 @@
1
+ import { Row } from "@tanstack/react-table";
2
+ import { IconButton, Stack } from "@mui/material";
3
+ import { FiX, FiChevronUp, FiChevronDown } from "react-icons/fi";
4
+
5
+ export function RowPinButtons({ row }: { row: Row<any> }) {
6
+ if (!row.getCanPin()) {
7
+ return null;
8
+ }
9
+
10
+ if (row.getIsPinned()) {
11
+ return (
12
+ <IconButton
13
+ onClick={() => row.pin(false, true, true)}
14
+ size="small"
15
+ sx={{ color: "text.secondary" }}
16
+ >
17
+ <FiX size={16} />
18
+ </IconButton>
19
+ );
20
+ }
21
+
22
+ return (
23
+ <Stack direction="row">
24
+ <IconButton
25
+ onClick={() => row.pin("top", true, true)}
26
+ size="small"
27
+ sx={{ color: "text.secondary" }}
28
+ >
29
+ <FiChevronUp size={16} />
30
+ </IconButton>
31
+ <IconButton
32
+ onClick={() => row.pin("bottom", true, true)}
33
+ size="small"
34
+ sx={{ color: "text.secondary" }}
35
+ >
36
+ <FiChevronDown size={16} />
37
+ </IconButton>
38
+ </Stack>
39
+ );
40
+ }
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}
@@ -113,15 +116,23 @@ const AnoccaSkin: Skin = {
113
116
  );
114
117
  },
115
118
  HeaderRow: TableHeaderRow,
116
- HeaderCell: (props) => {
117
- return <TableHeaderCell {...props} />;
118
- },
119
+ HeaderCell: React.forwardRef((props, ref) => {
120
+ return <TableHeaderCell {...props} ref={ref} />;
121
+ }),
119
122
  TableBody: ({ children }) => {
120
123
  return (
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
+ height: "var(--table-height)",
131
+ display: "flex",
132
+ flexDirection: "column",
133
+ justifyContent: "flex-start",
134
+ alignItems: "stretch",
135
+ }}
125
136
  >
126
137
  {children}
127
138
  </TableBody>
@@ -206,6 +217,11 @@ const AnoccaSkin: Skin = {
206
217
  sx={{
207
218
  ...dndStyle,
208
219
  ...vars,
220
+ width: "var(--table-width)",
221
+ display: "flex",
222
+ flexDirection: "column",
223
+ justifyContent: "flex-start",
224
+ alignItems: "stretch",
209
225
  }}
210
226
  data-index={flatIndex}
211
227
  ref={ref}
@@ -228,6 +244,14 @@ const AnoccaSkin: Skin = {
228
244
  zIndex: 1,
229
245
  boxSizing: "border-box",
230
246
  backgroundColor: "var(--row-background-color)",
247
+ "&:hover": {
248
+ backgroundColor: (theme) => {
249
+ // Always use solid background colors for all cells on hover
250
+ return theme.palette.mode === "dark"
251
+ ? "#1e1e52" // Dark blue solid color
252
+ : "#E3F2FD"; // Light blue solid color
253
+ },
254
+ },
231
255
  }}
232
256
  >
233
257
  {children}
@@ -257,47 +281,64 @@ const AnoccaSkin: Skin = {
257
281
  </TableRow>
258
282
  );
259
283
  },
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
284
+ Cell: React.forwardRef(
285
+ (
286
+ { children, header, isMeasuring, isLastPinned, isLast, isLastCenter },
287
+ ref,
288
+ ) => {
289
+ const { isPinned } = header;
290
+ const { table } = useTableContext();
291
+ return (
292
+ <TableCell
293
+ className="td"
294
+ component="div"
295
+ ref={ref}
296
+ sx={{
297
+ height: "var(--row-height)",
298
+ width: isMeasuring ? "auto" : header.width,
299
+ overflow: "hidden",
300
+ textOverflow: "ellipsis",
301
+ whiteSpace: "nowrap",
302
+ zIndex: isPinned ? 5 : 0,
303
+ boxSizing: "border-box",
304
+ fontSize: "0.875rem",
305
+ color: "text.primary",
306
+ alignItems: "center",
307
+ gap: "8px",
308
+ display: "flex",
309
+ justifyContent: "flex-start",
310
+ alignContent: "center",
311
+ padding: "6px 12px",
312
+ backgroundColor: "var(--row-background-color)",
313
+ borderBottom: "none",
314
+ flexShrink: 0,
315
+ position: "relative",
316
+ borderRight:
317
+ ((isPinned === "start" && !isLastPinned) || !isPinned) &&
318
+ !isLast &&
319
+ !(isLastCenter && table.getIsSomeColumnsPinned("right"))
320
+ ? (theme) => `1px solid ${theme.palette.divider}`
321
+ : undefined,
322
+ borderLeft:
323
+ isPinned === "end" && !isLastPinned
324
+ ? (theme) => `1px solid ${theme.palette.divider}`
325
+ : undefined,
326
+ ".table-row:hover &": {
327
+ backgroundColor: (theme) => {
328
+ // Always use solid background colors for all cells on hover
329
+ return theme.palette.mode === "dark"
330
+ ? "#1e1e52" // Dark blue solid color
331
+ : "#E3F2FD"; // Light blue solid color
332
+ },
333
+ zIndex: isPinned ? 2 : 0,
292
334
  },
293
- zIndex: isPinned ? 2 : 0,
294
- },
295
- }}
296
- >
297
- {children}
298
- </TableCell>
299
- );
300
- }),
335
+ }}
336
+ >
337
+ {children}
338
+ </TableCell>
339
+ );
340
+ },
341
+ ),
301
342
  PinnedColsOverlay: ({ position }) => {
302
343
  const { table } = useTableContext();
303
344
  if (!table.getIsSomeColumnsPinned(position)) {
@@ -321,7 +362,6 @@ const AnoccaSkin: Skin = {
321
362
  if (position === "left") {
322
363
  style.boxShadow =
323
364
  "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
365
  } else if (position === "right") {
326
366
  style.boxShadow =
327
367
  "-4px 0 8px -4px rgba(0, 0, 0, 0.15), -6px 0 12px -6px rgba(0, 0, 0, 0.1)";
@@ -330,51 +370,81 @@ const AnoccaSkin: Skin = {
330
370
  },
331
371
  };
332
372
 
333
- function TableHeaderCell({
334
- headerId,
335
- isPinned,
336
- width,
337
- header,
338
- type,
339
- }: VirtualHeader & {
340
- type: "header" | "footer";
341
- }) {
342
- return (
343
- <TableCell
344
- component="div"
345
- className="th"
346
- data-header-id={headerId}
347
- data-is-pinned={isPinned}
348
- sx={{
349
- transition: "background-color 0.2s ease",
350
- whiteSpace: "nowrap",
351
- zIndex: isPinned ? 1 : 0,
352
- display: "flex",
353
- overflow: "hidden",
354
- height: "var(--header-row-height)",
355
- width,
356
- position: "relative",
357
- flexShrink: 0,
358
- alignItems: "center",
359
- gap: "8px",
360
- justifyContent: "space-between",
361
- padding: "6px 12px",
362
- boxSizing: "border-box",
363
- fontWeight: 600,
364
- backgroundColor: isPinned
365
- ? (theme) => theme.palette.background.paper
366
- : "transparent",
367
- borderRight: (theme) => `1px solid ${theme.palette.divider}`,
368
- }}
369
- >
370
- <div style={{ flex: 1, display: "flex", justifyContent: "flex-start" }}>
371
- {header && !header.isPlaceholder
372
- ? flexRender(header.column.columnDef[type], header.getContext())
373
- : null}
374
- </div>
375
- </TableCell>
376
- );
377
- }
373
+ const TableHeaderCell = React.forwardRef<
374
+ HTMLDivElement,
375
+ VirtualHeader & {
376
+ type: "header" | "footer";
377
+ isLast: boolean;
378
+ isFirst: boolean;
379
+ isLastPinned: boolean;
380
+ isFirstPinned: boolean;
381
+ isLastCenter: boolean;
382
+ isFirstCenter: boolean;
383
+ isMeasuring: boolean;
384
+ }
385
+ >(
386
+ (
387
+ {
388
+ headerId,
389
+ isPinned,
390
+ width,
391
+ header,
392
+ type,
393
+ isLast,
394
+ isLastPinned,
395
+ isLastCenter,
396
+ isMeasuring,
397
+ },
398
+ ref,
399
+ ) => {
400
+ const { table } = useTableContext();
401
+ return (
402
+ <TableCell
403
+ ref={ref}
404
+ component="div"
405
+ className="th"
406
+ data-header-id={headerId}
407
+ data-is-pinned={isPinned}
408
+ sx={{
409
+ transition: "background-color 0.2s ease",
410
+ whiteSpace: "nowrap",
411
+ zIndex: isPinned ? 1 : 0,
412
+ display: "flex",
413
+ overflow: "hidden",
414
+ height: "var(--header-row-height)",
415
+ width: isMeasuring ? "auto" : width,
416
+ position: "relative",
417
+ flexShrink: 0,
418
+ alignItems: "center",
419
+ gap: "8px",
420
+ justifyContent: "space-between",
421
+ padding: "6px 12px",
422
+ boxSizing: "border-box",
423
+ fontWeight: 600,
424
+ backgroundColor: isPinned
425
+ ? (theme) => theme.palette.background.paper
426
+ : "transparent",
427
+ borderRight:
428
+ ((isPinned === "start" && !isLastPinned) || !isPinned) &&
429
+ !isLast &&
430
+ !(isLastCenter && table.getIsSomeColumnsPinned("right"))
431
+ ? (theme) => `1px solid ${theme.palette.divider}`
432
+ : undefined,
433
+ borderLeft:
434
+ isPinned === "end" && !isLastPinned
435
+ ? (theme) => `1px solid ${theme.palette.divider}`
436
+ : undefined,
437
+ }}
438
+ >
439
+ <div style={{ flex: 1, display: "flex", justifyContent: "flex-start" }}>
440
+ {header && !header.isPlaceholder
441
+ ? flexRender(header.column.columnDef[type], header.getContext())
442
+ : null}
443
+ </div>
444
+ </TableCell>
445
+ );
446
+ },
447
+ );
378
448
 
379
449
  export { AnoccaSkin };
380
450