@tfehotels/tfe-gatsby-library 1.0.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.
Files changed (84) hide show
  1. package/README.md +41 -0
  2. package/lib/index.browser.cjs +2 -0
  3. package/lib/index.browser.cjs.map +1 -0
  4. package/lib/index.browser.d.ts +640 -0
  5. package/lib/index.browser.esm.js +2 -0
  6. package/lib/index.browser.esm.js.map +1 -0
  7. package/lib/index.node.cjs +2 -0
  8. package/lib/index.node.cjs.map +1 -0
  9. package/lib/index.node.d.ts +116 -0
  10. package/lib/index.node.esm.js +2 -0
  11. package/lib/index.node.esm.js.map +1 -0
  12. package/package.json +84 -0
  13. package/src/browser/api/button/index.tsx +16 -0
  14. package/src/browser/api/button/types.ts +7 -0
  15. package/src/browser/api/checkbox/index.tsx +74 -0
  16. package/src/browser/api/checkbox/types.tsx +21 -0
  17. package/src/browser/api/country-prefix/index.tsx +150 -0
  18. package/src/browser/api/country-prefix/types.tsx +17 -0
  19. package/src/browser/api/form/index.tsx +330 -0
  20. package/src/browser/api/form/types.ts +31 -0
  21. package/src/browser/api/google-places/index.tsx +90 -0
  22. package/src/browser/api/google-places/types.ts +24 -0
  23. package/src/browser/api/icon/index.tsx +26 -0
  24. package/src/browser/api/icon/types.tsx +24 -0
  25. package/src/browser/api/image/index.tsx +91 -0
  26. package/src/browser/api/image/types.ts +11 -0
  27. package/src/browser/api/input/index.tsx +44 -0
  28. package/src/browser/api/input/types.ts +10 -0
  29. package/src/browser/api/link/index.tsx +54 -0
  30. package/src/browser/api/link/types.ts +24 -0
  31. package/src/browser/api/linklist/index.tsx +17 -0
  32. package/src/browser/api/linklist/types.ts +6 -0
  33. package/src/browser/api/select/index.tsx +99 -0
  34. package/src/browser/api/select/types.ts +24 -0
  35. package/src/browser/api/svg/index.tsx +8 -0
  36. package/src/browser/api/svg/types.ts +8 -0
  37. package/src/browser/api/text/index.tsx +14 -0
  38. package/src/browser/api/text/types.ts +12 -0
  39. package/src/browser/api/textarea/index.tsx +12 -0
  40. package/src/browser/api/title/index.tsx +19 -0
  41. package/src/browser/api/title/types.ts +10 -0
  42. package/src/browser/api/types.ts +245 -0
  43. package/src/browser/carousel/buttons/index.tsx +81 -0
  44. package/src/browser/carousel/buttons/types.ts +15 -0
  45. package/src/browser/carousel/dots/index.tsx +53 -0
  46. package/src/browser/carousel/dots/types.ts +14 -0
  47. package/src/browser/carousel/index.tsx +131 -0
  48. package/src/browser/carousel/types.ts +21 -0
  49. package/src/browser/markdown/index.tsx +41 -0
  50. package/src/browser/markdown/types.ts +11 -0
  51. package/src/browser/modal/index.tsx +35 -0
  52. package/src/browser/modal/types.ts +9 -0
  53. package/src/browser/spinner/index.tsx +19 -0
  54. package/src/browser/spinner/types.ts +5 -0
  55. package/src/browser/toast/index.tsx +84 -0
  56. package/src/browser/use_viewport/index.tsx +34 -0
  57. package/src/browser/use_viewport/types.ts +5 -0
  58. package/src/browser/utils/animation.ts +12 -0
  59. package/src/browser/utils/booking_engine.ts +180 -0
  60. package/src/browser/utils/eclub.ts +30 -0
  61. package/src/browser/utils/forms.ts +76 -0
  62. package/src/browser/utils/hotel.ts +25 -0
  63. package/src/browser/utils/image.ts +63 -0
  64. package/src/browser/utils/location.ts +213 -0
  65. package/src/browser/utils/notifications.tsx +25 -0
  66. package/src/browser/utils/number.ts +6 -0
  67. package/src/browser/utils/requests.ts +2 -0
  68. package/src/browser/utils/search.ts +25 -0
  69. package/src/browser/utils/string.ts +9 -0
  70. package/src/browser/utils/types.ts +106 -0
  71. package/src/browser/utils/url.ts +116 -0
  72. package/src/browser/utils/viewport.ts +59 -0
  73. package/src/index.browser.ts +103 -0
  74. package/src/index.node.ts +16 -0
  75. package/src/node/api/index.ts +174 -0
  76. package/src/node/api/types.ts +19 -0
  77. package/src/node/build/index.ts +142 -0
  78. package/src/node/build/types.ts +5 -0
  79. package/src/node/config/index.ts +149 -0
  80. package/src/node/form/index.ts +23 -0
  81. package/src/node/form/types.ts +3 -0
  82. package/src/node/property/index.ts +78 -0
  83. package/src/node/property/types.ts +25 -0
  84. package/src/node/url/index.ts +8 -0
