@vrobots/storybook 0.1.0

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 (59) hide show
  1. package/README.md +73 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.js +3 -0
  4. package/dist/package.json +63 -0
  5. package/dist/src/components/AvatarIconMenu.d.ts +8 -0
  6. package/dist/src/components/AvatarIconMenu.js +8 -0
  7. package/dist/src/components/Breadcrumbs.d.ts +11 -0
  8. package/dist/src/components/Breadcrumbs.js +18 -0
  9. package/dist/src/components/Display.d.ts +4 -0
  10. package/dist/src/components/Display.js +7 -0
  11. package/dist/src/components/Frame.d.ts +7 -0
  12. package/dist/src/components/Frame.js +14 -0
  13. package/dist/src/components/Header.d.ts +11 -0
  14. package/dist/src/components/Header.js +15 -0
  15. package/dist/src/components/Logo.d.ts +5 -0
  16. package/dist/src/components/Logo.js +7 -0
  17. package/dist/src/components/Menu.d.ts +12 -0
  18. package/dist/src/components/Menu.js +17 -0
  19. package/dist/src/components/Page.d.ts +6 -0
  20. package/dist/src/components/Page.js +6 -0
  21. package/dist/src/components/Sidebar.d.ts +15 -0
  22. package/dist/src/components/Sidebar.js +66 -0
  23. package/dist/src/components/index.d.ts +8 -0
  24. package/dist/src/components/index.js +8 -0
  25. package/dist/src/components/ui/color-mode.d.ts +21 -0
  26. package/dist/src/components/ui/color-mode.js +44 -0
  27. package/dist/src/hooks/index.d.ts +3 -0
  28. package/dist/src/hooks/index.js +3 -0
  29. package/dist/src/hooks/useBreakpoint.d.ts +1 -0
  30. package/dist/src/hooks/useBreakpoint.js +12 -0
  31. package/dist/src/hooks/useIsMobile.d.ts +1 -0
  32. package/dist/src/hooks/useIsMobile.js +6 -0
  33. package/dist/src/hooks/useSelectedColorSchema.d.ts +5 -0
  34. package/dist/src/hooks/useSelectedColorSchema.js +8 -0
  35. package/dist/src/stories/AvatarIconMenu.stories.d.ts +18 -0
  36. package/dist/src/stories/AvatarIconMenu.stories.js +27 -0
  37. package/dist/src/stories/Breadcrumbs.stories.d.ts +14 -0
  38. package/dist/src/stories/Breadcrumbs.stories.js +22 -0
  39. package/dist/src/stories/Frame.stories.d.ts +24 -0
  40. package/dist/src/stories/Frame.stories.js +56 -0
  41. package/dist/src/stories/Header.stories.d.ts +22 -0
  42. package/dist/src/stories/Header.stories.js +39 -0
  43. package/dist/src/stories/Menu.stories.d.ts +12 -0
  44. package/dist/src/stories/Menu.stories.js +17 -0
  45. package/dist/src/stories/Sidebar.stories.d.ts +16 -0
  46. package/dist/src/stories/Sidebar.stories.js +25 -0
  47. package/dist/src/utils/calculate.d.ts +5 -0
  48. package/dist/src/utils/calculate.js +15 -0
  49. package/dist/src/utils/cookies.d.ts +5 -0
  50. package/dist/src/utils/cookies.js +26 -0
  51. package/dist/src/utils/data.d.ts +6 -0
  52. package/dist/src/utils/data.js +20 -0
  53. package/dist/src/utils/format.d.ts +23 -0
  54. package/dist/src/utils/format.js +76 -0
  55. package/dist/src/utils/index.d.ts +14 -0
  56. package/dist/src/utils/index.js +13 -0
  57. package/dist/src/utils/validation.d.ts +13 -0
  58. package/dist/src/utils/validation.js +66 -0
  59. package/package.json +63 -0
