@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.
- package/.storybook/main.ts +18 -0
- package/.storybook/preview.ts +14 -0
- package/CHANGELOG.md +16 -0
- package/README.md +54 -0
- package/index.html +13 -0
- package/package.json +10 -2
- package/src/HeaderPinButtons.tsx +81 -0
- package/src/RowPinButtons.tsx +40 -0
- package/src/index.tsx +161 -91
- package/src/stories/ReactTanstackTableUiStory.mdx +136 -0
- package/src/stories/ReactTanstackTableUiStory.stories.tsx +206 -0
- package/src/stories/ReactTanstackTableUiStoryComponent.tsx +113 -0
- package/src/stories/ScrollbarWidthSpecified.mdx +42 -0
- package/src/stories/createSourceCode.ts +53 -0
- package/vite.config.ts +23 -0
- package/dist/cjs/index.cjs +0 -351
- package/dist/cjs/index.cjs.map +0 -10
- package/dist/cjs/package.json +0 -5
- package/dist/mjs/index.mjs +0 -320
- package/dist/mjs/index.mjs.map +0 -10
- package/dist/mjs/package.json +0 -5
- package/dist/types/index.d.ts +0 -3
@@ -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;
|
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.
|
3
|
+
"version": "1.0.15",
|
4
4
|
"main": "./dist/cjs/index.cjs",
|
5
5
|
"dependencies": {
|
6
|
-
"@rttui/core": "^1.0.
|
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={{
|
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(
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
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
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
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
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
:
|
374
|
-
|
375
|
-
|
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
|
|