@proyecto-viviana/ui 0.2.3 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/index.js +192 -179
  2. package/dist/index.js.map +3 -3
  3. package/dist/index.ssr.js +24 -21
  4. package/dist/index.ssr.js.map +3 -3
  5. package/dist/radio/index.d.ts +27 -12
  6. package/dist/radio/index.d.ts.map +1 -1
  7. package/package.json +12 -13
  8. package/src/alert/index.tsx +0 -48
  9. package/src/assets/favicon.png +0 -0
  10. package/src/assets/fire.gif +0 -0
  11. package/src/autocomplete/index.tsx +0 -313
  12. package/src/avatar/index.tsx +0 -75
  13. package/src/badge/index.tsx +0 -43
  14. package/src/breadcrumbs/index.tsx +0 -207
  15. package/src/button/Button.tsx +0 -74
  16. package/src/button/index.ts +0 -2
  17. package/src/button/types.ts +0 -24
  18. package/src/calendar/DateField.tsx +0 -200
  19. package/src/calendar/DatePicker.tsx +0 -298
  20. package/src/calendar/RangeCalendar.tsx +0 -236
  21. package/src/calendar/TimeField.tsx +0 -196
  22. package/src/calendar/index.tsx +0 -223
  23. package/src/checkbox/index.tsx +0 -257
  24. package/src/color/index.tsx +0 -687
  25. package/src/combobox/index.tsx +0 -383
  26. package/src/components.css +0 -1077
  27. package/src/custom/calendar-card/index.tsx +0 -66
  28. package/src/custom/chip/index.tsx +0 -46
  29. package/src/custom/conversation/index.tsx +0 -105
  30. package/src/custom/event-card/index.tsx +0 -132
  31. package/src/custom/header/index.tsx +0 -33
  32. package/src/custom/lateral-nav/index.tsx +0 -88
  33. package/src/custom/logo/index.tsx +0 -58
  34. package/src/custom/nav-header/index.tsx +0 -42
  35. package/src/custom/page-layout/index.tsx +0 -29
  36. package/src/custom/profile-card/index.tsx +0 -64
  37. package/src/custom/project-card/index.tsx +0 -59
  38. package/src/custom/timeline-item/index.tsx +0 -105
  39. package/src/dialog/Dialog.tsx +0 -260
  40. package/src/dialog/index.tsx +0 -3
  41. package/src/disclosure/index.tsx +0 -307
  42. package/src/gridlist/index.tsx +0 -403
  43. package/src/icon/icons/GitHubIcon.tsx +0 -20
  44. package/src/icon/index.tsx +0 -48
  45. package/src/index.ts +0 -322
  46. package/src/landmark/index.tsx +0 -231
  47. package/src/link/index.tsx +0 -130
  48. package/src/listbox/index.tsx +0 -231
  49. package/src/menu/index.tsx +0 -297
  50. package/src/meter/index.tsx +0 -163
  51. package/src/numberfield/index.tsx +0 -482
  52. package/src/popover/index.tsx +0 -260
  53. package/src/progress-bar/index.tsx +0 -169
  54. package/src/radio/index.tsx +0 -173
  55. package/src/searchfield/index.tsx +0 -453
  56. package/src/select/index.tsx +0 -349
  57. package/src/separator/index.tsx +0 -141
  58. package/src/slider/index.tsx +0 -382
  59. package/src/styles.css +0 -450
  60. package/src/switch/ToggleSwitch.tsx +0 -112
  61. package/src/switch/index.tsx +0 -90
  62. package/src/table/index.tsx +0 -531
  63. package/src/tabs/index.tsx +0 -273
  64. package/src/tag-group/index.tsx +0 -240
  65. package/src/test-utils/index.ts +0 -32
  66. package/src/textfield/index.tsx +0 -211
  67. package/src/theme.css +0 -101
  68. package/src/toast/index.tsx +0 -324
  69. package/src/toolbar/index.tsx +0 -108
  70. package/src/tooltip/index.tsx +0 -197
  71. package/src/tree/index.tsx +0 -494
