@cambly/syntax-core 5.8.0 → 5.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -124,6 +124,7 @@ __export(src_exports, {
124
124
  Heading: () => Heading_default,
125
125
  IconButton: () => IconButton_default,
126
126
  MiniActionCard: () => MiniActionCard_default,
127
+ Modal: () => Modal,
127
128
  RadioButton: () => RadioButton_default,
128
129
  SelectList: () => SelectList_default,
129
130
  Typography: () => Typography_default
@@ -601,11 +602,11 @@ var ButtonGroup = ({
601
602
  size = "md",
602
603
  children
603
604
  }) => {
604
- const classnames2 = (0, import_classnames5.default)(ButtonGroup_module_default.buttonGroup, gap[size], {
605
+ const classnames3 = (0, import_classnames5.default)(ButtonGroup_module_default.buttonGroup, gap[size], {
605
606
  [ButtonGroup_module_default.horizontal]: orientation === "horizontal",
606
607
  [ButtonGroup_module_default.vertical]: orientation === "vertical"
607
608
  });
608
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: classnames2, children });
609
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: classnames3, children });
609
610
  };
610
611
  var ButtonGroup_default = ButtonGroup;
611
612
 
@@ -616,7 +617,7 @@ var Card = ({
616
617
  size = "sm",
617
618
  "data-testid": dataTestId
618
619
  }) => {
619
- const sizeWidth = {
620
+ const sizeWidth2 = {
620
621
  sm: 352,
621
622
  lg: 744
622
623
  };
@@ -626,7 +627,7 @@ var Card = ({
626
627
  rounding: "xl",
627
628
  padding: 7,
628
629
  smPadding: 9,
629
- maxWidth: sizeWidth[size],
630
+ maxWidth: sizeWidth2[size],
630
631
  width: "100%",
631
632
  backgroundColor: "white",
632
633
  "data-testid": dataTestId,
@@ -769,7 +770,7 @@ function setupGlobalFocusEvents() {
769
770
  return;
770
771
  }
771
772
  const { focus } = HTMLElement.prototype;
772
- HTMLElement.prototype.focus = function focusElement(...args) {
773
+ HTMLElement.prototype.focus = function focusElement2(...args) {
773
774
  hasEventBeforeFocus = true;
774
775
  focus.apply(this, args);
775
776
  };
@@ -904,15 +905,207 @@ var MiniActionCard = ({
904
905
  }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: MiniActionCard_module_default.miniActionCard, children });
905
906
  var MiniActionCard_default = MiniActionCard;
906
907
 
907
- // src/RadioButton/RadioButton.tsx
908
- var import_react6 = require("react");
908
+ // src/Modal/Modal.tsx
909
909
  var import_classnames8 = __toESM(require_classnames());
910
910
 
911
+ // src/Modal/FocusTrap.tsx
912
+ var import_react6 = require("react");
913
+ var import_jsx_runtime13 = require("react/jsx-runtime");
914
+ function queryFocusableAll(el) {
915
+ const selector = [
916
+ "a[href]",
917
+ "area[href]",
918
+ "input:not([disabled])",
919
+ "select:not([disabled])",
920
+ "textarea:not([disabled])",
921
+ "button:not([disabled])",
922
+ "iframe",
923
+ "object",
924
+ "embed",
925
+ '[tabindex="-1"]',
926
+ '[tabindex="0"]',
927
+ "[contenteditable]",
928
+ "audio[controls]",
929
+ "video[controls]",
930
+ "summary"
931
+ ].join(",");
932
+ return el.querySelectorAll(selector);
933
+ }
934
+ var focusElement = (el) => {
935
+ if (typeof el.focus === "function") {
936
+ el.focus();
937
+ }
938
+ };
939
+ function FocusTrap({
940
+ children
941
+ }) {
942
+ const elRef = (0, import_react6.useRef)(null);
943
+ const previouslyFocusedElRef = (0, import_react6.useRef)(null);
944
+ (0, import_react6.useEffect)(() => {
945
+ const { current: element } = elRef;
946
+ const focusFirstChild = () => {
947
+ const withinIframe = window !== window.parent;
948
+ if (element && !withinIframe) {
949
+ focusElement(queryFocusableAll(element)[0]);
950
+ }
951
+ };
952
+ const handleFocus = (event) => {
953
+ if (!element || event.target instanceof Node && element.contains(event.target)) {
954
+ return;
955
+ }
956
+ if (event.target instanceof Element && event.target.closest('[data-testid="syntax-focus-trap"]') !== null) {
957
+ return;
958
+ }
959
+ event.stopPropagation();
960
+ event.preventDefault();
961
+ focusFirstChild();
962
+ };
963
+ previouslyFocusedElRef.current = document.activeElement;
964
+ focusFirstChild();
965
+ document.addEventListener("focus", handleFocus, true);
966
+ return function cleanup() {
967
+ const { current: previouslyFocusedEl } = previouslyFocusedElRef;
968
+ document.removeEventListener("focus", handleFocus, true);
969
+ if (previouslyFocusedEl) {
970
+ focusElement(previouslyFocusedEl);
971
+ }
972
+ };
973
+ }, [elRef, previouslyFocusedElRef]);
974
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { "data-testid": "syntax-focus-trap", ref: elRef, children });
975
+ }
976
+
977
+ // src/Modal/StopScroll.tsx
978
+ var import_react7 = require("react");
979
+ function StopScroll(props) {
980
+ (0, import_react7.useEffect)(() => {
981
+ const originalStyle = window.getComputedStyle(document.body).overflow;
982
+ document.body.style.overflow = "hidden";
983
+ return () => {
984
+ document.body.style.overflow = originalStyle;
985
+ };
986
+ }, []);
987
+ return props.children;
988
+ }
989
+
990
+ // src/Modal/Layer.tsx
991
+ var import_react_dom = require("react-dom");
992
+ var import_jsx_runtime14 = require("react/jsx-runtime");
993
+ function Layer({
994
+ children,
995
+ zIndex = 1
996
+ }) {
997
+ return (0, import_react_dom.createPortal)(
998
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
999
+ Box_default,
1000
+ {
1001
+ "data-testid": "syntax-layer",
1002
+ position: "fixed",
1003
+ dangerouslySetInlineStyle: {
1004
+ __style: { zIndex, inset: 0 }
1005
+ },
1006
+ children
1007
+ }
1008
+ ),
1009
+ document.body
1010
+ );
1011
+ }
1012
+
1013
+ // css-module:./Modal.module.css#css-module
1014
+ var Modal_module_default = { "backdrop": "_backdrop_30t3h_1", "closeButton": "_closeButton_30t3h_12", "closeButtonWithImage": "_closeButtonWithImage_30t3h_32" };
1015
+
1016
+ // src/Modal/Modal.tsx
1017
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1018
+ function XIcon({ color = "#000" }) {
1019
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", fill: color, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1020
+ "path",
1021
+ {
1022
+ fill: "inherit",
1023
+ d: "M11.25.758a.83.83 0 0 0-1.175 0L6 4.825 1.925.75A.83.83 0 1 0 .75 1.925L4.825 6 .75 10.075a.83.83 0 1 0 1.175 1.175L6 7.175l4.075 4.075a.83.83 0 1 0 1.175-1.175L7.175 6l4.075-4.075a.835.835 0 0 0 0-1.167Z"
1024
+ }
1025
+ ) });
1026
+ }
1027
+ var sizeWidth = {
1028
+ sm: 400,
1029
+ lg: 600
1030
+ };
1031
+ function Modal({
1032
+ header,
1033
+ children,
1034
+ image,
1035
+ onDismiss,
1036
+ footer,
1037
+ accessibilityCloseLabel = "close modal",
1038
+ size = "sm",
1039
+ zIndex = 1,
1040
+ "data-testid": dataTestId
1041
+ }) {
1042
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Layer, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(StopScroll, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(FocusTrap, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1043
+ "div",
1044
+ {
1045
+ className: Modal_module_default.backdrop,
1046
+ role: "presentation",
1047
+ onClick: (e) => e.target === e.currentTarget && onDismiss(),
1048
+ onKeyDown: (e) => e.key === "Escape" && onDismiss(),
1049
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1050
+ Box_default,
1051
+ {
1052
+ "data-testid": dataTestId,
1053
+ backgroundColor: "white",
1054
+ rounding: "xl",
1055
+ display: "flex",
1056
+ direction: "column",
1057
+ minWidth: 240,
1058
+ maxWidth: sizeWidth[size],
1059
+ width: "100%",
1060
+ dangerouslySetInlineStyle: { __style: { overflow: "hidden" } },
1061
+ children: [
1062
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { position: "relative", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1063
+ "button",
1064
+ {
1065
+ "aria-label": accessibilityCloseLabel,
1066
+ type: "button",
1067
+ className: (0, import_classnames8.default)(Modal_module_default.closeButton, {
1068
+ [Modal_module_default.closeButtonWithImage]: !!image
1069
+ }),
1070
+ onClick: onDismiss,
1071
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(XIcon, { color: image ? "#fff" : "#000" })
1072
+ }
1073
+ ) }),
1074
+ image && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { maxHeight: 200, children: image }),
1075
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { display: "flex", gap: 3, direction: "column", padding: 9, children: [
1076
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Heading_default, { as: "h1", size: 500, children: header }),
1077
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Box_default, { marginBottom: 4, children }),
1078
+ footer && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1079
+ Box_default,
1080
+ {
1081
+ display: "flex",
1082
+ direction: "column",
1083
+ gap: 3,
1084
+ smDirection: "row",
1085
+ smJustifyContent: "end",
1086
+ lgDirection: "row",
1087
+ lgJustifyContent: "end",
1088
+ children: footer
1089
+ }
1090
+ )
1091
+ ] })
1092
+ ]
1093
+ }
1094
+ )
1095
+ }
1096
+ ) }) }) });
1097
+ }
1098
+ Modal.displayName = "Modal";
1099
+
1100
+ // src/RadioButton/RadioButton.tsx
1101
+ var import_react8 = require("react");
1102
+ var import_classnames9 = __toESM(require_classnames());
1103
+
911
1104
  // css-module:./RadioButton.module.css#css-module
