@transferwise/components 0.0.0-experimental-bb7ed4a → 0.0.0-experimental-137c428

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/build/index.js +212 -12
  2. package/build/index.js.map +1 -1
  3. package/build/index.mjs +213 -14
  4. package/build/index.mjs.map +1 -1
  5. package/build/main.css +125 -0
  6. package/build/styles/carousel/Carousel.css +125 -0
  7. package/build/styles/main.css +125 -0
  8. package/build/types/carousel/Carousel.d.ts +19 -0
  9. package/build/types/carousel/Carousel.d.ts.map +1 -0
  10. package/build/types/carousel/Carousel.test.d.ts +2 -0
  11. package/build/types/carousel/Carousel.test.d.ts.map +1 -0
  12. package/build/types/carousel/index.d.ts +3 -0
  13. package/build/types/carousel/index.d.ts.map +1 -0
  14. package/build/types/common/dateUtils/index.d.ts +0 -1
  15. package/build/types/common/dateUtils/index.d.ts.map +1 -1
  16. package/build/types/dateLookup/DateLookup.d.ts +2 -2
  17. package/build/types/dateLookup/DateLookup.d.ts.map +1 -1
  18. package/build/types/dateLookup/dayCalendar/table/DayCalendarTable.d.ts +1 -1
  19. package/build/types/dateLookup/dayCalendar/table/DayCalendarTable.d.ts.map +1 -1
  20. package/build/types/index.d.ts +2 -0
  21. package/build/types/index.d.ts.map +1 -1
  22. package/package.json +5 -5
  23. package/src/carousel/Carousel.css +125 -0
  24. package/src/carousel/Carousel.less +125 -0
  25. package/src/carousel/Carousel.story.tsx +62 -0
  26. package/src/carousel/Carousel.test.tsx +221 -0
  27. package/src/carousel/Carousel.tsx +269 -0
  28. package/src/carousel/index.ts +3 -0
  29. package/src/common/dateUtils/index.ts +0 -1
  30. package/src/dateLookup/DateLookup.tests.story.tsx +10 -44
  31. package/src/dateLookup/DateLookup.tsx +12 -9
  32. package/src/dateLookup/dayCalendar/table/DayCalendarTable.tsx +2 -5
  33. package/src/index.ts +2 -0
  34. package/src/main.css +125 -0
  35. package/src/main.less +1 -0
  36. package/build/types/common/dateUtils/getDateView/getDateView.d.ts +0 -2
  37. package/build/types/common/dateUtils/getDateView/getDateView.d.ts.map +0 -1
  38. package/src/common/dateUtils/getDateView/getDateView.ts +0 -5
package/build/index.js CHANGED
@@ -2184,6 +2184,210 @@ const Button = /*#__PURE__*/React.forwardRef(({
2184
2184
  });
2185
2185
  });
2186
2186
 