@@ -1,349 +0,0 @@
1
- /**
2
- * Select component for proyecto-viviana-ui
3
- *
4
- * Styled select component built on top of solidaria-components.
5
- * Inspired by Spectrum 2's Picker component patterns.
6
- */
7
-
8
- import { type JSX, Show, splitProps, createContext, useContext } from 'solid-js'
9
- import {
10
- Select as HeadlessSelect,
11
- SelectTrigger as HeadlessSelectTrigger,
12
- SelectValue as HeadlessSelectValue,
13
- SelectListBox as HeadlessSelectListBox,
14
- SelectOption as HeadlessSelectOption,
15
- type SelectProps as HeadlessSelectProps,
16
- type SelectTriggerProps as HeadlessSelectTriggerProps,
17
- type SelectValueProps as HeadlessSelectValueProps,
18
- type SelectListBoxProps as HeadlessSelectListBoxProps,
19
- type SelectOptionProps as HeadlessSelectOptionProps,
20
- type SelectRenderProps,
21
- type SelectTriggerRenderProps,
22
- type SelectValueRenderProps,
23
- type SelectListBoxRenderProps,
24
- type SelectOptionRenderProps,
25
- } from '@proyecto-viviana/solidaria-components'
26
- import type { Key } from '@proyecto-viviana/solid-stately'
27
-
28
- // ============================================
29
- // SIZE CONTEXT
30
- // ============================================
31
-
32
- export type SelectSize = 'sm' | 'md' | 'lg'
33
-
34
- const SelectSizeContext = createContext<SelectSize>('md')
35
-
36
- // ============================================
37
- // TYPES
38
- // ============================================
39
-
40
- export interface SelectProps<T> extends Omit<HeadlessSelectProps<T>, 'class' | 'style'> {
41
- /** The size of the select. */
42
- size?: SelectSize
43
- /** Additional CSS class name. */
44
- class?: string
45
- /** Label for the select. */
46
- label?: string
47
- /** Description for the select. */
48
- description?: string
49
- /** Error message when invalid. */
50
- errorMessage?: string
51
- /** Whether the select is invalid. */
52
- isInvalid?: boolean
53
- }
54
-
55
- export interface SelectTriggerProps extends Omit<HeadlessSelectTriggerProps, 'class' | 'style'> {
56
- /** Additional CSS class name. */
57
- class?: string
58
- }
59
-
60
- export interface SelectValueProps<T> extends Omit<HeadlessSelectValueProps<T>, 'class' | 'style'> {
61
- /** Additional CSS class name. */
62
- class?: string
63
- }
64
-
65
- export interface SelectListBoxProps<T> extends Omit<HeadlessSelectListBoxProps<T>, 'class' | 'style'> {
66
- /** Additional CSS class name. */
67
- class?: string
68
- }
69
-
70
- export interface SelectOptionProps<T> extends Omit<HeadlessSelectOptionProps<T>, 'class' | 'style'> {
71
- /** Additional CSS class name. */
72
- class?: string
73
- }
74
-
75
- // ============================================
76
- // STYLES
77
- // ============================================
78
-
79
- const sizeStyles = {
80
- sm: {
81
- trigger: 'h-8 text-sm px-3 gap-2',
82
- label: 'text-sm',
83
- option: 'text-sm py-1.5 px-3',
84
- icon: 'h-4 w-4',
85
- },
86
- md: {
87
- trigger: 'h-10 text-base px-4 gap-2',
88
- label: 'text-base',
89
- option: 'text-base py-2 px-4',
90
- icon: 'h-5 w-5',
91
- },
92
- lg: {
93
- trigger: 'h-12 text-lg px-5 gap-3',
94
- label: 'text-lg',
95
- option: 'text-lg py-2.5 px-5',
96
- icon: 'h-6 w-6',
97
- },
98
- }
99
-
100
- // ============================================
101
- // SELECT COMPONENT
102
- // ============================================
103
-
104
- /**
105
- * A select displays a collapsible list of options and allows a user to select one of them.
106
- *
107
- * Built on solidaria-components Select for full accessibility support.
108
- */
109
- export function Select<T>(props: SelectProps<T>): JSX.Element {
110
- const [local, headlessProps] = splitProps(props, [
111
- 'size',
112
- 'class',
113
- 'label',
114
- 'description',
115
- 'errorMessage',
116
- 'isInvalid',
117
- ])
118
-
119
- const size = local.size ?? 'md'
120
- const customClass = local.class ?? ''
121
-
122
- const getClassName = (renderProps: SelectRenderProps): string => {
123
- const base = 'relative inline-flex flex-col gap-1.5'
124
- const disabledClass = renderProps.isDisabled ? 'opacity-50' : ''
125
- return [base, disabledClass, customClass].filter(Boolean).join(' ')
126
- }
127
-
128
- return (
129
- <SelectSizeContext.Provider value={size}>
130
- <HeadlessSelect
131
- {...headlessProps}
132
- class={getClassName}
133
- >
134
- <Show when={local.label}>
135
- <label class={`text-primary-200 font-medium ${sizeStyles[size].label}`}>
136
- {local.label}
137
- </label>
138
- </Show>
139
- {props.children}
140
- <Show when={local.description && !local.isInvalid}>
141
- <span class="text-primary-400 text-sm">{local.description}</span>
142
- </Show>
143
- <Show when={local.errorMessage && local.isInvalid}>
144
- <span class="text-danger-400 text-sm">{local.errorMessage}</span>
145
- </Show>
146
- </HeadlessSelect>
147
- </SelectSizeContext.Provider>
148
- )
149
- }
150
-
151
- // ============================================
152
- // SELECT TRIGGER COMPONENT
153
- // ============================================
154
-
155
- /**
156
- * The trigger button for a select.
157
- * SSR-compatible - renders children and chevron icon directly without render props.
158
- */
159
- export function SelectTrigger(props: SelectTriggerProps): JSX.Element {
160
- const [local, headlessProps] = splitProps(props, ['class'])
161
- const size = useContext(SelectSizeContext)
162
- const sizeStyle = sizeStyles[size]
163
- const customClass = local.class ?? ''
164
-
165
- const getClassName = (renderProps: SelectTriggerRenderProps): string => {
166
- const base = 'inline-flex items-center justify-between rounded-lg border-2 transition-all duration-200 w-full'
167
- const sizeClass = sizeStyle.trigger
168
-
169
- let colorClass: string
170
- if (renderProps.isDisabled) {
171
- colorClass = 'border-bg-300 bg-bg-200 text-primary-500 cursor-not-allowed'
172
- } else if (renderProps.isOpen) {
173
- colorClass = 'border-accent bg-bg-300 text-primary-100'
174
- } else if (renderProps.isHovered) {
175
- colorClass = 'border-accent-300 bg-bg-300 text-primary-100 cursor-pointer'
176
- } else {
177
- colorClass = 'border-primary-600 bg-bg-400 text-primary-200 cursor-pointer'
178
- }
179
-
180
- const focusClass = renderProps.isFocusVisible
181
- ? 'ring-2 ring-accent-300 ring-offset-2 ring-offset-bg-400'
182
- : ''
183
-
184
- return [base, sizeClass, colorClass, focusClass, customClass].filter(Boolean).join(' ')
185
- }
186
-
187
- return (
188
- <HeadlessSelectTrigger
189
- {...headlessProps}
190
- class={getClassName}
191
- >
192
- {props.children as JSX.Element}
193
- {/* Chevron rotates via CSS based on data-open attribute from headless component */}
194
- <ChevronIcon class={`${sizeStyle.icon} transition-transform duration-200 data-open:rotate-180`} />
195
- </HeadlessSelectTrigger>
196
- )
197
- }
198
-
199
- // ============================================
200
- // SELECT VALUE COMPONENT
201
- // ============================================
202
-
203
- /**
204
- * Displays the selected value in a select.
205
- */
206
- export function SelectValue<T>(props: SelectValueProps<T>): JSX.Element {
207
- const [local, headlessProps] = splitProps(props, ['class'])
208
- const customClass = local.class ?? ''
209
-
210
- const getClassName = (renderProps: SelectValueRenderProps<T>): string => {
211
- const base = 'truncate flex-1 text-left'
212
- const placeholderClass = !renderProps.isSelected ? 'text-primary-500' : ''
213
- return [base, placeholderClass, customClass].filter(Boolean).join(' ')
214
- }
215
-
216
- return (
217
- <HeadlessSelectValue
218
- {...headlessProps}
219
- class={getClassName}
220
- children={props.children}
221
- />
222
- )
223
- }
224
-
225
- // ============================================
226
- // SELECT LISTBOX COMPONENT
227
- // ============================================
228
-
229
- /**
230
- * The listbox popup for a select.
231
- */
232
- export function SelectListBox<T>(props: SelectListBoxProps<T>): JSX.Element {
233
- const [local, headlessProps] = splitProps(props, ['class'])
234
- const customClass = local.class ?? ''
235
-
236
- const getClassName = (_renderProps: SelectListBoxRenderProps): string => {
237
- const base = 'absolute z-50 mt-1 w-full rounded-lg border-2 border-primary-600 bg-bg-400 py-1 shadow-lg max-h-60 overflow-auto'
238
- return [base, customClass].filter(Boolean).join(' ')
239
- }
240
-
241
- return (
242
- <HeadlessSelectListBox
243
- {...headlessProps}
244
- class={getClassName}
245
- children={props.children}
246
- />
247
- )
248
- }
249
-
250
- // ============================================
251
- // SELECT OPTION COMPONENT
252
- // ============================================
253
-
254
- // Padding classes for when no check icon is shown (to maintain alignment)
255
- const paddingStyles = {
256
- sm: 'pl-6', // h-4 (1rem) + gap-2 (0.5rem) = 1.5rem = pl-6
257
- md: 'pl-7', // h-5 (1.25rem) + gap-2 (0.5rem) = 1.75rem ≈ pl-7
258
- lg: 'pl-9', // h-6 (1.5rem) + gap-3 (0.75rem) = 2.25rem = pl-9
259
- }
260
-
261
- /**
262
- * An option in a select listbox.
263
- * SSR-compatible - renders check icon and content directly without render props.
264
- */
265
- export function SelectOption<T>(props: SelectOptionProps<T>): JSX.Element {
266
- const [local, headlessProps] = splitProps(props, ['class'])
267
- const size = useContext(SelectSizeContext)
268
- const sizeStyle = sizeStyles[size]
269
- const customClass = local.class ?? ''
270
-
271
- const getClassName = (renderProps: SelectOptionRenderProps): string => {
272
- const base = 'flex items-center gap-2 cursor-pointer transition-colors duration-150'
273
- const sizeClass = sizeStyle.option
274
-
275
- let colorClass: string
276
- if (renderProps.isDisabled) {
277
- colorClass = 'text-primary-500 cursor-not-allowed'
278
- } else if (renderProps.isSelected) {
279
- colorClass = 'bg-accent/20 text-accent'
280
- } else if (renderProps.isFocused || renderProps.isHovered) {
281
- colorClass = 'bg-bg-300 text-primary-100'
282
- } else {
283
- colorClass = 'text-primary-200'
284
- }
285
-
286
- const focusClass = renderProps.isFocusVisible
287
- ? 'ring-2 ring-inset ring-accent-300'
288
- : ''
289
-
290
- return [base, sizeClass, colorClass, focusClass, customClass].filter(Boolean).join(' ')
291
- }
292
-
293
- const iconClass = `${sizeStyle.icon} text-accent shrink-0 hidden data-selected:block`
294
- const paddingClass = paddingStyles[size]
295
-
296
- return (
297
- <HeadlessSelectOption
298
- {...headlessProps}
299
- class={getClassName}
300
- >
301
- {/* Check icon shows only when selected via data-selected attribute */}
302
- <CheckIcon class={iconClass} />
303
- <span class={`flex-1 data-selected:pl-0 ${paddingClass}`}>
304
- {props.children as JSX.Element}
305
- </span>
306
- </HeadlessSelectOption>
307
- )
308
- }
309
-
310
- // ============================================
311
- // ICONS
312
- // ============================================
313
-
314
- function ChevronIcon(props: { class?: string }): JSX.Element {
315
- return (
316
- <svg
317
- class={props.class}
318
- fill="none"
319
- viewBox="0 0 24 24"
320
- stroke="currentColor"
321
- stroke-width="2"
322
- >
323
- <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />
324
- </svg>
325
- )
326
- }
327
-
328
- function CheckIcon(props: { class?: string }): JSX.Element {
329
- return (
330
- <svg
331
- class={props.class}
332
- fill="none"
333
- viewBox="0 0 24 24"
334
- stroke="currentColor"
335
- stroke-width="2"
336
- >
337
- <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
338
- </svg>
339
- )
340
- }
341
-
342
- // Attach sub-components for convenience
343
- Select.Trigger = SelectTrigger
344
- Select.Value = SelectValue
345
- Select.ListBox = SelectListBox
346
- Select.Option = SelectOption
347
-
348
- // Re-export Key type for convenience
349
- export type { Key }
@@ -1,141 +0,0 @@
1
- /**
2
- * Separator component for proyecto-viviana-ui
3
- *
4
- * Styled separator component built on top of solidaria hook directly.
5
- */
6
-
7
- import { type JSX, splitProps, createMemo, Show } from 'solid-js';
8
- import { createSeparator, type Orientation } from '@proyecto-viviana/solidaria';
9
-
10
- // ============================================
11
- // TYPES
12
- // ============================================
13
-
14
- export type SeparatorVariant = 'default' | 'subtle' | 'strong';
15
- export type SeparatorSize = 'sm' | 'md' | 'lg';
16
-
17
- export interface SeparatorProps {
18
- /** The orientation of the separator. @default 'horizontal' */
19
- orientation?: Orientation;
20
- /** The visual style variant. @default 'default' */
21
- variant?: SeparatorVariant;
22
- /** The size/thickness of the separator. @default 'md' */
23
- size?: SeparatorSize;
24
- /** Additional CSS class name. */
25
- class?: string;
26
- /** An accessibility label for the separator. */
27
- 'aria-label'?: string;
28
- }
29
-
30
- // ============================================
31
- // STYLES
32
- // ============================================
33
-
34
- const variantStyles = {
35
- default: 'bg-bg-100',
36
- subtle: 'bg-bg-200',
37
- strong: 'bg-primary-600',
38
- };
39
-
40
- const horizontalSizeStyles = {
41
- sm: 'h-px',
42
- md: 'h-0.5',
43
- lg: 'h-1',
44
- };
45
-
46
- const verticalSizeStyles = {
47
- sm: 'w-px',
48
- md: 'w-0.5',
49
- lg: 'w-1',
50
- };
51
-
52
- // ============================================
53
- // SEPARATOR COMPONENT
54
- // ============================================
55
-
56
- /**
57
- * A separator is a visual divider between two groups of content,
58
- * e.g. groups of menu items or sections of a page.
59
- *
60
- * @example
61
- * ```tsx
62
- * <Separator />
63
- *
64
- * // Vertical separator
65
- * <div class="flex items-center gap-4">
66
- * <span>Item 1</span>
67
- * <Separator orientation="vertical" />
68
- * <span>Item 2</span>
69
- * </div>
70
- *
71
- * // Different variants
72
- * <Separator variant="strong" />
73
- * ```
74
- */
75
- export function Separator(props: SeparatorProps): JSX.Element {
76
- const [local, ariaProps] = splitProps(props, [
77
- 'orientation',
78
- 'variant',
79
- 'size',
80
- 'class',
81
- ]);
82
-
83
- const orientation = () => local.orientation ?? 'horizontal';
84
- const variant = () => local.variant ?? 'default';
85
- const size = () => local.size ?? 'md';
86
-
87
- // Determine the element type
88
- const elementType = createMemo(() => {
89
- // If vertical, use div since hr is inherently horizontal
90
- if (orientation() === 'vertical') {
91
- return 'div';
92
- }
93
- return 'hr';
94
- });
95
-
96
- // Create separator aria props
97
- const separatorAria = createSeparator({
98
- get orientation() { return orientation(); },
99
- get elementType() { return elementType(); },
100
- get 'aria-label'() { return ariaProps['aria-label']; },
101
- });
102
-
103
- // Build class string
104
- const className = createMemo(() => {
105
- const isVertical = orientation() === 'vertical';
106
- const sizeStyles = isVertical ? verticalSizeStyles : horizontalSizeStyles;
107
-
108
- const base = [
109
- variantStyles[variant()],
110
- sizeStyles[size()],
111
- isVertical ? 'h-full self-stretch' : 'w-full',
112
- 'border-0', // Reset hr default border
113
- local.class ?? '',
114
- ];
115
-
116
- return base.filter(Boolean).join(' ');
117
- });
118
-
119
- // Extract props without ref to avoid type issues with specific element types
120
- const getAriaProps = () => {
121
- const { ref: _, ...props } = separatorAria.separatorProps as Record<string, unknown>;
122
- return props;
123
- };
124
-
125
- return (
126
- <Show
127
- when={orientation() === 'vertical'}
128
- fallback={
129
- <hr
130
- {...getAriaProps()}
131
- class={className()}
132
- />
133
- }
134
- >
135
- <div
136
- {...getAriaProps()}
137
- class={className()}
138
- />
139
- </Show>
140
- );
141
- }