@dtdot/lego 1.7.1 → 1.8.1

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.
@@ -1,13 +1,17 @@
1
1
  import React from 'react';
2
+ import { IconProp } from '@fortawesome/fontawesome-svg-core';
2
3
  import { Status } from '../../theme/theme.types';
3
4
  interface BadgeSpanProps {
4
5
  variant: BadgeVariant;
6
+ useHover: boolean;
5
7
  }
6
8
  export declare const BadgeSpan: import("styled-components").StyledComponent<"span", import("styled-components").DefaultTheme, BadgeSpanProps, never>;
7
9
  export type BadgeVariant = Status;
8
10
  export interface BadgeProps {
9
11
  children: React.ReactNode;
10
12
  variant: BadgeVariant;
13
+ actionIcon?: IconProp;
14
+ onAction?: () => void;
11
15
  }
12
- declare const Badge: ({ children, variant }: BadgeProps) => JSX.Element;
16
+ declare const Badge: ({ children, variant, actionIcon, onAction }: BadgeProps) => JSX.Element;
13
17
  export default Badge;
@@ -1,3 +1,4 @@
1
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
1
2
  import React from 'react';
2
3
  import styled from 'styled-components';
3
4
  import getThemeStatusColour from '../../theme/helpers/getThemeStatusColour';
@@ -11,10 +12,27 @@ export const BadgeSpan = styled.span `
11
12
  font-family: ${(props) => props.theme.fonts.default.family};
12
13
  font-size: ${(props) => props.theme.fonts.default.size};
13
14
  font-weight: ${(props) => props.theme.fonts.default.weight};
15
+ line-height: ${(props) => props.theme.fonts.default.size};
14
16
 
15
17
  text-transform: lowercase;
18
+
19
+ &:hover {
20
+ background-color: ${(props) => props.useHover && getThemeStatusColour(props.variant, props.theme).hover};
21
+ }
22
+ `;
23
+ const ActionSpan = styled.span `
24
+ vertical-align: middle;
25
+ padding: 3px 7px;
26
+ margin: -3px -7px -3px 0;
27
+ cursor: pointer;
28
+ user-select: none;
29
+
30
+ font-size: ${(props) => props.theme.fonts.default.size};
16
31
  `;
