Skip to content

Commit a64564c

Browse files
committed
feat: initialize docs with vite
1 parent 54a6944 commit a64564c

16 files changed

Lines changed: 385 additions & 10 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
node_modules/
22
dist/
3-
*.tgz
3+
*.tgz
4+
pnpm-lock.yaml

docs/.gitignore

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?

docs/app.d.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

docs/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>ModuleTSX</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="/src/main.tsx"></script>
11+
</body>
12+
</html>

docs/package.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "docs",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc -b && vite build",
9+
"lint": "eslint .",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"@mdi/js": "^7.4.47",
14+
"react": "^19.2.4",
15+
"react-dom": "^19.2.4",
16+
"soda-material": "^0.0.36"
17+
},
18+
"devDependencies": {
19+
"@types/node": "^24.12.0",
20+
"@types/react": "^19.2.14",
21+
"@types/react-dom": "^19.2.3",
22+
"@vitejs/plugin-react": "^6.0.1",
23+
"typescript": "~5.9.3",
24+
"vite": "^8.0.0"
25+
}
26+
}

docs/App.tsx renamed to docs/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ import {
1717
mdiSendVariantOutline,
1818
mdiShare,
1919
} from "@mdi/js";
20-
import Icon from "@mdi/react";
20+
import { Icon } from "./Icon.tsx";
2121
import {
2222
BottomAppBar,
2323
BottomSheet,
24-
BottomSheetHandle,
24+
type BottomSheetHandle,
2525
Button,
2626
Card,
2727
Checkbox,

docs/src/Icon.tsx

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { forwardRef, useId } from "react";
2+
import type { CSSProperties, SVGProps } from "react";
3+
4+
// export { default as Stack } from "./Stack";
5+
6+
export interface IconProps extends Omit<SVGProps<SVGSVGElement>, "path" | "color" | "rotate"> {
7+
path: string;
8+
size?: number | string | null;
9+
color?: string | null;
10+
horizontal?: boolean;
11+
vertical?: boolean;
12+
rotate?: number;
13+
spin?: boolean | number;
14+
inStack?: boolean;
15+
title?: string | null;
16+
description?: string | null;
17+
}
18+
19+
export const Icon = forwardRef<SVGSVGElement, IconProps>(
20+
(
21+
{
22+
path,
23+
id,
24+
title = null,
25+
description = null,
26+
size = null,
27+
color = "currentColor",
28+
horizontal = false,
29+
vertical = false,
30+
rotate = 0,
31+
spin = false,
32+
style,
33+
inStack = false,
34+
...rest
35+
},
36+
ref,
37+
) => {
38+
const reactId = useId();
39+
const iconId = id ?? reactId;
40+
41+
const computedStyle: CSSProperties = { ...style };
42+
const pathStyle: CSSProperties = {};
43+
const transforms: string[] = [];
44+
45+
if (size !== null) {
46+
if (inStack) {
47+
transforms.push(`scale(${size})`);
48+
} else {
49+
const dimension = typeof size === "string" ? size : `${size * 1.5}rem`;
50+
computedStyle.width = dimension;
51+
computedStyle.height = dimension;
52+
}
53+
}
54+
55+
if (horizontal) transforms.push("scaleX(-1)");
56+
if (vertical) transforms.push("scaleY(-1)");
57+
if (rotate !== 0) transforms.push(`rotate(${rotate}deg)`);
58+
59+
if (color !== null) {
60+
pathStyle.fill = color;
61+
}
62+
63+
// Cast `rest` to SVGProps<SVGPathElement> to satisfy strict event handler target checks
64+
let transformElement = <path d={path} style={pathStyle} {...(inStack ? (rest as SVGProps<SVGPathElement>) : {})} />;
65+
66+
if (transforms.length > 0) {
67+
computedStyle.transform = transforms.join(" ");
68+
computedStyle.transformOrigin = "center";
69+
if (inStack) {
70+
transformElement = (
71+
<g style={computedStyle}>
72+
{transformElement}
73+
<rect width="24" height="24" fill="transparent" />
74+
</g>
75+
);
76+
}
77+
}
78+
79+
let spinElement = transformElement;
80+
const spinSec = spin === true || typeof spin !== "number" ? 2 : spin;
81+
let inverse = !inStack && (horizontal || vertical);
82+
83+
if (spinSec < 0) {
84+
inverse = !inverse;
85+
}
86+
87+
if (spin) {
88+
spinElement = (
89+
<g
90+
style={{
91+
animation: `spin${inverse ? "-inverse" : ""} linear ${Math.abs(spinSec)}s infinite`,
92+
transformOrigin: "center",
93+
}}
94+
>
95+
{transformElement}
96+
{!(horizontal || vertical || rotate !== 0) && <rect width="24" height="24" fill="transparent" />}
97+
</g>
98+
);
99+
}
100+
101+
if (inStack) {
102+
return spinElement;
103+
}
104+
105+
const labelledById = `icon_labelledby_${iconId}`;
106+
const describedById = `icon_describedby_${iconId}`;
107+
let ariaLabelledby;
108+
let role;
109+
110+
if (title) {
111+
ariaLabelledby = description ? `${labelledById} ${describedById}` : labelledById;
112+
} else {
113+
role = "presentation";
114+
if (description) {
115+
throw new Error("title attribute required when description is set");
116+
}
117+
}
118+
119+
return (
120+
<svg ref={ref} viewBox="0 0 24 24" style={computedStyle} role={role} aria-labelledby={ariaLabelledby} {...rest}>
121+
{title && <title id={labelledById}>{title}</title>}
122+
{description && <desc id={describedById}>{description}</desc>}
123+
124+
{!inStack && spin && (
125+
<style>
126+
{inverse
127+
? "@keyframes spin-inverse { from { transform: rotate(0deg) } to { transform: rotate(-360deg) } }"
128+
: "@keyframes spin { from { transform: rotate(0deg) } to { transform: rotate(360deg) } }"}
129+
</style>
130+
)}
131+
132+
{spinElement}
133+
</svg>
134+
);
135+
},
136+
);
137+
138+
Icon.displayName = "Icon";
139+
140+
export default Icon;

docs/src/Stack.tsx

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import React, { forwardRef, useId } from "react";
2+
import type { CSSProperties, ReactElement, SVGProps } from "react";
3+
import type { IconProps } from "./Icon.tsx";
4+
5+
export interface StackProps extends Omit<SVGProps<SVGSVGElement>, "children" | "color" | "rotate"> {
6+
title?: string | null;
7+
description?: string | null;
8+
size?: number | string | null;
9+
color?: string | null;
10+
horizontal?: boolean | null;
11+
vertical?: boolean | null;
12+
rotate?: number | null;
13+
spin?: boolean | number | null;
14+
children: ReactElement<IconProps> | ReactElement<IconProps>[];
15+
}
16+
17+
export const Stack = forwardRef<SVGSVGElement, StackProps>(
18+
(
19+
{
20+
title = null,
21+
description = null,
22+
size = null,
23+
color = null,
24+
horizontal = null,
25+
vertical = null,
26+
rotate = null,
27+
spin = null,
28+
style,
29+
children,
30+
id,
31+
...rest
32+
},
33+
ref,
34+
) => {
35+
const reactId = useId();
36+
const stackId = id ?? reactId;
37+
38+
let anySpin = spin === null ? false : spin;
39+
40+
const childrenWithProps = React.Children.map(children, (child) => {
41+
if (!React.isValidElement(child)) return child;
42+
43+
const childElement = child as ReactElement<IconProps>;
44+
45+
if (anySpin !== true) {
46+
anySpin = (spin === null ? childElement.props.spin : spin) === true;
47+
}
48+
49+
let scaledSize = childElement.props.size;
50+
if (typeof size === "number" && typeof childElement.props.size === "number") {
51+
scaledSize = childElement.props.size / size;
52+
}
53+
54+
const props: Partial<IconProps> = {
55+
size: scaledSize,
56+
color: color === null ? childElement.props.color : color,
57+
horizontal: horizontal === null ? childElement.props.horizontal : horizontal,
58+
vertical: vertical === null ? childElement.props.vertical : vertical,
59+
rotate: rotate === null ? childElement.props.rotate : rotate,
60+
spin: spin === null ? childElement.props.spin : spin,
61+
inStack: true,
62+
};
63+
64+
return React.cloneElement(childElement, props);
65+
});
66+
67+
const computedStyle: CSSProperties = { ...style };
68+
69+
if (size !== null) {
70+
computedStyle.width = typeof size === "string" ? size : `${size * 1.5}rem`;
71+
}
72+
73+
const labelledById = `stack_labelledby_${stackId}`;
74+
const describedById = `stack_describedby_${stackId}`;
75+
let ariaLabelledby;
76+
let role;
77+
78+
if (title) {
79+
ariaLabelledby = description ? `${labelledById} ${describedById}` : labelledById;
80+
} else {
81+
role = "presentation";
82+
if (description) {
83+
throw new Error("title attribute required when description is set");
84+
}
85+
}
86+
87+
return (
88+
<svg ref={ref} viewBox="0 0 24 24" style={computedStyle} role={role} aria-labelledby={ariaLabelledby} {...rest}>
89+
{title && <title id={labelledById}>{title}</title>}
90+
{description && <desc id={describedById}>{description}</desc>}
91+
92+
{anySpin && (
93+
<style>
94+
{"@keyframes spin { from { transform: rotate(0deg) } to { transform: rotate(360deg) } }"}
95+
{"@keyframes spin-inverse { from { transform: rotate(0deg) } to { transform: rotate(-360deg) } }"}
96+
</style>
97+
)}
98+
99+
{childrenWithProps}
100+
</svg>
101+
);
102+
},
103+
);
104+
105+
Stack.displayName = "Stack";
106+
107+
export default Stack;
File renamed without changes.

0 commit comments

Comments
 (0)