@koine/react 1.0.5 → 1.0.8

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 (159) hide show
  1. package/Alert/Alert.js +18 -0
  2. package/Alert/index.js +1 -0
  3. package/Animations/Reveal.js +17 -0
  4. package/Animations/Underline.js +15 -0
  5. package/Animations/index.js +3 -0
  6. package/Animations/useReveal.js +70 -0
  7. package/Autocomplete/AutocompleteDownshift.js +158 -0
  8. package/Autocomplete/AutocompleteDownshiftMultiselect.js +353 -0
  9. package/Autocomplete/AutocompleteMui.js +172 -0
  10. package/Autocomplete/AutocompleteReach.js +112 -0
  11. package/Autocomplete/components.js +89 -0
  12. package/Autocomplete/helpers.js +28 -0
  13. package/Autocomplete/index.js +3 -0
  14. package/Bg/BgColor.js +33 -0
  15. package/Bg/BgPhoto.js +59 -0
  16. package/Bg/BgSvg.js +15 -0
  17. package/Bg/index.js +3 -0
  18. package/Breadcrumbs/Breadcrumbs.js +70 -0
  19. package/Breadcrumbs/index.js +1 -0
  20. package/Buttons/Button.js +79 -0
  21. package/Buttons/ButtonComposite.d.ts +1 -1
  22. package/Buttons/ButtonComposite.js +53 -0
  23. package/Buttons/ButtonFab.js +8 -0
  24. package/Buttons/ButtonLink.js +16 -0
  25. package/Buttons/IconButton.js +19 -0
  26. package/Buttons/index.js +5 -0
  27. package/Calendar/CalendarDaygridCell.js +52 -0
  28. package/Calendar/CalendarDaygridNav.js +23 -0
  29. package/Calendar/CalendarDaygridTable.js +49 -0
  30. package/Calendar/CalendarLegend.js +12 -0
  31. package/Calendar/calendar-api-google.js +97 -0
  32. package/Calendar/index.js +6 -0
  33. package/Calendar/types.js +1 -0
  34. package/Calendar/useCalendar.js +166 -0
  35. package/Calendar/utils.js +197 -0
  36. package/Carousel/Carousel.js +378 -0
  37. package/Carousel/CarouselCss.js +39 -0
  38. package/Carousel/index.js +1 -0
  39. package/Collapsable/Collapsable.js +132 -0
  40. package/Collapsable/index.js +1 -0
  41. package/Debug/Debug.js +21 -0
  42. package/Debug/index.js +1 -0
  43. package/Dialog/Dialog.js +93 -0
  44. package/Dialog/index.js +1 -0
  45. package/Editor/Editor--tiptap.js +21 -0
  46. package/Editor/components.d.ts +1 -2
  47. package/Editor/components.js +28 -0
  48. package/Editor/index.js +1 -0
  49. package/Favicon/FaviconTags.js +14 -0
  50. package/Favicon/index.js +1 -0
  51. package/Forms/Checkbox/Checkbox.js +24 -0
  52. package/Forms/Checkbox/index.js +1 -0
  53. package/Forms/Feedback/Feedback.js +10 -0
  54. package/Forms/Feedback/index.js +1 -0
  55. package/Forms/Field/Field.js +61 -0
  56. package/Forms/Field/FieldControl.js +45 -0
  57. package/Forms/Field/FieldHint.js +6 -0
  58. package/Forms/Field/index.js +2 -0
  59. package/Forms/Form/Form.js +64 -0
  60. package/Forms/Form/index.js +1 -0
  61. package/Forms/Input/Input.js +25 -0
  62. package/Forms/Input/index.js +1 -0
  63. package/Forms/InputGroup/InputGroup.js +42 -0
  64. package/Forms/InputGroup/index.js +1 -0
  65. package/Forms/Label/Label.js +24 -0
  66. package/Forms/Label/index.js +1 -0
  67. package/Forms/Password/Password.js +32 -0
  68. package/Forms/Password/index.js +1 -0
  69. package/Forms/Radio/Radio.js +31 -0
  70. package/Forms/Radio/index.js +1 -0
  71. package/Forms/Switch/Switch.js +50 -0
  72. package/Forms/Switch/index.js +1 -0
  73. package/Forms/Textarea/Textarea.js +15 -0
  74. package/Forms/Textarea/TextareaRich.js +44 -0
  75. package/Forms/Textarea/index.js +2 -0
  76. package/Forms/Toggle/Toggle.js +79 -0
  77. package/Forms/Toggle/index.js +1 -0
  78. package/Forms/Toggle/useToggle.js +143 -0
  79. package/Forms/antispam.js +56 -0
  80. package/Forms/helpers.js +44 -0
  81. package/Forms/index.js +17 -0
  82. package/Forms/styles.js +60 -0
  83. package/Gauge/Gauge.js +102 -0
  84. package/Grid/Grid.js +79 -0
  85. package/Grid/index.js +1 -0
  86. package/Hamburger/Hamburger.js +55 -0
  87. package/Hamburger/index.js +1 -0
  88. package/Header/index.js +1 -0
  89. package/Header/useHeader.js +30 -0
  90. package/Hidden/Hidden.js +14 -0
  91. package/Hidden/index.js +1 -0
  92. package/Img/Img.js +34 -0
  93. package/Img/index.js +1 -0
  94. package/Link/Link.js +2 -0
  95. package/Link/LinkBlank.d.ts +1 -1
  96. package/Link/LinkBlank.js +28 -0
  97. package/Link/index.js +2 -0
  98. package/Menu/Menu.js +11 -0
  99. package/Menu/index.js +1 -0
  100. package/MenuItem/MenuItem.js +20 -0
  101. package/MenuItem/index.js +1 -0
  102. package/Meta/Meta.js +4 -0
  103. package/Meta/index.js +1 -0
  104. package/NoJs/NoJs.js +6 -0
  105. package/NoJs/index.js +1 -0
  106. package/Pagination/PaginationNav.js +87 -0
  107. package/Pagination/PaginationResults.js +10 -0
  108. package/Pagination/index.js +2 -0
  109. package/Pill/Pill.js +37 -0
  110. package/Pill/index.js +1 -0
  111. package/Progress/ProgressCircular.js +38 -0
  112. package/Progress/ProgressLinear.js +34 -0
  113. package/Progress/ProgressOverlay.js +40 -0
  114. package/Progress/index.js +3 -0
  115. package/Rating/Rating.js +93 -0
  116. package/Rating/index.js +45 -0
  117. package/Select/SelectDownshift.js +38 -0
  118. package/Select/components.js +20 -0
  119. package/Select/index.js +3 -0
  120. package/Sidebar/Sidebar.js +48 -0
  121. package/Sidebar/index.js +1 -0
  122. package/Spacing/Spacing.js +47 -0
  123. package/Spacing/index.js +1 -0
  124. package/Sticky/Sticky.js +220 -0
  125. package/Sticky/StickyCss.js +6 -0
  126. package/Sticky/index.js +1 -0
  127. package/Tabs/Tabs.js +67 -0
  128. package/Tabs/index.js +1 -0
  129. package/Typography/CopyPasteVisible.js +6 -0
  130. package/Typography/Native.js +47 -0
  131. package/Typography/ReadMore.js +71 -0
  132. package/Typography/TextLoop.js +45 -0
  133. package/Typography/TypeStairs.js +46 -0
  134. package/Typography/index.js +5 -0
  135. package/helpers/index.js +19 -0
  136. package/hooks/index.js +5 -0
  137. package/hooks/useDateLocale.js +30 -0
  138. package/hooks/useFocus.js +11 -0
  139. package/hooks/usePrevious.js +8 -0
  140. package/hooks/useTraceUpdate.js +20 -0
  141. package/hooks/useWindowSize.js +13 -0
  142. package/index.js +36 -0
  143. package/index.umd.js +232 -239
  144. package/package.json +15 -9
  145. package/styles/Body.js +17 -0
  146. package/styles/Global.js +50 -0
  147. package/styles/classed.js +11 -0
  148. package/styles/index.js +7 -0
  149. package/styles/media.js +150 -0
  150. package/styles/spacing.d.ts +6 -6
  151. package/styles/spacing.js +46 -0
  152. package/styles/styled.d.ts +2 -2
  153. package/styles/styled.js +27 -0
  154. package/styles/theme--vanilla.js +53 -0
  155. package/styles/theme.d.ts +0 -7
  156. package/styles/theme.js +38 -0
  157. package/types.js +1 -0
  158. package/typings.d.ts +21 -0
  159. package/index.esm.js +0 -9456
