@pcoi/components 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 (103) hide show
  1. package/dist/components.css +1 -0
  2. package/dist/index.d.ts +667 -0
  3. package/dist/index.js +2 -0
  4. package/dist/index.mjs +1048 -0
  5. package/package.json +36 -0
  6. package/src/Badge/Badge.css +40 -0
  7. package/src/Badge/Badge.tsx +36 -0
  8. package/src/Badge/index.ts +2 -0
  9. package/src/Button/Button.css +93 -0
  10. package/src/Button/Button.figma.tsx +29 -0
  11. package/src/Button/Button.tsx +47 -0
  12. package/src/Button/index.ts +1 -0
  13. package/src/Callout/Callout.css +43 -0
  14. package/src/Callout/Callout.tsx +39 -0
  15. package/src/Callout/index.ts +1 -0
  16. package/src/Card/Card.css +88 -0
  17. package/src/Card/Card.tsx +60 -0
  18. package/src/Card/index.ts +1 -0
  19. package/src/ChatInterface/ChatInterface.css +49 -0
  20. package/src/ChatInterface/ChatInterface.tsx +120 -0
  21. package/src/ChatInterface/index.ts +6 -0
  22. package/src/ChatMessage/ChatMessage.css +55 -0
  23. package/src/ChatMessage/ChatMessage.tsx +71 -0
  24. package/src/ChatMessage/index.ts +2 -0
  25. package/src/ChatMessageList/ChatMessageList.css +24 -0
  26. package/src/ChatMessageList/ChatMessageList.tsx +51 -0
  27. package/src/ChatMessageList/index.ts +2 -0
  28. package/src/Checkbox/Checkbox.css +97 -0
  29. package/src/Checkbox/Checkbox.tsx +70 -0
  30. package/src/Checkbox/index.ts +2 -0
  31. package/src/CitationMark/CitationMark.css +40 -0
  32. package/src/CitationMark/CitationMark.tsx +38 -0
  33. package/src/CitationMark/index.ts +2 -0
  34. package/src/CitedExcerpt/CitedExcerpt.css +75 -0
  35. package/src/CitedExcerpt/CitedExcerpt.tsx +51 -0
  36. package/src/CitedExcerpt/index.ts +2 -0
  37. package/src/ComparisonTable/ComparisonTable.css +66 -0
  38. package/src/ComparisonTable/ComparisonTable.tsx +48 -0
  39. package/src/ComparisonTable/index.ts +1 -0
  40. package/src/ContactForm/ContactForm.css +38 -0
  41. package/src/ContactForm/ContactForm.tsx +57 -0
  42. package/src/ContactForm/index.ts +1 -0
  43. package/src/DataTable/DataTable.css +56 -0
  44. package/src/DataTable/DataTable.tsx +104 -0
  45. package/src/DataTable/index.ts +2 -0
  46. package/src/DocumentOverlay/DocumentOverlay.css +57 -0
  47. package/src/DocumentOverlay/DocumentOverlay.tsx +86 -0
  48. package/src/DocumentOverlay/index.ts +2 -0
  49. package/src/Footer/Footer.css +72 -0
  50. package/src/Footer/Footer.tsx +56 -0
  51. package/src/Footer/index.ts +1 -0
  52. package/src/FormField/FormField.css +78 -0
  53. package/src/FormField/FormField.tsx +103 -0
  54. package/src/FormField/index.ts +2 -0
  55. package/src/HowStep/HowStep.css +48 -0
  56. package/src/HowStep/HowStep.tsx +38 -0
  57. package/src/HowStep/index.ts +1 -0
  58. package/src/LogoMark/LogoMark.css +16 -0
  59. package/src/LogoMark/LogoMark.tsx +25 -0
  60. package/src/LogoMark/index.ts +2 -0
  61. package/src/Modal/Modal.css +101 -0
  62. package/src/Modal/Modal.tsx +141 -0
  63. package/src/Modal/index.ts +2 -0
  64. package/src/Nav/Nav.css +161 -0
  65. package/src/Nav/Nav.tsx +101 -0
  66. package/src/Nav/index.ts +1 -0
  67. package/src/Panel/Panel.css +35 -0
  68. package/src/Panel/Panel.tsx +61 -0
  69. package/src/Panel/index.ts +2 -0
  70. package/src/PromptBar/PromptBar.css +68 -0
  71. package/src/PromptBar/PromptBar.tsx +93 -0
  72. package/src/PromptBar/index.ts +2 -0
  73. package/src/RadioGroup/RadioGroup.css +117 -0
  74. package/src/RadioGroup/RadioGroup.tsx +112 -0
  75. package/src/RadioGroup/index.ts +2 -0
  76. package/src/SectionHeader/SectionHeader.css +38 -0
  77. package/src/SectionHeader/SectionHeader.tsx +55 -0
  78. package/src/SectionHeader/index.ts +1 -0
  79. package/src/Select/Select.css +90 -0
  80. package/src/Select/Select.tsx +100 -0
  81. package/src/Select/index.ts +2 -0
  82. package/src/SignalsPanel/SignalsPanel.css +51 -0
  83. package/src/SignalsPanel/SignalsPanel.tsx +33 -0
  84. package/src/SignalsPanel/index.ts +1 -0
  85. package/src/SuggestionCard/SuggestionCard.css +51 -0
  86. package/src/SuggestionCard/SuggestionCard.tsx +34 -0
  87. package/src/SuggestionCard/index.ts +2 -0
  88. package/src/SuggestionCards/SuggestionCards.css +15 -0
  89. package/src/SuggestionCards/SuggestionCards.tsx +40 -0
  90. package/src/SuggestionCards/index.ts +2 -0
  91. package/src/Toast/Toast.css +85 -0
  92. package/src/Toast/Toast.tsx +77 -0
  93. package/src/Toast/index.ts +2 -0
  94. package/src/Toggle/Toggle.css +110 -0
  95. package/src/Toggle/Toggle.tsx +73 -0
  96. package/src/Toggle/index.ts +2 -0
  97. package/src/TypingIndicator/TypingIndicator.css +70 -0
  98. package/src/TypingIndicator/TypingIndicator.tsx +37 -0
  99. package/src/TypingIndicator/index.ts +2 -0
  100. package/src/index.ts +37 -0
  101. package/src/styles/utilities.css +14 -0
  102. package/src/styles.css +32 -0
  103. package/src/types.ts +65 -0
