@redacto.io/consent-sdk-react 4.0.0 → 5.0.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 (160) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/LICENSE +176 -0
  3. package/dist/index.js +231 -96
  4. package/dist/index.mjs +231 -96
  5. package/dist/privacy-center.d.mts +649 -0
  6. package/dist/privacy-center.d.ts +649 -0
  7. package/dist/privacy-center.js +20824 -0
  8. package/dist/privacy-center.mjs +20789 -0
  9. package/package.json +47 -3
  10. package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +6 -4
  11. package/src/RedactoNoticeConsent/api/index.ts +2 -0
  12. package/src/RedactoNoticeConsent/api/types.ts +2 -0
  13. package/src/RedactoNoticeConsent/components/DigiLockerCallback.tsx +128 -62
  14. package/src/RedactoNoticeConsent/language-codes.ts +97 -0
  15. package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx +0 -3
  16. package/src/RedactoNoticeConsentInline/api/index.ts +0 -1
  17. package/src/RedactoPrivacyCenter/PrivacyCenterActivityPage.tsx +19 -0
  18. package/src/RedactoPrivacyCenter/PrivacyCenterCaseDetailsPage.tsx +154 -0
  19. package/src/RedactoPrivacyCenter/PrivacyCenterConsentManagerPage.tsx +17 -0
  20. package/src/RedactoPrivacyCenter/PrivacyCenterFormPage.tsx +79 -0
  21. package/src/RedactoPrivacyCenter/PrivacyCenterHomePage.tsx +30 -0
  22. package/src/RedactoPrivacyCenter/PrivacyCenterLayout.tsx +173 -0
  23. package/src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx +55 -0
  24. package/src/RedactoPrivacyCenter/api/actions.ts +476 -0
  25. package/src/RedactoPrivacyCenter/api/client.ts +524 -0
  26. package/src/RedactoPrivacyCenter/api/config.ts +33 -0
  27. package/src/RedactoPrivacyCenter/api/fetcher.ts +181 -0
  28. package/src/RedactoPrivacyCenter/api/upload.ts +93 -0
  29. package/src/RedactoPrivacyCenter/assets/character.svg +31 -0
  30. package/src/RedactoPrivacyCenter/assets/fileAttach.svg +9 -0
  31. package/src/RedactoPrivacyCenter/assets/greenTick.svg +4 -0
  32. package/src/RedactoPrivacyCenter/assets/mail.svg +3 -0
  33. package/src/RedactoPrivacyCenter/assets/poweredByRedacto.svg +9 -0
  34. package/src/RedactoPrivacyCenter/assets/sentImg.svg +9 -0
  35. package/src/RedactoPrivacyCenter/assets/uploadFileIcon.svg +9 -0
  36. package/src/RedactoPrivacyCenter/components/ActivitiesList.tsx +272 -0
  37. package/src/RedactoPrivacyCenter/components/CaseDetails/AttachmentCard.tsx +38 -0
  38. package/src/RedactoPrivacyCenter/components/CaseDetails/ChatBubble.tsx +31 -0
  39. package/src/RedactoPrivacyCenter/components/CaseDetails/DocumentRequestCard.tsx +73 -0
  40. package/src/RedactoPrivacyCenter/components/CaseDetails/MessageComposer.tsx +87 -0
  41. package/src/RedactoPrivacyCenter/components/CaseDetails/MessageItem.tsx +95 -0
  42. package/src/RedactoPrivacyCenter/components/CaseDetails/MessagesTab.tsx +147 -0
  43. package/src/RedactoPrivacyCenter/components/CaseDetails/RequestDetailsTab.tsx +171 -0
  44. package/src/RedactoPrivacyCenter/components/CaseDetails/StatusEvent.tsx +23 -0
  45. package/src/RedactoPrivacyCenter/components/CaseDetails/useFileUpload.ts +116 -0
  46. package/src/RedactoPrivacyCenter/components/CaseDetails/useMessagePolling.ts +36 -0
  47. package/src/RedactoPrivacyCenter/components/CaseDetails/utils.ts +56 -0
  48. package/src/RedactoPrivacyCenter/components/CaseDetailsModal.tsx +469 -0
  49. package/src/RedactoPrivacyCenter/components/CaseHistory.tsx +426 -0
  50. package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +732 -0
  51. package/src/RedactoPrivacyCenter/components/ConsentManagerColumns.tsx +238 -0
  52. package/src/RedactoPrivacyCenter/components/ConsentManagerConstants.ts +7 -0
  53. package/src/RedactoPrivacyCenter/components/ConsentManagerTableSkeleton.tsx +155 -0
  54. package/src/RedactoPrivacyCenter/components/DataRequest/CorrectionDataSection.tsx +189 -0
  55. package/src/RedactoPrivacyCenter/components/DataRequest/GrievanceDataSection.tsx +118 -0
  56. package/src/RedactoPrivacyCenter/components/DataRequest/NominationDataSection.tsx +66 -0
  57. package/src/RedactoPrivacyCenter/components/DataRequest/PurposeSelectionSection.tsx +304 -0
  58. package/src/RedactoPrivacyCenter/components/Form.tsx +1596 -0
  59. package/src/RedactoPrivacyCenter/components/GrievanceTable.tsx +174 -0
  60. package/src/RedactoPrivacyCenter/components/GrievanceTablePagination.tsx +337 -0
  61. package/src/RedactoPrivacyCenter/components/ModifyConsentModal.tsx +330 -0
  62. package/src/RedactoPrivacyCenter/components/Pagination.tsx +140 -0
  63. package/src/RedactoPrivacyCenter/components/PrivacyCenterLayout.tsx +304 -0
  64. package/src/RedactoPrivacyCenter/components/RequestSubmit.tsx +232 -0
  65. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/SideBarPC.tsx +475 -0
  66. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/SideMenuPC.tsx +408 -0
  67. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/constants.tsx +42 -0
  68. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/menuItemsPC.tsx +1 -0
  69. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/types.ts +40 -0
  70. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/utils.ts +38 -0
  71. package/src/RedactoPrivacyCenter/components/ThemeTransitionOverlay.tsx +85 -0
  72. package/src/RedactoPrivacyCenter/components/activitiesColumns.tsx +141 -0
  73. package/src/RedactoPrivacyCenter/components/caseHistoryColumns.tsx +159 -0
  74. package/src/RedactoPrivacyCenter/components/constant.ts +16 -0
  75. package/src/RedactoPrivacyCenter/components/types.ts +76 -0
  76. package/src/RedactoPrivacyCenter/components/utils.tsx +10 -0
  77. package/src/RedactoPrivacyCenter/config/routes.ts +9 -0
  78. package/src/RedactoPrivacyCenter/config/table.ts +25 -0
  79. package/src/RedactoPrivacyCenter/context/AuthContext.tsx +137 -0
  80. package/src/RedactoPrivacyCenter/context/BaseUrlContext.tsx +41 -0
  81. package/src/RedactoPrivacyCenter/context/LocaleContext.tsx +11 -0
  82. package/src/RedactoPrivacyCenter/context/NavigationContext.tsx +96 -0
  83. package/src/RedactoPrivacyCenter/context/OrganizationContext.tsx +30 -0
  84. package/src/RedactoPrivacyCenter/context/PageChromeContext.tsx +60 -0
  85. package/src/RedactoPrivacyCenter/context/theme.tsx +127 -0
  86. package/src/RedactoPrivacyCenter/context/types.ts +14 -0
  87. package/src/RedactoPrivacyCenter/lib/api.ts +566 -0
  88. package/src/RedactoPrivacyCenter/lib/consent-manager/utils.tsx +63 -0
  89. package/src/RedactoPrivacyCenter/lib/constants.ts +161 -0
  90. package/src/RedactoPrivacyCenter/lib/i18n.ts +81 -0
  91. package/src/RedactoPrivacyCenter/lib/locales.ts +105 -0
  92. package/src/RedactoPrivacyCenter/lib/queries.ts +134 -0
  93. package/src/RedactoPrivacyCenter/lib/types.ts +531 -0
  94. package/src/RedactoPrivacyCenter/lib/useCurrentLanguage.ts +37 -0
  95. package/src/RedactoPrivacyCenter/lib/utils.ts +626 -0
  96. package/src/RedactoPrivacyCenter/locales/as/translation.json +280 -0
  97. package/src/RedactoPrivacyCenter/locales/bho/translation.json +280 -0
  98. package/src/RedactoPrivacyCenter/locales/bn/translation.json +280 -0
  99. package/src/RedactoPrivacyCenter/locales/brx/translation.json +280 -0
  100. package/src/RedactoPrivacyCenter/locales/doi/translation.json +280 -0
  101. package/src/RedactoPrivacyCenter/locales/en/translation.json +255 -0
  102. package/src/RedactoPrivacyCenter/locales/gom/translation.json +280 -0
  103. package/src/RedactoPrivacyCenter/locales/gu/translation.json +280 -0
  104. package/src/RedactoPrivacyCenter/locales/hi/translation.json +280 -0
  105. package/src/RedactoPrivacyCenter/locales/kn/translation.json +280 -0
  106. package/src/RedactoPrivacyCenter/locales/ks/translation.json +280 -0
  107. package/src/RedactoPrivacyCenter/locales/mai/translation.json +280 -0
  108. package/src/RedactoPrivacyCenter/locales/ml/translation.json +280 -0
  109. package/src/RedactoPrivacyCenter/locales/mni-Mtei/translation.json +280 -0
  110. package/src/RedactoPrivacyCenter/locales/mr/translation.json +280 -0
  111. package/src/RedactoPrivacyCenter/locales/ne/translation.json +280 -0
  112. package/src/RedactoPrivacyCenter/locales/or/translation.json +280 -0
  113. package/src/RedactoPrivacyCenter/locales/pa/translation.json +280 -0
  114. package/src/RedactoPrivacyCenter/locales/sa/translation.json +280 -0
  115. package/src/RedactoPrivacyCenter/locales/sat/translation.json +280 -0
  116. package/src/RedactoPrivacyCenter/locales/sd/translation.json +280 -0
  117. package/src/RedactoPrivacyCenter/locales/ta/translation.json +280 -0
  118. package/src/RedactoPrivacyCenter/locales/te/translation.json +280 -0
  119. package/src/RedactoPrivacyCenter/locales/ur/translation.json +280 -0
  120. package/src/RedactoPrivacyCenter/styles/base.css +117 -0
  121. package/src/RedactoPrivacyCenter/styles/injectStyles.ts +1725 -0
  122. package/src/RedactoPrivacyCenter/styles/pcStyles.ts +813 -0
  123. package/src/RedactoPrivacyCenter/styles/responsive.ts +138 -0
  124. package/src/RedactoPrivacyCenter/styles/variables.css +133 -0
  125. package/src/RedactoPrivacyCenter/table/AdvancedTable.tsx +367 -0
  126. package/src/RedactoPrivacyCenter/table/AdvancedTablePagination.tsx +476 -0
  127. package/src/RedactoPrivacyCenter/table/index.ts +2 -0
  128. package/src/RedactoPrivacyCenter/types/images.d.ts +29 -0
  129. package/src/RedactoPrivacyCenter/ui/Footer.tsx +75 -0
  130. package/src/RedactoPrivacyCenter/ui/FormBlockWrapper.tsx +54 -0
  131. package/src/RedactoPrivacyCenter/ui/PCAccordion.tsx +93 -0
  132. package/src/RedactoPrivacyCenter/ui/PCActionIcon.tsx +47 -0
  133. package/src/RedactoPrivacyCenter/ui/PCAvatar.tsx +69 -0
  134. package/src/RedactoPrivacyCenter/ui/PCBadge.tsx +48 -0
  135. package/src/RedactoPrivacyCenter/ui/PCButton.tsx +77 -0
  136. package/src/RedactoPrivacyCenter/ui/PCCheckbox.tsx +55 -0
  137. package/src/RedactoPrivacyCenter/ui/PCCollapse.tsx +107 -0
  138. package/src/RedactoPrivacyCenter/ui/PCEmpty.tsx +35 -0
  139. package/src/RedactoPrivacyCenter/ui/PCInput.tsx +132 -0
  140. package/src/RedactoPrivacyCenter/ui/PCLoader.tsx +31 -0
  141. package/src/RedactoPrivacyCenter/ui/PCModal.tsx +106 -0
  142. package/src/RedactoPrivacyCenter/ui/PCPopover.tsx +173 -0
  143. package/src/RedactoPrivacyCenter/ui/PCSelect.tsx +387 -0
  144. package/src/RedactoPrivacyCenter/ui/PCTable.tsx +149 -0
  145. package/src/RedactoPrivacyCenter/ui/PCText.tsx +41 -0
  146. package/src/RedactoPrivacyCenter/ui/PCTextarea.tsx +43 -0
  147. package/src/RedactoPrivacyCenter/ui/PCTitle.tsx +37 -0
  148. package/src/RedactoPrivacyCenter/ui/PCTooltip.tsx +119 -0
  149. package/src/RedactoPrivacyCenter/ui/SimpleBar.tsx +25 -0
  150. package/src/RedactoPrivacyCenter/ui/StatusBadge.tsx +53 -0
  151. package/src/RedactoPrivacyCenter/ui/ThemeToggle.tsx +72 -0
  152. package/src/RedactoPrivacyCenter/ui/index.ts +18 -0
  153. package/src/RedactoPrivacyCenter/utils/cn.ts +28 -0
  154. package/src/RedactoPrivacyCenter/utils/date.ts +48 -0
  155. package/src/RedactoPrivacyCenter/utils/status.ts +111 -0
  156. package/src/RedactoPrivacyCenter/utils/toast.ts +130 -0
  157. package/src/privacy-center.ts +108 -0
  158. package/tsconfig.json +2 -0
  159. package/tsup.config.ts +16 -1
  160. package/.turbo/turbo-build.log +0 -21
