@lookiero/checkout 15.2.3 → 15.2.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## (2026-05-27)
2
+
3
+ ### Bug Fixes
4
+
5
+ - checkout RadioReturnQuestionItem ([#505](https://github.com/lookiero/sty-sp-front/issues/505)) ([4a01deb](https://github.com/lookiero/sty-sp-front/commit/4a01deb17c7ebff417e203f28b58329570c7c01c))
6
+ - **checkout:** clip and fill product variant images in XO ([#754](https://github.com/lookiero/sty-sp-front/issues/754)) ([8801c46](https://github.com/lookiero/sty-sp-front/commit/8801c466e8357b99410ef08e5d6323c6792fca67))
7
+ - **notifications:** propagate bodyI18nValues through notification chain ([#727](https://github.com/lookiero/sty-sp-front/issues/727)) ([c8f1b30](https://github.com/lookiero/sty-sp-front/commit/c8f1b30a3bd5212b712d2243fdd1a6309b676321))
8
+ - **slider:** correct price range slider alignment on Android ([#749](https://github.com/lookiero/sty-sp-front/issues/749)) ([9022d83](https://github.com/lookiero/sty-sp-front/commit/9022d8303fdcfd9f125fdb87cf41fc8df9db673a))
9
+ - **ui:** carousel Bullets background color applied inside style object ([#757](https://github.com/lookiero/sty-sp-front/issues/757)) ([d764531](https://github.com/lookiero/sty-sp-front/commit/d764531a5e33c781b1e952a2310ba0fb91e799c6))
10
+
1
11
  # Changelog
2
12
 
3
13
  All notable changes to `@lookiero/checkout` are generated from Conventional Commits scoped to `apps/checkout`.
@@ -2,7 +2,6 @@ import { FC } from "react";
2
2
  import { StyleProp, TextStyle, ViewStyle } from "react-native";
3
3
  interface SelectModalStyle {
4
4
  readonly modalContent: StyleProp<ViewStyle>;
5
- readonly option: StyleProp<ViewStyle>;
6
5
  readonly optionText: StyleProp<TextStyle>;
7
6
  }
8
7
  interface Option {
@@ -1,18 +1,27 @@
1
- import React, { useCallback, useMemo } from "react";
2
- import { TouchableHighlight, View } from "react-native";
3
- import { Text } from "@lookiero/sty-psp-ui";
4
- import { Modal } from "@lookiero/sty-psp-ui";
1
+ import React, { useMemo } from "react";
2
+ import { Pressable, View } from "react-native";
3
+ import { Checkbox, Modal, Text } from "@lookiero/sty-psp-ui";
4
+ import { Tradename } from "@lookiero/sty-sp-tradename";
5
+ import { useStaticInfo } from "../../../../hooks/useStaticInfo";
5
6
  import { style as modalStyle } from "./SelectModal.style";
6
7
  const SelectModal = ({ modalVisible, options, style: customStyle, testID, title, value, portalHostName, onChange = () => void 0, onClose = () => void 0, }) => {
7
- const handleOnPressOption = useCallback((value) => {
8
- onChange(value);
9
- onClose();
10
- }, [onClose, onChange]);
11
8
  const style = useMemo(() => modalStyle(), []);
9
+ const { tradename } = useStaticInfo();
12
10
  return (React.createElement(Modal, { portalHostName: portalHostName, testID: testID, visible: modalVisible, scroll: true, showCloseButton: true, onClose: onClose },
13
11
  React.createElement(View, { style: [style.modalContent, customStyle?.modalContent] },
14
12
  title && (React.createElement(Text, { level: 3, style: style.modalTitle, variant: "heading" }, title)),
15
- options.map(({ label, value: optionValue }) => (React.createElement(TouchableHighlight, { key: optionValue, accessibilityLabel: optionValue, disabled: value === optionValue, style: [style.option, customStyle?.option], testID: optionValue, underlayColor: style.underlayColor, accessible: true, onPress: value !== optionValue ? () => handleOnPressOption(optionValue) : undefined },
16
- React.createElement(Text, { level: 3, style: [style.optionText, value === optionValue && style.textActive, customStyle?.optionText] }, label)))))));
13
+ React.createElement(View, { accessibilityRole: "radiogroup", style: style.container, testID: "options-radiogroup" }, options.map(({ label, value: optionValue }) => {
14
+ const checked = value === optionValue;
15
+ return (React.createElement(Pressable, { key: optionValue, accessibilityLabel: label, accessibilityRole: "radio", accessibilityState: { checked, disabled: checked }, disabled: checked, testID: optionValue, style: [
16
+ style.wrapper,
17
+ checked && style.wrapperChecked,
18
+ tradename === Tradename.LOOKIERO && style.wrapperLookiero,
19
+ ], accessible: true, onPress: () => {
20
+ onChange(optionValue);
21
+ onClose();
22
+ } },
23
+ React.createElement(Checkbox, { checked: checked }),
24
+ React.createElement(Text, { style: style.text }, label)));
25
+ })))));
17
26
  };
18
27
  export { SelectModal };
@@ -1,22 +1,33 @@
1
1
  declare const style: () => {
2
- underlayColor: string;
2
+ container: {
3
+ gap: number;
4
+ };
3
5
  modalContent: {
4
- paddingBottom: number;
5
6
  paddingHorizontal: number;
6
7
  };
7
8
  modalTitle: {
8
9
  marginBottom: number;
9
10
  };
10
- option: {
11
- borderBottomColor: string;
12
- borderBottomWidth: number;
13
- paddingVertical: number;
11
+ text: {
12
+ color: string;
13
+ flex: number;
14
+ marginLeft: number;
15
+ };
16
+ wrapper: {
17
+ alignItems: "center";
18
+ borderColor: string;
19
+ borderWidth: number;
20
+ flex: number;
21
+ flexDirection: "row";
22
+ padding: number;
14
23
  };
15
- optionText: {
16
- lineHeight: number;
24
+ wrapperChecked: {
25
+ borderColor: string;
26
+ borderWidth: number;
27
+ padding: number;
17
28
  };
18
- textActive: {
19
- color: string;
29
+ wrapperLookiero: {
30
+ borderRadius: number;
20
31
  };
21
32
  };
22
33
  export { style };
@@ -1,30 +1,38 @@
1
1
  import { StyleSheet } from "react-native";
2
2
  import { theme } from "@lookiero/sty-psp-ui";
3
3
  const style = () => {
4
- const { borderWidth1, colorBgPrimaryLight, colorBorderInteractive, colorTextMedium, space1, space5, space6 } = theme();
5
- const styles = StyleSheet.create({
4
+ const { colorText, colorBorderInputFocus, colorBorderInteractive, space025, space3, space4, space6, borderWidth1, borderWidth2, borderRadius3, } = theme();
5
+ return StyleSheet.create({
6
+ container: {
7
+ gap: space3,
8
+ },
6
9
  modalContent: {
7
- paddingBottom: space6,
8
10
  paddingHorizontal: space6,
9
11
  },
10
12
  modalTitle: {
11
- marginBottom: space1,
13
+ marginBottom: space3,
14
+ },
15
+ text: {
16
+ color: colorText,
17
+ flex: 1,
18
+ marginLeft: space4,
12
19
  },
13
- option: {
14
- borderBottomColor: colorBorderInteractive,
15
- borderBottomWidth: borderWidth1,
16
- paddingVertical: space5,
20
+ wrapper: {
21
+ alignItems: "center",
22
+ borderColor: colorBorderInteractive,
23
+ borderWidth: borderWidth1,
24
+ flex: 1,
25
+ flexDirection: "row",
26
+ padding: space4,
17
27
  },
18
- optionText: {
19
- lineHeight: space6,
28
+ wrapperChecked: {
29
+ borderColor: colorBorderInputFocus,
30
+ borderWidth: borderWidth2,
31
+ padding: space4 - space025,
20
32
  },
21
- textActive: {
22
- color: colorTextMedium,
33
+ wrapperLookiero: {
34
+ borderRadius: borderRadius3,
23
35
  },
24
36
  });
25
- return {
26
- ...styles,
27
- underlayColor: colorBgPrimaryLight,
28
- };
29
37
  };
30
38
  export { style };
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "15.2.3";
2
- export declare const RELEASE = "checkout@15.2.3";
1
+ export declare const VERSION = "15.2.4";
2
+ export declare const RELEASE = "checkout@15.2.4";
@@ -1,2 +1,2 @@
1
- export const VERSION = "15.2.3";
2
- export const RELEASE = "checkout@15.2.3";
1
+ export const VERSION = "15.2.4";
2
+ export const RELEASE = "checkout@15.2.4";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lookiero/checkout",
3
- "version": "15.2.3",
3
+ "version": "15.2.4",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "sideEffects": "false",
@@ -7,6 +7,10 @@ import { I18nMessages } from "../../../../i18n/i18n";
7
7
  import { render } from "../../../../test/render";
8
8
  import { ItemActions } from "./ItemActions";
9
9
 
10
+ jest.mock("../../../../hooks/useStaticInfo", () => ({
11
+ useStaticInfo: () => ({ tradename: "LOOKIERO" }),
12
+ }));
13
+
10
14
  const productVariantProjection: ProductVariantProjection[] = [
11
15
  {
12
16
  id: "2875e66d-4e2a-47b1-a58b-61e316dcc66a",
@@ -714,7 +714,6 @@ exports[`ItemActions component matches the snapshot 1`] = `
714
714
  style={
715
715
  [
716
716
  {
717
- "paddingBottom": 24,
718
717
  "paddingHorizontal": 24,
719
718
  },
720
719
  undefined,
@@ -734,7 +733,7 @@ exports[`ItemActions component matches the snapshot 1`] = `
734
733
  "lineHeight": 36,
735
734
  },
736
735
  {
737
- "marginBottom": 4,
736
+ "marginBottom": 12,
738
737
  },
739
738
  ]
740
739
  }
@@ -742,128 +741,306 @@ exports[`ItemActions component matches the snapshot 1`] = `
742
741
  item.change_size_button
743
742
  </Text>
744
743
  <View
745
- accessibilityLabel="2875e66d-4e2a-47b1-a58b-61e316dcc66a"
746
- accessibilityState={
744
+ accessibilityRole="radiogroup"
745
+ style={
747
746
  {
748
- "disabled": true,
747
+ "gap": 12,
749
748
  }
750
749
  }
751
- accessibilityValue={
752
- {
753
- "max": undefined,
754
- "min": undefined,
755
- "now": undefined,
756
- "text": undefined,
750
+ testID="options-radiogroup"
751
+ >
752
+ <View
753
+ accessibilityLabel="S"
754
+ accessibilityRole="radio"
755
+ accessibilityState={
756
+ {
757
+ "busy": undefined,
758
+ "checked": true,
759
+ "disabled": true,
760
+ "expanded": undefined,
761
+ "selected": undefined,
762
+ }
757
763
  }
758
- }
759
- accessible={true}
760
- focusable={false}
761
- onClick={[Function]}
762
- onResponderGrant={[Function]}
763
- onResponderMove={[Function]}
764
- onResponderRelease={[Function]}
765
- onResponderTerminate={[Function]}
766
- onResponderTerminationRequest={[Function]}
767
- onStartShouldSetResponder={[Function]}
768
- style={
769
- [
764
+ accessibilityValue={
770
765
  {
771
- "borderBottomColor": "#DAD8D8",
772
- "borderBottomWidth": 1,
773
- "paddingVertical": 20,
774
- },
775
- undefined,
776
- ]
777
- }
778
- testID="2875e66d-4e2a-47b1-a58b-61e316dcc66a"
779
- >
780
- <Text
766
+ "max": undefined,
767
+ "min": undefined,
768
+ "now": undefined,
769
+ "text": undefined,
770
+ }
771
+ }
772
+ accessible={true}
773
+ collapsable={false}
774
+ focusable={true}
775
+ onBlur={[Function]}
776
+ onClick={[Function]}
777
+ onFocus={[Function]}
778
+ onResponderGrant={[Function]}
779
+ onResponderMove={[Function]}
780
+ onResponderRelease={[Function]}
781
+ onResponderTerminate={[Function]}
782
+ onResponderTerminationRequest={[Function]}
783
+ onStartShouldSetResponder={[Function]}
781
784
  style={
782
785
  [
783
786
  {
784
- "color": "#0C0A0A",
785
- "fontFamily": "AreaNormal-Semibold",
786
- "fontSize": 15,
787
- "fontStyle": "normal",
788
- "fontWeight": "300",
789
- "letterSpacing": -0.2,
790
- "lineHeight": 20,
787
+ "alignItems": "center",
788
+ "borderColor": "#DAD8D8",
789
+ "borderWidth": 1,
790
+ "flex": 1,
791
+ "flexDirection": "row",
792
+ "padding": 16,
793
+ },
794
+ {
795
+ "borderColor": "#0C0A0A",
796
+ "borderWidth": 2,
797
+ "padding": 15,
798
+ },
799
+ {
800
+ "borderRadius": 8,
791
801
  },
802
+ ]
803
+ }
804
+ testID="2875e66d-4e2a-47b1-a58b-61e316dcc66a"
805
+ >
806
+ <View
807
+ style={
792
808
  [
793
809
  {
794
- "lineHeight": 24,
810
+ "alignItems": "center",
811
+ "borderRadius": 9999,
812
+ "borderWidth": 2,
813
+ "height": 22,
814
+ "justifyContent": "center",
815
+ "width": 22,
795
816
  },
817
+ undefined,
796
818
  {
797
- "color": "#837C7C",
819
+ "backgroundColor": "#F4A584",
820
+ "borderColor": "#F4A584",
798
821
  },
799
- undefined,
800
- ],
801
- ]
802
- }
803
- >
804
- S
805
- </Text>
806
- </View>
807
- <View
808
- accessibilityLabel="4016fcfc-a08e-4800-bc07-0d7dd59848fc"
809
- accessibilityState={
810
- {
811
- "disabled": false,
812
- }
813
- }
814
- accessibilityValue={
815
- {
816
- "max": undefined,
817
- "min": undefined,
818
- "now": undefined,
819
- "text": undefined,
822
+ ]
823
+ }
824
+ testID="animated-checked"
825
+ >
826
+ <View
827
+ style={
828
+ {
829
+ "opacity": 1,
830
+ "scale": 1,
831
+ }
832
+ }
833
+ >
834
+ <Text
835
+ accessibilityElementsHidden={true}
836
+ allowFontScaling={false}
837
+ importantForAccessibility="no"
838
+ selectable={false}
839
+ style={
840
+ [
841
+ {
842
+ "color": "#0C0A0A",
843
+ "fontFamily": "AreaNormal-Semibold",
844
+ "fontSize": 15,
845
+ "fontStyle": "normal",
846
+ "fontWeight": "300",
847
+ "letterSpacing": -0.2,
848
+ "lineHeight": 20,
849
+ },
850
+ [
851
+ {
852
+ "fontFamily": "auroraicons",
853
+ "fontSize": 24,
854
+ "fontStyle": "normal",
855
+ "fontWeight": "normal",
856
+ "height": 24,
857
+ "lineHeight": 24,
858
+ "minHeight": 24,
859
+ "minWidth": 24,
860
+ "width": 24,
861
+ },
862
+ [
863
+ {
864
+ "color": "#0C0A0A",
865
+ },
866
+ undefined,
867
+ ],
868
+ ],
869
+ ]
870
+ }
871
+ testID="icon"
872
+ >
873
+
874
+ </Text>
875
+ </View>
876
+ </View>
877
+ <Text
878
+ style={
879
+ [
880
+ {
881
+ "color": "#0C0A0A",
882
+ "fontFamily": "AreaNormal-Semibold",
883
+ "fontSize": 15,
884
+ "fontStyle": "normal",
885
+ "fontWeight": "300",
886
+ "letterSpacing": -0.2,
887
+ "lineHeight": 20,
888
+ },
889
+ {
890
+ "color": "#0C0A0A",
891
+ "flex": 1,
892
+ "marginLeft": 16,
893
+ },
894
+ ]
895
+ }
896
+ >
897
+ S
898
+ </Text>
899
+ </View>
900
+ <View
901
+ accessibilityLabel="M"
902
+ accessibilityRole="radio"
903
+ accessibilityState={
904
+ {
905
+ "busy": undefined,
906
+ "checked": false,
907
+ "disabled": false,
908
+ "expanded": undefined,
909
+ "selected": undefined,
910
+ }
820
911
  }
821
- }
822
- accessible={true}
823
- focusable={true}
824
- onClick={[Function]}
825
- onResponderGrant={[Function]}
826
- onResponderMove={[Function]}
827
- onResponderRelease={[Function]}
828
- onResponderTerminate={[Function]}
829
- onResponderTerminationRequest={[Function]}
830
- onStartShouldSetResponder={[Function]}
831
- style={
832
- [
912
+ accessibilityValue={
833
913
  {
834
- "borderBottomColor": "#DAD8D8",
835
- "borderBottomWidth": 1,
836
- "paddingVertical": 20,
837
- },
838
- undefined,
839
- ]
840
- }
841
- testID="4016fcfc-a08e-4800-bc07-0d7dd59848fc"
842
- >
843
- <Text
914
+ "max": undefined,
915
+ "min": undefined,
916
+ "now": undefined,
917
+ "text": undefined,
918
+ }
919
+ }
920
+ accessible={true}
921
+ collapsable={false}
922
+ focusable={true}
923
+ onBlur={[Function]}
924
+ onClick={[Function]}
925
+ onFocus={[Function]}
926
+ onResponderGrant={[Function]}
927
+ onResponderMove={[Function]}
928
+ onResponderRelease={[Function]}
929
+ onResponderTerminate={[Function]}
930
+ onResponderTerminationRequest={[Function]}
931
+ onStartShouldSetResponder={[Function]}
844
932
  style={
845
933
  [
846
934
  {
847
- "color": "#0C0A0A",
848
- "fontFamily": "AreaNormal-Semibold",
849
- "fontSize": 15,
850
- "fontStyle": "normal",
851
- "fontWeight": "300",
852
- "letterSpacing": -0.2,
853
- "lineHeight": 20,
935
+ "alignItems": "center",
936
+ "borderColor": "#DAD8D8",
937
+ "borderWidth": 1,
938
+ "flex": 1,
939
+ "flexDirection": "row",
940
+ "padding": 16,
854
941
  },
942
+ false,
943
+ {
944
+ "borderRadius": 8,
945
+ },
946
+ ]
947
+ }
948
+ testID="4016fcfc-a08e-4800-bc07-0d7dd59848fc"
949
+ >
950
+ <View
951
+ style={
855
952
  [
856
953
  {
857
- "lineHeight": 24,
954
+ "alignItems": "center",
955
+ "borderRadius": 9999,
956
+ "borderWidth": 2,
957
+ "height": 22,
958
+ "justifyContent": "center",
959
+ "width": 22,
858
960
  },
859
- false,
860
961
  undefined,
861
- ],
862
- ]
863
- }
864
- >
865
- M
866
- </Text>
962
+ {
963
+ "backgroundColor": "#FFFFFF",
964
+ "borderColor": "#DAD8D8",
965
+ },
966
+ ]
967
+ }
968
+ testID="animated-checked"
969
+ >
970
+ <View
971
+ style={
972
+ {
973
+ "opacity": 0,
974
+ "scale": 0,
975
+ }
976
+ }
977
+ >
978
+ <Text
979
+ accessibilityElementsHidden={true}
980
+ allowFontScaling={false}
981
+ importantForAccessibility="no"
982
+ selectable={false}
983
+ style={
984
+ [
985
+ {
986
+ "color": "#0C0A0A",
987
+ "fontFamily": "AreaNormal-Semibold",
988
+ "fontSize": 15,
989
+ "fontStyle": "normal",
990
+ "fontWeight": "300",
991
+ "letterSpacing": -0.2,
992
+ "lineHeight": 20,
993
+ },
994
+ [
995
+ {
996
+ "fontFamily": "auroraicons",
997
+ "fontSize": 24,
998
+ "fontStyle": "normal",
999
+ "fontWeight": "normal",
1000
+ "height": 24,
1001
+ "lineHeight": 24,
1002
+ "minHeight": 24,
1003
+ "minWidth": 24,
1004
+ "width": 24,
1005
+ },
1006
+ [
1007
+ {
1008
+ "color": "#0C0A0A",
1009
+ },
1010
+ undefined,
1011
+ ],
1012
+ ],
1013
+ ]
1014
+ }
1015
+ testID="icon"
1016
+ >
1017
+
1018
+ </Text>
1019
+ </View>
1020
+ </View>
1021
+ <Text
1022
+ style={
1023
+ [
1024
+ {
1025
+ "color": "#0C0A0A",
1026
+ "fontFamily": "AreaNormal-Semibold",
1027
+ "fontSize": 15,
1028
+ "fontStyle": "normal",
1029
+ "fontWeight": "300",
1030
+ "letterSpacing": -0.2,
1031
+ "lineHeight": 20,
1032
+ },
1033
+ {
1034
+ "color": "#0C0A0A",
1035
+ "flex": 1,
1036
+ "marginLeft": 16,
1037
+ },
1038
+ ]
1039
+ }
1040
+ >
1041
+ M
1042
+ </Text>
1043
+ </View>
867
1044
  </View>
868
1045
  </View>
869
1046
  </View>
@@ -3,20 +3,34 @@ import React from "react";
3
3
  import { render } from "../../../../test/render";
4
4
  import { SelectModal } from "./SelectModal";
5
5
 
6
+ jest.mock("../../../../hooks/useStaticInfo", () => ({
7
+ useStaticInfo: () => ({ tradename: "LOOKIERO" }),
8
+ }));
9
+
6
10
  const mockOnChange = jest.fn();
7
- const options = [{ label: "Option label", value: "optionValue" }];
11
+ const mockOnClose = jest.fn();
12
+ const options = [
13
+ { label: "Option label", value: "optionValue" },
14
+ { label: "Selected label", value: "selectedValue" },
15
+ ];
8
16
 
9
- const renderSelectField = () =>
17
+ const renderSelectField = (value?: string) =>
10
18
  render(
11
19
  <SelectModal
12
20
  modalVisible={true}
13
21
  options={options}
14
22
  testID="select-field"
15
- value={undefined}
23
+ value={value}
16
24
  onChange={mockOnChange}
25
+ onClose={mockOnClose}
17
26
  />,
18
27
  );
19
28
 
29
+ beforeEach(() => {
30
+ mockOnChange.mockClear();
31
+ mockOnClose.mockClear();
32
+ });
33
+
20
34
  beforeAll(() => {
21
35
  jest.useFakeTimers();
22
36
  });
@@ -33,12 +47,53 @@ describe("SelectField component", () => {
33
47
  expect(toJSON()).toMatchSnapshot();
34
48
  });
35
49
 
36
- it("renders correctly", () => {
37
- const { getByTestId, getByText } = renderSelectField();
50
+ it("renders all options as radio buttons", () => {
51
+ const { getByRole } = renderSelectField();
52
+
53
+ expect(getByRole("radio", { name: "Option label" })).toBeTruthy();
54
+ expect(getByRole("radio", { name: "Selected label" })).toBeTruthy();
55
+ });
56
+
57
+ it("renders options inside a radiogroup", () => {
58
+ const { getByTestId } = renderSelectField();
59
+ const container = getByTestId("options-radiogroup");
60
+
61
+ expect(container.props.accessibilityRole).toBe("radiogroup");
62
+ });
63
+
64
+ it("unselected option has checked false", () => {
65
+ const { getByRole } = renderSelectField("selectedValue");
66
+
67
+ expect(getByRole("radio", { name: "Option label", checked: false })).toBeTruthy();
68
+ });
69
+
70
+ it("selected option has checked true", () => {
71
+ const { getByRole } = renderSelectField("selectedValue");
72
+
73
+ expect(getByRole("radio", { name: "Selected label", checked: true })).toBeTruthy();
74
+ });
75
+
76
+ it("accessibilityLabel uses label text, not value key", () => {
77
+ const { getByRole, queryByRole } = renderSelectField();
78
+
79
+ expect(getByRole("radio", { name: "Option label" })).toBeTruthy();
80
+ expect(queryByRole("radio", { name: "optionValue" })).toBeNull();
81
+ });
38
82
 
39
- fireEvent.press(getByTestId("select-field"));
40
- fireEvent.press(getByText("Option label"));
83
+ it("pressing an unselected option calls onChange and onClose", () => {
84
+ const { getByRole } = renderSelectField("selectedValue");
85
+
86
+ fireEvent.press(getByRole("radio", { name: "Option label" }));
41
87
 
42
88
  expect(mockOnChange).toHaveBeenCalledWith("optionValue");
89
+ expect(mockOnClose).toHaveBeenCalledTimes(1);
90
+ });
91
+
92
+ it("pressing the selected option does not call onChange", () => {
93
+ const { getByRole } = renderSelectField("selectedValue");
94
+
95
+ fireEvent.press(getByRole("radio", { name: "Selected label" }));
96
+
97
+ expect(mockOnChange).not.toHaveBeenCalled();
43
98
  });
44
99
  });
@@ -2,34 +2,51 @@ import { StyleSheet } from "react-native";
2
2
  import { theme } from "@lookiero/sty-psp-ui";
3
3
 
4
4
  const style = () => {
5
- const { borderWidth1, colorBgPrimaryLight, colorBorderInteractive, colorTextMedium, space1, space5, space6 } =
6
- theme();
5
+ const {
6
+ colorText,
7
+ colorBorderInputFocus,
8
+ colorBorderInteractive,
9
+ space025,
10
+ space3,
11
+ space4,
12
+ space6,
13
+ borderWidth1,
14
+ borderWidth2,
15
+ borderRadius3,
16
+ } = theme();
7
17
 
8
- const styles = StyleSheet.create({
18
+ return StyleSheet.create({
19
+ container: {
20
+ gap: space3,
21
+ },
9
22
  modalContent: {
10
- paddingBottom: space6,
11
23
  paddingHorizontal: space6,
12
24
  },
13
25
  modalTitle: {
14
- marginBottom: space1,
26
+ marginBottom: space3,
27
+ },
28
+ text: {
29
+ color: colorText,
30
+ flex: 1,
31
+ marginLeft: space4,
15
32
  },
16
- option: {
17
- borderBottomColor: colorBorderInteractive,
18
- borderBottomWidth: borderWidth1,
19
- paddingVertical: space5,
33
+ wrapper: {
34
+ alignItems: "center",
35
+ borderColor: colorBorderInteractive,
36
+ borderWidth: borderWidth1,
37
+ flex: 1,
38
+ flexDirection: "row",
39
+ padding: space4,
20
40
  },
21
- optionText: {
22
- lineHeight: space6,
41
+ wrapperChecked: {
42
+ borderColor: colorBorderInputFocus,
43
+ borderWidth: borderWidth2,
44
+ padding: space4 - space025,
23
45
  },
24
- textActive: {
25
- color: colorTextMedium,
46
+ wrapperLookiero: {
47
+ borderRadius: borderRadius3,
26
48
  },
27
49
  });
28
-
29
- return {
30
- ...styles,
31
- underlayColor: colorBgPrimaryLight,
32
- };
33
50
  };
34
51
 
35
52
  export { style };
@@ -1,12 +1,12 @@
1
- import React, { FC, useCallback, useMemo } from "react";
2
- import { StyleProp, TextStyle, TouchableHighlight, View, ViewStyle } from "react-native";
3
- import { Text } from "@lookiero/sty-psp-ui";
4
- import { Modal } from "@lookiero/sty-psp-ui";
1
+ import React, { FC, useMemo } from "react";
2
+ import { StyleProp, TextStyle, Pressable, View, ViewStyle } from "react-native";
3
+ import { Checkbox, Modal, Text } from "@lookiero/sty-psp-ui";
4
+ import { Tradename } from "@lookiero/sty-sp-tradename";
5
+ import { useStaticInfo } from "../../../../hooks/useStaticInfo";
5
6
  import { style as modalStyle } from "./SelectModal.style";
6
7
 
7
8
  interface SelectModalStyle {
8
9
  readonly modalContent: StyleProp<ViewStyle>;
9
- readonly option: StyleProp<ViewStyle>;
10
10
  readonly optionText: StyleProp<TextStyle>;
11
11
  }
12
12
 
@@ -38,15 +38,8 @@ const SelectModal: FC<SelectModalProps> = ({
38
38
  onChange = () => void 0,
39
39
  onClose = () => void 0,
40
40
  }) => {
41
- const handleOnPressOption = useCallback(
42
- (value: string) => {
43
- onChange(value);
44
- onClose();
45
- },
46
- [onClose, onChange],
47
- );
48
-
49
41
  const style = useMemo(() => modalStyle(), []);
42
+ const { tradename } = useStaticInfo();
50
43
 
51
44
  return (
52
45
  <Modal
@@ -63,25 +56,36 @@ const SelectModal: FC<SelectModalProps> = ({
63
56
  {title}
64
57
  </Text>
65
58
  )}
66
- {options.map(({ label, value: optionValue }) => (
67
- <TouchableHighlight
68
- key={optionValue}
69
- accessibilityLabel={optionValue}
70
- disabled={value === optionValue}
71
- style={[style.option, customStyle?.option]}
72
- testID={optionValue}
73
- underlayColor={style.underlayColor}
74
- accessible
75
- onPress={value !== optionValue ? () => handleOnPressOption(optionValue) : undefined}
76
- >
77
- <Text
78
- level={3}
79
- style={[style.optionText, value === optionValue && style.textActive, customStyle?.optionText]}
80
- >
81
- {label}
82
- </Text>
83
- </TouchableHighlight>
84
- ))}
59
+ <View accessibilityRole="radiogroup" style={style.container} testID="options-radiogroup">
60
+ {options.map(({ label, value: optionValue }) => {
61
+ const checked = value === optionValue;
62
+
63
+ return (
64
+ <Pressable
65
+ key={optionValue}
66
+ accessibilityLabel={label}
67
+ accessibilityRole="radio"
68
+ accessibilityState={{ checked, disabled: checked }}
69
+ disabled={checked}
70
+ testID={optionValue}
71
+ style={[
72
+ style.wrapper,
73
+ checked && style.wrapperChecked,
74
+ tradename === Tradename.LOOKIERO && style.wrapperLookiero,
75
+ ]}
76
+ accessible
77
+ onPress={() => {
78
+ onChange(optionValue);
79
+ onClose();
80
+ }}
81
+ >
82
+ <Checkbox checked={checked} />
83
+
84
+ <Text style={style.text}>{label}</Text>
85
+ </Pressable>
86
+ );
87
+ })}
88
+ </View>
85
89
  </View>
86
90
  </Modal>
87
91
  );
@@ -258,7 +258,6 @@ exports[`SelectField component matches the snapshot 1`] = `
258
258
  style={
259
259
  [
260
260
  {
261
- "paddingBottom": 24,
262
261
  "paddingHorizontal": 24,
263
262
  },
264
263
  undefined,
@@ -266,65 +265,302 @@ exports[`SelectField component matches the snapshot 1`] = `
266
265
  }
267
266
  >
268
267
  <View
269
- accessibilityLabel="optionValue"
270
- accessibilityState={
268
+ accessibilityRole="radiogroup"
269
+ style={
271
270
  {
272
- "disabled": false,
271
+ "gap": 12,
273
272
  }
274
273
  }
275
- accessibilityValue={
276
- {
277
- "max": undefined,
278
- "min": undefined,
279
- "now": undefined,
280
- "text": undefined,
274
+ testID="options-radiogroup"
275
+ >
276
+ <View
277
+ accessibilityLabel="Option label"
278
+ accessibilityRole="radio"
279
+ accessibilityState={
280
+ {
281
+ "busy": undefined,
282
+ "checked": false,
283
+ "disabled": false,
284
+ "expanded": undefined,
285
+ "selected": undefined,
286
+ }
281
287
  }
282
- }
283
- accessible={true}
284
- focusable={true}
285
- onClick={[Function]}
286
- onResponderGrant={[Function]}
287
- onResponderMove={[Function]}
288
- onResponderRelease={[Function]}
289
- onResponderTerminate={[Function]}
290
- onResponderTerminationRequest={[Function]}
291
- onStartShouldSetResponder={[Function]}
292
- style={
293
- [
288
+ accessibilityValue={
294
289
  {
295
- "borderBottomColor": "#DAD8D8",
296
- "borderBottomWidth": 1,
297
- "paddingVertical": 20,
298
- },
299
- undefined,
300
- ]
301
- }
302
- testID="optionValue"
303
- >
304
- <Text
290
+ "max": undefined,
291
+ "min": undefined,
292
+ "now": undefined,
293
+ "text": undefined,
294
+ }
295
+ }
296
+ accessible={true}
297
+ collapsable={false}
298
+ focusable={true}
299
+ onBlur={[Function]}
300
+ onClick={[Function]}
301
+ onFocus={[Function]}
302
+ onResponderGrant={[Function]}
303
+ onResponderMove={[Function]}
304
+ onResponderRelease={[Function]}
305
+ onResponderTerminate={[Function]}
306
+ onResponderTerminationRequest={[Function]}
307
+ onStartShouldSetResponder={[Function]}
305
308
  style={
306
309
  [
307
310
  {
308
- "color": "#0C0A0A",
309
- "fontFamily": "AreaNormal-Semibold",
310
- "fontSize": 15,
311
- "fontStyle": "normal",
312
- "fontWeight": "300",
313
- "letterSpacing": -0.2,
314
- "lineHeight": 20,
311
+ "alignItems": "center",
312
+ "borderColor": "#DAD8D8",
313
+ "borderWidth": 1,
314
+ "flex": 1,
315
+ "flexDirection": "row",
316
+ "padding": 16,
317
+ },
318
+ false,
319
+ {
320
+ "borderRadius": 8,
315
321
  },
322
+ ]
323
+ }
324
+ testID="optionValue"
325
+ >
326
+ <View
327
+ style={
316
328
  [
317
329
  {
318
- "lineHeight": 24,
330
+ "alignItems": "center",
331
+ "borderRadius": 9999,
332
+ "borderWidth": 2,
333
+ "height": 22,
334
+ "justifyContent": "center",
335
+ "width": 22,
319
336
  },
320
- false,
321
337
  undefined,
322
- ],
338
+ {
339
+ "backgroundColor": "#FFFFFF",
340
+ "borderColor": "#DAD8D8",
341
+ },
342
+ ]
343
+ }
344
+ testID="animated-checked"
345
+ >
346
+ <View
347
+ style={
348
+ {
349
+ "opacity": 0,
350
+ "scale": 0,
351
+ }
352
+ }
353
+ >
354
+ <Text
355
+ accessibilityElementsHidden={true}
356
+ allowFontScaling={false}
357
+ importantForAccessibility="no"
358
+ selectable={false}
359
+ style={
360
+ [
361
+ {
362
+ "color": "#0C0A0A",
363
+ "fontFamily": "AreaNormal-Semibold",
364
+ "fontSize": 15,
365
+ "fontStyle": "normal",
366
+ "fontWeight": "300",
367
+ "letterSpacing": -0.2,
368
+ "lineHeight": 20,
369
+ },
370
+ [
371
+ {
372
+ "fontFamily": "auroraicons",
373
+ "fontSize": 24,
374
+ "fontStyle": "normal",
375
+ "fontWeight": "normal",
376
+ "height": 24,
377
+ "lineHeight": 24,
378
+ "minHeight": 24,
379
+ "minWidth": 24,
380
+ "width": 24,
381
+ },
382
+ [
383
+ {
384
+ "color": "#0C0A0A",
385
+ },
386
+ undefined,
387
+ ],
388
+ ],
389
+ ]
390
+ }
391
+ testID="icon"
392
+ >
393
+
394
+ </Text>
395
+ </View>
396
+ </View>
397
+ <Text
398
+ style={
399
+ [
400
+ {
401
+ "color": "#0C0A0A",
402
+ "fontFamily": "AreaNormal-Semibold",
403
+ "fontSize": 15,
404
+ "fontStyle": "normal",
405
+ "fontWeight": "300",
406
+ "letterSpacing": -0.2,
407
+ "lineHeight": 20,
408
+ },
409
+ {
410
+ "color": "#0C0A0A",
411
+ "flex": 1,
412
+ "marginLeft": 16,
413
+ },
414
+ ]
415
+ }
416
+ >
417
+ Option label
418
+ </Text>
419
+ </View>
420
+ <View
421
+ accessibilityLabel="Selected label"
422
+ accessibilityRole="radio"
423
+ accessibilityState={
424
+ {
425
+ "busy": undefined,
426
+ "checked": false,
427
+ "disabled": false,
428
+ "expanded": undefined,
429
+ "selected": undefined,
430
+ }
431
+ }
432
+ accessibilityValue={
433
+ {
434
+ "max": undefined,
435
+ "min": undefined,
436
+ "now": undefined,
437
+ "text": undefined,
438
+ }
439
+ }
440
+ accessible={true}
441
+ collapsable={false}
442
+ focusable={true}
443
+ onBlur={[Function]}
444
+ onClick={[Function]}
445
+ onFocus={[Function]}
446
+ onResponderGrant={[Function]}
447
+ onResponderMove={[Function]}
448
+ onResponderRelease={[Function]}
449
+ onResponderTerminate={[Function]}
450
+ onResponderTerminationRequest={[Function]}
451
+ onStartShouldSetResponder={[Function]}
452
+ style={
453
+ [
454
+ {
455
+ "alignItems": "center",
456
+ "borderColor": "#DAD8D8",
457
+ "borderWidth": 1,
458
+ "flex": 1,
459
+ "flexDirection": "row",
460
+ "padding": 16,
461
+ },
462
+ false,
463
+ {
464
+ "borderRadius": 8,
465
+ },
323
466
  ]
324
467
  }
468
+ testID="selectedValue"
325
469
  >
326
- Option label
327
- </Text>
470
+ <View
471
+ style={
472
+ [
473
+ {
474
+ "alignItems": "center",
475
+ "borderRadius": 9999,
476
+ "borderWidth": 2,
477
+ "height": 22,
478
+ "justifyContent": "center",
479
+ "width": 22,
480
+ },
481
+ undefined,
482
+ {
483
+ "backgroundColor": "#FFFFFF",
484
+ "borderColor": "#DAD8D8",
485
+ },
486
+ ]
487
+ }
488
+ testID="animated-checked"
489
+ >
490
+ <View
491
+ style={
492
+ {
493
+ "opacity": 0,
494
+ "scale": 0,
495
+ }
496
+ }
497
+ >
498
+ <Text
499
+ accessibilityElementsHidden={true}
500
+ allowFontScaling={false}
501
+ importantForAccessibility="no"
502
+ selectable={false}
503
+ style={
504
+ [
505
+ {
506
+ "color": "#0C0A0A",
507
+ "fontFamily": "AreaNormal-Semibold",
508
+ "fontSize": 15,
509
+ "fontStyle": "normal",
510
+ "fontWeight": "300",
511
+ "letterSpacing": -0.2,
512
+ "lineHeight": 20,
513
+ },
514
+ [
515
+ {
516
+ "fontFamily": "auroraicons",
517
+ "fontSize": 24,
518
+ "fontStyle": "normal",
519
+ "fontWeight": "normal",
520
+ "height": 24,
521
+ "lineHeight": 24,
522
+ "minHeight": 24,
523
+ "minWidth": 24,
524
+ "width": 24,
525
+ },
526
+ [
527
+ {
528
+ "color": "#0C0A0A",
529
+ },
530
+ undefined,
531
+ ],
532
+ ],
533
+ ]
534
+ }
535
+ testID="icon"
536
+ >
537
+
538
+ </Text>
539
+ </View>
540
+ </View>
541
+ <Text
542
+ style={
543
+ [
544
+ {
545
+ "color": "#0C0A0A",
546
+ "fontFamily": "AreaNormal-Semibold",
547
+ "fontSize": 15,
548
+ "fontStyle": "normal",
549
+ "fontWeight": "300",
550
+ "letterSpacing": -0.2,
551
+ "lineHeight": 20,
552
+ },
553
+ {
554
+ "color": "#0C0A0A",
555
+ "flex": 1,
556
+ "marginLeft": 16,
557
+ },
558
+ ]
559
+ }
560
+ >
561
+ Selected label
562
+ </Text>
563
+ </View>
328
564
  </View>
329
565
  </View>
330
566
  </View>