@dtdot/lego 0.18.0 → 0.18.5

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,7 +1,9 @@
1
1
  /// <reference types="react" />
2
2
  import { ColourVariant } from '../../theme/theme.types';
3
+ import { IActionMenuItem } from './_ActionMenu.types';
3
4
  export interface ActionMenuProps {
5
+ items: IActionMenuItem[];
4
6
  variant?: ColourVariant;
5
7
  }
6
- declare const ActionMenu: ({ variant }: ActionMenuProps) => JSX.Element;
8
+ declare const ActionMenu: ({ items, variant }: ActionMenuProps) => JSX.Element;
7
9
  export default ActionMenu;
@@ -1,13 +1,52 @@
1
1
  import { faEllipsisV } from '@fortawesome/free-solid-svg-icons';
2
2
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
- import React from 'react';
3
+ import React, { useCallback, useEffect, useState } from 'react';
4
+ import ReactDOM from 'react-dom';
4
5
  import styled from 'styled-components';
6
+ import { usePopper } from 'react-popper';
5
7
  import Button from '../Button/Button.component';
8
+ import ActionMenuPanel from './_ActionMenuPanel.component';
6
9
  const StyledIcon = styled(FontAwesomeIcon) `
7
10
  font-size: 18px;
8
11
  `;
9
- const ActionMenu = ({ variant }) => {
10
- return (React.createElement(Button, { variant: variant },
11
- React.createElement(StyledIcon, { icon: faEllipsisV })));
12
+ const offsetFn = () => [70, 4];
13
+ const ActionMenu = ({ items, variant }) => {
14
+ const [shown, setShown] = useState(false);
15
+ const [referenceElement, setReferenceElement] = useState();
16
+ const [popperElement, setPopperElement] = useState();
17
+ const { styles, attributes } = usePopper(referenceElement, popperElement, {
18
+ modifiers: [
19
+ {
20
+ name: 'offset',
21
+ options: {
22
+ offset: offsetFn,
23
+ },
24
+ },
25
+ ],
26
+ });
27
+ const handleGlobalClick = useCallback((event) => {
28
+ if (!popperElement?.contains(event.target)) {
29
+ setShown(false);
30
+ }
31
+ }, [setShown, popperElement]);
32
+ useEffect(() => {
33
+ document.addEventListener('mouseup', handleGlobalClick);
34
+ return () => {
35
+ document.removeEventListener('mouseup', handleGlobalClick);
36
+ };
37
+ }, [handleGlobalClick, popperElement]);
38
+ const augmentedItems = items.map((item) => ({
39
+ ...item,
40
+ onClick: () => {
41
+ setShown(false);
42
+ item.onClick();
43
+ },
44
+ }));
45
+ return (React.createElement(React.Fragment, null,
46
+ React.createElement(Button, { variant: variant, ref: setReferenceElement, onClick: () => setShown(true) },
47
+ React.createElement(StyledIcon, { icon: faEllipsisV })),
48
+ shown &&
49
+ ReactDOM.createPortal(React.createElement("div", { ref: setPopperElement, style: styles.popper, ...attributes.popper },
50
+ React.createElement(ActionMenuPanel, { items: augmentedItems })), document.querySelector('body'))));
12
51
  };
13
52
  export default ActionMenu;
@@ -1,15 +1,47 @@
1
1
  import React from 'react';
2
2
  import { ActionMenu } from '../..';
3
3
  /* eslint-disable @typescript-eslint/no-empty-function */
4
- export const Standard = () => React.createElement(ActionMenu, null);
4
+ const items = [
5
+ {
6
+ label: 'Angry Lama',
7
+ onClick: () => {
8
+ console.log('Item 1 clicked');
9
+ },
10
+ },
11
+ {
12
+ label: 'Frightened Frog',
13
+ onClick: () => {
14
+ console.log('Item 2 clicked');
15
+ },
16
+ },
17
+ {
18
+ label: 'Hungry Bear',
19
+ onClick: () => {
20
+ console.log('Item 3 clicked');
21
+ },
22
+ },
23
+ {
24
+ label: 'Crazy Koala',
25
+ onClick: () => {
26
+ console.log('Item 4 clicked');
27
+ },
28
+ },
29
+ {
30
+ label: 'Dizzy Snake',
31
+ onClick: () => {
32
+ console.log('Item 5 clicked');
33
+ },
34
+ },
35
+ ];
36
+ export const Standard = () => React.createElement(ActionMenu, { items: items, variant: 'tertiary' });
5
37
  export const Variants = () => (React.createElement(React.Fragment, null,
6
- React.createElement(ActionMenu, { variant: 'primary' }),
38
+ React.createElement(ActionMenu, { items: items, variant: 'primary' }),
7
39
  React.createElement("br", null),
8
40
  React.createElement("br", null),
9
- React.createElement(ActionMenu, { variant: 'secondary' }),
41
+ React.createElement(ActionMenu, { items: items, variant: 'secondary' }),
10
42
  React.createElement("br", null),
11
43
  React.createElement("br", null),
12
- React.createElement(ActionMenu, { variant: 'tertiary' })));
44
+ React.createElement(ActionMenu, { items: items, variant: 'tertiary' })));
13
45
  export default {
14
46
  title: 'Components/ActionMenu',
15
47
  component: ActionMenu,
@@ -0,0 +1,4 @@
1
+ export interface IActionMenuItem {
2
+ label: string;
3
+ onClick: () => void;
4
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ /// <reference types="react" />
2
+ export interface ActionMenuItemProps {
3
+ label: string;
4
+ onClick: () => void;
5
+ }
6
+ declare const ActionMenuItem: ({ label, onClick }: ActionMenuItemProps) => JSX.Element;
7
+ export default ActionMenuItem;
@@ -0,0 +1,18 @@
1
+ import { motion } from 'framer-motion';
2
+ import React from 'react';
3
+ import styled, { useTheme } from 'styled-components';
4
+ const ActionMenuItemOuter = styled(motion.div) `
5
+ padding: 12px 16px;
6
+ cursor: pointer;
7
+
8
+ color: ${(props) => props.theme.colours.defaultFont};
9
+ font-family: ${(props) => props.theme.fonts.default.family};
10
+ font-size: ${(props) => props.theme.fonts.default.size};
11
+ font-weight: ${(props) => props.theme.fonts.default.weight};
12
+ `;
13
+ const ActionMenuItem = ({ label, onClick }) => {
14
+ const theme = useTheme();
15
+ return (React.createElement(React.Fragment, null,
16
+ React.createElement(ActionMenuItemOuter, { style: { backgroundColor: theme.colours.tertiary.main }, whileHover: { backgroundColor: theme.colours.tertiary.hover }, onClick: onClick }, label)));
17
+ };
18
+ export default ActionMenuItem;
@@ -0,0 +1,7 @@
1
+ /// <reference types="react" />
2
+ import { IActionMenuItem } from './_ActionMenu.types';
3
+ export interface ActionMenuPanelProps {
4
+ items: IActionMenuItem[];
5
+ }
6
+ declare const ActionMenuPanel: ({ items }: ActionMenuPanelProps) => JSX.Element;
7
+ export default ActionMenuPanel;
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import ActionMenuItem from './_ActionMenuItem.component';
4
+ const ActionMenuPanelOuter = styled.div `
5
+ background-color: ${(props) => props.theme.colours.tertiary.main};
6
+ min-width: 160px;
7
+ `;
8
+ const ActionMenuPanel = ({ items }) => (React.createElement(ActionMenuPanelOuter, null, items.map((item) => (React.createElement(ActionMenuItem, { key: item.label, label: item.label, onClick: item.onClick })))));
9
+ export default ActionMenuPanel;
@@ -7,5 +7,5 @@ export interface ButtonProps {
7
7
  type?: 'submit';
8
8
  onClick?: () => void;
9
9
  }
10
- declare const Button: ({ children, loading, variant, type, onClick }: ButtonProps) => JSX.Element;
10
+ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<unknown>>;
11
11
  export default Button;
@@ -53,8 +53,9 @@ const ButtonSpinner = styled.div `
53
53
  animation-iteration-count: infinite;
54
54
  }
55
55
  `;
56
- const Button = ({ children, loading, variant = 'primary', type, onClick }) => {
56
+ const Button = React.forwardRef(function Button(props, ref) {
57
+ const { children, loading, variant = 'primary', type, onClick } = props;
57
58
  const { width, height, alignSelf, marginTop } = useContext(ButtonContext);
58
- return (React.createElement(StyledButton, { width: width, height: height, alignSelf: alignSelf, marginTop: marginTop, variant: variant, type: type, onClick: onClick }, loading ? React.createElement(ButtonSpinner, { variant: variant }) : children));
59
- };
59
+ return (React.createElement(StyledButton, { ref: ref, width: width, height: height, alignSelf: alignSelf, marginTop: marginTop, variant: variant, type: type, onClick: onClick }, loading ? React.createElement(ButtonSpinner, { variant: variant }) : children));
60
+ });
60
61
  export default Button;
@@ -36,10 +36,10 @@ const Checklist = ({ items, value, onChange }) => {
36
36
  .sort((a, b) => checkedOrder.indexOf(a.id) - checkedOrder.indexOf(b.id));
37
37
  const unCheckedItems = items.filter((item) => !value.includes(item.id));
38
38
  return (React.createElement(LayoutGroup, null,
39
- unCheckedItems.map((item) => (React.createElement(motion.div, { layoutId: item.id, key: item.id, transition: { duration: 0.2 } },
39
+ unCheckedItems.map((item) => (React.createElement(motion.div, { layoutId: item.id, key: item.id },
40
40
  React.createElement(ChecklistItem, { label: item.label, value: value.includes(item.id), onChange: (checked) => handleChange(item.id, checked) })))),
41
41
  checkedItems.length ? React.createElement(ListDivider, null) : null,
42
- checkedItems.map((item) => (React.createElement(motion.div, { layoutId: item.id, key: item.id, transition: { duration: 0.2 } },
42
+ checkedItems.map((item) => (React.createElement(motion.div, { layoutId: item.id, key: item.id },
43
43
  React.createElement(ChecklistItem, { label: item.label, value: value.includes(item.id), onChange: (checked) => handleChange(item.id, checked) }))))));
44
44
  };
45
45
  export default Checklist;
@@ -1,3 +1,3 @@
1
- import { DefaultTheme } from 'styled-components';
2
- declare const darkTheme: DefaultTheme;
1
+ import { LegoTheme } from './theme.types';
2
+ declare const darkTheme: LegoTheme;
3
3
  export default darkTheme;
@@ -1,3 +1,3 @@
1
- import { DefaultTheme } from 'styled-components';
2
- declare const defaultTheme: DefaultTheme;
1
+ import { LegoTheme } from './theme.types';
2
+ declare const defaultTheme: LegoTheme;
3
3
  export default defaultTheme;
@@ -1,4 +1,4 @@
1
1
  import { DefaultTheme } from 'styled-components';
2
2
  import { Status } from '../theme.types';
3
- declare const _default: (status: Status, theme: DefaultTheme) => import("../../types/styled").IStatus;
3
+ declare const _default: (status: Status, theme: DefaultTheme) => import("../theme.types").IStatus;
4
4
  export default _default;
@@ -1,2 +1,54 @@
1
1
  export declare type ColourVariant = 'primary' | 'secondary' | 'tertiary';
2
2
  export declare type Status = 'info' | 'success' | 'warn' | 'danger';
3
+ export interface IPalette {
4
+ main: string;
5
+ hover: string;
6
+ contrastText: string;
7
+ }
8
+ export interface IStatus {
9
+ main: string;
10
+ contrast: string;
11
+ }
12
+ export interface IFont {
13
+ family: string;
14
+ size: string;
15
+ weight: string;
16
+ }
17
+ export interface LegoTheme {
18
+ name: string;
19
+ colours: {
20
+ background: string;
21
+ overlayBackground: string;
22
+ primary: IPalette;
23
+ secondary: IPalette;
24
+ tertiary: IPalette;
25
+ defaultFont: string;
26
+ secondaryFont: string;
27
+ secondaryFontHover: string;
28
+ defaultBorder: string;
29
+ faintBorder: string;
30
+ controlBackground: string;
31
+ controlBorder: string;
32
+ controlBorderFocus: string;
33
+ controlBorderHover: string;
34
+ controlPlaceholder: string;
35
+ uploadBackground: string;
36
+ uploadIcon: string;
37
+ cardBackground: string;
38
+ statusInfo: IStatus;
39
+ statusSuccess: IStatus;
40
+ statusWarn: IStatus;
41
+ statusDanger: IStatus;
42
+ };
43
+ fonts: {
44
+ default: IFont;
45
+ heading: IFont;
46
+ subHeading: IFont;
47
+ };
48
+ shadows: {
49
+ small: string;
50
+ medium: string;
51
+ large: string;
52
+ xlarge: string;
53
+ };
54
+ }
@@ -1,5 +1,5 @@
1
1
  declare const themes: {
2
- dark: import("styled-components").DefaultTheme;
3
- default: import("styled-components").DefaultTheme;
2
+ dark: import("./theme.types").LegoTheme;
3
+ default: import("./theme.types").LegoTheme;
4
4
  };
5
5
  export default themes;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dtdot/lego",
3
- "version": "0.18.0",
3
+ "version": "0.18.5",
4
4
  "description": "Some reusable components for building my applications",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
@@ -32,34 +32,36 @@
32
32
  "@types/spark-md5": "^3.0.2",
33
33
  "@types/styled-components": "^5.1.22",
34
34
  "@types/uuid": "^8.3.4",
35
- "@typescript-eslint/eslint-plugin": "^4.33.0",
36
- "@typescript-eslint/parser": "^4.33.0",
35
+ "@typescript-eslint/eslint-plugin": "^5.16.0",
36
+ "@typescript-eslint/parser": "^5.16.0",
37
37
  "babel-loader": "^8.2.3",
38
- "eslint": "^7.32.0",
39
- "eslint-config-prettier": "^7.2.0",
40
- "eslint-plugin-prettier": "^3.4.1",
41
- "eslint-plugin-react": "^7.28.0",
38
+ "eslint": "^8.12.0",
39
+ "eslint-config-prettier": "^8.5.0",
40
+ "eslint-plugin-prettier": "^4.0.0",
41
+ "eslint-plugin-react": "^7.29.4",
42
42
  "eslint-plugin-react-hooks": "^4.3.0",
43
- "prettier": "^2.5.1",
44
- "prettier-eslint": "^12.0.0",
43
+ "prettier": "^2.6.1",
44
+ "prettier-eslint": "^13.0.0",
45
45
  "react": "^17.0.2",
46
46
  "react-dom": "^17.0.2",
47
47
  "storybook-addon-styled-component-theme": "^1.3.0",
48
- "styled-components": "^5.3.3",
48
+ "styled-components": "^5.3.5",
49
49
  "typescript": "^4.5.5"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "react": "^17.0.1",
53
53
  "react-dom": "^17.0.1",
54
- "styled-components": "^5.2.1"
54
+ "styled-components": "^5.3.5"
55
55
  },
56
56
  "dependencies": {
57
57
  "@fortawesome/fontawesome-svg-core": "^1.2.32",
58
58
  "@fortawesome/free-solid-svg-icons": "^5.15.4",
59
59
  "@fortawesome/react-fontawesome": "^0.1.13",
60
+ "@popperjs/core": "^2.11.4",
60
61
  "framer-motion": "^6.2.8",
61
62
  "identicon.js": "^2.3.3",
62
63
  "qrcode": "^1.5.0",
64
+ "react-popper": "^2.2.5",
63
65
  "react-use-measure": "^2.1.1",
64
66
  "spark-md5": "^3.0.2",
65
67
  "uuid": "^8.3.2"