@hzblj/kara-components 0.23.1 → 0.24.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/CHANGELOG.md +13 -0
- package/lib/module/atoms/icon/icon.android.js +29 -4
- package/lib/module/atoms/icon/icon.android.js.map +1 -1
- package/lib/module/atoms/icon/icon.ios.js +35 -10
- package/lib/module/atoms/icon/icon.ios.js.map +1 -1
- package/lib/module/atoms/rn-icon/rn-icon.js +9 -8
- package/lib/module/atoms/rn-icon/rn-icon.js.map +1 -1
- package/lib/typescript/atoms/icon/icon.ios.d.ts +3 -2
- package/lib/typescript/atoms/icon/icon.types.d.ts +38 -4
- package/lib/typescript/atoms/rn-icon/rn-icon.d.ts +3 -2
- package/package.json +5 -5
- package/src/atoms/icon/icon.android.tsx +33 -3
- package/src/atoms/icon/icon.ios.tsx +47 -7
- package/src/atoms/icon/icon.types.ts +47 -4
- package/src/atoms/rn-icon/rn-icon.tsx +9 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @hzblj/kara-components
|
|
2
2
|
|
|
3
|
+
## 0.24.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#78](https://github.com/hzblj/kara-ui/pull/78) [`f13e538`](https://github.com/hzblj/kara-ui/commit/f13e538dec32f9a0ce21d86a64a0ad708dc9335e) Thanks [@hzblj](https://github.com/hzblj)! - `Icon` and `RnIcon` play SF Symbols effects (`effect`, once per `effectTrigger` or while `effectActive`), animate a new `name` with a `transition`, and draw `hierarchical`, `palette` and `multicolor` rendering modes (`secondaryColor`, `tertiaryColor`), a `variableValue` and a `gradient`, on both platforms. On iOS `Icon` now draws the custom SF Symbol `@hzblj/expo-native-icons` writes per icon, through the new `symbolStyle` modifier; on Android it hands the icon to expo-native-icons' view when one of these is set. Run a prebuild after upgrading.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [[`f13e538`](https://github.com/hzblj/kara-ui/commit/f13e538dec32f9a0ce21d86a64a0ad708dc9335e)]:
|
|
12
|
+
- @hzblj/kara-native@0.24.0
|
|
13
|
+
- @hzblj/kara-sx@0.24.0
|
|
14
|
+
- @hzblj/kara-theme@0.24.0
|
|
15
|
+
|
|
3
16
|
## 0.23.1
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
|
@@ -1,24 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { iconResourceName } from '@hzblj/expo-native-icons';
|
|
3
|
+
import { iconResourceName, nativeIconEffectRecord, nativeIconTriggerKey } from '@hzblj/expo-native-icons';
|
|
4
4
|
import { DrawableIcon } from '@hzblj/kara-native/jetpack-compose';
|
|
5
5
|
import { spacing, useAppTheme } from '@hzblj/kara-theme';
|
|
6
|
+
import { useMemo } from 'react';
|
|
6
7
|
import { useHostGuard } from "../../hooks/host-context.js";
|
|
7
8
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* The app's icon as the vector drawable the config plugin generated from the SVG, drawn by Material's `Icon`; with an
|
|
11
|
+
* effect, a transition, a rendering mode, a variable value or a gradient, by `@hzblj/expo-native-icons`' view, which
|
|
12
|
+
* plays them.
|
|
13
|
+
*/
|
|
9
14
|
export const Icon = ({
|
|
10
15
|
accessibilityLabel,
|
|
11
16
|
color = 'content.primary',
|
|
17
|
+
effect,
|
|
18
|
+
effectActive,
|
|
19
|
+
effectTrigger,
|
|
20
|
+
gradient,
|
|
12
21
|
name,
|
|
13
|
-
|
|
22
|
+
renderingMode,
|
|
23
|
+
secondaryColor,
|
|
24
|
+
size = 's24',
|
|
25
|
+
tertiaryColor,
|
|
26
|
+
transition,
|
|
27
|
+
variableValue
|
|
14
28
|
}) => {
|
|
15
29
|
useHostGuard('Icon');
|
|
16
30
|
const theme = useAppTheme();
|
|
31
|
+
const effectKey = effect ? JSON.stringify(effect) : undefined;
|
|
32
|
+
const record = useMemo(() => effectKey ? nativeIconEffectRecord(JSON.parse(effectKey)) : undefined, [effectKey]);
|
|
17
33
|
return /*#__PURE__*/_jsx(DrawableIcon, {
|
|
18
34
|
accessibilityLabel: accessibilityLabel,
|
|
35
|
+
effect: record,
|
|
36
|
+
effectActive: effectActive,
|
|
37
|
+
effectTrigger: nativeIconTriggerKey(effectTrigger),
|
|
38
|
+
gradient: gradient,
|
|
19
39
|
iconColor: theme.color(color),
|
|
20
40
|
iconSize: spacing[size],
|
|
21
|
-
|
|
41
|
+
renderingMode: renderingMode,
|
|
42
|
+
resourceName: iconResourceName(name),
|
|
43
|
+
secondaryColor: secondaryColor ? theme.color(secondaryColor) : undefined,
|
|
44
|
+
tertiaryColor: tertiaryColor ? theme.color(tertiaryColor) : undefined,
|
|
45
|
+
transition: transition,
|
|
46
|
+
variableValue: variableValue
|
|
22
47
|
});
|
|
23
48
|
};
|
|
24
49
|
//# sourceMappingURL=icon.android.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["iconResourceName","DrawableIcon","spacing","useAppTheme","useHostGuard","jsx","_jsx","Icon","accessibilityLabel","color","name","size","theme","iconColor","iconSize","resourceName"],"sourceRoot":"../../../../src","sources":["atoms/icon/icon.android.tsx"],"mappings":";;AAAA,SAAQA,gBAAgB,QAAO,0BAA0B;
|
|
1
|
+
{"version":3,"names":["iconResourceName","nativeIconEffectRecord","nativeIconTriggerKey","DrawableIcon","spacing","useAppTheme","useMemo","useHostGuard","jsx","_jsx","Icon","accessibilityLabel","color","effect","effectActive","effectTrigger","gradient","name","renderingMode","secondaryColor","size","tertiaryColor","transition","variableValue","theme","effectKey","JSON","stringify","undefined","record","parse","iconColor","iconSize","resourceName"],"sourceRoot":"../../../../src","sources":["atoms/icon/icon.android.tsx"],"mappings":";;AAAA,SAAQA,gBAAgB,EAAEC,sBAAsB,EAAEC,oBAAoB,QAAO,0BAA0B;AACvG,SAAQC,YAAY,QAAO,oCAAoC;AAC/D,SAAQC,OAAO,EAAEC,WAAW,QAAO,mBAAmB;AACtD,SAAQC,OAAO,QAAO,OAAO;AAE7B,SAAQC,YAAY,QAAO,6BAA0B;AAAA,SAAAC,GAAA,IAAAC,IAAA;AAGrD;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,IAAmB,GAAGA,CAAC;EAClCC,kBAAkB;EAClBC,KAAK,GAAG,iBAAiB;EACzBC,MAAM;EACNC,YAAY;EACZC,aAAa;EACbC,QAAQ;EACRC,IAAI;EACJC,aAAa;EACbC,cAAc;EACdC,IAAI,GAAG,KAAK;EACZC,aAAa;EACbC,UAAU;EACVC;AACS,CAAC,KAAK;EACfhB,YAAY,CAAC,MAAM,CAAC;EACpB,MAAMiB,KAAK,GAAGnB,WAAW,CAAC,CAAC;EAC3B,MAAMoB,SAAS,GAAGZ,MAAM,GAAGa,IAAI,CAACC,SAAS,CAACd,MAAM,CAAC,GAAGe,SAAS;EAC7D,MAAMC,MAAM,GAAGvB,OAAO,CAAC,MAAOmB,SAAS,GAAGxB,sBAAsB,CAACyB,IAAI,CAACI,KAAK,CAACL,SAAS,CAAC,CAAC,GAAGG,SAAU,EAAE,CAACH,SAAS,CAAC,CAAC;EAElH,oBACEhB,IAAA,CAACN,YAAY;IACXQ,kBAAkB,EAAEA,kBAAmB;IACvCE,MAAM,EAAEgB,MAAO;IACff,YAAY,EAAEA,YAAa;IAC3BC,aAAa,EAAEb,oBAAoB,CAACa,aAAa,CAAE;IACnDC,QAAQ,EAAEA,QAAS;IACnBe,SAAS,EAAEP,KAAK,CAACZ,KAAK,CAACA,KAAK,CAAE;IAC9BoB,QAAQ,EAAE5B,OAAO,CAACgB,IAAI,CAAE;IACxBF,aAAa,EAAEA,aAAc;IAC7Be,YAAY,EAAEjC,gBAAgB,CAACiB,IAAI,CAAE;IACrCE,cAAc,EAAEA,cAAc,GAAGK,KAAK,CAACZ,KAAK,CAACO,cAAc,CAAC,GAAGS,SAAU;IACzEP,aAAa,EAAEA,aAAa,GAAGG,KAAK,CAACZ,KAAK,CAACS,aAAa,CAAC,GAAGO,SAAU;IACtEN,UAAU,EAAEA,UAAW;IACvBC,aAAa,EAAEA;EAAc,CAC9B,CAAC;AAEN,CAAC","ignoreList":[]}
|
|
@@ -1,35 +1,60 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { Image } from '@expo/ui/swift-ui';
|
|
4
|
-
import { accessibilityHidden, frame, accessibilityLabel as labelModifier
|
|
5
|
-
import {
|
|
4
|
+
import { accessibilityHidden, frame, imageScale, accessibilityLabel as labelModifier } from '@expo/ui/swift-ui/modifiers';
|
|
5
|
+
import { iconSymbolName, nativeIconEffectRecord, nativeIconTriggerKey } from '@hzblj/expo-native-icons';
|
|
6
|
+
import { symbolStyle } from '@hzblj/kara-native/swift-ui';
|
|
6
7
|
import { spacing, useAppTheme } from '@hzblj/kara-theme';
|
|
7
8
|
import { useMemo } from 'react';
|
|
8
9
|
import { useHostGuard } from "../../hooks/host-context.js";
|
|
9
10
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
10
11
|
/**
|
|
11
|
-
* The app's icon
|
|
12
|
-
*
|
|
12
|
+
* The app's icon as the custom SF Symbol the config plugin generated from the SVG. At the small symbol scale its box is
|
|
13
|
+
* its point size, so the token size is the font size and the box fills the frame, the same size the image was. The
|
|
14
|
+
* `symbolStyle` modifier colours it and plays its effects and transitions, the way `NativeIconView` does in UIKit.
|
|
13
15
|
*/
|
|
14
16
|
export const Icon = ({
|
|
15
17
|
accessibilityLabel,
|
|
16
18
|
color = 'content.primary',
|
|
19
|
+
effect,
|
|
20
|
+
effectActive,
|
|
21
|
+
effectTrigger,
|
|
22
|
+
gradient,
|
|
17
23
|
name,
|
|
24
|
+
renderingMode,
|
|
25
|
+
secondaryColor,
|
|
18
26
|
size = 's24',
|
|
19
|
-
|
|
27
|
+
tertiaryColor,
|
|
28
|
+
testID,
|
|
29
|
+
transition,
|
|
30
|
+
variableValue
|
|
20
31
|
}) => {
|
|
21
32
|
useHostGuard('Icon');
|
|
22
33
|
const theme = useAppTheme();
|
|
23
34
|
const side = spacing[size];
|
|
24
|
-
const
|
|
35
|
+
const symbol = iconSymbolName(name);
|
|
36
|
+
const effectKey = effect ? JSON.stringify(effect) : undefined;
|
|
37
|
+
const modifiers = useMemo(() => [imageScale('small'), symbolStyle({
|
|
38
|
+
color: theme.color(color),
|
|
39
|
+
effect: effectKey ? nativeIconEffectRecord(JSON.parse(effectKey)) : undefined,
|
|
40
|
+
effectActive,
|
|
41
|
+
effectTrigger: nativeIconTriggerKey(effectTrigger),
|
|
42
|
+
gradient,
|
|
43
|
+
renderingMode,
|
|
44
|
+
secondaryColor: secondaryColor ? theme.color(secondaryColor) : undefined,
|
|
45
|
+
tertiaryColor: tertiaryColor ? theme.color(tertiaryColor) : undefined,
|
|
46
|
+
transition,
|
|
47
|
+
transitionValue: `${symbol}:${variableValue ?? ''}`
|
|
48
|
+
}), frame({
|
|
25
49
|
height: side,
|
|
26
50
|
width: side
|
|
27
|
-
}), accessibilityLabel ? labelModifier(accessibilityLabel) : accessibilityHidden(true)], [accessibilityLabel, side]);
|
|
51
|
+
}), accessibilityLabel ? labelModifier(accessibilityLabel) : accessibilityHidden(true)], [accessibilityLabel, color, effectActive, effectKey, effectTrigger, gradient, renderingMode, secondaryColor, side, symbol, tertiaryColor, theme, transition, variableValue]);
|
|
28
52
|
return /*#__PURE__*/_jsx(Image, {
|
|
29
|
-
assetName:
|
|
30
|
-
color: theme.color(color),
|
|
53
|
+
assetName: symbol,
|
|
31
54
|
modifiers: modifiers,
|
|
32
|
-
|
|
55
|
+
size: side,
|
|
56
|
+
testID: testID,
|
|
57
|
+
variableValue: variableValue
|
|
33
58
|
});
|
|
34
59
|
};
|
|
35
60
|
//# sourceMappingURL=icon.ios.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Image","accessibilityHidden","frame","accessibilityLabel","labelModifier","
|
|
1
|
+
{"version":3,"names":["Image","accessibilityHidden","frame","imageScale","accessibilityLabel","labelModifier","iconSymbolName","nativeIconEffectRecord","nativeIconTriggerKey","symbolStyle","spacing","useAppTheme","useMemo","useHostGuard","jsx","_jsx","Icon","color","effect","effectActive","effectTrigger","gradient","name","renderingMode","secondaryColor","size","tertiaryColor","testID","transition","variableValue","theme","side","symbol","effectKey","JSON","stringify","undefined","modifiers","parse","transitionValue","height","width","assetName"],"sourceRoot":"../../../../src","sources":["atoms/icon/icon.ios.tsx"],"mappings":";;AAAA,SAAQA,KAAK,QAAO,mBAAmB;AACvC,SAAQC,mBAAmB,EAAEC,KAAK,EAAEC,UAAU,EAAEC,kBAAkB,IAAIC,aAAa,QAAO,6BAA6B;AACvH,SAAQC,cAAc,EAAEC,sBAAsB,EAAEC,oBAAoB,QAAO,0BAA0B;AACrG,SAAQC,WAAW,QAAO,6BAA6B;AACvD,SAAQC,OAAO,EAAEC,WAAW,QAAO,mBAAmB;AACtD,SAAQC,OAAO,QAAO,OAAO;AAE7B,SAAQC,YAAY,QAAO,6BAA0B;AAAA,SAAAC,GAAA,IAAAC,IAAA;AAGrD;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,IAAmB,GAAGA,CAAC;EAClCZ,kBAAkB;EAClBa,KAAK,GAAG,iBAAiB;EACzBC,MAAM;EACNC,YAAY;EACZC,aAAa;EACbC,QAAQ;EACRC,IAAI;EACJC,aAAa;EACbC,cAAc;EACdC,IAAI,GAAG,KAAK;EACZC,aAAa;EACbC,MAAM;EACNC,UAAU;EACVC;AACS,CAAC,KAAK;EACfhB,YAAY,CAAC,MAAM,CAAC;EACpB,MAAMiB,KAAK,GAAGnB,WAAW,CAAC,CAAC;EAC3B,MAAMoB,IAAI,GAAGrB,OAAO,CAACe,IAAI,CAAC;EAC1B,MAAMO,MAAM,GAAG1B,cAAc,CAACgB,IAAI,CAAC;EACnC,MAAMW,SAAS,GAAGf,MAAM,GAAGgB,IAAI,CAACC,SAAS,CAACjB,MAAM,CAAC,GAAGkB,SAAS;EAE7D,MAAMC,SAAS,GAAGzB,OAAO,CACvB,MAAM,CACJT,UAAU,CAAC,OAAO,CAAC,EACnBM,WAAW,CAAC;IACVQ,KAAK,EAAEa,KAAK,CAACb,KAAK,CAACA,KAAK,CAAC;IACzBC,MAAM,EAAEe,SAAS,GAAG1B,sBAAsB,CAAC2B,IAAI,CAACI,KAAK,CAACL,SAAS,CAAC,CAAC,GAAGG,SAAS;IAC7EjB,YAAY;IACZC,aAAa,EAAEZ,oBAAoB,CAACY,aAAa,CAAC;IAClDC,QAAQ;IACRE,aAAa;IACbC,cAAc,EAAEA,cAAc,GAAGM,KAAK,CAACb,KAAK,CAACO,cAAc,CAAC,GAAGY,SAAS;IACxEV,aAAa,EAAEA,aAAa,GAAGI,KAAK,CAACb,KAAK,CAACS,aAAa,CAAC,GAAGU,SAAS;IACrER,UAAU;IACVW,eAAe,EAAE,GAAGP,MAAM,IAAIH,aAAa,IAAI,EAAE;EACnD,CAAC,CAAC,EACF3B,KAAK,CAAC;IAACsC,MAAM,EAAET,IAAI;IAAEU,KAAK,EAAEV;EAAI,CAAC,CAAC,EAClC3B,kBAAkB,GAAGC,aAAa,CAACD,kBAAkB,CAAC,GAAGH,mBAAmB,CAAC,IAAI,CAAC,CACnF,EACD,CACEG,kBAAkB,EAClBa,KAAK,EACLE,YAAY,EACZc,SAAS,EACTb,aAAa,EACbC,QAAQ,EACRE,aAAa,EACbC,cAAc,EACdO,IAAI,EACJC,MAAM,EACNN,aAAa,EACbI,KAAK,EACLF,UAAU,EACVC,aAAa,CAEjB,CAAC;EAED,oBAAOd,IAAA,CAACf,KAAK;IAAC0C,SAAS,EAAEV,MAAO;IAACK,SAAS,EAAEA,SAAU;IAACZ,IAAI,EAAEM,IAAK;IAACJ,MAAM,EAAEA,MAAO;IAACE,aAAa,EAAEA;EAAc,CAAE,CAAC;AACrH,CAAC","ignoreList":[]}
|
|
@@ -4,23 +4,24 @@ import { NativeIcon } from '@hzblj/expo-native-icons';
|
|
|
4
4
|
import { spacing, useAppTheme } from '@hzblj/kara-theme';
|
|
5
5
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
6
|
/**
|
|
7
|
-
* `@hzblj/expo-native-icons`' `NativeIcon`: a `UIImageView` over the app's
|
|
8
|
-
* its vector drawable on Android
|
|
7
|
+
* `@hzblj/expo-native-icons`' `NativeIcon`: a `UIImageView` over the app's custom SF Symbol on iOS, one view drawing
|
|
8
|
+
* its vector drawable on Android, with the effects, transitions and rendering modes on both. What a list row wants,
|
|
9
|
+
* rather than a SwiftUI or Compose host per row.
|
|
9
10
|
*/
|
|
10
11
|
export const RnIcon = ({
|
|
11
|
-
accessibilityLabel,
|
|
12
12
|
color = 'content.primary',
|
|
13
|
-
|
|
13
|
+
secondaryColor,
|
|
14
14
|
size = 's24',
|
|
15
|
-
|
|
15
|
+
tertiaryColor,
|
|
16
|
+
...props
|
|
16
17
|
}) => {
|
|
17
18
|
const theme = useAppTheme();
|
|
18
19
|
return /*#__PURE__*/_jsx(NativeIcon, {
|
|
19
|
-
|
|
20
|
+
...props,
|
|
20
21
|
color: theme.color(color),
|
|
21
|
-
|
|
22
|
+
secondaryColor: secondaryColor ? theme.color(secondaryColor) : undefined,
|
|
22
23
|
size: spacing[size],
|
|
23
|
-
|
|
24
|
+
tertiaryColor: tertiaryColor ? theme.color(tertiaryColor) : undefined
|
|
24
25
|
});
|
|
25
26
|
};
|
|
26
27
|
//# sourceMappingURL=rn-icon.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeIcon","spacing","useAppTheme","jsx","_jsx","RnIcon","
|
|
1
|
+
{"version":3,"names":["NativeIcon","spacing","useAppTheme","jsx","_jsx","RnIcon","color","secondaryColor","size","tertiaryColor","props","theme","undefined"],"sourceRoot":"../../../../src","sources":["atoms/rn-icon/rn-icon.tsx"],"mappings":";;AAAA,SAAQA,UAAU,QAAO,0BAA0B;AACnD,SAAQC,OAAO,EAAEC,WAAW,QAAO,mBAAmB;AAAA,SAAAC,GAAA,IAAAC,IAAA;AAItD;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,MAAuB,GAAGA,CAAC;EACtCC,KAAK,GAAG,iBAAiB;EACzBC,cAAc;EACdC,IAAI,GAAG,KAAK;EACZC,aAAa;EACb,GAAGC;AACQ,CAAC,KAAK;EACjB,MAAMC,KAAK,GAAGT,WAAW,CAAC,CAAC;EAE3B,oBACEE,IAAA,CAACJ,UAAU;IAAA,GACLU,KAAK;IACTJ,KAAK,EAAEK,KAAK,CAACL,KAAK,CAACA,KAAK,CAAE;IAC1BC,cAAc,EAAEA,cAAc,GAAGI,KAAK,CAACL,KAAK,CAACC,cAAc,CAAC,GAAGK,SAAU;IACzEJ,IAAI,EAAEP,OAAO,CAACO,IAAI,CAAE;IACpBC,aAAa,EAAEA,aAAa,GAAGE,KAAK,CAACL,KAAK,CAACG,aAAa,CAAC,GAAGG;EAAU,CACvE,CAAC;AAEN,CAAC","ignoreList":[]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IconComponent } from './icon.types';
|
|
2
2
|
/**
|
|
3
|
-
* The app's icon
|
|
4
|
-
*
|
|
3
|
+
* The app's icon as the custom SF Symbol the config plugin generated from the SVG. At the small symbol scale its box is
|
|
4
|
+
* its point size, so the token size is the font size and the box fills the frame, the same size the image was. The
|
|
5
|
+
* `symbolStyle` modifier colours it and plays its effects and transitions, the way `NativeIconView` does in UIKit.
|
|
5
6
|
*/
|
|
6
7
|
export declare const Icon: IconComponent;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NativeIconName } from '@hzblj/expo-native-icons';
|
|
1
|
+
import type { NativeIconEffect, NativeIconEffectTrigger, NativeIconName, NativeIconRenderingMode, NativeIconTransition } from '@hzblj/expo-native-icons';
|
|
2
2
|
import type { ColorToken, SpaceSize } from '@hzblj/kara-theme';
|
|
3
3
|
import type { ReactNode } from 'react';
|
|
4
4
|
/**
|
|
@@ -7,20 +7,54 @@ import type { ReactNode } from 'react';
|
|
|
7
7
|
* those names type-check, so an icon removed from the folder fails at every call site; before that, any string.
|
|
8
8
|
*/
|
|
9
9
|
export type IconName = NativeIconName;
|
|
10
|
+
/** An SF Symbols effect for `Icon` and `RnIcon`: `{type: 'bounce'}`, `{type: 'variableColor', fill: 'iterative'}`… */
|
|
11
|
+
export type IconEffect = NativeIconEffect;
|
|
12
|
+
/** How an icon's layers are coloured. */
|
|
13
|
+
export type IconRenderingMode = NativeIconRenderingMode;
|
|
14
|
+
/** How an icon changes into another when its `name` changes. */
|
|
15
|
+
export type IconTransition = NativeIconTransition;
|
|
10
16
|
/**
|
|
11
|
-
* One of the app's icons, in a host: SwiftUI `Image`
|
|
12
|
-
* drawable on Android. `RnIcon` draws the same asset outside one.
|
|
17
|
+
* One of the app's icons, in a host: SwiftUI `Image` of its custom SF Symbol on iOS, Material's `Icon` with the vector
|
|
18
|
+
* drawable on Android. `RnIcon` draws the same asset outside one. Both play the SF Symbols effects and transitions and
|
|
19
|
+
* draw the rendering modes and variable values, on both platforms.
|
|
13
20
|
*/
|
|
14
21
|
export type IconProps = {
|
|
15
22
|
/** What a screen reader says. Unset, the icon is decorative and hidden from it. */
|
|
16
23
|
accessibilityLabel?: string;
|
|
17
|
-
/** The icon's tint. `content.primary` by default. */
|
|
24
|
+
/** The icon's tint, and the primary colour of the other rendering modes. `content.primary` by default. */
|
|
18
25
|
color?: ColorToken;
|
|
26
|
+
/**
|
|
27
|
+
* An SF Symbols effect: `bounce`, `pulse`, `variableColor`, `wiggle`, `rotate`, `breathe`, and the states `scale`,
|
|
28
|
+
* `appear` and `disappear`. Plays once per change of `effectTrigger`, or while `effectActive`.
|
|
29
|
+
*/
|
|
30
|
+
effect?: IconEffect;
|
|
31
|
+
/** Runs `effect` while true; without an `effectTrigger`, true by default. */
|
|
32
|
+
effectActive?: boolean;
|
|
33
|
+
/** Plays `effect` once whenever this value changes, never on mount. */
|
|
34
|
+
effectTrigger?: NativeIconEffectTrigger;
|
|
35
|
+
/** Shades each layer's colour into a soft gradient, as SF Symbols does on iOS 26. iOS 26 and Android. */
|
|
36
|
+
gradient?: boolean;
|
|
19
37
|
/** Which of the app's icons: a key of `NativeIcons`, one per SVG in the icon folder. */
|
|
20
38
|
name: IconName;
|
|
39
|
+
/**
|
|
40
|
+
* How the layers are coloured: `monochrome` (the default) tints them all, `hierarchical` draws secondary and tertiary
|
|
41
|
+
* layers fainter, `palette` gives them `secondaryColor` and `tertiaryColor`, `multicolor` keeps the SVG's own fills.
|
|
42
|
+
*/
|
|
43
|
+
renderingMode?: IconRenderingMode;
|
|
44
|
+
/** The `palette` mode's colour for secondary layers. `color` by default. */
|
|
45
|
+
secondaryColor?: ColorToken;
|
|
21
46
|
/** Its width and height, a spacing token. `s24` by default. */
|
|
22
47
|
size?: SpaceSize;
|
|
48
|
+
/** The `palette` mode's colour for tertiary layers. `secondaryColor` by default. */
|
|
49
|
+
tertiaryColor?: ColorToken;
|
|
23
50
|
/** Test identifier, forwarded to the native view on iOS. Android ignores it. */
|
|
24
51
|
testID?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Animates a change of `name`: `replace`, `replaceUpUp`, `replaceOffUp`, `magicReplace` or `automatic`. With one set,
|
|
54
|
+
* a new `variableValue` eases in too. Unset, the icon swaps at once.
|
|
55
|
+
*/
|
|
56
|
+
transition?: IconTransition;
|
|
57
|
+
/** From 0 to 1: switches on the SVG's `data-variable` layers whose threshold it passes, the rest dimmed. */
|
|
58
|
+
variableValue?: number;
|
|
25
59
|
};
|
|
26
60
|
export type IconComponent = (props: IconProps) => ReactNode;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RnIconComponent } from './rn-icon.types';
|
|
2
2
|
/**
|
|
3
|
-
* `@hzblj/expo-native-icons`' `NativeIcon`: a `UIImageView` over the app's
|
|
4
|
-
* its vector drawable on Android
|
|
3
|
+
* `@hzblj/expo-native-icons`' `NativeIcon`: a `UIImageView` over the app's custom SF Symbol on iOS, one view drawing
|
|
4
|
+
* its vector drawable on Android, with the effects, transitions and rendering modes on both. What a list row wants,
|
|
5
|
+
* rather than a SwiftUI or Compose host per row.
|
|
5
6
|
*/
|
|
6
7
|
export declare const RnIcon: RnIconComponent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hzblj/kara-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "The atoms, molecules, organisms and templates of @hzblj/kara-ui — real SwiftUI and Jetpack Compose views through @expo/ui.",
|
|
5
5
|
"author": "Jan Blazej",
|
|
6
6
|
"license": "MIT",
|
|
@@ -64,11 +64,11 @@
|
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@hzblj/expo-native-icons": "^0.
|
|
67
|
+
"@hzblj/expo-native-icons": "^0.2.0",
|
|
68
68
|
"@hzblj/expo-rich-haptics": "^0.1.0",
|
|
69
|
-
"@hzblj/kara-native": "^0.
|
|
70
|
-
"@hzblj/kara-sx": "^0.
|
|
71
|
-
"@hzblj/kara-theme": "^0.
|
|
69
|
+
"@hzblj/kara-native": "^0.24.0",
|
|
70
|
+
"@hzblj/kara-sx": "^0.24.0",
|
|
71
|
+
"@hzblj/kara-theme": "^0.24.0",
|
|
72
72
|
"sf-symbols-typescript": "^2.2.0"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
@@ -1,21 +1,51 @@
|
|
|
1
|
-
import {iconResourceName} from '@hzblj/expo-native-icons'
|
|
1
|
+
import {iconResourceName, nativeIconEffectRecord, nativeIconTriggerKey} from '@hzblj/expo-native-icons'
|
|
2
2
|
import {DrawableIcon} from '@hzblj/kara-native/jetpack-compose'
|
|
3
3
|
import {spacing, useAppTheme} from '@hzblj/kara-theme'
|
|
4
|
+
import {useMemo} from 'react'
|
|
4
5
|
|
|
5
6
|
import {useHostGuard} from '../../hooks/host-context'
|
|
6
7
|
import type {IconComponent, IconProps} from './icon.types'
|
|
7
8
|
|
|
8
|
-
/**
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The app's icon as the vector drawable the config plugin generated from the SVG, drawn by Material's `Icon`; with an
|
|
11
|
+
* effect, a transition, a rendering mode, a variable value or a gradient, by `@hzblj/expo-native-icons`' view, which
|
|
12
|
+
* plays them.
|
|
13
|
+
*/
|
|
14
|
+
export const Icon: IconComponent = ({
|
|
15
|
+
accessibilityLabel,
|
|
16
|
+
color = 'content.primary',
|
|
17
|
+
effect,
|
|
18
|
+
effectActive,
|
|
19
|
+
effectTrigger,
|
|
20
|
+
gradient,
|
|
21
|
+
name,
|
|
22
|
+
renderingMode,
|
|
23
|
+
secondaryColor,
|
|
24
|
+
size = 's24',
|
|
25
|
+
tertiaryColor,
|
|
26
|
+
transition,
|
|
27
|
+
variableValue,
|
|
28
|
+
}: IconProps) => {
|
|
10
29
|
useHostGuard('Icon')
|
|
11
30
|
const theme = useAppTheme()
|
|
31
|
+
const effectKey = effect ? JSON.stringify(effect) : undefined
|
|
32
|
+
const record = useMemo(() => (effectKey ? nativeIconEffectRecord(JSON.parse(effectKey)) : undefined), [effectKey])
|
|
12
33
|
|
|
13
34
|
return (
|
|
14
35
|
<DrawableIcon
|
|
15
36
|
accessibilityLabel={accessibilityLabel}
|
|
37
|
+
effect={record}
|
|
38
|
+
effectActive={effectActive}
|
|
39
|
+
effectTrigger={nativeIconTriggerKey(effectTrigger)}
|
|
40
|
+
gradient={gradient}
|
|
16
41
|
iconColor={theme.color(color)}
|
|
17
42
|
iconSize={spacing[size]}
|
|
43
|
+
renderingMode={renderingMode}
|
|
18
44
|
resourceName={iconResourceName(name)}
|
|
45
|
+
secondaryColor={secondaryColor ? theme.color(secondaryColor) : undefined}
|
|
46
|
+
tertiaryColor={tertiaryColor ? theme.color(tertiaryColor) : undefined}
|
|
47
|
+
transition={transition}
|
|
48
|
+
variableValue={variableValue}
|
|
19
49
|
/>
|
|
20
50
|
)
|
|
21
51
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {Image} from '@expo/ui/swift-ui'
|
|
2
|
-
import {accessibilityHidden, frame, accessibilityLabel as labelModifier
|
|
3
|
-
import {
|
|
2
|
+
import {accessibilityHidden, frame, imageScale, accessibilityLabel as labelModifier} from '@expo/ui/swift-ui/modifiers'
|
|
3
|
+
import {iconSymbolName, nativeIconEffectRecord, nativeIconTriggerKey} from '@hzblj/expo-native-icons'
|
|
4
|
+
import {symbolStyle} from '@hzblj/kara-native/swift-ui'
|
|
4
5
|
import {spacing, useAppTheme} from '@hzblj/kara-theme'
|
|
5
6
|
import {useMemo} from 'react'
|
|
6
7
|
|
|
@@ -8,28 +9,67 @@ import {useHostGuard} from '../../hooks/host-context'
|
|
|
8
9
|
import type {IconComponent, IconProps} from './icon.types'
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* The app's icon
|
|
12
|
-
*
|
|
12
|
+
* The app's icon as the custom SF Symbol the config plugin generated from the SVG. At the small symbol scale its box is
|
|
13
|
+
* its point size, so the token size is the font size and the box fills the frame, the same size the image was. The
|
|
14
|
+
* `symbolStyle` modifier colours it and plays its effects and transitions, the way `NativeIconView` does in UIKit.
|
|
13
15
|
*/
|
|
14
16
|
export const Icon: IconComponent = ({
|
|
15
17
|
accessibilityLabel,
|
|
16
18
|
color = 'content.primary',
|
|
19
|
+
effect,
|
|
20
|
+
effectActive,
|
|
21
|
+
effectTrigger,
|
|
22
|
+
gradient,
|
|
17
23
|
name,
|
|
24
|
+
renderingMode,
|
|
25
|
+
secondaryColor,
|
|
18
26
|
size = 's24',
|
|
27
|
+
tertiaryColor,
|
|
19
28
|
testID,
|
|
29
|
+
transition,
|
|
30
|
+
variableValue,
|
|
20
31
|
}: IconProps) => {
|
|
21
32
|
useHostGuard('Icon')
|
|
22
33
|
const theme = useAppTheme()
|
|
23
34
|
const side = spacing[size]
|
|
35
|
+
const symbol = iconSymbolName(name)
|
|
36
|
+
const effectKey = effect ? JSON.stringify(effect) : undefined
|
|
24
37
|
|
|
25
38
|
const modifiers = useMemo(
|
|
26
39
|
() => [
|
|
27
|
-
|
|
40
|
+
imageScale('small'),
|
|
41
|
+
symbolStyle({
|
|
42
|
+
color: theme.color(color),
|
|
43
|
+
effect: effectKey ? nativeIconEffectRecord(JSON.parse(effectKey)) : undefined,
|
|
44
|
+
effectActive,
|
|
45
|
+
effectTrigger: nativeIconTriggerKey(effectTrigger),
|
|
46
|
+
gradient,
|
|
47
|
+
renderingMode,
|
|
48
|
+
secondaryColor: secondaryColor ? theme.color(secondaryColor) : undefined,
|
|
49
|
+
tertiaryColor: tertiaryColor ? theme.color(tertiaryColor) : undefined,
|
|
50
|
+
transition,
|
|
51
|
+
transitionValue: `${symbol}:${variableValue ?? ''}`,
|
|
52
|
+
}),
|
|
28
53
|
frame({height: side, width: side}),
|
|
29
54
|
accessibilityLabel ? labelModifier(accessibilityLabel) : accessibilityHidden(true),
|
|
30
55
|
],
|
|
31
|
-
[
|
|
56
|
+
[
|
|
57
|
+
accessibilityLabel,
|
|
58
|
+
color,
|
|
59
|
+
effectActive,
|
|
60
|
+
effectKey,
|
|
61
|
+
effectTrigger,
|
|
62
|
+
gradient,
|
|
63
|
+
renderingMode,
|
|
64
|
+
secondaryColor,
|
|
65
|
+
side,
|
|
66
|
+
symbol,
|
|
67
|
+
tertiaryColor,
|
|
68
|
+
theme,
|
|
69
|
+
transition,
|
|
70
|
+
variableValue,
|
|
71
|
+
]
|
|
32
72
|
)
|
|
33
73
|
|
|
34
|
-
return <Image assetName={
|
|
74
|
+
return <Image assetName={symbol} modifiers={modifiers} size={side} testID={testID} variableValue={variableValue} />
|
|
35
75
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
NativeIconEffect,
|
|
3
|
+
NativeIconEffectTrigger,
|
|
4
|
+
NativeIconName,
|
|
5
|
+
NativeIconRenderingMode,
|
|
6
|
+
NativeIconTransition,
|
|
7
|
+
} from '@hzblj/expo-native-icons'
|
|
2
8
|
import type {ColorToken, SpaceSize} from '@hzblj/kara-theme'
|
|
3
9
|
import type {ReactNode} from 'react'
|
|
4
10
|
|
|
@@ -9,21 +15,58 @@ import type {ReactNode} from 'react'
|
|
|
9
15
|
*/
|
|
10
16
|
export type IconName = NativeIconName
|
|
11
17
|
|
|
18
|
+
/** An SF Symbols effect for `Icon` and `RnIcon`: `{type: 'bounce'}`, `{type: 'variableColor', fill: 'iterative'}`… */
|
|
19
|
+
export type IconEffect = NativeIconEffect
|
|
20
|
+
|
|
21
|
+
/** How an icon's layers are coloured. */
|
|
22
|
+
export type IconRenderingMode = NativeIconRenderingMode
|
|
23
|
+
|
|
24
|
+
/** How an icon changes into another when its `name` changes. */
|
|
25
|
+
export type IconTransition = NativeIconTransition
|
|
26
|
+
|
|
12
27
|
/**
|
|
13
|
-
* One of the app's icons, in a host: SwiftUI `Image`
|
|
14
|
-
* drawable on Android. `RnIcon` draws the same asset outside one.
|
|
28
|
+
* One of the app's icons, in a host: SwiftUI `Image` of its custom SF Symbol on iOS, Material's `Icon` with the vector
|
|
29
|
+
* drawable on Android. `RnIcon` draws the same asset outside one. Both play the SF Symbols effects and transitions and
|
|
30
|
+
* draw the rendering modes and variable values, on both platforms.
|
|
15
31
|
*/
|
|
16
32
|
export type IconProps = {
|
|
17
33
|
/** What a screen reader says. Unset, the icon is decorative and hidden from it. */
|
|
18
34
|
accessibilityLabel?: string
|
|
19
|
-
/** The icon's tint. `content.primary` by default. */
|
|
35
|
+
/** The icon's tint, and the primary colour of the other rendering modes. `content.primary` by default. */
|
|
20
36
|
color?: ColorToken
|
|
37
|
+
/**
|
|
38
|
+
* An SF Symbols effect: `bounce`, `pulse`, `variableColor`, `wiggle`, `rotate`, `breathe`, and the states `scale`,
|
|
39
|
+
* `appear` and `disappear`. Plays once per change of `effectTrigger`, or while `effectActive`.
|
|
40
|
+
*/
|
|
41
|
+
effect?: IconEffect
|
|
42
|
+
/** Runs `effect` while true; without an `effectTrigger`, true by default. */
|
|
43
|
+
effectActive?: boolean
|
|
44
|
+
/** Plays `effect` once whenever this value changes, never on mount. */
|
|
45
|
+
effectTrigger?: NativeIconEffectTrigger
|
|
46
|
+
/** Shades each layer's colour into a soft gradient, as SF Symbols does on iOS 26. iOS 26 and Android. */
|
|
47
|
+
gradient?: boolean
|
|
21
48
|
/** Which of the app's icons: a key of `NativeIcons`, one per SVG in the icon folder. */
|
|
22
49
|
name: IconName
|
|
50
|
+
/**
|
|
51
|
+
* How the layers are coloured: `monochrome` (the default) tints them all, `hierarchical` draws secondary and tertiary
|
|
52
|
+
* layers fainter, `palette` gives them `secondaryColor` and `tertiaryColor`, `multicolor` keeps the SVG's own fills.
|
|
53
|
+
*/
|
|
54
|
+
renderingMode?: IconRenderingMode
|
|
55
|
+
/** The `palette` mode's colour for secondary layers. `color` by default. */
|
|
56
|
+
secondaryColor?: ColorToken
|
|
23
57
|
/** Its width and height, a spacing token. `s24` by default. */
|
|
24
58
|
size?: SpaceSize
|
|
59
|
+
/** The `palette` mode's colour for tertiary layers. `secondaryColor` by default. */
|
|
60
|
+
tertiaryColor?: ColorToken
|
|
25
61
|
/** Test identifier, forwarded to the native view on iOS. Android ignores it. */
|
|
26
62
|
testID?: string
|
|
63
|
+
/**
|
|
64
|
+
* Animates a change of `name`: `replace`, `replaceUpUp`, `replaceOffUp`, `magicReplace` or `automatic`. With one set,
|
|
65
|
+
* a new `variableValue` eases in too. Unset, the icon swaps at once.
|
|
66
|
+
*/
|
|
67
|
+
transition?: IconTransition
|
|
68
|
+
/** From 0 to 1: switches on the SVG's `data-variable` layers whose threshold it passes, the rest dimmed. */
|
|
69
|
+
variableValue?: number
|
|
27
70
|
}
|
|
28
71
|
|
|
29
72
|
export type IconComponent = (props: IconProps) => ReactNode
|
|
@@ -4,25 +4,26 @@ import {spacing, useAppTheme} from '@hzblj/kara-theme'
|
|
|
4
4
|
import type {RnIconComponent, RnIconProps} from './rn-icon.types'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* `@hzblj/expo-native-icons`' `NativeIcon`: a `UIImageView` over the app's
|
|
8
|
-
* its vector drawable on Android
|
|
7
|
+
* `@hzblj/expo-native-icons`' `NativeIcon`: a `UIImageView` over the app's custom SF Symbol on iOS, one view drawing
|
|
8
|
+
* its vector drawable on Android, with the effects, transitions and rendering modes on both. What a list row wants,
|
|
9
|
+
* rather than a SwiftUI or Compose host per row.
|
|
9
10
|
*/
|
|
10
11
|
export const RnIcon: RnIconComponent = ({
|
|
11
|
-
accessibilityLabel,
|
|
12
12
|
color = 'content.primary',
|
|
13
|
-
|
|
13
|
+
secondaryColor,
|
|
14
14
|
size = 's24',
|
|
15
|
-
|
|
15
|
+
tertiaryColor,
|
|
16
|
+
...props
|
|
16
17
|
}: RnIconProps) => {
|
|
17
18
|
const theme = useAppTheme()
|
|
18
19
|
|
|
19
20
|
return (
|
|
20
21
|
<NativeIcon
|
|
21
|
-
|
|
22
|
+
{...props}
|
|
22
23
|
color={theme.color(color)}
|
|
23
|
-
|
|
24
|
+
secondaryColor={secondaryColor ? theme.color(secondaryColor) : undefined}
|
|
24
25
|
size={spacing[size]}
|
|
25
|
-
|
|
26
|
+
tertiaryColor={tertiaryColor ? theme.color(tertiaryColor) : undefined}
|
|
26
27
|
/>
|
|
27
28
|
)
|
|
28
29
|
}
|