@proyecto-viviana/ui 0.3.2 → 0.3.4
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/dist/components.css +1077 -1077
- package/dist/index.js +236 -249
- package/dist/index.js.map +3 -3
- package/dist/index.ssr.js +78 -81
- package/dist/index.ssr.js.map +3 -3
- package/dist/radio/index.d.ts +12 -27
- package/dist/radio/index.d.ts.map +1 -1
- package/dist/test-utils/index.d.ts +2 -2
- package/dist/test-utils/index.d.ts.map +1 -1
- package/package.json +13 -12
- package/src/alert/index.tsx +48 -0
- package/src/assets/favicon.png +0 -0
- package/src/assets/fire.gif +0 -0
- package/src/autocomplete/index.tsx +313 -0
- package/src/avatar/index.tsx +75 -0
- package/src/badge/index.tsx +43 -0
- package/src/breadcrumbs/index.tsx +207 -0
- package/src/button/Button.tsx +74 -0
- package/src/button/index.ts +2 -0
- package/src/button/types.ts +24 -0
- package/src/calendar/DateField.tsx +200 -0
- package/src/calendar/DatePicker.tsx +298 -0
- package/src/calendar/RangeCalendar.tsx +236 -0
- package/src/calendar/TimeField.tsx +196 -0
- package/src/calendar/index.tsx +223 -0
- package/src/checkbox/index.tsx +257 -0
- package/src/color/index.tsx +687 -0
- package/src/combobox/index.tsx +383 -0
- package/src/components.css +1077 -0
- package/src/custom/calendar-card/index.tsx +66 -0
- package/src/custom/chip/index.tsx +46 -0
- package/src/custom/conversation/index.tsx +105 -0
- package/src/custom/event-card/index.tsx +132 -0
- package/src/custom/header/index.tsx +33 -0
- package/src/custom/lateral-nav/index.tsx +88 -0
- package/src/custom/logo/index.tsx +58 -0
- package/src/custom/nav-header/index.tsx +42 -0
- package/src/custom/page-layout/index.tsx +29 -0
- package/src/custom/profile-card/index.tsx +64 -0
- package/src/custom/project-card/index.tsx +59 -0
- package/src/custom/timeline-item/index.tsx +105 -0
- package/src/dialog/Dialog.tsx +260 -0
- package/src/dialog/index.tsx +3 -0
- package/src/disclosure/index.tsx +307 -0
- package/src/gridlist/index.tsx +403 -0
- package/src/icon/icons/GitHubIcon.tsx +20 -0
- package/src/icon/index.tsx +48 -0
- package/src/index.ts +322 -0
- package/src/landmark/index.tsx +231 -0
- package/src/link/index.tsx +130 -0
- package/src/listbox/index.tsx +231 -0
- package/src/menu/index.tsx +297 -0
- package/src/meter/index.tsx +163 -0
- package/src/numberfield/index.tsx +482 -0
- package/src/popover/index.tsx +260 -0
- package/src/progress-bar/index.tsx +169 -0
- package/src/radio/index.tsx +173 -0
- package/src/searchfield/index.tsx +453 -0
- package/src/select/index.tsx +349 -0
- package/src/separator/index.tsx +141 -0
- package/src/slider/index.tsx +382 -0
- package/src/styles.css +450 -0
- package/src/switch/ToggleSwitch.tsx +112 -0
- package/src/switch/index.tsx +90 -0
- package/src/table/index.tsx +531 -0
- package/src/tabs/index.tsx +273 -0
- package/src/tag-group/index.tsx +240 -0
- package/src/test-utils/index.ts +40 -0
- package/src/textfield/index.tsx +211 -0
- package/src/theme.css +101 -0
- package/src/toast/index.tsx +324 -0
- package/src/toolbar/index.tsx +108 -0
- package/src/tooltip/index.tsx +197 -0
- package/src/tree/index.tsx +494 -0
- package/dist/index.jsx +0 -6658
- package/dist/index.jsx.map +0 -7
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { JSX } from 'solid-js';
|
|
2
|
+
|
|
3
|
+
export interface GitHubIconProps {
|
|
4
|
+
size?: number;
|
|
5
|
+
color?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function GitHubIcon(props: GitHubIconProps): JSX.Element {
|
|
9
|
+
return (
|
|
10
|
+
<svg
|
|
11
|
+
viewBox="0 0 24 24"
|
|
12
|
+
width={props.size}
|
|
13
|
+
height={props.size}
|
|
14
|
+
fill={props.color}
|
|
15
|
+
aria-hidden="true"
|
|
16
|
+
>
|
|
17
|
+
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Component, JSX } from 'solid-js'
|
|
2
|
+
|
|
3
|
+
export interface IconProps {
|
|
4
|
+
/** The icon component to render (should accept size and color props) */
|
|
5
|
+
icon: Component<{ size?: string | number; color?: string }>
|
|
6
|
+
/** Size of the icon (e.g., '24px' or 24) */
|
|
7
|
+
size?: string | number
|
|
8
|
+
/** Color of the icon */
|
|
9
|
+
color?: string
|
|
10
|
+
/** Whether to show the accent shadow effect (4px offset to bottom) */
|
|
11
|
+
withShadow?: boolean
|
|
12
|
+
/** Additional CSS class */
|
|
13
|
+
class?: string
|
|
14
|
+
/** Click handler */
|
|
15
|
+
onClick?: () => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Icon wrapper component with optional accent shadow effect.
|
|
20
|
+
*
|
|
21
|
+
* The shadow effect creates a 4px offset accent-colored duplicate
|
|
22
|
+
* of the icon behind it for a stylized look.
|
|
23
|
+
*/
|
|
24
|
+
export function Icon(props: IconProps): JSX.Element {
|
|
25
|
+
const size = () => props.size ?? 24
|
|
26
|
+
const color = () => props.color ?? 'var(--color-primary-500)'
|
|
27
|
+
const IconComponent = props.icon
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
class={`vui-icon ${props.withShadow ? 'vui-icon--with-shadow' : ''} ${props.class ?? ''}`}
|
|
32
|
+
onClick={props.onClick}
|
|
33
|
+
>
|
|
34
|
+
{props.withShadow && (
|
|
35
|
+
<div class="vui-icon__shadow">
|
|
36
|
+
<IconComponent size={size()} color="var(--color-accent)" />
|
|
37
|
+
</div>
|
|
38
|
+
)}
|
|
39
|
+
<div class="vui-icon__main">
|
|
40
|
+
<IconComponent size={size()} color={color()} />
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Re-export common icons
|
|
47
|
+
export { GitHubIcon } from './icons/GitHubIcon'
|
|
48
|
+
export type { GitHubIconProps } from './icons/GitHubIcon'
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
// ============================================
|
|
2
|
+
// SPECTRUM-BASED COMPONENTS
|
|
3
|
+
// ============================================
|
|
4
|
+
|
|
5
|
+
// Button
|
|
6
|
+
export { Button } from './button';
|
|
7
|
+
export type { ButtonProps, ButtonVariant, ButtonStyle, StaticColor } from './button';
|
|
8
|
+
|
|
9
|
+
// Badge
|
|
10
|
+
export { Badge } from './badge';
|
|
11
|
+
export type { BadgeProps, BadgeVariant, BadgeSize } from './badge';
|
|
12
|
+
|
|
13
|
+
// Alert
|
|
14
|
+
export { Alert } from './alert';
|
|
15
|
+
export type { AlertProps, AlertVariant } from './alert';
|
|
16
|
+
|
|
17
|
+
// Avatar
|
|
18
|
+
export { Avatar, AvatarGroup } from './avatar';
|
|
19
|
+
export type { AvatarProps, AvatarGroupProps, AvatarSize } from './avatar';
|
|
20
|
+
|
|
21
|
+
// Switch
|
|
22
|
+
export { TabSwitch, ToggleSwitch } from './switch';
|
|
23
|
+
export type { TabSwitchProps, ToggleSwitchProps, SwitchSize } from './switch';
|
|
24
|
+
|
|
25
|
+
// Checkbox
|
|
26
|
+
export { Checkbox, CheckboxGroup } from './checkbox';
|
|
27
|
+
export type { CheckboxProps, CheckboxGroupProps, CheckboxSize } from './checkbox';
|
|
28
|
+
|
|
29
|
+
// Radio
|
|
30
|
+
export { RadioGroup, Radio } from './radio';
|
|
31
|
+
export type { RadioGroupProps, RadioProps, RadioGroupOrientation, RadioGroupSize } from './radio';
|
|
32
|
+
|
|
33
|
+
// Dialog
|
|
34
|
+
export { Dialog, DialogTrigger, DialogFooter } from './dialog';
|
|
35
|
+
export type { DialogProps, DialogTriggerProps, DialogFooterProps, DialogSize } from './dialog';
|
|
36
|
+
|
|
37
|
+
// Icon
|
|
38
|
+
export { Icon, GitHubIcon } from './icon';
|
|
39
|
+
export type { IconProps, GitHubIconProps } from './icon';
|
|
40
|
+
|
|
41
|
+
// Tooltip
|
|
42
|
+
export { Tooltip, TooltipTrigger, SimpleTooltip } from './tooltip';
|
|
43
|
+
export type { TooltipProps, TooltipTriggerProps, TooltipPlacement, TooltipVariant, SimpleTooltipProps } from './tooltip';
|
|
44
|
+
|
|
45
|
+
// Popover
|
|
46
|
+
export { Popover, PopoverTrigger, PopoverHeader, PopoverFooter } from './popover';
|
|
47
|
+
export type { PopoverProps, PopoverTriggerProps, PopoverHeaderProps, PopoverFooterProps, PopoverPlacement, PopoverSize, PopoverRenderProps } from './popover';
|
|
48
|
+
|
|
49
|
+
// TextField
|
|
50
|
+
export { TextField } from './textfield';
|
|
51
|
+
export type { TextFieldProps, TextFieldSize, TextFieldVariant } from './textfield';
|
|
52
|
+
|
|
53
|
+
// Link
|
|
54
|
+
export { Link } from './link';
|
|
55
|
+
export type { LinkProps, LinkVariant } from './link';
|
|
56
|
+
|
|
57
|
+
// ProgressBar
|
|
58
|
+
export { ProgressBar } from './progress-bar';
|
|
59
|
+
export type { ProgressBarProps, ProgressBarSize, ProgressBarVariant } from './progress-bar';
|
|
60
|
+
|
|
61
|
+
// Separator
|
|
62
|
+
export { Separator } from './separator';
|
|
63
|
+
export type { SeparatorProps, SeparatorVariant, SeparatorSize } from './separator';
|
|
64
|
+
|
|
65
|
+
// Toolbar
|
|
66
|
+
export { Toolbar } from './toolbar';
|
|
67
|
+
export type { ToolbarProps, ToolbarSize, ToolbarVariant } from './toolbar';
|
|
68
|
+
|
|
69
|
+
// Autocomplete
|
|
70
|
+
export { SearchAutocomplete } from './autocomplete';
|
|
71
|
+
export type { SearchAutocompleteProps, SearchAutocompleteItem, SearchAutocompleteSize } from './autocomplete';
|
|
72
|
+
|
|
73
|
+
// Select
|
|
74
|
+
export { Select, SelectTrigger, SelectValue, SelectListBox, SelectOption } from './select';
|
|
75
|
+
export type { SelectProps, SelectTriggerProps, SelectValueProps, SelectListBoxProps, SelectOptionProps, SelectSize } from './select';
|
|
76
|
+
|
|
77
|
+
// Menu
|
|
78
|
+
export { Menu, MenuItem, MenuTrigger, MenuButton, MenuSeparator } from './menu';
|
|
79
|
+
export type { MenuProps, MenuItemProps, MenuTriggerProps, MenuButtonProps, MenuSeparatorProps, MenuSize } from './menu';
|
|
80
|
+
|
|
81
|
+
// ListBox
|
|
82
|
+
export { ListBox, ListBoxOption } from './listbox';
|
|
83
|
+
export type { ListBoxProps, ListBoxOptionProps, ListBoxSize } from './listbox';
|
|
84
|
+
|
|
85
|
+
// Tabs
|
|
86
|
+
export { Tabs, TabList, Tab, TabPanel } from './tabs';
|
|
87
|
+
export type { TabsProps, TabListProps, TabProps, TabPanelProps, TabsSize, TabsVariant, TabOrientation } from './tabs';
|
|
88
|
+
|
|
89
|
+
// Breadcrumbs
|
|
90
|
+
export { Breadcrumbs, BreadcrumbItem } from './breadcrumbs';
|
|
91
|
+
export type { BreadcrumbsProps, BreadcrumbItemProps, BreadcrumbsSize, BreadcrumbsVariant } from './breadcrumbs';
|
|
92
|
+
|
|
93
|
+
// NumberField
|
|
94
|
+
export { NumberField } from './numberfield';
|
|
95
|
+
export type { NumberFieldProps, NumberFieldSize, NumberFieldVariant } from './numberfield';
|
|
96
|
+
|
|
97
|
+
// SearchField
|
|
98
|
+
export { SearchField } from './searchfield';
|
|
99
|
+
export type { SearchFieldProps, SearchFieldSize, SearchFieldVariant } from './searchfield';
|
|
100
|
+
|
|
101
|
+
// Slider
|
|
102
|
+
export { Slider } from './slider';
|
|
103
|
+
export type { SliderProps, SliderSize, SliderVariant } from './slider';
|
|
104
|
+
|
|
105
|
+
// ComboBox
|
|
106
|
+
export { ComboBox, ComboBoxInputGroup, ComboBoxInput, ComboBoxButton, ComboBoxListBox, ComboBoxOption, defaultContainsFilter } from './combobox';
|
|
107
|
+
export type { ComboBoxProps, ComboBoxInputProps, ComboBoxButtonProps, ComboBoxListBoxProps, ComboBoxOptionProps, ComboBoxSize, FilterFn, MenuTriggerAction } from './combobox';
|
|
108
|
+
|
|
109
|
+
// Toast
|
|
110
|
+
export {
|
|
111
|
+
Toast,
|
|
112
|
+
ToastRegion,
|
|
113
|
+
ToastProvider,
|
|
114
|
+
ToastContext,
|
|
115
|
+
addToast,
|
|
116
|
+
toastSuccess,
|
|
117
|
+
toastError,
|
|
118
|
+
toastWarning,
|
|
119
|
+
toastInfo,
|
|
120
|
+
globalToastQueue,
|
|
121
|
+
useToastContext,
|
|
122
|
+
} from './toast';
|
|
123
|
+
export type {
|
|
124
|
+
ToastProps,
|
|
125
|
+
ToastRegionProps,
|
|
126
|
+
ToastProviderProps,
|
|
127
|
+
ToastPlacement,
|
|
128
|
+
ToastVariant,
|
|
129
|
+
ToastContent,
|
|
130
|
+
ToastRenderProps,
|
|
131
|
+
ToastRegionRenderProps,
|
|
132
|
+
QueuedToast,
|
|
133
|
+
ToastOptions,
|
|
134
|
+
} from './toast';
|
|
135
|
+
|
|
136
|
+
// Disclosure
|
|
137
|
+
export {
|
|
138
|
+
Disclosure,
|
|
139
|
+
DisclosureGroup,
|
|
140
|
+
DisclosureTrigger,
|
|
141
|
+
DisclosurePanel,
|
|
142
|
+
} from './disclosure';
|
|
143
|
+
export type {
|
|
144
|
+
DisclosureProps,
|
|
145
|
+
DisclosureGroupProps,
|
|
146
|
+
DisclosureTriggerProps,
|
|
147
|
+
DisclosurePanelProps,
|
|
148
|
+
DisclosureSize,
|
|
149
|
+
DisclosureVariant,
|
|
150
|
+
} from './disclosure';
|
|
151
|
+
|
|
152
|
+
// Meter
|
|
153
|
+
export { Meter } from './meter';
|
|
154
|
+
export type { MeterProps, MeterSize, MeterVariant } from './meter';
|
|
155
|
+
|
|
156
|
+
// TagGroup
|
|
157
|
+
export { TagGroup } from './tag-group';
|
|
158
|
+
export type { TagGroupProps, TagProps, TagGroupSize, TagGroupVariant } from './tag-group';
|
|
159
|
+
|
|
160
|
+
// Calendar
|
|
161
|
+
export { Calendar } from './calendar';
|
|
162
|
+
export type { CalendarProps, CalendarSize, CalendarDate, DateValue } from './calendar';
|
|
163
|
+
|
|
164
|
+
// RangeCalendar
|
|
165
|
+
export { RangeCalendar } from './calendar/RangeCalendar';
|
|
166
|
+
export type { RangeCalendarProps, RangeCalendarSize, RangeValue } from './calendar/RangeCalendar';
|
|
167
|
+
|
|
168
|
+
// DateField
|
|
169
|
+
export { DateField } from './calendar/DateField';
|
|
170
|
+
export type { DateFieldProps, DateFieldSize } from './calendar/DateField';
|
|
171
|
+
|
|
172
|
+
// TimeField
|
|
173
|
+
export { TimeField } from './calendar/TimeField';
|
|
174
|
+
export type { TimeFieldProps, TimeFieldSize, TimeValue } from './calendar/TimeField';
|
|
175
|
+
|
|
176
|
+
// DatePicker
|
|
177
|
+
export { DatePicker } from './calendar/DatePicker';
|
|
178
|
+
export type { DatePickerProps, DatePickerSize } from './calendar/DatePicker';
|
|
179
|
+
|
|
180
|
+
// Table
|
|
181
|
+
export {
|
|
182
|
+
Table,
|
|
183
|
+
TableHeader,
|
|
184
|
+
TableColumn,
|
|
185
|
+
TableBody,
|
|
186
|
+
TableRow,
|
|
187
|
+
TableCell,
|
|
188
|
+
TableSelectionCheckbox,
|
|
189
|
+
TableSelectAllCheckbox,
|
|
190
|
+
} from './table';
|
|
191
|
+
export type {
|
|
192
|
+
TableProps,
|
|
193
|
+
TableHeaderProps,
|
|
194
|
+
TableColumnProps,
|
|
195
|
+
TableBodyProps,
|
|
196
|
+
TableRowProps,
|
|
197
|
+
TableCellProps,
|
|
198
|
+
TableSize,
|
|
199
|
+
TableVariant,
|
|
200
|
+
} from './table';
|
|
201
|
+
|
|
202
|
+
// GridList
|
|
203
|
+
export {
|
|
204
|
+
GridList,
|
|
205
|
+
GridListItem,
|
|
206
|
+
GridListSelectionCheckbox,
|
|
207
|
+
} from './gridlist';
|
|
208
|
+
export type {
|
|
209
|
+
GridListProps,
|
|
210
|
+
GridListItemProps,
|
|
211
|
+
GridListSize,
|
|
212
|
+
GridListVariant,
|
|
213
|
+
GridListLayout,
|
|
214
|
+
} from './gridlist';
|
|
215
|
+
|
|
216
|
+
// Tree
|
|
217
|
+
export {
|
|
218
|
+
Tree,
|
|
219
|
+
TreeItem,
|
|
220
|
+
TreeExpandButton,
|
|
221
|
+
TreeSelectionCheckbox,
|
|
222
|
+
} from './tree';
|
|
223
|
+
export type {
|
|
224
|
+
TreeProps,
|
|
225
|
+
TreeItemProps,
|
|
226
|
+
TreeExpandButtonProps,
|
|
227
|
+
TreeSize,
|
|
228
|
+
TreeVariant,
|
|
229
|
+
} from './tree';
|
|
230
|
+
|
|
231
|
+
// Color
|
|
232
|
+
export {
|
|
233
|
+
ColorSlider,
|
|
234
|
+
ColorSliderTrack,
|
|
235
|
+
ColorSliderThumb,
|
|
236
|
+
ColorArea,
|
|
237
|
+
ColorAreaGradient,
|
|
238
|
+
ColorAreaThumb,
|
|
239
|
+
ColorWheel,
|
|
240
|
+
ColorWheelTrack,
|
|
241
|
+
ColorWheelThumb,
|
|
242
|
+
ColorField,
|
|
243
|
+
ColorFieldInput,
|
|
244
|
+
ColorSwatch,
|
|
245
|
+
ColorPicker,
|
|
246
|
+
} from './color';
|
|
247
|
+
export type {
|
|
248
|
+
ColorSliderProps,
|
|
249
|
+
ColorAreaProps,
|
|
250
|
+
ColorWheelProps,
|
|
251
|
+
ColorFieldProps,
|
|
252
|
+
ColorSwatchProps,
|
|
253
|
+
ColorPickerProps,
|
|
254
|
+
ColorSize,
|
|
255
|
+
} from './color';
|
|
256
|
+
|
|
257
|
+
// Landmark
|
|
258
|
+
export {
|
|
259
|
+
Landmark,
|
|
260
|
+
SkipLink,
|
|
261
|
+
LandmarkNavigator,
|
|
262
|
+
useLandmarkController,
|
|
263
|
+
} from './landmark';
|
|
264
|
+
export type {
|
|
265
|
+
LandmarkProps,
|
|
266
|
+
SkipLinkProps,
|
|
267
|
+
LandmarkNavigatorProps,
|
|
268
|
+
AriaLandmarkRole,
|
|
269
|
+
LandmarkController,
|
|
270
|
+
} from './landmark';
|
|
271
|
+
|
|
272
|
+
// ============================================
|
|
273
|
+
// CUSTOM COMPONENTS
|
|
274
|
+
// ============================================
|
|
275
|
+
|
|
276
|
+
// Chip
|
|
277
|
+
export { Chip } from './custom/chip';
|
|
278
|
+
export type { ChipProps, ChipVariant } from './custom/chip';
|
|
279
|
+
|
|
280
|
+
// NavHeader
|
|
281
|
+
export { NavHeader } from './custom/nav-header';
|
|
282
|
+
export type { NavHeaderProps } from './custom/nav-header';
|
|
283
|
+
|
|
284
|
+
// Header
|
|
285
|
+
export { Header } from './custom/header';
|
|
286
|
+
export type { HeaderProps } from './custom/header';
|
|
287
|
+
|
|
288
|
+
// LateralNav
|
|
289
|
+
export { LateralNav, NavItem, NavLink, NavSection } from './custom/lateral-nav';
|
|
290
|
+
export type { LateralNavProps, NavItemProps, NavLinkProps, NavSectionProps } from './custom/lateral-nav';
|
|
291
|
+
|
|
292
|
+
// TimelineItem
|
|
293
|
+
export { TimelineItem } from './custom/timeline-item';
|
|
294
|
+
export type { TimelineItemProps, TimelineEventType } from './custom/timeline-item';
|
|
295
|
+
|
|
296
|
+
// Conversation
|
|
297
|
+
export { Conversation, ConversationPreview, ConversationBubble } from './custom/conversation';
|
|
298
|
+
export type { ConversationProps, ConversationPreviewProps, ConversationBubbleProps, Message } from './custom/conversation';
|
|
299
|
+
|
|
300
|
+
// ProfileCard
|
|
301
|
+
export { ProfileCard } from './custom/profile-card';
|
|
302
|
+
export type { ProfileCardProps } from './custom/profile-card';
|
|
303
|
+
|
|
304
|
+
// EventCard
|
|
305
|
+
export { EventCard, EventListItem } from './custom/event-card';
|
|
306
|
+
export type { EventCardProps, EventListItemProps } from './custom/event-card';
|
|
307
|
+
|
|
308
|
+
// CalendarCard
|
|
309
|
+
export { CalendarCard } from './custom/calendar-card';
|
|
310
|
+
export type { CalendarCardProps } from './custom/calendar-card';
|
|
311
|
+
|
|
312
|
+
// Logo
|
|
313
|
+
export { Logo } from './custom/logo';
|
|
314
|
+
export type { LogoProps, LogoSize } from './custom/logo';
|
|
315
|
+
|
|
316
|
+
// ProjectCard
|
|
317
|
+
export { ProjectCard } from './custom/project-card';
|
|
318
|
+
export type { ProjectCardProps, ProjectCardSize } from './custom/project-card';
|
|
319
|
+
|
|
320
|
+
// PageLayout
|
|
321
|
+
export { PageLayout } from './custom/page-layout';
|
|
322
|
+
export type { PageLayoutProps } from './custom/page-layout';
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Landmark component for proyecto-viviana-ui
|
|
3
|
+
*
|
|
4
|
+
* Styled landmark component built on top of solidaria-components.
|
|
5
|
+
* Landmarks help screen reader users navigate between major sections of a page.
|
|
6
|
+
* Press F6 to cycle through landmarks, or Shift+F6 to go backwards.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { type JSX, splitProps, Show } from 'solid-js'
|
|
10
|
+
import {
|
|
11
|
+
Landmark as HeadlessLandmark,
|
|
12
|
+
useLandmarkController,
|
|
13
|
+
type LandmarkProps as HeadlessLandmarkProps,
|
|
14
|
+
type AriaLandmarkRole,
|
|
15
|
+
type LandmarkController,
|
|
16
|
+
} from '@proyecto-viviana/solidaria-components'
|
|
17
|
+
|
|
18
|
+
// ============================================
|
|
19
|
+
// TYPES
|
|
20
|
+
// ============================================
|
|
21
|
+
|
|
22
|
+
export interface LandmarkProps extends Omit<HeadlessLandmarkProps, 'class' | 'style'> {
|
|
23
|
+
/** Additional CSS class name. */
|
|
24
|
+
class?: string
|
|
25
|
+
/** Whether to show a visual indicator (for development). */
|
|
26
|
+
showLabel?: boolean
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type { AriaLandmarkRole, LandmarkController }
|
|
30
|
+
|
|
31
|
+
// ============================================
|
|
32
|
+
// STYLES
|
|
33
|
+
// ============================================
|
|
34
|
+
|
|
35
|
+
const roleLabels: Record<AriaLandmarkRole, string> = {
|
|
36
|
+
main: 'Main',
|
|
37
|
+
navigation: 'Navigation',
|
|
38
|
+
search: 'Search',
|
|
39
|
+
banner: 'Banner',
|
|
40
|
+
contentinfo: 'Footer',
|
|
41
|
+
complementary: 'Aside',
|
|
42
|
+
form: 'Form',
|
|
43
|
+
region: 'Region',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const roleColors: Record<AriaLandmarkRole, string> = {
|
|
47
|
+
main: 'bg-accent/10 border-accent-300',
|
|
48
|
+
navigation: 'bg-primary-500/10 border-primary-400',
|
|
49
|
+
search: 'bg-warning-400/10 border-warning-400',
|
|
50
|
+
banner: 'bg-success-400/10 border-success-400',
|
|
51
|
+
contentinfo: 'bg-danger-400/10 border-danger-400',
|
|
52
|
+
complementary: 'bg-primary-300/10 border-primary-300',
|
|
53
|
+
form: 'bg-accent-200/10 border-accent-200',
|
|
54
|
+
region: 'bg-bg-200/50 border-bg-300',
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============================================
|
|
58
|
+
// LANDMARK COMPONENT
|
|
59
|
+
// ============================================
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A landmark is a region of the page that helps screen reader users navigate.
|
|
63
|
+
* Press F6 to cycle through landmarks, or Shift+F6 to go backwards.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```tsx
|
|
67
|
+
* // Main content area
|
|
68
|
+
* <Landmark role="main" aria-label="Main content">
|
|
69
|
+
* <h1>Welcome</h1>
|
|
70
|
+
* <p>Page content here...</p>
|
|
71
|
+
* </Landmark>
|
|
72
|
+
*
|
|
73
|
+
* // Navigation
|
|
74
|
+
* <Landmark role="navigation" aria-label="Primary navigation">
|
|
75
|
+
* <nav>...</nav>
|
|
76
|
+
* </Landmark>
|
|
77
|
+
*
|
|
78
|
+
* // With development label visible
|
|
79
|
+
* <Landmark role="main" aria-label="Main content" showLabel>
|
|
80
|
+
* ...
|
|
81
|
+
* </Landmark>
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export function Landmark(props: LandmarkProps): JSX.Element {
|
|
85
|
+
const [local, headlessProps] = splitProps(props, ['class', 'showLabel'])
|
|
86
|
+
const customClass = local.class ?? ''
|
|
87
|
+
|
|
88
|
+
const role = () => headlessProps.role
|
|
89
|
+
|
|
90
|
+
const getClassName = (): string => {
|
|
91
|
+
const base = 'relative'
|
|
92
|
+
const debugClass = local.showLabel
|
|
93
|
+
? `border-2 border-dashed ${roleColors[role()]}`
|
|
94
|
+
: ''
|
|
95
|
+
return [base, debugClass, customClass].filter(Boolean).join(' ')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<HeadlessLandmark {...headlessProps} class={getClassName()}>
|
|
100
|
+
<Show when={local.showLabel}>
|
|
101
|
+
<div
|
|
102
|
+
class={`absolute -top-3 left-2 px-2 py-0.5 text-xs font-medium rounded ${roleColors[role()]} text-primary-200`}
|
|
103
|
+
>
|
|
104
|
+
{roleLabels[role()]}
|
|
105
|
+
<Show when={headlessProps['aria-label']}>
|
|
106
|
+
<span class="text-primary-400"> - {headlessProps['aria-label']}</span>
|
|
107
|
+
</Show>
|
|
108
|
+
</div>
|
|
109
|
+
</Show>
|
|
110
|
+
{props.children}
|
|
111
|
+
</HeadlessLandmark>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ============================================
|
|
116
|
+
// SKIP LINK COMPONENT
|
|
117
|
+
// ============================================
|
|
118
|
+
|
|
119
|
+
export interface SkipLinkProps {
|
|
120
|
+
/** The ID of the element to skip to (usually the main landmark). */
|
|
121
|
+
href: string
|
|
122
|
+
/** The text to display in the skip link. */
|
|
123
|
+
children?: JSX.Element
|
|
124
|
+
/** Additional CSS class name. */
|
|
125
|
+
class?: string
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* A skip link allows keyboard users to bypass repetitive navigation and jump directly to main content.
|
|
130
|
+
* The link is visually hidden until focused.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```tsx
|
|
134
|
+
* <SkipLink href="#main-content">Skip to main content</SkipLink>
|
|
135
|
+
*
|
|
136
|
+
* <Landmark role="navigation">...</Landmark>
|
|
137
|
+
*
|
|
138
|
+
* <Landmark role="main" id="main-content">
|
|
139
|
+
* ...
|
|
140
|
+
* </Landmark>
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export function SkipLink(props: SkipLinkProps): JSX.Element {
|
|
144
|
+
const customClass = props.class ?? ''
|
|
145
|
+
|
|
146
|
+
const className = [
|
|
147
|
+
// Visually hidden by default
|
|
148
|
+
'absolute left-0 top-0 -translate-y-full',
|
|
149
|
+
// Show when focused
|
|
150
|
+
'focus:translate-y-0',
|
|
151
|
+
// Styling
|
|
152
|
+
'z-50 px-4 py-2 bg-accent text-white font-medium rounded-br-lg',
|
|
153
|
+
'transition-transform duration-200',
|
|
154
|
+
'focus:outline-none focus:ring-2 focus:ring-accent-300 focus:ring-offset-2',
|
|
155
|
+
customClass,
|
|
156
|
+
]
|
|
157
|
+
.filter(Boolean)
|
|
158
|
+
.join(' ')
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<a href={props.href} class={className}>
|
|
162
|
+
{props.children ?? 'Skip to main content'}
|
|
163
|
+
</a>
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ============================================
|
|
168
|
+
// LANDMARK NAVIGATOR COMPONENT
|
|
169
|
+
// ============================================
|
|
170
|
+
|
|
171
|
+
export interface LandmarkNavigatorProps {
|
|
172
|
+
/** Additional CSS class name. */
|
|
173
|
+
class?: string
|
|
174
|
+
/** Whether to show the navigator (for development/accessibility testing). */
|
|
175
|
+
isVisible?: boolean
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* A floating navigator for landmarks, useful for development and accessibility testing.
|
|
180
|
+
* Provides buttons to navigate between landmarks programmatically.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```tsx
|
|
184
|
+
* // Show in development only
|
|
185
|
+
* <LandmarkNavigator isVisible={import.meta.env.DEV} />
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
export function LandmarkNavigator(props: LandmarkNavigatorProps): JSX.Element {
|
|
189
|
+
const controller = useLandmarkController()
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
<Show when={props.isVisible}>
|
|
193
|
+
<div
|
|
194
|
+
class={`fixed bottom-4 right-4 z-50 flex flex-col gap-2 p-3 bg-bg-400 border border-bg-300 rounded-lg shadow-lg ${props.class ?? ''}`}
|
|
195
|
+
>
|
|
196
|
+
<span class="text-xs font-medium text-primary-400 uppercase tracking-wider">
|
|
197
|
+
Landmarks (F6)
|
|
198
|
+
</span>
|
|
199
|
+
<div class="flex gap-1">
|
|
200
|
+
<button
|
|
201
|
+
type="button"
|
|
202
|
+
onClick={() => controller.focusPrevious()}
|
|
203
|
+
class="px-2 py-1 text-sm bg-bg-300 hover:bg-bg-200 text-primary-200 rounded transition-colors"
|
|
204
|
+
title="Previous landmark (Shift+F6)"
|
|
205
|
+
>
|
|
206
|
+
←
|
|
207
|
+
</button>
|
|
208
|
+
<button
|
|
209
|
+
type="button"
|
|
210
|
+
onClick={() => controller.focusMain()}
|
|
211
|
+
class="px-3 py-1 text-sm bg-accent hover:bg-accent-200 text-white rounded transition-colors"
|
|
212
|
+
title="Go to main content"
|
|
213
|
+
>
|
|
214
|
+
Main
|
|
215
|
+
</button>
|
|
216
|
+
<button
|
|
217
|
+
type="button"
|
|
218
|
+
onClick={() => controller.focusNext()}
|
|
219
|
+
class="px-2 py-1 text-sm bg-bg-300 hover:bg-bg-200 text-primary-200 rounded transition-colors"
|
|
220
|
+
title="Next landmark (F6)"
|
|
221
|
+
>
|
|
222
|
+
→
|
|
223
|
+
</button>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</Show>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Export controller hook for convenience
|
|
231
|
+
export { useLandmarkController }
|