@custmaz/layout-icons 0.1.0

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/dist/index.mjs ADDED
@@ -0,0 +1,297 @@
1
+ // src/createIcon.tsx
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function createIcon(name, render) {
4
+ const Icon = ({
5
+ size = 24,
6
+ strokeWidth = 0.8,
7
+ radius = 1,
8
+ variant = "outline",
9
+ title,
10
+ ...props
11
+ }) => {
12
+ const ariaHidden = title == null ? true : void 0;
13
+ const role = title ? "img" : void 0;
14
+ return /* @__PURE__ */ jsxs(
15
+ "svg",
16
+ {
17
+ width: size,
18
+ height: size,
19
+ viewBox: "0 0 24 24",
20
+ fill: variant === "filled" ? "currentColor" : "none",
21
+ stroke: variant === "outline" ? "currentColor" : "none",
22
+ strokeWidth: variant === "outline" ? strokeWidth : void 0,
23
+ strokeLinecap: "round",
24
+ strokeLinejoin: "round",
25
+ focusable: "false",
26
+ "aria-hidden": ariaHidden,
27
+ role,
28
+ ...props,
29
+ children: [
30
+ title && /* @__PURE__ */ jsx("title", { children: title }),
31
+ render({ radius, variant })
32
+ ]
33
+ }
34
+ );
35
+ };
36
+ Icon.displayName = name;
37
+ return Icon;
38
+ }
39
+
40
+ // src/iconLayout.tsx
41
+ function repeat(count, render) {
42
+ return Array.from({ length: count }, (_, i) => render(i));
43
+ }
44
+ function horizontalStack(options) {
45
+ const { count, startX, gap, render } = options;
46
+ return repeat(count, (i) => {
47
+ const x = startX + i * gap;
48
+ return render(x, i);
49
+ });
50
+ }
51
+ function verticalStack(options) {
52
+ const { count, startY, gap, render } = options;
53
+ return repeat(count, (i) => {
54
+ const y = startY + i * gap;
55
+ return render(y, i);
56
+ });
57
+ }
58
+ function grid(options) {
59
+ const { rows, cols, startX, startY, cellSize, gap, render } = options;
60
+ return repeat(
61
+ rows,
62
+ (row) => repeat(cols, (col) => {
63
+ const x = startX + col * (cellSize + gap);
64
+ const y = startY + row * (cellSize + gap);
65
+ return render(x, y, row, col);
66
+ })
67
+ );
68
+ }
69
+
70
+ // src/icons/Grid.tsx
71
+ import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
72
+ var Grid = createIcon("Grid", ({ radius }) => /* @__PURE__ */ jsx2(Fragment, { children: grid({
73
+ rows: 2,
74
+ cols: 2,
75
+ startX: 2,
76
+ startY: 2,
77
+ cellSize: 7,
78
+ gap: 1.5,
79
+ render: (x, y, row, col) => /* @__PURE__ */ jsx2(
80
+ "rect",
81
+ {
82
+ x,
83
+ y,
84
+ width: 7,
85
+ height: 7,
86
+ rx: radius
87
+ },
88
+ `${row}-${col}`
89
+ )
90
+ }) }));
91
+
92
+ // src/icons/Grid3x3.tsx
93
+ import { Fragment as Fragment2, jsx as jsx3 } from "react/jsx-runtime";
94
+ var Grid3x3 = createIcon("Grid3x3", ({ radius }) => /* @__PURE__ */ jsx3(Fragment2, { children: grid({
95
+ rows: 3,
96
+ cols: 3,
97
+ startX: 2,
98
+ startY: 2,
99
+ cellSize: 5,
100
+ gap: 1.5,
101
+ render: (x, y, row, col) => /* @__PURE__ */ jsx3(
102
+ "rect",
103
+ {
104
+ x,
105
+ y,
106
+ width: 5,
107
+ height: 5,
108
+ rx: radius
109
+ },
110
+ `${row}-${col}`
111
+ )
112
+ }) }));
113
+
114
+ // src/icons/Masonry.tsx
115
+ import { Fragment as Fragment3, jsx as jsx4 } from "react/jsx-runtime";
116
+ var Masonry = createIcon("Masonry", ({ radius }) => {
117
+ const blocks = [
118
+ { x: 3, y: 3, width: 6, height: 18 },
119
+ { x: 11, y: 3, width: 5, height: 10 },
120
+ { x: 11, y: 15, width: 5, height: 6 },
121
+ { x: 18, y: 3, width: 3, height: 18 }
122
+ ];
123
+ return /* @__PURE__ */ jsx4(Fragment3, { children: blocks.map((props, i) => /* @__PURE__ */ jsx4("rect", { ...props, rx: radius }, i)) });
124
+ });
125
+
126
+ // src/icons/List.tsx
127
+ import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
128
+ var List = createIcon("List", ({ radius }) => {
129
+ const rows = [
130
+ { iconY: 4, textY: 5.5 },
131
+ { iconY: 10, textY: 11.5 },
132
+ { iconY: 16, textY: 17.5 }
133
+ ];
134
+ return /* @__PURE__ */ jsx5(Fragment4, { children: rows.map(({ iconY, textY }, i) => /* @__PURE__ */ jsxs2("g", { children: [
135
+ /* @__PURE__ */ jsx5(
136
+ "rect",
137
+ {
138
+ x: 3,
139
+ y: iconY,
140
+ width: 5,
141
+ height: 5,
142
+ rx: radius
143
+ }
144
+ ),
145
+ /* @__PURE__ */ jsx5(
146
+ "rect",
147
+ {
148
+ x: 11,
149
+ y: textY,
150
+ width: 10,
151
+ height: 2,
152
+ rx: 1
153
+ }
154
+ )
155
+ ] }, i)) });
156
+ });
157
+
158
+ // src/icons/Tall.tsx
159
+ import { Fragment as Fragment5, jsx as jsx6 } from "react/jsx-runtime";
160
+ var Tall = createIcon("Tall", ({ radius }) => /* @__PURE__ */ jsx6(Fragment5, { children: horizontalStack({
161
+ count: 3,
162
+ startX: 3,
163
+ gap: 6.5,
164
+ render: (x, i) => /* @__PURE__ */ jsx6(
165
+ "rect",
166
+ {
167
+ x,
168
+ y: 3,
169
+ width: 5,
170
+ height: 18,
171
+ rx: radius
172
+ },
173
+ i
174
+ )
175
+ }) }));
176
+
177
+ // src/icons/Landscape.tsx
178
+ import { Fragment as Fragment6, jsx as jsx7 } from "react/jsx-runtime";
179
+ var Landscape = createIcon("Landscape", ({ radius }) => {
180
+ const rows = [
181
+ { y: 3, height: 5 },
182
+ { y: 10, height: 5 },
183
+ { y: 17, height: 4 }
184
+ ];
185
+ return /* @__PURE__ */ jsx7(Fragment6, { children: rows.map(({ y, height }, i) => /* @__PURE__ */ jsx7(
186
+ "rect",
187
+ {
188
+ x: 3,
189
+ y,
190
+ width: 18,
191
+ height,
192
+ rx: radius
193
+ },
194
+ i
195
+ )) });
196
+ });
197
+
198
+ // src/icons/Card.tsx
199
+ import { Fragment as Fragment7, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
200
+ var Card = createIcon("Card", ({ radius, variant }) => {
201
+ const outerPadding = 4;
202
+ const size = 16;
203
+ return /* @__PURE__ */ jsxs3(Fragment7, { children: [
204
+ /* @__PURE__ */ jsx8(
205
+ "rect",
206
+ {
207
+ x: outerPadding,
208
+ y: outerPadding,
209
+ width: size,
210
+ height: size,
211
+ rx: radius + 1
212
+ }
213
+ ),
214
+ variant === "outline" && /* @__PURE__ */ jsx8(
215
+ "rect",
216
+ {
217
+ x: 6,
218
+ y: 7,
219
+ width: 12,
220
+ height: 2,
221
+ rx: 1
222
+ }
223
+ )
224
+ ] });
225
+ });
226
+
227
+ // src/icons/Split.tsx
228
+ import { Fragment as Fragment8, jsx as jsx9 } from "react/jsx-runtime";
229
+ var Split = createIcon("Split", ({ radius }) => /* @__PURE__ */ jsx9(Fragment8, { children: horizontalStack({
230
+ count: 2,
231
+ startX: 3,
232
+ gap: 10,
233
+ render: (x, i) => /* @__PURE__ */ jsx9(
234
+ "rect",
235
+ {
236
+ x,
237
+ y: 3,
238
+ width: 8,
239
+ height: 18,
240
+ rx: radius
241
+ },
242
+ i
243
+ )
244
+ }) }));
245
+
246
+ // src/icons/HamburgerMenu.tsx
247
+ import { Fragment as Fragment9, jsx as jsx10 } from "react/jsx-runtime";
248
+ var HamburgerMenu = createIcon(
249
+ "HamburgerMenu",
250
+ ({ radius }) => /* @__PURE__ */ jsx10(Fragment9, { children: verticalStack({
251
+ count: 3,
252
+ startY: 5,
253
+ gap: 5.75,
254
+ render: (y, i) => /* @__PURE__ */ jsx10(
255
+ "rect",
256
+ {
257
+ x: 3,
258
+ y,
259
+ width: 18,
260
+ height: 2.5,
261
+ rx: radius
262
+ },
263
+ i
264
+ )
265
+ }) })
266
+ );
267
+
268
+ // src/icons/Kebab.tsx
269
+ import { Fragment as Fragment10, jsx as jsx11 } from "react/jsx-runtime";
270
+ var Kebab = createIcon("Kebab", () => /* @__PURE__ */ jsx11(Fragment10, { children: horizontalStack({
271
+ count: 3,
272
+ startX: 6,
273
+ gap: 6,
274
+ render: (x, i) => /* @__PURE__ */ jsx11("circle", { cx: x, cy: 12, r: 1.5 }, i)
275
+ }) }));
276
+
277
+ // src/icons/Meatballs.tsx
278
+ import { Fragment as Fragment11, jsx as jsx12 } from "react/jsx-runtime";
279
+ var Meatballs = createIcon("Meatballs", () => /* @__PURE__ */ jsx12(Fragment11, { children: verticalStack({
280
+ count: 3,
281
+ startY: 6,
282
+ gap: 6,
283
+ render: (y, i) => /* @__PURE__ */ jsx12("circle", { cx: 12, cy: y, r: 1.5 }, i)
284
+ }) }));
285
+ export {
286
+ Card,
287
+ Grid,
288
+ Grid3x3,
289
+ HamburgerMenu,
290
+ Kebab,
291
+ Landscape,
292
+ List,
293
+ Masonry,
294
+ Meatballs,
295
+ Split,
296
+ Tall
297
+ };
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@custmaz/layout-icons",
3
+ "version": "0.1.0",
4
+ "description": "A small set of layout-focused SVG icons for React, designed for UI structure and composition.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/custmaz/layout-icons.git"
9
+ },
10
+ "homepage": "https://github.com/custmaz/layout-icons",
11
+ "bugs": {
12
+ "url": "https://github.com/custmaz/layout-icons/issues"
13
+ },
14
+ "main": "dist/index.cjs",
15
+ "module": "dist/index.js",
16
+ "types": "dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "src",
27
+ "tsconfig.json",
28
+ "LICENSE",
29
+ "README.md",
30
+ "CHANGELOG.md"
31
+ ],
32
+ "sideEffects": false,
33
+ "scripts": {
34
+ "build": "tsup src/index.tsx --format esm,cjs --dts",
35
+ "prepublishOnly": "npm run build"
36
+ },
37
+ "peerDependencies": {
38
+ "react": ">=17"
39
+ },
40
+ "devDependencies": {
41
+ "@types/react": ">=17",
42
+ "tsup": "^8.5.1",
43
+ "typescript": "^5.9.3"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "keywords": [
49
+ "react",
50
+ "icons",
51
+ "svg",
52
+ "layout",
53
+ "grid",
54
+ "masonry",
55
+ "card",
56
+ "gallery",
57
+ "ui",
58
+ "design-system",
59
+ "react-icons",
60
+ "menu",
61
+ "accessibility",
62
+ "themeable"
63
+ ]
64
+ }
@@ -0,0 +1,45 @@
1
+ import * as React from "react";
2
+ import { IconProps } from "./types";
3
+
4
+ export function createIcon(
5
+ name: string,
6
+ render: (ctx: {
7
+ radius: number;
8
+ variant: "outline" | "filled";
9
+ }) => React.ReactNode
10
+ ) {
11
+ const Icon = ({
12
+ size = 24,
13
+ strokeWidth = 0.8,
14
+ radius = 1,
15
+ variant = "outline",
16
+ title,
17
+ ...props
18
+ }: IconProps) => {
19
+ const ariaHidden = title == null ? true : undefined;
20
+ const role = title ? "img" : undefined;
21
+
22
+ return (
23
+ <svg
24
+ width={size}
25
+ height={size}
26
+ viewBox="0 0 24 24"
27
+ fill={variant === "filled" ? "currentColor" : "none"}
28
+ stroke={variant === "outline" ? "currentColor" : "none"}
29
+ strokeWidth={variant === "outline" ? strokeWidth : undefined}
30
+ strokeLinecap="round"
31
+ strokeLinejoin="round"
32
+ focusable="false"
33
+ aria-hidden={ariaHidden}
34
+ role={role}
35
+ {...props}
36
+ >
37
+ {title && <title>{title}</title>}
38
+ {render({ radius, variant })}
39
+ </svg>
40
+ );
41
+ };
42
+
43
+ Icon.displayName = name;
44
+ return Icon;
45
+ }
@@ -0,0 +1,70 @@
1
+ import * as React from "react";
2
+
3
+ // util
4
+ export function repeat(count: number, render: (index: number) => React.ReactNode) {
5
+ return Array.from({ length: count }, (_, i) => render(i));
6
+ }
7
+
8
+ // types
9
+ type HorizontalStackOptions = {
10
+ count: number;
11
+ startX: number;
12
+ gap: number;
13
+ render: (x: number, index: number) => React.ReactNode;
14
+ };
15
+
16
+ type VerticalStackOptions = {
17
+ count: number;
18
+ startY: number;
19
+ gap: number;
20
+ render: (y: number, index: number) => React.ReactNode;
21
+ };
22
+
23
+ type GridOptions = {
24
+ rows: number;
25
+ cols: number;
26
+ startX: number;
27
+ startY: number;
28
+ cellSize: number;
29
+ gap: number;
30
+
31
+ render: (
32
+ x: number,
33
+ y: number,
34
+ row: number,
35
+ col: number
36
+ ) => React.ReactNode;
37
+ };
38
+
39
+
40
+ // layout helpers
41
+ export function horizontalStack(options: HorizontalStackOptions) {
42
+ const { count, startX, gap, render } = options;
43
+
44
+ return repeat(count, (i) => {
45
+ const x = startX + i * gap;
46
+ return render(x, i);
47
+ });
48
+ }
49
+
50
+ export function verticalStack(options: VerticalStackOptions) {
51
+ const { count, startY, gap, render } = options;
52
+
53
+ return repeat(count, (i) => {
54
+ const y = startY + i * gap;
55
+ return render(y, i);
56
+ });
57
+ }
58
+
59
+ export function grid(options: GridOptions) {
60
+ const { rows, cols, startX, startY, cellSize, gap, render } = options;
61
+
62
+ return repeat(rows, (row) =>
63
+ repeat(cols, (col) => {
64
+ const x = startX + col * (cellSize + gap);
65
+ const y = startY + row * (cellSize + gap);
66
+
67
+ return render(x, y, row, col);
68
+ })
69
+ );
70
+ }
@@ -0,0 +1,28 @@
1
+ import { createIcon } from "../createIcon";
2
+
3
+ export const Card = createIcon("Card", ({ radius, variant }) => {
4
+ const outerPadding = 4;
5
+ const size = 16;
6
+
7
+ return (
8
+ <>
9
+ <rect
10
+ x={outerPadding}
11
+ y={outerPadding}
12
+ width={size}
13
+ height={size}
14
+ rx={radius + 1}
15
+ />
16
+
17
+ {variant === "outline" && (
18
+ <rect
19
+ x={6}
20
+ y={7}
21
+ width={12}
22
+ height={2}
23
+ rx={1}
24
+ />
25
+ )}
26
+ </>
27
+ );
28
+ });
@@ -0,0 +1,25 @@
1
+ import { createIcon } from "../createIcon";
2
+ import { grid } from "../iconLayout";
3
+
4
+ export const Grid = createIcon("Grid", ({ radius }) => (
5
+ <>
6
+ {grid({
7
+ rows: 2,
8
+ cols: 2,
9
+ startX: 2,
10
+ startY: 2,
11
+ cellSize: 7,
12
+ gap: 1.5,
13
+ render: (x, y, row, col) => (
14
+ <rect
15
+ key={`${row}-${col}`}
16
+ x={x}
17
+ y={y}
18
+ width={7}
19
+ height={7}
20
+ rx={radius}
21
+ />
22
+ ),
23
+ })}
24
+ </>
25
+ ));
@@ -0,0 +1,25 @@
1
+ import { createIcon } from "../createIcon";
2
+ import { grid } from "../iconLayout";
3
+
4
+ export const Grid3x3 = createIcon("Grid3x3", ({ radius }) => (
5
+ <>
6
+ {grid({
7
+ rows: 3,
8
+ cols: 3,
9
+ startX: 2,
10
+ startY: 2,
11
+ cellSize: 5,
12
+ gap: 1.5,
13
+ render: (x, y, row, col) => (
14
+ <rect
15
+ key={`${row}-${col}`}
16
+ x={x}
17
+ y={y}
18
+ width={5}
19
+ height={5}
20
+ rx={radius}
21
+ />
22
+ ),
23
+ })}
24
+ </>
25
+ ));
@@ -0,0 +1,23 @@
1
+ import { createIcon } from "../createIcon";
2
+ import { verticalStack } from "../iconLayout";
3
+
4
+ export const HamburgerMenu = createIcon("HamburgerMenu", ({ radius }) => (
5
+ <>
6
+ {verticalStack({
7
+ count: 3,
8
+ startY: 5,
9
+ gap: 5.75,
10
+ render: (y, i) => (
11
+ <rect
12
+ key={i}
13
+ x={3}
14
+ y={y}
15
+ width={18}
16
+ height={2.5}
17
+ rx={radius}
18
+ />
19
+ ),
20
+ })}
21
+ </>
22
+ )
23
+ );
@@ -0,0 +1,15 @@
1
+ import { createIcon } from "../createIcon";
2
+ import { horizontalStack } from "../iconLayout";
3
+
4
+ export const Kebab = createIcon("Kebab", () => (
5
+ <>
6
+ {horizontalStack({
7
+ count: 3,
8
+ startX: 6,
9
+ gap: 6,
10
+ render: (x, i) => (
11
+ <circle key={i} cx={x} cy={12} r={1.5} />
12
+ ),
13
+ })}
14
+ </>
15
+ ));
@@ -0,0 +1,24 @@
1
+ import { createIcon } from "../createIcon";
2
+
3
+ export const Landscape = createIcon("Landscape", ({ radius }) => {
4
+ const rows = [
5
+ { y: 3, height: 5 },
6
+ { y: 10, height: 5 },
7
+ { y: 17, height: 4 },
8
+ ];
9
+
10
+ return (
11
+ <>
12
+ {rows.map(({ y, height }, i) => (
13
+ <rect
14
+ key={i}
15
+ x={3}
16
+ y={y}
17
+ width={18}
18
+ height={height}
19
+ rx={radius}
20
+ />
21
+ ))}
22
+ </>
23
+ );
24
+ });
@@ -0,0 +1,32 @@
1
+ import { createIcon } from "../createIcon";
2
+
3
+ export const List = createIcon("List", ({ radius }) => {
4
+ const rows = [
5
+ { iconY: 4, textY: 5.5 },
6
+ { iconY: 10, textY: 11.5 },
7
+ { iconY: 16, textY: 17.5 },
8
+ ];
9
+
10
+ return (
11
+ <>
12
+ {rows.map(({ iconY, textY }, i) => (
13
+ <g key={i}>
14
+ <rect
15
+ x={3}
16
+ y={iconY}
17
+ width={5}
18
+ height={5}
19
+ rx={radius}
20
+ />
21
+ <rect
22
+ x={11}
23
+ y={textY}
24
+ width={10}
25
+ height={2}
26
+ rx={1}
27
+ />
28
+ </g>
29
+ ))}
30
+ </>
31
+ );
32
+ });
@@ -0,0 +1,18 @@
1
+ import { createIcon } from "../createIcon";
2
+
3
+ export const Masonry = createIcon("Masonry", ({ radius }) => {
4
+ const blocks = [
5
+ { x: 3, y: 3, width: 6, height: 18 },
6
+ { x: 11, y: 3, width: 5, height: 10 },
7
+ { x: 11, y: 15, width: 5, height: 6 },
8
+ { x: 18, y: 3, width: 3, height: 18 },
9
+ ];
10
+
11
+ return (
12
+ <>
13
+ {blocks.map((props, i) => (
14
+ <rect key={i} {...props} rx={radius} />
15
+ ))}
16
+ </>
17
+ );
18
+ });
@@ -0,0 +1,15 @@
1
+ import { createIcon } from "../createIcon";
2
+ import { verticalStack } from "../iconLayout";
3
+
4
+ export const Meatballs = createIcon("Meatballs", () => (
5
+ <>
6
+ {verticalStack({
7
+ count: 3,
8
+ startY: 6,
9
+ gap: 6,
10
+ render: (y, i) => (
11
+ <circle key={i} cx={12} cy={y} r={1.5} />
12
+ ),
13
+ })}
14
+ </>
15
+ ));