react-native-nano-icons 0.1.2 → 0.1.4

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.
Files changed (91) hide show
  1. package/README.md +20 -164
  2. package/android/build.gradle +28 -0
  3. package/android/src/main/java/com/nanoicons/NanoIconView.kt +78 -0
  4. package/android/src/main/java/com/nanoicons/NanoIconViewManager.kt +84 -0
  5. package/android/src/main/java/com/nanoicons/NanoIconsPackage.kt +22 -0
  6. package/ios/NanoIconView.h +4 -0
  7. package/ios/NanoIconView.mm +286 -0
  8. package/lib/commonjs/cli/build.js +1 -1
  9. package/lib/commonjs/cli/config.d.ts +2 -2
  10. package/lib/commonjs/cli/config.js +7 -6
  11. package/lib/commonjs/scripts/cli.js +15 -5
  12. package/lib/commonjs/src/core/font/compile.d.ts +13 -2
  13. package/lib/commonjs/src/core/font/compile.js +49 -46
  14. package/lib/commonjs/src/core/pipeline/managers.js +19 -3
  15. package/lib/commonjs/src/core/pipeline/run.js +121 -32
  16. package/lib/commonjs/src/core/svg/layers.d.ts +16 -0
  17. package/lib/commonjs/src/core/svg/layers.js +27 -0
  18. package/lib/commonjs/src/core/svg/svg_dom.d.ts +29 -1
  19. package/lib/commonjs/src/core/svg/svg_dom.js +78 -2
  20. package/lib/commonjs/src/core/svg/svg_pathops.d.ts +11 -0
  21. package/lib/commonjs/src/core/svg/svg_pathops.js +209 -19
  22. package/lib/commonjs/src/core/types.d.ts +30 -15
  23. package/lib/module/core/font/compile.js +52 -41
  24. package/lib/module/core/font/compile.js.map +1 -1
  25. package/lib/module/core/pipeline/managers.js +17 -3
  26. package/lib/module/core/pipeline/managers.js.map +1 -1
  27. package/lib/module/core/pipeline/run.js +131 -44
  28. package/lib/module/core/pipeline/run.js.map +1 -1
  29. package/lib/module/core/shims/picosvg-0.22.3-py3-none-any.whl +0 -0
  30. package/lib/module/core/svg/layers.js +34 -0
  31. package/lib/module/core/svg/layers.js.map +1 -1
  32. package/lib/module/core/svg/svg_dom.js +91 -4
  33. package/lib/module/core/svg/svg_dom.js.map +1 -1
  34. package/lib/module/core/svg/svg_pathops.js +203 -19
  35. package/lib/module/core/svg/svg_pathops.js.map +1 -1
  36. package/lib/module/createNanoIconsSet.js +3 -79
  37. package/lib/module/createNanoIconsSet.js.map +1 -1
  38. package/lib/module/createNanoIconsSet.native.js +108 -0
  39. package/lib/module/createNanoIconsSet.native.js.map +1 -0
  40. package/lib/module/createNanoIconsSet.shared.js +91 -0
  41. package/lib/module/createNanoIconsSet.shared.js.map +1 -0
  42. package/lib/module/index.js +1 -2
  43. package/lib/module/index.js.map +1 -1
  44. package/lib/module/specs/NanoIconViewNativeComponent.ts +15 -0
  45. package/lib/module/types.js +4 -0
  46. package/lib/module/types.js.map +1 -0
  47. package/lib/module/utils/shallowEqualColor.js +15 -0
  48. package/lib/module/utils/shallowEqualColor.js.map +1 -0
  49. package/lib/typescript/src/core/font/compile.d.ts +13 -2
  50. package/lib/typescript/src/core/font/compile.d.ts.map +1 -1
  51. package/lib/typescript/src/core/pipeline/managers.d.ts.map +1 -1
  52. package/lib/typescript/src/core/pipeline/run.d.ts.map +1 -1
  53. package/lib/typescript/src/core/svg/layers.d.ts +16 -0
  54. package/lib/typescript/src/core/svg/layers.d.ts.map +1 -1
  55. package/lib/typescript/src/core/svg/svg_dom.d.ts +29 -1
  56. package/lib/typescript/src/core/svg/svg_dom.d.ts.map +1 -1
  57. package/lib/typescript/src/core/svg/svg_pathops.d.ts +11 -0
  58. package/lib/typescript/src/core/svg/svg_pathops.d.ts.map +1 -1
  59. package/lib/typescript/src/core/types.d.ts +30 -15
  60. package/lib/typescript/src/core/types.d.ts.map +1 -1
  61. package/lib/typescript/src/createNanoIconsSet.d.ts +5 -18
  62. package/lib/typescript/src/createNanoIconsSet.d.ts.map +1 -1
  63. package/lib/typescript/src/createNanoIconsSet.native.d.ts +7 -0
  64. package/lib/typescript/src/createNanoIconsSet.native.d.ts.map +1 -0
  65. package/lib/typescript/src/createNanoIconsSet.shared.d.ts +11 -0
  66. package/lib/typescript/src/createNanoIconsSet.shared.d.ts.map +1 -0
  67. package/lib/typescript/src/index.d.ts.map +1 -1
  68. package/lib/typescript/src/specs/NanoIconViewNativeComponent.d.ts +14 -0
  69. package/lib/typescript/src/specs/NanoIconViewNativeComponent.d.ts.map +1 -0
  70. package/lib/typescript/src/types.d.ts +19 -0
  71. package/lib/typescript/src/types.d.ts.map +1 -0
  72. package/lib/typescript/src/utils/shallowEqualColor.d.ts +4 -0
  73. package/lib/typescript/src/utils/shallowEqualColor.d.ts.map +1 -0
  74. package/package.json +22 -5
  75. package/react-native-nano-icons.podspec +18 -0
  76. package/scripts/cli.ts +14 -5
  77. package/src/core/font/compile.ts +65 -61
  78. package/src/core/pipeline/managers.ts +26 -3
  79. package/src/core/pipeline/run.ts +156 -38
  80. package/src/core/shims/picosvg-0.22.3-py3-none-any.whl +0 -0
  81. package/src/core/svg/layers.ts +44 -0
  82. package/src/core/svg/svg_dom.ts +96 -4
  83. package/src/core/svg/svg_pathops.ts +245 -27
  84. package/src/core/types.ts +21 -10
  85. package/src/createNanoIconsSet.native.tsx +140 -0
  86. package/src/createNanoIconsSet.shared.tsx +121 -0
  87. package/src/createNanoIconsSet.tsx +7 -126
  88. package/src/index.ts +1 -2
  89. package/src/specs/NanoIconViewNativeComponent.ts +15 -0
  90. package/src/types.ts +27 -0
  91. package/src/utils/shallowEqualColor.ts +17 -0
