@kaizen/components 1.47.3 → 1.47.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.
@@ -2,8 +2,8 @@
2
2
 
3
3
  var tslib = require('tslib');
4
4
  var React = require('react');
5
+ var reactDom = require('@floating-ui/react-dom');
5
6
  var classnames = require('classnames');
6
- var reactPopper = require('react-popper');
7
7
  var CalendarPopover_module = require('./CalendarPopover.module.scss.cjs');
8
8
  function _interopDefault(e) {
9
9
  return e && e.__esModule ? e : {
@@ -20,28 +20,39 @@ var classnames__default = /*#__PURE__*/_interopDefault(classnames);
20
20
  var CalendarPopover = function (_a) {
21
21
  var children = _a.children,
22
22
  referenceElement = _a.referenceElement,
23
- popperOptions = _a.popperOptions,
23
+ floatingOptions = _a.floatingOptions,
24
24
  classNameOverride = _a.classNameOverride,
25
- restProps = tslib.__rest(_a, ["children", "referenceElement", "popperOptions", "classNameOverride"]);
25
+ restProps = tslib.__rest(_a, ["children", "referenceElement", "floatingOptions", "classNameOverride"]);
26
26
  var _b = React.useState(null),
27
- popperElement = _b[0],
28
- setPopperElement = _b[1];
29
- var _c = reactPopper.usePopper(referenceElement, popperElement, tslib.__assign({
30
- modifiers: [{
31
- name: "offset",
32
- options: {
33
- offset: [0, 15]
34
- }
35
- }],
36
- placement: "bottom-start",
37
- strategy: "fixed"
38
- }, popperOptions)),
39
- popperStyles = _c.styles,
40
- popperAttributes = _c.attributes;
27
+ floatingElement = _b[0],
28
+ setFloatingElement = _b[1];
29
+ var floatingStyles = reactDom.useFloating(tslib.__assign({
30
+ placement: "bottom-start",
31
+ elements: {
32
+ reference: referenceElement,
33
+ floating: floatingElement
34
+ },
35
+ strategy: "fixed",
36
+ middleware: [reactDom.size({
37
+ apply: function (_a) {
38
+ var availableHeight = _a.availableHeight,
39
+ availableWidth = _a.availableWidth,
40
+ elements = _a.elements;
41
+ Object.assign(elements.floating.style, {
42
+ // 155 is enough of a minimum to cut off half of the second row of dates.
43
+ // This indicates to users that there is more content that is scrollable
44
+ maxHeight: "".concat(Math.max(availableHeight - 25, 155), "px"),
45
+ maxWidth: "".concat(availableWidth, "px")
46
+ });
47
+ }
48
+ }), reactDom.offset(15), reactDom.autoPlacement({
49
+ allowedPlacements: ["bottom-start", "bottom", "top-start", "top"]
50
+ })],
51
+ whileElementsMounted: reactDom.autoUpdate
52
+ }, floatingOptions)).floatingStyles;
41
53
  return React__default.default.createElement("div", tslib.__assign({
42
- ref: setPopperElement,
43
- style: popperStyles === null || popperStyles === void 0 ? void 0 : popperStyles.popper
44
- }, popperAttributes === null || popperAttributes === void 0 ? void 0 : popperAttributes.popper, {
54
+ ref: setFloatingElement,
55
+ style: floatingStyles,
45
56
  className: classnames__default.default(CalendarPopover_module.calendarPopover, classNameOverride),
46
57
  role: "dialog",
47
58
  "aria-modal": "true"
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var styleInject = require('../../__build-tools/styleInject.cjs');
4
- var css_248z = ".CalendarPopover-module_calendarPopover__p2xp9{background-color:var(--color-white,#fff);border-radius:var(--border-borderless-border-radius,7px);box-shadow:var(--shadow-large-box-shadow,0 3px 9px 0 rgba(0,0,0,.1),0 8px 40px 0 rgba(0,0,0,.08));padding:var(--spacing-md,1.5rem);z-index:1010}";
4
+ var css_248z = ".CalendarPopover-module_calendarPopover__p2xp9{background-color:var(--color-white,#fff);border-radius:var(--border-borderless-border-radius,7px);box-shadow:var(--shadow-large-box-shadow,0 3px 9px 0 rgba(0,0,0,.1),0 8px 40px 0 rgba(0,0,0,.08));box-sizing:border-box;overflow:auto;padding:var(--spacing-12,.75rem) var(--spacing-8,.5rem);z-index:1010}@media (min-width:768px){.CalendarPopover-module_calendarPopover__p2xp9{padding:var(--spacing-24,1.5rem)}}";
5
5
  var styles = {
6
6
  "calendarPopover": "CalendarPopover-module_calendarPopover__p2xp9"
7
7
  };
@@ -1,7 +1,7 @@
1
1
  import { __rest, __assign } from 'tslib';
2
2
  import React, { useState } from 'react';
3
+ import { useFloating, size, offset, autoPlacement, autoUpdate } from '@floating-ui/react-dom';
3
4
  import classnames from 'classnames';
4
- import { usePopper } from 'react-popper';
5
5
  import styles from './CalendarPopover.module.scss.mjs';
6
6
 
7
7
  /**
@@ -12,28 +12,39 @@ const CalendarPopover = /*#__PURE__*/function () {
12
12
  const CalendarPopover = function (_a) {
13
13
  var children = _a.children,
14
14
  referenceElement = _a.referenceElement,
15
- popperOptions = _a.popperOptions,
15
+ floatingOptions = _a.floatingOptions,
16
16
  classNameOverride = _a.classNameOverride,
17
- restProps = __rest(_a, ["children", "referenceElement", "popperOptions", "classNameOverride"]);
17
+ restProps = __rest(_a, ["children", "referenceElement", "floatingOptions", "classNameOverride"]);
18
18
  var _b = useState(null),
19
- popperElement = _b[0],
20
- setPopperElement = _b[1];
21
- var _c = usePopper(referenceElement, popperElement, __assign({
22
- modifiers: [{
23
- name: "offset",
24
- options: {
25
- offset: [0, 15]
26
- }
27
- }],
28
- placement: "bottom-start",
29
- strategy: "fixed"
30
- }, popperOptions)),
31
- popperStyles = _c.styles,
32
- popperAttributes = _c.attributes;
19
+ floatingElement = _b[0],
20
+ setFloatingElement = _b[1];
21
+ var floatingStyles = useFloating(__assign({
22
+ placement: "bottom-start",
23
+ elements: {
24
+ reference: referenceElement,
25
+ floating: floatingElement
26
+ },
27
+ strategy: "fixed",
28
+ middleware: [size({
29
+ apply: function (_a) {
30
+ var availableHeight = _a.availableHeight,
31
+ availableWidth = _a.availableWidth,
32
+ elements = _a.elements;
33
+ Object.assign(elements.floating.style, {
34
+ // 155 is enough of a minimum to cut off half of the second row of dates.
35
+ // This indicates to users that there is more content that is scrollable
36
+ maxHeight: "".concat(Math.max(availableHeight - 25, 155), "px"),
37
+ maxWidth: "".concat(availableWidth, "px")
38
+ });
39
+ }
40
+ }), offset(15), autoPlacement({
41
+ allowedPlacements: ["bottom-start", "bottom", "top-start", "top"]
42
+ })],
43
+ whileElementsMounted: autoUpdate
44
+ }, floatingOptions)).floatingStyles;
33
45
  return /*#__PURE__*/React.createElement("div", __assign({
34
- ref: setPopperElement,
35
- style: popperStyles === null || popperStyles === void 0 ? void 0 : popperStyles.popper
36
- }, popperAttributes === null || popperAttributes === void 0 ? void 0 : popperAttributes.popper, {
46
+ ref: setFloatingElement,
47
+ style: floatingStyles,
37
48
  className: classnames(styles.calendarPopover, classNameOverride),
38
49
  role: "dialog",
39
50
  "aria-modal": "true"
@@ -1,5 +1,5 @@
1
1
  import { styleInject } from '../../__build-tools/styleInject.mjs';
2
- var css_248z = ".CalendarPopover-module_calendarPopover__p2xp9{background-color:var(--color-white,#fff);border-radius:var(--border-borderless-border-radius,7px);box-shadow:var(--shadow-large-box-shadow,0 3px 9px 0 rgba(0,0,0,.1),0 8px 40px 0 rgba(0,0,0,.08));padding:var(--spacing-md,1.5rem);z-index:1010}";
2
+ var css_248z = ".CalendarPopover-module_calendarPopover__p2xp9{background-color:var(--color-white,#fff);border-radius:var(--border-borderless-border-radius,7px);box-shadow:var(--shadow-large-box-shadow,0 3px 9px 0 rgba(0,0,0,.1),0 8px 40px 0 rgba(0,0,0,.08));box-sizing:border-box;overflow:auto;padding:var(--spacing-12,.75rem) var(--spacing-8,.5rem);z-index:1010}@media (min-width:768px){.CalendarPopover-module_calendarPopover__p2xp9{padding:var(--spacing-24,1.5rem)}}";
3
3
  var styles = {
4
4
  "calendarPopover": "CalendarPopover-module_calendarPopover__p2xp9"
5
5
  };
@@ -1,16 +1,16 @@
1
1
  import React, { HTMLAttributes } from "react";
2
- import { Options } from "@popperjs/core";
2
+ import { UseFloatingOptions } from "@floating-ui/react-dom";
3
3
  import { OverrideClassName } from "../../types/OverrideClassName";
4
4
  export type CalendarPopoverProps = {
5
5
  children: React.ReactNode;
6
6
  referenceElement: HTMLElement | null;
7
- popperOptions?: Partial<Options>;
7
+ floatingOptions?: Partial<UseFloatingOptions>;
8
8
  } & OverrideClassName<HTMLAttributes<HTMLDivElement>>;
9
9
  /**
10
10
  * Only for use with Calendar components.
11
11
  * @todo: Replace with Popover when we have a reusable one.
12
12
  */
13
13
  export declare const CalendarPopover: {
14
- ({ children, referenceElement, popperOptions, classNameOverride, ...restProps }: CalendarPopoverProps): JSX.Element;
14
+ ({ children, referenceElement, floatingOptions, classNameOverride, ...restProps }: CalendarPopoverProps): JSX.Element;
15
15
  displayName: string;
16
16
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaizen/components",
3
- "version": "1.47.3",
3
+ "version": "1.47.4",
4
4
  "description": "Kaizen component library",
5
5
  "author": "Geoffrey Chong <geoff.chong@cultureamp.com>",
6
6
  "homepage": "https://cultureamp.design",
@@ -26,26 +26,26 @@
26
26
  "styles.css"
27
27
  ],
28
28
  "dependencies": {
29
- "@floating-ui/react-dom": "^2.0.9",
29
+ "@floating-ui/react-dom": "^2.1.0",
30
30
  "@headlessui/react": "<=1.5.0",
31
- "@internationalized/date": "^3.5.3",
31
+ "@internationalized/date": "^3.5.4",
32
32
  "@popperjs/core": "^2.11.8",
33
33
  "@reach/tabs": "^0.18.0",
34
- "@react-aria/button": "^3.9.4",
35
- "@react-aria/datepicker": "^3.10.0",
36
- "@react-aria/focus": "^3.17.0",
37
- "@react-aria/i18n": "^3.11.0",
38
- "@react-aria/listbox": "^3.12.0",
39
- "@react-aria/menu": "^3.14.0",
40
- "@react-aria/overlays": "^3.22.0",
41
- "@react-aria/select": "^3.14.4",
42
- "@react-aria/utils": "^3.24.0",
43
- "@react-stately/collections": "^3.10.6",
44
- "@react-stately/datepicker": "^3.9.3",
45
- "@react-stately/list": "^3.10.4",
46
- "@react-stately/menu": "^3.7.0",
47
- "@react-stately/select": "^3.6.3",
48
- "@react-types/shared": "^3.23.0",
34
+ "@react-aria/button": "^3.9.5",
35
+ "@react-aria/datepicker": "^3.10.1",
36
+ "@react-aria/focus": "^3.17.1",
37
+ "@react-aria/i18n": "^3.11.1",
38
+ "@react-aria/listbox": "^3.12.1",
39
+ "@react-aria/menu": "^3.14.1",
40
+ "@react-aria/overlays": "^3.22.1",
41
+ "@react-aria/select": "^3.14.5",
42
+ "@react-aria/utils": "^3.24.1",
43
+ "@react-stately/collections": "^3.10.7",
44
+ "@react-stately/datepicker": "^3.9.4",
45
+ "@react-stately/list": "^3.10.5",
46
+ "@react-stately/menu": "^3.7.1",
47
+ "@react-stately/select": "^3.6.4",
48
+ "@react-types/shared": "^3.23.1",
49
49
  "classnames": "^2.5.1",
50
50
  "date-fns": "^3.6.0",
51
51
  "lodash.debounce": "^4.0.8",
@@ -70,7 +70,7 @@
70
70
  "react-select": "^5.8.0",
71
71
  "react-textfit": "^1.1.1",
72
72
  "resize-observer-polyfill": "^1.5.1",
73
- "use-debounce": "^10.0.0",
73
+ "use-debounce": "^10.0.1",
74
74
  "uuid": "^9.0.1",
75
75
  "@kaizen/hosted-assets": "2.0.3"
76
76
  },
@@ -79,7 +79,7 @@
79
79
  },
80
80
  "devDependencies": {
81
81
  "@cultureamp/frontend-apis": "^9.5.0",
82
- "@cultureamp/i18n-react-intl": "^2.5.6",
82
+ "@cultureamp/i18n-react-intl": "^2.5.7",
83
83
  "@types/lodash.debounce": "^4.0.9",
84
84
  "@types/react-dom": "^18.3.0",
85
85
  "@types/react-textfit": "^1.1.4",
@@ -87,15 +87,15 @@
87
87
  "autoprefixer": "^10.4.19",
88
88
  "query-string": "^9.0.0",
89
89
  "react-intl": "^6.6.8",
90
- "rollup": "^4.17.2",
90
+ "rollup": "^4.18.0",
91
91
  "sass": "^1.77.2",
92
92
  "serialize-query-params": "^2.0.2",
93
93
  "svgo": "^3.3.2",
94
- "ts-jest": "^29.1.2",
94
+ "ts-jest": "^29.1.3",
95
95
  "tslib": "^2.6.2",
96
96
  "tsx": "^4.10.2",
97
- "@kaizen/package-bundler": "1.0.1",
98
- "@kaizen/design-tokens": "10.4.0"
97
+ "@kaizen/design-tokens": "10.4.0",
98
+ "@kaizen/package-bundler": "1.0.2"
99
99
  },
100
100
  "devDependenciesComments": {
101
101
  "postcss": "Installed in root",
@@ -103,7 +103,7 @@
103
103
  "postcss-preset-env": "Installed in root"
104
104
  },
105
105
  "peerDependencies": {
106
- "@cultureamp/i18n-react-intl": "^2.5.6",
106
+ "@cultureamp/i18n-react-intl": "^2.5.7",
107
107
  "react": "^18.3.1",
108
108
  "react-intl": "^6.6.8"
109
109
  },
@@ -111,6 +111,7 @@
111
111
  "build": "pnpm package-bundler build-shared-ui && pnpm build:global-styles",
112
112
  "build:global-styles": "postcss ./styles/global.css --output dist/styles.css",
113
113
  "clean": "rm -rf dist",
114
+ "lint:ts": "tsc --noEmit",
114
115
  "test": "FORCE_COLOR=1 jest",
115
116
  "test:ci": "pnpm test -- --ci",
116
117
  "update-icons": "./src/Icon/bin/update-icons.sh",
@@ -2,11 +2,18 @@
2
2
  @import "~@kaizen/design-tokens/sass/color";
3
3
  @import "~@kaizen/design-tokens/sass/shadow";
4
4
  @import "~@kaizen/design-tokens/sass/spacing";
5
+ @import "~@kaizen/design-tokens/sass/layout";
5
6
 
6
7
  .calendarPopover {
7
8
  background-color: $color-white;
8
9
  z-index: 1010;
9
10
  box-shadow: $shadow-large-box-shadow;
10
11
  border-radius: $border-borderless-border-radius;
11
- padding: $spacing-md;
12
+ padding: $spacing-12 $spacing-8;
13
+ box-sizing: border-box;
14
+ overflow: auto;
15
+
16
+ @media (min-width: $layout-breakpoints-medium) {
17
+ padding: $spacing-24;
18
+ }
12
19
  }
@@ -1,14 +1,20 @@
1
1
  import React, { HTMLAttributes, useState } from "react"
2
- import { Options } from "@popperjs/core"
2
+ import {
3
+ autoUpdate,
4
+ offset,
5
+ useFloating,
6
+ UseFloatingOptions,
7
+ size,
8
+ autoPlacement,
9
+ } from "@floating-ui/react-dom"
3
10
  import classnames from "classnames"
4
- import { usePopper } from "react-popper"
5
11
  import { OverrideClassName } from "~types/OverrideClassName"
6
12
  import styles from "./CalendarPopover.module.scss"
7
13
 
8
14
  export type CalendarPopoverProps = {
9
15
  children: React.ReactNode
10
16
  referenceElement: HTMLElement | null
11
- popperOptions?: Partial<Options>
17
+ floatingOptions?: Partial<UseFloatingOptions>
12
18
  } & OverrideClassName<HTMLAttributes<HTMLDivElement>>
13
19
 
14
20
  /**
@@ -18,37 +24,45 @@ export type CalendarPopoverProps = {
18
24
  export const CalendarPopover = ({
19
25
  children,
20
26
  referenceElement,
21
- popperOptions,
27
+ floatingOptions,
22
28
  classNameOverride,
23
29
  ...restProps
24
30
  }: CalendarPopoverProps): JSX.Element => {
25
- const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(
31
+ const [floatingElement, setFloatingElement] = useState<HTMLDivElement | null>(
26
32
  null
27
33
  )
28
34
 
29
- const { styles: popperStyles, attributes: popperAttributes } = usePopper(
30
- referenceElement,
31
- popperElement,
32
- {
33
- modifiers: [
34
- {
35
- name: "offset",
36
- options: {
37
- offset: [0, 15],
38
- },
35
+ const { floatingStyles } = useFloating({
36
+ placement: "bottom-start",
37
+ elements: {
38
+ reference: referenceElement,
39
+ floating: floatingElement,
40
+ },
41
+ strategy: "fixed",
42
+ middleware: [
43
+ size({
44
+ apply({ availableHeight, availableWidth, elements }) {
45
+ Object.assign(elements.floating.style, {
46
+ // 155 is enough of a minimum to cut off half of the second row of dates.
47
+ // This indicates to users that there is more content that is scrollable
48
+ maxHeight: `${Math.max(availableHeight - 25, 155)}px`,
49
+ maxWidth: `${availableWidth}px`,
50
+ })
39
51
  },
40
- ],
41
- placement: "bottom-start",
42
- strategy: "fixed",
43
- ...popperOptions,
44
- }
45
- )
52
+ }),
53
+ offset(15),
54
+ autoPlacement({
55
+ allowedPlacements: ["bottom-start", "bottom", "top-start", "top"],
56
+ }),
57
+ ],
58
+ whileElementsMounted: autoUpdate,
59
+ ...floatingOptions,
60
+ })
46
61
 
47
62
  return (
48
63
  <div
49
- ref={setPopperElement}
50
- style={popperStyles?.popper}
51
- {...popperAttributes?.popper}
64
+ ref={setFloatingElement}
65
+ style={floatingStyles}
52
66
  className={classnames(styles.calendarPopover, classNameOverride)}
53
67
  role="dialog"
54
68
  aria-modal="true"
@@ -1,5 +1,7 @@
1
1
  import React from "react"
2
+ import { offset, size, autoPlacement } from "@floating-ui/react-dom"
2
3
  import { Meta } from "@storybook/react"
4
+ import { Text } from "~components/Text"
3
5
  import {
4
6
  StickerSheet,
5
7
  StickerSheetStory,
@@ -11,7 +13,9 @@ import { CalendarPopover, CalendarPopoverProps } from "../index"
11
13
  export default {
12
14
  title: "Components/Date controls/Calendars/CalendarPopover",
13
15
  parameters: {
14
- chromatic: { disable: false },
16
+ chromatic: {
17
+ disable: false,
18
+ },
15
19
  controls: { disable: true },
16
20
  a11y: {
17
21
  config: {
@@ -24,34 +28,65 @@ export default {
24
28
  ],
25
29
  },
26
30
  },
31
+ viewport: {
32
+ viewports: {
33
+ ViewportFull: {
34
+ name: "Viewport full size",
35
+ styles: {
36
+ width: "1024px",
37
+ height: "1500px",
38
+ },
39
+ },
40
+ },
41
+ defaultViewport: "ViewportFull",
42
+ },
27
43
  },
28
44
  } satisfies Meta
29
45
 
30
46
  const CalendarPopoverExample = ({
31
47
  children,
32
48
  rowHeight = 300,
33
- }: Partial<CalendarPopoverProps & { rowHeight: number }>): JSX.Element => {
49
+ /** this is here as a convenient way to test overlap */
50
+ strategy = "fixed",
51
+ }: Partial<
52
+ CalendarPopoverProps & {
53
+ rowHeight: number
54
+ /** this is here as a convenient way to test overlap */
55
+ strategy?: "absolute" | "fixed"
56
+ }
57
+ >): JSX.Element => {
34
58
  const [referenceElement, setReferenceElement] =
35
59
  React.useState<HTMLDivElement | null>(null)
36
60
 
37
61
  return (
38
62
  <>
39
63
  <div
64
+ className="bg-orange-300 inline-block"
40
65
  ref={setReferenceElement}
41
- style={{ paddingBottom: "24px", marginTop: `${rowHeight}px` }}
42
- />
66
+ style={{ marginBottom: `${rowHeight}px` }}
67
+ >
68
+ Reference element
69
+ </div>
43
70
  <CalendarPopover
44
71
  referenceElement={referenceElement}
45
- popperOptions={{
46
- modifiers: [
47
- {
48
- name: "offset",
49
- options: {
50
- offset: [24, 0],
72
+ floatingOptions={{
73
+ strategy,
74
+ middleware: [
75
+ offset(15),
76
+ size({
77
+ apply({ availableHeight, availableWidth, elements }) {
78
+ Object.assign(elements.floating.style, {
79
+ maxHeight: `${Math.max(availableHeight - 25, 155)}px`,
80
+ maxWidth: `${availableWidth}px`,
81
+ })
51
82
  },
52
- },
83
+ }),
84
+ autoPlacement({
85
+ // This needs to be here for testing purposes as the default behaviour
86
+ // will cause overlapping calendars in the table
87
+ allowedPlacements: ["bottom-start"],
88
+ }),
53
89
  ],
54
- placement: "top-start",
55
90
  }}
56
91
  >
57
92
  {children}
@@ -73,13 +108,13 @@ const StickerSheetTemplate: StickerSheetStory = {
73
108
  </StickerSheet.Row>
74
109
 
75
110
  <StickerSheet.Row rowTitle="CalendarSingle">
76
- <CalendarPopoverExample>
111
+ <CalendarPopoverExample rowHeight={350}>
77
112
  <CalendarSingle selected={new Date("2022-02-19")} />
78
113
  </CalendarPopoverExample>
79
114
  </StickerSheet.Row>
80
115
 
81
116
  <StickerSheet.Row rowTitle="CalendarRange">
82
- <CalendarPopoverExample>
117
+ <CalendarPopoverExample rowHeight={350}>
83
118
  <CalendarRange
84
119
  selected={{
85
120
  from: new Date("2022-02-19"),
@@ -90,8 +125,9 @@ const StickerSheetTemplate: StickerSheetStory = {
90
125
  </StickerSheet.Row>
91
126
 
92
127
  <StickerSheet.Row rowTitle="CalendarRange with divider">
93
- <CalendarPopoverExample>
128
+ <CalendarPopoverExample rowHeight={350}>
94
129
  <CalendarRange
130
+ data-testid="sb-final-calendar"
95
131
  selected={{
96
132
  from: new Date("2022-02-19"),
97
133
  to: new Date("2022-03-04"),
@@ -118,3 +154,56 @@ export const StickerSheetRTL: StickerSheetStory = {
118
154
  textDirection: "rtl",
119
155
  },
120
156
  }
157
+
158
+ export const StickerSheetResponsive: StickerSheetStory = {
159
+ name: "Sticker Sheet (Responsive)",
160
+ render: () => (
161
+ <>
162
+ <Text variant="intro-lede" classNameOverride="mb-12 ">
163
+ CalendarSingle scaled to availableHeight
164
+ </Text>
165
+ <div className="h-[250px] p-12 bg-purple-100 overflow-hidden relative">
166
+ <CalendarPopoverExample strategy="absolute">
167
+ <CalendarSingle selected={new Date("2022-02-19")} />
168
+ </CalendarPopoverExample>
169
+ </div>
170
+ <Text variant="intro-lede" classNameOverride="mb-12 ">
171
+ CalendarRange scaled to availableHeight
172
+ </Text>
173
+ <div className="h-[250px] p-12 bg-purple-100 overflow-hidden relative">
174
+ <CalendarPopoverExample strategy="absolute">
175
+ <CalendarRange
176
+ selected={{
177
+ from: new Date("2022-02-19"),
178
+ to: new Date("2022-03-04"),
179
+ }}
180
+ hasDivider
181
+ />
182
+ </CalendarPopoverExample>
183
+ </div>
184
+ <Text variant="intro-lede" classNameOverride="mb-12 mt-24">
185
+ CalendarSingle scaled to availableWidth
186
+ </Text>
187
+ <div className="h-[250px] p-12 bg-purple-100 overflow-hidden relative w-[250px]">
188
+ <CalendarPopoverExample strategy="absolute">
189
+ <CalendarSingle selected={new Date("2022-03-19")} />
190
+ </CalendarPopoverExample>
191
+ </div>
192
+ <Text variant="intro-lede" classNameOverride="mb-12 mt-24">
193
+ CalendarRanger scaled to availableWidth
194
+ </Text>
195
+ <div className="h-[250px] p-12 bg-purple-100 overflow-hidden relative w-[250px]">
196
+ <CalendarPopoverExample strategy="absolute">
197
+ <CalendarRange
198
+ data-testid="sb-final-calendar"
199
+ selected={{
200
+ from: new Date("2022-02-19"),
201
+ to: new Date("2022-03-04"),
202
+ }}
203
+ hasDivider
204
+ />
205
+ </CalendarPopoverExample>
206
+ </div>
207
+ </>
208
+ ),
209
+ }
@@ -70,3 +70,17 @@ There are multiple props to disable days within the Calendar.
70
70
 
71
71
  <Canvas of={DatePickerStories.DisabledDays} />
72
72
  <Controls of={DatePickerStories.DisabledDays} />
73
+
74
+ ### Responsive behaviour
75
+
76
+ To ensure calendar content is accessible across multiple viewports and satisfy the [content reflow](https://www.w3.org/WAI/WCAG21/Understanding/reflow.html) spec in WCAG guidelines, the `DatePicker`'s popover will scroll when there is not enough space available. The main case for this is to assist users on 400% zoom and ensure content is not visually lost below the fold.
77
+
78
+ <Canvas of={DatePickerStories.LimitedViewportHeight} />
79
+
80
+ This is determined by the [size](https://floating-ui.com/docs/size) middleware from the `floatingUI` library, which calculates and sets the available height and width based on the viewport and available whitespace.
81
+
82
+ <Canvas of={DatePickerStories.FullViewportHeight} />
83
+
84
+ The `DatePicker`'s popover will also re-adjust its position to the top if there is not enough space available below.
85
+
86
+ <Canvas of={DatePickerStories.AboveIfAvailable} />
@@ -1,6 +1,7 @@
1
1
  import React, { useEffect, useState } from "react"
2
2
  import { action } from "@storybook/addon-actions"
3
3
  import { Meta, StoryObj } from "@storybook/react"
4
+ import { userEvent, within, expect } from "@storybook/test"
4
5
  import Highlight from "react-highlight"
5
6
  import { Button } from "~components/Button"
6
7
  import { defaultMonthControls } from "~components/Calendar/_docs/controls/defaultMonthControls"
@@ -249,3 +250,118 @@ export const Validation: Story = {
249
250
  export const DisabledDays: Story = {
250
251
  parameters: { controls: { include: /^disabled/ } },
251
252
  }
253
+
254
+ export const LimitedWindowWidth: Story = {
255
+ name: "At 400% window size",
256
+ parameters: {
257
+ controls: { disable: true },
258
+ viewport: {
259
+ viewports: {
260
+ ViewportAt400: {
261
+ name: "Viewport at 400%",
262
+ styles: {
263
+ width: "320px",
264
+ height: "350px",
265
+ },
266
+ },
267
+ },
268
+ defaultViewport: "ViewportAt400",
269
+ },
270
+ a11y: { disable: true }, // accessible label fix to be addressed in a separate PR
271
+ },
272
+ play: async ({ canvasElement }) => {
273
+ const canvas = within(canvasElement)
274
+ await userEvent.click(canvas.getByRole("button", { name: "Choose date" }))
275
+ await expect(canvas.getByRole("dialog")).toBeInTheDocument()
276
+ },
277
+ }
278
+
279
+ export const AboveIfAvailable: Story = {
280
+ name: "Limited viewport autoplacement above",
281
+ args: {
282
+ labelText: "Calendar with space above",
283
+ },
284
+ parameters: {
285
+ viewport: {
286
+ viewports: {
287
+ LimitedViewportAutoPlace: {
288
+ name: "Limited vertical space",
289
+ styles: {
290
+ width: "1024px",
291
+ height: "500px",
292
+ },
293
+ },
294
+ },
295
+ defaultViewport: "LimitedViewportAutoPlace",
296
+ },
297
+ a11y: { disable: true }, // accessible label fix to be addressed in a separate PR
298
+ },
299
+ decorators: [
300
+ Story => (
301
+ <div className="mt-[350px]">
302
+ <Story />
303
+ </div>
304
+ ),
305
+ ],
306
+ play: async ({ canvasElement }) => {
307
+ const canvas = within(canvasElement)
308
+ await userEvent.click(canvas.getByRole("button", { name: "Choose date" }))
309
+ await expect(canvas.getByRole("dialog")).toBeInTheDocument()
310
+ },
311
+ }
312
+
313
+ export const LimitedViewportHeight: Story = {
314
+ name: "Limited viewport height",
315
+ args: {
316
+ labelText: "Calendar with reduced space below",
317
+ },
318
+ parameters: {
319
+ viewport: {
320
+ viewports: {
321
+ LimitedViewportHeight: {
322
+ name: "Limited vertical space",
323
+ styles: {
324
+ width: "1024px",
325
+ height: "300px",
326
+ },
327
+ },
328
+ },
329
+ defaultViewport: "LimitedViewportHeight",
330
+ },
331
+ a11y: { disable: true }, // accessible label fix to be addressed in a separate PR
332
+ },
333
+ decorators: [
334
+ Story => (
335
+ <div className="mb-[150px]">
336
+ <Story />
337
+ </div>
338
+ ),
339
+ ],
340
+ play: async ({ canvasElement }) => {
341
+ const canvas = within(canvasElement)
342
+ await userEvent.click(canvas.getByRole("button", { name: "Choose date" }))
343
+ await expect(canvas.getByRole("dialog")).toBeInTheDocument()
344
+ },
345
+ }
346
+
347
+ export const FullViewportHeight: Story = {
348
+ name: "Full viewport height",
349
+ args: {
350
+ labelText: "Calendar with full space below",
351
+ },
352
+ decorators: [
353
+ Story => (
354
+ <div className="mb-[350px]">
355
+ <Story />
356
+ </div>
357
+ ),
358
+ ],
359
+ play: async ({ canvasElement }) => {
360
+ const canvas = within(canvasElement)
361
+ await userEvent.click(canvas.getByRole("button", { name: "Choose date" }))
362
+ await expect(canvas.getByRole("dialog")).toBeInTheDocument()
363
+ },
364
+ parameters: {
365
+ a11y: { disable: true }, // accessible label fix to be addressed in a separate PR
366
+ },
367
+ }
@@ -23,3 +23,8 @@ Date range picker form field.
23
23
 
24
24
  <Canvas of={DateRangePickerStories.Playground} />
25
25
  <Controls of={DateRangePickerStories.Playground} />
26
+
27
+
28
+ ## Responsive behaviour
29
+
30
+ As both the `DatePicker` and `DateRangePicker` use the `CalendarPopover` component under the hood, they share the same responsive behaviour. You can read more on this [here](/docs/components-date-controls-datepicker--docs#responsive-behaviour).