keystone-design-bootstrap 1.0.3
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/README.md +179 -0
- package/package.json +59 -0
- package/src/contexts/ThemeContext.tsx +34 -0
- package/src/contexts/index.ts +1 -0
- package/src/design_system/elements/IconComponent.tsx +98 -0
- package/src/design_system/elements/avatar/avatar-label-group.tsx +30 -0
- package/src/design_system/elements/avatar/avatar-profile-photo.tsx +125 -0
- package/src/design_system/elements/avatar/avatar.tsx +131 -0
- package/src/design_system/elements/avatar/base-components/avatar-add-button.tsx +34 -0
- package/src/design_system/elements/avatar/base-components/avatar-company-icon.tsx +26 -0
- package/src/design_system/elements/avatar/base-components/avatar-online-indicator.tsx +31 -0
- package/src/design_system/elements/avatar/base-components/index.tsx +4 -0
- package/src/design_system/elements/avatar/base-components/verified-tick.tsx +34 -0
- package/src/design_system/elements/avatar/utils.ts +12 -0
- package/src/design_system/elements/badges/avatar.tsx +132 -0
- package/src/design_system/elements/badges/badge-groups.tsx +176 -0
- package/src/design_system/elements/badges/badge-types.ts +266 -0
- package/src/design_system/elements/badges/badges.tsx +430 -0
- package/src/design_system/elements/breadcrumb/Breadcrumb.tsx +33 -0
- package/src/design_system/elements/button-group/button-group.tsx +106 -0
- package/src/design_system/elements/buttons/app-store-buttons-outline.tsx +378 -0
- package/src/design_system/elements/buttons/app-store-buttons.tsx +567 -0
- package/src/design_system/elements/buttons/button-utility.tsx +116 -0
- package/src/design_system/elements/buttons/button.aman.tsx +174 -0
- package/src/design_system/elements/buttons/button.tsx +271 -0
- package/src/design_system/elements/buttons/close-button.tsx +42 -0
- package/src/design_system/elements/buttons/round-button.tsx +29 -0
- package/src/design_system/elements/buttons/social-button.tsx +148 -0
- package/src/design_system/elements/buttons/social-logos.tsx +115 -0
- package/src/design_system/elements/carousel/carousel-base.tsx +308 -0
- package/src/design_system/elements/carousel/carousel.tsx +308 -0
- package/src/design_system/elements/checkbox/checkbox.tsx +120 -0
- package/src/design_system/elements/date-picker/calendar.tsx +101 -0
- package/src/design_system/elements/date-picker/cell.tsx +106 -0
- package/src/design_system/elements/date-picker/date-input.tsx +32 -0
- package/src/design_system/elements/date-picker/date-picker.tsx +86 -0
- package/src/design_system/elements/date-picker/date-range-picker.tsx +163 -0
- package/src/design_system/elements/date-picker/range-calendar.tsx +161 -0
- package/src/design_system/elements/date-picker/range-preset.tsx +28 -0
- package/src/design_system/elements/featured-icon/featured-icon.tsx +154 -0
- package/src/design_system/elements/form/form.tsx +10 -0
- package/src/design_system/elements/form/hook-form.tsx +75 -0
- package/src/design_system/elements/hint-text/hint-text.tsx +33 -0
- package/src/design_system/elements/index.tsx +158 -0
- package/src/design_system/elements/input/hint-text.tsx +33 -0
- package/src/design_system/elements/input/input-group.tsx +133 -0
- package/src/design_system/elements/input/input.aman.tsx +172 -0
- package/src/design_system/elements/input/input.tsx +271 -0
- package/src/design_system/elements/input/label.tsx +50 -0
- package/src/design_system/elements/label/label.tsx +50 -0
- package/src/design_system/elements/loading-indicator/loading-indicator.tsx +123 -0
- package/src/design_system/elements/map/GoogleMap.tsx +286 -0
- package/src/design_system/elements/markdown-renderer/MarkdownRenderer.tsx +155 -0
- package/src/design_system/elements/modals/modal.tsx +41 -0
- package/src/design_system/elements/pagination/pagination-base.tsx +378 -0
- package/src/design_system/elements/pagination/pagination-dot.tsx +54 -0
- package/src/design_system/elements/pagination/pagination-line.tsx +50 -0
- package/src/design_system/elements/pagination/pagination.tsx +330 -0
- package/src/design_system/elements/photo-fallback/photo-fallback.tsx +143 -0
- package/src/design_system/elements/progress-indicators/progress-circles.tsx +176 -0
- package/src/design_system/elements/progress-indicators/progress-indicators.tsx +123 -0
- package/src/design_system/elements/progress-indicators/simple-circle.tsx +29 -0
- package/src/design_system/elements/radio-buttons/radio-buttons.tsx +129 -0
- package/src/design_system/elements/rating/rating-badge.tsx +144 -0
- package/src/design_system/elements/rating/rating-stars.tsx +77 -0
- package/src/design_system/elements/select/combobox.tsx +152 -0
- package/src/design_system/elements/select/multi-select.tsx +363 -0
- package/src/design_system/elements/select/popover.tsx +34 -0
- package/src/design_system/elements/select/select-item.tsx +97 -0
- package/src/design_system/elements/select/select-native.tsx +69 -0
- package/src/design_system/elements/select/select.aman.tsx +75 -0
- package/src/design_system/elements/select/select.tsx +146 -0
- package/src/design_system/elements/shared-assets/credit-card/credit-card.tsx +237 -0
- package/src/design_system/elements/shared-assets/credit-card/icons.tsx +75 -0
- package/src/design_system/elements/shared-assets/iphone-mockup.tsx +172 -0
- package/src/design_system/elements/shared-assets/section-divider.tsx +12 -0
- package/src/design_system/elements/slideout-menus/slideout-menu.tsx +122 -0
- package/src/design_system/elements/tabs/tabs.tsx +225 -0
- package/src/design_system/elements/tags/base-components/tag-checkbox.tsx +45 -0
- package/src/design_system/elements/tags/base-components/tag-close-x.tsx +34 -0
- package/src/design_system/elements/tags/tags.tsx +176 -0
- package/src/design_system/elements/textarea/textarea.aman.tsx +52 -0
- package/src/design_system/elements/textarea/textarea.tsx +111 -0
- package/src/design_system/elements/toggle/toggle.tsx +140 -0
- package/src/design_system/elements/tooltip/tooltip.tsx +109 -0
- package/src/design_system/hooks/use-breakpoint.ts +37 -0
- package/src/design_system/hooks/use-resize-observer.ts +68 -0
- package/src/design_system/logo/keystone-logo-minimal.tsx +93 -0
- package/src/design_system/logo/keystone-logo.tsx +22 -0
- package/src/design_system/sections/about-home.aman.tsx +85 -0
- package/src/design_system/sections/about-home.tsx +115 -0
- package/src/design_system/sections/blog-cards.tsx +848 -0
- package/src/design_system/sections/blog-gallery.aman.tsx +77 -0
- package/src/design_system/sections/blog-gallery.tsx +204 -0
- package/src/design_system/sections/blog-home.aman.tsx +84 -0
- package/src/design_system/sections/blog-home.tsx +153 -0
- package/src/design_system/sections/blog-post.aman.tsx +74 -0
- package/src/design_system/sections/blog-post.tsx +301 -0
- package/src/design_system/sections/blog-section.aman.tsx +101 -0
- package/src/design_system/sections/blog-section.tsx +179 -0
- package/src/design_system/sections/contact-home.tsx +25 -0
- package/src/design_system/sections/contact-section.aman.tsx +173 -0
- package/src/design_system/sections/contact-section.tsx +143 -0
- package/src/design_system/sections/faq-grid.aman.tsx +79 -0
- package/src/design_system/sections/faq-grid.tsx +102 -0
- package/src/design_system/sections/faq-home.aman.tsx +92 -0
- package/src/design_system/sections/faq-home.tsx +134 -0
- package/src/design_system/sections/feature-tab.tsx +43 -0
- package/src/design_system/sections/feature-text.tsx +284 -0
- package/src/design_system/sections/footer-home.aman.tsx +62 -0
- package/src/design_system/sections/footer-home.tsx +259 -0
- package/src/design_system/sections/generic-header-component.tsx +103 -0
- package/src/design_system/sections/header-navigation.aman.tsx +360 -0
- package/src/design_system/sections/header-navigation.tsx +334 -0
- package/src/design_system/sections/hero-faq.aman.tsx +38 -0
- package/src/design_system/sections/hero-faq.tsx +55 -0
- package/src/design_system/sections/hero-generic-text.aman.tsx +49 -0
- package/src/design_system/sections/hero-generic-text.tsx +51 -0
- package/src/design_system/sections/hero-home.aman.tsx +84 -0
- package/src/design_system/sections/hero-home.tsx +246 -0
- package/src/design_system/sections/hero-location-detail.aman.tsx +33 -0
- package/src/design_system/sections/hero-location-detail.tsx +72 -0
- package/src/design_system/sections/hero-service-detail.aman.tsx +53 -0
- package/src/design_system/sections/hero-service-detail.tsx +51 -0
- package/src/design_system/sections/hero-social-media.aman.tsx +42 -0
- package/src/design_system/sections/hero-social-media.tsx +35 -0
- package/src/design_system/sections/hero-testimonials.aman.tsx +38 -0
- package/src/design_system/sections/hero-testimonials.tsx +55 -0
- package/src/design_system/sections/home-hero-component.tsx +228 -0
- package/src/design_system/sections/index.tsx +131 -0
- package/src/design_system/sections/job-gallery.aman.tsx +91 -0
- package/src/design_system/sections/job-gallery.tsx +183 -0
- package/src/design_system/sections/location-details-section.aman.tsx +179 -0
- package/src/design_system/sections/location-details-section.tsx +196 -0
- package/src/design_system/sections/location-grid.aman.tsx +76 -0
- package/src/design_system/sections/location-grid.tsx +123 -0
- package/src/design_system/sections/services-grid.aman.tsx +85 -0
- package/src/design_system/sections/services-grid.tsx +104 -0
- package/src/design_system/sections/services-home.aman.tsx +78 -0
- package/src/design_system/sections/services-home.tsx +131 -0
- package/src/design_system/sections/social-media-grid.aman.tsx +132 -0
- package/src/design_system/sections/social-media-grid.tsx +189 -0
- package/src/design_system/sections/statistics-section.aman.tsx +79 -0
- package/src/design_system/sections/statistics-section.tsx +97 -0
- package/src/design_system/sections/team-grid.aman.tsx +85 -0
- package/src/design_system/sections/team-grid.tsx +88 -0
- package/src/design_system/sections/testimonials-home.aman.tsx +113 -0
- package/src/design_system/sections/testimonials-home.tsx +90 -0
- package/src/design_system/sections/values-section.aman.tsx +73 -0
- package/src/design_system/sections/values-section.tsx +128 -0
- package/src/design_system/utils/icon-mapping.tsx +28 -0
- package/src/index.ts +7 -0
- package/src/lib/component-registry.ts +53 -0
- package/src/lib/hooks/index.ts +8 -0
- package/src/lib/hooks/use-breakpoint.ts +37 -0
- package/src/lib/hooks/use-clipboard.ts +79 -0
- package/src/lib/hooks/use-resize-observer.ts +68 -0
- package/src/lib/server-api.ts +115 -0
- package/src/styles/style-overrides.aman.css +101 -0
- package/src/styles/theme.css +224 -0
- package/src/styles/typography.css +430 -0
- package/src/themes/index.ts +23 -0
- package/src/types/api/blog-post.ts +53 -0
- package/src/types/api/company-information.ts +44 -0
- package/src/types/api/contact.ts +63 -0
- package/src/types/api/faq.ts +37 -0
- package/src/types/api/job-posting.ts +34 -0
- package/src/types/api/location.ts +36 -0
- package/src/types/api/photos.ts +28 -0
- package/src/types/api/service.ts +37 -0
- package/src/types/api/social-post.ts +28 -0
- package/src/types/api/team-member.ts +29 -0
- package/src/types/api/testimonial.ts +29 -0
- package/src/types/api/website-photos.ts +22 -0
- package/src/types/config.ts +21 -0
- package/src/types/index.ts +21 -0
- package/src/utils/countries.tsx +1351 -0
- package/src/utils/cx.ts +25 -0
- package/src/utils/gradient-placeholder.ts +59 -0
- package/src/utils/is-react-component.ts +33 -0
- package/src/utils/markdown-toc.ts +54 -0
- package/src/utils/photo-helpers.ts +94 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ReactNode } from "react";
|
|
2
|
+
import { createContext, useContext, useId } from "react";
|
|
3
|
+
import { Form as AriaForm } from "react-aria-components";
|
|
4
|
+
import type { Control, FieldPath, FieldValues, UseControllerReturn, UseFormReturn } from "react-hook-form";
|
|
5
|
+
import { FormProvider, useController, useFormContext } from "react-hook-form";
|
|
6
|
+
|
|
7
|
+
interface FormProps<TFieldValues extends FieldValues = FieldValues> extends ComponentPropsWithoutRef<typeof AriaForm> {
|
|
8
|
+
form: UseFormReturn<TFieldValues>;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface FormFieldProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> {
|
|
13
|
+
name: TName;
|
|
14
|
+
control: Control<TFieldValues>;
|
|
15
|
+
children: ReactNode | ((control: UseControllerReturn<TFieldValues, TName>) => ReactNode);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface FormFieldContextValues<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> {
|
|
19
|
+
id: string;
|
|
20
|
+
name: TName;
|
|
21
|
+
control?: UseControllerReturn<TFieldValues, TName>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const FormFieldContext = createContext<FormFieldContextValues>({} as FormFieldContextValues);
|
|
25
|
+
|
|
26
|
+
export const useFormFieldContext = () => {
|
|
27
|
+
const context = useContext(FormFieldContext);
|
|
28
|
+
const { getFieldState, formState } = useFormContext();
|
|
29
|
+
const fieldState = getFieldState(context.name, formState);
|
|
30
|
+
|
|
31
|
+
if (!context) {
|
|
32
|
+
throw new Error("The 'useFormContext' hook must be used within a '<FormField />'");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return { ...context, ...fieldState };
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const HookForm = <TFieldValues extends FieldValues = FieldValues>({ form, ...props }: FormProps<TFieldValues>) => {
|
|
39
|
+
return (
|
|
40
|
+
<FormProvider {...form}>
|
|
41
|
+
<AriaForm {...props} />
|
|
42
|
+
</FormProvider>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
HookForm.displayName = "HookForm";
|
|
47
|
+
|
|
48
|
+
export const FormField = <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({
|
|
49
|
+
children,
|
|
50
|
+
...props
|
|
51
|
+
}: FormFieldProps<TFieldValues, TName>) => {
|
|
52
|
+
const id = "form-item-" + useId();
|
|
53
|
+
const control = useController(props);
|
|
54
|
+
const withValidationBehavior = {
|
|
55
|
+
...control,
|
|
56
|
+
field: {
|
|
57
|
+
...control.field,
|
|
58
|
+
validationBehavior: "aria",
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<FormFieldContext.Provider
|
|
64
|
+
value={{
|
|
65
|
+
id,
|
|
66
|
+
name: props.name,
|
|
67
|
+
control: control as UseControllerReturn<FieldValues, TName>,
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
{children && (typeof children === "function" ? children(withValidationBehavior) : children)}
|
|
71
|
+
</FormFieldContext.Provider>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
FormField.displayName = "FormField";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ReactNode, Ref } from "react";
|
|
4
|
+
import type { TextProps as AriaTextProps } from "react-aria-components";
|
|
5
|
+
import { Text as AriaText } from "react-aria-components";
|
|
6
|
+
import { cx } from '../../../utils/cx';
|
|
7
|
+
|
|
8
|
+
interface HintTextProps extends AriaTextProps {
|
|
9
|
+
/** Indicates that the hint text is an error message. */
|
|
10
|
+
isInvalid?: boolean;
|
|
11
|
+
ref?: Ref<HTMLElement>;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const HintText = ({ isInvalid, className, ...props }: HintTextProps) => {
|
|
16
|
+
return (
|
|
17
|
+
<AriaText
|
|
18
|
+
{...props}
|
|
19
|
+
slot={isInvalid ? "errorMessage" : "description"}
|
|
20
|
+
className={cx(
|
|
21
|
+
"text-sm text-tertiary",
|
|
22
|
+
|
|
23
|
+
// Invalid state
|
|
24
|
+
isInvalid && "text-error-primary",
|
|
25
|
+
"group-invalid:text-error-primary",
|
|
26
|
+
|
|
27
|
+
className,
|
|
28
|
+
)}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
HintText.displayName = "HintText";
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Elements Exports
|
|
3
|
+
* All commonly used elements export from here with theme variant support
|
|
4
|
+
* Includes: Buttons, Form inputs, Date pickers, UI components
|
|
5
|
+
* Excludes: .demo.tsx, .story.tsx, and specialized sub-components
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use client';
|
|
9
|
+
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import { getThemedComponent } from '../../lib/component-registry';
|
|
12
|
+
import { useTheme } from '../../contexts/ThemeContext';
|
|
13
|
+
|
|
14
|
+
// Import all base components - Buttons
|
|
15
|
+
import { Button as BaseButton } from './buttons/button';
|
|
16
|
+
import { RoundButton as BaseRoundButton } from './buttons/round-button';
|
|
17
|
+
import { CloseButton as BaseCloseButton } from './buttons/close-button';
|
|
18
|
+
import { SocialButton as BaseSocialButton } from './buttons/social-button';
|
|
19
|
+
import { AppStoreButton as BaseAppStoreButton, GooglePlayButton as BaseGooglePlayButton } from './buttons/app-store-buttons';
|
|
20
|
+
import { ButtonGroup as BaseButtonGroup } from './button-group/button-group';
|
|
21
|
+
|
|
22
|
+
// Form inputs
|
|
23
|
+
import { Input as BaseInput } from './input/input';
|
|
24
|
+
import { InputGroup as BaseInputGroup } from './input/input-group';
|
|
25
|
+
import { TextArea as BaseTextarea } from './textarea/textarea';
|
|
26
|
+
import { Checkbox as BaseCheckbox } from './checkbox/checkbox';
|
|
27
|
+
import { Toggle as BaseToggle } from './toggle/toggle';
|
|
28
|
+
import { Form as BaseForm } from './form/form';
|
|
29
|
+
import { Label as BaseLabel } from './input/label';
|
|
30
|
+
import { HintText as BaseHintText } from './input/hint-text';
|
|
31
|
+
import { Select as BaseSelect } from './select/select';
|
|
32
|
+
import { SelectItem as BaseSelectItem } from './select/select-item';
|
|
33
|
+
import { MultiSelect as BaseMultiSelect } from './select/multi-select';
|
|
34
|
+
import { NativeSelect as BaseNativeSelect } from './select/select-native';
|
|
35
|
+
import { RadioGroup as BaseRadioGroup, RadioButton as BaseRadioButton } from './radio-buttons/radio-buttons';
|
|
36
|
+
|
|
37
|
+
// Date pickers
|
|
38
|
+
import { DatePicker as BaseDatePicker } from './date-picker/date-picker';
|
|
39
|
+
import { DateRangePicker as BaseDateRangePicker } from './date-picker/date-range-picker';
|
|
40
|
+
|
|
41
|
+
// UI components
|
|
42
|
+
import PhotoWithFallbackBase from './photo-fallback/photo-fallback';
|
|
43
|
+
import { LoadingIndicator as BaseLoadingIndicator } from './loading-indicator/loading-indicator';
|
|
44
|
+
import { Badge as BaseBadge, BadgeWithDot as BaseBadgeWithDot } from './badges/badges';
|
|
45
|
+
import { BadgeGroup as BaseBadgeGroup } from './badges/badge-groups';
|
|
46
|
+
import { RatingStars as BaseRatingStars } from './rating/rating-stars';
|
|
47
|
+
import { RatingBadge as BaseRatingBadge } from './rating/rating-badge';
|
|
48
|
+
import { Tooltip as BaseTooltip } from './tooltip/tooltip';
|
|
49
|
+
import { Avatar as BaseAvatar } from './avatar/avatar';
|
|
50
|
+
import { AvatarLabelGroup as BaseAvatarLabelGroup } from './avatar/avatar-label-group';
|
|
51
|
+
import { AvatarProfilePhoto as BaseAvatarProfilePhoto } from './avatar/avatar-profile-photo';
|
|
52
|
+
import { VerifiedTick as BaseVerifiedTick } from './avatar/base-components';
|
|
53
|
+
import { Breadcrumb as BaseBreadcrumb } from './breadcrumb/Breadcrumb';
|
|
54
|
+
import { Tabs as BaseTabs } from './tabs/tabs';
|
|
55
|
+
import { TagGroup as BaseTagGroup, TagList as BaseTagList, Tag as BaseTag } from './tags/tags';
|
|
56
|
+
import { FeaturedIcon as BaseFeaturedIcon } from './featured-icon/featured-icon';
|
|
57
|
+
import { ProgressBar as BaseProgressBar } from './progress-indicators/progress-indicators';
|
|
58
|
+
import { ProgressBarCircle as BaseProgressBarCircle } from './progress-indicators/progress-circles';
|
|
59
|
+
import { CircleProgressBar as BaseCircleProgressBar } from './progress-indicators/simple-circle';
|
|
60
|
+
import { SlideoutMenu as BaseSlideoutMenu } from './slideout-menus/slideout-menu';
|
|
61
|
+
import { Pagination as BasePagination } from './pagination/pagination-base';
|
|
62
|
+
import { PaginationDot as BasePaginationDot } from './pagination/pagination-dot';
|
|
63
|
+
import { PaginationLine as BasePaginationLine } from './pagination/pagination-line';
|
|
64
|
+
import { PaginationPageDefault as BasePaginationPageDefault, PaginationPageMinimalCenter as BasePaginationPageMinimalCenter } from './pagination/pagination';
|
|
65
|
+
import BaseGoogleMap from './map/GoogleMap';
|
|
66
|
+
import BaseMarkdownRenderer from './markdown-renderer/MarkdownRenderer';
|
|
67
|
+
|
|
68
|
+
// Import variant files to trigger registration (only ones that exist)
|
|
69
|
+
import './buttons/button.aman';
|
|
70
|
+
import './input/input.aman';
|
|
71
|
+
import './textarea/textarea.aman';
|
|
72
|
+
import './select/select.aman';
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Create themed component wrapper
|
|
76
|
+
*/
|
|
77
|
+
function createThemedExport(componentName: string, BaseComponent: React.ComponentType<any>) {
|
|
78
|
+
return function ThemedComponent(props: any) {
|
|
79
|
+
const { theme } = useTheme();
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const Component = getThemedComponent(componentName, theme);
|
|
83
|
+
return React.createElement(Component, props);
|
|
84
|
+
} catch {
|
|
85
|
+
// No variant registered, use base component
|
|
86
|
+
return React.createElement(BaseComponent, props);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// All elements wrapped (falls back to base if no variant)
|
|
92
|
+
// Buttons
|
|
93
|
+
export const Button = createThemedExport('button', BaseButton);
|
|
94
|
+
export const RoundButton = createThemedExport('round-button', BaseRoundButton);
|
|
95
|
+
export const CloseButton = createThemedExport('close-button', BaseCloseButton);
|
|
96
|
+
export const SocialButton = createThemedExport('social-button', BaseSocialButton);
|
|
97
|
+
export const AppStoreButton = createThemedExport('app-store-button', BaseAppStoreButton);
|
|
98
|
+
export const GooglePlayButton = createThemedExport('google-play-button', BaseGooglePlayButton);
|
|
99
|
+
export const ButtonGroup = createThemedExport('button-group', BaseButtonGroup);
|
|
100
|
+
|
|
101
|
+
// Form inputs
|
|
102
|
+
export const Input = createThemedExport('input', BaseInput);
|
|
103
|
+
export const Textarea = createThemedExport('textarea', BaseTextarea);
|
|
104
|
+
export const Checkbox = createThemedExport('checkbox', BaseCheckbox);
|
|
105
|
+
export const Toggle = createThemedExport('toggle', BaseToggle);
|
|
106
|
+
export const Form = createThemedExport('form', BaseForm);
|
|
107
|
+
export const InputGroup = createThemedExport('input-group', BaseInputGroup);
|
|
108
|
+
export const Label = createThemedExport('label', BaseLabel);
|
|
109
|
+
export const HintText = createThemedExport('hint-text', BaseHintText);
|
|
110
|
+
export const Select = createThemedExport('select', BaseSelect);
|
|
111
|
+
export const SelectItem = createThemedExport('select-item', BaseSelectItem);
|
|
112
|
+
export const MultiSelect = createThemedExport('multi-select', BaseMultiSelect);
|
|
113
|
+
export const NativeSelect = createThemedExport('native-select', BaseNativeSelect);
|
|
114
|
+
export const RadioGroup = createThemedExport('radio-group', BaseRadioGroup);
|
|
115
|
+
export const RadioButton = createThemedExport('radio-button', BaseRadioButton);
|
|
116
|
+
|
|
117
|
+
// Date pickers
|
|
118
|
+
export const DatePicker = createThemedExport('date-picker', BaseDatePicker);
|
|
119
|
+
export const DateRangePicker = createThemedExport('date-range-picker', BaseDateRangePicker);
|
|
120
|
+
|
|
121
|
+
// UI components
|
|
122
|
+
export const PhotoWithFallback = createThemedExport('photo-fallback', PhotoWithFallbackBase);
|
|
123
|
+
export const LoadingIndicator = createThemedExport('loading-indicator', BaseLoadingIndicator);
|
|
124
|
+
export const Badge = createThemedExport('badge', BaseBadge);
|
|
125
|
+
export const BadgeWithDot = createThemedExport('badge-with-dot', BaseBadgeWithDot);
|
|
126
|
+
export const BadgeGroup = createThemedExport('badge-group', BaseBadgeGroup);
|
|
127
|
+
export const RatingStars = createThemedExport('rating-stars', BaseRatingStars);
|
|
128
|
+
export const RatingBadge = createThemedExport('rating-badge', BaseRatingBadge);
|
|
129
|
+
export const Tooltip = createThemedExport('tooltip', BaseTooltip);
|
|
130
|
+
export const Avatar = createThemedExport('avatar', BaseAvatar);
|
|
131
|
+
export const AvatarLabelGroup = createThemedExport('avatar-label-group', BaseAvatarLabelGroup);
|
|
132
|
+
export const AvatarProfilePhoto = createThemedExport('avatar-profile-photo', BaseAvatarProfilePhoto);
|
|
133
|
+
export const VerifiedTick = createThemedExport('verified-tick', BaseVerifiedTick);
|
|
134
|
+
export const Breadcrumb = createThemedExport('breadcrumb', BaseBreadcrumb);
|
|
135
|
+
export const FeaturedIcon = createThemedExport('featured-icon', BaseFeaturedIcon);
|
|
136
|
+
export const ProgressBar = createThemedExport('progress-bar', BaseProgressBar);
|
|
137
|
+
export const ProgressBarCircle = createThemedExport('progress-bar-circle', BaseProgressBarCircle);
|
|
138
|
+
export const CircleProgressBar = createThemedExport('circle-progress-bar', BaseCircleProgressBar);
|
|
139
|
+
export const PaginationDot = createThemedExport('pagination-dot', BasePaginationDot);
|
|
140
|
+
export const PaginationLine = createThemedExport('pagination-line', BasePaginationLine);
|
|
141
|
+
export const PaginationPageDefault = createThemedExport('pagination-page-default', BasePaginationPageDefault);
|
|
142
|
+
export const PaginationPageMinimalCenter = createThemedExport('pagination-page-minimal-center', BasePaginationPageMinimalCenter);
|
|
143
|
+
export const GoogleMap = createThemedExport('google-map', BaseGoogleMap);
|
|
144
|
+
export const MarkdownRenderer = createThemedExport('markdown-renderer', BaseMarkdownRenderer);
|
|
145
|
+
|
|
146
|
+
// Re-export compound components directly (they have subcomponents like .Root, .List, .DropZone, .Group, .Slot, etc.)
|
|
147
|
+
export { Tabs } from './tabs/tabs';
|
|
148
|
+
export { TagGroup, TagList, Tag } from './tags/tags';
|
|
149
|
+
export { Pagination } from './pagination/pagination-base';
|
|
150
|
+
export { SlideoutMenu } from './slideout-menus/slideout-menu';
|
|
151
|
+
|
|
152
|
+
// Re-export everything from subdirectories that doesn't need theming
|
|
153
|
+
export * from './rating/rating-stars';
|
|
154
|
+
export * from './rating/rating-badge';
|
|
155
|
+
export * from './carousel/carousel';
|
|
156
|
+
|
|
157
|
+
// Re-export combobox (still exists in select directory but not wrapped with theming)
|
|
158
|
+
export { ComboBox } from './select/combobox';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ReactNode, Ref } from "react";
|
|
4
|
+
import type { TextProps as AriaTextProps } from "react-aria-components";
|
|
5
|
+
import { Text as AriaText } from "react-aria-components";
|
|
6
|
+
import { cx } from '../../../utils/cx';
|
|
7
|
+
|
|
8
|
+
interface HintTextProps extends AriaTextProps {
|
|
9
|
+
/** Indicates that the hint text is an error message. */
|
|
10
|
+
isInvalid?: boolean;
|
|
11
|
+
ref?: Ref<HTMLElement>;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const HintText = ({ isInvalid, className, ...props }: HintTextProps) => {
|
|
16
|
+
return (
|
|
17
|
+
<AriaText
|
|
18
|
+
{...props}
|
|
19
|
+
slot={isInvalid ? "errorMessage" : "description"}
|
|
20
|
+
className={cx(
|
|
21
|
+
"text-sm text-tertiary",
|
|
22
|
+
|
|
23
|
+
// Invalid state
|
|
24
|
+
isInvalid && "text-error-primary",
|
|
25
|
+
"group-invalid:text-error-primary",
|
|
26
|
+
|
|
27
|
+
className,
|
|
28
|
+
)}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
HintText.displayName = "HintText";
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { type HTMLAttributes, type ReactNode } from "react";
|
|
4
|
+
import { HintText } from './hint-text';
|
|
5
|
+
import type { InputBaseProps } from './input';
|
|
6
|
+
import { TextField } from './input';
|
|
7
|
+
import { Label } from './label';
|
|
8
|
+
import { cx, sortCx } from '../../../utils/cx';
|
|
9
|
+
|
|
10
|
+
interface InputPrefixProps extends HTMLAttributes<HTMLDivElement> {
|
|
11
|
+
/** The position of the prefix. */
|
|
12
|
+
position?: "leading" | "trailing";
|
|
13
|
+
/** The size of the prefix. */
|
|
14
|
+
size?: "sm" | "md";
|
|
15
|
+
/** Indicates that the prefix is disabled. */
|
|
16
|
+
isDisabled?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const InputPrefix = ({ isDisabled, children, ...props }: InputPrefixProps) => (
|
|
20
|
+
<span
|
|
21
|
+
{...props}
|
|
22
|
+
className={cx(
|
|
23
|
+
"flex text-md text-tertiary shadow-xs ring-1 ring-border-primary ring-inset",
|
|
24
|
+
// Styles when the prefix is within an `InputGroup`
|
|
25
|
+
"in-data-input-wrapper:in-data-leading:-mr-px in-data-input-wrapper:in-data-leading:rounded-l-lg",
|
|
26
|
+
"in-data-input-wrapper:in-data-trailing:-ml-px in-data-input-wrapper:in-data-trailing:rounded-r-lg",
|
|
27
|
+
// Size styles based on size when within an `InputGroup`
|
|
28
|
+
"in-data-input-wrapper:in-data-[input-size=md]:py-2.5 in-data-input-wrapper:in-data-[input-size=md]:pr-3 in-data-input-wrapper:in-data-[input-size=md]:pl-3.5 in-data-input-wrapper:in-data-[input-size=sm]:px-3 in-data-input-wrapper:in-data-[input-size=sm]:py-2",
|
|
29
|
+
// Disabled styles
|
|
30
|
+
isDisabled && "border-disabled bg-disabled_subtle text-tertiary",
|
|
31
|
+
"in-data-input-wrapper:group-disabled:bg-disabled_subtle in-data-input-wrapper:group-disabled:text-disabled in-data-input-wrapper:group-disabled:ring-border-disabled",
|
|
32
|
+
|
|
33
|
+
props.className,
|
|
34
|
+
)}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
</span>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// `${string}ClassName` is used to omit any className prop that ends with a `ClassName` suffix
|
|
41
|
+
interface InputGroupProps extends Omit<InputBaseProps, "type" | "icon" | "placeholder" | "tooltip" | "shortcut" | `${string}ClassName`> {
|
|
42
|
+
/** A prefix text that is displayed in the same box as the input.*/
|
|
43
|
+
prefix?: string;
|
|
44
|
+
/** A leading addon that is displayed with visual separation from the input. */
|
|
45
|
+
leadingAddon?: ReactNode;
|
|
46
|
+
/** A trailing addon that is displayed with visual separation from the input. */
|
|
47
|
+
trailingAddon?: ReactNode;
|
|
48
|
+
/** The class name to apply to the input group. */
|
|
49
|
+
className?: string;
|
|
50
|
+
/** The children of the input group (i.e `<InputBase />`) */
|
|
51
|
+
children: ReactNode;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const InputGroup = ({ size = "sm", prefix, leadingAddon, trailingAddon, label, hint, children, ...props }: InputGroupProps) => {
|
|
55
|
+
const hasLeading = !!leadingAddon;
|
|
56
|
+
const hasTrailing = !!trailingAddon;
|
|
57
|
+
|
|
58
|
+
const paddings = sortCx({
|
|
59
|
+
sm: {
|
|
60
|
+
input: cx(
|
|
61
|
+
// Apply padding styles when select element is passed as a child
|
|
62
|
+
hasLeading && "group-has-[&>select]:px-2.5 group-has-[&>select]:pl-2.5",
|
|
63
|
+
hasTrailing && (prefix ? "group-has-[&>select]:pr-6 group-has-[&>select]:pl-0" : "group-has-[&>select]:pr-6 group-has-[&>select]:pl-3"),
|
|
64
|
+
),
|
|
65
|
+
leadingText: "pl-3",
|
|
66
|
+
},
|
|
67
|
+
md: {
|
|
68
|
+
input: cx(
|
|
69
|
+
// Apply padding styles when select element is passed as a child
|
|
70
|
+
hasLeading && "group-has-[&>select]:px-3 group-has-[&>select]:pl-3",
|
|
71
|
+
hasTrailing && (prefix ? "group-has-[&>select]:pr-6 group-has-[&>select]:pl-0" : "group-has-[&>select]:pr-6 group-has-[&>select]:pl-3"),
|
|
72
|
+
),
|
|
73
|
+
leadingText: "pl-3.5",
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<TextField
|
|
79
|
+
size={size}
|
|
80
|
+
aria-label={label || undefined}
|
|
81
|
+
inputClassName={cx(paddings[size].input)}
|
|
82
|
+
tooltipClassName={cx(hasTrailing && !hasLeading && "group-has-[&>select]:right-0")}
|
|
83
|
+
wrapperClassName={cx(
|
|
84
|
+
"z-10",
|
|
85
|
+
// Apply styles based on the presence of leading or trailing elements
|
|
86
|
+
hasLeading && "rounded-l-none",
|
|
87
|
+
hasTrailing && "rounded-r-none",
|
|
88
|
+
// When select element is passed as a child
|
|
89
|
+
"group-has-[&>select]:bg-transparent group-has-[&>select]:shadow-none group-has-[&>select]:ring-0 group-has-[&>select]:focus-within:ring-0",
|
|
90
|
+
// In `Input` component, there is "group-disabled" class so here we need to use "group-disabled:group-has-[&>select]" to avoid conflict
|
|
91
|
+
"group-disabled:group-has-[&>select]:bg-transparent",
|
|
92
|
+
)}
|
|
93
|
+
{...props}
|
|
94
|
+
>
|
|
95
|
+
{({ isDisabled, isInvalid, isRequired }) => (
|
|
96
|
+
<>
|
|
97
|
+
{label && <Label isRequired={isRequired}>{label}</Label>}
|
|
98
|
+
|
|
99
|
+
<div
|
|
100
|
+
data-input-size={size}
|
|
101
|
+
className={cx(
|
|
102
|
+
"group relative flex h-max w-full flex-row justify-center rounded-lg bg-primary transition-all duration-100 ease-linear",
|
|
103
|
+
|
|
104
|
+
// Only apply focus ring when child is select and input is focused
|
|
105
|
+
"has-[&>select]:shadow-xs has-[&>select]:ring-1 has-[&>select]:ring-border-primary has-[&>select]:ring-inset has-[&>select]:has-[input:focus]:ring-2 has-[&>select]:has-[input:focus]:ring-border-brand",
|
|
106
|
+
|
|
107
|
+
isDisabled && "cursor-not-allowed has-[&>select]:bg-disabled_subtle has-[&>select]:ring-border-disabled",
|
|
108
|
+
isInvalid && "has-[&>select]:ring-border-error_subtle has-[&>select]:has-[input:focus]:ring-border-error",
|
|
109
|
+
)}
|
|
110
|
+
>
|
|
111
|
+
{leadingAddon && <section data-leading={hasLeading || undefined}>{leadingAddon}</section>}
|
|
112
|
+
|
|
113
|
+
{prefix && (
|
|
114
|
+
<span className={cx("my-auto grow pr-2", paddings[size].leadingText)}>
|
|
115
|
+
<p className={cx("text-md text-tertiary", isDisabled && "text-disabled")}>{prefix}</p>
|
|
116
|
+
</span>
|
|
117
|
+
)}
|
|
118
|
+
|
|
119
|
+
{children}
|
|
120
|
+
|
|
121
|
+
{trailingAddon && <section data-trailing={hasTrailing || undefined}>{trailingAddon}</section>}
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
{hint && <HintText isInvalid={isInvalid}>{hint}</HintText>}
|
|
125
|
+
</>
|
|
126
|
+
)}
|
|
127
|
+
</TextField>
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
InputGroup.Prefix = InputPrefix;
|
|
132
|
+
|
|
133
|
+
InputGroup.displayName = "InputGroup";
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { type ComponentType, type HTMLAttributes, type Ref, createContext, useContext } from "react";
|
|
4
|
+
import { HelpCircle, InfoCircle } from "@untitledui/icons";
|
|
5
|
+
import type { InputProps as AriaInputProps, TextFieldProps as AriaTextFieldProps } from "react-aria-components";
|
|
6
|
+
import { Group as AriaGroup, Input as AriaInput, TextField as AriaTextField } from "react-aria-components";
|
|
7
|
+
import { HintText } from './hint-text';
|
|
8
|
+
import { Label } from './label';
|
|
9
|
+
import { Tooltip, TooltipTrigger } from '../tooltip/tooltip';
|
|
10
|
+
import { cx, sortCx } from '../../../utils/cx';
|
|
11
|
+
|
|
12
|
+
export interface InputBaseProps extends AriaTextFieldProps {
|
|
13
|
+
tooltip?: string;
|
|
14
|
+
size?: "sm" | "md";
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
iconClassName?: string;
|
|
17
|
+
inputClassName?: string;
|
|
18
|
+
wrapperClassName?: string;
|
|
19
|
+
tooltipClassName?: string;
|
|
20
|
+
shortcut?: string | boolean;
|
|
21
|
+
ref?: Ref<HTMLInputElement>;
|
|
22
|
+
groupRef?: Ref<HTMLDivElement>;
|
|
23
|
+
icon?: ComponentType<HTMLAttributes<HTMLOrSVGElement>>;
|
|
24
|
+
label?: string;
|
|
25
|
+
hint?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const TextFieldContext = createContext<Partial<InputBaseProps>>({});
|
|
29
|
+
|
|
30
|
+
export const InputBase = ({
|
|
31
|
+
ref,
|
|
32
|
+
tooltip,
|
|
33
|
+
shortcut,
|
|
34
|
+
groupRef,
|
|
35
|
+
size = "sm",
|
|
36
|
+
isInvalid,
|
|
37
|
+
isDisabled,
|
|
38
|
+
icon: Icon,
|
|
39
|
+
placeholder,
|
|
40
|
+
wrapperClassName,
|
|
41
|
+
tooltipClassName,
|
|
42
|
+
inputClassName,
|
|
43
|
+
iconClassName,
|
|
44
|
+
isRequired: _isRequired,
|
|
45
|
+
...inputProps
|
|
46
|
+
}: Omit<InputBaseProps, "label" | "hint">) => {
|
|
47
|
+
const hasTrailingIcon = tooltip || isInvalid;
|
|
48
|
+
const hasLeadingIcon = Icon;
|
|
49
|
+
const context = useContext(TextFieldContext);
|
|
50
|
+
const inputSize = context?.size || size;
|
|
51
|
+
|
|
52
|
+
const sizes = sortCx({
|
|
53
|
+
sm: {
|
|
54
|
+
root: cx("px-3 py-2.5", hasTrailingIcon && "pr-9", hasLeadingIcon && "pl-10"),
|
|
55
|
+
iconLeading: "left-3",
|
|
56
|
+
iconTrailing: "right-3",
|
|
57
|
+
shortcut: "pr-2.5",
|
|
58
|
+
},
|
|
59
|
+
md: {
|
|
60
|
+
root: cx("px-3.5 py-3", hasTrailingIcon && "pr-9.5", hasLeadingIcon && "pl-10.5"),
|
|
61
|
+
iconLeading: "left-3.5",
|
|
62
|
+
iconTrailing: "right-3.5",
|
|
63
|
+
shortcut: "pr-3",
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<AriaGroup
|
|
69
|
+
{...{ isDisabled, isInvalid }}
|
|
70
|
+
ref={groupRef}
|
|
71
|
+
className={({ isFocusWithin, isDisabled, isInvalid }) =>
|
|
72
|
+
cx(
|
|
73
|
+
"relative flex w-full flex-row place-content-center place-items-center rounded-sm bg-white shadow-sm ring-1 ring-secondary transition-shadow duration-100 ease-linear ring-inset",
|
|
74
|
+
isFocusWithin && !isDisabled && "ring-2 ring-focus-ring",
|
|
75
|
+
isDisabled && "cursor-not-allowed bg-primary ring-secondary",
|
|
76
|
+
isInvalid && "ring-error_subtle",
|
|
77
|
+
isInvalid && isFocusWithin && "ring-2 ring-error",
|
|
78
|
+
context?.wrapperClassName,
|
|
79
|
+
wrapperClassName,
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
>
|
|
83
|
+
{Icon && (
|
|
84
|
+
<Icon
|
|
85
|
+
className={cx(
|
|
86
|
+
"pointer-events-none absolute size-5 text-secondary",
|
|
87
|
+
isDisabled && "text-border-secondary",
|
|
88
|
+
sizes[inputSize].iconLeading,
|
|
89
|
+
context?.iconClassName,
|
|
90
|
+
iconClassName,
|
|
91
|
+
)}
|
|
92
|
+
/>
|
|
93
|
+
)}
|
|
94
|
+
|
|
95
|
+
<AriaInput
|
|
96
|
+
{...(inputProps as AriaInputProps)}
|
|
97
|
+
ref={ref}
|
|
98
|
+
placeholder={placeholder}
|
|
99
|
+
className={cx(
|
|
100
|
+
"m-0 w-full bg-transparent text-base font-body text-fg-primary ring-0 outline-hidden placeholder:text-secondary autofill:rounded-sm autofill:text-fg-primary",
|
|
101
|
+
isDisabled && "cursor-not-allowed text-secondary",
|
|
102
|
+
sizes[inputSize].root,
|
|
103
|
+
context?.inputClassName,
|
|
104
|
+
inputClassName,
|
|
105
|
+
)}
|
|
106
|
+
/>
|
|
107
|
+
|
|
108
|
+
{tooltip && !isInvalid && (
|
|
109
|
+
<Tooltip title={tooltip} placement="top">
|
|
110
|
+
<TooltipTrigger
|
|
111
|
+
className={cx(
|
|
112
|
+
"absolute cursor-pointer text-secondary transition duration-200 hover:text-fg-primary focus:text-fg-primary",
|
|
113
|
+
sizes[inputSize].iconTrailing,
|
|
114
|
+
context?.tooltipClassName,
|
|
115
|
+
tooltipClassName,
|
|
116
|
+
)}
|
|
117
|
+
>
|
|
118
|
+
<HelpCircle className="size-4" />
|
|
119
|
+
</TooltipTrigger>
|
|
120
|
+
</Tooltip>
|
|
121
|
+
)}
|
|
122
|
+
|
|
123
|
+
{isInvalid && (
|
|
124
|
+
<InfoCircle
|
|
125
|
+
className={cx(
|
|
126
|
+
"pointer-events-none absolute size-4 text-error",
|
|
127
|
+
sizes[inputSize].iconTrailing,
|
|
128
|
+
)}
|
|
129
|
+
/>
|
|
130
|
+
)}
|
|
131
|
+
|
|
132
|
+
{shortcut && (
|
|
133
|
+
<kbd
|
|
134
|
+
className={cx(
|
|
135
|
+
"pointer-events-none absolute flex h-5 items-center justify-center rounded bg-utility-gray-50 px-1.5 text-xs font-medium text-tertiary shadow-xs ring-1 ring-inset ring-utility-gray-200",
|
|
136
|
+
sizes[inputSize].shortcut,
|
|
137
|
+
)}
|
|
138
|
+
>
|
|
139
|
+
{shortcut === true ? "⌘K" : shortcut}
|
|
140
|
+
</kbd>
|
|
141
|
+
)}
|
|
142
|
+
</AriaGroup>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export const Input = ({
|
|
147
|
+
label,
|
|
148
|
+
hint,
|
|
149
|
+
size,
|
|
150
|
+
isInvalid,
|
|
151
|
+
isDisabled,
|
|
152
|
+
isRequired,
|
|
153
|
+
...props
|
|
154
|
+
}: InputBaseProps) => {
|
|
155
|
+
const textFieldContext = { size, wrapperClassName: props.wrapperClassName, inputClassName: props.inputClassName, iconClassName: props.iconClassName, tooltipClassName: props.tooltipClassName };
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<TextFieldContext.Provider value={textFieldContext}>
|
|
159
|
+
<AriaTextField
|
|
160
|
+
{...({ isInvalid, isDisabled, isRequired } as AriaTextFieldProps)}
|
|
161
|
+
className="flex flex-col gap-1.5"
|
|
162
|
+
>
|
|
163
|
+
{label && <Label>{label}</Label>}
|
|
164
|
+
<InputBase {...props} size={size} isInvalid={isInvalid} isDisabled={isDisabled} />
|
|
165
|
+
{hint && <HintText>{hint}</HintText>}
|
|
166
|
+
</AriaTextField>
|
|
167
|
+
</TextFieldContext.Provider>
|
|
168
|
+
);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
import { registerThemeVariant } from '../../../lib/component-registry';
|
|
172
|
+
registerThemeVariant('input', 'aman', Input);
|