@pcoi/components 0.1.2 → 1.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.
- package/LICENSE +21 -0
- package/README.md +52 -0
- package/dist/index.d.ts +829 -609
- package/dist/index.js +3517 -2
- package/dist/styles.css +2 -0
- package/package.json +35 -31
- package/dist/components.css +0 -1
- package/dist/index.mjs +0 -994
- package/src/Badge/Badge.css +0 -40
- package/src/Badge/Badge.tsx +0 -36
- package/src/Badge/index.ts +0 -2
- package/src/Button/Button.css +0 -93
- package/src/Button/Button.figma.tsx +0 -27
- package/src/Button/Button.test.tsx +0 -32
- package/src/Button/Button.tsx +0 -47
- package/src/Button/index.ts +0 -1
- package/src/Callout/Callout.css +0 -48
- package/src/Callout/Callout.figma.tsx +0 -25
- package/src/Callout/Callout.tsx +0 -43
- package/src/Callout/index.ts +0 -1
- package/src/Card/Card.css +0 -88
- package/src/Card/Card.figma.tsx +0 -28
- package/src/Card/Card.tsx +0 -60
- package/src/Card/index.ts +0 -1
- package/src/ChatInterface/ChatInterface.css +0 -50
- package/src/ChatInterface/ChatInterface.integration.test.tsx +0 -123
- package/src/ChatInterface/ChatInterface.tsx +0 -125
- package/src/ChatInterface/index.ts +0 -6
- package/src/ChatMessage/ChatMessage.css +0 -55
- package/src/ChatMessage/ChatMessage.tsx +0 -71
- package/src/ChatMessage/index.ts +0 -2
- package/src/ChatMessageList/ChatMessageList.css +0 -24
- package/src/ChatMessageList/ChatMessageList.test.tsx +0 -70
- package/src/ChatMessageList/ChatMessageList.tsx +0 -56
- package/src/ChatMessageList/index.ts +0 -2
- package/src/Checkbox/Checkbox.css +0 -97
- package/src/Checkbox/Checkbox.tsx +0 -70
- package/src/Checkbox/index.ts +0 -2
- package/src/CitationMark/CitationMark.css +0 -40
- package/src/CitationMark/CitationMark.tsx +0 -38
- package/src/CitationMark/index.ts +0 -2
- package/src/CitedExcerpt/CitedExcerpt.css +0 -75
- package/src/CitedExcerpt/CitedExcerpt.tsx +0 -53
- package/src/CitedExcerpt/index.ts +0 -2
- package/src/ComparisonTable/ComparisonTable.css +0 -66
- package/src/ComparisonTable/ComparisonTable.tsx +0 -54
- package/src/ComparisonTable/index.ts +0 -1
- package/src/ContactForm/ContactForm.css +0 -38
- package/src/ContactForm/ContactForm.tsx +0 -58
- package/src/ContactForm/index.ts +0 -1
- package/src/DataTable/DataTable.css +0 -56
- package/src/DataTable/DataTable.tsx +0 -104
- package/src/DataTable/index.ts +0 -2
- package/src/DocumentOverlay/DocumentOverlay.css +0 -57
- package/src/DocumentOverlay/DocumentOverlay.test.tsx +0 -95
- package/src/DocumentOverlay/DocumentOverlay.tsx +0 -87
- package/src/DocumentOverlay/index.ts +0 -2
- package/src/Footer/Footer.css +0 -72
- package/src/Footer/Footer.tsx +0 -59
- package/src/Footer/index.ts +0 -1
- package/src/FormField/FormField.css +0 -78
- package/src/FormField/FormField.figma.tsx +0 -28
- package/src/FormField/FormField.tsx +0 -103
- package/src/FormField/index.ts +0 -2
- package/src/HowStep/HowStep.css +0 -48
- package/src/HowStep/HowStep.figma.tsx +0 -23
- package/src/HowStep/HowStep.tsx +0 -38
- package/src/HowStep/index.ts +0 -1
- package/src/LogoMark/LogoMark.css +0 -16
- package/src/LogoMark/LogoMark.tsx +0 -24
- package/src/LogoMark/index.ts +0 -2
- package/src/Modal/Modal.css +0 -101
- package/src/Modal/Modal.figma.tsx +0 -28
- package/src/Modal/Modal.test.tsx +0 -46
- package/src/Modal/Modal.tsx +0 -144
- package/src/Modal/index.ts +0 -2
- package/src/Nav/Nav.css +0 -161
- package/src/Nav/Nav.tsx +0 -105
- package/src/Nav/index.ts +0 -1
- package/src/Panel/Panel.css +0 -35
- package/src/Panel/Panel.tsx +0 -61
- package/src/Panel/index.ts +0 -2
- package/src/PromptBar/PromptBar.css +0 -68
- package/src/PromptBar/PromptBar.figma.tsx +0 -25
- package/src/PromptBar/PromptBar.test.tsx +0 -83
- package/src/PromptBar/PromptBar.tsx +0 -93
- package/src/PromptBar/index.ts +0 -2
- package/src/RadioGroup/RadioGroup.css +0 -117
- package/src/RadioGroup/RadioGroup.tsx +0 -112
- package/src/RadioGroup/index.ts +0 -2
- package/src/SectionHeader/SectionHeader.css +0 -38
- package/src/SectionHeader/SectionHeader.figma.tsx +0 -23
- package/src/SectionHeader/SectionHeader.tsx +0 -55
- package/src/SectionHeader/index.ts +0 -1
- package/src/Select/Select.css +0 -90
- package/src/Select/Select.figma.tsx +0 -33
- package/src/Select/Select.tsx +0 -100
- package/src/Select/index.ts +0 -2
- package/src/SignalsPanel/SignalsPanel.css +0 -51
- package/src/SignalsPanel/SignalsPanel.tsx +0 -35
- package/src/SignalsPanel/index.ts +0 -1
- package/src/SuggestionCard/SuggestionCard.css +0 -51
- package/src/SuggestionCard/SuggestionCard.tsx +0 -34
- package/src/SuggestionCard/index.ts +0 -2
- package/src/SuggestionCards/SuggestionCards.css +0 -15
- package/src/SuggestionCards/SuggestionCards.test.tsx +0 -27
- package/src/SuggestionCards/SuggestionCards.tsx +0 -40
- package/src/SuggestionCards/index.ts +0 -2
- package/src/Toast/Toast.css +0 -85
- package/src/Toast/Toast.tsx +0 -82
- package/src/Toast/index.ts +0 -2
- package/src/Toggle/Toggle.css +0 -110
- package/src/Toggle/Toggle.figma.tsx +0 -24
- package/src/Toggle/Toggle.tsx +0 -73
- package/src/Toggle/index.ts +0 -2
- package/src/TypingIndicator/TypingIndicator.css +0 -70
- package/src/TypingIndicator/TypingIndicator.tsx +0 -37
- package/src/TypingIndicator/index.ts +0 -2
- package/src/index.ts +0 -39
- package/src/styles/utilities.css +0 -14
- package/src/styles.css +0 -33
- package/src/types.ts +0 -66
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
export interface CheckboxProps
|
|
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 Checkbox — Custom styled checkbox with label
|
|
15
|
-
* Tokens: bg/default, border/default, border/error, focus/border, focus/glow,
|
|
16
|
-
* action/primary-bg, action/primary-text, text/primary, text/error, radius-sm
|
|
17
|
-
*/
|
|
18
|
-
export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
|
|
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-checkbox",
|
|
35
|
-
error ? "pcoi-checkbox--error" : "",
|
|
36
|
-
disabled ? "pcoi-checkbox--disabled" : "",
|
|
37
|
-
className,
|
|
38
|
-
]
|
|
39
|
-
.filter(Boolean)
|
|
40
|
-
.join(" ");
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<div className={wrapperClasses}>
|
|
44
|
-
<label htmlFor={fieldId} className="pcoi-checkbox__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-checkbox__input"
|
|
54
|
-
{...props}
|
|
55
|
-
/>
|
|
56
|
-
<span className="pcoi-checkbox__box" aria-hidden="true" />
|
|
57
|
-
<span className="pcoi-checkbox__label">{label}</span>
|
|
58
|
-
</label>
|
|
59
|
-
{error && (
|
|
60
|
-
<span id={errorId} className="pcoi-checkbox__error" role="alert">
|
|
61
|
-
{error}
|
|
62
|
-
</span>
|
|
63
|
-
)}
|
|
64
|
-
</div>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
Checkbox.displayName = "Checkbox";
|
|
70
|
-
export default Checkbox;
|
package/src/Checkbox/index.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/* CitationMark — @pcoi/components */
|
|
2
|
-
|
|
3
|
-
.pcoi-citation-mark {
|
|
4
|
-
display: inline-flex;
|
|
5
|
-
align-items: center;
|
|
6
|
-
justify-content: center;
|
|
7
|
-
min-width: 32px;
|
|
8
|
-
min-height: 32px;
|
|
9
|
-
padding: var(--pcoi-semantic-spacing-inline-2xs) var(--pcoi-semantic-spacing-chip-x);
|
|
10
|
-
font-family: var(--pcoi-semantic-type-mono-font);
|
|
11
|
-
font-size: var(--pcoi-semantic-type-body-compact-size);
|
|
12
|
-
font-weight: var(--pcoi-semantic-type-label-weight);
|
|
13
|
-
line-height: var(--pcoi-semantic-type-none-line-height);
|
|
14
|
-
color: var(--pcoi-semantic-text-accent);
|
|
15
|
-
background: var(--pcoi-semantic-surface-accent-dim);
|
|
16
|
-
border: 1px solid var(--pcoi-semantic-border-accent-dim);
|
|
17
|
-
border-radius: var(--pcoi-semantic-radius-badge);
|
|
18
|
-
cursor: pointer;
|
|
19
|
-
vertical-align: middle;
|
|
20
|
-
transition:
|
|
21
|
-
background var(--pcoi-effect-transition-fast),
|
|
22
|
-
color var(--pcoi-effect-transition-fast),
|
|
23
|
-
border-color var(--pcoi-effect-transition-fast),
|
|
24
|
-
transform var(--pcoi-effect-transition-fast);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.pcoi-citation-mark:hover {
|
|
28
|
-
color: var(--pcoi-semantic-text-accent-hover);
|
|
29
|
-
background: var(--pcoi-semantic-surface-accent-dim);
|
|
30
|
-
border-color: var(--pcoi-semantic-border-accent-subtle);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.pcoi-citation-mark:active {
|
|
34
|
-
transform: var(--pcoi-effect-transform-press-scale-control);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.pcoi-citation-mark:focus-visible {
|
|
38
|
-
outline: none;
|
|
39
|
-
box-shadow: var(--pcoi-effect-shadow-focus-ring);
|
|
40
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
export interface CitationMarkProps
|
|
4
|
-
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
5
|
-
/** 1-based citation index displayed in the button */
|
|
6
|
-
index: number;
|
|
7
|
-
/** Tooltip text (defaults to "Citation {index}") */
|
|
8
|
-
sourceLabel?: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* PCOI CitationMark — Inline pill-shaped citation button [1]
|
|
13
|
-
* Tokens: text/accent, surface/accent-dim, border/accent-dim,
|
|
14
|
-
* radius-full, font-family/mono, transition-fast,
|
|
15
|
-
* shadow/focus-ring, transform/press-scale-control
|
|
16
|
-
*/
|
|
17
|
-
export const CitationMark = React.forwardRef<
|
|
18
|
-
HTMLButtonElement,
|
|
19
|
-
CitationMarkProps
|
|
20
|
-
>(({ index, sourceLabel, className = "", ...rest }, ref) => {
|
|
21
|
-
const classes = ["pcoi-citation-mark", className].filter(Boolean).join(" ");
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<button
|
|
25
|
-
ref={ref}
|
|
26
|
-
type="button"
|
|
27
|
-
className={classes}
|
|
28
|
-
title={sourceLabel ?? `Citation ${index}`}
|
|
29
|
-
aria-label={sourceLabel ?? `Citation ${index}`}
|
|
30
|
-
{...rest}
|
|
31
|
-
>
|
|
32
|
-
{index}
|
|
33
|
-
</button>
|
|
34
|
-
);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
CitationMark.displayName = "CitationMark";
|
|
38
|
-
export default CitationMark;
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/* CitedExcerpt — @pcoi/components */
|
|
2
|
-
|
|
3
|
-
.pcoi-cited-excerpt {
|
|
4
|
-
display: flex;
|
|
5
|
-
flex-direction: column;
|
|
6
|
-
gap: var(--pcoi-semantic-spacing-form-gap-compact);
|
|
7
|
-
padding: var(--pcoi-semantic-spacing-input-y);
|
|
8
|
-
background: var(--pcoi-semantic-surface-accent-dim);
|
|
9
|
-
border-left: var(--pcoi-semantic-sizing-accent-border-width) solid
|
|
10
|
-
var(--pcoi-semantic-border-accent-dim);
|
|
11
|
-
border-radius: var(--pcoi-semantic-radius-input);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
.pcoi-cited-excerpt__source {
|
|
15
|
-
display: inline-flex;
|
|
16
|
-
align-items: center;
|
|
17
|
-
align-self: flex-start;
|
|
18
|
-
padding: 0;
|
|
19
|
-
font-family: var(--pcoi-semantic-type-body-font);
|
|
20
|
-
font-size: var(--pcoi-semantic-type-body-sm-size);
|
|
21
|
-
color: var(--pcoi-semantic-text-accent);
|
|
22
|
-
background: none;
|
|
23
|
-
border: none;
|
|
24
|
-
cursor: pointer;
|
|
25
|
-
transition:
|
|
26
|
-
color var(--pcoi-effect-transition-fast);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.pcoi-cited-excerpt__source:hover {
|
|
30
|
-
color: var(--pcoi-semantic-text-accent-hover);
|
|
31
|
-
text-decoration: underline;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.pcoi-cited-excerpt__source:focus-visible {
|
|
35
|
-
outline: none;
|
|
36
|
-
box-shadow: var(--pcoi-effect-shadow-focus-ring);
|
|
37
|
-
border-radius: var(--pcoi-semantic-radius-btn);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.pcoi-cited-excerpt__body {
|
|
41
|
-
display: flex;
|
|
42
|
-
align-items: baseline;
|
|
43
|
-
gap: var(--pcoi-semantic-spacing-form-gap-compact);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.pcoi-cited-excerpt__index {
|
|
47
|
-
flex-shrink: 0;
|
|
48
|
-
padding: 0;
|
|
49
|
-
background: none;
|
|
50
|
-
border: none;
|
|
51
|
-
cursor: pointer;
|
|
52
|
-
font-family: var(--pcoi-semantic-type-mono-font);
|
|
53
|
-
font-size: var(--pcoi-semantic-type-body-compact-size);
|
|
54
|
-
font-weight: var(--pcoi-semantic-type-label-weight);
|
|
55
|
-
color: var(--pcoi-semantic-text-accent);
|
|
56
|
-
transition: color var(--pcoi-effect-transition-fast);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.pcoi-cited-excerpt__index:hover {
|
|
60
|
-
color: var(--pcoi-semantic-text-accent-hover);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.pcoi-cited-excerpt__index:focus-visible {
|
|
64
|
-
outline: none;
|
|
65
|
-
box-shadow: var(--pcoi-effect-shadow-focus-ring);
|
|
66
|
-
border-radius: var(--pcoi-semantic-radius-btn);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.pcoi-cited-excerpt__text {
|
|
70
|
-
margin: 0;
|
|
71
|
-
font-family: var(--pcoi-semantic-type-body-font);
|
|
72
|
-
font-size: var(--pcoi-semantic-type-body-compact-size);
|
|
73
|
-
color: var(--pcoi-semantic-text-secondary);
|
|
74
|
-
line-height: var(--pcoi-semantic-type-body-line-height);
|
|
75
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
export interface CitedExcerptProps
|
|
4
|
-
extends React.HTMLAttributes<HTMLDivElement> {
|
|
5
|
-
/** 1-based citation index */
|
|
6
|
-
index: number;
|
|
7
|
-
/** Short excerpt from the source document */
|
|
8
|
-
excerpt: string;
|
|
9
|
-
/** Source document title */
|
|
10
|
-
sourceTitle: string;
|
|
11
|
-
/** Called when the source link is clicked */
|
|
12
|
-
onSourceClick?: () => void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* PCOI CitedExcerpt — Blockquote with excerpt text above, clickable index + source below
|
|
17
|
-
* Tokens: surface/accent-dim, border/accent-dim, accent-border-w,
|
|
18
|
-
* radius-sm, text/secondary, text/accent, type/body-compact-size
|
|
19
|
-
*/
|
|
20
|
-
export const CitedExcerpt = React.forwardRef<HTMLDivElement, CitedExcerptProps>(
|
|
21
|
-
({ index, excerpt, sourceTitle, onSourceClick, className = "", ...rest }, ref) => {
|
|
22
|
-
const classes = ["pcoi-cited-excerpt", className]
|
|
23
|
-
.filter(Boolean)
|
|
24
|
-
.join(" ");
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<div ref={ref} className={classes} {...rest}>
|
|
28
|
-
<button
|
|
29
|
-
type="button"
|
|
30
|
-
className="pcoi-cited-excerpt__source"
|
|
31
|
-
onClick={onSourceClick}
|
|
32
|
-
aria-label={`View source: ${sourceTitle}`}
|
|
33
|
-
>
|
|
34
|
-
{sourceTitle}
|
|
35
|
-
</button>
|
|
36
|
-
<div className="pcoi-cited-excerpt__body">
|
|
37
|
-
<button
|
|
38
|
-
type="button"
|
|
39
|
-
className="pcoi-cited-excerpt__index"
|
|
40
|
-
onClick={onSourceClick}
|
|
41
|
-
aria-label={`Citation ${index}, view source: ${sourceTitle}`}
|
|
42
|
-
>
|
|
43
|
-
[{index}]
|
|
44
|
-
</button>
|
|
45
|
-
<p className="pcoi-cited-excerpt__text">{excerpt}</p>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
CitedExcerpt.displayName = "CitedExcerpt";
|
|
53
|
-
export default CitedExcerpt;
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/* ComparisonTable — @pcoi/components */
|
|
2
|
-
|
|
3
|
-
.pcoi-comparison {
|
|
4
|
-
max-width: var(--pcoi-semantic-sizing-comparison-width, 900px);
|
|
5
|
-
border: 1px solid var(--pcoi-semantic-border-card);
|
|
6
|
-
border-radius: var(--pcoi-semantic-radius-card);
|
|
7
|
-
overflow: hidden;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.pcoi-comparison__table {
|
|
11
|
-
width: 100%;
|
|
12
|
-
border-collapse: collapse;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.pcoi-comparison__header .pcoi-comparison__col {
|
|
16
|
-
font-family: var(--pcoi-semantic-type-mono-font);
|
|
17
|
-
font-size: var(--pcoi-semantic-type-body-sm-size);
|
|
18
|
-
font-weight: var(--pcoi-semantic-type-emphasis-weight);
|
|
19
|
-
letter-spacing: var(--pcoi-semantic-type-label-letter-spacing);
|
|
20
|
-
text-transform: uppercase;
|
|
21
|
-
color: var(--pcoi-semantic-text-secondary);
|
|
22
|
-
padding: var(--pcoi-semantic-spacing-stack-md) var(--pcoi-semantic-spacing-card-gap);
|
|
23
|
-
background: var(--pcoi-semantic-bg-alt);
|
|
24
|
-
text-align: left;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.pcoi-comparison__row {
|
|
28
|
-
border-top: 1px solid var(--pcoi-semantic-border-card);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.pcoi-comparison__col {
|
|
32
|
-
padding: var(--pcoi-semantic-spacing-stack-md) var(--pcoi-semantic-spacing-card-gap);
|
|
33
|
-
font-size: var(--pcoi-semantic-type-body-compact-size);
|
|
34
|
-
color: var(--pcoi-semantic-text-secondary);
|
|
35
|
-
line-height: var(--pcoi-semantic-type-body-compact-line-height);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.pcoi-comparison__col--label {
|
|
39
|
-
font-weight: var(--pcoi-semantic-type-label-weight);
|
|
40
|
-
color: var(--pcoi-semantic-text-primary);
|
|
41
|
-
text-align: left;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.pcoi-comparison__col--highlight {
|
|
45
|
-
background: var(--pcoi-semantic-surface-highlight);
|
|
46
|
-
color: var(--pcoi-semantic-text-accent);
|
|
47
|
-
font-weight: var(--pcoi-semantic-type-label-weight);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.pcoi-comparison__header .pcoi-comparison__col--highlight {
|
|
51
|
-
color: var(--pcoi-semantic-text-accent);
|
|
52
|
-
font-weight: var(--pcoi-semantic-type-emphasis-weight);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/* ── Responsive ── */
|
|
56
|
-
/* 768px = mobile breakpoint (CSS vars are not supported in @media) */
|
|
57
|
-
@media (max-width: 768px) {
|
|
58
|
-
.pcoi-comparison {
|
|
59
|
-
overflow-x: auto;
|
|
60
|
-
-webkit-overflow-scrolling: touch;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.pcoi-comparison__table {
|
|
64
|
-
min-width: var(--pcoi-semantic-sizing-comparison-scroll-width);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
export interface ComparisonRow {
|
|
4
|
-
/** Feature label shown in the first column */
|
|
5
|
-
label: string;
|
|
6
|
-
/** Competitor's value for this feature */
|
|
7
|
-
competitor: string;
|
|
8
|
-
/** PCOI's value for this feature */
|
|
9
|
-
pcoi: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface ComparisonTableProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
13
|
-
/** Column header for the competitor (default: "Typical SaaS AI") */
|
|
14
|
-
competitorName?: string;
|
|
15
|
-
/** Column header for PCOI (default: "PCOI") */
|
|
16
|
-
pcoiName?: string;
|
|
17
|
-
/** Feature comparison rows */
|
|
18
|
-
rows: ComparisonRow[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* PCOI Comparison Table
|
|
23
|
-
* Semantic <table> with 3 columns: label | competitor | PCOI (highlighted)
|
|
24
|
-
* Tokens: radius-md, border/default, bg/alt, surface/accent-dim, text/accent
|
|
25
|
-
*/
|
|
26
|
-
export const ComparisonTable = React.forwardRef<HTMLDivElement, ComparisonTableProps>(
|
|
27
|
-
({ competitorName = "Typical SaaS AI", pcoiName = "PCOI", rows, className = "", ...rest }, ref) => (
|
|
28
|
-
<div ref={ref} className={`pcoi-comparison ${className}`} {...rest}>
|
|
29
|
-
<table className="pcoi-comparison__table">
|
|
30
|
-
<thead>
|
|
31
|
-
<tr className="pcoi-comparison__header">
|
|
32
|
-
<th className="pcoi-comparison__col" scope="col">
|
|
33
|
-
<span className="pcoi-sr-only">Feature</span>
|
|
34
|
-
</th>
|
|
35
|
-
<th className="pcoi-comparison__col" scope="col">{competitorName}</th>
|
|
36
|
-
<th className="pcoi-comparison__col pcoi-comparison__col--highlight" scope="col">{pcoiName}</th>
|
|
37
|
-
</tr>
|
|
38
|
-
</thead>
|
|
39
|
-
<tbody>
|
|
40
|
-
{rows.map((row, i) => (
|
|
41
|
-
<tr key={i} className="pcoi-comparison__row">
|
|
42
|
-
<th className="pcoi-comparison__col pcoi-comparison__col--label" scope="row">{row.label}</th>
|
|
43
|
-
<td className="pcoi-comparison__col">{row.competitor}</td>
|
|
44
|
-
<td className="pcoi-comparison__col pcoi-comparison__col--highlight">{row.pcoi}</td>
|
|
45
|
-
</tr>
|
|
46
|
-
))}
|
|
47
|
-
</tbody>
|
|
48
|
-
</table>
|
|
49
|
-
</div>
|
|
50
|
-
)
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
ComparisonTable.displayName = "ComparisonTable";
|
|
54
|
-
export default ComparisonTable;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { ComparisonTable, type ComparisonTableProps, type ComparisonRow } from "./ComparisonTable";
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/* ContactForm — @pcoi/components */
|
|
2
|
-
|
|
3
|
-
.pcoi-form {
|
|
4
|
-
background: var(--pcoi-semantic-bg-surface);
|
|
5
|
-
border: 1px solid var(--pcoi-semantic-border-default);
|
|
6
|
-
border-radius: var(--pcoi-semantic-radius-panel);
|
|
7
|
-
padding: var(--pcoi-semantic-spacing-form-padding);
|
|
8
|
-
display: flex;
|
|
9
|
-
flex-direction: column;
|
|
10
|
-
gap: var(--pcoi-semantic-spacing-form-gap);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.pcoi-form__row {
|
|
14
|
-
display: grid;
|
|
15
|
-
grid-template-columns: 1fr 1fr;
|
|
16
|
-
gap: var(--pcoi-semantic-spacing-form-gap);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.pcoi-form__full {
|
|
20
|
-
grid-column: 1 / -1;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.pcoi-form__note {
|
|
24
|
-
font-size: var(--pcoi-semantic-type-label-size);
|
|
25
|
-
color: var(--pcoi-semantic-text-muted);
|
|
26
|
-
margin: 0;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/* ── Responsive ── */
|
|
30
|
-
@media (max-width: 768px) {
|
|
31
|
-
.pcoi-form {
|
|
32
|
-
padding: var(--pcoi-semantic-spacing-panel-padding);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.pcoi-form__row {
|
|
36
|
-
grid-template-columns: 1fr;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import { Button } from "../Button";
|
|
3
|
-
import { FormField } from "../FormField";
|
|
4
|
-
|
|
5
|
-
export interface ContactFormProps extends Omit<React.FormHTMLAttributes<HTMLFormElement>, "onSubmit"> {
|
|
6
|
-
/** Called with form field values when the form is submitted */
|
|
7
|
-
onSubmit?: (data: Record<string, string>) => void;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* PCOI Contact Form
|
|
12
|
-
* Composes: FormField (atom), Button (atom)
|
|
13
|
-
* Tokens: bg/surface, border/default, radius-lg, spacing-40 (padding), spacing-20 (gap)
|
|
14
|
-
*/
|
|
15
|
-
export const ContactForm = React.forwardRef<HTMLFormElement, ContactFormProps>(
|
|
16
|
-
({ onSubmit, className = "", ...rest }, ref) => {
|
|
17
|
-
const [submitted, setSubmitted] = useState(false);
|
|
18
|
-
|
|
19
|
-
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
20
|
-
e.preventDefault();
|
|
21
|
-
const form = e.currentTarget;
|
|
22
|
-
const formData = new FormData(form);
|
|
23
|
-
const data = Object.fromEntries(formData.entries()) as Record<string, string>;
|
|
24
|
-
onSubmit?.(data);
|
|
25
|
-
setSubmitted(true);
|
|
26
|
-
form.reset();
|
|
27
|
-
setTimeout(() => setSubmitted(false), 3000);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<form ref={ref} className={`pcoi-form ${className}`} onSubmit={handleSubmit} aria-label="Contact form" {...rest}>
|
|
32
|
-
<div className="pcoi-form__row">
|
|
33
|
-
<FormField label="Name" name="name" placeholder="Your name" required />
|
|
34
|
-
<FormField label="Company" name="company" placeholder="Company name" required />
|
|
35
|
-
</div>
|
|
36
|
-
<div className="pcoi-form__row">
|
|
37
|
-
<FormField label="Email" name="email" type="email" placeholder="you@company.com" required />
|
|
38
|
-
<FormField label="Your Role" name="role" placeholder="CEO, COO, VP Ops, etc." />
|
|
39
|
-
</div>
|
|
40
|
-
<FormField
|
|
41
|
-
label="What problem are you trying to solve?"
|
|
42
|
-
name="context"
|
|
43
|
-
multiline
|
|
44
|
-
rows={3}
|
|
45
|
-
placeholder="Tell us about the knowledge challenges in your organization..."
|
|
46
|
-
className="pcoi-form__full"
|
|
47
|
-
/>
|
|
48
|
-
<Button type="submit" variant="primary" size="large" disabled={submitted}>
|
|
49
|
-
{submitted ? "Message Received" : "Start the Conversation"}
|
|
50
|
-
</Button>
|
|
51
|
-
<p className="pcoi-form__note">No sales automation. A real person reads this and responds personally.</p>
|
|
52
|
-
</form>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
ContactForm.displayName = "ContactForm";
|
|
58
|
-
export default ContactForm;
|
package/src/ContactForm/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { ContactForm, type ContactFormProps } from "./ContactForm";
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/* DataTable — @pcoi/components */
|
|
2
|
-
|
|
3
|
-
.pcoi-data-table {
|
|
4
|
-
width: 100%;
|
|
5
|
-
overflow: hidden;
|
|
6
|
-
overflow-x: auto;
|
|
7
|
-
border: 1px solid var(--pcoi-semantic-border-card);
|
|
8
|
-
border-radius: var(--pcoi-semantic-radius-card);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.pcoi-data-table__table {
|
|
12
|
-
width: 100%;
|
|
13
|
-
border-collapse: collapse;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.pcoi-data-table__th {
|
|
17
|
-
font-family: var(--pcoi-semantic-type-mono-font);
|
|
18
|
-
font-size: var(--pcoi-semantic-type-body-sm-size);
|
|
19
|
-
font-weight: var(--pcoi-semantic-type-emphasis-weight);
|
|
20
|
-
letter-spacing: var(--pcoi-semantic-type-label-letter-spacing);
|
|
21
|
-
text-transform: uppercase;
|
|
22
|
-
color: var(--pcoi-semantic-text-secondary);
|
|
23
|
-
text-align: left;
|
|
24
|
-
padding: var(--pcoi-semantic-spacing-stack-md) var(--pcoi-semantic-spacing-card-gap);
|
|
25
|
-
background: var(--pcoi-semantic-bg-alt);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.pcoi-data-table__th--center { text-align: center; }
|
|
29
|
-
.pcoi-data-table__th--right { text-align: right; }
|
|
30
|
-
|
|
31
|
-
.pcoi-data-table__td {
|
|
32
|
-
font-size: var(--pcoi-semantic-type-body-compact-size);
|
|
33
|
-
color: var(--pcoi-semantic-text-secondary);
|
|
34
|
-
line-height: var(--pcoi-semantic-type-body-compact-line-height);
|
|
35
|
-
text-align: left;
|
|
36
|
-
padding: var(--pcoi-semantic-spacing-stack-md) var(--pcoi-semantic-spacing-card-gap);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.pcoi-data-table__td--center { text-align: center; }
|
|
40
|
-
.pcoi-data-table__td--right { text-align: right; }
|
|
41
|
-
|
|
42
|
-
.pcoi-data-table__row {
|
|
43
|
-
border-top: 1px solid var(--pcoi-semantic-border-card);
|
|
44
|
-
transition: background var(--pcoi-effect-transition-fast, 0.2s ease);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.pcoi-data-table__row:hover {
|
|
48
|
-
background: var(--pcoi-semantic-bg-card-hover);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.pcoi-data-table__empty {
|
|
52
|
-
font-size: var(--pcoi-semantic-type-body-size);
|
|
53
|
-
color: var(--pcoi-semantic-text-muted);
|
|
54
|
-
text-align: center;
|
|
55
|
-
padding: var(--pcoi-semantic-spacing-component-gap) var(--pcoi-semantic-spacing-stack-md);
|
|
56
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
export interface DataTableColumn<T = Record<string, unknown>> {
|
|
4
|
-
/** Unique key matching a property on the row data */
|
|
5
|
-
key: string;
|
|
6
|
-
/** Column header text */
|
|
7
|
-
header: string;
|
|
8
|
-
/** Text alignment (default: "left") */
|
|
9
|
-
align?: "left" | "center" | "right";
|
|
10
|
-
/** Custom cell renderer */
|
|
11
|
-
render?: (value: unknown, row: T) => React.ReactNode;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface DataTableProps<T = Record<string, unknown>> extends React.HTMLAttributes<HTMLDivElement> {
|
|
15
|
-
/** Column definitions */
|
|
16
|
-
columns: DataTableColumn<T>[];
|
|
17
|
-
/** Row data */
|
|
18
|
-
rows: T[];
|
|
19
|
-
/** Key extractor for row identity */
|
|
20
|
-
rowKey?: keyof T | ((row: T, index: number) => string);
|
|
21
|
-
/** Empty state message */
|
|
22
|
-
emptyText?: string;
|
|
23
|
-
/** Accessible label for the table (describes its content for screen readers) */
|
|
24
|
-
ariaLabel?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* PCOI DataTable — Presentational data table for dashboards
|
|
29
|
-
* Tokens: bg/card-hover, border/default, text/primary, text/secondary,
|
|
30
|
-
* font-size/caption/body-default, spacing-12/16
|
|
31
|
-
*/
|
|
32
|
-
export const DataTable = React.forwardRef<HTMLDivElement, DataTableProps>(
|
|
33
|
-
(
|
|
34
|
-
{
|
|
35
|
-
columns,
|
|
36
|
-
rows,
|
|
37
|
-
rowKey,
|
|
38
|
-
emptyText = "No data available",
|
|
39
|
-
ariaLabel,
|
|
40
|
-
className = "",
|
|
41
|
-
...rest
|
|
42
|
-
},
|
|
43
|
-
ref
|
|
44
|
-
) => {
|
|
45
|
-
const getRowKey = (row: Record<string, unknown>, index: number): string => {
|
|
46
|
-
if (!rowKey) return String(index);
|
|
47
|
-
if (typeof rowKey === "function") return rowKey(row, index);
|
|
48
|
-
return String(row[rowKey as string]);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<div ref={ref} className={`pcoi-data-table ${className}`} {...rest}>
|
|
53
|
-
<table className="pcoi-data-table__table" aria-label={ariaLabel}>
|
|
54
|
-
<thead className="pcoi-data-table__head">
|
|
55
|
-
<tr className="pcoi-data-table__head-row">
|
|
56
|
-
{columns.map((col) => (
|
|
57
|
-
<th
|
|
58
|
-
key={col.key}
|
|
59
|
-
className={`pcoi-data-table__th${col.align ? ` pcoi-data-table__th--${col.align}` : ""}`}
|
|
60
|
-
>
|
|
61
|
-
{col.header}
|
|
62
|
-
</th>
|
|
63
|
-
))}
|
|
64
|
-
</tr>
|
|
65
|
-
</thead>
|
|
66
|
-
<tbody className="pcoi-data-table__body">
|
|
67
|
-
{rows.length === 0 ? (
|
|
68
|
-
<tr>
|
|
69
|
-
<td
|
|
70
|
-
colSpan={columns.length}
|
|
71
|
-
className="pcoi-data-table__empty"
|
|
72
|
-
>
|
|
73
|
-
{emptyText}
|
|
74
|
-
</td>
|
|
75
|
-
</tr>
|
|
76
|
-
) : (
|
|
77
|
-
rows.map((row, index) => (
|
|
78
|
-
<tr
|
|
79
|
-
key={getRowKey(row as Record<string, unknown>, index)}
|
|
80
|
-
className="pcoi-data-table__row"
|
|
81
|
-
>
|
|
82
|
-
{columns.map((col) => {
|
|
83
|
-
const value = (row as Record<string, unknown>)[col.key];
|
|
84
|
-
return (
|
|
85
|
-
<td
|
|
86
|
-
key={col.key}
|
|
87
|
-
className={`pcoi-data-table__td${col.align ? ` pcoi-data-table__td--${col.align}` : ""}`}
|
|
88
|
-
>
|
|
89
|
-
{col.render ? col.render(value, row) : String(value ?? "")}
|
|
90
|
-
</td>
|
|
91
|
-
);
|
|
92
|
-
})}
|
|
93
|
-
</tr>
|
|
94
|
-
))
|
|
95
|
-
)}
|
|
96
|
-
</tbody>
|
|
97
|
-
</table>
|
|
98
|
-
</div>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
DataTable.displayName = "DataTable";
|
|
104
|
-
export default DataTable;
|
package/src/DataTable/index.ts
DELETED