@@ -0,0 +1,121 @@
1
+ import { memo, useMemo } from 'react';
2
+ import { PixelRatio, Platform, Text, View, type TextProps } from 'react-native';
3
+ import type { NanoGlyphMapInput, GlyphEntry } from './core/types';
4
+ import type { IconComponent, IconProps } from './types';
5
+ import { shallowEqualColor } from './utils/shallowEqualColor';
6
+
7
+ export type { IconComponent, IconProps };
8
+ export { shallowEqualColor };
9
+
10
+ const DEFAULT_ICON_SIZE = 12;
11
+
12
+ /**
13
+ * JS implementation using <View> + <Text> layers.
14
+ * Used on web and as a fallback when native component is unavailable (e.g. Expo Go).
15
+ */
16
+ export function createJSIconSet<GM extends NanoGlyphMapInput>(
17
+ glyphMap: GM
18
+ ): IconComponent<GM> {
19
+ const fontBasename = glyphMap.m.f;
20
+
21
+ const fontReference = Platform.select({
22
+ windows: `/Assets/${fontBasename}`,
23
+ default: fontBasename,
24
+ });
25
+
26
+ const styleOverrides: TextProps['style'] = {
27
+ fontFamily: fontReference,
28
+ fontWeight: 'normal',
29
+ fontStyle: 'normal',
30
+ position: 'absolute',
31
+ includeFontPadding: false,
32
+ bottom: 0,
33
+ };
34
+
35
+ const unitsPerEm = glyphMap.m.u;
36
+
37
+ const resolveEntry = (name: keyof GM['i']): GlyphEntry => {
38
+ return (glyphMap.i[name as string] ?? [
39
+ unitsPerEm,
40
+ [[63, 'black']],
41
+ ]) as GlyphEntry;
42
+ };
43
+
44
+ const codepointCache = new Map<number, string>();
45
+ const getChar = (codepoint: number): string => {
46
+ let ch = codepointCache.get(codepoint);
47
+ if (ch === undefined) {
48
+ ch = String.fromCodePoint(codepoint);
49
+ codepointCache.set(codepoint, ch);
50
+ }
51
+ return ch;
52
+ };
53
+
54
+ const Icon = memo(
55
+ ({
56
+ name,
57
+ size = DEFAULT_ICON_SIZE,
58
+ color,
59
+ style,
60
+ allowFontScaling = true,
61
+ accessible,
62
+ accessibilityLabel,
63
+ accessibilityRole = 'image',
64
+ testID,
65
+ ref,
66
+ }: IconProps<keyof GM['i']>) => {
67
+ const fontScale = allowFontScaling ? PixelRatio.getFontScale() : 1;
68
+ const [adv, layers] = resolveEntry(name);
69
+ const scaledSize = size * fontScale;
70
+ const width = (adv / unitsPerEm) * scaledSize;
71
+
72
+ const colorArray = Array.isArray(color) ? color : [color];
73
+ const lastPaletteColor = colorArray?.length
74
+ ? colorArray[colorArray.length - 1]
75
+ : undefined;
76
+
77
+ const containerStyle = useMemo(
78
+ () => [{ height: scaledSize, width, bottom: 0 as const }, style],
79
+ [scaledSize, width, style]
80
+ );
81
+
82
+ const sizeStyle = useMemo(() => ({ fontSize: size }), [size]);
83
+
84
+ return (
85
+ <View
86
+ ref={ref}
87
+ style={containerStyle}
88
+ accessible={accessible}
89
+ accessibilityRole={accessibilityRole}
90
+ accessibilityLabel={accessibilityLabel ?? (name as string)}
91
+ testID={testID}>
92
+ {layers.map(([codepoint, srcColor], i) => {
93
+ const layerColor =
94
+ colorArray?.[i] ?? lastPaletteColor ?? srcColor ?? 'black';
95
+
96
+ return (
97
+ <Text
98
+ key={i}
99
+ selectable={false}
100
+ accessible={false}
101
+ allowFontScaling={allowFontScaling}
102
+ style={[styleOverrides, sizeStyle, { color: layerColor }]}>
103
+ {getChar(codepoint)}
104
+ </Text>
105
+ );
106
+ })}
107
+ </View>
108
+ );
109
+ },
110
+ (prev, next) =>
111
+ prev.name === next.name &&
112
+ prev.size === next.size &&
113
+ prev.allowFontScaling === next.allowFontScaling &&
114
+ prev.style === next.style &&
115
+ shallowEqualColor(prev.color, next.color)
116
+ );
117
+
118
+ Icon.displayName = `NanoIcon(${fontBasename})`;
119
+
120
+ return Icon;
121
+ }
@@ -1,131 +1,12 @@
1
- import { forwardRef, type ComponentRef, type Ref } from 'react';
2
- import {
3
- Platform,
4
- Text,
5
- View,
6
- type ViewProps,
7
- type ColorValue,
8
- type TextProps,
9
- useWindowDimensions,
10
- } from 'react-native';
11
- import type { GlyphEntry, NanoGlyphMap } from './core/types';
1
+ import type { NanoGlyphMapInput } from './core/types';
2
+ import type { IconComponent } from './types';
3
+ import { createJSIconSet } from './createNanoIconsSet.shared';
12
4
 