17
- const Badge = ({ children, variant }) => {
18
- return (React.createElement(BadgeSpan, { variant: variant, "data-cy": 'badge' }, children));
32
+ const Badge = ({ children, variant, actionIcon, onAction }) => {
33
+ return (React.createElement(BadgeSpan, { variant: variant, useHover: !!actionIcon, "data-cy": 'badge' },
34
+ children,
35
+ actionIcon && (React.createElement(ActionSpan, { onClick: onAction },
36
+ React.createElement(FontAwesomeIcon, { icon: actionIcon })))));
19
37
  };
20
38
  export default Badge;
@@ -24,6 +24,6 @@ const BadgeSelector = ({ options, value, onChange }) => {
24
24
  const handleClick = (_value) => {
25
25
  onChange([_value]);
26
26
  };
27
- return (React.createElement(BadgeSelectorOuter, { "data-cy": 'badge-selector' }, options.map((option) => (React.createElement(InteractiveBadge, { key: option.value, variant: option.variant, inactive: !value.includes(option.value), onClick: () => handleClick(option.value), "data-cy": value.includes(option.value) ? 'badge-selected' : 'badge' }, option.name)))));
27
+ return (React.createElement(BadgeSelectorOuter, { "data-cy": 'badge-selector' }, options.map((option) => (React.createElement(InteractiveBadge, { useHover: false, key: option.value, variant: option.variant, inactive: !value.includes(option.value), onClick: () => handleClick(option.value), "data-cy": value.includes(option.value) ? 'badge-selected' : 'badge' }, option.name)))));
28
28
  };
29
29
  export default BadgeSelector;
@@ -1,6 +1,4 @@
1
1
  import React from 'react';
2
- export declare const INPUT_HEIGHT = 48;
3
- export declare const InputStyles: import("styled-components").FlattenInterpolation<import("styled-components").ThemeProps<import("styled-components").DefaultTheme>>;
4
2
  export interface IInputProps {
5
3
  'name'?: string;
6
4
  'label'?: string;
@@ -3,75 +3,19 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
3
  import React, { useState } from 'react';
4
4
  import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
5
5
  import { motion } from 'framer-motion';
6
- import styled, { css } from 'styled-components';
7
- import getThemeControlColours from '../../theme/helpers/getThemeControlColours';
6
+ import styled from 'styled-components';
7
+ import ControlDescription from '../../shared/ControlDescription';
8
+ import ControlLabel from '../../shared/ControlLabel';
9
+ import { ControlStyles } from '../../shared/ControlStyles';
8
10
  import useFormNode, { getValue } from '../Form/useFormNode.hook';
9
- export const INPUT_HEIGHT = 48;
10
11
  const InputContainer = styled.div `
11
12
  position: relative;
12
13
  margin: 2px 0;
13
14
 
14
15
  background-color: ${(props) => props.theme.colours.controlBackground};
15
16
  `;
16
- const InputLabel = styled.label `
17
- display: block;
18
- padding-bottom: 8px;
19
-
20
- color: ${(props) => getThemeControlColours(props.theme).font};
21
- font-family: ${(props) => props.theme.fonts.default.family};
22
- font-size: ${(props) => props.theme.fonts.default.size};
23
- `;
24
- const InputDescription = styled.div `
25
- color: ${(props) => props.theme.colours.controlDescriptionColour};
26
- font-family: ${(props) => props.theme.fonts.emphasis.family};
27
- font-size: ${(props) => props.theme.fonts.emphasis.size};
28
- font-weight: ${(props) => props.theme.fonts.emphasis.weight};
29
- line-height: 18px;
30
-
31
- padding-top: 4px;
32
- padding-bottom: 6px;
33
- font-style: italic;
34
- `;
35
- export const InputStyles = css `
36
- outline: none;
37
- box-shadow: none;
38
-
39
- width: 100%;
40
- height: ${INPUT_HEIGHT}px;
41
- padding: 0 12px;
42
- scroll-margin-bottom: 100px;
43
-
44
- font-family: ${(props) => props.theme.fonts.default.family};
45
- font-size: ${(props) => props.theme.fonts.default.size};
46
-
47
- color: ${(props) => getThemeControlColours(props.theme).font};
48
- background-color: ${(props) => getThemeControlColours(props.theme).background};
49
-
50
- border: 1px solid ${(props) => getThemeControlColours(props.theme).border};
51
- border-radius: 2px;
52
-
53
- &:hover {
54
- border: 1px solid ${(props) => getThemeControlColours(props.theme).borderHover};
55
- }
56
-
57
- &:focus {
58
- border: 1px solid ${(props) => getThemeControlColours(props.theme).borderFocus};
59
- }
60
-
61
- &::placeholder {
62
- color: ${(props) => getThemeControlColours(props.theme).placeholder};
63
- }
64
-
65
- &:disabled {
66
- color: ${(props) => getThemeControlColours(props.theme).font};
67
- opacity: 1;
68
- -webkit-text-fill-color: ${(props) => getThemeControlColours(props.theme).font};
69
- background-color: ${(props) => props.theme.colours.controlBackgroundDisabled};
70
- border: none;
71
- }
72
- `;
73
17
  const StyledInput = styled(motion.input) `
74
- ${InputStyles}
18
+ ${ControlStyles}
75
19
  `;
76
20
  const ErrorMessage = styled(motion.div) `
77
21
  position: absolute;
@@ -145,14 +89,14 @@ const Input = React.forwardRef(function ForwardRefInput(props, ref) {
145
89
  };
146
90
  const animationVariant = error ? (isFocused ? 'errorFocus' : 'error') : undefined;
147
91
  return (React.createElement("div", null,
148
- label && React.createElement(InputLabel, { htmlFor: name }, label),
92
+ label && React.createElement(ControlLabel, { htmlFor: name }, label),
149
93
  React.createElement(InputContainer, { "data-cy": dataCy },
150
94
  React.createElement(StyledInput, { ref: ref, animate: animationVariant, variants: inputVariants, transition: { type: 'spring', duration: 0.3 }, type: type, name: name, placeholder: placeholder, disabled: disabled, value: getValue(value, contextValue), onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, autoFocus: autoFocus, "data-cy": 'input' }),
151
95
  React.createElement(ErrorContainer, { animate: error ? 'show' : undefined, style: { opacity: 0 }, variants: errorVariants, transition: { type: 'spring', duration: 0.3 }, "data-cy": 'error-indicator' },
152
96
  React.createElement(ErrorInner, null,
153
97
  React.createElement(FontAwesomeIcon, { icon: faExclamationCircle }))),
154
98
  error && (React.createElement(ErrorMessage, { style: { opacity: 0, y: 0 }, animate: animationVariant, variants: messageVariants, transition: { type: 'spring', duration: 0.3 }, "data-cy": 'error-message' }, error))),
155
- splitDescription && (React.createElement(InputDescription, null, splitDescription.map((line, index) => (React.createElement(React.Fragment, null,
99
+ splitDescription && (React.createElement(ControlDescription, null, splitDescription.map((line, index) => (React.createElement(React.Fragment, null,
156
100
  index !== 0 && React.createElement("br", null),
157
101
  line)))))));
158
102
  });
@@ -0,0 +1,17 @@
1
+ /// <reference types="react" />
2
+ export type SelectOption = {
3
+ value: string;
4
+ label: string;
5
+ };
6
+ export interface ISelectProps {
7
+ 'name'?: string;
8
+ 'label'?: string;
9
+ 'description'?: string;
10
+ 'placeholder'?: string;
11
+ 'value'?: string;
12
+ 'onChange'?: (value: any) => void;
13
+ 'data-cy'?: string;
14
+ 'options': SelectOption[];
15
+ }
16
+ declare const Select: (props: ISelectProps) => JSX.Element;
17
+ export default Select;
@@ -0,0 +1,86 @@
1
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
2
+ import React, { useState } from 'react';
3
+ import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons';
4
+ import { motion } from 'framer-motion';
5
+ import styled, { useTheme } from 'styled-components';
6
+ import ControlDescription from '../../shared/ControlDescription';
7
+ import ControlLabel from '../../shared/ControlLabel';
8
+ import { ControlStyles } from '../../shared/ControlStyles';
9
+ import getThemeControlColours from '../../theme/helpers/getThemeControlColours';
10
+ import useFormNode, { getValue } from '../Form/useFormNode.hook';
11
+ const ControlOuter = styled.div `
12
+ position: relative;
13
+ `;
14
+ const SelectControl = styled.div `
15
+ ${ControlStyles}
16
+ cursor: pointer;
17
+ `;
18
+ const TextContainer = styled.div `
19
+ display: flex;
20
+ align-items: center;
21
+ height: 100%;
22
+ `;
23
+ const IconContainer = styled.div `
24
+ position: absolute;
25
+ right: 0;
26
+ top: 0;
27
+ height: 48px;
28
+ padding: 0 16px;
29
+ display: flex;
30
+ align-items: center;
31
+ `;
32
+ const PlaceholderText = styled.div `
33
+ color: ${(props) => getThemeControlColours(props.theme).placeholder};
34
+ `;
35
+ const ValueText = styled.div `
36
+ color: ${(props) => getThemeControlColours(props.theme).font};
37
+ `;
38
+ const OptionsContainer = styled.div `
39
+ width: 100%;
40
+ position: absolute;
41
+ background-color: ${(props) => props.theme.colours.controlBackground};
42
+ z-index: 10000;
43
+
44
+ box-shadow: ${(props) => props.theme.shadows.small};
45
+ `;
46
+ const Option = styled(motion.div) `
47
+ color: ${(props) => getThemeControlColours(props.theme).font};
48
+ background-color: ${(props) => props.theme.colours.controlBackgroundDisabled};
49
+ height: 36px;
50
+ display: flex;
51
+ align-items: center;
52
+ padding: 0 12px;
53
+ cursor: pointer;
54
+ `;
55
+ const Select = (props) => {
56
+ const theme = useTheme();
57
+ const [isOpen, setIsOpen] = useState(false);
58
+ const { label, name, description, placeholder, 'value': propsValue, 'data-cy': dataCy, options } = props;
59
+ const { value: contextValue, onChange: contextOnChange } = useFormNode(name);
60
+ const value = getValue(propsValue, contextValue);
61
+ const splitDescription = description ? description.split('\\n').map((str) => str.trim()) : undefined;
62
+ const selectValue = (option) => {
63
+ setIsOpen(false);
64
+ if (contextOnChange) {
65
+ contextOnChange(option.value);
66
+ }
67
+ if (props.onChange) {
68
+ props.onChange(option.value);
69
+ }
70
+ };
71
+ const valueLabel = value && options.find((o) => o.value === value)?.label;
72
+ return (React.createElement("div", null,
73
+ label && React.createElement(ControlLabel, { htmlFor: name }, label),
74
+ React.createElement(ControlOuter, null,
75
+ React.createElement(SelectControl, { "data-cy": dataCy, onClick: () => setIsOpen(!isOpen) },
76
+ React.createElement(TextContainer, null,
77
+ !value && placeholder && React.createElement(PlaceholderText, null, placeholder),
78
+ value && React.createElement(ValueText, null, valueLabel)),
79
+ React.createElement(IconContainer, null,
80
+ React.createElement(FontAwesomeIcon, { icon: isOpen ? faChevronUp : faChevronDown }))),
81
+ isOpen && (React.createElement(OptionsContainer, null, options.map((option) => (React.createElement(Option, { whileHover: { backgroundColor: theme.colours.controlBorder }, transition: { type: 'spring', duration: 0.2 }, key: option.value, onClick: () => selectValue(option) }, option.label)))))),
82
+ splitDescription && (React.createElement(ControlDescription, null, splitDescription.map((line, index) => (React.createElement(React.Fragment, null,
83
+ index !== 0 && React.createElement("br", null),
84
+ line)))))));
85
+ };
86
+ export default Select;
@@ -4,9 +4,9 @@ import React, { useState } from 'react';
4
4
  import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
5
5
  import { motion } from 'framer-motion';
6
6
  import styled from 'styled-components';
7
+ import { ControlStyles } from '../../shared/ControlStyles';
7
8
  import getThemeControlColours from '../../theme/helpers/getThemeControlColours';
8
9
  import useFormNode, { getValue } from '../Form/useFormNode.hook';
9
- import { InputStyles } from '../Input/Input.component';
10
10
  const TextAreaContainer = styled.div `
11
11
  position: relative;
12
12
  `;
@@ -19,7 +19,7 @@ const TextAreaLabel = styled.label `
19
19
  font-size: ${(props) => props.theme.fonts.default.size};
20
20
  `;
21
21
  const StyledTextArea = styled(motion.textarea) `
22
- ${InputStyles}
22
+ ${ControlStyles}
23
23
  height: initial;
24
24
  width: 100% !important;
25
25
  min-height: 144px;
package/build/index.d.ts CHANGED
@@ -31,6 +31,7 @@ export { default as Modal } from './components/Modal/Modal.component';
31
31
  export { default as PageHeader } from './components/PageHeader/PageHeader.component';
32
32
  export { default as ProfileImage } from './components/ProfileImage/ProfileImage.component';
33
33
  export { default as QrCode } from './components/QrCode/QrCode.component';
34
+ export { default as Select } from './components/Select/Select.component';
34
35
  export { default as Spacer } from './components/Spacer/Spacer.component';
35
36
  export { default as SquareButton } from './components/SquareButton/SquareButton.component';
36
37
  export { default as Swimlane } from './components/Swimlane/Swimlane.component';
package/build/index.js CHANGED
@@ -31,6 +31,7 @@ export { default as Modal } from './components/Modal/Modal.component';
31
31
  export { default as PageHeader } from './components/PageHeader/PageHeader.component';
32
32
  export { default as ProfileImage } from './components/ProfileImage/ProfileImage.component';
33
33
  export { default as QrCode } from './components/QrCode/QrCode.component';
34
+ export { default as Select } from './components/Select/Select.component';
34
35
  export { default as Spacer } from './components/Spacer/Spacer.component';
35
36
  export { default as SquareButton } from './components/SquareButton/SquareButton.component';
36
37
  export { default as Swimlane } from './components/Swimlane/Swimlane.component';
@@ -0,0 +1,2 @@
1
+ declare const ControlDescription: import("styled-components").StyledComponent<"div", import("styled-components").DefaultTheme, {}, never>;
2
+ export default ControlDescription;
@@ -0,0 +1,13 @@
1
+ import styled from 'styled-components';
2
+ const ControlDescription = styled.div `
3
+ color: ${(props) => props.theme.colours.controlDescriptionColour};
4
+ font-family: ${(props) => props.theme.fonts.emphasis.family};
5
+ font-size: ${(props) => props.theme.fonts.emphasis.size};
6
+ font-weight: ${(props) => props.theme.fonts.emphasis.weight};
7
+ line-height: 18px;
8
+
9
+ padding-top: 4px;
10
+ padding-bottom: 6px;
11
+ font-style: italic;
12
+ `;
13
+ export default ControlDescription;
@@ -0,0 +1,2 @@
1
+ declare const ControlLabel: import("styled-components").StyledComponent<"label", import("styled-components").DefaultTheme, {}, never>;
2
+ export default ControlLabel;
@@ -0,0 +1,11 @@
1
+ import styled from 'styled-components';
2
+ import getThemeControlColours from '../theme/helpers/getThemeControlColours';
3
+ const ControlLabel = styled.label `
4
+ display: block;
5
+ padding-bottom: 8px;
6
+
7
+ color: ${(props) => getThemeControlColours(props.theme).font};
8
+ font-family: ${(props) => props.theme.fonts.default.family};
9
+ font-size: ${(props) => props.theme.fonts.default.size};
10
+ `;
11
+ export default ControlLabel;
@@ -0,0 +1,2 @@
1
+ export declare const CONTROL_HEIGHT = 48;
2
+ export declare const ControlStyles: import("styled-components").FlattenInterpolation<import("styled-components").ThemeProps<import("styled-components").DefaultTheme>>;
@@ -0,0 +1,41 @@
1
+ import { css } from 'styled-components';
2
+ import getThemeControlColours from '../theme/helpers/getThemeControlColours';
3
+ export const CONTROL_HEIGHT = 48;
4
+ export const ControlStyles = css `
5
+ outline: none;
6
+ box-shadow: none;
7
+
8
+ width: 100%;
9
+ height: ${CONTROL_HEIGHT}px;
10
+ padding: 0 12px;
11
+ scroll-margin-bottom: 100px;
12
+
13
+ font-family: ${(props) => props.theme.fonts.default.family};
14
+ font-size: ${(props) => props.theme.fonts.default.size};
15
+
16
+ color: ${(props) => getThemeControlColours(props.theme).font};
17
+ background-color: ${(props) => getThemeControlColours(props.theme).background};
18
+
19
+ border: 1px solid ${(props) => getThemeControlColours(props.theme).border};
20
+ border-radius: 2px;
21
+
22
+ &:hover {
23
+ border: 1px solid ${(props) => getThemeControlColours(props.theme).borderHover};
24
+ }
25
+
26
+ &:focus {
27
+ border: 1px solid ${(props) => getThemeControlColours(props.theme).borderFocus};
28
+ }
29
+
30
+ &::placeholder {
31
+ color: ${(props) => getThemeControlColours(props.theme).placeholder};
32
+ }
33
+
34
+ &:disabled {
35
+ color: ${(props) => getThemeControlColours(props.theme).font};
36
+ opacity: 1;
37
+ -webkit-text-fill-color: ${(props) => getThemeControlColours(props.theme).font};
38
+ background-color: ${(props) => props.theme.colours.controlBackgroundDisabled};
39
+ border: none;
40
+ }
41
+ `;
@@ -38,21 +38,25 @@ const darkTheme = {
38
38
  main: '#83bfff',
39
39
  contrast: '#191919',
40
40
  dull: '#0070e8',
41
+ hover: '#8fc5ff',
41
42
  },
42
43
  statusSuccess: {
43
44
  main: '#8ddaa9',
44
45
  contrast: '#191919',
45
46
  dull: '#35a35d',
47
+ hover: '#98deb2',
46
48
  },
47
49
  statusWarn: {
48
50
  main: '#f1a374',
49
51
  contrast: '#191919',
50
52
  dull: '#c35514',
53
+ hover: '#f2ac82',
51
54
  },
52
55
  statusDanger: {
53
56
  main: '#e87a7a',
54
57
  contrast: '#191919',
55
58
  dull: '#b51f1f',
59
+ hover: '#ea8787',
56
60
  },
57
61
  },
58
62
  fonts: {
@@ -39,21 +39,25 @@ const defaultTheme = {
39
39
  main: colours.blue,
40
40
  contrast: colours.blue,
41
41
  dull: colours.blue,
42
+ hover: colours.blue,
42
43
  },
43
44
  statusSuccess: {
44
45
  main: colours.green,
45
46
  contrast: colours.green,
46
47
  dull: colours.green,
48
+ hover: colours.green,
47
49
  },
48
50
  statusWarn: {
49
51
  main: colours.yellow,
50
52
  contrast: colours.yellow,
51
53
  dull: colours.yellow,
54
+ hover: colours.yellow,
52
55
  },
53
56
  statusDanger: {
54
57
  main: colours.red,
55
58
  contrast: colours.red,
56
59
  dull: colours.red,
60
+ hover: colours.red,
57
61
  },
58
62
  },
59
63
  fonts: {
@@ -9,6 +9,7 @@ export interface IStatus {
9
9
  main: string;
10
10
  contrast: string;
11
11
  dull: string;
12
+ hover: string;
12
13
  }
13
14
  export interface IFont {
14
15
  family: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dtdot/lego",
3
- "version": "1.7.1",
3
+ "version": "1.8.1",
4
4
  "description": "Some reusable components for building my applications",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
@@ -62,11 +62,11 @@
62
62
  "@fortawesome/fontawesome-svg-core": "^6.2.1",
63
63
  "@fortawesome/free-solid-svg-icons": "^6.2.1",
64
64
  "@fortawesome/react-fontawesome": "^0.2.0",
65
- "@popperjs/core": "^2.11.6",
65
+ "@popperjs/core": "^2.11.7",
66
66
  "framer-motion": "^8.0.2",
67
67
  "identicon.js": "^2.3.3",
68
68
  "qrcode": "^1.5.1",
69
- "react-popper": "^2.2.5",
69
+ "react-popper": "^2.3.0",
70
70
  "react-use-measure": "^2.1.1",
71
71
  "spark-md5": "^3.0.2",
72
72
  "uuid": "^9.0.0"