@kodiak-finance/orderly-ui-notification 2.8.20 → 2.8.21-beta.3

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.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { useMemo, useState, useEffect, useCallback } from 'react';
1
+ import React2, { useMemo, useState, useEffect, useCallback, useRef, useLayoutEffect } from 'react';
2
2
  import { useTranslation } from '@kodiak-finance/orderly-i18n';
3
- import { Flex, Text, cn, ChevronDownIcon, ScrollArea, Divider, Icon, ExtensionSlot, ExtensionPositionEnum, ChevronLeftIcon, ChevronRightIcon } from '@kodiak-finance/orderly-ui';
3
+ import { Flex, Text, cn, ChevronDownIcon, ScrollArea, Divider, useEmblaCarousel, Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody, Icon, ExtensionSlot, ExtensionPositionEnum, ChevronLeftIcon, ChevronRightIcon, useScreen, CloseIcon } from '@kodiak-finance/orderly-ui';
4
4
  import { AnnouncementType, EMPTY_LIST } from '@kodiak-finance/orderly-types';
5
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
  import { UTCDate, UTCDateMini } from '@date-fns/utc';
7
7
  import { differenceInHours, differenceInMinutes, format } from 'date-fns';
8
8
  import { produce } from 'immer';
@@ -791,8 +791,9 @@ var useAnnouncement = (options) => {
791
791
  };
792
792
  useEffect(() => {
793
793
  const len = memoizedTips.length;
794
+ const shouldShow = announcementStore.show ?? true;
794
795
  setShowAnnouncement(
795
- Boolean(len) && announcementStore.show && !options?.hideTips
796
+ Boolean(len) && shouldShow && !options?.hideTips
796
797
  );
797
798
  }, [
798
799
  memoizedTips,
@@ -866,7 +867,464 @@ var AnnouncementCenterPage = (props) => {
866
867
  }
867
868
  );
868
869
  };
