@rdicons/react-native 0.6.0 → 0.7.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/README.md +23 -1
- package/dist/effects.js +210 -0
- package/dist/motion.js +106 -0
- package/dist/rd-static.d.ts +1278 -0
- package/dist/rd-static.js +640 -0
- package/dist/rd.js +638 -638
- package/dist/runtime.d.ts +22 -3
- package/dist/runtime.js +163 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,10 +47,32 @@ That writes one `.tsx` file per icon, with no dependency on this package. (`--fo
|
|
|
47
47
|
|
|
48
48
|
## Animation
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
The rd icons can move, with React Native's own `Animated` (no extra library):
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { Bell, Rocket } from '@rdicons/react-native/rd'
|
|
54
|
+
|
|
55
|
+
<Bell animate /> {/* plays once when it appears */}
|
|
56
|
+
<Rocket animate="loop" speed={1.5} /> {/* repeats: loading states */}
|
|
57
|
+
|
|
58
|
+
const ref = useRef<RdIconHandle>(null)
|
|
59
|
+
<Pressable onPress={() => ref.current?.play()}><Bell ref={ref} /></Pressable>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The animation is the same as on the web (all 638 rd icons), and it stops when the device asks for reduced motion. Other libraries ignore `animate`. `@rdicons/react-native/rd-static` is the same library without the animation data, about 60% smaller, for apps that do not animate.
|
|
51
63
|
|
|
52
64
|
## Licenses
|
|
53
65
|
|
|
54
66
|
The code of this package is MIT. The icons keep the license of their library (MIT, ISC, Apache-2.0, and CC BY 4.0 for Solar, which requires you to credit the author). The `LICENSES` folder has the full text for each library.
|
|
55
67
|
|
|
68
|
+
|
|
69
|
+
## Colour effects
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
<Folder duotone color="#4f46e5" />
|
|
73
|
+
<Folder gradient={['#ec4899', '#4f46e5']} />
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`duotone` fills closed shapes with a soft second tone; `gradient` makes the line run from one color to another. Details: https://rdicons.vimalbhatt.com/docs/effects
|
|
77
|
+
|
|
56
78
|
Needs React 17+, React Native 0.70+ and `react-native-svg` 13+. ESM, with types. Part of [rdicons](https://rdicons.vimalbhatt.com).
|
package/dist/effects.js
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// ../core/src/effects.ts
|
|
2
|
+
var ARGS = { m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0 };
|
|
3
|
+
var NUM = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g;
|
|
4
|
+
function firstSubpath(d) {
|
|
5
|
+
let cur = { x: 0, y: 0 };
|
|
6
|
+
let start = null;
|
|
7
|
+
let closed = false;
|
|
8
|
+
let min = { x: Infinity, y: Infinity };
|
|
9
|
+
let max = { x: -Infinity, y: -Infinity };
|
|
10
|
+
const add = (p) => {
|
|
11
|
+
min = { x: Math.min(min.x, p.x), y: Math.min(min.y, p.y) };
|
|
12
|
+
max = { x: Math.max(max.x, p.x), y: Math.max(max.y, p.y) };
|
|
13
|
+
};
|
|
14
|
+
for (const m of d.matchAll(/([a-zA-Z])([^a-zA-Z]*)/g)) {
|
|
15
|
+
const cmd = m[1];
|
|
16
|
+
const lower = cmd.toLowerCase();
|
|
17
|
+
const rel = cmd === lower;
|
|
18
|
+
if (!(lower in ARGS)) return null;
|
|
19
|
+
if (lower === "z") {
|
|
20
|
+
if (start) {
|
|
21
|
+
closed = true;
|
|
22
|
+
cur = start;
|
|
23
|
+
}
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
if (lower === "m" && start) break;
|
|
27
|
+
const args = m[2];
|
|
28
|
+
let pos = 0;
|
|
29
|
+
const number = () => {
|
|
30
|
+
while (pos < args.length && /[\s,]/.test(args[pos])) pos++;
|
|
31
|
+
const r = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/y;
|
|
32
|
+
r.lastIndex = pos;
|
|
33
|
+
const x = r.exec(args);
|
|
34
|
+
if (!x) return null;
|
|
35
|
+
pos = r.lastIndex;
|
|
36
|
+
return parseFloat(x[0]);
|
|
37
|
+
};
|
|
38
|
+
const flag = () => {
|
|
39
|
+
while (pos < args.length && /[\s,]/.test(args[pos])) pos++;
|
|
40
|
+
if (args[pos] !== "0" && args[pos] !== "1") return null;
|
|
41
|
+
return Number(args[pos++]);
|
|
42
|
+
};
|
|
43
|
+
let first = true;
|
|
44
|
+
for (; ; ) {
|
|
45
|
+
const ox = rel ? cur.x : 0, oy = rel ? cur.y : 0;
|
|
46
|
+
if (lower === "a") {
|
|
47
|
+
const rx = number(), ry = number(), rot = number(), f1 = flag(), f2 = flag(), x = number(), y = number();
|
|
48
|
+
if ([rx, ry, rot, f1, f2, x, y].some((v) => v == null)) break;
|
|
49
|
+
const end = { x: ox + x, y: oy + y };
|
|
50
|
+
const mid = { x: (cur.x + end.x) / 2, y: (cur.y + end.y) / 2 };
|
|
51
|
+
add({ x: mid.x - Math.abs(rx), y: mid.y - Math.abs(ry) });
|
|
52
|
+
add({ x: mid.x + Math.abs(rx), y: mid.y + Math.abs(ry) });
|
|
53
|
+
cur = end;
|
|
54
|
+
add(cur);
|
|
55
|
+
} else {
|
|
56
|
+
const a = [];
|
|
57
|
+
for (let k = 0; k < ARGS[lower]; k++) {
|
|
58
|
+
const v = number();
|
|
59
|
+
if (v == null) break;
|
|
60
|
+
a.push(v);
|
|
61
|
+
}
|
|
62
|
+
if (a.length < ARGS[lower]) break;
|
|
63
|
+
switch (lower) {
|
|
64
|
+
case "m": {
|
|
65
|
+
cur = { x: ox + a[0], y: oy + a[1] };
|
|
66
|
+
if (first) start = cur;
|
|
67
|
+
add(cur);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case "l":
|
|
71
|
+
case "t": {
|
|
72
|
+
cur = { x: ox + a[0], y: oy + a[1] };
|
|
73
|
+
add(cur);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
case "h": {
|
|
77
|
+
cur = { x: ox + a[0], y: cur.y };
|
|
78
|
+
add(cur);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case "v": {
|
|
82
|
+
cur = { x: cur.x, y: oy + a[0] };
|
|
83
|
+
add(cur);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case "c": {
|
|
87
|
+
add({ x: ox + a[0], y: oy + a[1] });
|
|
88
|
+
add({ x: ox + a[2], y: oy + a[3] });
|
|
89
|
+
cur = { x: ox + a[4], y: oy + a[5] };
|
|
90
|
+
add(cur);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case "s":
|
|
94
|
+
case "q": {
|
|
95
|
+
add({ x: ox + a[0], y: oy + a[1] });
|
|
96
|
+
cur = { x: ox + a[2], y: oy + a[3] };
|
|
97
|
+
add(cur);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
first = false;
|
|
103
|
+
}
|
|
104
|
+
if (!start && lower !== "m") return null;
|
|
105
|
+
}
|
|
106
|
+
if (!start || !isFinite(min.x)) return null;
|
|
107
|
+
add(start);
|
|
108
|
+
return { start, end: cur, closed, min, max };
|
|
109
|
+
}
|
|
110
|
+
var attr = (tag, name) => {
|
|
111
|
+
var _a;
|
|
112
|
+
const m = tag.match(new RegExp(`(?:^|\\s)${name}\\s*=\\s*("([^"]*)"|'([^']*)')`));
|
|
113
|
+
return m ? (_a = m[2]) != null ? _a : m[3] : null;
|
|
114
|
+
};
|
|
115
|
+
var num = (v) => v == null ? null : Number.isFinite(parseFloat(v)) ? parseFloat(v) : null;
|
|
116
|
+
var MIN_SIDE = 5;
|
|
117
|
+
function fillableShapes(body) {
|
|
118
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
119
|
+
if (!/stroke=/.test(body)) return [];
|
|
120
|
+
const out = [];
|
|
121
|
+
let i = -1;
|
|
122
|
+
for (const m of body.matchAll(/<(path|circle|ellipse|rect|polygon|line|polyline)\b[^>]*>/g)) {
|
|
123
|
+
i++;
|
|
124
|
+
const tag = m[0];
|
|
125
|
+
const kind = m[1];
|
|
126
|
+
const ownFill = attr(tag, "fill");
|
|
127
|
+
if (ownFill && ownFill !== "none") continue;
|
|
128
|
+
if (kind === "circle") {
|
|
129
|
+
if (((_a = num(attr(tag, "r"))) != null ? _a : 0) * 2 >= MIN_SIDE) out.push(i);
|
|
130
|
+
} else if (kind === "ellipse") {
|
|
131
|
+
if (((_b = num(attr(tag, "rx"))) != null ? _b : 0) * 2 >= MIN_SIDE && ((_c = num(attr(tag, "ry"))) != null ? _c : 0) * 2 >= MIN_SIDE) out.push(i);
|
|
132
|
+
} else if (kind === "rect") {
|
|
133
|
+
if (((_d = num(attr(tag, "width"))) != null ? _d : 0) >= MIN_SIDE && ((_e = num(attr(tag, "height"))) != null ? _e : 0) >= MIN_SIDE) out.push(i);
|
|
134
|
+
} else if (kind === "polygon") {
|
|
135
|
+
const pts = (_h = (_g = ((_f = attr(tag, "points")) != null ? _f : "").match(NUM)) == null ? void 0 : _g.map(Number)) != null ? _h : [];
|
|
136
|
+
const xs = pts.filter((_, k) => k % 2 === 0), ys = pts.filter((_, k) => k % 2 === 1);
|
|
137
|
+
if (xs.length >= 3 && Math.max(...xs) - Math.min(...xs) >= MIN_SIDE && Math.max(...ys) - Math.min(...ys) >= MIN_SIDE) out.push(i);
|
|
138
|
+
} else if (kind === "path") {
|
|
139
|
+
const sp = firstSubpath((_i = attr(tag, "d")) != null ? _i : "");
|
|
140
|
+
if (!sp) continue;
|
|
141
|
+
const w = sp.max.x - sp.min.x, h = sp.max.y - sp.min.y;
|
|
142
|
+
if (w < MIN_SIDE || h < MIN_SIDE) continue;
|
|
143
|
+
const gap = Math.hypot(sp.end.x - sp.start.x, sp.end.y - sp.start.y);
|
|
144
|
+
if (sp.closed || gap <= Math.max(2.5, 0.35 * Math.min(w, h))) out.push(i);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
var esc = (s) => s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
150
|
+
var safeColor = (c) => /^[#a-zA-Z0-9(),.%\s\-/]+$/.test(c) ? c : "#000000";
|
|
151
|
+
function gradientLine(w, h, angle = 45) {
|
|
152
|
+
const a = angle * Math.PI / 180;
|
|
153
|
+
const dx = Math.cos(a), dy = Math.sin(a);
|
|
154
|
+
const half = (Math.abs(w * dx) + Math.abs(h * dy)) / 2;
|
|
155
|
+
const cx = w / 2, cy = h / 2;
|
|
156
|
+
const r = (n) => Math.round(n * 100) / 100;
|
|
157
|
+
return { x1: r(cx - dx * half), y1: r(cy - dy * half), x2: r(cx + dx * half), y2: r(cy + dy * half) };
|
|
158
|
+
}
|
|
159
|
+
function applyEffects(body, w, h, base, o) {
|
|
160
|
+
var _a, _b, _c;
|
|
161
|
+
const id = ((_a = o.gradientId) != null ? _a : "rdg").replace(/[^a-zA-Z0-9_-]/g, "");
|
|
162
|
+
const g = o.gradient;
|
|
163
|
+
const paint = g ? `url(#${id})` : base;
|
|
164
|
+
let out = body.replace(/currentColor/g, paint);
|
|
165
|
+
if (o.duotone) {
|
|
166
|
+
const idx = new Set(fillableShapes(body));
|
|
167
|
+
if (idx.size) {
|
|
168
|
+
const fill = o.duotone.color ? safeColor(o.duotone.color) : paint;
|
|
169
|
+
const opacity = Math.min(1, Math.max(0, (_b = o.duotone.opacity) != null ? _b : 0.2));
|
|
170
|
+
let i = -1;
|
|
171
|
+
out = out.replace(/<(path|circle|ellipse|rect|polygon|line|polyline)\b([^>]*?)(\/?)>/g, (whole, tagName, rest, slash) => {
|
|
172
|
+
i++;
|
|
173
|
+
if (!idx.has(i)) return whole;
|
|
174
|
+
const cleaned = rest.replace(/\sfill="[^"]*"/, "");
|
|
175
|
+
return `<${tagName}${cleaned} fill="${esc(fill)}" fill-opacity="${opacity}"${slash}>`;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (g) {
|
|
180
|
+
const l = gradientLine(w, h, (_c = g.angle) != null ? _c : 45);
|
|
181
|
+
out = `<defs><linearGradient id="${id}" gradientUnits="userSpaceOnUse" x1="${l.x1}" y1="${l.y1}" x2="${l.x2}" y2="${l.y2}"><stop offset="0" stop-color="${esc(safeColor(g.from))}"/><stop offset="1" stop-color="${esc(safeColor(g.to))}"/></linearGradient></defs>${out}`;
|
|
182
|
+
}
|
|
183
|
+
return out;
|
|
184
|
+
}
|
|
185
|
+
function parseEffectProps(p, gradientId) {
|
|
186
|
+
var _a, _b;
|
|
187
|
+
let duotone = null;
|
|
188
|
+
const d = p.duotone;
|
|
189
|
+
if (d === true || d === "" || d === "true") duotone = {};
|
|
190
|
+
else if (typeof d === "number") duotone = { opacity: d };
|
|
191
|
+
else if (typeof d === "string" && d) duotone = { color: d };
|
|
192
|
+
else if (d && typeof d === "object") duotone = { color: (_a = d.color) != null ? _a : null, opacity: d.opacity };
|
|
193
|
+
let gradient = null;
|
|
194
|
+
const g = p.gradient;
|
|
195
|
+
if (typeof g === "string" && g) {
|
|
196
|
+
const [from, to, angle] = g.split(",").map((x) => x.trim());
|
|
197
|
+
if (from && to) gradient = { from, to, angle: angle !== void 0 && Number.isFinite(Number(angle)) ? Number(angle) : 45 };
|
|
198
|
+
} else if (Array.isArray(g) && g.length >= 2) gradient = { from: String(g[0]), to: String(g[1]), angle: typeof g[2] === "number" ? g[2] : 45 };
|
|
199
|
+
else if (g && typeof g === "object" && "from" in g) gradient = { from: g.from, to: g.to, angle: (_b = g.angle) != null ? _b : 45 };
|
|
200
|
+
if (!duotone && !gradient) return null;
|
|
201
|
+
return { duotone, gradient, gradientId };
|
|
202
|
+
}
|
|
203
|
+
export {
|
|
204
|
+
applyEffects,
|
|
205
|
+
fillableShapes,
|
|
206
|
+
firstSubpath,
|
|
207
|
+
gradientLine,
|
|
208
|
+
parseEffectProps,
|
|
209
|
+
safeColor
|
|
210
|
+
};
|
package/dist/motion.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The maths of the rd animations, with no React Native in it: easing curves, and the keyframes of one property turned into a
|
|
3
|
+
* piecewise-linear table (inputRange / outputRange) that Animated.Value.interpolate can play. The easing of each keyframe interval
|
|
4
|
+
* is baked into the table by sampling it, which is how CSS applies it too (per interval, not over the whole animation).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** cubic-bezier(x1, y1, x2, y2) as a function of time (0..1) to progress */
|
|
8
|
+
export function bezier(x1, y1, x2, y2) {
|
|
9
|
+
const cx = 3 * x1, bx = 3 * (x2 - x1) - cx, ax = 1 - cx - bx
|
|
10
|
+
const cy = 3 * y1, by = 3 * (y2 - y1) - cy, ay = 1 - cy - by
|
|
11
|
+
const sx = (t) => ((ax * t + bx) * t + cx) * t
|
|
12
|
+
const sy = (t) => ((ay * t + by) * t + cy) * t
|
|
13
|
+
const dx = (t) => (3 * ax * t + 2 * bx) * t + cx
|
|
14
|
+
return (x) => {
|
|
15
|
+
if (x <= 0) return 0
|
|
16
|
+
if (x >= 1) return 1
|
|
17
|
+
let t = x
|
|
18
|
+
for (let i = 0; i < 8; i++) {
|
|
19
|
+
const e = sx(t) - x
|
|
20
|
+
if (Math.abs(e) < 1e-6) return sy(t)
|
|
21
|
+
const d = dx(t)
|
|
22
|
+
if (Math.abs(d) < 1e-6) break
|
|
23
|
+
t -= e / d
|
|
24
|
+
}
|
|
25
|
+
let lo = 0, hi = 1
|
|
26
|
+
t = x
|
|
27
|
+
while (lo < hi) {
|
|
28
|
+
const e = sx(t)
|
|
29
|
+
if (Math.abs(e - x) < 1e-6) break
|
|
30
|
+
if (x > e) lo = t
|
|
31
|
+
else hi = t
|
|
32
|
+
t = (hi + lo) / 2
|
|
33
|
+
if (hi - lo < 1e-7) break
|
|
34
|
+
}
|
|
35
|
+
return sy(t)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const IO = bezier(0.42, 0, 0.58, 1)
|
|
40
|
+
const OUT = bezier(0, 0, 0.58, 1)
|
|
41
|
+
|
|
42
|
+
/** 'io' | 'o' | 'l' | 's' | [x1, y1, x2, y2] to an easing function */
|
|
43
|
+
export function easing(e) {
|
|
44
|
+
if (e === 'io') return IO
|
|
45
|
+
if (e === 'o') return OUT
|
|
46
|
+
if (e === 'l') return (u) => u
|
|
47
|
+
if (e === 's') return (u) => (u >= 1 ? 1 : 0) // steps(1, end)
|
|
48
|
+
if (Array.isArray(e)) return bezier(e[0], e[1], e[2], e[3])
|
|
49
|
+
return IO
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const resolve = (v, vars) => (v !== null && typeof v === 'object' ? v.s * (vars.s ?? 1) : v)
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The values of one property over the animation, as { inputRange, outputRange } for Animated.Value.interpolate.
|
|
56
|
+
* frames = [[offset, { tx, ty, r, sx, sy, o, d }], ...] key = 'tx' | 'ty' | 'r' | 'sx' | 'sy' | 'o' | 'd'
|
|
57
|
+
* vars = the element's custom properties ({ s })
|
|
58
|
+
* Returns null when no keyframe sets the property.
|
|
59
|
+
*/
|
|
60
|
+
export function trackOf(frames, key, ease, vars = {}, samples = 12) {
|
|
61
|
+
const own = frames.filter(([, f]) => key in f)
|
|
62
|
+
if (!own.length) return null
|
|
63
|
+
const fn = easing(ease)
|
|
64
|
+
const input = []
|
|
65
|
+
const output = []
|
|
66
|
+
const push = (x, y) => {
|
|
67
|
+
if (input.length && x <= input[input.length - 1]) x = input[input.length - 1] + 1e-6 // strictly increasing, as interpolate needs
|
|
68
|
+
input.push(x)
|
|
69
|
+
output.push(y)
|
|
70
|
+
}
|
|
71
|
+
push(own[0][0], resolve(own[0][1][key], vars))
|
|
72
|
+
for (let i = 1; i < own.length; i++) {
|
|
73
|
+
const [o0, f0] = own[i - 1]
|
|
74
|
+
const [o1, f1] = own[i]
|
|
75
|
+
const v0 = resolve(f0[key], vars)
|
|
76
|
+
const v1 = resolve(f1[key], vars)
|
|
77
|
+
if (ease === 's') {
|
|
78
|
+
// steps(1, end): hold the value of this keyframe until the next one, then jump
|
|
79
|
+
push(o1 - 1e-5, v0)
|
|
80
|
+
push(o1, v1)
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
const n = ease === 'l' || v0 === v1 ? 1 : samples
|
|
84
|
+
for (let s = 1; s <= n; s++) {
|
|
85
|
+
const u = s / n
|
|
86
|
+
push(o0 + (o1 - o0) * u, v0 + (v1 - v0) * fn(u))
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (input[0] > 0) { input.unshift(0); output.unshift(output[0]) }
|
|
90
|
+
if (input[input.length - 1] < 1) { input.push(1); output.push(output[output.length - 1]) }
|
|
91
|
+
return { inputRange: input, outputRange: output }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Evaluates a table at progress u (what interpolate does), for tests and for non-animated previews. */
|
|
95
|
+
export function sample(track, u) {
|
|
96
|
+
const { inputRange: x, outputRange: y } = track
|
|
97
|
+
if (u <= x[0]) return y[0]
|
|
98
|
+
if (u >= x[x.length - 1]) return y[y.length - 1]
|
|
99
|
+
let i = 1
|
|
100
|
+
while (x[i] < u) i++
|
|
101
|
+
const t = (u - x[i - 1]) / (x[i] - x[i - 1])
|
|
102
|
+
return y[i - 1] + (y[i] - y[i - 1]) * t
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Delay in seconds of one animation for an element: the fixed part plus the per-index part (--k), which staggers lists of strokes. */
|
|
106
|
+
export const delayOf = (a, vars = {}) => (a.l ?? 0) + (a.lk ?? 0) * (vars.k ?? 0)
|