13
- const DEFAULT_ICON_SIZE = 12;
5
+ export type { IconComponent, IconProps } from './types';
6
+ export { shallowEqualColor } from './utils/shallowEqualColor';
14
7
 
15
- type ViewRef = ComponentRef<typeof View>;
16
-
17
- export type IconProps<Name> = TextProps & {
18
- name: Name;
19
- size?: number;
20
- colorPalette?: ColorValue[];
21
- innerRef?: Ref<ViewRef>;
22
- };
23
-
24
- export type IconComponent<GM extends NanoGlyphMap> = React.FC<
25
- TextProps & {
26
- name: keyof GM['icons'];
27
- size?: number;
28
- colorPalette?: ColorValue[];
29
- innerRef?: Ref<ViewRef>;
30
- } & React.RefAttributes<ViewRef>
31
- >;
32
-
33
- export function createIconSet<GM extends NanoGlyphMap>(
8
+ export function createIconSet<GM extends NanoGlyphMapInput>(
34
9
  glyphMap: GM
35
10
  ): IconComponent<GM> {
36
- const fontBasename = glyphMap.meta.fontFamily;
37
-
38
- const fontReference = Platform.select({
39
- windows: `/Assets/${fontBasename}`,
40
- android: fontBasename,
41
- default: fontBasename,
42
- });
43
-
44
- const styleOverrides: TextProps['style'] = {
45
- fontFamily: fontReference,
46
- fontWeight: 'normal',
47
- fontStyle: 'normal',
48
- position: 'absolute',
49
- includeFontPadding: false,
50
- bottom: 0,
51
- };
52
-
53
- const resolveEntry = (name: keyof GM['icons']): GlyphEntry => {
54
- return (
55
- glyphMap.icons[name as string] ?? {
56
- adv: glyphMap.meta.upm,
57
- layers: [{ codepoint: 63, color: 'black' }], // "?"
58
- }
59
- );
60
- };
61
-
62
- const Icon = ({
63
- name,
64
- size = DEFAULT_ICON_SIZE,
65
- colorPalette,
66
- style,
67
- allowFontScaling = true,
68
- innerRef,
69
- ...props
70
- }: IconProps<keyof GM['icons']>) => {
71
- const { fontScale } = useWindowDimensions();
72
-
73
- const entry = resolveEntry(name);
74
- const layers = entry.layers ?? [];
75
-
76
- const scaledSize = allowFontScaling ? size * fontScale : size;
77
- const width = (entry.adv / glyphMap.meta.upm) * scaledSize;
78
-
79
- const containerProps: ViewProps = {
80
- style: {
81
- height: scaledSize,
82
- width,
83
- bottom: 0,
84
- },
85
- };
86
-
87
- const lastPaletteColor = colorPalette?.length
88
- ? colorPalette[colorPalette.length - 1]
89
- : undefined;
90
-
91
- return (
92
- <View
93
- nativeID={`nano-icon-container-${String(name)}`}
94
- ref={innerRef}
95
- {...containerProps}
96
- >
97
- {layers.map(({ codepoint, color: srcColor }, i) => {
98
- const layerColor =
99
- colorPalette?.[i] ?? lastPaletteColor ?? srcColor ?? 'black';
100
-
101
- return (
102
- <Text
103
- key={`${codepoint}-${i}`}
104
- selectable={false}
105
- {...props}
106
- allowFontScaling={allowFontScaling}
107
- style={[
108
- style,
109
- styleOverrides,
110
- {
111
- fontSize: size,
112
- color: layerColor,
113
- },
114
- ]}
115
- >
116
- {String.fromCodePoint(codepoint)}
117
- </Text>
118
- );
119
- })}
120
- </View>
121
- );
122
- };
123
-
124
- const WrappedIcon = forwardRef<ViewRef, IconProps<keyof GM['icons']>>(
125
- (props, ref) => <Icon innerRef={ref} {...props} />
126
- );
127
-
128
- WrappedIcon.displayName = `NanoIcon(${fontBasename})`;
129
-
130
- return WrappedIcon;
11
+ return createJSIconSet(glyphMap);
131
12
  }
package/src/index.ts CHANGED
@@ -1,7 +1,6 @@
1
- // Extension-less so Metro can resolve when example uses path alias to ../src
2
1
  export {
3
2
  createIconSet as createNanoIconSet,
4
3
  type IconComponent,
5
4
  type IconProps,
6
5
  } from './createNanoIconsSet';
7
- export type { ColorValue } from 'react-native';
6
+ export type { ColorValue } from 'react-native';
@@ -0,0 +1,15 @@
1
+ import { codegenNativeComponent } from 'react-native';
2
+ import type { CodegenTypes as CT, ViewProps } from 'react-native';
3
+
4
+ export interface NativeProps extends ViewProps {
5
+ fontFamily: string;
6
+ codepoints: ReadonlyArray<CT.Int32>;
7
+ colors: ReadonlyArray<CT.Int32>;
8
+ fontSize: CT.Float;
9
+ advanceWidth: CT.Int32;
10
+ unitsPerEm: CT.Int32;
11
+ iconWidth: CT.Float;
12
+ iconHeight: CT.Float;
13
+ }
14
+
15
+ export default codegenNativeComponent<NativeProps>('NanoIconView');
package/src/types.ts ADDED
@@ -0,0 +1,27 @@
1
+ import type { ComponentRef, Ref } from 'react';
2
+ import type {
3
+ AccessibilityRole,
4
+ ColorValue,
5
+ View,
6
+ ViewStyle,
7
+ } from 'react-native';
8
+ import type { NanoGlyphMapInput } from './core/types';
9
+
10
+ type ViewRef = ComponentRef<typeof View>;
11
+
12
+ export type IconProps<Name> = {
13
+ name: Name;
14
+ size?: number;
15
+ color?: ColorValue | ColorValue[];
16
+ allowFontScaling?: boolean;
17
+ style?: ViewStyle;
18
+ accessible?: boolean;
19
+ accessibilityLabel?: string;
20
+ accessibilityRole?: AccessibilityRole;
21
+ ref?: Ref<ViewRef>;
22
+ testID?: string;
23
+ };
24
+
25
+ export type IconComponent<GM extends NanoGlyphMapInput> = React.FC<
26
+ IconProps<keyof GM['i']>
27
+ >;
@@ -0,0 +1,17 @@
1
+ import type { ColorValue } from 'react-native';
2
+
3
+ /** Shallow-compare two color props (single value or array) instead of arr ref for memo equality. */
4
+ export function shallowEqualColor(
5
+ a: ColorValue | ColorValue[] | undefined,
6
+ b: ColorValue | ColorValue[] | undefined
7
+ ): boolean {
8
+ if (a === b) return true;
9
+ if (Array.isArray(a) && Array.isArray(b)) {
10
+ if (a.length !== b.length) return false;
11
+ for (let i = 0; i < a.length; i++) {
12
+ if (a[i] !== b[i]) return false;
13
+ }
14
+ return true;
15
+ }
16
+ return false;
17
+ }