polpo 0.1.0 → 0.1.2

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 (128) hide show
  1. package/.storybook/theme.ts +2 -2
  2. package/.turbo/turbo-build.log +0 -77
  3. package/.turbo/turbo-lint.log +1 -1
  4. package/README.md +2 -5
  5. package/dist/chunk-CFYQBHH5.js +3 -0
  6. package/dist/chunk-CFYQBHH5.js.map +1 -0
  7. package/dist/chunk-MAWW6AA7.js +3 -0
  8. package/dist/chunk-MAWW6AA7.js.map +1 -0
  9. package/dist/get-modal-position-drle0OjP.d.cts +49 -0
  10. package/dist/get-modal-position-drle0OjP.d.ts +49 -0
  11. package/dist/helpers.cjs +1 -1
  12. package/dist/helpers.cjs.map +1 -1
  13. package/dist/helpers.d.cts +9 -2
  14. package/dist/helpers.d.ts +9 -2
  15. package/dist/helpers.js +1 -1
  16. package/dist/hooks.cjs +1 -1
  17. package/dist/hooks.cjs.map +1 -1
  18. package/dist/hooks.d.cts +59 -21
  19. package/dist/hooks.d.ts +59 -21
  20. package/dist/hooks.js +1 -1
  21. package/dist/ui.cjs +601 -389
  22. package/dist/ui.cjs.map +1 -1
  23. package/dist/ui.d.cts +97 -77
  24. package/dist/ui.d.ts +97 -77
  25. package/dist/ui.js +585 -373
  26. package/dist/ui.js.map +1 -1
  27. package/dist/use-modal-in-container-DiNW1PE_.d.cts +34 -0
  28. package/dist/use-modal-in-container-neGo-kMk.d.ts +34 -0
  29. package/package.json +5 -5
  30. package/src/components/buttons/button/button.stories.tsx +4 -4
  31. package/src/components/buttons/button/button.style.ts +10 -5
  32. package/src/components/buttons/button/button.tsx +7 -19
  33. package/src/components/cards/flip-card/flip-card.tsx +1 -1
  34. package/src/components/cursor/cursor.stories.tsx +35 -0
  35. package/src/components/cursor/cursor.style.ts +73 -0
  36. package/src/components/cursor/cursor.tsx +49 -0
  37. package/src/components/cursor/index.ts +1 -0
  38. package/src/components/form/checkbox/checkbox.stories.tsx +51 -0
  39. package/src/components/form/checkbox/checkbox.style.ts +73 -37
  40. package/src/components/form/checkbox/checkbox.tsx +38 -4
  41. package/src/components/form/field/field.stories.tsx +5 -1
  42. package/src/components/form/field/field.style.ts +12 -0
  43. package/src/components/form/field/field.tsx +3 -1
  44. package/src/components/form/field/field.types.ts +6 -0
  45. package/src/components/form/input-color/input-color.style.ts +5 -4
  46. package/src/components/form/input-color/input-color.tsx +41 -44
  47. package/src/components/form/radio/radio.stories.tsx +29 -5
  48. package/src/components/form/radio/radio.style.ts +45 -24
  49. package/src/components/form/radio/radio.tsx +22 -3
  50. package/src/components/form/select/options.tsx +119 -67
  51. package/src/components/form/select/select.stories.tsx +103 -42
  52. package/src/components/form/select/select.style.ts +10 -92
  53. package/src/components/form/select/select.tsx +19 -42
  54. package/src/components/form/select/select.types.ts +4 -21
  55. package/src/components/form/slider/slider.style.ts +2 -0
  56. package/src/components/icon/icons/social.tsx +17 -1
  57. package/src/components/index.ts +1 -0
  58. package/src/components/infinity-scroll/infinity-scroll.tsx +1 -1
  59. package/src/components/line/line.stories.tsx +3 -4
  60. package/src/components/modals/action-modal/action-modal.stories.tsx +58 -39
  61. package/src/components/modals/action-modal/action-modal.style.ts +13 -25
  62. package/src/components/modals/action-modal/action-modal.tsx +68 -70
  63. package/src/components/modals/aside-modal/aside-modal.stories.tsx +11 -15
  64. package/src/components/modals/aside-modal/aside-modal.style.ts +17 -37
  65. package/src/components/modals/aside-modal/aside-modal.tsx +41 -43
  66. package/src/components/modals/confirmation-modal/confirmation-modal.stories.tsx +21 -9
  67. package/src/components/modals/index.ts +2 -0
  68. package/src/components/modals/menu/index.ts +1 -0
  69. package/src/components/modals/menu/menu.stories.tsx +69 -0
  70. package/src/components/modals/menu/menu.style.ts +62 -0
  71. package/src/components/modals/menu/menu.tsx +142 -0
  72. package/src/components/modals/modal/backdrop.tsx +70 -0
  73. package/src/components/modals/modal/index.ts +1 -0
  74. package/src/components/modals/modal/modal.stories.tsx +325 -0
  75. package/src/components/modals/modal/modal.style.ts +62 -2
  76. package/src/components/modals/modal/modal.tsx +82 -123
  77. package/src/components/modals/portal/index.ts +1 -0
  78. package/src/components/modals/portal/portal.tsx +18 -0
  79. package/src/components/tabs/tabs-list.tsx +13 -10
  80. package/src/components/tabs/tabs.style.ts +48 -43
  81. package/src/components/tag/tag.stories.tsx +11 -12
  82. package/src/components/tag/tag.style.ts +9 -4
  83. package/src/components/tag/tag.tsx +2 -12
  84. package/src/components/tooltips/tooltip/tooltip.stories.tsx +5 -2
  85. package/src/components/tooltips/tooltip/tooltip.style.ts +37 -6
  86. package/src/components/tooltips/tooltip/tooltip.tsx +33 -19
  87. package/src/components/typography/typography.stories.tsx +3 -1
  88. package/src/components/typography/typography.tsx +21 -0
  89. package/src/contexts/theme-context/theme.animations.ts +91 -2
  90. package/src/contexts/theme-context/theme.defaults.ts +1 -1
  91. package/src/core/http-client.ts +49 -47
  92. package/src/core/variants/color.ts +3 -30
  93. package/src/core/variants/radius.ts +12 -41
  94. package/src/core/variants/size.ts +8 -33
  95. package/src/helpers/get-modal-position-relative-to-screen.ts +86 -0
  96. package/src/helpers/get-modal-position.ts +173 -28
  97. package/src/helpers/index.ts +1 -0
  98. package/src/hooks/index.ts +9 -3
  99. package/src/hooks/use-click-outside.ts +32 -0
  100. package/src/hooks/use-cookie.ts +124 -0
  101. package/src/hooks/use-dimensions.ts +11 -14
  102. package/src/hooks/use-dom-container.ts +32 -0
  103. package/src/hooks/use-event-listener.ts +4 -4
  104. package/src/hooks/use-geolocation.ts +63 -0
  105. package/src/hooks/use-in-view.ts +9 -11
  106. package/src/hooks/use-intersection-observer.ts +19 -0
  107. package/src/hooks/use-modal-in-container.ts +60 -52
  108. package/src/hooks/use-modal-transition.ts +54 -0
  109. package/src/hooks/use-modal.ts +21 -0
  110. package/src/hooks/use-mouse-position.ts +55 -7
  111. package/src/hooks/use-resize-observer.ts +18 -0
  112. package/src/stories/GettingStarted.mdx +2 -6
  113. package/svg/Name=npm, Category=social.svg +3 -0
  114. package/tsconfig.json +1 -0
  115. package/vite.config.ts +1 -0
  116. package/.turbo/daemon/f5c5c8fb195b01d0-turbo.log.2024-05-26 +0 -0
  117. package/.turbo/turbo-build$colon$watch.log +0 -96
  118. package/.turbo/turbo-build-storybook.log +0 -0
  119. package/.turbo/turbo-lint$colon$fix.log +0 -2
  120. package/dist/chunk-M4KRSYE7.js +0 -3
  121. package/dist/chunk-M4KRSYE7.js.map +0 -1
  122. package/dist/chunk-U5XSMSKZ.js +0 -3
  123. package/dist/chunk-U5XSMSKZ.js.map +0 -1
  124. package/dist/get-modal-position-DPftPoU2.d.cts +0 -28
  125. package/dist/get-modal-position-DPftPoU2.d.ts +0 -28
  126. package/src/components/form/select/select-option.tsx +0 -84
  127. package/src/hooks/use-observer.ts +0 -18
  128. package/src/hooks/use-on-click-outside-ref.ts +0 -17