@@ -0,0 +1,91 @@
1
+ import React from "react"
2
+ import {
3
+ GatsbyImage,
4
+ getImage,
5
+ withArtDirection,
6
+ IGatsbyImageData,
7
+ } from "gatsby-plugin-image"
8
+ import { ImageType } from "../types"
9
+ import { ImagePropsType } from "./types"
10
+ import classNames from "classnames"
11
+
12
+ const buildImage = (img: ImageType): IGatsbyImageData | undefined => {
13
+ if (!img) {
14
+ return undefined
15
+ }
16
+
17
+ let fallback = {
18
+ src: img.url,
19
+ sizes: "100vw",
20
+ srcSet: "",
21
+ }
22
+ let sources = []
23
+ let placeholder = { fallback: img.url }
24
+ const sizes = [img.width, 360, 769, 1024, 1216, 1408].sort((a, b) => a - b)
25
+
26
+ if (img.optimized) {
27
+ fallback.src = img.url + img.name + "-" + img.width + "w.jpg"
28
+ placeholder.fallback = img.url + img.name + "-20w.jpg"
29
+ sources.push({ sizes: "100vw", srcSet: "", type: "image/avif" })
30
+ sources.push({ sizes: "100vw", srcSet: "", type: "image/webp" })
31
+ for (let index in sizes) {
32
+ if (sizes[index] > img.width) {
33
+ break
34
+ }
35
+ let image_url =
36
+ (index === "0" ? "" : ",") + img.url + img.name + "-" + sizes[index]
37
+ fallback.srcSet += image_url + "w.jpg " + sizes[index] + "w"
38
+ sources[0].srcSet += image_url + "w.avif " + sizes[index] + "w"
39
+ sources[1].srcSet += image_url + "w.webp " + sizes[index] + "w"
40
+ }
41
+ }
42
+
43
+ return getImage({
44
+ childImageSharp: {
45
+ gatsbyImageData: {
46
+ backgroundColor: "transparent",
47
+ height: img.height / img.width,
48
+ width: 1,
49
+ layout: "fullWidth",
50
+ placeholder: placeholder,
51
+ images: {
52
+ fallback: fallback,
53
+ sources: sources,
54
+ },
55
+ },
56
+ },
57
+ })
58
+ }
59
+
60
+ const Image = ({ imageData, ...props }: ImagePropsType) => {
61
+ const initImage = () => {
62
+ const image_data = buildImage(props.image as ImageType)
63
+ const mobile_image_data = buildImage(props.mobile_image as ImageType)
64
+ return image_data && mobile_image_data // If mobile image exists, it must be added using Art Direction.
65
+ ? withArtDirection(image_data, [
66
+ {
67
+ media: "(max-width: 768px)",
68
+ image: mobile_image_data,
69
+ },
70
+ ])
71
+ : image_data
72
+ }
73
+ let image = imageData ?? initImage()
74
+
75
+ return image ? (
76
+ <GatsbyImage
77
+ className={classNames({
78
+ ["mobile-img"]: !!props.image && !!props.mobile_image,
79
+ [props.className as string]: !!props.className,
80
+ })}
81
+ image={image}
82
+ onLoad={props.onLoad}
83
+ alt={props.image?.alt ? props.image.alt : ""}
84
+ style={props.style}
85
+ />
86
+ ) : (
87
+ <span>Missing image!</span>
88
+ )
89
+ }
90
+
91
+ export default Image
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ import { MediaType } from "../types";
3
+ import { IGatsbyImageData } from "gatsby-plugin-image";
4
+
5
+ export interface ImagePropsType extends MediaType {
6
+ type: "image";
7
+ className?: string;
8
+ style?: React.CSSProperties;
9
+ onLoad?: any;
10
+ imageData?: IGatsbyImageData;
11
+ }
@@ -0,0 +1,44 @@
1
+ import React from "react"
2
+ import { InputPropsType } from "./types"
3
+ import Markdown from "../../markdown"
4
+ import Icon from "../icon"
5
+
6
+
7
+ const Input = ({
8
+ label,
9
+ type,
10
+ input_type,
11
+ description,
12
+ name,
13
+ input_name,
14
+ icon,
15
+ iconOnClick,
16
+ read_only,
17
+ ...props
18
+ }: InputPropsType) => {
19
+ return (
20
+ <label
21
+ className={`input label-${name}${
22
+ input_type === "hidden" ? " hidden" : ""
23
+ }`}
24
+ >
25
+ {!!label && <span>{label}</span>}
26
+ {!!icon && <Icon icon={icon} onClick={iconOnClick} />}
27
+ <input
28
+ type={input_type}
29
+ name={input_name}
30
+ readOnly={read_only}
31
+ {...props}
32
+ />
33
+ {!!description && (
34
+ <div className="desc">
35
+ <div>
36
+ <Markdown>{description}</Markdown>
37
+ </div>
38
+ </div>
39
+ )}
40
+ </label>
41
+ )
42
+ }
43
+
44
+ export default Input
@@ -0,0 +1,10 @@
1
+ import { ChangeEventHandler } from "react";
2
+ import { DataAttributeType, InputType } from "../types";
3
+
4
+ export interface InputPropsType extends Omit<InputType, "type" | "data"> {
5
+ type?: "input";
6
+ data?: DataAttributeType;
7
+ className?: string;
8
+ read_only?: boolean;
9
+ onChange?: ChangeEventHandler<HTMLInputElement>;
10
+ }
@@ -0,0 +1,54 @@
1
+ import React, { useState } from "react"
2
+ import { Link as PageLink } from "gatsby"
3
+ import { LinkPropsType, ExternalLinkPropsType } from "./types"
4
+ import Icon from "../icon"
5
+
6
+ const ExternalLink = ({ animate = true, ...props }: ExternalLinkPropsType) => {
7
+ const [scale, setScale] = useState(1)
8
+
9
+ const setState = (n: number) => {
10
+ if (animate) {
11
+ setScale(n)
12
+ }
13
+ }
14
+
15
+ return (
16
+ <a
17
+ className={props.className}
18
+ onMouseDown={() => setState(0.95)}
19
+ onMouseUp={() => setState(1)}
20
+ onTouchStart={() => setState(0.95)}
21
+ onTouchEnd={() => setState(1)}
22
+ style={{ transform: `scale(${scale})`, transition: "color 0.2s ease, transform 0.2s ease" }}
23
+ title={props.title}
24
+ href={props.to}
25
+ target={props.target}
26
+ onClick={props.onClick}
27
+ >
28
+ {props.children}
29
+ </a>
30
+ )
31
+ }
32
+
33
+ const Link = (props: LinkPropsType) => {
34
+ const LinkTag = props.page_slug ? PageLink : ExternalLink
35
+ let slug = (props.page_slug ? props.page_slug : props.external_link) as string
36
+ if (props.anchor) {
37
+ slug = `${slug}#${props.anchor}`
38
+ }
39
+ return (
40
+ <LinkTag
41
+ className={props.className}
42
+ to={slug}
43
+ title={props.title}
44
+ target={props.target}
45
+ onClick={props.onClick}
46
+ animate={props.animate}
47
+ >
48
+ {!!props.icon && <Icon icon={props.icon} />}
49
+ {props.children ? props.children : props.text}
50
+ </LinkTag>
51
+ )
52
+ }
53
+
54
+ export default Link
@@ -0,0 +1,24 @@
1
+ import { MouseEventHandler } from "react";
2
+ import { DataAttributeType, LinkType } from "../types";
3
+
4
+ export interface LinkPropsType extends Omit<LinkType, "type" | "tag" | "data"> {
5
+ type?: "link";
6
+ tag?: "a";
7
+ className?: string;
8
+ title?: string;
9
+ anchor?: string;
10
+ data?: DataAttributeType;
11
+ onClick?: MouseEventHandler<HTMLAnchorElement>;
12
+ children?: React.ReactNode;
13
+ animate?: boolean;
14
+ }
15
+
16
+ export interface ExternalLinkPropsType {
17
+ className?: string;
18
+ to: string;
19
+ target?: string;
20
+ title?: string;
21
+ onClick?: MouseEventHandler<HTMLAnchorElement>;
22
+ children?: React.ReactNode;
23
+ animate?: boolean;
24
+ }
@@ -0,0 +1,17 @@
1
+ import React from "react"
2
+ import { LinkType } from "../types"
3
+ import { LinkListPropsType } from "./types"
4
+ import Link from "../link"
5
+
6
+ const LinkList = ({ pk, ...props }: LinkListPropsType) => {
7
+ return (
8
+ <ul className={props.className}>
9
+ {props.links.map((link: LinkType, k: number) => (
10
+ <li key={`LinkList${pk}-${k}`}>
11
+ <Link {...link}>{props.children}</Link>
12
+ </li>
13
+ ))}
14
+ </ul>
15
+ )
16
+ }
17
+ export default LinkList
@@ -0,0 +1,6 @@
1
+ import { LinkListType } from "../types";
2
+
3
+ export interface LinkListPropsType extends LinkListType {
4
+ className?: string;
5
+ children?: React.ReactNode;
6
+ }
@@ -0,0 +1,99 @@
1
+ import React, { useEffect, useState } from "react"
2
+ import ReactSelect from "react-select"
3
+ import {
4
+ GroupedOptionsType,
5
+ OptionType,
6
+ OptionsType,
7
+ SelectPropsType,
8
+ } from "./types"
9
+
10
+ /**
11
+ * Transforms the options into the allowed format, which could be either
12
+ *
13
+ * - Normal options:
14
+ * [
15
+ * {label: "option 1", value: "1"},
16
+ * {label: "option 2", value: "2"},
17
+ * ...
18
+ * ]
19
+ *
20
+ * - Grouped options:
21
+ * [
22
+ * {label: "Group 1", options: [{label: "option 1", value: "1"}, {label: "option 2", value: "2"}, ..]},
23
+ * {label: "Group 2", options: [{label: "option 3", value: "3"}, {label: "option 4", value: "4"}, ..]},
24
+ * ...
25
+ * ]
26
+ */
27
+ const formatOptions = (
28
+ options: OptionsType
29
+ ): (OptionType | GroupedOptionsType)[] => {
30
+ if (Array.isArray(options)) {
31
+ return options
32
+ }
33
+ return typeof options[Object.keys(options)[0]] === "string"
34
+ ? Object.entries(options).reduce((acc, [value, label]) => {
35
+ // @ts-ignore
36
+ acc.push({ label: label, value: value })
37
+ return acc
38
+ }, [] as OptionType[])
39
+ : Object.entries(options).reduce((acc, [label, values]) => {
40
+ acc.push({
41
+ label: label,
42
+ options: Object.entries(values).reduce(
43
+ (opts, [k, v]) => [...opts, { label: v, value: k }],
44
+ [] as OptionType[]
45
+ ),
46
+ })
47
+ return acc
48
+ }, [] as GroupedOptionsType[])
49
+ }
50
+
51
+ const getValue = (
52
+ options: (OptionType | GroupedOptionsType)[],
53
+ value: string
54
+ ): any => {
55
+ for (let option of options) {
56
+ if (option.hasOwnProperty("options")) {
57
+ for (let opt of (option as GroupedOptionsType).options) {
58
+ if (value === opt.value) {
59
+ return opt
60
+ }
61
+ }
62
+ return option
63
+ } else if (value === (option as OptionType).value) {
64
+ return option
65
+ }
66
+ }
67
+ return null
68
+ }
69
+
70
+ const Select: React.FC<SelectPropsType> = ({
71
+ value,
72
+ styles,
73
+ options,
74
+ label,
75
+ ...props
76
+ }) => {
77
+ const [show, setShow] = useState<boolean>(false)
78
+ const opts = formatOptions(options) as any
79
+
80
+ useEffect(() => setShow(true), [])
81
+
82
+ return (
83
+ show && (
84
+ <label
85
+ className={"label-" + (props.className ? props.className : props.name)}
86
+ >
87
+ {!!label && <span>{label}</span>}
88
+ <ReactSelect
89
+ options={opts}
90
+ value={typeof value === "string" ? getValue(opts, value) : value}
91
+ styles={styles}
92
+ {...props}
93
+ />
94
+ </label>
95
+ )
96
+ )
97
+ }
98
+
99
+ export default Select
@@ -0,0 +1,24 @@
1
+ import OptionTypeBase, { Props as SelectProps } from "react-select"
2
+
3
+ export interface OptionType {
4
+ label: string
5
+ value: string
6
+ }
7
+ export interface GroupedOptionsType {
8
+ label: string
9
+ options: OptionType[]
10
+ }
11
+
12
+ export type OptionsType =
13
+ | { [key: string]: string | { [key: string]: string } }
14
+ | OptionType[]
15
+ | GroupedOptionsType[]
16
+ export interface SelectPropsType
17
+ extends Omit<SelectProps<OptionTypeBase>, "value" | "options"> {
18
+ className?: string
19
+ name?: string
20
+ value?: OptionType | string | null
21
+ options: OptionsType
22
+ styles?: any
23
+ label?: string
24
+ }
@@ -0,0 +1,8 @@
1
+ import React from "react"
2
+ import { FilePropsType } from "./types"
3
+
4
+ const SVG = (props: FilePropsType) => {
5
+ return <img className={props.className} src={props.file.url} />
6
+ }
7
+
8
+ export default SVG
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import { FileMediaType } from "../types";
3
+
4
+ export interface FilePropsType extends FileMediaType {
5
+ className?: string;
6
+ style?: React.CSSProperties;
7
+ onLoad?: any;
8
+ }
@@ -0,0 +1,14 @@
1
+ import React from "react"
2
+ import { TextPropsType } from "./types"
3
+ import Markdown from "../../markdown"
4
+
5
+
6
+ const Text = (props: TextPropsType) => {
7
+ return (
8
+ <div className={props.className}>
9
+ <Markdown tagAttrs={props.tagAttrs}>{props.text}</Markdown>
10
+ </div>
11
+ )
12
+ }
13
+
14
+ export default Text
@@ -0,0 +1,12 @@
1
+ import { MouseEventHandler } from "react";
2
+ import { DataAttributeType } from "../types";
3
+ import { TagAttributesType } from "../../markdown/types";
4
+
5
+ export interface TextPropsType {
6
+ className?: string;
7
+ text: string;
8
+ type?: "text";
9
+ data?: DataAttributeType;
10
+ onClick?: MouseEventHandler<HTMLAnchorElement>;
11
+ tagAttrs?: TagAttributesType;
12
+ }
@@ -0,0 +1,12 @@
1
+ import React from "react"
2
+
3
+ const TextArea = ({ label, ...props }: any) => {
4
+ return (
5
+ <label className={`textarea label-${props.name}`}>
6
+ {!!label && <span>{label}</span>}
7
+ <textarea {...props} />
8
+ </label>
9
+ )
10
+ }
11
+
12
+ export default TextArea
@@ -0,0 +1,19 @@
1
+ import React, { useMemo } from "react"
2
+ import { TitlePropsType } from "./types"
3
+ import Markdown from "../../markdown"
4
+
5
+ const Title = (props: TitlePropsType) => {
6
+ const data = useMemo(() => {
7
+ return props.title && props.title[0] === "#"
8
+ ? props.title
9
+ : `### ${props.title}`
10
+ }, [props.title])
11
+
12
+ return (
13
+ <Markdown className={props.className} onClick={props.onClick}>
14
+ {data}
15
+ </Markdown>
16
+ )
17
+ }
18
+
19
+ export default Title
@@ -0,0 +1,10 @@
1
+ import { MouseEventHandler } from "react";
2
+ import { DataAttributeType } from "../types";
3
+
4
+ export interface TitlePropsType {
5
+ className?: string;
6
+ title: string;
7
+ type?: "title";
8
+ data?: DataAttributeType;
9
+ onClick?: MouseEventHandler<HTMLDivElement>;
10
+ }