@robr0/design-system 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.
- package/LICENSE +21 -0
- package/README.md +127 -0
- package/charts.d.ts +14 -0
- package/charts.js +20 -0
- package/components/Accordion/Accordion.css +119 -0
- package/components/Accordion/Accordion.d.ts +24 -0
- package/components/Accordion/Accordion.js +76 -0
- package/components/Alert/Alert.css +252 -0
- package/components/Alert/Alert.d.ts +24 -0
- package/components/Alert/Alert.js +53 -0
- package/components/AlertDialog/AlertDialog.css +131 -0
- package/components/AlertDialog/AlertDialog.d.ts +29 -0
- package/components/AlertDialog/AlertDialog.js +143 -0
- package/components/AppLayout/AppLayout.css +52 -0
- package/components/AppLayout/AppLayout.d.ts +27 -0
- package/components/AppLayout/AppLayout.js +45 -0
- package/components/AppSidebar/AppSidebar.css +434 -0
- package/components/AppSidebar/AppSidebar.d.ts +67 -0
- package/components/AppSidebar/AppSidebar.js +272 -0
- package/components/Avatar/Avatar.css +133 -0
- package/components/Avatar/Avatar.d.ts +20 -0
- package/components/Avatar/Avatar.js +56 -0
- package/components/Avatar/demoAvatars.d.ts +14 -0
- package/components/Avatar/demoAvatars.js +16 -0
- package/components/Badge/Badge.css +68 -0
- package/components/Badge/Badge.d.ts +13 -0
- package/components/Badge/Badge.js +15 -0
- package/components/Breadcrumb/Breadcrumb.css +92 -0
- package/components/Breadcrumb/Breadcrumb.d.ts +19 -0
- package/components/Breadcrumb/Breadcrumb.js +39 -0
- package/components/Button/Button.css +381 -0
- package/components/Button/Button.d.ts +39 -0
- package/components/Button/Button.js +71 -0
- package/components/ButtonGroup/ButtonGroup.css +39 -0
- package/components/ButtonGroup/ButtonGroup.d.ts +13 -0
- package/components/ButtonGroup/ButtonGroup.js +37 -0
- package/components/Card/Card.css +169 -0
- package/components/Card/Card.d.ts +30 -0
- package/components/Card/Card.js +90 -0
- package/components/Carousel/Carousel.css +112 -0
- package/components/Carousel/Carousel.d.ts +25 -0
- package/components/Carousel/Carousel.js +126 -0
- package/components/Chart/AreaChart.d.ts +36 -0
- package/components/Chart/AreaChart.js +99 -0
- package/components/Chart/BarChart.d.ts +34 -0
- package/components/Chart/BarChart.js +107 -0
- package/components/Chart/Chart.css +176 -0
- package/components/Chart/LineChart.d.ts +34 -0
- package/components/Chart/LineChart.js +90 -0
- package/components/Chart/PieChart.d.ts +34 -0
- package/components/Chart/PieChart.js +106 -0
- package/components/Chart/RadarChart.d.ts +34 -0
- package/components/Chart/RadarChart.js +91 -0
- package/components/Chart/RadialChart.d.ts +37 -0
- package/components/Chart/RadialChart.js +119 -0
- package/components/Chart/ScatterChart.d.ts +36 -0
- package/components/Chart/ScatterChart.js +109 -0
- package/components/Chart/StackedBarChart.d.ts +34 -0
- package/components/Chart/StackedBarChart.js +111 -0
- package/components/Chart/Treemap.d.ts +33 -0
- package/components/Chart/Treemap.js +109 -0
- package/components/Checkbox/Checkbox.css +164 -0
- package/components/Checkbox/Checkbox.d.ts +45 -0
- package/components/Checkbox/Checkbox.js +125 -0
- package/components/Chip/Chip.css +195 -0
- package/components/Chip/Chip.d.ts +27 -0
- package/components/Chip/Chip.js +80 -0
- package/components/CircularButton/CircularButton.css +206 -0
- package/components/CircularButton/CircularButton.d.ts +30 -0
- package/components/CircularButton/CircularButton.js +54 -0
- package/components/CodeBlock/CodeBlock.css +180 -0
- package/components/CodeBlock/CodeBlock.d.ts +23 -0
- package/components/CodeBlock/CodeBlock.js +85 -0
- package/components/ColourSwatch/ColourSwatch.css +88 -0
- package/components/ColourSwatch/ColourSwatch.d.ts +34 -0
- package/components/ColourSwatch/ColourSwatch.js +42 -0
- package/components/Combobox/Combobox.css +411 -0
- package/components/Combobox/Combobox.d.ts +73 -0
- package/components/Combobox/Combobox.js +312 -0
- package/components/CommandPalette/CommandPalette.css +310 -0
- package/components/CommandPalette/CommandPalette.d.ts +60 -0
- package/components/CommandPalette/CommandPalette.js +263 -0
- package/components/ContactCard/ContactCard.css +123 -0
- package/components/ContactCard/ContactCard.d.ts +23 -0
- package/components/ContactCard/ContactCard.js +78 -0
- package/components/ContributionGraph/ContributionGraph.css +142 -0
- package/components/ContributionGraph/ContributionGraph.d.ts +26 -0
- package/components/ContributionGraph/ContributionGraph.js +125 -0
- package/components/DateInput/DateInput.css +163 -0
- package/components/DateInput/DateInput.d.ts +43 -0
- package/components/DateInput/DateInput.js +69 -0
- package/components/DatePicker/DatePicker.css +198 -0
- package/components/DatePicker/DatePicker.d.ts +22 -0
- package/components/DatePicker/DatePicker.js +170 -0
- package/components/Dialog/Dialog.css +176 -0
- package/components/Dialog/Dialog.d.ts +28 -0
- package/components/Dialog/Dialog.js +132 -0
- package/components/Divider/Divider.css +100 -0
- package/components/Divider/Divider.d.ts +18 -0
- package/components/Divider/Divider.js +31 -0
- package/components/Drawer/Drawer.css +262 -0
- package/components/Drawer/Drawer.d.ts +30 -0
- package/components/Drawer/Drawer.js +134 -0
- package/components/Dropdown/Dropdown.css +300 -0
- package/components/Dropdown/Dropdown.d.ts +48 -0
- package/components/Dropdown/Dropdown.js +196 -0
- package/components/DropdownMenu/DropdownMenu.css +303 -0
- package/components/DropdownMenu/DropdownMenu.d.ts +42 -0
- package/components/DropdownMenu/DropdownMenu.js +322 -0
- package/components/EmptyState/EmptyState.css +115 -0
- package/components/EmptyState/EmptyState.d.ts +27 -0
- package/components/EmptyState/EmptyState.js +32 -0
- package/components/EntityCard/EntityCard.css +69 -0
- package/components/EntityCard/EntityCard.d.ts +18 -0
- package/components/EntityCard/EntityCard.js +26 -0
- package/components/Figure/Figure.css +61 -0
- package/components/Figure/Figure.d.ts +17 -0
- package/components/Figure/Figure.js +35 -0
- package/components/FileInput/FileInput.css +308 -0
- package/components/FileInput/FileInput.d.ts +54 -0
- package/components/FileInput/FileInput.js +177 -0
- package/components/Input/Input.css +193 -0
- package/components/Input/Input.d.ts +40 -0
- package/components/Input/Input.js +71 -0
- package/components/Instructions/Instructions.css +216 -0
- package/components/Instructions/Instructions.d.ts +28 -0
- package/components/Instructions/Instructions.js +32 -0
- package/components/LinkList/LinkList.css +71 -0
- package/components/LinkList/LinkList.d.ts +20 -0
- package/components/LinkList/LinkList.js +41 -0
- package/components/MotionSwatch/MotionSwatch.css +176 -0
- package/components/MotionSwatch/MotionSwatch.d.ts +25 -0
- package/components/MotionSwatch/MotionSwatch.js +74 -0
- package/components/Nav/Nav.css +51 -0
- package/components/Nav/Nav.d.ts +19 -0
- package/components/Nav/Nav.js +26 -0
- package/components/Pagination/Pagination.css +126 -0
- package/components/Pagination/Pagination.d.ts +22 -0
- package/components/Pagination/Pagination.js +83 -0
- package/components/Popover/Popover.css +99 -0
- package/components/Popover/Popover.d.ts +28 -0
- package/components/Popover/Popover.js +102 -0
- package/components/ProgressBar/ProgressBar.css +60 -0
- package/components/ProgressBar/ProgressBar.d.ts +16 -0
- package/components/ProgressBar/ProgressBar.js +27 -0
- package/components/Quote/Quote.css +79 -0
- package/components/Quote/Quote.d.ts +18 -0
- package/components/Quote/Quote.js +26 -0
- package/components/RadioButton/RadioButton.css +132 -0
- package/components/RadioButton/RadioButton.d.ts +43 -0
- package/components/RadioButton/RadioButton.js +77 -0
- package/components/SectionTitle/SectionTitle.css +37 -0
- package/components/SectionTitle/SectionTitle.d.ts +10 -0
- package/components/SectionTitle/SectionTitle.js +17 -0
- package/components/SegmentedControl/SegmentedControl.css +129 -0
- package/components/SegmentedControl/SegmentedControl.d.ts +33 -0
- package/components/SegmentedControl/SegmentedControl.js +91 -0
- package/components/SelectionCard/SelectionCard.css +251 -0
- package/components/SelectionCard/SelectionCard.d.ts +26 -0
- package/components/SelectionCard/SelectionCard.js +85 -0
- package/components/Skeleton/Skeleton.css +79 -0
- package/components/Skeleton/Skeleton.d.ts +16 -0
- package/components/Skeleton/Skeleton.js +30 -0
- package/components/Slider/Slider.css +86 -0
- package/components/Slider/Slider.d.ts +25 -0
- package/components/Slider/Slider.js +46 -0
- package/components/SpacingSwatch/SpacingSwatch.css +108 -0
- package/components/SpacingSwatch/SpacingSwatch.d.ts +20 -0
- package/components/SpacingSwatch/SpacingSwatch.js +50 -0
- package/components/Spinner/Spinner.css +73 -0
- package/components/Spinner/Spinner.d.ts +14 -0
- package/components/Spinner/Spinner.js +42 -0
- package/components/Stat/Stat.css +78 -0
- package/components/Stat/Stat.d.ts +19 -0
- package/components/Stat/Stat.js +30 -0
- package/components/Table/Table.css +186 -0
- package/components/Table/Table.d.ts +45 -0
- package/components/Table/Table.js +65 -0
- package/components/Tabs/Tabs.css +140 -0
- package/components/Tabs/Tabs.d.ts +28 -0
- package/components/Tabs/Tabs.js +77 -0
- package/components/Textarea/Textarea.css +152 -0
- package/components/Textarea/Textarea.d.ts +40 -0
- package/components/Textarea/Textarea.js +74 -0
- package/components/Timeline/Timeline.css +339 -0
- package/components/Timeline/Timeline.d.ts +63 -0
- package/components/Timeline/Timeline.js +69 -0
- package/components/Toast/Toast.css +342 -0
- package/components/Toast/Toast.d.ts +63 -0
- package/components/Toast/Toast.js +213 -0
- package/components/ToggleGroup/ToggleGroup.css +84 -0
- package/components/ToggleGroup/ToggleGroup.d.ts +30 -0
- package/components/ToggleGroup/ToggleGroup.js +53 -0
- package/components/ToggleSwitch/ToggleSwitch.css +139 -0
- package/components/ToggleSwitch/ToggleSwitch.d.ts +23 -0
- package/components/ToggleSwitch/ToggleSwitch.js +50 -0
- package/components/Tooltip/Tooltip.css +122 -0
- package/components/Tooltip/Tooltip.d.ts +21 -0
- package/components/Tooltip/Tooltip.js +63 -0
- package/components/TypographySwatch/TypographySwatch.css +81 -0
- package/components/TypographySwatch/TypographySwatch.d.ts +24 -0
- package/components/TypographySwatch/TypographySwatch.js +40 -0
- package/components/registry.d.ts +20 -0
- package/components/registry.js +7 -0
- package/components/registry.json +67 -0
- package/components/registry.json.d.ts +70 -0
- package/components/registry.json.js +8 -0
- package/fonts/MaterialSymbolsRounded-VariableFont_FILL,GRAD,opsz,wght.woff2 +0 -0
- package/fonts/material-symbols.css +94 -0
- package/index.d.ts +62 -0
- package/index.js +123 -0
- package/package.json +63 -0
- package/tokens/registry.d.ts +22 -0
- package/tokens/registry.js +14 -0
- package/tokens/registry.json +203 -0
- package/tokens/registry.json.d.ts +206 -0
- package/tokens/registry.json.js +8 -0
- package/tokens/tokens-dark.css +119 -0
- package/tokens/tokens-light.css +159 -0
- package/tokens/tokens-motion.css +68 -0
- package/tokens/tokens-primitives.css +176 -0
- package/tokens/tokens-typography.css +116 -0
- package/tokens/tokens.css +11 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
TEXTAREA COMPONENT
|
|
3
|
+
Multi-line text input with label and counter
|
|
4
|
+
============================================ */
|
|
5
|
+
|
|
6
|
+
.ds-textarea {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: var(--gap-sm); /* 8px */
|
|
10
|
+
width: 100%;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* ============================================
|
|
14
|
+
LABEL
|
|
15
|
+
============================================ */
|
|
16
|
+
|
|
17
|
+
.ds-textarea__label {
|
|
18
|
+
font-family: var(--font-paragraph-em-family);
|
|
19
|
+
font-size: var(--font-paragraph-em-size);
|
|
20
|
+
font-weight: var(--font-paragraph-em-weight);
|
|
21
|
+
line-height: var(--font-paragraph-em-line-height);
|
|
22
|
+
letter-spacing: var(--font-paragraph-em-letter-spacing);
|
|
23
|
+
color: var(--color-text-primary);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.ds-textarea__required {
|
|
27
|
+
color: var(--color-core-accent-coral);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* ============================================
|
|
31
|
+
FIELD
|
|
32
|
+
============================================ */
|
|
33
|
+
|
|
34
|
+
.ds-textarea__field {
|
|
35
|
+
width: 100%;
|
|
36
|
+
padding: var(--padding-sm) var(--padding-md); /* 8px 16px */
|
|
37
|
+
border: var(--border-xs) solid var(--color-input-border-primary);
|
|
38
|
+
border-radius: var(--radius-md); /* 12px */
|
|
39
|
+
background-color: var(--color-input-bg-primary);
|
|
40
|
+
|
|
41
|
+
/* Typography */
|
|
42
|
+
font-family: var(--font-paragraph-family);
|
|
43
|
+
font-size: var(--font-paragraph-size);
|
|
44
|
+
font-weight: var(--font-paragraph-weight);
|
|
45
|
+
line-height: var(--font-paragraph-line-height);
|
|
46
|
+
letter-spacing: var(--font-paragraph-letter-spacing);
|
|
47
|
+
color: var(--color-input-text-primary);
|
|
48
|
+
|
|
49
|
+
/* Transitions */
|
|
50
|
+
transition: border-color var(--motion-duration-base) var(--motion-ease-standard), background-color var(--motion-duration-base) var(--motion-ease-standard);
|
|
51
|
+
outline: none;
|
|
52
|
+
box-sizing: border-box;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.ds-textarea__field::placeholder {
|
|
56
|
+
color: var(--color-input-text-placeholder);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ds-textarea__field:hover:not(:focus):not(:disabled) {
|
|
60
|
+
border-color: var(--color-input-border-hover);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ds-textarea__field:focus {
|
|
64
|
+
border-color: var(--color-input-border-selected);
|
|
65
|
+
background-color: var(--color-input-bg-primary);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* ============================================
|
|
69
|
+
FOOTER (helper + counter)
|
|
70
|
+
============================================ */
|
|
71
|
+
|
|
72
|
+
.ds-textarea__footer {
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: flex-start;
|
|
75
|
+
justify-content: space-between;
|
|
76
|
+
gap: var(--gap-sm);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.ds-textarea__helper {
|
|
80
|
+
font-family: var(--font-paragraph-sm-family);
|
|
81
|
+
font-size: var(--font-paragraph-sm-size);
|
|
82
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
83
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
84
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
85
|
+
color: var(--color-text-tertiary);
|
|
86
|
+
margin: 0;
|
|
87
|
+
flex: 1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.ds-textarea__counter {
|
|
91
|
+
font-family: var(--font-paragraph-sm-family);
|
|
92
|
+
font-size: var(--font-paragraph-sm-size);
|
|
93
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
94
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
95
|
+
color: var(--color-text-tertiary);
|
|
96
|
+
flex-shrink: 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* ============================================
|
|
100
|
+
ERROR STATE
|
|
101
|
+
============================================ */
|
|
102
|
+
|
|
103
|
+
.ds-textarea--error .ds-textarea__field {
|
|
104
|
+
border-color: var(--color-status-error-border);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.ds-textarea--error .ds-textarea__field:focus {
|
|
108
|
+
border-color: var(--color-status-error-border);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.ds-textarea--error .ds-textarea__helper {
|
|
112
|
+
color: var(--color-status-error-border);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.ds-textarea--error .ds-textarea__counter {
|
|
116
|
+
color: var(--color-status-error-border);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* ============================================
|
|
120
|
+
DISABLED STATE
|
|
121
|
+
============================================ */
|
|
122
|
+
|
|
123
|
+
.ds-textarea--disabled .ds-textarea__label {
|
|
124
|
+
color: var(--color-input-text-disabled);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.ds-textarea--disabled .ds-textarea__field {
|
|
128
|
+
background-color: var(--color-input-bg-disabled);
|
|
129
|
+
border-color: var(--color-input-border-disabled);
|
|
130
|
+
color: var(--color-input-text-disabled);
|
|
131
|
+
cursor: not-allowed;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.ds-textarea--disabled .ds-textarea__field::placeholder {
|
|
135
|
+
color: var(--color-input-text-disabled);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* ============================================
|
|
139
|
+
SIZE — COMPACT
|
|
140
|
+
============================================ */
|
|
141
|
+
|
|
142
|
+
.ds-textarea--compact .ds-textarea__field {
|
|
143
|
+
padding: var(--padding-xs) var(--padding-sm-md); /* 6px 12px */
|
|
144
|
+
font-size: var(--font-paragraph-sm-size);
|
|
145
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
146
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.ds-textarea--compact .ds-textarea__label {
|
|
150
|
+
font-size: var(--font-paragraph-sm-size);
|
|
151
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
152
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface TextareaProps {
|
|
3
|
+
/** Textarea label text */
|
|
4
|
+
label?: string;
|
|
5
|
+
/** Placeholder text */
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
/** Current value */
|
|
8
|
+
value?: string;
|
|
9
|
+
/** Number of visible rows */
|
|
10
|
+
rows?: number;
|
|
11
|
+
/** Component size */
|
|
12
|
+
size?: 'default' | 'compact';
|
|
13
|
+
/** Whether the textarea is disabled */
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
/** Whether the textarea is required */
|
|
16
|
+
required?: boolean;
|
|
17
|
+
/** Error state — shows error styling and message */
|
|
18
|
+
error?: boolean;
|
|
19
|
+
/** Helper or error message displayed below */
|
|
20
|
+
helperText?: string;
|
|
21
|
+
/** Whether the textarea is resizable */
|
|
22
|
+
resize?: 'none' | 'vertical' | 'horizontal' | 'both';
|
|
23
|
+
/** Max character count — shows counter when set */
|
|
24
|
+
maxLength?: number;
|
|
25
|
+
/** Callback when value changes */
|
|
26
|
+
onChange?: (value: string) => void;
|
|
27
|
+
/** Callback on focus */
|
|
28
|
+
onFocus?: () => void;
|
|
29
|
+
/** Callback on blur */
|
|
30
|
+
onBlur?: () => void;
|
|
31
|
+
/** Additional CSS classes */
|
|
32
|
+
className?: string;
|
|
33
|
+
/** Accessible label override */
|
|
34
|
+
ariaLabel?: string;
|
|
35
|
+
/** HTML name attribute */
|
|
36
|
+
name?: string;
|
|
37
|
+
/** HTML id attribute */
|
|
38
|
+
id?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare const Textarea: ({ label, placeholder, value, rows, size, disabled, required, error, helperText, resize, maxLength, onChange, onFocus, onBlur, className, ariaLabel, name, id, }: TextareaProps) => React.JSX.Element;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import "./Textarea.css";
|
|
4
|
+
const Textarea = ({
|
|
5
|
+
label,
|
|
6
|
+
placeholder = "",
|
|
7
|
+
value = "",
|
|
8
|
+
rows = 4,
|
|
9
|
+
size = "default",
|
|
10
|
+
disabled = false,
|
|
11
|
+
required = false,
|
|
12
|
+
error = false,
|
|
13
|
+
helperText,
|
|
14
|
+
resize = "vertical",
|
|
15
|
+
maxLength,
|
|
16
|
+
onChange,
|
|
17
|
+
onFocus,
|
|
18
|
+
onBlur,
|
|
19
|
+
className = "",
|
|
20
|
+
ariaLabel,
|
|
21
|
+
name,
|
|
22
|
+
id
|
|
23
|
+
}) => {
|
|
24
|
+
const baseClass = "ds-textarea";
|
|
25
|
+
const sizeClass = size === "compact" ? `${baseClass}--compact` : "";
|
|
26
|
+
const errorClass = error ? `${baseClass}--error` : "";
|
|
27
|
+
const disabledClass = disabled ? `${baseClass}--disabled` : "";
|
|
28
|
+
const classes = [baseClass, sizeClass, errorClass, disabledClass, className].filter(Boolean).join(" ");
|
|
29
|
+
const handleChange = (e) => {
|
|
30
|
+
if (onChange) {
|
|
31
|
+
onChange(e.target.value);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const inputId = id || name || label?.toLowerCase().replace(/\s+/g, "-");
|
|
35
|
+
const charCount = value?.length || 0;
|
|
36
|
+
return /* @__PURE__ */ jsxs("div", { className: classes, children: [
|
|
37
|
+
label && /* @__PURE__ */ jsxs("label", { className: `${baseClass}__label`, htmlFor: inputId, children: [
|
|
38
|
+
label,
|
|
39
|
+
required && /* @__PURE__ */ jsx("span", { className: `${baseClass}__required`, "aria-hidden": "true", children: " *" })
|
|
40
|
+
] }),
|
|
41
|
+
/* @__PURE__ */ jsx(
|
|
42
|
+
"textarea",
|
|
43
|
+
{
|
|
44
|
+
className: `${baseClass}__field`,
|
|
45
|
+
id: inputId,
|
|
46
|
+
name,
|
|
47
|
+
value,
|
|
48
|
+
placeholder,
|
|
49
|
+
rows,
|
|
50
|
+
disabled,
|
|
51
|
+
required,
|
|
52
|
+
maxLength,
|
|
53
|
+
"aria-label": ariaLabel || label,
|
|
54
|
+
"aria-invalid": error,
|
|
55
|
+
"aria-describedby": helperText ? `${inputId}-helper` : void 0,
|
|
56
|
+
onChange: handleChange,
|
|
57
|
+
onFocus,
|
|
58
|
+
onBlur,
|
|
59
|
+
style: { resize }
|
|
60
|
+
}
|
|
61
|
+
),
|
|
62
|
+
/* @__PURE__ */ jsxs("div", { className: `${baseClass}__footer`, children: [
|
|
63
|
+
helperText && /* @__PURE__ */ jsx("p", { className: `${baseClass}__helper`, id: `${inputId}-helper`, children: helperText }),
|
|
64
|
+
maxLength && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__counter`, "aria-live": "polite", "aria-atomic": "true", children: [
|
|
65
|
+
charCount,
|
|
66
|
+
"/",
|
|
67
|
+
maxLength
|
|
68
|
+
] })
|
|
69
|
+
] })
|
|
70
|
+
] });
|
|
71
|
+
};
|
|
72
|
+
export {
|
|
73
|
+
Textarea
|
|
74
|
+
};
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
TIMELINE COMPONENT
|
|
3
|
+
Ordered steps/events with connected markers.
|
|
4
|
+
Vertical timeline or horizontal stepper.
|
|
5
|
+
============================================ */
|
|
6
|
+
|
|
7
|
+
.ds-timeline {
|
|
8
|
+
margin: 0;
|
|
9
|
+
padding: 0;
|
|
10
|
+
list-style: none;
|
|
11
|
+
display: flex;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.ds-timeline__item {
|
|
15
|
+
position: relative;
|
|
16
|
+
display: flex;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* ============================================
|
|
20
|
+
MARKERS
|
|
21
|
+
Dot by default; badge (circle) when numbered;
|
|
22
|
+
bare floating icon when carrying an icon.
|
|
23
|
+
============================================ */
|
|
24
|
+
|
|
25
|
+
.ds-timeline__marker {
|
|
26
|
+
position: relative;
|
|
27
|
+
z-index: 1;
|
|
28
|
+
flex-shrink: 0;
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
width: 12px;
|
|
33
|
+
height: 12px;
|
|
34
|
+
border-radius: var(--radius-full);
|
|
35
|
+
background-color: var(--color-bg-container-tertiary);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.ds-timeline__marker--badge {
|
|
39
|
+
width: 28px;
|
|
40
|
+
height: 28px;
|
|
41
|
+
background-color: var(--color-bg-container-primary);
|
|
42
|
+
border: var(--border-xs) solid var(--color-bg-container-border);
|
|
43
|
+
font-family: var(--font-paragraph-sm-em-family);
|
|
44
|
+
font-size: var(--font-paragraph-sm-em-size);
|
|
45
|
+
font-weight: var(--font-paragraph-sm-em-weight);
|
|
46
|
+
color: var(--color-text-secondary);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Icon markers float bare — same 28px box as the badge
|
|
50
|
+
so connector geometry is shared, but no circle */
|
|
51
|
+
.ds-timeline__marker--icon {
|
|
52
|
+
width: 28px;
|
|
53
|
+
height: 28px;
|
|
54
|
+
background-color: transparent;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.ds-timeline__marker-icon {
|
|
58
|
+
--icon-size: var(--icon-size-md);
|
|
59
|
+
line-height: 1;
|
|
60
|
+
color: var(--color-icon-primary);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* ============================================
|
|
64
|
+
CONTENT
|
|
65
|
+
============================================ */
|
|
66
|
+
|
|
67
|
+
.ds-timeline__content {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
gap: var(--gap-xxs);
|
|
71
|
+
min-width: 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.ds-timeline__meta {
|
|
75
|
+
font-family: var(--font-paragraph-sm-family);
|
|
76
|
+
font-size: var(--font-paragraph-sm-size);
|
|
77
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
78
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
79
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
80
|
+
color: var(--color-text-tertiary);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.ds-timeline__title {
|
|
84
|
+
font-family: var(--font-heading-3-family);
|
|
85
|
+
font-size: var(--font-heading-3-size);
|
|
86
|
+
font-weight: var(--font-heading-3-weight);
|
|
87
|
+
line-height: var(--font-heading-3-line-height);
|
|
88
|
+
letter-spacing: var(--font-heading-3-letter-spacing);
|
|
89
|
+
color: var(--color-text-primary);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.ds-timeline__description {
|
|
93
|
+
margin-top: var(--gap-sm);
|
|
94
|
+
font-family: var(--font-paragraph-family);
|
|
95
|
+
font-size: var(--font-paragraph-size);
|
|
96
|
+
font-weight: var(--font-paragraph-weight);
|
|
97
|
+
line-height: var(--font-paragraph-line-height);
|
|
98
|
+
letter-spacing: var(--font-paragraph-letter-spacing);
|
|
99
|
+
color: var(--color-text-primary);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* ============================================
|
|
103
|
+
VERTICAL (default) — markers on the left,
|
|
104
|
+
connector line running down between them
|
|
105
|
+
============================================ */
|
|
106
|
+
|
|
107
|
+
.ds-timeline--vertical {
|
|
108
|
+
flex-direction: column;
|
|
109
|
+
gap: var(--gap-lg);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.ds-timeline--vertical .ds-timeline__item {
|
|
113
|
+
gap: var(--gap-md);
|
|
114
|
+
align-items: flex-start;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* Align dot markers with the title's line box */
|
|
118
|
+
.ds-timeline--vertical .ds-timeline__marker {
|
|
119
|
+
margin-top: 6px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.ds-timeline--vertical .ds-timeline__marker--badge,
|
|
123
|
+
.ds-timeline--vertical .ds-timeline__marker--icon {
|
|
124
|
+
margin-top: 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Connector line — from this marker down to the next item */
|
|
128
|
+
.ds-timeline--vertical .ds-timeline__item::before {
|
|
129
|
+
content: '';
|
|
130
|
+
position: absolute;
|
|
131
|
+
top: 0;
|
|
132
|
+
bottom: calc(-1 * var(--gap-lg));
|
|
133
|
+
left: 5px; /* centre of the 12px dot */
|
|
134
|
+
width: var(--border-md);
|
|
135
|
+
background-color: var(--color-divider);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.ds-timeline--vertical.ds-timeline--numbered .ds-timeline__item::before,
|
|
139
|
+
.ds-timeline--vertical .ds-timeline__item:has(.ds-timeline__marker--badge)::before,
|
|
140
|
+
.ds-timeline--vertical .ds-timeline__item:has(.ds-timeline__marker--icon)::before {
|
|
141
|
+
left: 13px; /* centre of the 28px badge/icon box */
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* Bare icons have no opaque fill to cover the line —
|
|
145
|
+
start it just below the icon box instead */
|
|
146
|
+
.ds-timeline--vertical .ds-timeline__item:has(.ds-timeline__marker--icon)::before {
|
|
147
|
+
top: 32px;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.ds-timeline--vertical .ds-timeline__item:last-child::before {
|
|
151
|
+
display: none;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* ============================================
|
|
155
|
+
HORIZONTAL — stepper: markers on top,
|
|
156
|
+
connector line running across
|
|
157
|
+
============================================ */
|
|
158
|
+
|
|
159
|
+
.ds-timeline--horizontal {
|
|
160
|
+
flex-direction: row;
|
|
161
|
+
align-items: flex-start;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.ds-timeline--horizontal .ds-timeline__item {
|
|
165
|
+
flex: 1;
|
|
166
|
+
flex-direction: column;
|
|
167
|
+
gap: var(--gap-sm);
|
|
168
|
+
min-width: 0;
|
|
169
|
+
padding-right: var(--padding-md);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* Connector line — from this marker across to the next */
|
|
173
|
+
.ds-timeline--horizontal .ds-timeline__item::before {
|
|
174
|
+
content: '';
|
|
175
|
+
position: absolute;
|
|
176
|
+
top: 5px; /* centre of the 12px dot */
|
|
177
|
+
left: 0;
|
|
178
|
+
right: 0;
|
|
179
|
+
height: var(--border-md);
|
|
180
|
+
background-color: var(--color-divider);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.ds-timeline--horizontal.ds-timeline--numbered .ds-timeline__item::before,
|
|
184
|
+
.ds-timeline--horizontal .ds-timeline__item:has(.ds-timeline__marker--badge)::before,
|
|
185
|
+
.ds-timeline--horizontal .ds-timeline__item:has(.ds-timeline__marker--icon)::before {
|
|
186
|
+
top: 13px; /* centre of the 28px badge/icon box */
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* Bare icons have no opaque fill to cover the line —
|
|
190
|
+
start it just after the icon box instead */
|
|
191
|
+
.ds-timeline--horizontal .ds-timeline__item:has(.ds-timeline__marker--icon)::before {
|
|
192
|
+
left: 32px;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.ds-timeline--horizontal .ds-timeline__item:last-child::before {
|
|
196
|
+
display: none;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* ============================================
|
|
200
|
+
COMPANY VARIANT — a logo marker per entry,
|
|
201
|
+
a company/tool name, and one or more nested
|
|
202
|
+
roles. A segmented bar runs down each entry
|
|
203
|
+
(résumé / pipeline histories).
|
|
204
|
+
============================================ */
|
|
205
|
+
|
|
206
|
+
/* 32px logo marker — bare, transparent box; the image keeps its own shape.
|
|
207
|
+
Reset the base marker's circular clip so logos are never cropped. */
|
|
208
|
+
.ds-timeline__marker--logo {
|
|
209
|
+
width: 32px;
|
|
210
|
+
height: 32px;
|
|
211
|
+
background-color: transparent;
|
|
212
|
+
border-radius: 0;
|
|
213
|
+
overflow: visible;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* Logos display in their natural aspect ratio, capped at the 32px box */
|
|
217
|
+
.ds-timeline__marker--logo :where(img, svg) {
|
|
218
|
+
max-width: 32px;
|
|
219
|
+
max-height: 32px;
|
|
220
|
+
object-fit: contain;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* Logo sits at the top of the entry, aligned with the company name */
|
|
224
|
+
.ds-timeline--company .ds-timeline__marker--logo {
|
|
225
|
+
margin-top: 0;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.ds-timeline--company .ds-timeline__content {
|
|
229
|
+
gap: var(--gap-sm);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.ds-timeline__company-name {
|
|
233
|
+
font-family: var(--font-title-body-family);
|
|
234
|
+
font-size: var(--font-title-body-size);
|
|
235
|
+
font-weight: var(--font-title-body-weight);
|
|
236
|
+
line-height: var(--font-title-body-line-height);
|
|
237
|
+
color: var(--color-text-primary);
|
|
238
|
+
/* centre the name against the 32px logo */
|
|
239
|
+
display: flex;
|
|
240
|
+
align-items: center;
|
|
241
|
+
min-height: 32px;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.ds-timeline__roles {
|
|
245
|
+
display: flex;
|
|
246
|
+
flex-direction: column;
|
|
247
|
+
gap: var(--gap-lg);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.ds-timeline__role {
|
|
251
|
+
display: flex;
|
|
252
|
+
flex-direction: column;
|
|
253
|
+
gap: var(--gap-sm);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.ds-timeline__role-header {
|
|
257
|
+
display: flex;
|
|
258
|
+
align-items: center;
|
|
259
|
+
justify-content: space-between;
|
|
260
|
+
gap: var(--gap-md);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.ds-timeline__role-title {
|
|
264
|
+
margin: 0;
|
|
265
|
+
flex: 1;
|
|
266
|
+
min-width: 0;
|
|
267
|
+
font-family: var(--font-heading-3-family);
|
|
268
|
+
font-size: var(--font-heading-3-size);
|
|
269
|
+
font-weight: var(--font-heading-3-weight);
|
|
270
|
+
line-height: var(--font-heading-3-line-height);
|
|
271
|
+
letter-spacing: var(--font-heading-3-letter-spacing);
|
|
272
|
+
color: var(--color-text-primary);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.ds-timeline__role-dates {
|
|
276
|
+
flex-shrink: 0;
|
|
277
|
+
white-space: nowrap;
|
|
278
|
+
font-family: var(--font-paragraph-family);
|
|
279
|
+
font-size: var(--font-paragraph-size);
|
|
280
|
+
font-weight: var(--font-paragraph-weight);
|
|
281
|
+
line-height: var(--font-paragraph-line-height);
|
|
282
|
+
color: var(--color-text-tertiary);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.ds-timeline__present {
|
|
286
|
+
color: var(--color-status-positive-text);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.ds-timeline__role-description {
|
|
290
|
+
margin: 0;
|
|
291
|
+
font-family: var(--font-paragraph-family);
|
|
292
|
+
font-size: var(--font-paragraph-size);
|
|
293
|
+
font-weight: var(--font-paragraph-weight);
|
|
294
|
+
line-height: var(--font-paragraph-line-height);
|
|
295
|
+
letter-spacing: var(--font-paragraph-letter-spacing);
|
|
296
|
+
color: var(--color-text-secondary);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.ds-timeline__role-bullets {
|
|
300
|
+
margin: 0;
|
|
301
|
+
padding-left: 20px;
|
|
302
|
+
list-style: disc;
|
|
303
|
+
display: flex;
|
|
304
|
+
flex-direction: column;
|
|
305
|
+
gap: var(--gap-sm);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.ds-timeline__role-bullets li {
|
|
309
|
+
font-family: var(--font-paragraph-family);
|
|
310
|
+
font-size: var(--font-paragraph-size);
|
|
311
|
+
font-weight: var(--font-paragraph-weight);
|
|
312
|
+
line-height: var(--font-paragraph-line-height);
|
|
313
|
+
color: var(--color-text-secondary);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.ds-timeline__role-bullets a {
|
|
317
|
+
color: var(--color-action-primary-bg);
|
|
318
|
+
font-weight: var(--font-paragraph-em-weight);
|
|
319
|
+
text-decoration: none;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.ds-timeline__role-bullets a:hover {
|
|
323
|
+
text-decoration: underline;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* Connector — centred under the 32px logo, with an even 8px break above and
|
|
327
|
+
below every logo: it starts 8px below this logo and runs down to 8px above
|
|
328
|
+
the next one (extending into the inter-entry gap). */
|
|
329
|
+
.ds-timeline--company .ds-timeline__item::before {
|
|
330
|
+
left: 16px; /* centre of the 32px logo */
|
|
331
|
+
top: 40px; /* 32px logo + 8px break */
|
|
332
|
+
bottom: calc(8px - var(--gap-lg)); /* stop 8px above the next logo */
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/* Last entry has no following logo — stop the bar at its own content */
|
|
336
|
+
.ds-timeline--company .ds-timeline__item:last-child::before {
|
|
337
|
+
display: block;
|
|
338
|
+
bottom: 0;
|
|
339
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface TimelineItem {
|
|
3
|
+
/** Step or event title */
|
|
4
|
+
title: string;
|
|
5
|
+
/** Small line above the title, e.g. a date range or stage tag */
|
|
6
|
+
meta?: string;
|
|
7
|
+
/** Body content under the title */
|
|
8
|
+
description?: React.ReactNode;
|
|
9
|
+
/** Material Symbol shown in the marker (overrides dot/number) */
|
|
10
|
+
icon?: string;
|
|
11
|
+
}
|
|
12
|
+
/** A single role/position within a company entry (`company` variant). */
|
|
13
|
+
export interface TimelineRole {
|
|
14
|
+
/** Role or position title */
|
|
15
|
+
title: string;
|
|
16
|
+
/** Start of the date range, e.g. "May 2024" (omit for entries with no dates) */
|
|
17
|
+
start?: string;
|
|
18
|
+
/** End of the date range, e.g. "Jan 2026" (ignored when `present` is set) */
|
|
19
|
+
end?: string;
|
|
20
|
+
/** Renders a green "Present" in place of `end` for current roles */
|
|
21
|
+
present?: boolean;
|
|
22
|
+
/** Optional summary paragraph under the role header */
|
|
23
|
+
description?: React.ReactNode;
|
|
24
|
+
/** Optional bullet points; each entry is rendered as an `<li>` */
|
|
25
|
+
bullets?: React.ReactNode[];
|
|
26
|
+
}
|
|
27
|
+
/** A company/tool entry grouping one or more roles under a logo (`company` variant). */
|
|
28
|
+
export interface TimelineCompany {
|
|
29
|
+
/** Company or tool name shown beside the logo */
|
|
30
|
+
name: string;
|
|
31
|
+
/** Image node used as the marker (e.g. an `<img>` / framework image element) */
|
|
32
|
+
logo?: React.ReactNode;
|
|
33
|
+
/** One or more roles nested under this entry */
|
|
34
|
+
roles: TimelineRole[];
|
|
35
|
+
}
|
|
36
|
+
/** Default variant — a flat sequence of steps/events with dot, badge, or icon markers. */
|
|
37
|
+
export interface TimelineDefaultProps {
|
|
38
|
+
variant?: 'default';
|
|
39
|
+
/** Ordered list of steps/events */
|
|
40
|
+
items: TimelineItem[];
|
|
41
|
+
/** `vertical` timeline (default) or `horizontal` stepper */
|
|
42
|
+
orientation?: 'vertical' | 'horizontal';
|
|
43
|
+
/** Number the markers 1..n instead of dots */
|
|
44
|
+
numbered?: boolean;
|
|
45
|
+
/** Additional CSS classes */
|
|
46
|
+
className?: string;
|
|
47
|
+
}
|
|
48
|
+
/** Company variant — grouped roles under a logo, for résumé/pipeline histories. */
|
|
49
|
+
export interface TimelineCompanyProps {
|
|
50
|
+
variant: 'company';
|
|
51
|
+
/** Ordered list of company/tool entries */
|
|
52
|
+
items: TimelineCompany[];
|
|
53
|
+
/** Additional CSS classes */
|
|
54
|
+
className?: string;
|
|
55
|
+
}
|
|
56
|
+
export type TimelineProps = TimelineDefaultProps | TimelineCompanyProps;
|
|
57
|
+
/**
|
|
58
|
+
* Timeline component — an ordered sequence of steps or events with
|
|
59
|
+
* connected markers. Vertical for histories and process narratives,
|
|
60
|
+
* horizontal for compact steppers. The `company` variant groups one or
|
|
61
|
+
* more roles under a logo marker for résumé/pipeline histories.
|
|
62
|
+
*/
|
|
63
|
+
export declare const Timeline: (props: TimelineProps) => React.JSX.Element;
|