@@ -0,0 +1,34 @@
1
+ import { RefObject } from 'react';
2
+ import { P as PositionContainer } from './get-modal-position-drle0OjP.cjs';
3
+
4
+ declare enum ModalState {
5
+ OPENING = "OPENING",
6
+ OPEN = "OPEN",
7
+ CLOSING = "CLOSING",
8
+ CLOSED = "CLOSED"
9
+ }
10
+ declare const useModalTransition: (transitionDuration?: number, onClose?: () => void) => {
11
+ isVisible: boolean;
12
+ closeModal: () => void;
13
+ openModal: () => void;
14
+ modalState: ModalState;
15
+ };
16
+
17
+ type UseModalInContainerParams<Container extends HTMLElement = HTMLElement, Modal extends HTMLElement = Container> = {
18
+ closeOnClickOutside?: boolean;
19
+ transitionDuration?: number;
20
+ windowOffset?: number;
21
+ offset?: number;
22
+ position?: `${PositionContainer}`;
23
+ modalRef: RefObject<Modal>;
24
+ containerRef?: RefObject<Container>;
25
+ onClose?: () => void;
26
+ };
27
+ declare const useModalInContainer: <Container extends HTMLElement = HTMLElement, Modal extends HTMLElement = Container>({ closeOnClickOutside, offset, windowOffset, position, transitionDuration, modalRef, containerRef, onClose, }: UseModalInContainerParams<Container, Modal>) => {
28
+ isVisible: boolean;
29
+ closeModal: () => void;
30
+ openModal: () => void;
31
+ modalState: ModalState;
32
+ };
33
+
34
+ export { ModalState as M, type UseModalInContainerParams as U, useModalTransition as a, useModalInContainer as u };
@@ -0,0 +1,34 @@
1
+ import { RefObject } from 'react';
2
+ import { P as PositionContainer } from './get-modal-position-drle0OjP.js';
3
+
4
+ declare enum ModalState {
5
+ OPENING = "OPENING",
6
+ OPEN = "OPEN",
7
+ CLOSING = "CLOSING",
8
+ CLOSED = "CLOSED"
9
+ }
10
+ declare const useModalTransition: (transitionDuration?: number, onClose?: () => void) => {
11
+ isVisible: boolean;
12
+ closeModal: () => void;
13
+ openModal: () => void;
14
+ modalState: ModalState;
15
+ };
16
+
17
+ type UseModalInContainerParams<Container extends HTMLElement = HTMLElement, Modal extends HTMLElement = Container> = {
18
+ closeOnClickOutside?: boolean;
19
+ transitionDuration?: number;
20
+ windowOffset?: number;
21
+ offset?: number;
22
+ position?: `${PositionContainer}`;
23
+ modalRef: RefObject<Modal>;
24
+ containerRef?: RefObject<Container>;
25
+ onClose?: () => void;
26
+ };
27
+ declare const useModalInContainer: <Container extends HTMLElement = HTMLElement, Modal extends HTMLElement = Container>({ closeOnClickOutside, offset, windowOffset, position, transitionDuration, modalRef, containerRef, onClose, }: UseModalInContainerParams<Container, Modal>) => {
28
+ isVisible: boolean;
29
+ closeModal: () => void;
30
+ openModal: () => void;
31
+ modalState: ModalState;
32
+ };
33
+
34
+ export { ModalState as M, type UseModalInContainerParams as U, useModalTransition as a, useModalInContainer as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polpo",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "sideEffects": false,
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -12,9 +12,9 @@
12
12
  "exports": {
13
13
  ".": null,
14
14
  "./ui": {
15
- "main": "./dist/polpo.cjs",
16
- "module": "./dist/polpo.js",
17
- "types": "./dist/polpo.d.ts"
15
+ "main": "./dist/ui.cjs",
16
+ "module": "./dist/ui.js",
17
+ "types": "./dist/ui.d.ts"
18
18
  },
19
19
  "./hooks": {
20
20
  "main": "./dist/hooks.cjs",
@@ -40,7 +40,7 @@
40
40
  "clean": "rm -rf ./dist",
41
41
  "build": "yarn clean && tsup",
42
42
  "publish-package": "yarn lint && yarn build && yarn publish --no-git-tag-version",
43
- "transform-svgs": "node ../../node_modules/@juanmsl/svg-to-react && yarn lint:fix",
43
+ "transform-svgs": "svg-to-react && yarn lint:fix",
44
44
  "dev": "storybook dev -p 6006 --quiet",
45
45
  "build-storybook": "storybook build"
46
46
  },
@@ -1,8 +1,8 @@
1
- import { RadiusVariants, SizeVariants } from '../../../core/variants';
1
+ import { ColorVariants, RadiusVariants, SizeVariants } from '../../../core/variants';
2
2
  import { Grid } from '../../../layouts';
3
3
  import { IconNames } from '../../icon';
4
4
 
5
- import { Button, ButtonColor, ButtonVariant } from './button';
5
+ import { Button, ButtonVariant } from './button';
6
6
 
7
7
  import type { Meta, StoryObj } from '@storybook/react';
8
8
 
@@ -14,7 +14,7 @@ const meta: Meta<typeof Button> = {
14
14
  className: { control: false },
15
15
  color: {
16
16
  control: 'inline-radio',
17
- options: [undefined, ...Object.values(ButtonColor)],
17
+ options: [undefined, ...Object.values(ColorVariants)],
18
18
  },
19
19
  disabled: { control: 'boolean' },
20
20
  isLoading: { control: 'boolean' },
@@ -93,7 +93,7 @@ export const Colors: Story = {
93
93
  render: args => (
94
94
  <Grid gtc='300px' ji='center' gap='1em' ai='center'>
95
95
  <Button {...args}>Default</Button>
96
- {Object.values(ButtonColor).map(color => (
96
+ {Object.values(ColorVariants).map(color => (
97
97
  <Button {...args} color={color} key={color}>
98
98
  {color}
99
99
  </Button>
@@ -1,13 +1,18 @@
1
1
  import styled from 'styled-components';
2
2
 
3
- import { RadiusStyles, SizeStyles } from '../../../core/variants';
3
+ import { RadiusStyles, RadiusVariants, SizeStyles, SizeVariants } from '../../../core/variants';
4
4
 
5
- export type ButtonStyleProps = {
5
+ export type ButtonColorStyles = {
6
6
  $color: string;
7
7
  $colorDark: string;
8
8
  $colorContrast: string;
9
9
  };
10
10
 
11
+ export type ButtonStyleProps = ButtonColorStyles & {
12
+ $size: `${SizeVariants}`;
13
+ $radius: `${RadiusVariants}`;
14
+ };
15
+
11
16
  export const ButtonStyle = styled.button<ButtonStyleProps>`
12
17
  cursor: pointer;
13
18
  font-weight: bold;
@@ -24,9 +29,6 @@ export const ButtonStyle = styled.button<ButtonStyleProps>`
24
29
  position: relative;
25
30
  user-select: none;
26
31
 
27
- ${SizeStyles}
28
- ${RadiusStyles}
29
-
30
32
  .button-loader-icon {
31
33
  animation: spin 800ms linear infinite;
32
34
  font-size: 1.2em;
@@ -63,6 +65,9 @@ export const ButtonStyle = styled.button<ButtonStyleProps>`
63
65
  transition: all 250ms ease;
64
66
  border: 1px solid ${props => props.$color};
65
67
 
68
+ ${props => SizeStyles[props.$size]}
69
+ ${props => RadiusStyles[props.$radius]}
70
+
66
71
  &:not(:disabled) {
67
72
  &:not(.no-shadow) {
68
73
  &:hover {
@@ -2,11 +2,11 @@ import React, { ButtonHTMLAttributes } from 'react';
2
2
  import { useTheme } from 'styled-components';
3
3
 
4
4
  import { ThemeColor } from '../../../contexts';
5
- import { SizeVariants, useSizeClassName, RadiusVariants, useRadiusClassName } from '../../../core/variants';
5
+ import { SizeVariants, RadiusVariants, ColorVariants } from '../../../core/variants';
6
6
  import { Icon, IconNameT } from '../../icon';
7
7
  import { Ripple } from '../../ripple';
8
8
 
9
- import { ButtonStyle, ButtonStyleProps } from './button.style';
9
+ import { ButtonStyle, ButtonColorStyles } from './button.style';
10
10
 
11
11
  import { useClassNames } from '@polpo/hooks';
12
12
 
@@ -16,17 +16,7 @@ export enum ButtonVariant {
16
16
  FLAT = 'flat',
17
17
  }
18
18
 
19
- export enum ButtonColor {
20
- PRIMARY = 'primary',
21
- SECONDARY = 'secondary',
22
- TERTIARY = 'tertiary',
23
- INFO = 'info',
24
- WARNING = 'warning',
25
- ALERT = 'alert',
26
- ACTIVE = 'active',
27
- }
28
-
29
- const getColor = (color?: ThemeColor): ButtonStyleProps | null => {
19
+ const getColor = (color?: ThemeColor): ButtonColorStyles | null => {
30
20
  if (color) {
31
21
  return {
32
22
  $color: color.main,
@@ -53,7 +43,7 @@ export type ButtonProps = {
53
43
  style?: React.CSSProperties;
54
44
  type?: ButtonHTMLAttributes<HTMLButtonElement>['type'];
55
45
  noShadow?: boolean;
56
- color?: `${ButtonColor}`;
46
+ color?: `${ColorVariants}`;
57
47
  };
58
48
 
59
49
  const ButtonComponent = (
@@ -77,11 +67,7 @@ const ButtonComponent = (
77
67
  ref: React.ForwardedRef<HTMLButtonElement>,
78
68
  ) => {
79
69
  const theme = useTheme();
80
- const buttonSize = useSizeClassName(size);
81
- const buttonRadius = useRadiusClassName(radius);
82
70
  const buttonClassName = useClassNames({
83
- [buttonRadius]: true,
84
- [buttonSize]: true,
85
71
  'ghost-variant': variant === ButtonVariant.GHOST,
86
72
  'flat-variant': variant === ButtonVariant.FLAT,
87
73
  'is-loading': !disabled && isLoading,
@@ -90,7 +76,7 @@ const ButtonComponent = (
90
76
  [className]: !!className,
91
77
  });
92
78
 
93
- const buttonColors: ButtonStyleProps = (color && getColor(theme.colors[color])) || {
79
+ const buttonColors: ButtonColorStyles = (color && getColor(theme.colors[color])) || {
94
80
  $color: theme.colors.text.main,
95
81
  $colorDark: theme.colors.text.dark,
96
82
  $colorContrast: theme.colors.background.main,
@@ -105,6 +91,8 @@ const ButtonComponent = (
105
91
  disabled={disabled}
106
92
  onClick={onClick}
107
93
  type={type}
94
+ $size={size}
95
+ $radius={radius}
108
96
  >
109
97
  {leftIcon && (!isLoading || disabled) && <Icon className='button-left-icon' name={leftIcon} />}
110
98
  <span className='button-text'>
@@ -16,7 +16,7 @@ export const FlipCard = ({
16
16
  flipSpeed = 500,
17
17
  isFlipped = false,
18
18
  children,
19
- }: FlipCardProps): React.ReactElement => {
19
+ }: FlipCardProps) => {
20
20
  const getComponent = (key: 0 | 1): React.ReactNode => {
21
21
  if (children.length !== 2) {
22
22
  throw new Error('Component FlipCard requires 2 children');
@@ -0,0 +1,35 @@
1
+ import { Cursor } from './cursor';
2
+
3
+ import { SectionLayout, Typography } from '@polpo/ui';
4
+
5
+ import type { Meta, StoryObj } from '@storybook/react';
6
+
7
+ const meta: Meta<typeof Cursor> = {
8
+ title: 'Cursor',
9
+ component: Cursor,
10
+ parameters: {
11
+ layout: 'fullscreen',
12
+ },
13
+ argTypes: {},
14
+ args: {},
15
+ render: () => (
16
+ <section>
17
+ <Cursor />
18
+ <SectionLayout>
19
+ <Typography align='center' variant='header4'>
20
+ Hello world
21
+ </Typography>
22
+ <Typography align='center'>
23
+ <a href=''>Link, hover me!</a>
24
+ </Typography>
25
+ </SectionLayout>
26
+ </section>
27
+ ),
28
+ };
29
+
30
+ export default meta;
31
+ type Story = StoryObj<typeof Cursor>;
32
+
33
+ export const Default: Story = {
34
+ args: {},
35
+ };
@@ -0,0 +1,73 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const CursorOverlayStyle = styled.section`
4
+ position: fixed;
5
+ top: 0;
6
+ left: 0;
7
+ width: 100%;
8
+ height: 100%;
9
+ cursor: none;
10
+ pointer-events: none;
11
+ `;
12
+
13
+ export const CursorStyle = styled.span`
14
+ position: fixed;
15
+ border-radius: 50%;
16
+ z-index: 99999999;
17
+ pointer-events: none;
18
+ transform: translateZ(0);
19
+
20
+ @media (any-pointer: coarse) {
21
+ display: none;
22
+ }
23
+
24
+ &.outer-circle {
25
+ margin-left: -15px;
26
+ margin-top: -15px;
27
+ width: 30px;
28
+ height: 30px;
29
+ border: 2px solid ${props => props.theme.colors.primary.main};
30
+ box-sizing: border-box;
31
+ z-index: 99999999;
32
+ opacity: 0.5;
33
+ transition:
34
+ all 0.08s ease-out,
35
+ width 0.3s ease-in-out,
36
+ height 0.3s ease-in-out,
37
+ margin 0.3s ease-in-out,
38
+ opacity 0.3s ease-in-out;
39
+
40
+ &.cursor-hover {
41
+ margin-left: -40px;
42
+ margin-top: -40px;
43
+ width: 80px;
44
+ height: 80px;
45
+ background-color: ${props => props.theme.colors.primary.main};
46
+ opacity: 0.3;
47
+ }
48
+
49
+ &.cursor-text {
50
+ margin-left: -2px;
51
+ margin-top: -40px;
52
+ width: 4px;
53
+ height: 80px;
54
+ background-color: ${props => props.theme.colors.primary.main};
55
+ opacity: 0.3;
56
+ }
57
+ }
58
+
59
+ &.inner-circle {
60
+ margin-left: -3px;
61
+ margin-top: -3px;
62
+ width: 6px;
63
+ height: 6px;
64
+ z-index: 99999999;
65
+ background-color: ${props => props.theme.colors.primary.main};
66
+ transition: opacity 0.3s ease-in-out;
67
+ opacity: 1;
68
+
69
+ &.cursor-hover {
70
+ opacity: 0;
71
+ }
72
+ }
73
+ `;
@@ -0,0 +1,49 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ import { CursorOverlayStyle, CursorStyle } from './cursor.style';
4
+
5
+ import { useEventListener, useMousePosition } from '@polpo/hooks';
6
+
7
+ export const Cursor = () => {
8
+ const { x, y, elementX, elementY, ref } = useMousePosition();
9
+ const [isCursorHover, setIsCursorHover] = useState(false);
10
+
11
+ useEventListener('mouseover', e => {
12
+ const computedCursor = getComputedStyle(e.target as HTMLElement).cursor;
13
+
14
+ setIsCursorHover(computedCursor === 'pointer');
15
+ });
16
+
17
+ useEffect(() => {
18
+ if (!('ontouchstart' in window || navigator.maxTouchPoints)) {
19
+ document.body.style.cursor = 'none';
20
+ }
21
+
22
+ return () => {
23
+ document.body.style.cursor = 'auto';
24
+ };
25
+ }, []);
26
+
27
+ if (x === null || y === null || 'ontouchstart' in window || navigator.maxTouchPoints) {
28
+ return null;
29
+ }
30
+
31
+ const translate3d = `translate3d(${elementX}px, ${elementY}px, 0)`;
32
+
33
+ return (
34
+ <CursorOverlayStyle ref={ref}>
35
+ <CursorStyle
36
+ className={`outer-circle ${isCursorHover ? 'cursor-hover' : ''}`}
37
+ style={{
38
+ transform: translate3d,
39
+ }}
40
+ />
41
+ <CursorStyle
42
+ className={`inner-circle ${isCursorHover ? 'cursor-hover' : ''}`}
43
+ style={{
44
+ transform: translate3d,
45
+ }}
46
+ />
47
+ </CursorOverlayStyle>
48
+ );
49
+ };
@@ -0,0 +1 @@
1
+ export * from './cursor';
@@ -1,10 +1,13 @@
1
1
  import { useState } from 'react';
2
2
 
3
+ import { ColorVariants } from '../../../core/variants';
3
4
  import { IconNames } from '../../icon';
4
5
  import { UnControlledComponentArgTypes } from '../form.stories.types';
5
6
 
6
7
  import { Checkbox } from './checkbox';
7
8
 
9
+ import { SectionLayout } from '@polpo/ui';
10
+
8
11
  import type { Meta, StoryObj } from '@storybook/react';
9
12
 
10
13
  const meta: Meta<typeof Checkbox> = {
@@ -15,6 +18,7 @@ const meta: Meta<typeof Checkbox> = {
15
18
  placeholder: { table: { disable: true } },
16
19
  label: { control: 'text' },
17
20
  icon: { options: [undefined, ...IconNames.toSorted()] },
21
+ color: { control: { type: 'inline-radio', options: Object.values(ColorVariants) } },
18
22
  },
19
23
  args: {
20
24
  label: 'Checkbox',
@@ -32,3 +36,50 @@ type Story = StoryObj<typeof Checkbox>;
32
36
  export const Default: Story = {
33
37
  args: {},
34
38
  };
39
+
40
+ export const MultipleOptions: Story = {
41
+ args: {},
42
+ render: args => {
43
+ const [option1, setOption1] = useState(false);
44
+ const [option2, setOption2] = useState(false);
45
+ const [option3, setOption3] = useState(false);
46
+ const [option4, setOption4] = useState(false);
47
+
48
+ return (
49
+ <SectionLayout fitHeightContent>
50
+ <Checkbox {...args} value={option1} setValue={setOption1} label='Option 1' />
51
+ <Checkbox {...args} value={option2} setValue={setOption2} label='Option 2' />
52
+ <Checkbox {...args} value={option3} setValue={setOption3} label='Option 3' />
53
+ <Checkbox {...args} value={option4} setValue={setOption4} label='Option 4' />
54
+ </SectionLayout>
55
+ );
56
+ },
57
+ };
58
+
59
+ export const Colors: Story = {
60
+ args: {},
61
+ argTypes: {
62
+ color: { control: false },
63
+ },
64
+ render: args => {
65
+ const [option1, setOption1] = useState(false);
66
+ const [option2, setOption2] = useState(false);
67
+ const [option3, setOption3] = useState(false);
68
+ const [option4, setOption4] = useState(false);
69
+ const [option5, setOption5] = useState(false);
70
+ const [option6, setOption6] = useState(false);
71
+ const [option7, setOption7] = useState(false);
72
+
73
+ return (
74
+ <SectionLayout fitHeightContent>
75
+ <Checkbox {...args} color='primary' value={option1} setValue={setOption1} label='Primary' />
76
+ <Checkbox {...args} color='secondary' value={option2} setValue={setOption2} label='Secondary' />
77
+ <Checkbox {...args} color='tertiary' value={option3} setValue={setOption3} label='Tertiary' />
78
+ <Checkbox {...args} color='info' value={option4} setValue={setOption4} label='Info' />
79
+ <Checkbox {...args} color='active' value={option5} setValue={setOption5} label='Active' />
80
+ <Checkbox {...args} color='warning' value={option6} setValue={setOption6} label='Warning' />
81
+ <Checkbox {...args} color='alert' value={option7} setValue={setOption7} label='Alert' />
82
+ </SectionLayout>
83
+ );
84
+ },
85
+ };
@@ -1,44 +1,35 @@
1
1
  import styled from 'styled-components';
2
2
 
3
- export const CheckboxStyle = styled.section`
4
- border-radius: 42%;
5
- background: ${props => props.theme.colors.background.paper};
6
- color: ${props => props.theme.colors.primary.main};
7
- transition: all 300ms ease;
3
+ export const CheckboxFillStyle = styled.section`
4
+ transition: all 200ms ease-out;
5
+ border-radius: inherit;
6
+ margin: auto;
7
+ width: 0;
8
+ height: 0;
9
+ overflow: hidden;
8
10
  position: relative;
9
- padding: 2px;
10
- width: 1.4em;
11
- height: 1.4em;
12
- border: 1px solid;
11
+ display: grid;
12
+ place-content: center;
13
+ place-items: center;
13
14
 
14
15
  .checkbox-icon {
15
- position: absolute;
16
- top: 50%;
17
- left: 50%;
18
- transform: translate(-50%, -50%);
19
- color: ${props => props.theme.colors.primary.contrast};
20
16
  font-size: 0.7em;
21
17
  z-index: 1;
22
18
  opacity: 0;
23
19
  transition: opacity 300ms ease;
24
-
25
- path {
26
- filter: drop-shadow(0px 0 3px rgba(0, 0, 0, 1));
27
- }
28
20
  }
21
+ `;
29
22
 
30
- &.is-checked {
31
- background: ${props => props.theme.colors.primary.main};
32
- color: ${props => props.theme.colors.primary.main};
33
-
34
- .checkbox-icon {
35
- opacity: 1;
36
- }
37
-
38
- &:hover {
39
- background: ${props => props.theme.colors.primary.light};
40
- }
41
- }
23
+ export const CheckboxStyle = styled.section`
24
+ border-radius: 40%;
25
+ background: ${props => props.theme.colors.background.paper};
26
+ transition: all 300ms ease;
27
+ width: 1em;
28
+ height: 1em;
29
+ margin: 2px;
30
+ outline: 1px solid;
31
+ display: flex;
32
+ position: relative;
42
33
 
43
34
  .checkbox-input {
44
35
  position: absolute;
@@ -52,24 +43,69 @@ export const CheckboxStyle = styled.section`
52
43
  }
53
44
  `;
54
45
 
55
- export const CheckboxContainerStyle = styled.section`
56
- display: flex;
46
+ type CheckboxContainerStyleProps = {
47
+ $color: string;
48
+ $colorIcon: string;
49
+ };
50
+
51
+ export const CheckboxContainerStyle = styled.section<CheckboxContainerStyleProps>`
52
+ display: grid;
53
+ grid-auto-flow: column;
54
+ grid-auto-columns: auto 1fr;
57
55
  align-items: center;
58
- gap: 1em;
56
+ gap: 0.5em;
59
57
  width: fit-content;
60
58
 
61
59
  .checkbox-label {
62
60
  cursor: pointer;
63
61
  user-select: none;
62
+ width: 100%;
63
+ }
64
+
65
+ ${CheckboxStyle} {
66
+ color: ${props => props.$color};
67
+
68
+ &.is-checked {
69
+ ${CheckboxFillStyle} {
70
+ width: 100%;
71
+ height: 100%;
72
+ background: ${props => props.$color};
73
+ color: ${props => props.$colorIcon};
74
+ }
75
+
76
+ .checkbox-icon {
77
+ opacity: 1;
78
+ }
79
+ }
64
80
  }
65
81
 
66
82
  ${CheckboxStyle}:hover,
67
83
  &:has(.checkbox-label:hover) ${CheckboxStyle} {
68
- box-shadow: 0 0 0 0.4em ${props => props.theme.colors.primary.main}88;
84
+ box-shadow: 0 0 0 0.3em ${props => props.$color}88;
85
+ padding: 2px;
86
+
87
+ ${CheckboxFillStyle} {
88
+ width: 20%;
89
+ height: 20%;
90
+ border-radius: 20%;
91
+ background: ${props => props.$color}88;
92
+ color: ${props => props.$colorIcon};
93
+ }
94
+
95
+ &:is(.is-checked) {
96
+ ${CheckboxFillStyle} {
97
+ width: 100%;
98
+ height: 100%;
99
+ border-radius: inherit;
100
+ background: ${props => props.$color};
101
+ }
102
+ }
69
103
  }
70
104
 
71
- ${CheckboxStyle}:active,
72
- &:has(.checkbox-label:active) ${CheckboxStyle} {
73
- transform: scale(0.95);
105
+ ${CheckboxStyle}:focus,
106
+ &:has(.checkbox-input:focus) ${CheckboxStyle},
107
+ &:has(.checkbox-label:focus) ${CheckboxStyle} {
108
+ box-shadow: 0 0 0 0.3em ${props => props.$color}88;
109
+ padding: 2px;
74
110
  }
75
111
  `;