@@ -0,0 +1,93 @@
1
+ import { type ReactNode, type CSSProperties, type HTMLAttributes } from 'react';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+
4
+ export type PCAccordionProps = Readonly<
5
+ HTMLAttributes<HTMLDivElement> & {
6
+ children: ReactNode;
7
+ className?: string;
8
+ style?: CSSProperties;
9
+ }
10
+ >;
11
+
12
+ export function PCAccordion({ children, className = '', style = {}, ...props }: PCAccordionProps) {
13
+ const accordionStyle: CSSProperties = {
14
+ ...pcStyles.accordion,
15
+ ...style,
16
+ };
17
+
18
+ return (
19
+ <div className={`pc-accordion ${className}`} style={accordionStyle} {...props}>
20
+ {children}
21
+ </div>
22
+ );
23
+ }
24
+
25
+ export type PCAccordionHeaderProps = Readonly<
26
+ Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
27
+ children: ReactNode | ((props: { open: boolean; toggle: () => void }) => ReactNode);
28
+ className?: string;
29
+ style?: CSSProperties;
30
+ open?: boolean;
31
+ onToggle?: () => void;
32
+ }
33
+ >;
34
+
35
+ export function PCAccordionHeader({
36
+ children,
37
+ className = '',
38
+ style = {},
39
+ open = false,
40
+ onToggle,
41
+ ...props
42
+ }: PCAccordionHeaderProps) {
43
+ const headerStyle: CSSProperties = {
44
+ ...pcStyles.accordionHeader,
45
+ ...style,
46
+ };
47
+
48
+ return (
49
+ <div
50
+ className={`pc-accordion-header ${className}`}
51
+ style={headerStyle}
52
+ onClick={onToggle}
53
+ {...props}
54
+ >
55
+ {typeof children === 'function' ? children({ open, toggle: onToggle || (() => {}) }) : children}
56
+ </div>
57
+ );
58
+ }
59
+
60
+ export type PCAccordionBodyProps = Readonly<
61
+ HTMLAttributes<HTMLDivElement> & {
62
+ children: ReactNode;
63
+ className?: string;
64
+ style?: CSSProperties;
65
+ open?: boolean;
66
+ }
67
+ >;
68
+
69
+ export function PCAccordionBody({
70
+ children,
71
+ className = '',
72
+ style = {},
73
+ open = false,
74
+ ...props
75
+ }: PCAccordionBodyProps) {
76
+ const bodyStyle: CSSProperties = {
77
+ ...pcStyles.accordionBody,
78
+ maxHeight: open ? '1000px' : '0',
79
+ overflow: open ? 'visible' : 'hidden',
80
+ padding: open ? pcStyles.accordionBody.padding : '0',
81
+ ...style,
82
+ };
83
+
84
+ return (
85
+ <div className={`pc-accordion-body ${className}`} style={bodyStyle} {...props}>
86
+ {children}
87
+ </div>
88
+ );
89
+ }
90
+
91
+ // Compound component pattern
92
+ PCAccordion.Header = PCAccordionHeader;
93
+ PCAccordion.Body = PCAccordionBody;
@@ -0,0 +1,47 @@
1
+ import { type ReactNode, type CSSProperties, type ButtonHTMLAttributes, forwardRef } from 'react';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+
4
+ export interface PCActionIconProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'style'> {
5
+ children: ReactNode;
6
+ className?: string;
7
+ style?: CSSProperties;
8
+ variant?: 'default' | 'outline';
9
+ size?: 'sm' | 'md';
10
+ disabled?: boolean;
11
+ 'aria-label': string;
12
+ }
13
+
14
+ export const PCActionIcon = forwardRef<HTMLButtonElement, PCActionIconProps>(({
15
+ children,
16
+ className = '',
17
+ style = {},
18
+ variant = 'default',
19
+ size = 'md',
20
+ disabled = false,
21
+ type = 'button',
22
+ ...props
23
+ }, ref) => {
24
+ const baseStyle: CSSProperties = {
25
+ ...pcStyles.actionIcon,
26
+ ...(variant === 'outline' && pcStyles.actionIconOutline),
27
+ ...(size === 'sm' && pcStyles.actionIconSm),
28
+ ...(size === 'md' && pcStyles.actionIconMd),
29
+ ...(disabled && pcStyles.actionIconDisabled),
30
+ ...style,
31
+ };
32
+
33
+ return (
34
+ <button
35
+ ref={ref}
36
+ type={type}
37
+ className={`pc-action-icon ${className}`}
38
+ style={baseStyle}
39
+ disabled={disabled}
40
+ {...props}
41
+ >
42
+ {children}
43
+ </button>
44
+ );
45
+ });
46
+
47
+ PCActionIcon.displayName = 'PCActionIcon';
@@ -0,0 +1,69 @@
1
+ import { type CSSProperties } from 'react';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+
4
+ export interface PCAvatarProps {
5
+ name?: string;
6
+ src?: string;
7
+ className?: string;
8
+ style?: CSSProperties;
9
+ size?: 'sm' | 'md' | 'lg';
10
+ color?: 'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'info';
11
+ }
12
+
13
+ function getInitials(name: string): string {
14
+ return name
15
+ .split(' ')
16
+ .map((n) => n[0])
17
+ .join('')
18
+ .toUpperCase()
19
+ .slice(0, 2);
20
+ }
21
+
22
+ function getColor(color: string): string {
23
+ const colorMap: Record<string, string> = {
24
+ primary: getVar('--pc-primary'),
25
+ secondary: getVar('--pc-secondary'),
26
+ success: getVar('--pc-success'),
27
+ error: getVar('--pc-error'),
28
+ warning: getVar('--pc-warning'),
29
+ info: getVar('--pc-info'),
30
+ };
31
+ return colorMap[color] || colorMap.primary;
32
+ }
33
+
34
+ const getVar = (varName: string): string => `var(${varName})`;
35
+
36
+ export function PCAvatar({
37
+ name = '',
38
+ src,
39
+ className = '',
40
+ style = {},
41
+ size = 'md',
42
+ color = 'primary',
43
+ }: PCAvatarProps) {
44
+ const avatarStyle: CSSProperties = {
45
+ ...pcStyles.avatar,
46
+ ...(size === 'sm' && pcStyles.avatarSm),
47
+ ...(size === 'md' && pcStyles.avatarMd),
48
+ ...(size === 'lg' && pcStyles.avatarLg),
49
+ backgroundColor: getColor(color),
50
+ ...style,
51
+ };
52
+
53
+ if (src) {
54
+ return (
55
+ <img
56
+ src={src}
57
+ alt={name}
58
+ className={className}
59
+ style={avatarStyle}
60
+ />
61
+ );
62
+ }
63
+
64
+ return (
65
+ <div className={className} style={avatarStyle}>
66
+ {name ? getInitials(name) : '?'}
67
+ </div>
68
+ );
69
+ }
@@ -0,0 +1,48 @@
1
+ import { type ReactNode, type CSSProperties } from 'react';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+
4
+ export interface PCBadgeProps {
5
+ children: ReactNode;
6
+ className?: string;
7
+ style?: CSSProperties;
8
+ variant?: 'success' | 'error' | 'warning' | 'info' | 'secondary';
9
+ size?: 'sm' | 'md';
10
+ renderAsDot?: boolean;
11
+ }
12
+
13
+ export function PCBadge({
14
+ children,
15
+ className = '',
16
+ style = {},
17
+ variant = 'secondary',
18
+ size = 'md',
19
+ renderAsDot = false,
20
+ }: PCBadgeProps) {
21
+ const badgeStyle: CSSProperties = {
22
+ ...pcStyles.badge,
23
+ ...(variant === 'success' && pcStyles.badgeSuccess),
24
+ ...(variant === 'error' && pcStyles.badgeError),
25
+ ...(variant === 'warning' && pcStyles.badgeWarning),
26
+ ...(variant === 'info' && pcStyles.badgeInfo),
27
+ ...(variant === 'secondary' && pcStyles.badgeSecondary),
28
+ ...(size === 'sm' && pcStyles.badgeSm),
29
+ ...(renderAsDot && {
30
+ width: size === 'sm' ? '6px' : '8px',
31
+ height: size === 'sm' ? '6px' : '8px',
32
+ padding: 0,
33
+ borderRadius: '50%',
34
+ display: 'inline-block',
35
+ }),
36
+ ...style,
37
+ };
38
+
39
+ if (renderAsDot) {
40
+ return <span className={className} style={badgeStyle} />;
41
+ }
42
+
43
+ return (
44
+ <span className={className} style={badgeStyle}>
45
+ {children}
46
+ </span>
47
+ );
48
+ }
@@ -0,0 +1,77 @@
1
+ import { type ReactNode, type CSSProperties, type ButtonHTMLAttributes } from 'react';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+
4
+ const getVar = (varName: string): string => `var(${varName})`;
5
+
6
+ export interface PCButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'style'> {
7
+ children: ReactNode;
8
+ className?: string;
9
+ style?: CSSProperties;
10
+ variant?: 'primary' | 'secondary' | 'outline' | 'text' | 'danger';
11
+ size?: 'sm' | 'md' | 'lg';
12
+ isLoading?: boolean;
13
+ disabled?: boolean;
14
+ }
15
+
16
+ export function PCButton({
17
+ children,
18
+ className = '',
19
+ style = {},
20
+ variant = 'primary',
21
+ size = 'md',
22
+ isLoading = false,
23
+ disabled = false,
24
+ type = 'button',
25
+ ...props
26
+ }: PCButtonProps) {
27
+ const variantClass = `pc-button-${variant}`;
28
+ const baseStyle: CSSProperties = {
29
+ ...pcStyles.button,
30
+ ...(variant === 'primary' && pcStyles.buttonPrimary),
31
+ ...(variant === 'secondary' && pcStyles.buttonSecondary),
32
+ ...(variant === 'outline' && pcStyles.buttonOutline),
33
+ ...(variant === 'text' && pcStyles.buttonText),
34
+ ...(variant === 'danger' && pcStyles.buttonDanger),
35
+ ...(size === 'sm' && pcStyles.buttonSm),
36
+ ...(size === 'lg' && pcStyles.buttonLg),
37
+ ...(disabled && pcStyles.buttonDisabled),
38
+ ...style,
39
+ };
40
+
41
+ // Determine loader color based on variant
42
+ const loaderColor = variant === 'primary' || variant === 'danger' || variant === 'secondary'
43
+ ? 'inverse'
44
+ : 'primary';
45
+
46
+ return (
47
+ <button
48
+ type={type}
49
+ className={`pc-button ${variantClass} ${className}`}
50
+ style={baseStyle}
51
+ disabled={disabled || isLoading}
52
+ {...props}
53
+ >
54
+ {isLoading ? (
55
+ <span style={{
56
+ display: 'inline-flex',
57
+ alignItems: 'center',
58
+ justifyContent: 'center',
59
+ gap: '6px',
60
+ }}>
61
+ <div style={{
62
+ ...pcStyles.loader,
63
+ ...pcStyles.loaderMd,
64
+ ...(loaderColor === 'inverse'
65
+ ? { borderColor: `${getVar('--pc-text-inverse')} transparent ${getVar('--pc-text-inverse')} transparent` }
66
+ : pcStyles.loaderPrimary
67
+ ),
68
+ }} />
69
+ {children}
70
+ </span>
71
+ ) : (
72
+ children
73
+ )}
74
+ </button>
75
+ );
76
+ }
77
+
@@ -0,0 +1,55 @@
1
+ import { type ReactNode, type CSSProperties, type InputHTMLAttributes } from 'react';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+
4
+ export interface PCCheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'style' | 'size' | 'type'> {
5
+ className?: string;
6
+ style?: CSSProperties;
7
+ label?: ReactNode;
8
+ labelClassName?: string;
9
+ size?: 'sm' | 'md';
10
+ checked?: boolean;
11
+ onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
12
+ }
13
+
14
+ export function PCCheckbox({
15
+ className = '',
16
+ style = {},
17
+ label,
18
+ labelClassName = '',
19
+ size = 'md',
20
+ checked,
21
+ onChange,
22
+ ...props
23
+ }: PCCheckboxProps) {
24
+ const checkboxStyle: CSSProperties = {
25
+ ...pcStyles.checkbox,
26
+ ...(size === 'sm' && pcStyles.checkboxSm),
27
+ ...style,
28
+ };
29
+
30
+ const labelStyle: CSSProperties = {
31
+ ...pcStyles.checkboxLabel,
32
+ };
33
+
34
+ const checkbox = (
35
+ <input
36
+ type="checkbox"
37
+ className={`pc-checkbox ${size === 'sm' ? 'pc-checkbox-sm' : ''} ${className}`}
38
+ style={checkboxStyle}
39
+ checked={checked}
40
+ onChange={onChange}
41
+ {...props}
42
+ />
43
+ );
44
+
45
+ if (label) {
46
+ return (
47
+ <label className={labelClassName} style={labelStyle}>
48
+ {checkbox}
49
+ <span>{label}</span>
50
+ </label>
51
+ );
52
+ }
53
+
54
+ return checkbox;
55
+ }
@@ -0,0 +1,107 @@
1
+ import { type ReactNode, type CSSProperties, type HTMLAttributes, useState } from 'react';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+
4
+ export type PCCollapseProps = Readonly<
5
+ Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
6
+ children: ReactNode | ((props: { open: boolean; toggle: () => void }) => ReactNode);
7
+ defaultOpen?: boolean;
8
+ className?: string;
9
+ style?: CSSProperties;
10
+ }
11
+ >;
12
+
13
+ export function PCCollapse({
14
+ children,
15
+ defaultOpen = false,
16
+ className = '',
17
+ style = {},
18
+ ...props
19
+ }: PCCollapseProps) {
20
+ const [open, setOpen] = useState(defaultOpen);
21
+
22
+ const toggle = () => setOpen(!open);
23
+
24
+ const collapseStyle: CSSProperties = {
25
+ ...style,
26
+ };
27
+
28
+ return (
29
+ <div className={`pc-collapse ${className}`} style={collapseStyle} {...props}>
30
+ {typeof children === 'function' ? children({ open, toggle }) : children}
31
+ </div>
32
+ );
33
+ }
34
+
35
+ export type PCCollapseHeaderProps = Readonly<
36
+ Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
37
+ children: ReactNode | ((props: { open: boolean; toggle: () => void }) => ReactNode);
38
+ className?: string;
39
+ style?: CSSProperties;
40
+ open?: boolean;
41
+ toggle?: () => void;
42
+ }
43
+ >;
44
+
45
+ export function PCCollapseHeader({
46
+ children,
47
+ className = '',
48
+ style = {},
49
+ open = false,
50
+ toggle,
51
+ ...props
52
+ }: PCCollapseHeaderProps) {
53
+ const headerStyle: CSSProperties = {
54
+ ...pcStyles.accordionHeader,
55
+ ...style,
56
+ };
57
+
58
+ const rendered: ReactNode = typeof children === 'function'
59
+ ? children({ open, toggle: toggle || (() => {}) })
60
+ : children;
61
+
62
+ return (
63
+ <div
64
+ className={`pc-collapse-header ${className}`}
65
+ style={headerStyle}
66
+ onClick={toggle}
67
+ {...props}
68
+ >
69
+ {rendered}
70
+ </div>
71
+ );
72
+ }
73
+
74
+ export type PCCollapseBodyProps = Readonly<
75
+ HTMLAttributes<HTMLDivElement> & {
76
+ children: ReactNode;
77
+ className?: string;
78
+ style?: CSSProperties;
79
+ open?: boolean;
80
+ }
81
+ >;
82
+
83
+ export function PCCollapseBody({
84
+ children,
85
+ className = '',
86
+ style = {},
87
+ open = false,
88
+ ...props
89
+ }: PCCollapseBodyProps) {
90
+ const bodyStyle: CSSProperties = {
91
+ ...pcStyles.accordionBody,
92
+ maxHeight: open ? '1000px' : '0',
93
+ overflow: open ? 'visible' : 'hidden',
94
+ padding: open ? pcStyles.accordionBody.padding : '0',
95
+ ...style,
96
+ };
97
+
98
+ return (
99
+ <div className={`pc-collapse-body ${className}`} style={bodyStyle} {...props}>
100
+ {children}
101
+ </div>
102
+ );
103
+ }
104
+
105
+ // Compound component pattern
106
+ PCCollapse.Header = PCCollapseHeader;
107
+ PCCollapse.Body = PCCollapseBody;
@@ -0,0 +1,35 @@
1
+ import { type ReactNode, type CSSProperties } from 'react';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+
4
+ export interface PCEmptyProps {
5
+ icon?: ReactNode;
6
+ title?: ReactNode;
7
+ description?: ReactNode;
8
+ className?: string;
9
+ style?: CSSProperties;
10
+ }
11
+
12
+ export function PCEmpty({
13
+ icon,
14
+ title,
15
+ description,
16
+ className = '',
17
+ style = {},
18
+ }: PCEmptyProps) {
19
+ const emptyStyle: CSSProperties = {
20
+ ...pcStyles.empty,
21
+ ...style,
22
+ };
23
+
24
+ return (
25
+ <div className={`pc-empty ${className}`} style={emptyStyle}>
26
+ {icon && <div style={pcStyles.emptyIcon}>{icon}</div>}
27
+ {title && (
28
+ <div style={{ ...pcStyles.emptyText, fontWeight: pcStyles.fontWeightSemibold.fontWeight, marginBottom: pcStyles.gapSm.gap }}>
29
+ {title}
30
+ </div>
31
+ )}
32
+ {description && <div style={pcStyles.emptyText}>{description}</div>}
33
+ </div>
34
+ );
35
+ }
@@ -0,0 +1,132 @@
1
+ import { type ReactNode, type CSSProperties, type InputHTMLAttributes, useState, useRef, useEffect } from 'react';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+ import { X } from 'lucide-react';
4
+
5
+ export type PCInputProps = Readonly<
6
+ Omit<InputHTMLAttributes<HTMLInputElement>, 'style' | 'size' | 'prefix'> & {
7
+ className?: string;
8
+ style?: CSSProperties;
9
+ label?: ReactNode;
10
+ error?: boolean;
11
+ clearable?: boolean;
12
+ onClear?: () => void;
13
+ prefix?: ReactNode;
14
+ suffix?: ReactNode;
15
+ inputClassName?: string;
16
+ size?: 'sm' | 'md' | 'lg';
17
+ clearAriaLabel?: string;
18
+ }
19
+ >;
20
+
21
+ export function PCInput({
22
+ className = '',
23
+ style = {},
24
+ label,
25
+ error = false,
26
+ clearable = false,
27
+ onClear,
28
+ prefix,
29
+ suffix,
30
+ inputClassName = '',
31
+ size = 'md',
32
+ clearAriaLabel = 'Clear input',
33
+ value,
34
+ onChange,
35
+ ...props
36
+ }: PCInputProps) {
37
+ const [showClear, setShowClear] = useState(false);
38
+ const inputRef = useRef<HTMLInputElement>(null);
39
+
40
+ useEffect(() => {
41
+ if (clearable && value && String(value).length > 0) {
42
+ setShowClear(true);
43
+ } else {
44
+ setShowClear(false);
45
+ }
46
+ }, [value, clearable]);
47
+
48
+ const handleClear = () => {
49
+ if (inputRef.current) {
50
+ const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
51
+ window.HTMLInputElement.prototype,
52
+ 'value'
53
+ )?.set;
54
+ nativeInputValueSetter?.call(inputRef.current, '');
55
+ const ev = new Event('input', { bubbles: true });
56
+ inputRef.current.dispatchEvent(ev);
57
+ }
58
+ onClear?.();
59
+ };
60
+
61
+ const inputStyle: CSSProperties = {
62
+ ...pcStyles.input,
63
+ ...(size === 'sm' && pcStyles.inputSm),
64
+ ...(size === 'lg' && pcStyles.inputLg),
65
+ ...(error && pcStyles.inputError),
66
+ ...(props.disabled && pcStyles.inputDisabled),
67
+ };
68
+
69
+ const wrapperStyle: CSSProperties = {
70
+ ...pcStyles.inputWrapper,
71
+ ...style,
72
+ };
73
+
74
+ if (prefix || suffix || clearable) {
75
+ return (
76
+ <div className={className} style={wrapperStyle}>
77
+ {label && <label style={pcStyles.inputLabel}>{label}</label>}
78
+ <div style={pcStyles.inputWithPrefix}>
79
+ {prefix && <span style={pcStyles.inputPrefix}>{prefix}</span>}
80
+ <input
81
+ ref={inputRef}
82
+ className={`pc-input ${inputClassName}`}
83
+ style={{
84
+ ...inputStyle,
85
+ border: 'none',
86
+ flex: 1,
87
+ paddingLeft: prefix ? 0 : undefined,
88
+ paddingRight: (suffix || showClear) ? 0 : undefined,
89
+ }}
90
+ value={value}
91
+ onChange={onChange}
92
+ {...props}
93
+ />
94
+ {showClear && (
95
+ <button
96
+ type="button"
97
+ onClick={handleClear}
98
+ style={{
99
+ ...pcStyles.actionIcon,
100
+ padding: '0.25rem',
101
+ background: 'none',
102
+ border: 'none',
103
+ cursor: 'pointer',
104
+ display: 'flex',
105
+ alignItems: 'center',
106
+ color: pcStyles.textSecondary.color,
107
+ }}
108
+ aria-label={clearAriaLabel}
109
+ >
110
+ <X size={16} />
111
+ </button>
112
+ )}
113
+ {suffix && <span style={pcStyles.inputSuffix}>{suffix}</span>}
114
+ </div>
115
+ </div>
116
+ );
117
+ }
118
+
119
+ return (
120
+ <div className={className} style={wrapperStyle}>
121
+ {label && <label style={pcStyles.inputLabel}>{label}</label>}
122
+ <input
123
+ ref={inputRef}
124
+ className={`pc-input ${inputClassName}`}
125
+ style={inputStyle}
126
+ value={value}
127
+ onChange={onChange}
128
+ {...props}
129
+ />
130
+ </div>
131
+ );
132
+ }
@@ -0,0 +1,31 @@
1
+ import { type CSSProperties } from 'react';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+
4
+ export interface PCLoaderProps {
5
+ className?: string;
6
+ style?: CSSProperties;
7
+ size?: 'sm' | 'md' | 'lg';
8
+ color?: 'primary' | 'info';
9
+ variant?: 'spinner';
10
+ ariaLabel?: string;
11
+ }
12
+
13
+ export function PCLoader({
14
+ className = '',
15
+ style = {},
16
+ size = 'md',
17
+ color = 'primary',
18
+ ariaLabel = 'Loading',
19
+ }: PCLoaderProps) {
20
+ const loaderStyle: CSSProperties = {
21
+ ...pcStyles.loader,
22
+ ...(size === 'sm' && pcStyles.loaderSm),
23
+ ...(size === 'md' && pcStyles.loaderMd),
24
+ ...(size === 'lg' && pcStyles.loaderLg),
25
+ ...(color === 'primary' && pcStyles.loaderPrimary),
26
+ ...(color === 'info' && pcStyles.loaderInfo),
27
+ ...style,
28
+ };
29
+
30
+ return <div className={className} style={loaderStyle} aria-label={ariaLabel} role="status" />;
31
+ }