@proyecto-viviana/ui 0.2.5 → 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.
- package/dist/index.js +210 -557
- package/dist/index.js.map +7 -1
- package/dist/index.ssr.js +42 -399
- package/dist/index.ssr.js.map +7 -1
- package/dist/radio/index.d.ts +27 -12
- package/dist/radio/index.d.ts.map +1 -1
- package/package.json +11 -12
- package/src/alert/index.tsx +0 -48
- package/src/assets/favicon.png +0 -0
- package/src/assets/fire.gif +0 -0
- package/src/autocomplete/index.tsx +0 -313
- package/src/avatar/index.tsx +0 -75
- package/src/badge/index.tsx +0 -43
- package/src/breadcrumbs/index.tsx +0 -207
- package/src/button/Button.tsx +0 -74
- package/src/button/index.ts +0 -2
- package/src/button/types.ts +0 -24
- package/src/calendar/DateField.tsx +0 -200
- package/src/calendar/DatePicker.tsx +0 -298
- package/src/calendar/RangeCalendar.tsx +0 -236
- package/src/calendar/TimeField.tsx +0 -196
- package/src/calendar/index.tsx +0 -223
- package/src/checkbox/index.tsx +0 -257
- package/src/color/index.tsx +0 -687
- package/src/combobox/index.tsx +0 -383
- package/src/components.css +0 -1077
- package/src/custom/calendar-card/index.tsx +0 -66
- package/src/custom/chip/index.tsx +0 -46
- package/src/custom/conversation/index.tsx +0 -105
- package/src/custom/event-card/index.tsx +0 -132
- package/src/custom/header/index.tsx +0 -33
- package/src/custom/lateral-nav/index.tsx +0 -88
- package/src/custom/logo/index.tsx +0 -58
- package/src/custom/nav-header/index.tsx +0 -42
- package/src/custom/page-layout/index.tsx +0 -29
- package/src/custom/profile-card/index.tsx +0 -64
- package/src/custom/project-card/index.tsx +0 -59
- package/src/custom/timeline-item/index.tsx +0 -105
- package/src/dialog/Dialog.tsx +0 -260
- package/src/dialog/index.tsx +0 -3
- package/src/disclosure/index.tsx +0 -307
- package/src/gridlist/index.tsx +0 -403
- package/src/icon/icons/GitHubIcon.tsx +0 -20
- package/src/icon/index.tsx +0 -48
- package/src/index.ts +0 -322
- package/src/landmark/index.tsx +0 -231
- package/src/link/index.tsx +0 -130
- package/src/listbox/index.tsx +0 -231
- package/src/menu/index.tsx +0 -297
- package/src/meter/index.tsx +0 -163
- package/src/numberfield/index.tsx +0 -482
- package/src/popover/index.tsx +0 -260
- package/src/progress-bar/index.tsx +0 -169
- package/src/radio/index.tsx +0 -173
- package/src/searchfield/index.tsx +0 -453
- package/src/select/index.tsx +0 -349
- package/src/separator/index.tsx +0 -141
- package/src/slider/index.tsx +0 -382
- package/src/styles.css +0 -450
- package/src/switch/ToggleSwitch.tsx +0 -112
- package/src/switch/index.tsx +0 -90
- package/src/table/index.tsx +0 -531
- package/src/tabs/index.tsx +0 -273
- package/src/tag-group/index.tsx +0 -240
- package/src/test-utils/index.ts +0 -32
- package/src/textfield/index.tsx +0 -211
- package/src/theme.css +0 -101
- package/src/toast/index.tsx +0 -324
- package/src/toolbar/index.tsx +0 -108
- package/src/tooltip/index.tsx +0 -197
- package/src/tree/index.tsx +0 -494
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Breadcrumbs component for proyecto-viviana-ui
|
|
3
|
-
*
|
|
4
|
-
* Styled breadcrumbs component built on top of solidaria-components.
|
|
5
|
-
* Inspired by Spectrum 2's Breadcrumbs component patterns.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { type JSX, splitProps, createContext, useContext } from 'solid-js'
|
|
9
|
-
import {
|
|
10
|
-
Breadcrumbs as HeadlessBreadcrumbs,
|
|
11
|
-
BreadcrumbItem as HeadlessBreadcrumbItem,
|
|
12
|
-
type BreadcrumbsProps as HeadlessBreadcrumbsProps,
|
|
13
|
-
type BreadcrumbItemProps as HeadlessBreadcrumbItemProps,
|
|
14
|
-
type BreadcrumbsRenderProps,
|
|
15
|
-
type BreadcrumbItemRenderProps,
|
|
16
|
-
} from '@proyecto-viviana/solidaria-components'
|
|
17
|
-
|
|
18
|
-
// ============================================
|
|
19
|
-
// SIZE CONTEXT
|
|
20
|
-
// ============================================
|
|
21
|
-
|
|
22
|
-
export type BreadcrumbsSize = 'sm' | 'md' | 'lg'
|
|
23
|
-
export type BreadcrumbsVariant = 'default' | 'subtle'
|
|
24
|
-
|
|
25
|
-
interface BreadcrumbsContextValue {
|
|
26
|
-
size: BreadcrumbsSize
|
|
27
|
-
variant: BreadcrumbsVariant
|
|
28
|
-
showSeparator: boolean
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const BreadcrumbsSizeContext = createContext<BreadcrumbsContextValue>({
|
|
32
|
-
size: 'md',
|
|
33
|
-
variant: 'default',
|
|
34
|
-
showSeparator: true,
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
// ============================================
|
|
38
|
-
// TYPES
|
|
39
|
-
// ============================================
|
|
40
|
-
|
|
41
|
-
export interface BreadcrumbsProps<T> extends Omit<HeadlessBreadcrumbsProps<T>, 'class' | 'style'> {
|
|
42
|
-
/** The size of the breadcrumbs. */
|
|
43
|
-
size?: BreadcrumbsSize
|
|
44
|
-
/** The visual variant. */
|
|
45
|
-
variant?: BreadcrumbsVariant
|
|
46
|
-
/** Whether to show separators between items. */
|
|
47
|
-
showSeparator?: boolean
|
|
48
|
-
/** Additional CSS class name. */
|
|
49
|
-
class?: string
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface BreadcrumbItemProps extends Omit<HeadlessBreadcrumbItemProps, 'class' | 'style'> {
|
|
53
|
-
/** Additional CSS class name. */
|
|
54
|
-
class?: string
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// ============================================
|
|
58
|
-
// STYLES
|
|
59
|
-
// ============================================
|
|
60
|
-
|
|
61
|
-
const sizeStyles = {
|
|
62
|
-
sm: {
|
|
63
|
-
text: 'text-sm',
|
|
64
|
-
icon: 'h-3 w-3',
|
|
65
|
-
gap: 'gap-1',
|
|
66
|
-
},
|
|
67
|
-
md: {
|
|
68
|
-
text: 'text-base',
|
|
69
|
-
icon: 'h-4 w-4',
|
|
70
|
-
gap: 'gap-1.5',
|
|
71
|
-
},
|
|
72
|
-
lg: {
|
|
73
|
-
text: 'text-lg',
|
|
74
|
-
icon: 'h-5 w-5',
|
|
75
|
-
gap: 'gap-2',
|
|
76
|
-
},
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const variantStyles = {
|
|
80
|
-
default: {
|
|
81
|
-
item: 'text-primary-400 hover:text-primary-200',
|
|
82
|
-
current: 'text-primary-100 font-medium',
|
|
83
|
-
separator: 'text-primary-500',
|
|
84
|
-
},
|
|
85
|
-
subtle: {
|
|
86
|
-
item: 'text-primary-500 hover:text-primary-300',
|
|
87
|
-
current: 'text-primary-200',
|
|
88
|
-
separator: 'text-primary-600',
|
|
89
|
-
},
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ============================================
|
|
93
|
-
// BREADCRUMBS COMPONENT
|
|
94
|
-
// ============================================
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Breadcrumbs show hierarchy and navigational context for a user's location within an application.
|
|
98
|
-
*
|
|
99
|
-
* Built on solidaria-components Breadcrumbs for full accessibility support.
|
|
100
|
-
*/
|
|
101
|
-
export function Breadcrumbs<T>(props: BreadcrumbsProps<T>): JSX.Element {
|
|
102
|
-
const [local, headlessProps] = splitProps(props, [
|
|
103
|
-
'size',
|
|
104
|
-
'variant',
|
|
105
|
-
'showSeparator',
|
|
106
|
-
'class',
|
|
107
|
-
])
|
|
108
|
-
|
|
109
|
-
const size = local.size ?? 'md'
|
|
110
|
-
const variant = local.variant ?? 'default'
|
|
111
|
-
const showSeparator = local.showSeparator ?? true
|
|
112
|
-
const customClass = local.class ?? ''
|
|
113
|
-
|
|
114
|
-
const getClassName = (renderProps: BreadcrumbsRenderProps): string => {
|
|
115
|
-
const base = 'flex items-center'
|
|
116
|
-
const sizeClass = sizeStyles[size].gap
|
|
117
|
-
const disabledClass = renderProps.isDisabled ? 'opacity-50' : ''
|
|
118
|
-
return [base, sizeClass, disabledClass, customClass].filter(Boolean).join(' ')
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return (
|
|
122
|
-
<BreadcrumbsSizeContext.Provider value={{ size, variant, showSeparator }}>
|
|
123
|
-
<HeadlessBreadcrumbs
|
|
124
|
-
{...headlessProps}
|
|
125
|
-
class={getClassName}
|
|
126
|
-
children={props.children}
|
|
127
|
-
/>
|
|
128
|
-
</BreadcrumbsSizeContext.Provider>
|
|
129
|
-
)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ============================================
|
|
133
|
-
// BREADCRUMB ITEM COMPONENT
|
|
134
|
-
// ============================================
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* A BreadcrumbItem represents an individual breadcrumb in the navigation trail.
|
|
138
|
-
*/
|
|
139
|
-
export function BreadcrumbItem(props: BreadcrumbItemProps): JSX.Element {
|
|
140
|
-
const [local, headlessProps] = splitProps(props, ['class'])
|
|
141
|
-
const ctx = useContext(BreadcrumbsSizeContext)
|
|
142
|
-
const customClass = local.class ?? ''
|
|
143
|
-
|
|
144
|
-
const getClassName = (renderProps: BreadcrumbItemRenderProps): string => {
|
|
145
|
-
const sizeClass = sizeStyles[ctx.size].text
|
|
146
|
-
const vStyles = variantStyles[ctx.variant]
|
|
147
|
-
|
|
148
|
-
let stateClass: string
|
|
149
|
-
if (renderProps.isCurrent) {
|
|
150
|
-
stateClass = vStyles.current
|
|
151
|
-
} else if (renderProps.isDisabled) {
|
|
152
|
-
stateClass = 'text-primary-600 cursor-not-allowed'
|
|
153
|
-
} else {
|
|
154
|
-
stateClass = vStyles.item
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const cursorClass = renderProps.isCurrent || renderProps.isDisabled ? '' : 'cursor-pointer'
|
|
158
|
-
const transitionClass = 'transition-colors duration-150'
|
|
159
|
-
const focusClass = renderProps.isFocusVisible
|
|
160
|
-
? 'ring-2 ring-accent-300 ring-offset-1 ring-offset-bg-400 outline-none rounded'
|
|
161
|
-
: ''
|
|
162
|
-
|
|
163
|
-
return [sizeClass, stateClass, cursorClass, transitionClass, focusClass, customClass].filter(Boolean).join(' ')
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const vStyles = variantStyles[ctx.variant]
|
|
167
|
-
// Hide separator on first item, and on current (last) item
|
|
168
|
-
const separatorClass = `${sizeStyles[ctx.size].icon} ${vStyles.separator} mx-1 shrink-0 hidden data-current:hidden [&:not([data-current])]:block [li:first-child_&]:!hidden`
|
|
169
|
-
|
|
170
|
-
// Wrap children with separator icon
|
|
171
|
-
const renderChildren = () => (
|
|
172
|
-
<>
|
|
173
|
-
{/* Separator shows before items except first and current */}
|
|
174
|
-
{ctx.showSeparator && <ChevronIcon class={separatorClass} />}
|
|
175
|
-
{props.children as JSX.Element}
|
|
176
|
-
</>
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
return (
|
|
180
|
-
<HeadlessBreadcrumbItem
|
|
181
|
-
{...headlessProps}
|
|
182
|
-
class={getClassName}
|
|
183
|
-
children={renderChildren()}
|
|
184
|
-
/>
|
|
185
|
-
)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// ============================================
|
|
189
|
-
// ICONS
|
|
190
|
-
// ============================================
|
|
191
|
-
|
|
192
|
-
function ChevronIcon(props: { class?: string }): JSX.Element {
|
|
193
|
-
return (
|
|
194
|
-
<svg
|
|
195
|
-
class={props.class}
|
|
196
|
-
fill="none"
|
|
197
|
-
viewBox="0 0 24 24"
|
|
198
|
-
stroke="currentColor"
|
|
199
|
-
stroke-width="2"
|
|
200
|
-
>
|
|
201
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
|
|
202
|
-
</svg>
|
|
203
|
-
)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Attach sub-components for convenience
|
|
207
|
-
Breadcrumbs.Item = BreadcrumbItem
|
package/src/button/Button.tsx
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Button component for proyecto-viviana-ui
|
|
3
|
-
*
|
|
4
|
-
* A styled button component built on top of solidaria-components.
|
|
5
|
-
* This component only handles styling - all behavior and accessibility
|
|
6
|
-
* is provided by the headless Button from solidaria-components.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { type JSX, splitProps, mergeProps as solidMergeProps } from 'solid-js';
|
|
10
|
-
import { Button as HeadlessButton, type ButtonRenderProps } from '@proyecto-viviana/solidaria-components';
|
|
11
|
-
import type { ButtonProps } from './types';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Buttons allow users to perform an action or to navigate to another page.
|
|
15
|
-
* They have multiple styles for various needs, and are ideal for calling attention to
|
|
16
|
-
* where a user needs to do something in order to move forward in a flow.
|
|
17
|
-
*
|
|
18
|
-
* Built on solidaria-components Button for full accessibility support.
|
|
19
|
-
* Styles are defined in components.css using the vui-button class system.
|
|
20
|
-
*/
|
|
21
|
-
export function Button(props: ButtonProps): JSX.Element {
|
|
22
|
-
const defaultProps: Partial<ButtonProps> = {
|
|
23
|
-
variant: 'primary',
|
|
24
|
-
buttonStyle: 'fill',
|
|
25
|
-
size: 'md',
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const merged = solidMergeProps(defaultProps, props);
|
|
29
|
-
|
|
30
|
-
const [local, headlessProps] = splitProps(merged, [
|
|
31
|
-
'variant',
|
|
32
|
-
'buttonStyle',
|
|
33
|
-
'size',
|
|
34
|
-
'fullWidth',
|
|
35
|
-
'staticColor',
|
|
36
|
-
'class',
|
|
37
|
-
]);
|
|
38
|
-
|
|
39
|
-
// Generate class based on render props
|
|
40
|
-
const getClassName = (renderProps: ButtonRenderProps): string => {
|
|
41
|
-
const classList = [
|
|
42
|
-
'vui-button',
|
|
43
|
-
`vui-button--${local.buttonStyle}`,
|
|
44
|
-
`vui-button--${local.variant}`,
|
|
45
|
-
`vui-button--${local.size}`,
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
if (renderProps.isPressed) {
|
|
49
|
-
classList.push('is-pressed');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (local.fullWidth) {
|
|
53
|
-
classList.push('vui-button--full-width');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (local.class) {
|
|
57
|
-
classList.push(local.class);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return classList.join(' ');
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<HeadlessButton
|
|
65
|
-
{...headlessProps}
|
|
66
|
-
class={getClassName}
|
|
67
|
-
data-variant={local.variant}
|
|
68
|
-
data-style={local.buttonStyle}
|
|
69
|
-
data-static-color={local.staticColor || undefined}
|
|
70
|
-
>
|
|
71
|
-
{props.children}
|
|
72
|
-
</HeadlessButton>
|
|
73
|
-
);
|
|
74
|
-
}
|
package/src/button/index.ts
DELETED
package/src/button/types.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { JSX } from 'solid-js';
|
|
2
|
-
import type { ButtonProps as HeadlessButtonProps } from '@proyecto-viviana/solidaria-components';
|
|
3
|
-
|
|
4
|
-
export type ButtonVariant = 'primary' | 'secondary' | 'accent' | 'positive' | 'negative' | 'ghost' | 'link';
|
|
5
|
-
export type ButtonStyle = 'fill' | 'outline';
|
|
6
|
-
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
7
|
-
export type StaticColor = 'white' | 'black';
|
|
8
|
-
|
|
9
|
-
export interface ButtonProps extends Omit<HeadlessButtonProps, 'class' | 'children' | 'style'> {
|
|
10
|
-
/** The content to display in the button. */
|
|
11
|
-
children?: JSX.Element;
|
|
12
|
-
/** The visual style of the button. */
|
|
13
|
-
variant?: ButtonVariant;
|
|
14
|
-
/** The background style of the button. */
|
|
15
|
-
buttonStyle?: ButtonStyle;
|
|
16
|
-
/** The size of the button. */
|
|
17
|
-
size?: ButtonSize;
|
|
18
|
-
/** Whether the button should take up the full width of its container. */
|
|
19
|
-
fullWidth?: boolean;
|
|
20
|
-
/** The static color style to apply. Useful when the button appears over a color background. */
|
|
21
|
-
staticColor?: StaticColor;
|
|
22
|
-
/** Additional CSS class name. */
|
|
23
|
-
class?: string;
|
|
24
|
-
}
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DateField component for proyecto-viviana-ui
|
|
3
|
-
*
|
|
4
|
-
* Styled date field component with segment-based editing.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { type JSX, splitProps } from 'solid-js';
|
|
8
|
-
import {
|
|
9
|
-
DateField as HeadlessDateField,
|
|
10
|
-
DateInput,
|
|
11
|
-
DateSegment,
|
|
12
|
-
type DateFieldProps as HeadlessDateFieldProps,
|
|
13
|
-
type CalendarDate,
|
|
14
|
-
type DateValue,
|
|
15
|
-
} from '@proyecto-viviana/solidaria-components';
|
|
16
|
-
|
|
17
|
-
// ============================================
|
|
18
|
-
// TYPES
|
|
19
|
-
// ============================================
|
|
20
|
-
|
|
21
|
-
export type DateFieldSize = 'sm' | 'md' | 'lg';
|
|
22
|
-
|
|
23
|
-
export interface DateFieldProps<T extends DateValue = DateValue>
|
|
24
|
-
extends Omit<HeadlessDateFieldProps<T>, 'class' | 'style' | 'children'> {
|
|
25
|
-
/** The size of the field. @default 'md' */
|
|
26
|
-
size?: DateFieldSize;
|
|
27
|
-
/** Additional CSS class name. */
|
|
28
|
-
class?: string;
|
|
29
|
-
/** Label for the field. */
|
|
30
|
-
label?: string;
|
|
31
|
-
/** Description text. */
|
|
32
|
-
description?: string;
|
|
33
|
-
/** Error message. */
|
|
34
|
-
errorMessage?: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ============================================
|
|
38
|
-
// STYLES
|
|
39
|
-
// ============================================
|
|
40
|
-
|
|
41
|
-
const sizeStyles = {
|
|
42
|
-
sm: {
|
|
43
|
-
container: 'text-sm',
|
|
44
|
-
input: 'px-2 py-1 gap-0.5',
|
|
45
|
-
segment: 'px-0.5',
|
|
46
|
-
label: 'text-xs',
|
|
47
|
-
},
|
|
48
|
-
md: {
|
|
49
|
-
container: 'text-base',
|
|
50
|
-
input: 'px-3 py-2 gap-1',
|
|
51
|
-
segment: 'px-1',
|
|
52
|
-
label: 'text-sm',
|
|
53
|
-
},
|
|
54
|
-
lg: {
|
|
55
|
-
container: 'text-lg',
|
|
56
|
-
input: 'px-4 py-3 gap-1.5',
|
|
57
|
-
segment: 'px-1.5',
|
|
58
|
-
label: 'text-base',
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
// ============================================
|
|
63
|
-
// DATE FIELD COMPONENT
|
|
64
|
-
// ============================================
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* A date field allows users to enter and edit date values using a keyboard.
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* ```tsx
|
|
71
|
-
* // Basic usage
|
|
72
|
-
* <DateField label="Birth date" />
|
|
73
|
-
*
|
|
74
|
-
* // Controlled
|
|
75
|
-
* const [date, setDate] = createSignal<CalendarDate | null>(null);
|
|
76
|
-
* <DateField
|
|
77
|
-
* label="Event date"
|
|
78
|
-
* value={date()}
|
|
79
|
-
* onChange={setDate}
|
|
80
|
-
* />
|
|
81
|
-
*
|
|
82
|
-
* // With validation
|
|
83
|
-
* <DateField
|
|
84
|
-
* label="Future date"
|
|
85
|
-
* minValue={today(getLocalTimeZone())}
|
|
86
|
-
* errorMessage="Date must be in the future"
|
|
87
|
-
* />
|
|
88
|
-
* ```
|
|
89
|
-
*/
|
|
90
|
-
export function DateField<T extends DateValue = CalendarDate>(
|
|
91
|
-
props: DateFieldProps<T>
|
|
92
|
-
): JSX.Element {
|
|
93
|
-
const [local, rest] = splitProps(props, [
|
|
94
|
-
'size',
|
|
95
|
-
'class',
|
|
96
|
-
'label',
|
|
97
|
-
'description',
|
|
98
|
-
'errorMessage',
|
|
99
|
-
'isInvalid',
|
|
100
|
-
]);
|
|
101
|
-
|
|
102
|
-
const size = () => local.size ?? 'md';
|
|
103
|
-
const sizeConfig = () => sizeStyles[size()];
|
|
104
|
-
const isInvalid = () => local.isInvalid || !!local.errorMessage;
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<HeadlessDateField
|
|
108
|
-
{...rest}
|
|
109
|
-
isInvalid={isInvalid()}
|
|
110
|
-
class={`
|
|
111
|
-
flex flex-col gap-1
|
|
112
|
-
${sizeConfig().container}
|
|
113
|
-
${local.class ?? ''}
|
|
114
|
-
`}
|
|
115
|
-
>
|
|
116
|
-
{/* Label */}
|
|
117
|
-
{local.label && (
|
|
118
|
-
<label class={`font-medium text-primary-200 ${sizeConfig().label}`}>
|
|
119
|
-
{local.label}
|
|
120
|
-
{rest.isRequired && <span class="text-red-500 ml-0.5">*</span>}
|
|
121
|
-
</label>
|
|
122
|
-
)}
|
|
123
|
-
|
|
124
|
-
{/* Input container */}
|
|
125
|
-
<DateInput
|
|
126
|
-
class={({ isFocused, isDisabled }) => {
|
|
127
|
-
const base = `
|
|
128
|
-
inline-flex items-center
|
|
129
|
-
${sizeConfig().input}
|
|
130
|
-
bg-bg-400 rounded-md border
|
|
131
|
-
transition-colors duration-150
|
|
132
|
-
`;
|
|
133
|
-
|
|
134
|
-
let borderClass = 'border-primary-600';
|
|
135
|
-
if (isInvalid()) {
|
|
136
|
-
borderClass = 'border-red-500';
|
|
137
|
-
} else if (isFocused) {
|
|
138
|
-
borderClass = 'border-accent';
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const disabledClass = isDisabled
|
|
142
|
-
? 'opacity-50 cursor-not-allowed'
|
|
143
|
-
: '';
|
|
144
|
-
|
|
145
|
-
const focusClass = isFocused
|
|
146
|
-
? 'ring-2 ring-accent/30'
|
|
147
|
-
: '';
|
|
148
|
-
|
|
149
|
-
return `${base} ${borderClass} ${disabledClass} ${focusClass}`.trim();
|
|
150
|
-
}}
|
|
151
|
-
>
|
|
152
|
-
{(segment) => (
|
|
153
|
-
<DateSegment
|
|
154
|
-
segment={segment}
|
|
155
|
-
class={({ isFocused, isPlaceholder, isEditable }) => {
|
|
156
|
-
const base = `
|
|
157
|
-
${sizeConfig().segment}
|
|
158
|
-
rounded
|
|
159
|
-
outline-none
|
|
160
|
-
tabular-nums
|
|
161
|
-
`;
|
|
162
|
-
|
|
163
|
-
let stateClass = '';
|
|
164
|
-
if (segment.type === 'literal') {
|
|
165
|
-
stateClass = 'text-primary-400';
|
|
166
|
-
} else if (isPlaceholder) {
|
|
167
|
-
stateClass = 'text-primary-500 italic';
|
|
168
|
-
} else {
|
|
169
|
-
stateClass = 'text-primary-100';
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const focusClass = isFocused && isEditable
|
|
173
|
-
? 'bg-accent text-white'
|
|
174
|
-
: '';
|
|
175
|
-
|
|
176
|
-
return `${base} ${stateClass} ${focusClass}`.trim();
|
|
177
|
-
}}
|
|
178
|
-
/>
|
|
179
|
-
)}
|
|
180
|
-
</DateInput>
|
|
181
|
-
|
|
182
|
-
{/* Description */}
|
|
183
|
-
{local.description && !isInvalid() && (
|
|
184
|
-
<p class={`text-primary-400 ${sizeConfig().label}`}>
|
|
185
|
-
{local.description}
|
|
186
|
-
</p>
|
|
187
|
-
)}
|
|
188
|
-
|
|
189
|
-
{/* Error message */}
|
|
190
|
-
{isInvalid() && local.errorMessage && (
|
|
191
|
-
<p class={`text-red-500 ${sizeConfig().label}`}>
|
|
192
|
-
{local.errorMessage}
|
|
193
|
-
</p>
|
|
194
|
-
)}
|
|
195
|
-
</HeadlessDateField>
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Re-export types
|
|
200
|
-
export type { CalendarDate, DateValue };
|