@@ -0,0 +1,24 @@
1
+ import styled from "styled-components";
2
+ export const label = `
3
+ display: flex;
4
+ font-size: 13px;
5
+ cursor: pointer;
6
+ `;
7
+ export const labelMaterial = `
8
+ z-index: 2;
9
+ position: relative;
10
+ display: inline-block;
11
+ padding: 0 5px;
12
+ font-weight: 100;
13
+ font-size: 10px;
14
+ background: var(--bodyBg);
15
+ transform: translateY(-0.3em) translateX(1em);
16
+ cursor: pointer;
17
+
18
+ + * {
19
+ margin-top: -1em;
20
+ }
21
+ `;
22
+ export const Label = styled.label `
23
+ ${labelMaterial}
24
+ `;
@@ -0,0 +1 @@
1
+ export * from "./Label";
@@ -0,0 +1,32 @@
1
+ import { __rest } from "tslib";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { forwardRef, useState } from "react";
4
+ import styled from "styled-components";
5
+ import { ImEye as IconVisible, ImEyeBlocked as IconInvisible, } from "react-icons/im";
6
+ import { Label } from "../Label/Label";
7
+ import { InputNative } from "../Input/Input";
8
+ const ICON_WIDTH = "2em";
9
+ const PasswordInputWrap = styled.div `
10
+ position: relative;
11
+ `;
12
+ export const PasswordInputNative = styled(InputNative) `
13
+ position: relative;
14
+ padding-right: ${ICON_WIDTH};
15
+ `;
16
+ const PasswordIcon = styled.span `
17
+ position: absolute;
18
+ top: 0;
19
+ right: 0;
20
+ bottom: 0;
21
+ width: ${ICON_WIDTH};
22
+ display: flex;
23
+ align-items: center;
24
+ justify-content: center;
25
+ cursor: pointer;
26
+ opacity: 0.5;
27
+ `;
28
+ export const Password = forwardRef(function Password(_a, ref) {
29
+ var { register, name, label } = _a, props = __rest(_a, ["register", "name", "label"]);
30
+ const [visible, setVisible] = useState(false);
31
+ return (_jsxs(_Fragment, { children: [label && _jsx(Label, { children: label }), _jsxs(PasswordInputWrap, { children: [_jsx(PasswordInputNative, Object.assign({ type: visible ? "text" : "password", autoComplete: "new-password" }, (register ? register(name) : { name, ref }), props)), _jsx(PasswordIcon, Object.assign({ onClick: () => setVisible((prev) => !prev) }, { children: visible ? _jsx(IconInvisible, {}) : _jsx(IconVisible, {}) }))] })] }));
32
+ });
@@ -0,0 +1 @@
1
+ export * from "./Password";
@@ -0,0 +1,31 @@
1
+ import { __rest } from "tslib";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { forwardRef } from "react";
4
+ import styled from "styled-components";
5
+ import { label } from "../Label/Label";
6
+ import { Toggle, ToggleLabel, ToggleIndicatorSquared } from "../Toggle";
7
+ import { InputInvisible } from "../styles";
8
+ const RadioRoot = styled.div ``;
9
+ const RadioLabel = styled.div `
10
+ ${label}
11
+ `;
12
+ const RadioOptionRoot = styled.label `
13
+ display: flex;
14
+ align-items: center;
15
+ padding: 0.05em;
16
+ cursor: pointer;
17
+ `;
18
+ const RadioToggle = styled(Toggle) ``;
19
+ const RadioIndicator = styled(ToggleIndicatorSquared) ``;
20
+ const RadioOptionLabel = styled(ToggleLabel) ``;
21
+ const RadioOption = forwardRef(function RadioOption(_a, ref) {
22
+ var { register, name, label, $ref } = _a, props = __rest(_a, ["register", "name", "label", "$ref"]);
23
+ const inputProps = register ? register(name) : { name, ref: $ref || ref };
24
+ return (_jsxs(RadioOptionRoot, { children: [_jsxs(RadioToggle, { children: [_jsx(InputInvisible, Object.assign({ type: "radio" }, inputProps, props)), _jsx(RadioIndicator, {})] }), _jsx(RadioOptionLabel, { children: label })] }));
25
+ });
26
+ export const Radio = forwardRef(function Radio(_a, ref) {
27
+ var { label, options } = _a, props = __rest(_a, ["label", "options"]);
28
+ if (!options)
29
+ return null;
30
+ return (_jsxs(RadioRoot, { children: [label && _jsx(RadioLabel, { children: label }), options.map((option, idx) => (_jsx(RadioOption, Object.assign({}, option, props, { "$ref": ref }), idx)))] }));
31
+ });
@@ -0,0 +1 @@
1
+ export * from "./Radio";
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import styled from "styled-components";
4
+ import { CheckboxRoot, CheckboxLabel } from "../Checkbox";
5
+ import { toggleBase } from "../Toggle";
6
+ import { useToggle } from "../Toggle/useToggle";
7
+ import { stateFocus } from "../../styles/styled";
8
+ const SWITCH_GUTTER = 0.25;
9
+ const SWITCH_HANDLE_SIZE = 1;
10
+ export const SwitchTrack = styled.span `
11
+ position: relative;
12
+ width: ${SWITCH_HANDLE_SIZE * 3}em;
13
+ height: ${SWITCH_HANDLE_SIZE * 1.5}em;
14
+ padding: ${SWITCH_GUTTER}em;
15
+ border-radius: ${SWITCH_HANDLE_SIZE}em;
16
+ ${toggleBase}
17
+
18
+ input:focus ~ & {
19
+ ${stateFocus}
20
+ }
21
+
22
+ input:disabled ~ & {
23
+ opacity: 0.5;
24
+ cursor: not-allowed;
25
+ }
26
+ `;
27
+ export const SwitchHandle = styled.span `
28
+ position: absolute;
29
+ width: ${SWITCH_HANDLE_SIZE}em;
30
+ height: ${SWITCH_HANDLE_SIZE}em;
31
+ left: ${SWITCH_GUTTER}em;
32
+ margin-top: -1px;
33
+ /* border: 1px solid currentColor; */
34
+ background: currentColor;
35
+ opacity: 0.5;
36
+ border-radius: 100%;
37
+ transition: all 0.18s ease-in-out;
38
+
39
+ input:checked + ${SwitchTrack} & {
40
+ opacity: 1;
41
+ left: calc(100% - ${SWITCH_HANDLE_SIZE}em - ${SWITCH_GUTTER}em);
42
+ }
43
+ `;
44
+ /**
45
+ * All logic and invisible Inputs come from the `useToggle` hook
46
+ */
47
+ export const Switch = forwardRef(function Switch(props, ref) {
48
+ const { rootProps, Inputs, label } = useToggle(props, ref);
49
+ return (_jsxs(CheckboxRoot, Object.assign({}, rootProps, { children: [Inputs, _jsx(SwitchTrack, { children: _jsx(SwitchHandle, {}) }), label && _jsx(CheckboxLabel, { children: label })] })));
50
+ });
@@ -0,0 +1 @@
1
+ export * from "./Switch";
@@ -0,0 +1,15 @@
1
+ import { __rest } from "tslib";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { forwardRef } from "react";
4
+ import styled from "styled-components";
5
+ import { Label } from "../Label/Label";
6
+ import { inputBase, inputFocus } from "../styles";
7
+ export const TextareaNative = styled.textarea `
8
+ ${inputBase}
9
+ ${inputFocus}
10
+ resize: vertical;
11
+ `;
12
+ export const Textarea = forwardRef(function Textarea(_a, ref) {
13
+ var { register, name, label } = _a, props = __rest(_a, ["register", "name", "label"]);
14
+ return (_jsxs(_Fragment, { children: [label && _jsx(Label, { children: label }), _jsx(TextareaNative, Object.assign({}, (register ? register(name) : { name, ref }), props))] }));
15
+ });
@@ -0,0 +1,44 @@
1
+ import { __rest } from "tslib";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { forwardRef } from "react";
4
+ import styled from "styled-components";
5
+ // import TextareaAutosize from "@mui/base/TextareaAutosize";
6
+ import { Label } from "../Label/Label";
7
+ import { Editor } from "../../Editor";
8
+ import { triggerOnChange } from "../helpers";
9
+ const Root = styled.div `
10
+ .ProseMirror {
11
+ max-height: 160px;
12
+ overflow: auto;
13
+ }
14
+ .EditorContent {
15
+ position: relative;
16
+ &:after {
17
+ position: absolute;
18
+ content: "";
19
+ bottom: 0;
20
+ left: 0;
21
+ right: 16px; /* scrollbar width? */
22
+ height: 3em;
23
+ background: linear-gradient(0deg, white, white 33%, transparent);
24
+ pointer-events: none;
25
+ }
26
+ }
27
+ `;
28
+ export const TextareaRich = forwardRef(function TextareaRich(_a, ref) {
29
+ var { register, setValue, name, label, defaultValue = "", onChange } = _a, props = __rest(_a, ["register", "setValue", "name", "label", "defaultValue", "onChange"]);
30
+ if (register)
31
+ register(name);
32
+ return (_jsxs(Root, { children: [label && _jsx(Label, { children: label }), _jsx(Editor, Object.assign({ options: {
33
+ // element: <TextareaAutosize />,
34
+ content: defaultValue,
35
+ onUpdate: (onChange || setValue) && name
36
+ ? ({ editor }) => {
37
+ const value = editor.getHTML();
38
+ if (setValue)
39
+ setValue(name, value);
40
+ triggerOnChange(onChange, name, value);
41
+ }
42
+ : undefined,
43
+ } }, props))] }));
44
+ });
@@ -0,0 +1,2 @@
1
+ export * from "./Textarea";
2
+ export * from "./TextareaRich";
@@ -0,0 +1,79 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * @file
4
+ *
5
+ * About accessibility:
6
+ * - minimum target size of 44px https://www.w3.org/TR/WCAG21/#target-size
7
+ */
8
+ import styled from "styled-components";
9
+ import { uid } from "@koine/utils";
10
+ import { stateFocus } from "../../styles/styled";
11
+ export const toggleBase = `
12
+ border: 1px solid var(--forms-border-color);
13
+ `;
14
+ export const toggleIndicatorBg = `
15
+ display: inline-block;
16
+ flex-shrink: 0;
17
+ width: 100%;
18
+ height: 100%;
19
+ `;
20
+ export const toggleIndicatorBgShape = `
21
+ ${toggleIndicatorBg}
22
+ fill: none;
23
+ stroke-width: 2px;
24
+ stroke: var(--forms-border-color);
25
+ `;
26
+ export const toggleIndicatorFg = `
27
+ position: absolute;
28
+ left: 0;
29
+ width: 100%;
30
+ height: 100%;
31
+ fill: currentcolor;
32
+ `;
33
+ export const Toggle = styled.span `
34
+ position: relative;
35
+ display: inline-flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ width: 2em;
39
+ height: 2em;
40
+ margin: 0 -0.3em; /* rtl */
41
+ padding: 0.3em;
42
+ `;
43
+ export const ToggleLabel = styled.span `
44
+ margin-left: 0.6em; /* rtl */
45
+ `;
46
+ export const ToggleLabelSub = styled.small `
47
+ opacity: 0.7;
48
+ font-size: 0.7em; ;
49
+ `;
50
+ export const ToggleIndicatorHolder = styled.span `
51
+ position: relative;
52
+ display: flex;
53
+
54
+ input:focus ~ & {
55
+ ${stateFocus}
56
+ }
57
+ `;
58
+ export const ToggleIndicatorBgSquare = styled.svg `
59
+ ${toggleIndicatorBgShape}
60
+ `;
61
+ export const ToggleIndicatorBgCircle = styled.svg `
62
+ ${toggleIndicatorBgShape}
63
+ `;
64
+ export const ToggleIndicatorFg = styled.svg `
65
+ ${toggleIndicatorFg}
66
+ transform: scale(0);
67
+ transition: transform 0.18s ease;
68
+
69
+ input:checked + ${ToggleIndicatorHolder} & {
70
+ transform: scale(1);
71
+ }
72
+ `;
73
+ export const ToggleIndicatorSquared = (props) => {
74
+ return (_jsxs(ToggleIndicatorHolder, { children: [_jsx(ToggleIndicatorBgSquare, Object.assign({ viewBox: "0 0 24 24" }, { children: _jsx("rect", { width: "24", height: "24" }) })), _jsx(ToggleIndicatorFg, Object.assign({ viewBox: "0 0 24 24" }, { children: _jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" }) }))] }));
75
+ };
76
+ export const ToggleIndicatorRounded = ({ r = 6, }) => {
77
+ const id = uid("Toggle");
78
+ return (_jsxs(ToggleIndicatorHolder, { children: [_jsxs(ToggleIndicatorBgCircle, Object.assign({ viewBox: "0 0 24 24" }, { children: [_jsx("circle", { cy: "12", cx: "12", r: "12", id: `r_${id}`, clipPath: `url(#c_${id})` }), _jsx("clipPath", Object.assign({ id: `c_${id}` }, { children: _jsx("use", { xlinkHref: `#r_${id}` }) }))] })), _jsx(ToggleIndicatorFg, Object.assign({ viewBox: "0 0 24 24" }, { children: _jsx("circle", { r: r, cx: "12", cy: "12" }) }))] }));
79
+ };
@@ -0,0 +1 @@
1
+ export * from "./Toggle";
@@ -0,0 +1,143 @@
1
+ import { __rest } from "tslib";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useMemo } from "react";
4
+ import { useWatch } from "react-hook-form";
5
+ import { InputInvisible } from "../styles";
6
+ /**
7
+ * This hook is meant to powere Checkboxes, Switches and checkbox-like Radios
8
+ * components, it works in fact in two modes:
9
+ *
10
+ * 1: behaviour as standard checkbox
11
+ * yup validation would simply look like:
12
+ *
13
+ * ```ts
14
+ * privacy: boolean().required(),
15
+ * // add `.nullable()` if you do not provide a boolean `defaultValue`
16
+ * ```
17
+ *
18
+ * 2: beahviour as two radio for checkbox with custom true/false values as
19
+ * strings yup validation would look like:
20
+ *
21
+ * ```ts
22
+ * newsletter: string().oneOf(["yes", "no"]).required(),
23
+ * // add `.nullable()` if you do not provide a string `defaultValue`
24
+ *
25
+ * // to do not make it required and avoid triggering an error when the input is
26
+ * // untouched you need to set the default value of the input in the form
27
+ * // initialization's `defaultValues` as such:
28
+ *
29
+ * useForm({ defaultValues: { newsletter: "no" }})
30
+ * ```
31
+ *
32
+ * To enable this mode either pass the props `valueTrue` and `valueFalse` or
33
+ * an array of options with the shape of `Option`
34
+ */
35
+ export function useToggle(props, ref) {
36
+ const { name, control, register, label, options, value: propValue } = props, restProps = __rest(props, ["name", "control", "register", "label", "options", "value"]);
37
+ let { id, valueTrue, valueFalse } = restProps,
38
+ // defaultChecked,
39
+ // defaultValue,
40
+ // eslint-disable-next-line prefer-const
41
+ remainingInputProps = __rest(restProps, ["id", "valueTrue", "valueFalse"]);
42
+ // use options data convention to pass on the true/false values
43
+ if (options) {
44
+ valueTrue = options
45
+ .filter((opt) => opt.value === "true")[0]
46
+ .label.toString();
47
+ valueFalse = options
48
+ .filter((opt) => opt.value === "false")[0]
49
+ .label.toString();
50
+ }
51
+ id = `switch-${name}`;
52
+ const idTrue = `${id}-true`;
53
+ const idFalse = `${id}-false`;
54
+ const isRadio = !!(valueTrue && valueFalse);
55
+ // // manage default values for both toggle modes
56
+ // defaultChecked = isUndefined(defaultChecked) ? false : defaultChecked;
57
+ // // TODO: maybe throw an error if the defaultValue that arrives here is not
58
+ // // a valid value
59
+ // defaultValue =
60
+ // defaultValue === valueTrue || defaultValue === valueFalse
61
+ // ? defaultValue
62
+ // : valueFalse;
63
+ // get the value either from the uncontrolled watched input or from the given
64
+ // prop to control the component
65
+ let value = useWatch({
66
+ name,
67
+ control,
68
+ // defaultValue: isRadio ? defaultValue : defaultChecked,
69
+ });
70
+ if (propValue) {
71
+ value = propValue;
72
+ }
73
+ // get the input props needed by react-hook-form, first check if we have
74
+ // a `register` function, then check if we have a `control` object or just
75
+ // rely on the `name` prop and `ref`, they probably would be passed alongside
76
+ // an `onChange` prop that is spreaded on the inputs
77
+ const inputProps = useMemo(() => {
78
+ return register
79
+ ? register(name)
80
+ : control
81
+ ? control.register(name)
82
+ : {
83
+ name,
84
+ ref,
85
+ };
86
+ }, [register, control, name, ref]);
87
+ /**
88
+ * Accessibility.
89
+ *
90
+ * Fake the spacebar keyboard behaviour on the radio mode of the checkbox.
91
+ * Without this *only* the arrow keys would change the checkbox state
92
+ */
93
+ const handleKeyDown = useCallback((event) => {
94
+ if (event.key === " ") {
95
+ event.preventDefault();
96
+ event.stopPropagation();
97
+ const firstInput = event.target;
98
+ const next = firstInput.nextElementSibling;
99
+ const prev = firstInput.previousElementSibling;
100
+ const secondInput = (next === null || next === void 0 ? void 0 : next.tagName) === "INPUT" ? next : prev;
101
+ let target = firstInput;
102
+ if (firstInput.checked) {
103
+ target = secondInput;
104
+ }
105
+ else {
106
+ if (!secondInput.checked) {
107
+ target =
108
+ firstInput.value === valueTrue ? firstInput : secondInput;
109
+ }
110
+ }
111
+ if (target)
112
+ target.click();
113
+ }
114
+ }, [valueTrue]);
115
+ // collect all the return values that are dependent on the current value
116
+ // of the input
117
+ const valueDependentProps = useMemo(() => ({
118
+ rootProps: {
119
+ htmlFor: isRadio
120
+ ? !value || value === valueFalse
121
+ ? idTrue
122
+ : idFalse
123
+ : id,
124
+ },
125
+ label: label ? label : value,
126
+ value,
127
+ }), [value, valueFalse, isRadio, id, idTrue, idFalse, label]);
128
+ const Inputs = useMemo(() => isRadio ? (_jsxs(_Fragment, { children: [_jsx(InputInvisible, Object.assign({ id: idFalse }, inputProps, remainingInputProps, { onKeyDown: handleKeyDown, type: "radio", value: valueFalse })), _jsx(InputInvisible, Object.assign({ id: idTrue }, inputProps, remainingInputProps, { onKeyDown: handleKeyDown, type: "radio", value: valueTrue }))] })) : (_jsx(InputInvisible, Object.assign({ id: id, type: "checkbox" }, inputProps, remainingInputProps))), [
129
+ inputProps,
130
+ remainingInputProps,
131
+ handleKeyDown,
132
+ isRadio,
133
+ idFalse,
134
+ idTrue,
135
+ valueFalse,
136
+ valueTrue,
137
+ id,
138
+ // defaultChecked,
139
+ // defaultValue,
140
+ ]);
141
+ // console.log("useToggle: render", value);
142
+ return Object.assign(Object.assign({}, valueDependentProps), { Inputs });
143
+ }
@@ -0,0 +1,56 @@
1
+ import { object } from "yup";
2
+ import { encode, decode, isUndefined } from "@koine/utils";
3
+ /**
4
+ * Encode form
5
+ *
6
+ * Takes a record of yup validations and outputs a `yup` schema with encoded
7
+ * names (antispam technique) and a record of the encoded/decoded input `name`s.
8
+ *
9
+ * We skip the names prefixed wth an underscore which are considered programmatic
10
+ * form data not created by user input.
11
+ */
12
+ export function encodeForm(validationRules) {
13
+ const encoded = {};
14
+ const encodedNames = {};
15
+ for (const name in validationRules) {
16
+ if (!name.startsWith("_")) {
17
+ const encodedName = encode(name);
18
+ encoded[encodedName] = validationRules[name];
19
+ encodedNames[name] = encodedName;
20
+ }
21
+ }
22
+ // we need `.required()` to correctly infer the type @see
23
+ // https://github.com/jquense/yup/issues/946
24
+ const encodedSchema = object(encoded).required();
25
+ return { encodedSchema, encodedNames };
26
+ }
27
+ /**
28
+ * Decode form data
29
+ *
30
+ * This function is meant to be used inside an api endpoint to gather an encoded
31
+ * form submit data and transform it to the decoded desired json data.
32
+ *
33
+ * Here too we skip encoding/decoding process for names prefixed wth an underscore
34
+ * which are considered programmatic form data not created by user input.
35
+ */
36
+ export function decodeForm(formData) {
37
+ const json = {};
38
+ for (const encodedName in formData) {
39
+ const decodedName = decode(encodedName);
40
+ // always add underscore prefixed names as they are treated as internal
41
+ // private inputs outside of the honeypot system, normalise them here removing
42
+ // the underscore prefix
43
+ if (encodedName.startsWith("_")) {
44
+ // @ts-expect-error nevermind
45
+ json[encodedName.substring(1)] = formData[encodedName];
46
+ }
47
+ // if the decoded `name` is empty and the encoded `name` is defined honeypot passed
48
+ else if (!isUndefined(formData[encodedName]) &&
49
+ formData[decodedName] === "") {
50
+ // @ts-expect-error nevermind
51
+ json[decodedName] = formData[encodedName];
52
+ }
53
+ }
54
+ // console.log(formData, decoded, json);
55
+ return json;
56
+ }
@@ -0,0 +1,44 @@
1
+ import { isString, matchSorter } from "@koine/utils";
2
+ export const normaliseOptions = (options = []) => {
3
+ return options.map((option) => {
4
+ return isString(option)
5
+ ? {
6
+ label: option,
7
+ value: option,
8
+ }
9
+ : option;
10
+ });
11
+ };
12
+ export function defaultOptionsFilterFn(options, inputValue) {
13
+ if (!inputValue) {
14
+ return options;
15
+ }
16
+ return matchSorter(options, inputValue, { keys: ["value", "label"] });
17
+ }
18
+ /**
19
+ * We are faking the native input `onChange` event
20
+ */
21
+ export function triggerOnChange(onChange, name, value) {
22
+ // @ts-expect-error nevermind
23
+ if (onChange)
24
+ onChange({ target: { name, value } });
25
+ }
26
+ /**
27
+ * @see https://hustle.bizongo.in/simulate-react-on-change-on-controlled-components-baa336920e04
28
+ * @deprecated
29
+ */
30
+ export function triggerChange(input, value) {
31
+ const obj = window.Object;
32
+ if (!obj) {
33
+ // if (__DEV__) {
34
+ // console.warn("triggerChange: window.Object does not exists, bailing.");
35
+ // }
36
+ return;
37
+ }
38
+ // @ts-expect-error nevermind
39
+ const nativeInputValueSetter = obj.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
40
+ // @ts-expect-error nevermind
41
+ nativeInputValueSetter.call(input, value);
42
+ const inputEvent = new Event("input", { bubbles: true });
43
+ input.dispatchEvent(inputEvent);
44
+ }
package/Forms/index.js ADDED
@@ -0,0 +1,17 @@
1
+ export * from "./antispam";
2
+ export * from "./Checkbox";
3
+ export * from "./Input";
4
+ export * from "./InputGroup";
5
+ export * from "./Feedback";
6
+ export * from "./Field";
7
+ export * from "./InputGroup";
8
+ export * from "./Form";
9
+ export * from "./Label";
10
+ export * from "./Password";
11
+ export * from "./Radio";
12
+ // export * from "./Select";
13
+ export * from "./Switch";
14
+ export * from "./Textarea";
15
+ export * from "./Toggle";
16
+ export * from "./helpers";
17
+ export * from "./styles";
@@ -0,0 +1,60 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import styled from "styled-components";
3
+ import { stateFocus } from "../styles/styled";
4
+ import { ProgressLinear } from "../Progress/ProgressLinear";
5
+ import { invisible } from "../styles/styled";
6
+ export const InputInvisible = styled.input `
7
+ ${invisible}
8
+ `;
9
+ export const InputHoneypot = styled(InputInvisible).attrs({
10
+ type: "text",
11
+ autoComplete: "new-password",
12
+ tabIndex: -1,
13
+ }) ``;
14
+ export const InputProgress = styled((p) => (_jsx(ProgressLinear, Object.assign({ fg: "var(--accent300)", bg: "var(--accent400)" }, p)))) `
15
+ position: absolute;
16
+ bottom: 0;
17
+ left: 0;
18
+ width: 100%;
19
+ `;
20
+ /**
21
+ * Remove the default light blue background on autofilled inputs. To be used as
22
+ * a function that outputs a CSS string.
23
+ *
24
+ * @see https://stackoverflow.com/a/62624824/1938970
25
+ */
26
+ export const inputResetAutofill = `
27
+ &:-webkit-autofill,
28
+ &:-webkit-autofill:hover,
29
+ &:-webkit-autofill:focus,
30
+ &:-webkit-autofill:active {
31
+ -webkit-background-clip: text;
32
+ }
33
+ `;
34
+ /* FIXME: find a nice way to override this styling from implementation */
35
+ // border-bottom: 1px solid var(--forms-border-color);
36
+ // border: 0;
37
+ export const inputBorder = `
38
+ border: 1px solid var(--forms-border-color);
39
+ `;
40
+ export const inputPadding = `
41
+ padding: var(--forms-gutter-y) var(--forms-gutter-x);
42
+ `;
43
+ export const inputReset = `
44
+ width: 100%;
45
+ min-height: 44px;
46
+ ${inputBorder}
47
+ ${inputPadding}
48
+ `;
49
+ export const inputBase = `
50
+ ${inputReset}
51
+ ${inputResetAutofill}
52
+ background: transparent;
53
+ `;
54
+ export const inputFocus = `
55
+ &:focus {
56
+ outline: 0px;
57
+ appearance: none;
58
+ ${stateFocus}
59
+ }
60
+ `;