870
+ var useMarqueeOnce = (opts) => {
871
+ const {
872
+ isActive,
873
+ pxPerSec = 60,
874
+ startDelayMs = 500,
875
+ endDelayMs = 500,
876
+ fallbackStayMs = 2500,
877
+ onFinish
878
+ } = opts;
879
+ const containerRef = useRef(null);
880
+ const contentRef = useRef(null);
881
+ const rafRef = useRef(null);
882
+ const stopAll = () => {
883
+ if (rafRef.current) {
884
+ cancelAnimationFrame(rafRef.current);
885
+ }
886
+ rafRef.current = null;
887
+ };
888
+ const timers = useRef([]);
889
+ const clearTimers = () => {
890
+ timers.current?.forEach((id) => {
891
+ if (id) {
892
+ clearTimeout(id);
893
+ }
894
+ });
895
+ timers.current = [];
896
+ };
897
+ const [overflow, setOverflow] = useState(false);
898
+ const [delta, setDelta] = useState(0);
899
+ useLayoutEffect(() => {
900
+ const c = containerRef.current;
901
+ const t = contentRef.current;
902
+ if (!c || !t) {
903
+ return;
904
+ }
905
+ const update = () => {
906
+ const cw = c.clientWidth;
907
+ const tw = t.scrollWidth;
908
+ const need = Math.max(0, tw - cw);
909
+ setOverflow(need > 0);
910
+ setDelta(need);
911
+ };
912
+ update();
913
+ const ro = new ResizeObserver(update);
914
+ ro.observe(c);
915
+ ro.observe(t);
916
+ return () => {
917
+ ro.disconnect();
918
+ };
919
+ }, []);
920
+ useEffect(() => {
921
+ if (!isActive) {
922
+ stopAll();
923
+ clearTimers();
924
+ if (contentRef.current) {
925
+ contentRef.current.style.transform = "translate3d(0, 0, 0)";
926
+ }
927
+ return;
928
+ }
929
+ const run = async () => {
930
+ stopAll();
931
+ clearTimers();
932
+ if (!overflow || delta <= 0) {
933
+ const id = setTimeout(() => {
934
+ onFinish?.();
935
+ }, fallbackStayMs);
936
+ timers.current.push(id);
937
+ return;
938
+ }
939
+ const startId = setTimeout(() => {
940
+ const distance = delta;
941
+ const durationMs = distance / pxPerSec * 1e3;
942
+ const el = contentRef.current;
943
+ if (!el) {
944
+ return;
945
+ }
946
+ let startTs = 0;
947
+ const startX = 0;
948
+ const endX = -distance;
949
+ const step = (ts) => {
950
+ if (!startTs) {
951
+ startTs = ts;
952
+ }
953
+ const progress = Math.min(1, (ts - startTs) / durationMs);
954
+ const x = startX + (endX - startX) * progress;
955
+ el.style.transform = `translate3d(${x}px, 0, 0)`;
956
+ if (progress < 1) {
957
+ rafRef.current = requestAnimationFrame(step);
958
+ } else {
959
+ const endId = setTimeout(() => {
960
+ onFinish?.();
961
+ }, endDelayMs);
962
+ timers.current.push(endId);
963
+ }
964
+ };
965
+ rafRef.current = requestAnimationFrame(step);
966
+ }, startDelayMs);
967
+ timers.current.push(startId);
968
+ };
969
+ run();
970
+ return () => {
971
+ stopAll();
972
+ clearTimers();
973
+ };
974
+ }, [
975
+ isActive,
976
+ overflow,
977
+ delta,
978
+ pxPerSec,
979
+ startDelayMs,
980
+ endDelayMs,
981
+ fallbackStayMs,
982
+ onFinish
983
+ ]);
984
+ return { containerRef, contentRef, overflow, delta };
985
+ };
986
+ var usePrevNextButtons = (emblaApi, onButtonClick) => {
987
+ const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);
988
+ const [nextBtnDisabled, setNextBtnDisabled] = useState(true);
989
+ const onPrevButtonClick = useCallback(() => {
990
+ if (!emblaApi) {
991
+ return;
992
+ }
993
+ emblaApi.scrollPrev();
994
+ }, [emblaApi, onButtonClick]);
995
+ const onNextButtonClick = useCallback(() => {
996
+ if (!emblaApi) {
997
+ return;
998
+ }
999
+ emblaApi.scrollNext();
1000
+ }, [emblaApi, onButtonClick]);
1001
+ const onSelect = useCallback((api) => {
1002
+ setPrevBtnDisabled(!api.canScrollPrev());
1003
+ setNextBtnDisabled(!api.canScrollNext());
1004
+ }, []);
1005
+ useEffect(() => {
1006
+ if (!emblaApi) {
1007
+ return;
1008
+ }
1009
+ onSelect(emblaApi);
1010
+ emblaApi.on("reInit", onSelect).on("select", onSelect);
1011
+ return () => {
1012
+ emblaApi.off("reInit", onSelect).off("select", onSelect);
1013
+ };
1014
+ }, [emblaApi, onSelect]);
1015
+ return {
1016
+ prevBtnDisabled,
1017
+ nextBtnDisabled,
1018
+ onPrevButtonClick,
1019
+ onNextButtonClick
1020
+ };
1021
+ };
1022
+ var useSelectedSnapDisplay = (emblaApi) => {
1023
+ const [selectedSnap, setSelectedSnap] = useState(0);
1024
+ const [snapCount, setSnapCount] = useState(0);
1025
+ const updateScrollSnapState = useCallback((api) => {
1026
+ if (api) {
1027
+ setSnapCount(api.scrollSnapList().length);
1028
+ setSelectedSnap(api.selectedScrollSnap());
1029
+ }
1030
+ }, []);
1031
+ useEffect(() => {
1032
+ if (!emblaApi) {
1033
+ return;
1034
+ }
1035
+ updateScrollSnapState(emblaApi);
1036
+ emblaApi.on("select", updateScrollSnapState);
1037
+ emblaApi.on("reInit", updateScrollSnapState);
1038
+ return () => {
1039
+ emblaApi.off("select", updateScrollSnapState);
1040
+ emblaApi.off("reInit", updateScrollSnapState);
1041
+ };
1042
+ }, [emblaApi, updateScrollSnapState]);
1043
+ return {
1044
+ selectedSnap,
1045
+ snapCount
1046
+ };
1047
+ };
1048
+ var TipsType = ({ type }) => {
1049
+ const { t } = useTranslation();
1050
+ const { label, className } = useMemo(() => {
1051
+ const map = {
1052
+ [AnnouncementType.Listing]: {
1053
+ label: t("announcement.type.listing"),
1054
+ className: "oui-bg-primary/15 oui-text-primary"
1055
+ },
1056
+ [AnnouncementType.Maintenance]: {
1057
+ label: t("announcement.type.maintenance"),
1058
+ className: "oui-bg-[rgba(232,136,0,0.15)] oui-text-warning-darken"
1059
+ },
1060
+ [AnnouncementType.Delisting]: {
1061
+ label: t("announcement.type.delisting"),
1062
+ className: "oui-bg-[rgba(232,136,0,0.15)] oui-text-warning-darken"
1063
+ }
1064
+ };
1065
+ return map[type] || {
1066
+ label: type,
1067
+ className: map[AnnouncementType.Listing].className
1068
+ };
1069
+ }, [type, t]);
1070
+ if (!label) {
1071
+ return null;
1072
+ }
1073
+ return /* @__PURE__ */ jsx(
1074
+ Flex,
1075
+ {
1076
+ justify: "center",
1077
+ px: 2,
1078
+ r: "base",
1079
+ className: cn(
1080
+ "oui-text-2xs oui-font-medium oui-leading-[18px]",
1081
+ "oui-whitespace-nowrap oui-break-normal",
1082
+ className
1083
+ ),
1084
+ children: label
1085
+ }
1086
+ );
1087
+ };
1088
+ var AnnouncementItem2 = (props) => {
1089
+ const { type, text, url, isActive, onItemFinish, onItemClick } = props;
1090
+ const { containerRef, contentRef, overflow } = useMarqueeOnce({
1091
+ isActive,
1092
+ pxPerSec: 90,
1093
+ startDelayMs: 1e3,
1094
+ endDelayMs: 1e3,
1095
+ fallbackStayMs: 4e3,
1096
+ onFinish: onItemFinish
1097
+ });
1098
+ const onClick = () => {
1099
+ if (url) {
1100
+ onItemClick?.(url);
1101
+ }
1102
+ };
1103
+ return /* @__PURE__ */ jsx(
1104
+ Flex,
1105
+ {
1106
+ height: "100%",
1107
+ itemAlign: "center",
1108
+ className: "oui-flex-none oui-basis-full oui-transform-gpu",
1109
+ children: /* @__PURE__ */ jsx(
1110
+ "div",
1111
+ {
1112
+ ref: containerRef,
1113
+ className: cn(
1114
+ "oui-relative oui-flex oui-h-[34px] oui-w-full oui-transform-gpu oui-items-center oui-overflow-hidden",
1115
+ overflow ? "oui-justify-start" : "oui-justify-center"
1116
+ ),
1117
+ children: /* @__PURE__ */ jsxs(
1118
+ "div",
1119
+ {
1120
+ ref: contentRef,
1121
+ className: cn(
1122
+ "oui-inline-flex oui-items-center oui-gap-2",
1123
+ "oui-h-[34px] oui-whitespace-nowrap oui-leading-[34px]",
1124
+ "oui-w-fit oui-transform-gpu oui-will-change-transform"
1125
+ ),
1126
+ children: [
1127
+ /* @__PURE__ */ jsx(TipsType, { type }),
1128
+ /* @__PURE__ */ jsx(
1129
+ Text,
1130
+ {
1131
+ size: "xs",
1132
+ intensity: 80,
1133
+ className: cn(
1134
+ "oui-transform-gpu",
1135
+ url ? "oui-cursor-pointer" : void 0
1136
+ ),
1137
+ onClick: url ? onClick : void 0,
1138
+ children: text
1139
+ }
1140
+ )
1141
+ ]
1142
+ }
1143
+ )
1144
+ }
1145
+ )
1146
+ }
1147
+ );
1148
+ };
1149
+ var SoundIcon = React2.forwardRef((props, ref) => {
1150
+ return /* @__PURE__ */ jsx(
1151
+ "svg",
1152
+ {
1153
+ xmlns: "http://www.w3.org/2000/svg",
1154
+ width: 18,
1155
+ height: 18,
1156
+ viewBox: "0 0 18 18",
1157
+ fill: "currentColor",
1158
+ ref,
1159
+ focusable: false,
1160
+ ...props,
1161
+ children: /* @__PURE__ */ jsx(
1162
+ "path",
1163
+ {
1164
+ d: "M11.5312 2.25534C11.2703 2.14734 10.9472 2.18333 10.7109 2.41958C10.1862 2.94383 9.52305 3.37884 8.7642 3.70434C7.99343 4.03434 6.411 4.46108 5.25547 4.45358C3.00765 4.43858 1.49993 5.71283 1.5 8.18033C1.5 10.3426 2.72745 11.6003 4.49423 11.8831L4.5 13.4476C4.5 14.6888 5.50733 15.6953 6.75 15.6953C7.89188 15.6953 8.83245 14.8118 8.97765 13.7071C8.98462 13.6538 9 13.4476 9 12.6976C9.67373 13.0118 10.232 13.5091 10.7109 13.9876C11.1834 14.4593 12 14.1166 12 13.4491C12 12.7711 11.9964 11.5433 11.9964 10.3186C12.8805 9.99159 13.5 9.15383 13.5 8.20358C13.5 7.25333 12.9149 6.39385 12.004 6.0751C12.004 4.85035 12 3.63609 12 2.95809C12 2.62434 11.7923 2.36409 11.5312 2.25534ZM13.3359 3.59033C13.1501 3.63833 12.9956 3.7636 12.8906 3.94135C12.6809 4.29835 12.7913 4.76259 13.1484 4.97184C14.2882 5.64084 15 6.85883 15 8.20358C15 9.54908 14.289 10.7663 13.1484 11.4353C12.7912 11.6446 12.6576 12.1081 12.8672 12.4651C13.0768 12.8221 13.5411 12.9323 13.8984 12.7231C15.4934 11.7878 16.4999 10.0861 16.5 8.20358C16.5 6.32183 15.4922 4.61933 13.8984 3.68408C13.7198 3.57908 13.5217 3.54233 13.3359 3.59033ZM10.5035 4.47384C10.5035 5.16759 10.5 5.89059 10.5 6.70509C10.5 8.20359 10.5 8.2036 10.5 9.7021C10.5 10.5166 10.5024 11.2103 10.5024 11.9041C8.98343 11.0078 7.41735 10.6103 6.00157 10.4828C6.00157 9.33909 5.99775 7.07709 5.99775 5.89884C6.14475 5.89209 6.31575 5.87335 6.5625 5.83885C7.52017 5.7016 8.4717 5.45259 9.375 5.06559C9.80505 4.88184 10.1247 4.71534 10.5035 4.47384ZM4.49887 6.02484C4.49887 7.17684 4.49775 9.21234 4.49775 10.3643C3.52177 10.0943 3 9.40508 3 8.18033C3 6.96983 3.47025 6.25209 4.49887 6.02484ZM6 11.9971C6.23745 12.0053 7.0977 12.1583 7.49243 12.2581L7.5 13.4476C7.5 13.8616 7.16423 14.1968 6.75 14.1968C6.33577 14.1968 6 13.8616 6 13.4476V11.9971Z",
1165
+ fill: "#fff",
1166
+ fillOpacity: 0.98
1167
+ }
1168
+ )
1169
+ }
1170
+ );
1171
+ });
1172
+ if (process.env.NODE_ENV !== "production") {
1173
+ SoundIcon.displayName = "SoundIcon";
1174
+ }
1175
+ var SwitchTips = (props) => {
1176
+ const { selectedSnap, snapCount, prevDisabled, nextDisabled, prevTips, nextTips } = props;
1177
+ const { isMobile } = useScreen();
1178
+ if (isMobile) {
1179
+ return /* @__PURE__ */ jsxs("div", { "aria-live": "polite", className: "oui-text-sm oui-tabular-nums oui-text-base-contrast-54", children: [
1180
+ selectedSnap + 1,
1181
+ "/",
1182
+ snapCount
1183
+ ] });
1184
+ }
1185
+ return /* @__PURE__ */ jsxs("div", { className: "oui-flex oui-items-center oui-justify-center oui-gap-0 oui-text-base-contrast-54", children: [
1186
+ /* @__PURE__ */ jsx(
1187
+ ChevronLeftIcon,
1188
+ {
1189
+ size: 16,
1190
+ opacity: 1,
1191
+ className: cn(
1192
+ "oui-size-4 oui-shrink-0 oui-text-base-contrast-54 hover:oui-text-base-contrast-80 lg:oui-size-5",
1193
+ prevDisabled ? "oui-cursor-not-allowed" : "oui-cursor-pointer"
1194
+ ),
1195
+ onClick: prevDisabled ? void 0 : prevTips
1196
+ }
1197
+ ),
1198
+ /* @__PURE__ */ jsxs("div", { "aria-live": "polite", className: "oui-text-sm oui-tabular-nums oui-text-base-contrast-54", children: [
1199
+ selectedSnap + 1,
1200
+ "/",
1201
+ snapCount
1202
+ ] }),
1203
+ /* @__PURE__ */ jsx(
1204
+ ChevronRightIcon,
1205
+ {
1206
+ size: 16,
1207
+ opacity: 1,
1208
+ className: cn(
1209
+ "oui-size-4 oui-shrink-0 oui-text-base-contrast-54 hover:oui-text-base-contrast-80 lg:oui-size-5",
1210
+ nextDisabled ? "oui-cursor-not-allowed" : "oui-cursor-pointer"
1211
+ ),
1212
+ onClick: nextDisabled ? void 0 : nextTips
1213
+ }
1214
+ )
1215
+ ] });
1216
+ };
1217
+ var Controls = (props) => {
1218
+ const { selectedSnap, snapCount, prevDisabled, nextDisabled, prevTips, nextTips, closeTips } = props;
1219
+ const { isMobile } = useScreen();
1220
+ return /* @__PURE__ */ jsxs(Flex, { gap: isMobile ? 1 : 2, justify: "center", itemAlign: "center", children: [
1221
+ /* @__PURE__ */ jsx(
1222
+ SwitchTips,
1223
+ {
1224
+ prevDisabled,
1225
+ nextDisabled,
1226
+ selectedSnap,
1227
+ snapCount,
1228
+ prevTips,
1229
+ nextTips
1230
+ }
1231
+ ),
1232
+ /* @__PURE__ */ jsx(
1233
+ CloseIcon,
1234
+ {
1235
+ size: 18,
1236
+ onClick: closeTips,
1237
+ className: "oui-cursor-pointer oui-text-base-contrast-80 hover:oui-text-base-contrast"
1238
+ }
1239
+ )
1240
+ ] });
1241
+ };
1242
+ var AnnouncementBannerUI = (props) => {
1243
+ const { maintenanceDialogInfo, showAnnouncement, dataSource, onClose, style, className } = props;
1244
+ const { t, i18n } = useTranslation();
1245
+ const [emblaRef, emblaApi] = useEmblaCarousel({
1246
+ loop: true,
1247
+ axis: "y",
1248
+ align: "center",
1249
+ duration: 30
1250
+ });
1251
+ const { prevBtnDisabled, nextBtnDisabled, onPrevButtonClick, onNextButtonClick } = usePrevNextButtons(emblaApi);
1252
+ const { selectedSnap, snapCount } = useSelectedSnapDisplay(emblaApi);
1253
+ const goNext = useCallback(() => {
1254
+ if (!emblaApi) {
1255
+ return;
1256
+ }
1257
+ emblaApi.scrollNext();
1258
+ }, [emblaApi]);
1259
+ if (maintenanceDialogInfo) {
1260
+ return /* @__PURE__ */ jsx(Dialog, { open: true, children: /* @__PURE__ */ jsxs(
1261
+ DialogContent,
1262
+ {
1263
+ closable: false,
1264
+ onOpenAutoFocus: (event) => event.preventDefault(),
1265
+ className: "oui-w-[320px] lg:oui-w-auto",
1266
+ children: [
1267
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t("maintenance.dialog.title") }) }),
1268
+ /* @__PURE__ */ jsx(DialogBody, { className: "oui-text-2xs lg:oui-text-xs", children: maintenanceDialogInfo })
1269
+ ]
1270
+ }
1271
+ ) });
1272
+ }
1273
+ if (!showAnnouncement || !dataSource?.length) {
1274
+ return null;
1275
+ }
1276
+ return /* @__PURE__ */ jsxs(
1277
+ "div",
1278
+ {
1279
+ style,
1280
+ className: cn(
1281
+ "oui-relative oui-z-[1] oui-flex oui-transform-gpu oui-flex-row oui-flex-nowrap oui-items-center oui-justify-between oui-gap-x-1.5 oui-overflow-hidden oui-rounded-xl oui-bg-base-9 oui-px-4 oui-font-semibold",
1282
+ className
1283
+ ),
1284
+ children: [
1285
+ /* @__PURE__ */ jsx("div", { className: "oui-size-[18px]", children: /* @__PURE__ */ jsx(SoundIcon, {}) }),
1286
+ /* @__PURE__ */ jsx(
1287
+ "div",
1288
+ {
1289
+ ref: emblaRef,
1290
+ className: "oui-relative oui-h-[34px] oui-w-full oui-max-w-full oui-transform-gpu oui-overflow-hidden",
1291
+ children: /* @__PURE__ */ jsx("div", { className: "oui-flex oui-h-full oui-transform-gpu oui-flex-col", children: dataSource.map((item, index) => /* @__PURE__ */ jsx(
1292
+ AnnouncementItem2,
1293
+ {
1294
+ type: item?.type,
1295
+ text: item?.i18n?.[i18n.language] || item?.message?.trim() || "",
1296
+ url: item?.url || void 0,
1297
+ isActive: index === selectedSnap,
1298
+ onItemFinish: goNext,
1299
+ onItemClick: (url) => {
1300
+ if (props.onItemClick) {
1301
+ props.onItemClick(url);
1302
+ } else {
1303
+ window.open(url, "_blank");
1304
+ }
1305
+ }
1306
+ },
1307
+ `item-${item.announcement_id}-${index}`
1308
+ )) })
1309
+ }
1310
+ ),
1311
+ /* @__PURE__ */ jsx(
1312
+ Controls,
1313
+ {
1314
+ selectedSnap,
1315
+ snapCount,
1316
+ closeTips: onClose,
1317
+ prevTips: onPrevButtonClick,
1318
+ nextTips: onNextButtonClick,
1319
+ prevDisabled: prevBtnDisabled,
1320
+ nextDisabled: nextBtnDisabled
1321
+ }
1322
+ )
1323
+ ]
1324
+ }
1325
+ );
1326
+ };
869
1327
 
870
- export { AnnouncementCenterPage, AnnouncementCenterUI, AnnouncementItem, NotificationUI, useAnnouncement };
1328
+ export { AnnouncementBannerUI, AnnouncementCenterPage, AnnouncementCenterUI, AnnouncementItem, NotificationUI, useAnnouncement };
871
1329
  //# sourceMappingURL=out.js.map
872
1330
  //# sourceMappingURL=index.mjs.map