se-design 0.0.7

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 (70) hide show
  1. package/.prettierrc +8 -0
  2. package/.storybook/main.ts +25 -0
  3. package/.storybook/preview-head.html +6 -0
  4. package/.storybook/preview.ts +14 -0
  5. package/.vscode/settings.json +3 -0
  6. package/README.md +30 -0
  7. package/index.html +13 -0
  8. package/package.json +61 -0
  9. package/postcss.config.cjs +10 -0
  10. package/public/icons/back.svg +4 -0
  11. package/public/icons/close.svg +4 -0
  12. package/public/icons/down.svg +3 -0
  13. package/public/icons/pages.svg +4 -0
  14. package/public/icons/tick.svg +3 -0
  15. package/public/vite.svg +1 -0
  16. package/pull_request_template.md +31 -0
  17. package/src/App.css +42 -0
  18. package/src/App.tsx +35 -0
  19. package/src/assets/react.svg +1 -0
  20. package/src/components/Button/Button.stories.ts +98 -0
  21. package/src/components/Button/index.tsx +69 -0
  22. package/src/components/Icon/Icon.stories.ts +21 -0
  23. package/src/components/Icon/Icon.tsx +24 -0
  24. package/src/components/Icon/Icon.types.ts +4 -0
  25. package/src/components/MenuItem/MenuItem.stories.tsx +30 -0
  26. package/src/components/MenuItem/index.tsx +20 -0
  27. package/src/components/MenuList/MenuList.stories.tsx +20 -0
  28. package/src/components/MenuList/index.tsx +16 -0
  29. package/src/components/Modal/Modal.stories.ts +43 -0
  30. package/src/components/Modal/Modal.tsx +39 -0
  31. package/src/components/SplitButton/SplitButton.stories.ts +22 -0
  32. package/src/components/SplitButton/SplitButton.tsx +59 -0
  33. package/src/components/Tag/Tag.stories.tsx +20 -0
  34. package/src/components/Tag/Tag.tsx +13 -0
  35. package/src/components/Toggle/Toggle.stories.tsx +34 -0
  36. package/src/components/Toggle/Toggle.tsx +40 -0
  37. package/src/components/Toggle/Toggle.types.ts +14 -0
  38. package/src/components/Tooltip/Tooltip.stories.tsx +58 -0
  39. package/src/components/Tooltip/Tooltip.tsx +95 -0
  40. package/src/components/index.ts +9 -0
  41. package/src/index.css +23 -0
  42. package/src/index.ts +3 -0
  43. package/src/main.tsx +10 -0
  44. package/src/stories/Colors.mdx +24 -0
  45. package/src/stories/Configure.mdx +364 -0
  46. package/src/stories/Iconography.mdx +27 -0
  47. package/src/stories/assets/accessibility.png +0 -0
  48. package/src/stories/assets/accessibility.svg +5 -0
  49. package/src/stories/assets/addon-library.png +0 -0
  50. package/src/stories/assets/assets.png +0 -0
  51. package/src/stories/assets/avif-test-image.avif +0 -0
  52. package/src/stories/assets/context.png +0 -0
  53. package/src/stories/assets/discord.svg +15 -0
  54. package/src/stories/assets/docs.png +0 -0
  55. package/src/stories/assets/figma-plugin.png +0 -0
  56. package/src/stories/assets/github.svg +3 -0
  57. package/src/stories/assets/share.png +0 -0
  58. package/src/stories/assets/styling.png +0 -0
  59. package/src/stories/assets/testing.png +0 -0
  60. package/src/stories/assets/theming.png +0 -0
  61. package/src/stories/assets/tutorials.svg +12 -0
  62. package/src/stories/assets/youtube.svg +4 -0
  63. package/src/utils/colors.js +47 -0
  64. package/src/utils/common.types.ts +3 -0
  65. package/src/utils/iconNames.ts +6 -0
  66. package/src/vite-env.d.ts +1 -0
  67. package/tailwind.config.js +67 -0
  68. package/tsconfig.json +30 -0
  69. package/tsconfig.node.json +11 -0
  70. package/vite.config.ts +28 -0