912
1105
  var RadioButton_module_default = { "radioBaseContainer": "_radioBaseContainer_1yyn9_1", "disabled": "_disabled_1yyn9_9", "cursorDisabled": "_cursorDisabled_1yyn9_13", "cursorEnabled": "_cursorEnabled_1yyn9_17", "smBase": "_smBase_1yyn9_21", "mdBase": "_mdBase_1yyn9_25", "radioStyleOverride": "_radioStyleOverride_1yyn9_29", "smOverride": "_smOverride_1yyn9_34", "mdOverride": "_mdOverride_1yyn9_39", "background": "_background_1yyn9_44", "sm": "_sm_1yyn9_21", "md": "_md_1yyn9_25", "neutralBorder": "_neutralBorder_1yyn9_61", "smCheckedBorder": "_smCheckedBorder_1yyn9_65", "mdCheckedBorder": "_mdCheckedBorder_1yyn9_69", "errorBorderColor": "_errorBorderColor_1yyn9_73", "borderColor": "_borderColor_1yyn9_77" };
913
1106
 
914
1107
  // src/RadioButton/RadioButton.tsx
915
- var import_jsx_runtime13 = require("react/jsx-runtime");
1108
+ var import_jsx_runtime16 = require("react/jsx-runtime");
916
1109
  var RadioButton = ({
917
1110
  checked = false,
918
1111
  "data-testid": dataTestId,
@@ -925,17 +1118,17 @@ var RadioButton = ({
925
1118
  size = "md",
926
1119
  value
927
1120
  }) => {
928
- const [isFocused, setIsFocused] = (0, import_react6.useState)(false);
1121
+ const [isFocused, setIsFocused] = (0, import_react8.useState)(false);
929
1122
  const { isFocusVisible: isFocusVisible2 } = useFocusVisible();
930
- const sharedStyles = (0, import_classnames8.default)(RadioButton_module_default.background, RadioButton_module_default[size], {
1123
+ const sharedStyles = (0, import_classnames9.default)(RadioButton_module_default.background, RadioButton_module_default[size], {
931
1124
  [RadioButton_module_default.errorBorderColor]: error,
932
1125
  [RadioButton_module_default.borderColor]: !error,
933
1126
  [Focus_module_default.accessibilityOutlineFocus]: isFocused && isFocusVisible2
934
1127
  });
935
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1128
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
936
1129
  "label",
937
1130
  {
938
- className: (0, import_classnames8.default)(
1131
+ className: (0, import_classnames9.default)(
939
1132
  RadioButton_module_default.radioBaseContainer,
940
1133
  RadioButton_module_default[`cursor${disabled ? "Disabled" : "Enabled"}`],
941
1134
  {
@@ -945,23 +1138,23 @@ var RadioButton = ({
945
1138
  }
946
1139
  ),
947
1140
  children: [
948
- checked ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1141
+ checked ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
949
1142
  "div",
950
1143
  {
951
- className: (0, import_classnames8.default)(sharedStyles, {
1144
+ className: (0, import_classnames9.default)(sharedStyles, {
952
1145
  [RadioButton_module_default.mdCheckedBorder]: size === "md",
953
1146
  [RadioButton_module_default.smCheckedBorder]: size === "sm"
954
1147
  })
955
1148
  }
956
- ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: (0, import_classnames8.default)(sharedStyles, RadioButton_module_default.neutralBorder) }),
957
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1149
+ ) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: (0, import_classnames9.default)(sharedStyles, RadioButton_module_default.neutralBorder) }),
1150
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
958
1151
  "input",
959
1152
  {
960
1153
  "data-testid": dataTestId,
961
1154
  type: "radio",
962
1155
  id,
963
1156
  name,
964
- className: (0, import_classnames8.default)(
1157
+ className: (0, import_classnames9.default)(
965
1158
  RadioButton_module_default.radioStyleOverride,
966
1159
  RadioButton_module_default[`cursor${disabled ? "Disabled" : "Enabled"}`],
967
1160
  {
@@ -981,7 +1174,7 @@ var RadioButton = ({
981
1174
  }
982
1175
  }
983
1176
  ),
984
- label && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1177
+ label && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
985
1178
  Typography_default,
986
1179
  {
987
1180
  size: size === "md" ? 200 : 100,
@@ -996,8 +1189,8 @@ var RadioButton = ({
996
1189
  var RadioButton_default = RadioButton;
997
1190
 
998
1191
  // src/SelectList/SelectList.tsx
999
- var import_react7 = require("react");
1000
- var import_classnames9 = __toESM(require_classnames());
1192
+ var import_react9 = require("react");
1193
+ var import_classnames10 = __toESM(require_classnames());
1001
1194
 
1002
1195
  // ../syntax-design-tokens/dist/js/index.js
1003
1196
  var ColorBaseDestructive700 = "#d32a4b";
@@ -1007,17 +1200,17 @@ var ColorBaseGray800 = "#353535";
1007
1200
  var SelectList_module_default = { "selectContainer": "_selectContainer_1u9cw_1", "opacityOverlay": "_opacityOverlay_1u9cw_7", "outerTextContainer": "_outerTextContainer_1u9cw_11", "selectWrapper": "_selectWrapper_1u9cw_16", "selectBox": "_selectBox_1u9cw_21", "selectMouseFocusStyling": "_selectMouseFocusStyling_1u9cw_35", "unselected": "_unselected_1u9cw_40", "selected": "_selected_1u9cw_44", "arrowIcon": "_arrowIcon_1u9cw_48", "sm": "_sm_1u9cw_62", "md": "_md_1u9cw_67", "lg": "_lg_1u9cw_72", "selectError": "_selectError_1u9cw_77" };
1008
1201
 
1009
1202
  // src/SelectList/SelectOption.tsx
1010
- var import_jsx_runtime14 = require("react/jsx-runtime");
1203
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1011
1204
  var SelectOption = ({
1012
1205
  "data-testid": dataTestId,
1013
1206
  value,
1014
1207
  label,
1015
1208
  disabled = false
1016
- }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { "data-testid": dataTestId, value, disabled, children: label });
1209
+ }) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { "data-testid": dataTestId, value, disabled, children: label });
1017
1210
  var SelectOption_default = SelectOption;
1018
1211
 
1019
1212
  // src/SelectList/SelectList.tsx
1020
- var import_jsx_runtime15 = require("react/jsx-runtime");
1213
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1021
1214
  var iconSize3 = {
1022
1215
  sm: 20,
1023
1216
  md: 24,
@@ -1035,25 +1228,25 @@ var SelectList = ({
1035
1228
  selectedValue = "",
1036
1229
  size = "md"
1037
1230
  }) => {
1038
- const id = (0, import_react7.useId)();
1231
+ const id = (0, import_react9.useId)();
1039
1232
  const { isFocusVisible: isFocusVisible2 } = useFocusVisible();
1040
- const [isFocused, setIsFocused] = (0, import_react7.useState)(false);
1041
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1233
+ const [isFocused, setIsFocused] = (0, import_react9.useState)(false);
1234
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1042
1235
  "div",
1043
1236
  {
1044
- className: (0, import_classnames9.default)(SelectList_module_default.selectContainer, {
1237
+ className: (0, import_classnames10.default)(SelectList_module_default.selectContainer, {
1045
1238
  [SelectList_module_default.opacityOverlay]: disabled
1046
1239
  }),
1047
1240
  children: [
1048
- label && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { htmlFor: id, className: SelectList_module_default.outerTextContainer, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Typography_default, { size: 100, color: "gray700", children: label }) }),
1049
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: SelectList_module_default.selectWrapper, children: [
1050
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1241
+ label && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { htmlFor: id, className: SelectList_module_default.outerTextContainer, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Typography_default, { size: 100, color: "gray700", children: label }) }),
1242
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: SelectList_module_default.selectWrapper, children: [
1243
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
1051
1244
  "select",
1052
1245
  {
1053
1246
  id,
1054
1247
  "data-testid": dataTestId,
1055
1248
  disabled,
1056
- className: (0, import_classnames9.default)(SelectList_module_default.selectBox, SelectList_module_default[size], {
1249
+ className: (0, import_classnames10.default)(SelectList_module_default.selectBox, SelectList_module_default[size], {
1057
1250
  [SelectList_module_default.unselected]: !selectedValue && !errorText,
1058
1251
  [SelectList_module_default.selected]: selectedValue && !errorText,
1059
1252
  [SelectList_module_default.selectError]: errorText,
@@ -1068,19 +1261,19 @@ var SelectList = ({
1068
1261
  onFocus: () => setIsFocused(true),
1069
1262
  onBlur: () => setIsFocused(false),
1070
1263
  children: [
1071
- placeholderText && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("option", { disabled: true, value: placeholderText, children: placeholderText }),
1264
+ placeholderText && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { disabled: true, value: placeholderText, children: placeholderText }),
1072
1265
  children
1073
1266
  ]
1074
1267
  }
1075
1268
  ),
1076
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: SelectList_module_default.arrowIcon, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1269
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: SelectList_module_default.arrowIcon, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1077
1270
  "svg",
1078
1271
  {
1079
1272
  focusable: "false",
1080
1273
  "aria-hidden": "true",
1081
1274
  viewBox: "0 0 24 24",
1082
1275
  width: iconSize3[size],
1083
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1276
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1084
1277
  "path",
1085
1278
  {
1086
1279
  fill: errorText ? ColorBaseDestructive700 : ColorBaseGray800,
@@ -1090,7 +1283,7 @@ var SelectList = ({
1090
1283
  }
1091
1284
  ) })
1092
1285
  ] }),
1093
- (helperText || errorText) && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: SelectList_module_default.outerTextContainer, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1286
+ (helperText || errorText) && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: SelectList_module_default.outerTextContainer, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1094
1287
  Typography_default,
1095
1288
  {
1096
1289
  size: 100,
@@ -1117,6 +1310,7 @@ SelectList.Option = SelectOption_default;
1117
1310
  Heading,
1118
1311
  IconButton,
1119
1312
  MiniActionCard,
1313
+ Modal,
1120
1314
  RadioButton,
1121
1315
  SelectList,
1122
1316
  Typography