@windstream/react-shared-components 0.0.86 → 0.0.87

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 (135) hide show
  1. package/README.md +636 -630
  2. package/dist/core.d.ts +1 -1
  3. package/dist/index.d.ts +3 -3
  4. package/dist/index.js.map +1 -1
  5. package/package.json +177 -177
  6. package/src/components/accordion/Accordion.stories.tsx +230 -230
  7. package/src/components/accordion/types.ts +10 -10
  8. package/src/components/alert-card/AlertCard.stories.tsx +171 -171
  9. package/src/components/alert-card/index.tsx +32 -32
  10. package/src/components/alert-card/types.ts +9 -9
  11. package/src/components/brand-button/BrandButton.stories.tsx +223 -223
  12. package/src/components/brand-button/helpers.ts +35 -35
  13. package/src/components/brand-button/index.tsx +115 -115
  14. package/src/components/brand-button/types.ts +37 -37
  15. package/src/components/button/Button.stories.tsx +108 -108
  16. package/src/components/button/index.tsx +27 -27
  17. package/src/components/button/types.ts +14 -14
  18. package/src/components/call-button/CallButton.stories.tsx +324 -324
  19. package/src/components/call-button/index.tsx +86 -86
  20. package/src/components/call-button/types.ts +11 -11
  21. package/src/components/checkbox/Checkbox.stories.tsx +247 -247
  22. package/src/components/checkbox/index.tsx +197 -197
  23. package/src/components/checkbox/types.ts +27 -27
  24. package/src/components/checklist/Checklist.stories.tsx +150 -150
  25. package/src/components/checklist/index.tsx +54 -54
  26. package/src/components/checklist/types.ts +9 -9
  27. package/src/components/collapse/Collapse.stories.tsx +255 -255
  28. package/src/components/collapse/index.tsx +46 -46
  29. package/src/components/collapse/types.ts +6 -6
  30. package/src/components/divider/Divider.stories.tsx +205 -205
  31. package/src/components/divider/index.tsx +22 -22
  32. package/src/components/divider/type.ts +3 -3
  33. package/src/components/image/Image.stories.tsx +113 -113
  34. package/src/components/image/index.tsx +25 -25
  35. package/src/components/image/types.ts +40 -40
  36. package/src/components/input/Input.stories.tsx +325 -325
  37. package/src/components/input/index.tsx +177 -177
  38. package/src/components/input/types.ts +37 -37
  39. package/src/components/link/Link.stories.tsx +163 -163
  40. package/src/components/link/types.ts +25 -25
  41. package/src/components/list/List.stories.tsx +272 -272
  42. package/src/components/list/index.tsx +88 -88
  43. package/src/components/list/list-item/index.tsx +38 -38
  44. package/src/components/list/list-item/types.ts +13 -13
  45. package/src/components/list/types.ts +29 -29
  46. package/src/components/material-icon/MaterialIcon.stories.tsx +330 -330
  47. package/src/components/material-icon/constants.ts +97 -96
  48. package/src/components/material-icon/index.tsx +44 -44
  49. package/src/components/material-icon/types.ts +31 -31
  50. package/src/components/modal/Modal.stories.tsx +171 -171
  51. package/src/components/modal/index.tsx +164 -164
  52. package/src/components/modal/types.ts +24 -24
  53. package/src/components/next-image/index.tsx +32 -32
  54. package/src/components/next-image/types.ts +1 -1
  55. package/src/components/radio-button/RadioButton.stories.tsx +307 -307
  56. package/src/components/radio-button/index.tsx +75 -75
  57. package/src/components/radio-button/types.ts +21 -21
  58. package/src/components/see-more/SeeMore.stories.tsx +181 -181
  59. package/src/components/see-more/index.tsx +44 -44
  60. package/src/components/see-more/types.ts +4 -4
  61. package/src/components/select/Select.stories.tsx +411 -411
  62. package/src/components/select/index.tsx +150 -150
  63. package/src/components/select/types.ts +35 -35
  64. package/src/components/select-plan-button/SelectPlanButton.stories.tsx +184 -184
  65. package/src/components/select-plan-button/index.tsx +31 -31
  66. package/src/components/select-plan-button/types.ts +5 -5
  67. package/src/components/skeleton/Skeleton.stories.tsx +179 -179
  68. package/src/components/skeleton/index.tsx +61 -61
  69. package/src/components/skeleton/types.ts +4 -4
  70. package/src/components/spinner/Spinner.stories.tsx +335 -335
  71. package/src/components/spinner/index.tsx +44 -44
  72. package/src/components/spinner/types.ts +5 -5
  73. package/src/components/text/Text.stories.tsx +321 -321
  74. package/src/components/text/index.tsx +25 -25
  75. package/src/components/text/types.ts +45 -45
  76. package/src/components/tooltip/Tooltip.stories.tsx +219 -219
  77. package/src/components/tooltip/index.tsx +74 -74
  78. package/src/components/tooltip/types.ts +7 -7
  79. package/src/components/view-cart-button/ViewCartButton.stories.tsx +252 -252
  80. package/src/components/view-cart-button/index.tsx +44 -44
  81. package/src/components/view-cart-button/types.ts +5 -5
  82. package/src/contentful/blocks/button/Button.stories.tsx +40 -40
  83. package/src/contentful/blocks/button/index.tsx +85 -85
  84. package/src/contentful/blocks/button/types.ts +26 -26
  85. package/src/contentful/blocks/callout/Callout.stories.tsx +23 -23
  86. package/src/contentful/blocks/callout/index.tsx +66 -66
  87. package/src/contentful/blocks/cards/Cards.stories.tsx +23 -23
  88. package/src/contentful/blocks/cards/index.tsx +13 -13
  89. package/src/contentful/blocks/cards/product-card/index.tsx +199 -199
  90. package/src/contentful/blocks/cards/product-card/types.ts +20 -20
  91. package/src/contentful/blocks/cards/simple-card/index.tsx +77 -77
  92. package/src/contentful/blocks/cards/simple-card/types.ts +31 -31
  93. package/src/contentful/blocks/cards/testimonial-card/index.tsx +88 -88
  94. package/src/contentful/blocks/cards/testimonial-card/types.tsx +12 -12
  95. package/src/contentful/blocks/cards/types.ts +1 -1
  96. package/src/contentful/blocks/carousel/Carousel.stories.tsx +23 -23
  97. package/src/contentful/blocks/carousel/helper.tsx +314 -314
  98. package/src/contentful/blocks/carousel/index.tsx +52 -52
  99. package/src/contentful/blocks/carousel/types.ts +126 -126
  100. package/src/contentful/blocks/cta-callout/CtaCallout.stories.tsx +46 -46
  101. package/src/contentful/blocks/cta-callout/index.tsx +54 -54
  102. package/src/contentful/blocks/cta-callout/types.ts +22 -22
  103. package/src/contentful/blocks/find-kinetic/index.tsx +124 -124
  104. package/src/contentful/blocks/floating-banner/FloatingBanner.stories.tsx +34 -34
  105. package/src/contentful/blocks/floating-banner/types.ts +22 -22
  106. package/src/contentful/blocks/footer/Footer.stories.tsx +30 -30
  107. package/src/contentful/blocks/image-promo-bar/ImagePromoBar.stories.tsx +23 -23
  108. package/src/contentful/blocks/image-promo-bar/types.ts +27 -27
  109. package/src/contentful/blocks/modal/constants.ts +53 -53
  110. package/src/contentful/blocks/modal/index.tsx +91 -91
  111. package/src/contentful/blocks/modal/types.ts +12 -12
  112. package/src/contentful/blocks/navigation/desktop-link-groups.tsx/index.tsx +111 -111
  113. package/src/contentful/blocks/navigation/index.tsx +385 -385
  114. package/src/contentful/blocks/navigation/mobile-link-groups.tsx/index.tsx +80 -80
  115. package/src/contentful/blocks/navigation/types.ts +41 -41
  116. package/src/contentful/blocks/primary-hero/PrimaryHero.stories.tsx +23 -23
  117. package/src/contentful/blocks/primary-hero/index.tsx +212 -212
  118. package/src/contentful/blocks/primary-hero/types.ts +30 -30
  119. package/src/contentful/blocks/shape-background-wrapper/ShapeBackgroundWrapper.stories.tsx +26 -26
  120. package/src/contentful/blocks/shape-background-wrapper/index.tsx +124 -124
  121. package/src/contentful/blocks/shape-background-wrapper/types.ts +36 -36
  122. package/src/contentful/blocks/text/Text.stories.tsx +23 -23
  123. package/src/contentful/blocks/text/index.tsx +12 -12
  124. package/src/contentful/blocks/text/types.ts +1 -1
  125. package/src/contentful/index.ts +57 -57
  126. package/src/hooks/use-body-scroll-lock.ts +34 -34
  127. package/src/hooks/use-outside-click.ts +17 -17
  128. package/src/index.ts +96 -96
  129. package/src/next/index.ts +5 -5
  130. package/src/setupTests.ts +46 -46
  131. package/src/stories/DocsTemplate.tsx +24 -24
  132. package/src/styles/globals.css +307 -307
  133. package/src/types/global.d.ts +9 -9
  134. package/src/types/micro-components.ts +80 -80
  135. package/src/utils/index.ts +49 -49