@@ -0,0 +1,43 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Modal } from './Modal';
3
+
4
+ const meta = {
5
+ title: 'Components/Modal',
6
+ component: Modal,
7
+ tags: ['!!autodocs']
8
+ } satisfies Meta<typeof Modal>;
9
+
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Default: Story = {
14
+ args: {
15
+ title: 'Discard changes?',
16
+ content: 'Are you sure you want to discard the changes?',
17
+ cancelButtonText: 'Cancel',
18
+ successButtonText: 'Discard',
19
+ cancelButtonType: 'secondary',
20
+ successButtonType: 'negative'
21
+ }
22
+ };
23
+
24
+ export const modalWithPrimaryButton: Story = {
25
+ args: {
26
+ title: 'Sign document?',
27
+ content: 'You are one of the signers for NDA-file.',
28
+ cancelButtonText: 'Cancel',
29
+ successButtonText: 'Sign Now',
30
+ cancelButtonType: 'secondary',
31
+ successButtonType: 'primary'
32
+ }
33
+ };
34
+
35
+ export const modalWithoutHeader: Story = {
36
+ args: {
37
+ content: 'This is a modal without a header.',
38
+ cancelButtonText: 'Cancel',
39
+ successButtonText: 'Ok',
40
+ cancelButtonType: 'secondary',
41
+ successButtonType: 'primary'
42
+ }
43
+ };
@@ -0,0 +1,39 @@
1
+ import { FC } from 'react';
2
+ import { Button } from '../Button';
3
+
4
+ interface ModalProps {
5
+ title?: string;
6
+ content: string;
7
+ successButtonText: string;
8
+ cancelButtonText: string;
9
+ successButtonType: 'primary' | 'secondary' | 'negative' | 'negative-secondary';
10
+ cancelButtonType: 'primary' | 'secondary' | 'negative' | 'negative-secondary';
11
+ cancelAction?: () => void;
12
+ successAction?: () => void;
13
+ }
14
+
15
+ export const Modal: FC<ModalProps> = (props) => {
16
+ const {
17
+ title,
18
+ content,
19
+ successButtonType,
20
+ cancelButtonType,
21
+ successButtonText,
22
+ cancelButtonText,
23
+ cancelAction,
24
+ successAction
25
+ } = props;
26
+
27
+ return (
28
+ <div className="fixed inset-0 flex items-start justify-center z-50 backdrop-brightness-50">
29
+ <div className="flex flex-col gap-3 bg-white rounded shadow-lg p-8 mt-14 w-[500px]">
30
+ {title && <div className="text-lg font-semibold">{title}</div>}
31
+ <p className="leading-normal">{content}</p>
32
+ <div className="flex items-center justify-end gap-4 pt-2">
33
+ <Button type={cancelButtonType} onClick={cancelAction} label={cancelButtonText} />
34
+ <Button type={successButtonType} onClick={successAction} label={successButtonText} />
35
+ </div>
36
+ </div>
37
+ </div>
38
+ );
39
+ };
@@ -0,0 +1,22 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import { SplitButton } from './SplitButton';
4
+
5
+ const meta = {
6
+ title: 'Components/SplitButton',
7
+ component: SplitButton,
8
+ parameters: {
9
+ layout: 'centered'
10
+ },
11
+ tags: ['autodocs']
12
+ } satisfies Meta<typeof SplitButton>;
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof meta>;
16
+
17
+ export const Primary: Story = {
18
+ args: {
19
+ label: 'Button',
20
+ menuItems: [{ label: 'Email' }, { label: 'Rename' }, { label: 'Shedule Reminder Event', tag: 'NEW' }]
21
+ }
22
+ };
@@ -0,0 +1,59 @@
1
+ import { FC, useState } from 'react';
2
+ import { MenuItemProps } from 'src/components/MenuItem';
3
+ import { MenuList } from 'src/components/MenuList';
4
+
5
+ interface SplitButtonProps {
6
+ /**
7
+ * Button contents
8
+ */
9
+ label: string;
10
+ /**
11
+ * Optional click handler
12
+ */
13
+ onClick?: () => void;
14
+ /**
15
+ * Optional click handler for dropdown
16
+ */
17
+ onDropdownClick?: () => void;
18
+ menuItems?: MenuItemProps[];
19
+ }
20
+
21
+ export const SplitButton: FC<SplitButtonProps> = (props) => {
22
+ const { label, onDropdownClick = () => {}, menuItems = [], ...remainingProps } = props;
23
+ const [isOpen, setIsOpen] = useState(false);
24
+
25
+ const handleDropdownClick = () => {
26
+ setIsOpen(!isOpen);
27
+ onDropdownClick();
28
+ };
29
+
30
+ return (
31
+ <div className={'flex items-center relative'}>
32
+ <button
33
+ type="button"
34
+ className="px-8 py-2.5 rounded-l text-sm bg-blue-500 text-white border-r border-white"
35
+ {...remainingProps}
36
+ >
37
+ {label}
38
+ </button>
39
+ <button type="button" className="bg-blue-500 rounded-r" onClick={handleDropdownClick}>
40
+ <svg
41
+ className={`${isOpen ? 'rotate-180' : ''} transition-all`}
42
+ width="35"
43
+ height="40"
44
+ viewBox="0 0 35 40"
45
+ fill="none"
46
+ xmlns="http://www.w3.org/2000/svg"
47
+ >
48
+ <path d="M0 0H32C33.6569 0 35 1.34315 35 3V37C35 38.6569 33.6569 40 32 40H0V0Z" fill="transparent" />
49
+ <path d="M18 23.5L14 19.5L22 19.5L18 23.5Z" fill="white" />
50
+ </svg>
51
+ </button>
52
+ {isOpen && (
53
+ <div className="absolute top-full mt-1 w-max">
54
+ <MenuList items={menuItems} />
55
+ </div>
56
+ )}
57
+ </div>
58
+ );
59
+ };
@@ -0,0 +1,20 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Tag } from "./Tag";
3
+
4
+ const meta = {
5
+ title: "Components/Tag",
6
+ component: Tag,
7
+ parameters: {
8
+ layout: "centered",
9
+ },
10
+ tags: ["autodocs"],
11
+ } as Meta<typeof Tag>;
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Default: Story = {
17
+ args: {
18
+ label: "Tag",
19
+ },
20
+ };
@@ -0,0 +1,13 @@
1
+ import { FC } from 'react';
2
+
3
+ type TagProps = {
4
+ label: string;
5
+ };
6
+
7
+ export const Tag: FC<TagProps> = ({ label }) => {
8
+ return (
9
+ <span className="inline-block px-1.5 py-1 text-xs font-bold rounded-sm bg-yellow-400 uppercase leading-4">
10
+ {label}
11
+ </span>
12
+ );
13
+ };
@@ -0,0 +1,34 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Toggle } from "./Toggle";
3
+
4
+ const meta = {
5
+ title: "Components/Toggle",
6
+ component: Toggle,
7
+ tags: ["autodocs"],
8
+ } satisfies Meta<typeof Toggle>;
9
+
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Off: Story = {
14
+ args: {},
15
+ };
16
+
17
+ export const On: Story = {
18
+ args: {
19
+ initialState: true,
20
+ },
21
+ };
22
+
23
+ export const disabledOff: Story = {
24
+ args: {
25
+ disabled: true,
26
+ },
27
+ };
28
+
29
+ export const disabledOn: Story = {
30
+ args: {
31
+ initialState: true,
32
+ disabled: true,
33
+ },
34
+ };
@@ -0,0 +1,40 @@
1
+ import React, { useState } from "react";
2
+ import { ToggleProps } from "./Toggle.types";
3
+
4
+ export const Toggle: React.FC<ToggleProps> = ({
5
+ initialState,
6
+ onToggle,
7
+ disabled,
8
+ }) => {
9
+ const [checked, setChecked] = useState(initialState || false);
10
+
11
+ const handleToggle = () => {
12
+ const newChecked = !checked;
13
+ setChecked(newChecked);
14
+ if (onToggle) {
15
+ onToggle(newChecked);
16
+ }
17
+ };
18
+
19
+ return (
20
+ <label
21
+ className={`block w-8 h-4 p-0.5 rounded-full cursor-pointer bg-gray-500
22
+ ${checked ? " bg-green-600" : ""}
23
+ ${disabled ? " opacity-50 cursor-not-allowed" : ""}
24
+ `}
25
+ >
26
+ <input
27
+ className="opacity-0 hidden"
28
+ type="checkbox"
29
+ checked={checked}
30
+ onChange={handleToggle}
31
+ disabled={disabled}
32
+ />
33
+ <span
34
+ className={`block w-3 h-3 rounded-full bg-white transform transition-transform ${
35
+ checked ? "translate-x-4" : ""
36
+ }`}
37
+ ></span>
38
+ </label>
39
+ );
40
+ };
@@ -0,0 +1,14 @@
1
+ export interface ToggleProps {
2
+ /**
3
+ * Callback when the toggle is toggled
4
+ */
5
+ onToggle?: (checked: boolean) => void;
6
+ /**
7
+ * Initial state of the toggle
8
+ */
9
+ initialState?: boolean;
10
+ /**
11
+ * Optional disabled state
12
+ */
13
+ disabled?: boolean;
14
+ }
@@ -0,0 +1,58 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Tooltip } from "./Tooltip";
3
+ const meta = {
4
+ title: "Components/Tooltip",
5
+ component: Tooltip,
6
+ parameters: {
7
+ layout: "centered",
8
+ },
9
+ tags: ["autodocs"],
10
+ } satisfies Meta<typeof Tooltip>;
11
+
12
+ export default meta;
13
+ type Story = StoryObj<typeof meta>;
14
+
15
+ // const Template: Story = (args: TooltipProps) => <Tooltip {...args} />;
16
+
17
+ export const Default: Story = {
18
+ args: {
19
+ content: "This is a tooltip.",
20
+ tooltipSrc: <span className="underline">{`Hover me(Default)`}</span>,
21
+ },
22
+ };
23
+
24
+ export const BottomLeftAligned: Story = {
25
+ args: {
26
+ content: "This is a tooltip with a long content and has a double line.",
27
+ tooltipSrc: <span className="underline">{`Hover me(Bottom Left aligned)`}</span>,
28
+ position: 'bottom-left',
29
+ displayOn: 'hover'
30
+ },
31
+ };
32
+
33
+ export const BottomRightAligned: Story = {
34
+ args: {
35
+ content: "This is a tooltip.",
36
+ tooltipSrc: <span className="underline">{`Hover me(Bottom Right aligned)`}</span>,
37
+ position: 'bottom-right',
38
+ displayOn: 'hover'
39
+ },
40
+ };
41
+
42
+ export const LeftAligned: Story = {
43
+ args: {
44
+ content: "This is a tooltip.",
45
+ tooltipSrc: <span className="underline">{`Tooltip always on(Left aligned)`}</span>,
46
+ position: 'left',
47
+ displayOn: 'always-on'
48
+ },
49
+ };
50
+
51
+ export const RightAligned: Story = {
52
+ args: {
53
+ content: "This is a tooltip.",
54
+ tooltipSrc: <span className="underline">{`Click me(Right aligned)`}</span>,
55
+ position: 'right',
56
+ displayOn: 'click'
57
+ },
58
+ };
@@ -0,0 +1,95 @@
1
+ import { useEffect, useState, useRef } from "react";
2
+
3
+ export interface TooltipProps {
4
+ /**
5
+ * Tooltip contents
6
+ */
7
+ content: string;
8
+ /**
9
+ * Tooltip position
10
+ */
11
+ position?: "bottom-center" | "bottom-left" | "bottom-right" | "left" | "right";
12
+ /**
13
+ * Display tooltip on Hover, Click or Always
14
+ */
15
+ displayOn?: 'hover' | 'click' | 'always-on';
16
+ /**
17
+ * Tooltip trigger contents
18
+ */
19
+ tooltipSrc?: React.ReactNode;
20
+ }
21
+
22
+ export const Tooltip = ({ content, tooltipSrc, position = 'bottom-center', displayOn = 'hover' }: TooltipProps) => {
23
+ const [displayTooltip, setDisplayTooltip] = useState(displayOn === 'always-on');
24
+ const tooltipContentRef = useRef<HTMLDivElement>(null);;
25
+
26
+ useEffect(() => {
27
+ const tooltipContent = tooltipContentRef.current;
28
+
29
+ if(!tooltipContent) {
30
+ return
31
+ }
32
+
33
+ if(position == 'bottom-center') {
34
+ tooltipContent.setAttribute("style", `left: 50%;transform: translateX(-50%);`);
35
+ tooltipContent.classList.add(`before:left-[calc(50%-7px)]`);
36
+ tooltipContent.classList.add(`before:top-[-7px]`);
37
+ } else if(position == 'bottom-left') {
38
+ tooltipContent.classList.add(`before:left-[calc(10%-7px)]`);
39
+ tooltipContent.classList.add(`before:top-[-7px]`);
40
+ } else if(position == 'bottom-right') {
41
+ tooltipContent.setAttribute("style", `right: 0;`);
42
+ tooltipContent.classList.add(`before:right-[calc(10%+7px)]`);
43
+ tooltipContent.classList.add(`before:top-[-7px]`);
44
+ } else if(position == 'left') {
45
+ tooltipContent.setAttribute("style", `right: calc(100% + 10px);top:0;`);
46
+ tooltipContent.classList.add(`before:right-[-6px]`);
47
+ tooltipContent.classList.add(`before:top-0px`);
48
+ } else if(position == 'right') {
49
+ tooltipContent.setAttribute("style", `left: calc(100% + 10px);top:0;`);
50
+ tooltipContent.classList.add(`before:left-[-6px]`);
51
+ tooltipContent.classList.add(`before:top-0px`);
52
+ }
53
+
54
+ if(displayOn == 'hover') {
55
+ tooltipContent.classList.add(`group-hover:visible`);
56
+ }
57
+ }, [content]);
58
+
59
+ useEffect(() => {
60
+ const tooltipContent = tooltipContentRef.current;
61
+
62
+ if(!tooltipContent) {
63
+ return;
64
+ }
65
+ if(displayTooltip) {
66
+ tooltipContent.classList.remove(`invisible`);
67
+ } else {
68
+ tooltipContent.classList.add(`invisible`);
69
+ }
70
+ }, [displayTooltip])
71
+
72
+ const onTooltipSrcClick = () => {
73
+ if(displayOn == 'click') {
74
+ setDisplayTooltip((displayTooltip) => !displayTooltip)
75
+ }
76
+ }
77
+
78
+ return (
79
+ <div className="group relative" onClick={onTooltipSrcClick}>
80
+ <div className="cursor-pointer" id="tooltip-trigger">
81
+ {tooltipSrc}
82
+ </div>
83
+ <div
84
+ ref={tooltipContentRef}
85
+ id="tooltip-content"
86
+ className="flex justify-center px-3 py-2 min-w-24 max-w-60
87
+ absolute top-[calc(100%+8px)] w-max bg-gray-800 text-white text-xs rounded-[3px]
88
+ before:content-[' '] before:w-3.5 before:h-3.5 before:bg-gray-800 before:inline-block
89
+ before:absolute before:rounded-tl-sm before:rotate-45"
90
+ >
91
+ {content}
92
+ </div>
93
+ </div>
94
+ );
95
+ };
@@ -0,0 +1,9 @@
1
+ export { Button } from './Button';
2
+ export { Icon } from './Icon/Icon';
3
+ export { SplitButton } from './SplitButton/SplitButton';
4
+ export { Toggle } from './Toggle/Toggle';
5
+ export { Tag } from './Tag/Tag';
6
+ export { Modal } from './Modal/Modal';
7
+ export { Tooltip } from './Tooltip/Tooltip';
8
+ export { MenuItem } from './MenuItem';
9
+ export { MenuList } from './MenuList';
package/src/index.css ADDED
@@ -0,0 +1,23 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ :root {
6
+ /* font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; */
7
+ /* font-family: "lato", sans-serif;
8
+ line-height: 1.5;
9
+ font-weight: 400;
10
+
11
+ font-synthesis: none;
12
+ text-rendering: optimizeLegibility;
13
+ -webkit-font-smoothing: antialiased;
14
+ -moz-osx-font-smoothing: grayscale; */
15
+ }
16
+
17
+ body {
18
+ font-family: 'Inter', sans-serif;
19
+ }
20
+
21
+ img {
22
+ display: inline-block;
23
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ import './index.css';
2
+
3
+ export * from './components';
package/src/main.tsx ADDED
@@ -0,0 +1,10 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom/client'
3
+ import App from './App.tsx'
4
+ import './index.css'
5
+
6
+ ReactDOM.createRoot(document.getElementById('root')!).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>,
10
+ )
@@ -0,0 +1,24 @@
1
+ {/* Colors.mdx */}
2
+
3
+ import { Meta, ColorPalette, ColorItem } from '@storybook/blocks';
4
+ import colors from 'src/utils/colors'
5
+
6
+ <Meta title="Colors" />
7
+
8
+ # Colors
9
+
10
+ This file is used to display the color palette used in the Easy Design System.
11
+ The colors are imported from `src/utils/colors.ts` file.
12
+ ## Add a new color
13
+ - Add the new color to the `src/utils/colors.ts` file.
14
+ - After adding the new color, it will automatically appear in the color palette here.
15
+ - Each color is displayed with its name **(the key from the colors object)** and the color value.
16
+
17
+ ## Color Palette
18
+ <br />
19
+
20
+ <ColorPalette>
21
+ {Object.entries(colors).map(([title, colors]) => (
22
+ <ColorItem key={title} title={title} colors={colors} />
23
+ ))}
24
+ </ColorPalette>