2187
+ const Carousel = ({
2188
+ header,
2189
+ className,
2190
+ cards,
2191
+ onClick
2192
+ }) => {
2193
+ const [scrollPosition, setScrollPosition] = React.useState(0);
2194
+ const [previousScrollPosition, setPreviousScrollPosition] = React.useState(0);
2195
+ const [scrollIsAtEnd, setScrollIsAtEnd] = React.useState(false);
2196
+ const [visibleCardOnMobileView, setVisibleCardOnMobileView] = React.useState('');
2197
+ const carouselElementRef = React.useRef(null);
2198
+ const caraouselCardsRef = React.useRef([]);
2199
+ const isLeftActionButtonEnabled = scrollPosition > 8;
2200
+ const areActionButtonsEnabled = isLeftActionButtonEnabled || !scrollIsAtEnd;
2201
+ const [focusedCard, setFocusedCard] = React.useState(cards?.[0]?.id);
2202
+ const updateScrollButtonsState = () => {
2203
+ if (carouselElementRef.current) {
2204
+ const {
2205
+ scrollWidth,
2206
+ offsetWidth
2207
+ } = carouselElementRef.current;
2208
+ const scrollAtEnd = scrollWidth - offsetWidth <= scrollPosition + 8;
2209
+ setScrollIsAtEnd(scrollAtEnd);
2210
+ }
2211
+ const scrollDirecton = scrollPosition > previousScrollPosition ? 'right' : 'left';
2212
+ const cardsInFullViewIds = [];
2213
+ caraouselCardsRef.current.forEach(card => {
2214
+ if (isVisible(carouselElementRef.current, card)) {
2215
+ // eslint-disable-next-line functional/immutable-data
2216
+ cardsInFullViewIds.push(card.getAttribute('id') ?? '');
2217
+ }
2218
+ });
2219
+ if (cardsInFullViewIds.length >= 1) {
2220
+ const visibleCardIndex = scrollDirecton === 'right' ? cardsInFullViewIds.length - 1 : 0;
2221
+ const visibleCardId = cardsInFullViewIds[visibleCardIndex];
2222
+ setVisibleCardOnMobileView(visibleCardId);
2223
+ setFocusedCard(visibleCardId);
2224
+ }
2225
+ setPreviousScrollPosition(scrollPosition);
2226
+ };
2227
+ const scrollCarousel = (direction = 'right') => {
2228
+ if (carouselElementRef.current) {
2229
+ const {
2230
+ scrollWidth
2231
+ } = carouselElementRef.current;
2232
+ const cardWidth = scrollWidth / caraouselCardsRef.current.length;
2233
+ const res = Math.floor(cardWidth - cardWidth * 0.05);
2234
+ carouselElementRef.current.scrollBy({
2235
+ left: direction === 'right' ? res : -res,
2236
+ behavior: 'smooth'
2237
+ });
2238
+ }
2239
+ };
2240
+ const handleOnKeyDown = (event, index) => {
2241
+ if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {
2242
+ const nextIndex = event.key === 'ArrowRight' ? index + 1 : index - 1;
2243
+ const nextCard = cards[nextIndex];
2244
+ if (nextCard) {
2245
+ caraouselCardsRef.current[nextIndex].focus();
2246
+ scrollCardIntoView(caraouselCardsRef.current[nextIndex], nextCard);
2247
+ event.preventDefault();
2248
+ }
2249
+ }
2250
+ };
2251
+ const scrollCardIntoView = (element, card) => {
2252
+ element.scrollIntoView({
2253
+ behavior: 'smooth',
2254
+ block: 'nearest',
2255
+ inline: 'center'
2256
+ });
2257
+ setFocusedCard(card.id);
2258
+ };
2259
+ React.useEffect(() => {
2260
+ updateScrollButtonsState();
2261
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2262
+ }, [scrollPosition]);
2263
+ React.useEffect(() => {
2264
+ window.addEventListener('resize', updateScrollButtonsState);
2265
+ return () => {
2266
+ window.removeEventListener('resize', updateScrollButtonsState);
2267
+ };
2268
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2269
+ }, []);
2270
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
2271
+ className: className,
2272
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
2273
+ className: "d-flex justify-content-between m-b-1 carousel__header",
2274
+ children: [typeof header === 'string' ? /*#__PURE__*/jsxRuntime.jsx(Title, {
2275
+ as: "span",
2276
+ type: "title-body",
2277
+ children: header
2278
+ }) : header, areActionButtonsEnabled ? /*#__PURE__*/jsxRuntime.jsxs("div", {
2279
+ className: "hidden-xs",
2280
+ children: [/*#__PURE__*/jsxRuntime.jsx(ActionButton, {
2281
+ className: "carousel__scroll-button",
2282
+ tabIndex: -1,
2283
+ priority: "secondary",
2284
+ disabled: !isLeftActionButtonEnabled,
2285
+ "aria-hidden": "true",
2286
+ "data-testid": "scroll-carousel-left",
2287
+ onClick: () => scrollCarousel('left'),
2288
+ children: /*#__PURE__*/jsxRuntime.jsx(icons.ChevronLeft, {})
2289
+ }), /*#__PURE__*/jsxRuntime.jsx(ActionButton, {
2290
+ tabIndex: -1,
2291
+ className: "carousel__scroll-button m-l-1",
2292
+ priority: "secondary",
2293
+ "aria-hidden": "true",
2294
+ "data-testid": "scroll-carousel-right",
2295
+ disabled: scrollIsAtEnd,
2296
+ onClick: () => scrollCarousel(),
2297
+ children: /*#__PURE__*/jsxRuntime.jsx(icons.ChevronRight, {})
2298
+ })]
2299
+ }) : null]
2300
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
2301
+ ref: carouselElementRef,
2302
+ tabIndex: -1,
2303
+ role: "list",
2304
+ className: "carousel",
2305
+ onScroll: event => {
2306
+ const target = event.target;
2307
+ setScrollPosition(target.scrollLeft);
2308
+ },
2309
+ children: cards?.map((card, index) => {
2310
+ const sharedProps = {
2311
+ id: card.id,
2312
+ className: classNames__default.default('carousel__card', {
2313
+ 'carousel__card--focused': card.id === focusedCard
2314
+ }),
2315
+ role: 'listitem',
2316
+ 'aria-labelledby': `${card.id}-content`,
2317
+ onClick: () => {
2318
+ card.onClick?.();
2319
+ onClick?.(card.id);
2320
+ },
2321
+ onFocus: event => {
2322
+ scrollCardIntoView(event.currentTarget, card);
2323
+ }
2324
+ };
2325
+ const cardContent = /*#__PURE__*/jsxRuntime.jsx("div", {
2326
+ id: `${card.id}-content`,
2327
+ className: classNames__default.default('carousel__card-content', 'p-a-1', {
2328
+ [card.className ?? '']: !!card.className
2329
+ })
2330
+ // eslint-disable-next-line react/forbid-dom-props
2331
+ ,
2332
+ style: card.styles,
2333
+ children: card.content
2334
+ });
2335
+ if (card.type === 'button') {
2336
+ return /*#__PURE__*/React.createElement("button", {
2337
+ ...sharedProps,
2338
+ ref: el => {
2339
+ if (el) {
2340
+ // eslint-disable-next-line functional/immutable-data
2341
+ caraouselCardsRef.current[index] = el;
2342
+ }
2343
+ },
2344
+ key: card.id,
2345
+ type: "button",
2346
+ onKeyDown: event => handleOnKeyDown(event, index)
2347
+ }, cardContent);
2348
+ }
2349
+ return /*#__PURE__*/React.createElement("a", {
2350
+ ...sharedProps,
2351
+ ref: el => {
2352
+ if (el) {
2353
+ // eslint-disable-next-line functional/immutable-data
2354
+ caraouselCardsRef.current[index] = el;
2355
+ }
2356
+ },
2357
+ key: card.id,
2358
+ target: "_blank",
2359
+ rel: "noreferrer",
2360
+ href: card.href,
2361
+ onKeyDown: event => handleOnKeyDown(event, index)
2362
+ }, cardContent);
2363
+ })
2364
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
2365
+ className: "visible-xs",
2366
+ children: /*#__PURE__*/jsxRuntime.jsx("div", {
2367
+ className: "carousel__indicators",
2368
+ children: cards?.map((card, index) => /*#__PURE__*/jsxRuntime.jsx("button", {
2369
+ "data-testid": `${card.id}-indicator`,
2370
+ tabIndex: -1,
2371
+ type: "button",
2372
+ className: classNames__default.default('carousel__indicator', {
2373
+ 'carousel__indicator--selected': card.id === visibleCardOnMobileView
2374
+ }),
2375
+ onClick: () => {
2376
+ scrollCardIntoView(caraouselCardsRef.current[index], card);
2377
+ }
2378
+ }, `${card.id}-indicator`))
2379
+ })
2380
+ })]
2381
+ });
2382
+ };
2383
+ const isVisible = (container, el) => {
2384
+ const cWidth = container.offsetWidth;
2385
+ const cScrollOffset = container.scrollLeft;
2386
+ const elemLeft = el.offsetLeft - container.offsetLeft;
2387
+ const elemRight = elemLeft + el.offsetWidth;
2388
+ return elemLeft >= cScrollOffset && elemRight <= cScrollOffset + cWidth;
2389
+ };
2390
+
2187
2391
  const Card$1 = /*#__PURE__*/React.forwardRef((props, reference) => {
2188
2392
  const {
2189
2393
  'aria-label': ariaLabel,
@@ -2610,10 +2814,6 @@ const isMonthAndYearFormat = dateString => validDateString(dateString) && dateSt
2610
2814
  const MDY = new Set(['en-US']);
2611
2815
  const YMD = new Set(['hu', 'hu-HU', 'zh-HK', 'zh-CN', 'ja', 'ja-JP']);
2612
2816
 
2613
- const returnDateView = (selectedDate, min, max) => {
2614
- return selectedDate || (min || max) && moveToWithinRange(new Date(), min, max) || new Date();
2615
- };
2616
-
2617
2817
  var messages$9 = reactIntl.defineMessages({
2618
2818
  monthLabel: {
2619
2819
  id: "neptune.DateInput.month.label"
@@ -3358,9 +3558,6 @@ class DayCalendarTable extends React.PureComponent {
3358
3558
  onSelect(new Date(viewYear, viewMonth, day));
3359
3559
  };
3360
3560
  isDisabled = day => {
3361
- if (day === -1) {
3362
- return true;
3363
- }
3364
3561
  const {
3365
3562
  min,
3366
3563
  max,
@@ -3376,7 +3573,7 @@ class DayCalendarTable extends React.PureComponent {
3376
3573
  viewMonth,
3377
3574
  viewYear
3378
3575
  } = this.props;
3379
- return !!(selectedDate && Number(new Date(viewYear, viewMonth, day)) === Number(selectedDate));
3576
+ return !!(selectedDate && +new Date(viewYear, viewMonth, day) === +selectedDate);
3380
3577
  };
3381
3578
  isToday = day => {
3382
3579
  const {
@@ -3770,8 +3967,8 @@ class DateLookup extends React.PureComponent {
3770
3967
  originalDate: null,
3771
3968
  min: getStartOfDay(props.min),
3772
3969
  max: getStartOfDay(props.max),
3773
- viewMonth: returnDateView(props.value, props.min, props.max).getMonth(),
3774
- viewYear: returnDateView(props.value, props.min, props.max).getFullYear(),
3970
+ viewMonth: (props.value || new Date()).getMonth(),
3971
+ viewYear: (props.value || new Date()).getFullYear(),
3775
3972
  open: false,
3776
3973
  mode: 'day',
3777
3974
  isMobile: false
@@ -3792,7 +3989,7 @@ class DateLookup extends React.PureComponent {
3792
3989
  props.onChange(moveToWithinRange(selectedDate, min, max));
3793
3990
  return null;
3794
3991
  }
3795
- const viewDateThatIsWithinRange = returnDateView(selectedDate, min, max);
3992
+ const viewDateThatIsWithinRange = selectedDate || (min || max) && moveToWithinRange(new Date(), min, max) || new Date();
3796
3993
  const viewMonth = viewDateThatIsWithinRange.getMonth();
3797
3994
  const viewYear = viewDateThatIsWithinRange.getFullYear();
3798
3995
  return {
@@ -3917,7 +4114,9 @@ class DateLookup extends React.PureComponent {
3917
4114
  } else {
3918
4115
  date = getStartOfDay(new Date());
3919
4116
  }
3920
- date &&= moveToWithinRange(date, min, max);
4117
+ if (date) {
4118
+ date = moveToWithinRange(date, min, max);
4119
+ }
3921
4120
  if (date?.getTime() !== selectedDate?.getTime()) {
3922
4121
  this.props.onChange(date);
3923
4122
  }
@@ -14386,6 +14585,7 @@ exports.Body = Body;
14386
14585
  exports.BottomSheet = BottomSheet$2;
14387
14586
  exports.Button = Button;
14388
14587
  exports.Card = Card$2;
14588
+ exports.Carousel = Carousel;
14389
14589
  exports.Checkbox = Checkbox$1;
14390
14590
  exports.CheckboxButton = CheckboxButton$1;
14391
14591
  exports.CheckboxOption = CheckboxOption;