@@ -0,0 +1,22 @@
1
+ import { Breadcrumbs } from '../components/Breadcrumbs';
2
+ export const EXAMPLE_BREADCRUMBS = [
3
+ { title: 'Home', nav: '/' },
4
+ { title: 'Products', nav: '/products' },
5
+ { title: 'Electronics', nav: '/products/electronics' },
6
+ { title: 'Laptops', nav: '/products/electronics/laptops' },
7
+ { title: 'Gaming Laptops' },
8
+ ];
9
+ const meta = {
10
+ title: 'Navigation/Breadcrumbs',
11
+ component: Breadcrumbs,
12
+ tags: ['autodocs'],
13
+ parameters: {
14
+ layout: 'fullscreen',
15
+ },
16
+ };
17
+ export default meta;
18
+ export const Component = {
19
+ args: {
20
+ breadcrumbs: EXAMPLE_BREADCRUMBS
21
+ }
22
+ };
@@ -0,0 +1,24 @@
1
+ import type { StoryObj } from '@storybook/react-vite';
2
+ declare const meta: {
3
+ title: string;
4
+ component: import("react").ForwardRefExoticComponent<import("../components").IFrameProps & import("react").RefAttributes<HTMLDivElement>>;
5
+ tags: string[];
6
+ parameters: {
7
+ layout: string;
8
+ };
9
+ args: {
10
+ headerProps: {
11
+ appName: string;
12
+ logo: {
13
+ light: string;
14
+ dark: string;
15
+ };
16
+ menu: import("react/jsx-runtime").JSX.Element;
17
+ version: string;
18
+ };
19
+ children: import("react/jsx-runtime").JSX.Element;
20
+ };
21
+ };
22
+ export default meta;
23
+ type Story = StoryObj<typeof meta>;
24
+ export declare const Component: Story;
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import packageJson from '../../package.json';
3
+ import { Frame } from '../components/Frame';
4
+ import { Heading } from '@chakra-ui/react';
5
+ import { Menu } from '../components/Menu';
6
+ import { SidebarProvider, SidebarToggleButton } from '../components/Sidebar';
7
+ import { SIDEBAR_MENU } from './Sidebar.stories';
8
+ import { Page } from '../components/Page';
9
+ import { EXAMPLE_BREADCRUMBS } from './Breadcrumbs.stories';
10
+ import { useIsMobile } from '../hooks/useIsMobile';
11
+ import { AvatarIconMenu } from '../components/AvatarIconMenu';
12
+ const logo = {
13
+ light: '/logo_hyperion_official.svg',
14
+ dark: '/logo_hyperion_official_white.svg',
15
+ };
16
+ const menu = (_jsx(AvatarIconMenu, { name: "Segun Adebayo", src: "https://bit.ly/sage-adebayo", menu: [
17
+ { label: 'Account', value: 'account' },
18
+ { label: 'Settings', value: 'settings' },
19
+ { label: 'Logout', value: 'logout' },
20
+ ] }));
21
+ const meta = {
22
+ title: 'Frame/Frame',
23
+ component: Frame,
24
+ tags: ['autodocs'],
25
+ parameters: {
26
+ layout: 'fullscreen',
27
+ },
28
+ args: {
29
+ headerProps: {
30
+ appName: 'My Application',
31
+ logo,
32
+ menu,
33
+ version: packageJson.version,
34
+ },
35
+ children: (_jsx(Page, { breadcrumbs: EXAMPLE_BREADCRUMBS, children: _jsx(Heading, { children: "Gaming Laptops" }) })),
36
+ },
37
+ };
38
+ export default meta;
39
+ export const Component = {
40
+ args: {
41
+ headerProps: {
42
+ appName: 'My Application',
43
+ logo,
44
+ menu,
45
+ version: packageJson.version,
46
+ },
47
+ children: (_jsx(Page, { breadcrumbs: EXAMPLE_BREADCRUMBS, children: _jsx(Heading, { children: "Gaming Laptops" }) })),
48
+ },
49
+ decorators: [
50
+ (Story) => {
51
+ const isMobile = useIsMobile();
52
+ const isSidebarOpen = !isMobile;
53
+ return (_jsxs(SidebarProvider, { isOpen: isSidebarOpen, menu: _jsx(Menu, { label: 'Sidebar Menu', menuItems: SIDEBAR_MENU }), children: [_jsx(Story, {}), isMobile && _jsx(SidebarToggleButton, { name: 'sidebar-toggle', "aria-label": 'Toggle sidebar' })] }));
54
+ },
55
+ ],
56
+ };
@@ -0,0 +1,22 @@
1
+ import type { StoryObj } from '@storybook/react-vite';
2
+ declare const meta: {
3
+ title: string;
4
+ component: import("react").ForwardRefExoticComponent<import("../components").IHeaderProps & import("react").RefAttributes<HTMLDivElement>>;
5
+ tags: string[];
6
+ parameters: {
7
+ layout: string;
8
+ };
9
+ args: {
10
+ appName: string;
11
+ logo: {
12
+ light: string;
13
+ dark: string;
14
+ };
15
+ menu: null;
16
+ version: string;
17
+ };
18
+ };
19
+ export default meta;
20
+ type Story = StoryObj<typeof meta>;
21
+ export declare const LoggedIn: Story;
22
+ export declare const LoggedOut: Story;
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import packageJson from '../../package.json';
3
+ import { Header } from '../components/Header';
4
+ import { Avatar } from '@chakra-ui/react';
5
+ const logo = {
6
+ light: '/logo_hyperion_official.svg',
7
+ dark: '/logo_hyperion_official_white.svg',
8
+ };
9
+ const meta = {
10
+ title: 'Frame/Header',
11
+ component: Header,
12
+ tags: ['autodocs'],
13
+ parameters: {
14
+ layout: 'fullscreen',
15
+ },
16
+ args: {
17
+ appName: 'My Application',
18
+ logo,
19
+ menu: null,
20
+ version: packageJson.version,
21
+ },
22
+ };
23
+ export default meta;
24
+ export const LoggedIn = {
25
+ args: {
26
+ appName: 'My Application',
27
+ logo,
28
+ menu: (_jsxs(Avatar.Root, { children: [_jsx(Avatar.Fallback, { name: "Segun Adebayo" }), _jsx(Avatar.Image, { src: "https://bit.ly/sage-adebayo" })] })),
29
+ version: packageJson.version,
30
+ }
31
+ };
32
+ export const LoggedOut = {
33
+ args: {
34
+ appName: 'My Application',
35
+ logo,
36
+ menu: null,
37
+ version: packageJson.version,
38
+ }
39
+ };
@@ -0,0 +1,12 @@
1
+ import type { StoryObj } from '@storybook/react-vite';
2
+ declare const meta: {
3
+ title: string;
4
+ component: import("react").ForwardRefExoticComponent<import("../components").IMenuProps & import("react").RefAttributes<unknown>>;
5
+ tags: string[];
6
+ parameters: {
7
+ layout: string;
8
+ };
9
+ };
10
+ export default meta;
11
+ type Story = StoryObj<typeof meta>;
12
+ export declare const Component: Story;
@@ -0,0 +1,17 @@
1
+ import { Menu } from '../components/Menu';
2
+ import { SIDEBAR_MENU } from './Sidebar.stories';
3
+ const meta = {
4
+ title: 'Navigation/Menu',
5
+ component: Menu,
6
+ tags: ['autodocs'],
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ },
10
+ };
11
+ export default meta;
12
+ export const Component = {
13
+ args: {
14
+ label: 'Example Menu',
15
+ menuItems: SIDEBAR_MENU
16
+ }
17
+ };
@@ -0,0 +1,16 @@
1
+ import type { StoryObj } from '@storybook/react-vite';
2
+ export declare const SIDEBAR_MENU: {
3
+ label: string;
4
+ value: string;
5
+ }[];
6
+ declare const meta: {
7
+ title: string;
8
+ component: import("react").ForwardRefExoticComponent<import("react").RefAttributes<HTMLDivElement>>;
9
+ tags: string[];
10
+ parameters: {
11
+ layout: string;
12
+ };
13
+ };
14
+ export default meta;
15
+ type Story = StoryObj<typeof meta>;
16
+ export declare const Component: Story;
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Sidebar, SidebarProvider } from '../components/Sidebar';
3
+ import { Menu } from '../components/Menu';
4
+ export const SIDEBAR_MENU = [
5
+ { label: 'Dashboard', value: 'dashboard' },
6
+ { label: 'Settings', value: 'settings' },
7
+ { label: 'Profile', value: 'profile' },
8
+ { label: 'Logout', value: 'logout' },
9
+ ];
10
+ const meta = {
11
+ title: 'Frame/Sidebar',
12
+ component: Sidebar,
13
+ tags: ['autodocs'],
14
+ parameters: {
15
+ layout: 'fullscreen',
16
+ },
17
+ };
18
+ export default meta;
19
+ export const Component = {
20
+ decorators: [
21
+ (Story) => {
22
+ return (_jsx(SidebarProvider, { isOpen: true, menu: _jsx(Menu, { label: 'Sidebar Menu', menuItems: SIDEBAR_MENU }), children: _jsx(Story, {}) }));
23
+ },
24
+ ],
25
+ };
@@ -0,0 +1,5 @@
1
+ export interface ICalculate {
2
+ age: (date: Date) => number;
3
+ daysBetweenDates: (first: Date, second: Date) => number;
4
+ }
5
+ export declare const calculate: ICalculate;
@@ -0,0 +1,15 @@
1
+ export const calculate = {
2
+ age: (date) => {
3
+ const today = new Date();
4
+ const birthDateObj = new Date(date);
5
+ let age = today.getFullYear() - birthDateObj.getFullYear();
6
+ const monthDiff = today.getMonth() - birthDateObj.getMonth();
7
+ if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDateObj.getDate())) {
8
+ age--;
9
+ }
10
+ return age;
11
+ },
12
+ daysBetweenDates(first, second) {
13
+ return Math.round((second.getTime() - first.getTime()) / (24 * 60 * 60 * 1000));
14
+ }
15
+ };
@@ -0,0 +1,5 @@
1
+ export interface ICookies {
2
+ set: (name: string, value: string, expiresInMilliseconds?: number) => void;
3
+ get: (name: string) => string;
4
+ }
5
+ export declare const cookies: ICookies;
@@ -0,0 +1,26 @@
1
+ export const cookies = {
2
+ set: (name, value, expiresInMilliseconds) => {
3
+ let expires;
4
+ if (!!expiresInMilliseconds) {
5
+ const date = new Date();
6
+ date.setTime(date.getTime() + expiresInMilliseconds);
7
+ expires = `expires=${date};`;
8
+ }
9
+ document.cookie = `${name}=${value};${!!expires ? expires : ''}path/;SameSite=Lax`;
10
+ },
11
+ get: (name) => {
12
+ name = `${name}=`;
13
+ const decodedCookie = decodeURIComponent(document.cookie);
14
+ const cookies = decodedCookie.split(';');
15
+ for (let i = 0; i < cookies.length; i++) {
16
+ let cookie = cookies[i];
17
+ while (cookie.charAt(0) === ' ') {
18
+ cookie = cookie.substring(1);
19
+ }
20
+ if (cookie.indexOf(name) === 0) {
21
+ return cookie.substring(name.length, cookie.length);
22
+ }
23
+ }
24
+ return '';
25
+ }
26
+ };
@@ -0,0 +1,6 @@
1
+ import * as React from 'react';
2
+ import { AxiosResponse } from 'axios';
3
+ export interface IData {
4
+ handleDataState: (getCollection: (query: string) => Promise<AxiosResponse<any>>, setCollection: React.Dispatch<React.SetStateAction<any>>, setError: React.Dispatch<React.SetStateAction<string>>, setIsLoading: React.Dispatch<React.SetStateAction<any>>, query?: string) => (dataState: any) => void;
5
+ }
6
+ export declare const data: IData;
@@ -0,0 +1,20 @@
1
+ export const data = {
2
+ handleDataState: (getCollection, setCollection, setError, setIsLoading, query) => async (dataState) => {
3
+ setIsLoading(true);
4
+ try {
5
+ const { data: { data, meta: { total } } } = await getCollection(makeQuery(dataState, query));
6
+ setCollection({ data, total });
7
+ }
8
+ catch ({ response: { data: { message: error } } }) {
9
+ setError(error);
10
+ }
11
+ finally {
12
+ setIsLoading(false);
13
+ }
14
+ },
15
+ };
16
+ function makeQuery(dataState, additionalQuery) {
17
+ const { pageNumber, pageSize } = dataState;
18
+ const query = `?page=${pageNumber}&per_page=${pageSize}${!!additionalQuery ? additionalQuery : ''}`;
19
+ return query;
20
+ }
@@ -0,0 +1,23 @@
1
+ export interface IFormat {
2
+ lettersOnly: (value: string) => string;
3
+ lettersOnlyPlusSpace: (value: string) => string;
4
+ alphaNumeric: (value: string) => string;
5
+ alphaNumericPlusSpace: (value: string) => string;
6
+ numeric: (value: string) => string;
7
+ decimal: (value: string) => string;
8
+ maxChars: (value: string, max: number) => string;
9
+ capitalizeFirstLetter: (value: string) => string;
10
+ convertToTitleCase: (value: string) => string;
11
+ emailAddress: (emailAddress: string) => string;
12
+ currency: (value: number) => string;
13
+ currencyRound: (value: number) => string;
14
+ number: (value: number) => string;
15
+ stripNumberFormatting: (value: string) => number;
16
+ stripCurrencyFormatting: (value: string) => string;
17
+ roundNumber: (value: number, decimals: number) => number;
18
+ tel: (value: number) => string;
19
+ ssn: (value: string) => string;
20
+ ein: (value: string) => string;
21
+ convertToStandardCase: (str: string, delimiter: '_' | '-' | ' ' | ',') => string;
22
+ }
23
+ export declare const format: IFormat;
@@ -0,0 +1,76 @@
1
+ const l10nUSD = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
2
+ const l10nEN = new Intl.NumberFormat('en-US');
3
+ export const format = {
4
+ lettersOnly: (value) => value.replace(/[^A-Za-z?]/g, ''),
5
+ lettersOnlyPlusSpace: (value) => value.replace(/[^A-Za-z?\s]/g, ''),
6
+ alphaNumeric: (value) => value.replace(/[^a-z0-9]/gi, ''),
7
+ alphaNumericPlusSpace: (value) => value.replace(/[^a-z0-9\s]/gi, ''),
8
+ numeric: (value) => value.replace(/[^0-9]/gi, ''),
9
+ decimal: (value) => value.replace(/[^0-9.]/gi, ''),
10
+ maxChars: (value, max) => value.split('').map((x, i) => i < max).join(),
11
+ capitalizeFirstLetter: (value) => !!value ? value.charAt(0).toUpperCase() + value.split('').filter((x, i) => i > 0).join('').toLowerCase() : '',
12
+ convertToTitleCase: (value) => {
13
+ const parts = value.split('_');
14
+ const casedParts = parts.map(part => format.capitalizeFirstLetter(part));
15
+ return casedParts.join(' ');
16
+ },
17
+ emailAddress: (emailAddress) => {
18
+ return emailAddress.replace(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, '');
19
+ },
20
+ currency: (value) => l10nUSD.format(value),
21
+ currencyRound: (value) => {
22
+ const result = l10nUSD.format(value).toString();
23
+ return result.substr(0, result.length - 3);
24
+ },
25
+ number: (value) => l10nEN.format(value),
26
+ stripNumberFormatting: (value) => Number(value.replace(/[^0-9.]/g, '')),
27
+ stripCurrencyFormatting: (value) => {
28
+ value = value.replace('$', '');
29
+ value = value.replace('.', '');
30
+ const num = Number(value.replace(/[^0-9.]/g, ''));
31
+ if (num < 10) {
32
+ value = `0.0${num}`;
33
+ }
34
+ else if (num < 100) {
35
+ value = `0.${num}`;
36
+ }
37
+ else {
38
+ const str = num.toString();
39
+ value = str.substr(0, str.length - 2) + '.' + str.substr(str.length - 2, 2);
40
+ }
41
+ return parseFloat(value).toFixed(2);
42
+ },
43
+ roundNumber: (value, decimals) => {
44
+ return Number(Math.round(Number(value + 'e' + decimals)) + 'e-' + decimals);
45
+ },
46
+ tel: (value) => {
47
+ const telUnformatted = value.toString();
48
+ const telParts = telUnformatted.split('');
49
+ const telPart1 = telParts.filter((part, key) => key < 3).join('');
50
+ const telPart2 = telParts.filter((part, key) => key > 2 && key < 6).join('');
51
+ const telPart3 = telParts.filter((part, key) => key > 5).join('');
52
+ return `(${telPart1}) ${telPart2}-${telPart3}`;
53
+ },
54
+ ssn: (value) => {
55
+ const ssnUnformatted = format.numeric(value);
56
+ const ssnParts = ssnUnformatted.split('');
57
+ const ssnPart1 = ssnParts.filter((part, key) => key < 3).join('');
58
+ const ssnPart2 = ssnParts.filter((part, key) => key > 2 && key < 5).join('');
59
+ const ssnPart3 = ssnParts.filter((part, key) => key > 4).join('');
60
+ return `${ssnPart1}-${ssnPart2}-${ssnPart3}`;
61
+ },
62
+ ein: (value) => {
63
+ const einUnformatted = format.numeric(value);
64
+ const einParts = einUnformatted.split('');
65
+ const einPart1 = einParts.filter((part, key) => key < 2).join('');
66
+ const einPart2 = einParts.filter((part, key) => key > 1).join('');
67
+ return `${einPart1}-${einPart2}`;
68
+ },
69
+ convertToStandardCase: (str, delimiter) => {
70
+ const upperCaseFirstLetters = str
71
+ .split(delimiter)
72
+ .map(part => part.charAt(0).toUpperCase() + part.substring(1, part.length))
73
+ .join(' ');
74
+ return upperCaseFirstLetters;
75
+ }
76
+ };
@@ -0,0 +1,14 @@
1
+ import { ICookies } from './cookies';
2
+ import { IFormat } from './format';
3
+ import { IValidation } from './validation';
4
+ import { IData } from './data';
5
+ import { ICalculate } from './calculate';
6
+ export interface IUtils {
7
+ format: IFormat;
8
+ validation: IValidation;
9
+ cookies: ICookies;
10
+ data: IData;
11
+ calculate: ICalculate;
12
+ }
13
+ declare const utils: IUtils;
14
+ export default utils;
@@ -0,0 +1,13 @@
1
+ import { cookies } from './cookies';
2
+ import { format } from './format';
3
+ import { validation } from './validation';
4
+ import { data } from './data';
5
+ import { calculate } from './calculate';
6
+ const utils = {
7
+ cookies,
8
+ format,
9
+ validation,
10
+ data,
11
+ calculate,
12
+ };
13
+ export default utils;
@@ -0,0 +1,13 @@
1
+ export interface IValidation {
2
+ emailAddress: (emailAddress: string) => string;
3
+ emailAddressMatching: (emailAddress1: string, emailAddress2: string) => string;
4
+ minChars: (label: string, value: string, min: number) => string;
5
+ maxChars: (label: string, value: string, max: number) => string;
6
+ password: (password: string) => any;
7
+ creditCardNumber: (ccNum: string) => string;
8
+ mobile: () => boolean;
9
+ date: (date: any) => string;
10
+ nameFirstAndLast: (name: string) => string;
11
+ numeric: (label: string, value: string) => string;
12
+ }
13
+ export declare const validation: IValidation;
@@ -0,0 +1,66 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import owasp from 'owasp-password-strength-test';
3
+ export const validation = {
4
+ emailAddress: (emailAddress) => {
5
+ const test = /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,12})+$/.test(emailAddress);
6
+ return test || !emailAddress ? '' : 'Enter a valid email address';
7
+ },
8
+ emailAddressMatching: (emailAddress1, emailAddress2) => {
9
+ const test = emailAddress1 === emailAddress2;
10
+ return test || !emailAddress1 ? '' : 'Email addresses do not match';
11
+ },
12
+ minChars: (label, value, min) => {
13
+ const test = value.length >= min;
14
+ return test || !value ? '' : `${label} must contain at least ${min} characters`;
15
+ },
16
+ maxChars: (label, value, max) => {
17
+ const test = value.length <= max;
18
+ return test || !value ? '' : `${label} must contain ${max} characters or less`;
19
+ },
20
+ password: (password) => {
21
+ const result = owasp.test(password);
22
+ if (result.errors.length) {
23
+ const errors = result.errors.map((error, key) => (_jsxs("span", { children: [_jsx("span", { children: error.replace('The password', '• ').replace('.', '') }), _jsx("br", {})] }, `span-error-${key}`)));
24
+ return errors;
25
+ }
26
+ return '';
27
+ },
28
+ mobile: () => {
29
+ let check = false;
30
+ (function (a) { if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4)))
31
+ check = true; })(navigator.userAgent || navigator.vendor);
32
+ check = check ?? /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
33
+ check = check ?? navigator.maxTouchPoints > 0;
34
+ return check;
35
+ },
36
+ creditCardNumber: (ccNum) => {
37
+ const visaRegEx = /^(?:4[0-9]{12}(?:[0-9]{3})?)$/;
38
+ const mastercardRegEx = /^(?:5[1-5][0-9]{14})$/;
39
+ const amexpRegEx = /^(?:3[47][0-9]{13})$/;
40
+ const discovRegEx = /^(?:6(?:011|5[0-9][0-9])[0-9]{12})$/;
41
+ let isValid = false;
42
+ if (visaRegEx.test(ccNum)) {
43
+ isValid = true;
44
+ }
45
+ else if (mastercardRegEx.test(ccNum)) {
46
+ isValid = true;
47
+ }
48
+ else if (amexpRegEx.test(ccNum)) {
49
+ isValid = true;
50
+ }
51
+ else if (discovRegEx.test(ccNum)) {
52
+ isValid = true;
53
+ }
54
+ return (isValid || !ccNum) ? '' : 'Enter a valid credit card number';
55
+ },
56
+ date: (date) => {
57
+ const d = new Date(date);
58
+ const test = d instanceof Date && !isNaN(d.getTime());
59
+ return test || !date ? '' : 'Enter a valid date in MM/DD/YYYY format';
60
+ },
61
+ nameFirstAndLast: (name) => !!name.split(' ')[1] ? '' : 'Enter your first and last name.',
62
+ numeric: (label, value) => {
63
+ const test = /^\d+$/.test(value);
64
+ return test || !value ? '' : `${label} must contain only numbers`;
65
+ }
66
+ };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@vrobots/storybook",
3
+ "private": false,
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc -declaration",
16
+ "lint": "eslint .",
17
+ "storybook": "storybook dev -p 6006",
18
+ "pre-publish": "rimraf dist; npm run build"
19
+ },
20
+ "dependencies": {
21
+ "@chakra-ui/react": "^3.32.0",
22
+ "@emotion/react": "^11.14.0",
23
+ "@storybook/addon-themes": "^10.2.6",
24
+ "axios": "^1.13.4",
25
+ "motion": "^12.34.0",
26
+ "next-themes": "^0.4.6",
27
+ "owasp-password-strength-test": "^1.3.0",
28
+ "react": "^19.2.0",
29
+ "react-dnd": "^16.0.1",
30
+ "react-dnd-html5-backend": "^16.0.1",
31
+ "react-dnd-touch-backend": "^16.0.1",
32
+ "react-dom": "^19.2.0",
33
+ "react-icons": "^5.5.0"
34
+ },
35
+ "devDependencies": {
36
+ "@chromatic-com/storybook": "^5.0.0",
37
+ "@eslint/js": "^9.39.1",
38
+ "@storybook/addon-a11y": "^10.2.6",
39
+ "@storybook/addon-docs": "^10.2.6",
40
+ "@storybook/addon-vitest": "^10.2.6",
41
+ "@storybook/react-vite": "^10.2.6",
42
+ "@types/node": "^24.10.1",
43
+ "@types/react": "^19.2.5",
44
+ "@types/react-dom": "^19.2.3",
45
+ "@vitejs/plugin-react": "^5.1.1",
46
+ "@vitest/browser-playwright": "^4.0.18",
47
+ "@vitest/coverage-v8": "^4.0.18",
48
+ "@vrobots/types": "^0.4.17",
49
+ "eslint": "^9.39.1",
50
+ "eslint-plugin-react-hooks": "^7.0.1",
51
+ "eslint-plugin-react-refresh": "^0.4.24",
52
+ "eslint-plugin-storybook": "^10.2.6",
53
+ "globals": "^16.5.0",
54
+ "playwright": "^1.58.1",
55
+ "rimraf": "^6.1.2",
56
+ "storybook": "^10.2.6",
57
+ "ts-node": "^10.9.2",
58
+ "typescript": "~5.9.3",
59
+ "typescript-eslint": "^8.46.4",
60
+ "vite": "^7.2.4",
61
+ "vitest": "^4.0.18"
62
+ }
63
+ }