@@ -0,0 +1,85 @@
1
+ /* Toast — @pcoi/components */
2
+
3
+ .pcoi-toast {
4
+ position: fixed;
5
+ bottom: var(--pcoi-spacing-24);
6
+ right: var(--pcoi-spacing-24);
7
+ z-index: var(--pcoi-layout-zIndex-toast, 600);
8
+ animation: pcoi-toast-slide-in 0.3s ease;
9
+ }
10
+
11
+ .pcoi-toast__content {
12
+ display: flex;
13
+ align-items: center;
14
+ gap: var(--pcoi-spacing-12);
15
+ font-family: var(--pcoi-semantic-type-body-font);
16
+ background: var(--pcoi-semantic-surface-elevated);
17
+ border: 1px solid var(--pcoi-semantic-border-default);
18
+ border-radius: var(--pcoi-radius-md);
19
+ box-shadow: var(--pcoi-effect-shadow-elevated);
20
+ padding: var(--pcoi-spacing-14) var(--pcoi-spacing-20);
21
+ min-width: var(--pcoi-layout-container-toast-min);
22
+ max-width: var(--pcoi-layout-container-toast-max);
23
+ }
24
+
25
+ /* ── Left accent border per variant ── */
26
+ .pcoi-toast--success .pcoi-toast__content {
27
+ border-left: var(--pcoi-layout-component-accent-border-w) solid var(--pcoi-semantic-border-success);
28
+ }
29
+
30
+ .pcoi-toast--error .pcoi-toast__content {
31
+ border-left: var(--pcoi-layout-component-accent-border-w) solid var(--pcoi-semantic-border-error);
32
+ }
33
+
34
+ .pcoi-toast--warning .pcoi-toast__content {
35
+ border-left: var(--pcoi-layout-component-accent-border-w) solid var(--pcoi-semantic-border-warning);
36
+ }
37
+
38
+ .pcoi-toast--info .pcoi-toast__content {
39
+ border-left: var(--pcoi-layout-component-accent-border-w) solid var(--pcoi-semantic-border-info);
40
+ }
41
+
42
+ .pcoi-toast__message {
43
+ flex: 1;
44
+ font-size: var(--pcoi-semantic-type-body-size);
45
+ color: var(--pcoi-semantic-text-primary);
46
+ line-height: var(--pcoi-semantic-type-body-compact-line-height);
47
+ }
48
+
49
+ .pcoi-toast__close {
50
+ background: none;
51
+ border: none;
52
+ color: var(--pcoi-semantic-text-secondary);
53
+ font-size: var(--pcoi-semantic-type-close-sm-size);
54
+ line-height: var(--pcoi-semantic-type-none-line-height);
55
+ cursor: pointer;
56
+ padding: var(--pcoi-spacing-4);
57
+ border-radius: var(--pcoi-radius-sm);
58
+ flex-shrink: 0;
59
+ transition: color var(--pcoi-effect-transition-fast, 0.2s ease);
60
+ }
61
+
62
+ .pcoi-toast__close:hover {
63
+ color: var(--pcoi-semantic-text-primary);
64
+ }
65
+
66
+ .pcoi-toast__close:active {
67
+ transform: var(--pcoi-effect-transform-press-scale-icon);
68
+ }
69
+
70
+ .pcoi-toast__close:focus-visible {
71
+ outline: none;
72
+ box-shadow: var(--pcoi-effect-shadow-focus-ring);
73
+ }
74
+
75
+ /* ── Animation ── */
76
+ @keyframes pcoi-toast-slide-in {
77
+ from {
78
+ transform: translateX(100%);
79
+ opacity: 0;
80
+ }
81
+ to {
82
+ transform: translateX(0);
83
+ opacity: 1;
84
+ }
85
+ }
@@ -0,0 +1,77 @@
1
+ import React, { useEffect, useCallback } from "react";
2
+ import { createPortal } from "react-dom";
3
+ import { CloseIcon } from "../../../icons/src/react/CloseIcon";
4
+
5
+ export type ToastVariant = "success" | "error" | "warning" | "info";
6
+
7
+ export interface ToastProps extends React.HTMLAttributes<HTMLDivElement> {
8
+ /** Toast message */
9
+ message: string;
10
+ /** Visual variant determining color */
11
+ variant?: ToastVariant;
12
+ /** Whether the toast is visible */
13
+ open: boolean;
14
+ /** Called when the toast should dismiss */
15
+ onClose?: () => void;
16
+ /** Auto-dismiss duration in ms (default 5000, 0 = no auto-dismiss) */
17
+ duration?: number;
18
+ }
19
+
20
+ /**
21
+ * PCOI Toast — Non-blocking notification
22
+ * Tokens: surface/elevated, border/success|error|warning|info,
23
+ * text/primary, text/success|error|warning|info,
24
+ * shadow/elevated, zIndex/toast, radius-md
25
+ */
26
+ export const Toast: React.FC<ToastProps> = ({
27
+ message,
28
+ variant = "info",
29
+ open,
30
+ onClose,
31
+ duration = 5000,
32
+ className = "",
33
+ ...rest
34
+ }) => {
35
+ const handleClose = useCallback(() => {
36
+ onClose?.();
37
+ }, [onClose]);
38
+
39
+ useEffect(() => {
40
+ if (!open || duration === 0) return;
41
+
42
+ const timer = setTimeout(handleClose, duration);
43
+ return () => clearTimeout(timer);
44
+ }, [open, duration, handleClose]);
45
+
46
+ if (!open) return null;
47
+
48
+ const wrapperClasses = [
49
+ "pcoi-toast",
50
+ `pcoi-toast--${variant}`,
51
+ className,
52
+ ]
53
+ .filter(Boolean)
54
+ .join(" ");
55
+
56
+ return createPortal(
57
+ <div className={wrapperClasses} role="alert" {...rest}>
58
+ <div className="pcoi-toast__content">
59
+ <span className="pcoi-toast__message">{message}</span>
60
+ {onClose && (
61
+ <button
62
+ type="button"
63
+ className="pcoi-toast__close"
64
+ onClick={handleClose}
65
+ aria-label="Dismiss notification"
66
+ >
67
+ <CloseIcon size={16} />
68
+ </button>
69
+ )}
70
+ </div>
71
+ </div>,
72
+ document.body
73
+ );
74
+ };
75
+
76
+ Toast.displayName = "Toast";
77
+ export default Toast;
@@ -0,0 +1,2 @@
1
+ export { Toast, type ToastProps, type ToastVariant } from "./Toast";
2
+ export { default } from "./Toast";
@@ -0,0 +1,110 @@
1
+ /* Toggle — @pcoi/components */
2
+
3
+ .pcoi-toggle {
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: var(--pcoi-spacing-6);
7
+ }
8
+
9
+ .pcoi-toggle__control {
10
+ display: inline-flex;
11
+ align-items: center;
12
+ gap: var(--pcoi-spacing-12);
13
+ cursor: pointer;
14
+ }
15
+
16
+ .pcoi-toggle__input {
17
+ position: absolute;
18
+ width: 1px;
19
+ height: 1px;
20
+ padding: 0;
21
+ margin: -1px;
22
+ overflow: hidden;
23
+ clip: rect(0, 0, 0, 0);
24
+ white-space: nowrap;
25
+ border-width: 0;
26
+ }
27
+
28
+ .pcoi-toggle__track {
29
+ width: var(--pcoi-layout-component-toggle-track-w);
30
+ height: var(--pcoi-layout-component-toggle-track-h);
31
+ flex-shrink: 0;
32
+ border-radius: var(--pcoi-radius-full);
33
+ background: var(--pcoi-semantic-action-toggle-bg);
34
+ position: relative;
35
+ transition: background var(--pcoi-effect-transition-fast, 0.2s ease);
36
+ }
37
+
38
+ .pcoi-toggle__thumb {
39
+ position: absolute;
40
+ top: var(--pcoi-layout-component-toggle-thumb-inset);
41
+ left: var(--pcoi-layout-component-toggle-thumb-inset);
42
+ width: var(--pcoi-layout-component-toggle-thumb);
43
+ height: var(--pcoi-layout-component-toggle-thumb);
44
+ border-radius: var(--pcoi-radius-full);
45
+ background: var(--pcoi-semantic-action-toggle-thumb);
46
+ transition: transform var(--pcoi-effect-transition-fast, 0.2s ease),
47
+ background var(--pcoi-effect-transition-fast, 0.2s ease);
48
+ }
49
+
50
+ .pcoi-toggle__thumb::after {
51
+ content: "";
52
+ position: absolute;
53
+ top: 50%;
54
+ left: 50%;
55
+ width: var(--pcoi-layout-component-toggle-check-w);
56
+ height: var(--pcoi-layout-component-toggle-check-h);
57
+ border: solid var(--pcoi-semantic-action-success);
58
+ border-width: 0 var(--pcoi-layout-component-toggle-check-stroke) var(--pcoi-layout-component-toggle-check-stroke) 0;
59
+ transform: translate(-50%, -60%) rotate(45deg);
60
+ opacity: 0;
61
+ transition: opacity var(--pcoi-effect-transition-fast, 0.2s ease);
62
+ }
63
+
64
+ .pcoi-toggle__control:hover .pcoi-toggle__track {
65
+ box-shadow: 0 0 0 1px var(--pcoi-semantic-border-input-hover);
66
+ }
67
+
68
+ .pcoi-toggle__control:active .pcoi-toggle__track {
69
+ transform: var(--pcoi-effect-transform-press-scale-track);
70
+ }
71
+
72
+ .pcoi-toggle__input:checked + .pcoi-toggle__track {
73
+ background: var(--pcoi-semantic-action-toggle-bg-on);
74
+ }
75
+
76
+ .pcoi-toggle__input:checked + .pcoi-toggle__track .pcoi-toggle__thumb {
77
+ transform: translateX(var(--pcoi-layout-component-toggle-thumb-travel)) var(--pcoi-effect-transform-toggle-thumb-on);
78
+ }
79
+
80
+ .pcoi-toggle__input:checked + .pcoi-toggle__track .pcoi-toggle__thumb::after {
81
+ opacity: 1;
82
+ }
83
+
84
+ .pcoi-toggle__input:focus-visible + .pcoi-toggle__track {
85
+ outline: none;
86
+ box-shadow: var(--pcoi-effect-shadow-focus-ring);
87
+ }
88
+
89
+ .pcoi-toggle__label {
90
+ font-size: var(--pcoi-semantic-type-body-size);
91
+ color: var(--pcoi-semantic-text-primary);
92
+ }
93
+
94
+ /* ── Error state ── */
95
+ .pcoi-toggle--error .pcoi-toggle__track {
96
+ box-shadow: 0 0 0 1px var(--pcoi-semantic-border-error);
97
+ }
98
+
99
+ .pcoi-toggle__error {
100
+ font-size: var(--pcoi-semantic-type-label-size);
101
+ color: var(--pcoi-semantic-text-error);
102
+ margin: 0;
103
+ padding-left: calc(var(--pcoi-layout-component-toggle-track-w) + var(--pcoi-spacing-12));
104
+ }
105
+
106
+ /* ── Disabled state ── */
107
+ .pcoi-toggle--disabled {
108
+ opacity: var(--pcoi-effect-opacity-disabled);
109
+ pointer-events: none;
110
+ }
@@ -0,0 +1,73 @@
1
+ import React from "react";
2
+
3
+ export interface ToggleProps
4
+ extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "size"> {
5
+ /** Visible label text */
6
+ label: string;
7
+ /** Unique field name, also used to generate id */
8
+ name: string;
9
+ /** Error message — when truthy, field enters error state */
10
+ error?: string;
11
+ }
12
+
13
+ /**
14
+ * PCOI Toggle — Switch-style boolean control
15
+ * Tokens: action/toggle-bg, action/toggle-bg-on, action/toggle-thumb,
16
+ * focus/border, focus/glow, text/primary, text/error, radius-full
17
+ */
18
+ export const Toggle = React.forwardRef<HTMLInputElement, ToggleProps>(
19
+ (
20
+ {
21
+ label,
22
+ name,
23
+ error,
24
+ disabled = false,
25
+ className = "",
26
+ ...props
27
+ },
28
+ ref
29
+ ) => {
30
+ const fieldId = `pcoi-field-${name}`;
31
+ const errorId = error ? `${fieldId}-error` : undefined;
32
+
33
+ const wrapperClasses = [
34
+ "pcoi-toggle",
35
+ error ? "pcoi-toggle--error" : "",
36
+ disabled ? "pcoi-toggle--disabled" : "",
37
+ className,
38
+ ]
39
+ .filter(Boolean)
40
+ .join(" ");
41
+
42
+ return (
43
+ <div className={wrapperClasses}>
44
+ <label htmlFor={fieldId} className="pcoi-toggle__control">
45
+ <input
46
+ ref={ref}
47
+ type="checkbox"
48
+ id={fieldId}
49
+ name={name}
50
+ disabled={disabled}
51
+ aria-invalid={!!error}
52
+ aria-describedby={errorId}
53
+ className="pcoi-toggle__input"
54
+ role="switch"
55
+ {...props}
56
+ />
57
+ <span className="pcoi-toggle__track" aria-hidden="true">
58
+ <span className="pcoi-toggle__thumb" />
59
+ </span>
60
+ <span className="pcoi-toggle__label">{label}</span>
61
+ </label>
62
+ {error && (
63
+ <span id={errorId} className="pcoi-toggle__error" role="alert">
64
+ {error}
65
+ </span>
66
+ )}
67
+ </div>
68
+ );
69
+ }
70
+ );
71
+
72
+ Toggle.displayName = "Toggle";
73
+ export default Toggle;
@@ -0,0 +1,2 @@
1
+ export { Toggle, type ToggleProps } from "./Toggle";
2
+ export { default } from "./Toggle";
@@ -0,0 +1,70 @@
1
+ /* TypingIndicator — @pcoi/components */
2
+
3
+ .pcoi-typing-indicator {
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: var(--pcoi-spacing-8);
7
+ padding: var(--pcoi-spacing-16);
8
+ background: var(--pcoi-semantic-surface-accent-dim);
9
+ border: 1px solid var(--pcoi-semantic-border-card);
10
+ border-radius: var(--pcoi-radius-md);
11
+ animation: pcoi-typing-fade-in 0.2s ease;
12
+ }
13
+
14
+ .pcoi-typing-indicator__header {
15
+ display: flex;
16
+ align-items: center;
17
+ }
18
+
19
+ .pcoi-typing-indicator__dots {
20
+ display: flex;
21
+ align-items: center;
22
+ gap: 6px;
23
+ padding: var(--pcoi-spacing-4) 0;
24
+ }
25
+
26
+ .pcoi-typing-indicator__dot {
27
+ width: 8px;
28
+ height: 8px;
29
+ border-radius: var(--pcoi-radius-full);
30
+ background: var(--pcoi-semantic-text-accent);
31
+ opacity: 0.4;
32
+ animation: pcoi-typing-bounce 1.4s ease-in-out infinite;
33
+ }
34
+
35
+ .pcoi-typing-indicator__dot:nth-child(2) {
36
+ animation-delay: 0.2s;
37
+ }
38
+
39
+ .pcoi-typing-indicator__dot:nth-child(3) {
40
+ animation-delay: 0.4s;
41
+ }
42
+
43
+ @keyframes pcoi-typing-bounce {
44
+ 0%, 60%, 100% {
45
+ transform: translateY(0);
46
+ opacity: 0.4;
47
+ }
48
+ 30% {
49
+ transform: translateY(-6px);
50
+ opacity: 1;
51
+ }
52
+ }
53
+
54
+ @keyframes pcoi-typing-fade-in {
55
+ from {
56
+ opacity: 0;
57
+ transform: translateY(4px);
58
+ }
59
+ to {
60
+ opacity: 1;
61
+ transform: translateY(0);
62
+ }
63
+ }
64
+
65
+ /* ── Responsive: offset to match assistant messages on desktop ── */
66
+ @media (min-width: 1025px) {
67
+ .pcoi-typing-indicator {
68
+ margin-right: var(--pcoi-spacing-48);
69
+ }
70
+ }
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import { Badge } from "../Badge/Badge";
3
+
4
+ export interface TypingIndicatorProps
5
+ extends React.HTMLAttributes<HTMLDivElement> {
6
+ /** Label shown in the badge (default: "PCOI") */
7
+ label?: string;
8
+ }
9
+
10
+ /**
11
+ * PCOI TypingIndicator — Three bouncing dots indicating the assistant is composing a response
12
+ * Tokens: bg/card, border/card, radius-md, text/accent
13
+ */
14
+ export const TypingIndicator = React.forwardRef<
15
+ HTMLDivElement,
16
+ TypingIndicatorProps
17
+ >(({ label = "PCOI", className = "", ...rest }, ref) => {
18
+ const classes = ["pcoi-typing-indicator", className]
19
+ .filter(Boolean)
20
+ .join(" ");
21
+
22
+ return (
23
+ <div ref={ref} className={classes} {...rest}>
24
+ <div className="pcoi-typing-indicator__header">
25
+ <Badge>{label}</Badge>
26
+ </div>
27
+ <div className="pcoi-typing-indicator__dots" aria-label="Typing">
28
+ <span className="pcoi-typing-indicator__dot" />
29
+ <span className="pcoi-typing-indicator__dot" />
30
+ <span className="pcoi-typing-indicator__dot" />
31
+ </div>
32
+ </div>
33
+ );
34
+ });
35
+
36
+ TypingIndicator.displayName = "TypingIndicator";
37
+ export default TypingIndicator;
@@ -0,0 +1,2 @@
1
+ export { TypingIndicator, type TypingIndicatorProps } from "./TypingIndicator";
2
+ export { default } from "./TypingIndicator";
package/src/index.ts ADDED
@@ -0,0 +1,37 @@
1
+ // @pcoi/components — Barrel Export
2
+ // All components from the PCOI Design System
3
+ import "./styles.css";
4
+
5
+ export { type HeadingLevel, type LinkItem, type OptionItem, type ChatMessageRole, type Citation, type Suggestion, type TrackingProps } from "./types";
6
+ export { LogoMark, type LogoMarkProps } from "./LogoMark";
7
+ export { Button, type ButtonProps, type ButtonVariant, type ButtonSize } from "./Button";
8
+ export { FormField, type FormFieldProps } from "./FormField";
9
+ export { Card, type CardProps, type CardVariant } from "./Card";
10
+ export { Nav, type NavProps, type NavLink } from "./Nav";
11
+ export { SectionHeader, type SectionHeaderProps } from "./SectionHeader";
12
+ export { HowStep, type HowStepProps } from "./HowStep";
13
+ export { ComparisonTable, type ComparisonTableProps, type ComparisonRow } from "./ComparisonTable";
14
+ export { ContactForm, type ContactFormProps } from "./ContactForm";
15
+ export { Callout, type CalloutProps } from "./Callout";
16
+ export { SignalsPanel, type SignalsPanelProps } from "./SignalsPanel";
17
+ export { Footer, type FooterProps, type FooterLink } from "./Footer";
18
+ export { Select, type SelectProps } from "./Select";
19
+ export { Checkbox, type CheckboxProps } from "./Checkbox";
20
+ export { Toggle, type ToggleProps } from "./Toggle";
21
+ export { RadioGroup, type RadioGroupProps } from "./RadioGroup";
22
+ export { Panel, type PanelProps } from "./Panel";
23
+ export { DataTable, type DataTableProps, type DataTableColumn } from "./DataTable";
24
+ export { Badge, type BadgeProps, type BadgeVariant } from "./Badge";
25
+ export { Modal, type ModalProps } from "./Modal";
26
+ export { Toast, type ToastProps, type ToastVariant } from "./Toast";
27
+
28
+ // Chat Interface components
29
+ export { SuggestionCard, type SuggestionCardProps } from "./SuggestionCard";
30
+ export { CitedExcerpt, type CitedExcerptProps } from "./CitedExcerpt";
31
+ export { PromptBar, type PromptBarProps } from "./PromptBar";
32
+ export { ChatMessage, type ChatMessageProps } from "./ChatMessage";
33
+ export { SuggestionCards, type SuggestionCardsProps } from "./SuggestionCards";
34
+ export { ChatMessageList, type ChatMessageListProps } from "./ChatMessageList";
35
+ export { DocumentOverlay, type DocumentOverlayProps } from "./DocumentOverlay";
36
+ export { TypingIndicator, type TypingIndicatorProps } from "./TypingIndicator";
37
+ export { ChatInterface, type ChatInterfaceProps, type ChatInterfaceMessage } from "./ChatInterface";
@@ -0,0 +1,14 @@
1
+ /* @pcoi/components — Global Utilities */
2
+
3
+ /* Screen-reader only: visually hidden but accessible to assistive technology */
4
+ .pcoi-sr-only {
5
+ position: absolute;
6
+ width: 1px;
7
+ height: 1px;
8
+ padding: 0;
9
+ margin: -1px;
10
+ overflow: hidden;
11
+ clip: rect(0, 0, 0, 0);
12
+ white-space: nowrap;
13
+ border-width: 0;
14
+ }
package/src/styles.css ADDED
@@ -0,0 +1,32 @@
1
+ /* @pcoi/components — All component styles */
2
+ @import "./styles/utilities.css";
3
+ @import "./Badge/Badge.css";
4
+ @import "./LogoMark/LogoMark.css";
5
+ @import "./Button/Button.css";
6
+ @import "./FormField/FormField.css";
7
+ @import "./Card/Card.css";
8
+ @import "./Nav/Nav.css";
9
+ @import "./SectionHeader/SectionHeader.css";
10
+ @import "./HowStep/HowStep.css";
11
+ @import "./ComparisonTable/ComparisonTable.css";
12
+ @import "./ContactForm/ContactForm.css";
13
+ @import "./Callout/Callout.css";
14
+ @import "./SignalsPanel/SignalsPanel.css";
15
+ @import "./Footer/Footer.css";
16
+ @import "./Select/Select.css";
17
+ @import "./Checkbox/Checkbox.css";
18
+ @import "./Toggle/Toggle.css";
19
+ @import "./RadioGroup/RadioGroup.css";
20
+ @import "./Panel/Panel.css";
21
+ @import "./DataTable/DataTable.css";
22
+ @import "./Modal/Modal.css";
23
+ @import "./Toast/Toast.css";
24
+ @import "./SuggestionCard/SuggestionCard.css";
25
+ @import "./SuggestionCards/SuggestionCards.css";
26
+ @import "./CitedExcerpt/CitedExcerpt.css";
27
+ @import "./PromptBar/PromptBar.css";
28
+ @import "./ChatMessage/ChatMessage.css";
29
+ @import "./ChatMessageList/ChatMessageList.css";
30
+ @import "./TypingIndicator/TypingIndicator.css";
31
+ @import "./DocumentOverlay/DocumentOverlay.css";
32
+ @import "./ChatInterface/ChatInterface.css";
package/src/types.ts ADDED
@@ -0,0 +1,65 @@
1
+ // @pcoi/components — Shared Types
2
+
3
+ /** Semantic heading level for document outline (h1–h6) */
4
+ export type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
5
+
6
+ /** Navigation link used by Nav, Footer, and any link-list component */
7
+ export interface LinkItem {
8
+ label: string;
9
+ href: string;
10
+ /** Optional tracking identifier rendered as data-track-id on the anchor */
11
+ trackingId?: string;
12
+ }
13
+
14
+ /** Option item used by Select, RadioGroup */
15
+ export interface OptionItem {
16
+ label: string;
17
+ value: string;
18
+ disabled?: boolean;
19
+ }
20
+
21
+ /** Chat message sender role */
22
+ export type ChatMessageRole = "user" | "assistant";
23
+
24
+ /** Citation reference from an assistant response */
25
+ export interface Citation {
26
+ /** Unique citation index (1-based) */
27
+ index: number;
28
+ /** Short excerpt from the source document */
29
+ excerpt: string;
30
+ /** Source document title */
31
+ sourceTitle: string;
32
+ /** Source document identifier (e.g. URL or document ID) */
33
+ sourceId: string;
34
+ }
35
+
36
+ /** Suggestion prompt for the chat empty state */
37
+ export interface Suggestion {
38
+ /** Unique identifier */
39
+ id: string;
40
+ /** Display text */
41
+ label: string;
42
+ /** Optional icon rendered before the label */
43
+ icon?: React.ReactNode;
44
+ }
45
+
46
+ /**
47
+ * Standard data-track-* attributes for analytics integration.
48
+ * Supported on all components via HTML attribute pass-through.
49
+ * Exported for documentation and IDE discoverability.
50
+ *
51
+ * @example
52
+ * <Button data-track-id="hero-cta" data-track-action="click" data-track-category="engagement">
53
+ * Get Started
54
+ * </Button>
55
+ */
56
+ export interface TrackingProps {
57
+ /** Unique identifier for the tracked element */
58
+ "data-track-id"?: string;
59
+ /** Action type (e.g. "click", "submit", "view", "toggle") */
60
+ "data-track-action"?: string;
61
+ /** Category grouping (e.g. "navigation", "form", "engagement") */
62
+ "data-track-category"?: string;
63
+ /** Human-readable label for analytics dashboards */
64
+ "data-track-label"?: string;
65
+ }