@@ -1,91 +1,91 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import {
5
- backdropAnimationVariants,
6
- contentAnimationVariants,
7
- sizeToPixel,
8
- } from "./constants";
9
- import { ModalProps } from "./types";
10
- import { motion } from "framer-motion";
11
-
12
- import * as Dialog from "@radix-ui/react-dialog";
13
- import { MaterialIcon } from "@shared/components/material-icon";
14
- import { Text } from "@shared/components/text";
15
- import { Button } from "@shared/contentful/blocks/button";
16
- import { cx } from "@shared/utils";
17
-
18
- export const Modal: React.FC<ModalProps> = props => {
19
- const {
20
- isOpen,
21
- onRequestClose,
22
- size,
23
- title,
24
- content,
25
- description,
26
- children,
27
- bodyClassName,
28
- } = props;
29
-
30
- return (
31
- <Dialog.Root
32
- open={isOpen}
33
- onOpenChange={() => isOpen && onRequestClose?.()}
34
- >
35
- <Dialog.Portal>
36
- <motion.div
37
- initial="closed"
38
- animate={isOpen ? "open" : "closed"}
39
- variants={backdropAnimationVariants}
40
- transition={{ type: "tween", duration: 0.2, ease: "easeInOut" }}
41
- className="fixed inset-0 z-[1000] bg-scrim-bg-modal"
42
- >
43
- <Dialog.Overlay />
44
- </motion.div>
45
- <motion.div
46
- initial="closed"
47
- animate={isOpen ? "open" : "closed"}
48
- variants={contentAnimationVariants}
49
- transition={{ type: "tween", duration: 0.3, ease: "easeInOut" }}
50
- className="fixed left-1/2 top-1/2 z-[1001] w-auto -translate-x-1/2 -translate-y-1/2 focus:outline-none"
51
- >
52
- <Dialog.Content
53
- className={cx(
54
- "fixed left-[50%] top-[50%] w-[90vw] translate-x-[-50%] translate-y-[-50%] rounded-[6px] bg-bg p-[25px] shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none",
55
- bodyClassName
56
- )}
57
- style={{ maxWidth: sizeToPixel[size || "lg"] }}
58
- >
59
- <Dialog.Close asChild={true}>
60
- <Button
61
- showButtonAs="unstyled"
62
- buttonClassName="absolute right-0 top-0 mr-2 mt-2 bg-bg"
63
- >
64
- <MaterialIcon name="close" />
65
- </Button>
66
- </Dialog.Close>
67
- <div className="custom-modal-body max-h-[85vh] overflow-visible">
68
- {title ? (
69
- <Text
70
- className={cx(
71
- "mx-auto mb-3 mt-5 text-center",
72
- "heading5 md:max-w-[80%] md:pt-0",
73
- "mb-5 md:mb-[60px]"
74
- )}
75
- as="h2"
76
- >
77
- {title}
78
- </Text>
79
- ) : null}
80
-
81
- {description ? <Text as="div">{description}</Text> : null}
82
-
83
- {content}
84
- {children ? children : null}
85
- </div>
86
- </Dialog.Content>
87
- </motion.div>
88
- </Dialog.Portal>
89
- </Dialog.Root>
90
- );
91
- };
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import {
5
+ backdropAnimationVariants,
6
+ contentAnimationVariants,
7
+ sizeToPixel,
8
+ } from "./constants";
9
+ import { ModalProps } from "./types";
10
+ import { motion } from "framer-motion";
11
+
12
+ import * as Dialog from "@radix-ui/react-dialog";
13
+ import { MaterialIcon } from "@shared/components/material-icon";
14
+ import { Text } from "@shared/components/text";
15
+ import { Button } from "@shared/contentful/blocks/button";
16
+ import { cx } from "@shared/utils";
17
+
18
+ export const Modal: React.FC<ModalProps> = props => {
19
+ const {
20
+ isOpen,
21
+ onRequestClose,
22
+ size,
23
+ title,
24
+ content,
25
+ description,
26
+ children,
27
+ bodyClassName,
28
+ } = props;
29
+
30
+ return (
31
+ <Dialog.Root
32
+ open={isOpen}
33
+ onOpenChange={() => isOpen && onRequestClose?.()}
34
+ >
35
+ <Dialog.Portal>
36
+ <motion.div
37
+ initial="closed"
38
+ animate={isOpen ? "open" : "closed"}
39
+ variants={backdropAnimationVariants}
40
+ transition={{ type: "tween", duration: 0.2, ease: "easeInOut" }}
41
+ className="fixed inset-0 z-[1000] bg-scrim-bg-modal"
42
+ >
43
+ <Dialog.Overlay />
44
+ </motion.div>
45
+ <motion.div
46
+ initial="closed"
47
+ animate={isOpen ? "open" : "closed"}
48
+ variants={contentAnimationVariants}
49
+ transition={{ type: "tween", duration: 0.3, ease: "easeInOut" }}
50
+ className="fixed left-1/2 top-1/2 z-[1001] w-auto -translate-x-1/2 -translate-y-1/2 focus:outline-none"
51
+ >
52
+ <Dialog.Content
53
+ className={cx(
54
+ "fixed left-[50%] top-[50%] w-[90vw] translate-x-[-50%] translate-y-[-50%] rounded-[6px] bg-bg p-[25px] shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none",
55
+ bodyClassName
56
+ )}
57
+ style={{ maxWidth: sizeToPixel[size || "lg"] }}
58
+ >
59
+ <Dialog.Close asChild={true}>
60
+ <Button
61
+ showButtonAs="unstyled"
62
+ buttonClassName="absolute right-0 top-0 mr-2 mt-2 bg-bg"
63
+ >
64
+ <MaterialIcon name="close" />
65
+ </Button>
66
+ </Dialog.Close>
67
+ <div className="custom-modal-body max-h-[85vh] overflow-visible">
68
+ {title ? (
69
+ <Text
70
+ className={cx(
71
+ "mx-auto mb-3 mt-5 text-center",
72
+ "heading5 md:max-w-[80%] md:pt-0",
73
+ "mb-5 md:mb-[60px]"
74
+ )}
75
+ as="h2"
76
+ >
77
+ {title}
78
+ </Text>
79
+ ) : null}
80
+
81
+ {description ? <Text as="div">{description}</Text> : null}
82
+
83
+ {content}
84
+ {children ? children : null}
85
+ </div>
86
+ </Dialog.Content>
87
+ </motion.div>
88
+ </Dialog.Portal>
89
+ </Dialog.Root>
90
+ );
91
+ };
@@ -1,12 +1,12 @@
1
- import React from "react";
2
-
3
- export type ModalProps = {
4
- isOpen: boolean;
5
- onRequestClose?: () => void;
6
- size?: "lg" | "md" | "sm" | "xl" | "xs";
7
- title?: string;
8
- description?: React.ReactNode;
9
- content?: React.ReactNode;
10
- children?: React.ReactNode;
11
- bodyClassName?: string;
12
- };
1
+ import React from "react";
2
+
3
+ export type ModalProps = {
4
+ isOpen: boolean;
5
+ onRequestClose?: () => void;
6
+ size?: "lg" | "md" | "sm" | "xl" | "xs";
7
+ title?: string;
8
+ description?: React.ReactNode;
9
+ content?: React.ReactNode;
10
+ children?: React.ReactNode;
11
+ bodyClassName?: string;
12
+ };
@@ -1,111 +1,111 @@
1
- import React, { CSSProperties } from "react";
2
-
3
- import { MaterialIcon } from "@shared/components/material-icon";
4
- import { Text } from "@shared/components/text";
5
- import { Button } from "@shared/contentful/blocks/button";
6
- import { ButtonProps as ContentfulButtonProps } from "@shared/contentful/blocks/button/types";
7
- import { useOutsideClick } from "@shared/hooks/use-outside-click";
8
- import { cx } from "@shared/utils";
9
-
10
- type ComponentButtonGroup = {
11
- anchorId?: string | null;
12
- title?: string | null;
13
- items?: { items?: ContentfulButtonProps[] | null } | null;
14
- };
15
-
16
- type Link = ContentfulButtonProps | ComponentButtonGroup;
17
-
18
- type LinkGroupsProps = {
19
- link?: Link;
20
- anchorName: string;
21
- };
22
-
23
- const isButton = (link: Link): link is ContentfulButtonProps => {
24
- // If your group never has `href`, this is a simple and effective guard
25
- return typeof (link as ContentfulButtonProps).href === "string";
26
- };
27
-
28
- export const DesktopLinkGroups: React.FC<LinkGroupsProps> = ({
29
- link,
30
- anchorName,
31
- }) => {
32
- const [isOpen, setIsOpen] = React.useState(false);
33
-
34
- const ref = React.useRef<HTMLDivElement>(null);
35
- useOutsideClick(ref, () => setIsOpen(false));
36
-
37
- if (!link) return null;
38
-
39
- // Single button
40
- if (isButton(link)) {
41
- return (
42
- <Button
43
- key={`submenu-link-btn-${link.anchorId}`}
44
- {...link}
45
- linkClassName="body3 flex items-center text-text-link h-full"
46
- linkVariant="unstyled"
47
- />
48
- );
49
- }
50
-
51
- // Group
52
- const { anchorId, title, items } = link;
53
- const subMenu = Array.isArray(items?.items) ? items!.items! : [];
54
- const fullAnchorName = `--link-anchor-${anchorName}`;
55
-
56
- return (
57
- <div
58
- className="relative h-full"
59
- style={{ anchorName: fullAnchorName } as CSSProperties}
60
- ref={ref}
61
- >
62
- <Button
63
- onClick={() => setIsOpen(prev => !prev)}
64
- aria-expanded={isOpen}
65
- buttonClassName="group body3 flex h-full items-center"
66
- key={anchorId}
67
- showButtonAs="unstyled"
68
- >
69
- <Text as="span" className="group-hover:underline">
70
- {title ?? null}
71
- </Text>
72
- <MaterialIcon
73
- weight="700"
74
- className="text-icon-info group-hover:opacity-50"
75
- name={isOpen ? "keyboard_arrow_up" : "keyboard_arrow_down"}
76
- />
77
- </Button>
78
-
79
- <div
80
- className={cx(
81
- "fixed z-10 min-w-44 rounded-xl bg-bg shadow-lg",
82
- "transition-[opacity,transform] ease-out",
83
- isOpen && subMenu.length > 0
84
- ? "pointer-events-auto translate-y-0 opacity-100 duration-75"
85
- : "pointer-events-none -translate-y-2 opacity-0 duration-0"
86
- )}
87
- style={
88
- {
89
- positionAnchor: fullAnchorName,
90
- top: "anchor(bottom)",
91
- right: "anchor(right)",
92
- } as CSSProperties
93
- }
94
- >
95
- <ul className="flex flex-col gap-2 py-2">
96
- {subMenu.map((site, index) => {
97
- return (
98
- <li key={`submenu-link-${index}`} className="submenu-link">
99
- <Button
100
- {...site}
101
- linkVariant="unstyled"
102
- linkClassName="body3 px-4 hover:bg-bg-surface-hover flex items-center w-full h-11 text-text-link"
103
- />
104
- </li>
105
- );
106
- })}
107
- </ul>
108
- </div>
109
- </div>
110
- );
111
- };
1
+ import React, { CSSProperties } from "react";
2
+
3
+ import { MaterialIcon } from "@shared/components/material-icon";
4
+ import { Text } from "@shared/components/text";
5
+ import { Button } from "@shared/contentful/blocks/button";
6
+ import { ButtonProps as ContentfulButtonProps } from "@shared/contentful/blocks/button/types";
7
+ import { useOutsideClick } from "@shared/hooks/use-outside-click";
8
+ import { cx } from "@shared/utils";
9
+
10
+ type ComponentButtonGroup = {
11
+ anchorId?: string | null;
12
+ title?: string | null;
13
+ items?: { items?: ContentfulButtonProps[] | null } | null;
14
+ };
15
+
16
+ type Link = ContentfulButtonProps | ComponentButtonGroup;
17
+
18
+ type LinkGroupsProps = {
19
+ link?: Link;
20
+ anchorName: string;
21
+ };
22
+
23
+ const isButton = (link: Link): link is ContentfulButtonProps => {
24
+ // If your group never has `href`, this is a simple and effective guard
25
+ return typeof (link as ContentfulButtonProps).href === "string";
26
+ };
27
+
28
+ export const DesktopLinkGroups: React.FC<LinkGroupsProps> = ({
29
+ link,
30
+ anchorName,
31
+ }) => {
32
+ const [isOpen, setIsOpen] = React.useState(false);
33
+
34
+ const ref = React.useRef<HTMLDivElement>(null);
35
+ useOutsideClick(ref, () => setIsOpen(false));
36
+
37
+ if (!link) return null;
38
+
39
+ // Single button
40
+ if (isButton(link)) {
41
+ return (
42
+ <Button
43
+ key={`submenu-link-btn-${link.anchorId}`}
44
+ {...link}
45
+ linkClassName="body3 flex items-center text-text-link h-full"
46
+ linkVariant="unstyled"
47
+ />
48
+ );
49
+ }
50
+
51
+ // Group
52
+ const { anchorId, title, items } = link;
53
+ const subMenu = Array.isArray(items?.items) ? items!.items! : [];
54
+ const fullAnchorName = `--link-anchor-${anchorName}`;
55
+
56
+ return (
57
+ <div
58
+ className="relative h-full"
59
+ style={{ anchorName: fullAnchorName } as CSSProperties}
60
+ ref={ref}
61
+ >
62
+ <Button
63
+ onClick={() => setIsOpen(prev => !prev)}
64
+ aria-expanded={isOpen}
65
+ buttonClassName="group body3 flex h-full items-center"
66
+ key={anchorId}
67
+ showButtonAs="unstyled"
68
+ >
69
+ <Text as="span" className="group-hover:underline">
70
+ {title ?? null}
71
+ </Text>
72
+ <MaterialIcon
73
+ weight="700"
74
+ className="text-icon-info group-hover:opacity-50"
75
+ name={isOpen ? "keyboard_arrow_up" : "keyboard_arrow_down"}
76
+ />
77
+ </Button>
78
+
79
+ <div
80
+ className={cx(
81
+ "fixed z-10 min-w-44 rounded-xl bg-bg shadow-lg",
82
+ "transition-[opacity,transform] ease-out",
83
+ isOpen && subMenu.length > 0
84
+ ? "pointer-events-auto translate-y-0 opacity-100 duration-75"
85
+ : "pointer-events-none -translate-y-2 opacity-0 duration-0"
86
+ )}
87
+ style={
88
+ {
89
+ positionAnchor: fullAnchorName,
90
+ top: "anchor(bottom)",
91
+ right: "anchor(right)",
92
+ } as CSSProperties
93
+ }
94
+ >
95
+ <ul className="flex flex-col gap-2 py-2">
96
+ {subMenu.map((site, index) => {
97
+ return (
98
+ <li key={`submenu-link-${index}`} className="submenu-link">
99
+ <Button
100
+ {...site}
101
+ linkVariant="unstyled"
102
+ linkClassName="body3 px-4 hover:bg-bg-surface-hover flex items-center w-full h-11 text-text-link"
103
+ />
104
+ </li>
105
+ );
106
+ })}
107
+ </ul>
108
+ </div>
109
+ </div>
110
+ );
111
+ };