= props => {
8 | const [state, setState] = React.useState(false);
9 |
10 | React.useEffect(() => {
11 | let timeout: number;
12 | if (state) {
13 | timeout = window.setTimeout(() => setState(prev => !prev), 3000);
14 | }
15 |
16 | return () => window.clearTimeout(timeout);
17 | }, [state]);
18 |
19 | return (
20 |
21 |
24 | }
29 | suffix={}
30 | onClick={() => setState(!state)}
31 | >
32 | Send Email
33 |
34 |
37 |
38 | );
39 | };
40 |
41 | export default ButtonLoadingA11y;
42 |
--------------------------------------------------------------------------------
/src/select/SelectWrapper.tsx:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 |
4 | import { BoxOptions, useBox } from "../box";
5 | import { useTheme } from "../theme";
6 | import { createComponent, cx } from "../utils";
7 |
8 | import { SelectUIProps } from "./SelectProps";
9 |
10 | export const useSelectWrapper = createHook(
11 | ({ prefix, suffix, size, variant, invalid, loading, spinner, ...props }) => {
12 | const theme = useTheme("select");
13 | const className = cx(theme.wrapper, props.className);
14 |
15 | props = { ...props, className };
16 | props = useBox(props);
17 |
18 | return props;
19 | },
20 | );
21 |
22 | export const SelectWrapper = createComponent(props => {
23 | const htmlProps = useSelectWrapper(props);
24 |
25 | return createElement("div", htmlProps);
26 | }, "SelectWrapper");
27 |
28 | export type SelectWrapperOptions = BoxOptions &
29 | Partial & {};
30 |
31 | export type SelectWrapperProps = Props<
32 | SelectWrapperOptions
33 | >;
34 |
--------------------------------------------------------------------------------
/src/circular-progress/stories/CircularProgressCustom.stories.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentMeta, ComponentStoryObj } from "@storybook/react";
2 |
3 | import {
4 | createPreviewTabs,
5 | createUnionControl,
6 | } from "../../../.storybook/utils";
7 |
8 | import js from "./templates/CircularProgressCustomJsx";
9 | import ts from "./templates/CircularProgressCustomTsx";
10 | import CircularProgressCustom from "./CircularProgressCustom.component";
11 |
12 | type Meta = ComponentMeta;
13 | type Story = ComponentStoryObj;
14 |
15 | export default {
16 | title: "Feedback/CircularProgress/Custom",
17 | component: CircularProgressCustom,
18 | argTypes: {
19 | size: createUnionControl(["sm", "md", "lg", "xl"]),
20 | },
21 | parameters: {
22 | layout: "centered",
23 | options: { showPanel: false },
24 | preview: createPreviewTabs({ js, ts }),
25 | },
26 | } as Meta;
27 |
28 | export const Small: Story = { args: { size: "sm" } };
29 | export const Medium: Story = { args: { size: "md" } };
30 | export const Large: Story = { args: { size: "lg" } };
31 | export const ExtraLarge: Story = { args: { size: "xl" } };
32 |
--------------------------------------------------------------------------------
/src/textarea/Textarea.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { TextareaBase } from "./TextareaBase";
4 | import { TextareaGhost } from "./TextareaGhost";
5 | import { TextareaIcon } from "./TextareaIcon";
6 | import { TextareaProps, useTextareaProps } from "./TextareaProps";
7 | import { TextareaSpinner } from "./TextareaSpinner";
8 | import { TextareaWrapper } from "./TextareaWrapper";
9 |
10 | export const Textarea = React.forwardRef(
11 | (props, ref) => {
12 | const {
13 | wrapperProps,
14 | baseProps,
15 | spinnerProps,
16 | iconProps,
17 | ghostProps,
18 | uiProps,
19 | } = useTextareaProps(props);
20 | const { loading, icon } = uiProps;
21 |
22 | return (
23 |
24 |
25 | {loading ? (
26 |
27 | ) : icon ? (
28 |
29 | ) : null}
30 |
31 |
32 | );
33 | },
34 | );
35 |
36 | Textarea.displayName = "Textarea";
37 |
--------------------------------------------------------------------------------
/src/radio-group/stories/RadioGroupDisabled.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { Radio, RadioGroup, RadioGroupProps } from "../../index";
4 |
5 | export const RadioGroupDisabled: React.FC = props => {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | );
24 | };
25 |
26 | export default RadioGroupDisabled;
27 |
--------------------------------------------------------------------------------
/jest.setup.js:
--------------------------------------------------------------------------------
1 | const {
2 | matcherHint,
3 | printReceived,
4 | printExpected,
5 | } = require("jest-matcher-utils");
6 | const { toHaveNoViolations: axeMatchers } = require("jest-axe");
7 | const matchers = require("@testing-library/jest-dom/matchers");
8 |
9 | // Consider [aria-activedescendant="${id}"] #${id} as the focused element.
10 | function toHaveFocus(element) {
11 | const result = matchers.toHaveFocus.call(this, element);
12 | const { activeElement } = element.ownerDocument;
13 | const activeId =
14 | activeElement && activeElement.getAttribute("aria-activedescendant");
15 | return {
16 | ...result,
17 | pass: result.pass || activeId === element.id,
18 | message: () => {
19 | if (activeId) {
20 | return [
21 | matcherHint(`${this.isNot ? ".not" : ""}.toHaveFocus`, "element", ""),
22 | "",
23 | "Expected:",
24 | ` ${printExpected(element)}`,
25 | "Received:",
26 | ` ${printReceived(element.ownerDocument.getElementById(activeId))}`,
27 | ].join("\n");
28 | }
29 | return result.message();
30 | },
31 | };
32 | }
33 |
34 | expect.extend({ ...matchers, ...axeMatchers, toHaveFocus });
35 |
--------------------------------------------------------------------------------
/src/tag/stories/TagStack.stories.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentMeta, ComponentStoryObj } from "@storybook/react";
2 |
3 | import { createControls, createPreviewTabs } from "../../../.storybook/utils";
4 |
5 | import js from "./templates/TagStackJsx";
6 | import ts from "./templates/TagStackTsx";
7 | import { TagStack } from "./TagStack.component";
8 |
9 | type Meta = ComponentMeta;
10 | type Story = ComponentStoryObj;
11 |
12 | export default {
13 | title: "Primitives/Tag/Stack",
14 | component: TagStack,
15 | parameters: {
16 | layout: "centered",
17 | options: { showPanel: true, panelPosition: "right" },
18 | preview: createPreviewTabs({ js, ts }),
19 | },
20 | argTypes: createControls("tag", {
21 | ignore: [
22 | "__TYPE__",
23 | "wrapElement",
24 | "as",
25 | "ref",
26 | "autoFocus",
27 | "focusable",
28 | "accessibleWhenDisabled",
29 | "onFocusVisible",
30 | "clickOnEnter",
31 | "clickOnSpace",
32 | "size",
33 | "themeColor",
34 | "variant",
35 | "prefix",
36 | "suffix",
37 | "closable",
38 | ],
39 | }),
40 | } as Meta;
41 |
42 | export const Stack: Story = {};
43 |
--------------------------------------------------------------------------------
/tailwind-utils/utilities.js:
--------------------------------------------------------------------------------
1 | const plugin = require("tailwindcss/plugin");
2 |
3 | const utilities = plugin(function ({ addUtilities, theme }) {
4 | const utilities = {
5 | ".collapse-border > :first-of-type:not(:last-of-type)": {
6 | "border-top-right-radius": "0px",
7 | "border-bottom-right-radius": "0px",
8 | },
9 | ".collapse-border > :not(:first-of-type):not(:last-of-type)": {
10 | "border-radius": "0px",
11 | "margin-left": "-1px",
12 | },
13 | ".collapse-border > :not(:first-of-type):last-of-type": {
14 | "border-top-left-radius": "0px",
15 | "border-bottom-left-radius": "0px",
16 | "margin-left": "-1px",
17 | },
18 | ".meter-radius > :first-of-type:not(:last-of-type)": {
19 | "border-top-right-radius": "0px",
20 | "border-bottom-right-radius": "0px",
21 | },
22 | ".meter-radius > :not(:first-of-type):not(:last-of-type)": {
23 | "border-radius": "0px",
24 | },
25 | ".meter-radius > :not(:first-of-type):last-of-type": {
26 | "border-top-left-radius": "0px",
27 | "border-bottom-left-radius": "0px",
28 | },
29 | };
30 |
31 | addUtilities(utilities);
32 | });
33 |
34 | module.exports = utilities;
35 |
--------------------------------------------------------------------------------
/.all-contributorsrc:
--------------------------------------------------------------------------------
1 | {
2 | "projectName": "@adaptui/react-tailwind",
3 | "projectOwner": "hello@timeless.co",
4 | "repoType": "github",
5 | "repoHost": "https://github.com",
6 | "files": [
7 | "README.md"
8 | ],
9 | "imageSize": 100,
10 | "commit": true,
11 | "commitConvention": "angular",
12 | "contributors": [
13 | {
14 | "login": "navin-moorthy",
15 | "name": "Navin Moorthy",
16 | "avatar_url": "https://avatars.githubusercontent.com/u/39694575?v=4",
17 | "profile": "https://navinmoorthy.me/",
18 | "contributions": [
19 | "code"
20 | ]
21 | },
22 | {
23 | "login": "anuraghazra",
24 | "name": "Anurag Hazra",
25 | "avatar_url": "https://avatars.githubusercontent.com/u/35374649?v=4",
26 | "profile": "https://anuraghazra.github.io/",
27 | "contributions": [
28 | "code"
29 | ]
30 | },
31 | {
32 | "login": "mcnaveen",
33 | "name": "MC Naveen",
34 | "avatar_url": "https://avatars.githubusercontent.com/u/8493007?v=4",
35 | "profile": "https://github.com/mcnaveen",
36 | "contributions": [
37 | "code"
38 | ]
39 | }
40 | ],
41 | "contributorsPerLine": 7
42 | }
43 |
--------------------------------------------------------------------------------
/src/radio-group/stories/RadioGroupBasic.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { Radio, RadioGroup, RadioGroupProps } from "../../index";
4 |
5 | export type RadioGroupBasicProps = RadioGroupProps & {};
6 |
7 | export const RadioGroupBasic: React.FC = props => {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | );
26 | };
27 |
28 | export default RadioGroupBasic;
29 |
--------------------------------------------------------------------------------
/src/show-more/ShowMoreContent.tsx:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 | import {
4 | DisclosureCollapsibleContentOptions,
5 | useDisclosureCollapsibleContent,
6 | } from "@adaptui/react";
7 |
8 | import { BoxOptions, useBox } from "../box";
9 | import { createComponent } from "../utils";
10 |
11 | import { ShowMoreUIProps } from "./ShowMoreProps";
12 |
13 | export const useShowMoreContent = createHook(
14 | ({ state, button, ...props }) => {
15 | props = useDisclosureCollapsibleContent({ state, ...props });
16 | props = useBox(props);
17 |
18 | return props;
19 | },
20 | );
21 |
22 | export const ShowMoreContent = createComponent(
23 | props => {
24 | const htmlProps = useShowMoreContent(props);
25 |
26 | return createElement("div", htmlProps);
27 | },
28 | "ShowMoreContent",
29 | );
30 |
31 | export type ShowMoreContentOptions = BoxOptions &
32 | DisclosureCollapsibleContentOptions &
33 | Partial & {};
34 |
35 | export type ShowMoreContentProps = Props<
36 | ShowMoreContentOptions
37 | >;
38 |
--------------------------------------------------------------------------------
/src/radio-group/RadioGroupUIState.tsx:
--------------------------------------------------------------------------------
1 | export const useRadioGroupUIState = (
2 | props: RadioGroupUIStateProps,
3 | ): RadioGroupUIState => {
4 | const {
5 | size = "md",
6 | stack = "vertical",
7 | themeColor = "base",
8 | maxVisibleItems = null,
9 | } = props;
10 |
11 | return {
12 | size,
13 | themeColor,
14 | stack,
15 | maxVisibleItems,
16 | };
17 | };
18 |
19 | export type RadioGroupUIState = {
20 | /**
21 | * How large should the button be?
22 | *
23 | * @default md
24 | */
25 | size: keyof AdaptUI.GetThemeValue<"radio", "size">;
26 |
27 | /**
28 | * How the radio should be themed?
29 | *
30 | * @default base
31 | */
32 | themeColor: keyof AdaptUI.GetThemeValue<"radio", "themeColor">;
33 |
34 | /**
35 | * Controls how the group of radios are arranged
36 | *
37 | * @default vertical
38 | */
39 | stack: "vertical" | "horizontal";
40 |
41 | /**
42 | * Informs the Radio Group & Radio that Show More is used.
43 | *
44 | * @default null
45 | */
46 | maxVisibleItems: number | null;
47 | };
48 |
49 | export type RadioGroupUIStateProps = Partial<
50 | Pick
51 | >;
52 |
--------------------------------------------------------------------------------
/src/icons/EyesIcon.tsx:
--------------------------------------------------------------------------------
1 | import { createIcon } from "../create-icon";
2 |
3 | export const EyeOpen = createIcon({
4 | displayName: "EyeOpen",
5 | defaultProps: {
6 | fill: "none",
7 | strokeWidth: 2,
8 | strokeLinecap: "round",
9 | strokeLinejoin: "round",
10 | stroke: "#000",
11 | },
12 | viewBox: "0 0 24 24",
13 | path: (
14 | <>
15 |
19 |
20 | >
21 | ),
22 | });
23 |
24 | export const EyeClose = createIcon({
25 | displayName: "EyeOpen",
26 | defaultProps: {
27 | fill: "none",
28 | strokeWidth: 2,
29 | strokeLinecap: "round",
30 | strokeLinejoin: "round",
31 | stroke: "#000",
32 | },
33 | viewBox: "0 0 24 24",
34 | path: (
35 | <>
36 |
40 |
41 | >
42 | ),
43 | });
44 |
--------------------------------------------------------------------------------
/src/theme/defaultTheme/circularProgress.ts:
--------------------------------------------------------------------------------
1 | export const circularProgress = {
2 | wrapper: "relative inline-flex w-fit",
3 | size: {
4 | sm: {
5 | barWrapper: { base: "w-3.5 h-3.5", hint: " w-11 h-11" },
6 | hint: "text-xs font-medium",
7 | },
8 | md: {
9 | barWrapper: { base: "w-4 h-4", hint: " w-14 h-14" },
10 | hint: "text-sm font-medium",
11 | },
12 | lg: {
13 | barWrapper: { base: "w-5 h-5", hint: " w-16 h-16" },
14 | hint: "text-base font-medium",
15 | },
16 | xl: {
17 | barWrapper: { base: "w-7 h-7", hint: " w-20 h-20" },
18 | hint: "text-xl font-medium",
19 | },
20 | },
21 | themeColor: {
22 | base: {
23 | bar: "text-gray-900",
24 | track: "text-gray-100",
25 | hint: "text-gray-900",
26 | },
27 | primary: {
28 | bar: "text-blue-600",
29 | track: "text-blue-100",
30 | hint: "text-gray-900",
31 | },
32 | },
33 | barWrapper: {
34 | base: "",
35 | indeterminate: "animate-spin",
36 | },
37 | track: "",
38 | bar: {
39 | base: "transition-all",
40 | indeterminate: "animate-circularProgress",
41 | },
42 | hint: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 ",
43 | };
44 |
--------------------------------------------------------------------------------
/src/tooltip/TooltipPrefix.tsx:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 |
4 | import { BoxOptions, useBox } from "../box";
5 | import { useTheme } from "../theme";
6 | import { createComponent, cx } from "../utils";
7 |
8 | import { TooltipUIProps } from "./TooltipProps";
9 |
10 | export const useTooltipPrefix = createHook(
11 | ({
12 | state,
13 | anchor,
14 | content,
15 | withArrow,
16 | prefix,
17 | suffix,
18 | isDragging,
19 | ...props
20 | }) => {
21 | const theme = useTheme("tooltip");
22 | const className = cx(theme.prefix, props.className);
23 |
24 | props = { ...props, className };
25 | props = useBox(props);
26 | return props;
27 | },
28 | );
29 |
30 | export const TooltipPrefix = createComponent(props => {
31 | const htmlProps = useTooltipPrefix(props);
32 |
33 | return createElement("div", htmlProps);
34 | }, "TooltipPrefix");
35 |
36 | export type TooltipPrefixOptions = BoxOptions &
37 | Partial & {};
38 |
39 | export type TooltipPrefixProps = Props<
40 | TooltipPrefixOptions
41 | >;
42 |
--------------------------------------------------------------------------------
/src/tooltip/TooltipSuffix.tsx:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 |
4 | import { BoxOptions, useBox } from "../box";
5 | import { useTheme } from "../theme";
6 | import { createComponent, cx } from "../utils";
7 |
8 | import { TooltipUIProps } from "./TooltipProps";
9 |
10 | export const useTooltipSuffix = createHook(
11 | ({
12 | state,
13 | anchor,
14 | content,
15 | withArrow,
16 | prefix,
17 | suffix,
18 | isDragging,
19 | ...props
20 | }) => {
21 | const theme = useTheme("tooltip");
22 | const className = cx(theme.suffix, props.className);
23 |
24 | props = { ...props, className };
25 | props = useBox(props);
26 | return props;
27 | },
28 | );
29 |
30 | export const TooltipSuffix = createComponent(props => {
31 | const htmlProps = useTooltipSuffix(props);
32 |
33 | return createElement("div", htmlProps);
34 | }, "TooltipSuffix");
35 |
36 | export type TooltipSuffixOptions = BoxOptions &
37 | Partial & {};
38 |
39 | export type TooltipSuffixProps = Props<
40 | TooltipSuffixOptions
41 | >;
42 |
--------------------------------------------------------------------------------
/src/button/stories/ButtonStack.stories.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentMeta, ComponentStoryObj } from "@storybook/react";
2 |
3 | import { createControls, createPreviewTabs } from "../../../.storybook/utils";
4 |
5 | import js from "./templates/ButtonStackJsx";
6 | import ts from "./templates/ButtonStackTsx";
7 | import { ButtonStack } from "./ButtonStack.component";
8 |
9 | type Meta = ComponentMeta;
10 | type Story = ComponentStoryObj;
11 |
12 | export default {
13 | title: "Primitives/Button/Stack",
14 | component: ButtonStack,
15 | parameters: {
16 | layout: "centered",
17 | options: { showPanel: true, panelPosition: "right" },
18 | preview: createPreviewTabs({ js, ts }),
19 | },
20 | argTypes: createControls("button", {
21 | ignore: [
22 | "__TYPE__",
23 | "wrapElement",
24 | "as",
25 | "ref",
26 | "autoFocus",
27 | "focusable",
28 | "accessibleWhenDisabled",
29 | "onFocusVisible",
30 | "clickOnEnter",
31 | "clickOnSpace",
32 | "size",
33 | "themeColor",
34 | "variant",
35 | "prefix",
36 | "suffix",
37 | "iconOnly",
38 | "spinner",
39 | ],
40 | }),
41 | } as Meta;
42 |
43 | export const Stack: Story = {};
44 |
--------------------------------------------------------------------------------
/src/theme/defaultTheme/spinner.ts:
--------------------------------------------------------------------------------
1 | export const spinner = {
2 | base: "inline-block animate-spin",
3 | size: {
4 | xs: "h-3 w-3 border-[1.5px] border-solid rounded-full",
5 | sm: "h-3.5 w-3.5 border-[1.5px] border-solid rounded-full",
6 | md: "h-4 w-4 border-[1.5px] border-solid rounded-full",
7 | lg: "h-5 w-5 border-[1.5px] border-solid rounded-full",
8 | em: "h-[1em] w-[1em] border-[1.5px] border-solid rounded-full",
9 | },
10 | themeColor: {
11 | base: "text-gray-800 border-current",
12 | primary: "text-blue-800 border-current",
13 | secondary: "text-violet-800 border-current",
14 | success: "text-green-800 border-current",
15 | danger: "text-red-800 border-current",
16 | current: "text-current border-current",
17 | },
18 | track: {
19 | visible: {
20 | base: "border-b-gray-400 border-l-gray-400",
21 | primary: "border-b-blue-400 border-l-blue-400",
22 | secondary: "border-b-violet-400 border-l-violet-400",
23 | success: "border-b-green-400 border-l-green-400",
24 | danger: "border-b-red-400 border-l-red-400",
25 | current: "border-b-gray-400 border-l-gray-400",
26 | },
27 | transparent: "border-b-transparent border-l-transparent",
28 | },
29 | label: "sr-only",
30 | };
31 |
--------------------------------------------------------------------------------
/src/icons/TypingSmallStatus.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Box, BoxProps } from "../box";
4 |
5 | export type TypingSmallStatusProps = React.SVGProps & BoxProps & {};
6 |
7 | export const TypingSmallStatusIcon = React.forwardRef<
8 | HTMLOrSVGElement,
9 | TypingSmallStatusProps
10 | >((props, ref) => {
11 | return (
12 |
13 | {props => (
14 |
41 | )}
42 |
43 | );
44 | });
45 |
--------------------------------------------------------------------------------
/src/progress/ProgressHint.tsx:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 |
4 | import { BoxOptions, useBox } from "../box";
5 | import { useTheme } from "../theme";
6 | import { createComponent, cx } from "../utils";
7 |
8 | import { ProgressUIProps } from "./ProgressProps";
9 |
10 | export const useProgressHint = createHook(
11 | ({ state, size, themeColor, label, hint, ...props }) => {
12 | const theme = useTheme("progress");
13 | const className = cx(
14 | theme.hint,
15 | size ? theme.size[size]?.hint : "",
16 | themeColor ? theme.themeColor[themeColor]?.hint : "",
17 | props.className,
18 | );
19 |
20 | props = { ...props, className };
21 | props = useBox(props);
22 |
23 | return props;
24 | },
25 | );
26 |
27 | export const ProgressHint = createComponent(props => {
28 | const htmlProps = useProgressHint(props);
29 |
30 | return createElement("div", htmlProps);
31 | }, "ProgressHint");
32 |
33 | export type ProgressHintOptions = BoxOptions &
34 | Partial & {};
35 |
36 | export type ProgressHintProps = Props<
37 | ProgressHintOptions
38 | >;
39 |
--------------------------------------------------------------------------------
/src/radio/Radio.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { RadioDescription } from "./RadioDescription";
4 | import { RadioIcon } from "./RadioIcon";
5 | import { RadioInput } from "./RadioInput";
6 | import { RadioLabel } from "./RadioLabel";
7 | import { RadioProps, useRadioProps } from "./RadioProps";
8 | import { RadioText } from "./RadioText";
9 | import { RadioTextWrapper } from "./RadioTextWrapper";
10 |
11 | export const Radio = React.forwardRef(
12 | (props, ref) => {
13 | const {
14 | labelProps,
15 | inputProps,
16 | iconProps,
17 | textWrapperProps,
18 | textProps,
19 | descriptionProps,
20 | uiProps,
21 | } = useRadioProps(props);
22 | const { label, description } = uiProps;
23 |
24 | return (
25 |
26 |
27 |
28 |
29 | {label ? : null}
30 | {label && description ? (
31 |
32 | ) : null}
33 |
34 |
35 | );
36 | },
37 | );
38 |
39 | Radio.displayName = "Radio";
40 |
--------------------------------------------------------------------------------
/src/button/stories/ButtonLoadingA11y.stories.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentMeta, ComponentStoryObj } from "@storybook/react";
2 |
3 | import { createControls, createPreviewTabs } from "../../../.storybook/utils";
4 |
5 | import js from "./templates/ButtonLoadingA11yJsx";
6 | import ts from "./templates/ButtonLoadingA11yTsx";
7 | import { ButtonLoadingA11y } from "./ButtonLoadingA11y.component";
8 |
9 | type Meta = ComponentMeta;
10 | type Story = ComponentStoryObj;
11 |
12 | export default {
13 | title: "Primitives/Button/LoadingAlly",
14 | component: ButtonLoadingA11y,
15 | argTypes: createControls("button", {
16 | ignore: [
17 | "__TYPE__",
18 | "wrapElement",
19 | "as",
20 | "ref",
21 | "autoFocus",
22 | "focusable",
23 | "accessibleWhenDisabled",
24 | "onFocusVisible",
25 | "clickOnEnter",
26 | "clickOnSpace",
27 | "size",
28 | "themeColor",
29 | "variant",
30 | "prefix",
31 | "suffix",
32 | "iconOnly",
33 | "spinner",
34 | ],
35 | }),
36 | parameters: {
37 | layout: "centered",
38 | options: { showPanel: false },
39 | preview: createPreviewTabs({ js, ts }),
40 | },
41 | } as Meta;
42 |
43 | export const LoadingAlly: Story = {};
44 |
--------------------------------------------------------------------------------
/src/checkbox-group/CheckboxGroupUIState.tsx:
--------------------------------------------------------------------------------
1 | export const useCheckboxGroupUIState = (
2 | props: CheckboxGroupUIStateProps,
3 | ): CheckboxGroupUIState => {
4 | const {
5 | size = "md",
6 | themeColor = "base",
7 | stack = "vertical",
8 | maxVisibleItems = null,
9 | } = props;
10 |
11 | return {
12 | size,
13 | themeColor,
14 | stack,
15 | maxVisibleItems,
16 | };
17 | };
18 |
19 | export type CheckboxGroupUIState = {
20 | /**
21 | * How large should the checkbox be?
22 | *
23 | * @default md
24 | */
25 | size: keyof AdaptUI.GetThemeValue<"checkbox", "size">;
26 |
27 | /**
28 | * How the checkbox should be themed?
29 | *
30 | * @default base
31 | */
32 | themeColor: keyof AdaptUI.GetThemeValue<"checkbox", "themeColor">;
33 |
34 | /**
35 | * Controls how the group of checkboxs are arranged
36 | *
37 | * @default vertical
38 | */
39 | stack: "vertical" | "horizontal";
40 |
41 | /**
42 | * Informs the Checkbox Group & Checkbox that Show More is used.
43 | *
44 | * @default null
45 | */
46 | maxVisibleItems: number | null;
47 | };
48 |
49 | export type CheckboxGroupUIStateProps = Partial<
50 | Pick<
51 | CheckboxGroupUIState,
52 | "size" | "stack" | "maxVisibleItems" | "themeColor"
53 | >
54 | >;
55 |
--------------------------------------------------------------------------------
/src/progress/ProgressTrack.tsx:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 |
4 | import { BoxOptions, useBox } from "../box";
5 | import { useTheme } from "../theme";
6 | import { createComponent, cx } from "../utils";
7 |
8 | import { ProgressUIProps } from "./ProgressProps";
9 |
10 | export const useProgressTrack = createHook(
11 | ({ state, size, themeColor, label, hint, ...props }) => {
12 | const theme = useTheme("progress");
13 | const className = cx(
14 | theme.track,
15 | size ? theme.size[size]?.track : "",
16 | themeColor ? theme.themeColor[themeColor]?.track : "",
17 | props.className,
18 | );
19 |
20 | props = { ...props, className };
21 | props = useBox(props);
22 |
23 | return props;
24 | },
25 | );
26 |
27 | export const ProgressTrack = createComponent(props => {
28 | const htmlProps = useProgressTrack(props);
29 |
30 | return createElement("div", htmlProps);
31 | }, "ProgressTrack");
32 |
33 | export type ProgressTrackOptions = BoxOptions &
34 | Partial & {};
35 |
36 | export type ProgressTrackProps = Props<
37 | ProgressTrackOptions
38 | >;
39 |
--------------------------------------------------------------------------------
/src/theme/defaultTheme/index.ts:
--------------------------------------------------------------------------------
1 | import { avatar } from "./avatar";
2 | import { badge } from "./badge";
3 | import { button } from "./button";
4 | import { buttonGroup } from "./buttonGroup";
5 | import { checkbox } from "./checkbox";
6 | import { checkboxGroup } from "./checkboxGroup";
7 | import { circularProgress } from "./circularProgress";
8 | import { divider } from "./divider";
9 | import { icon } from "./icon";
10 | import { input } from "./input";
11 | import { meter } from "./meter";
12 | import { progress } from "./progress";
13 | import { radio } from "./radio";
14 | import { radioGroup } from "./radioGroup";
15 | import { select } from "./select";
16 | import { slider } from "./slider";
17 | import { spinner } from "./spinner";
18 | import { _switch } from "./switch";
19 | import { tag } from "./tag";
20 | import { textarea } from "./textarea";
21 | import { tooltip } from "./tooltip";
22 |
23 | export const theme = {
24 | avatar,
25 | badge,
26 | button,
27 | buttonGroup,
28 | divider,
29 | checkbox,
30 | checkboxGroup,
31 | circularProgress,
32 | icon,
33 | input,
34 | select,
35 | meter,
36 | progress,
37 | radio,
38 | radioGroup,
39 | slider,
40 | spinner,
41 | switch: _switch,
42 | tag,
43 | textarea,
44 | tooltip,
45 | };
46 |
47 | export default theme;
48 |
--------------------------------------------------------------------------------
/src/icons/Slot.tsx:
--------------------------------------------------------------------------------
1 | import { createIcon } from "../create-icon";
2 |
3 | export const SlotIcon = createIcon({
4 | displayName: "SlotIcon",
5 | viewBox: "0 0 12 12",
6 | path: (
7 |
13 | ),
14 | });
15 |
--------------------------------------------------------------------------------
/src/avatar/Avatar.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { AvatarIcon } from "./AvatarIcon";
4 | import { AvatarImage } from "./AvatarImage";
5 | import { AvatarInitials } from "./AvatarInitials";
6 | import { AvatarProps, useAvatarProps } from "./AvatarProps";
7 | import { AvatarStatusIndicator } from "./AvatarStatusIndicator";
8 | import { AvatarWrapper } from "./AvatarWrapper";
9 |
10 | export const Avatar = React.forwardRef(
11 | (props, ref) => {
12 | const {
13 | uiProps,
14 | wrapperProps,
15 | iconProps,
16 | initialsProps,
17 | imageProps,
18 | statusIndicatorProps,
19 | } = useAvatarProps(props);
20 | const { showFallback, initials, status } = uiProps;
21 |
22 | return (
23 |
24 | {showFallback ? (
25 | initials == null ? (
26 |
27 | ) : (
28 |
29 | )
30 | ) : (
31 |
32 | )}
33 | {status !== "none" ? (
34 |
35 | ) : null}
36 |
37 | );
38 | },
39 | );
40 |
41 | Avatar.displayName = "Avatar";
42 |
--------------------------------------------------------------------------------
/src/meter/MeterHint.tsx:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 |
4 | import { BoxOptions, useBox } from "../box";
5 | import { useTheme } from "../theme";
6 | import { createComponent, cx } from "../utils";
7 |
8 | import { MeterUIProps } from "./MeterProps";
9 |
10 | export const useMeterHint = createHook(
11 | ({
12 | state,
13 | size,
14 | themeColor,
15 | intervals,
16 | flatBorders,
17 | label,
18 | hint,
19 | ...props
20 | }) => {
21 | const theme = useTheme("meter");
22 | const className = cx(
23 | theme.hint,
24 | size ? theme.size[size]?.hint : "",
25 | themeColor ? theme.themeColor[themeColor]?.hint : "",
26 | props.className,
27 | );
28 |
29 | props = { ...props, className };
30 | props = useBox(props);
31 |
32 | return props;
33 | },
34 | );
35 |
36 | export const MeterHint = createComponent(props => {
37 | const htmlProps = useMeterHint(props);
38 |
39 | return createElement("div", htmlProps);
40 | }, "MeterHint");
41 |
42 | export type MeterHintOptions = BoxOptions &
43 | Partial & {};
44 |
45 | export type MeterHintProps = Props>;
46 |
--------------------------------------------------------------------------------
/src/slider/SliderThumbLabel.tsx:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 |
4 | import { BoxOptions, useBox } from "../box";
5 | import { useTheme } from "../theme";
6 | import { createComponent, cx } from "../utils";
7 |
8 | import { SliderThumbUIProps } from "./SliderThumbProps";
9 |
10 | export const useSliderThumbLabel = createHook(
11 | ({
12 | state,
13 | size,
14 | themeColor,
15 | knobIcon,
16 | tooltip,
17 | index,
18 | isDisabled,
19 | ...props
20 | }) => {
21 | const theme = useTheme("slider");
22 | const className = cx(theme.thumbLabel, props.className);
23 |
24 | props = { ...props, className };
25 | props = useBox(props);
26 |
27 | return props;
28 | },
29 | );
30 |
31 | export const SliderThumbLabel = createComponent(
32 | props => {
33 | const htmlProps = useSliderThumbLabel(props);
34 |
35 | return createElement("label", htmlProps);
36 | },
37 | "SliderThumbLabel",
38 | );
39 |
40 | export type SliderThumbLabelOptions = BoxOptions &
41 | Partial & {};
42 |
43 | export type SliderThumbLabelProps = Props<
44 | SliderThumbLabelOptions
45 | >;
46 |
--------------------------------------------------------------------------------
/src/meter/MeterTrack.tsx:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 |
4 | import { BoxOptions, useBox } from "../box";
5 | import { useTheme } from "../theme";
6 | import { createComponent, cx } from "../utils";
7 |
8 | import { MeterUIProps } from "./MeterProps";
9 |
10 | export const useMeterTrack = createHook(
11 | ({
12 | state,
13 | size,
14 | themeColor,
15 | intervals,
16 | flatBorders,
17 | label,
18 | hint,
19 | ...props
20 | }) => {
21 | const theme = useTheme("meter");
22 | const className = cx(
23 | theme.track,
24 | size ? theme.size[size]?.track : "",
25 | themeColor ? theme.themeColor[themeColor]?.track : "",
26 | props.className,
27 | );
28 |
29 | props = { ...props, className };
30 | props = useBox(props);
31 |
32 | return props;
33 | },
34 | );
35 |
36 | export const MeterTrack = createComponent(props => {
37 | const htmlProps = useMeterTrack(props);
38 |
39 | return createElement("div", htmlProps);
40 | }, "MeterTrack");
41 |
42 | export type MeterTrackOptions = BoxOptions &
43 | Partial & {};
44 |
45 | export type MeterTrackProps = Props>;
46 |
--------------------------------------------------------------------------------
/src/tooltip/TooltipUIState.tsx:
--------------------------------------------------------------------------------
1 | import { RenderProp } from "../utils";
2 |
3 | import { TooltipUIProps } from "./TooltipProps";
4 |
5 | export function useTooltipUIState(props: TooltipUIStateProps): TooltipUIState {
6 | const {
7 | anchor,
8 | content,
9 | prefix,
10 | suffix,
11 | withArrow = false,
12 | isDragging = false,
13 | } = props;
14 |
15 | return {
16 | anchor,
17 | content,
18 | prefix,
19 | suffix,
20 | withArrow,
21 | isDragging,
22 | };
23 | }
24 |
25 | export type TooltipUIState = {
26 | anchor: RenderProp & React.RefAttributes>;
27 | /**
28 | * Label for the Tooltip.
29 | */
30 | content: RenderProp;
31 |
32 | /**
33 | * Label for the Tooltip.
34 | */
35 | prefix: RenderProp;
36 |
37 | /**
38 | * Label for the Tooltip.
39 | */
40 | suffix: RenderProp;
41 |
42 | /**
43 | * If `true`, Tooltip will render an arrow.
44 | */
45 | withArrow: boolean;
46 |
47 | /**
48 | * If `true`, Tooltip will also render when dragged outside .
49 | */
50 | isDragging: boolean;
51 | };
52 |
53 | export type TooltipUIStateProps = Partial<
54 | Pick<
55 | TooltipUIState,
56 | "anchor" | "content" | "withArrow" | "prefix" | "suffix" | "isDragging"
57 | >
58 | >;
59 |
--------------------------------------------------------------------------------
/src/switch/Switch.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { cx } from "../utils";
4 |
5 | import { SwitchDescription } from "./SwitchDescription";
6 | import { SwitchIcon } from "./SwitchIcon";
7 | import { SwitchInput } from "./SwitchInput";
8 | import { SwitchLabel } from "./SwitchLabel";
9 | import { SwitchProps, useSwitchProps } from "./SwitchProps";
10 | import { SwitchText } from "./SwitchText";
11 |
12 | export const Switch = React.forwardRef(
13 | (props, ref) => {
14 | const {
15 | labelProps,
16 | inputProps,
17 | iconProps,
18 | textProps,
19 | descriptionProps,
20 | uiProps,
21 | } = useSwitchProps(props);
22 | const { label, description } = uiProps;
23 |
24 | return (
25 |
26 |
27 | {label && !description ? : null}
28 | {label && description ? (
29 |
30 |
31 |
32 |
33 | ) : null}
34 |
35 |
36 | );
37 | },
38 | );
39 |
40 | Switch.displayName = "Switch";
41 |
--------------------------------------------------------------------------------
/src/slider/SliderTrack.tsx:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 |
4 | import { BoxOptions, useBox } from "../box";
5 | import { useTheme } from "../theme";
6 | import { createComponent, cx } from "../utils";
7 |
8 | import { SliderUIProps } from "./SliderProps";
9 |
10 | export const useSliderTrack = createHook(
11 | ({
12 | state,
13 | range,
14 | size,
15 | themeColor,
16 | knobIcon,
17 | tooltip,
18 | isDisabled,
19 | ...props
20 | }) => {
21 | const theme = useTheme("slider");
22 | const className = cx(
23 | theme.track,
24 | size ? theme.size[size]?.track : "",
25 | themeColor ? theme.themeColor[themeColor]?.track : "",
26 | props.className,
27 | );
28 |
29 | props = { ...props, className };
30 | props = useBox(props);
31 |
32 | return props;
33 | },
34 | );
35 |
36 | export const SliderTrack = createComponent(props => {
37 | const htmlProps = useSliderTrack(props);
38 |
39 | return createElement("div", htmlProps);
40 | }, "SliderTrack");
41 |
42 | export type SliderTrackOptions = BoxOptions &
43 | Partial & {};
44 |
45 | export type SliderTrackProps = Props<
46 | SliderTrackOptions
47 | >;
48 |
--------------------------------------------------------------------------------
/src/checkbox/Checkbox.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { CheckboxDescription } from "./CheckboxDescription";
4 | import { CheckboxIcon } from "./CheckboxIcon";
5 | import { CheckboxInput } from "./CheckboxInput";
6 | import { CheckboxLabel } from "./CheckboxLabel";
7 | import { CheckboxProps, useCheckboxProps } from "./CheckboxProps";
8 | import { CheckboxText } from "./CheckboxText";
9 | import { CheckboxTextWrapper } from "./CheckboxTextWrapper";
10 |
11 | export const Checkbox = React.forwardRef(
12 | (props, ref) => {
13 | const {
14 | labelProps,
15 | inputProps,
16 | iconProps,
17 | textWrapperProps,
18 | textProps,
19 | descriptionProps,
20 | uiProps,
21 | } = useCheckboxProps(props);
22 | const { label, description } = uiProps;
23 |
24 | return (
25 |
26 |
27 |
28 |
29 | {label ? : null}
30 | {label && description ? (
31 |
32 | ) : null}
33 |
34 |
35 | );
36 | },
37 | );
38 |
39 | Checkbox.displayName = "Checkbox";
40 |
--------------------------------------------------------------------------------
/src/switch/SwitchInput.tsx:
--------------------------------------------------------------------------------
1 | import { CheckboxOptions, CheckboxProps, useCheckbox } from "ariakit";
2 | import { createElement, createHook } from "ariakit-utils/system";
3 | import { As, Props } from "ariakit-utils/types";
4 |
5 | import { BoxOptions, BoxProps, useBox } from "../box";
6 | import { useTheme } from "../theme";
7 | import { createComponent, cx } from "../utils";
8 |
9 | import { SwitchUIProps } from "./SwitchProps";
10 |
11 | export const useSwitchInput = createHook(
12 | ({ state, size, isChecked, icon, label, description, ...props }) => {
13 | const theme = useTheme("switch");
14 | const className = cx(theme.input, props.className);
15 |
16 | props = useCheckbox({ ...props, state }) as CheckboxProps;
17 | props = { ...props, className, role: "switch" };
18 | props = useBox(props as BoxProps) as CheckboxProps;
19 |
20 | return props;
21 | },
22 | );
23 |
24 | export const SwitchInput = createComponent(props => {
25 | const htmlProps = useSwitchInput(props);
26 |
27 | return createElement("input", htmlProps);
28 | }, "SwitchInput");
29 |
30 | export type SwitchInputOptions = BoxOptions &
31 | CheckboxOptions &
32 | Partial> & {};
33 |
34 | export type SwitchInputProps = Props<
35 | SwitchInputOptions
36 | >;
37 |
--------------------------------------------------------------------------------
/src/radio/RadioInput.tsx:
--------------------------------------------------------------------------------
1 | import { RadioOptions, RadioProps, useRadio } from "ariakit";
2 | import { createElement, createHook } from "ariakit-utils/system";
3 | import { As, Props } from "ariakit-utils/types";
4 |
5 | import { useBox } from "../box";
6 | import { useTheme } from "../theme";
7 | import { createComponent, cx } from "../utils";
8 |
9 | import { RadioUIProps } from "./RadioProps";
10 |
11 | export const useRadioInput = createHook(
12 | ({
13 | state,
14 | isChecked,
15 | size,
16 | themeColor,
17 | icon,
18 | label,
19 | description,
20 | stack,
21 | maxVisibleItems,
22 | ...props
23 | }) => {
24 | const theme = useTheme("radio");
25 | const className = cx(theme.input, props.className);
26 |
27 | props = { ...props, className };
28 | props = useRadio({ state, ...props }) as RadioProps;
29 | props = useBox(props) as RadioProps;
30 |
31 | return props;
32 | },
33 | );
34 |
35 | export const RadioInput = createComponent(props => {
36 | const htmlProps = useRadioInput(props);
37 |
38 | return createElement("input", htmlProps);
39 | }, "RadioInput");
40 |
41 | export type RadioInputOptions = RadioOptions &
42 | Partial & {};
43 |
44 | export type RadioInputProps = Props<
45 | RadioInputOptions
46 | >;
47 |
--------------------------------------------------------------------------------
/src/icons/stories/IconAll.component.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import {
4 | ActiveStatusIcon,
5 | AwayStatusIcon,
6 | CaretDownIcon,
7 | CaretLeftIcon,
8 | CaretRightIcon,
9 | CheckIcon,
10 | CircledCheckIcon,
11 | ClockIcon,
12 | CloseIcon,
13 | DashIcon,
14 | EqualsIcon,
15 | ErrorIcon,
16 | IconProps,
17 | SelectIcon,
18 | SleepStatusIcon,
19 | SlotIcon,
20 | TimelessIcon,
21 | TypingLargeStatusIcon,
22 | TypingSmallStatusIcon,
23 | UserIcon,
24 | } from "../../index";
25 |
26 | export type IconAllProps = IconProps & {};
27 |
28 | export const IconAll: React.FC = props => {
29 | return (
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | );
52 | };
53 |
54 | export default IconAll;
55 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "react-app",
4 | "react-app/jest",
5 | "plugin:prettier/recommended",
6 | "plugin:storybook/recommended"
7 | ],
8 | "plugins": ["simple-import-sort"],
9 | "rules": {
10 | "no-console": "off",
11 | "simple-import-sort/imports": [
12 | "error",
13 | {
14 | // https://github.com/lydell/eslint-plugin-simple-import-sort#custom-grouping
15 | "groups": [
16 | // Packages. `react` related packages come first.
17 | ["^react", "^ariakit", "^ariakit-utils", "^@adaptui/react", "^@?\\w"],
18 | // Parent imports. Put `..` last.
19 | ["^\\.\\.(?!/?$)", "^\\.\\./?$"],
20 | // Other relative imports. Put same-folder imports and `.` last.
21 | ["^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"],
22 | // Style imports.
23 | ["^.+\\.s?css$"]
24 | ]
25 | }
26 | ],
27 | "simple-import-sort/exports": "error",
28 | "import/first": "error",
29 | "import/newline-after-import": "error",
30 | "import/no-duplicates": "error",
31 | "react/jsx-uses-react": "off",
32 | "react/react-in-jsx-scope": "off",
33 | "testing-library/prefer-explicit-assert": ["error"],
34 | "testing-library/consistent-data-testid": [
35 | 2,
36 | {
37 | "testIdPattern": "^testid(-.*\\w)?$"
38 | }
39 | ]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/slider/SliderUIState.tsx:
--------------------------------------------------------------------------------
1 | import { RenderProp } from "../utils";
2 | import { SliderThumbUIProps } from "..";
3 |
4 | import { SliderUIProps } from "./SliderProps";
5 |
6 | export function useSliderUIState(props: SliderUIStateProps): SliderUIState {
7 | const {
8 | range = false,
9 | size = "md",
10 | themeColor = "base",
11 | tooltip = true,
12 | knobIcon,
13 | } = props;
14 |
15 | return {
16 | range,
17 | size,
18 | themeColor,
19 | knobIcon,
20 | tooltip,
21 | };
22 | }
23 |
24 | export type SliderUIState = {
25 | /**
26 | * How large should the button be?
27 | *
28 | * @default md
29 | */
30 | size: keyof AdaptUI.GetThemeValue<"slider", "size">;
31 |
32 | /**
33 | * How the slider should be themed?
34 | *
35 | * @default base
36 | */
37 | themeColor: keyof AdaptUI.GetThemeValue<"slider", "themeColor">;
38 |
39 | /**
40 | * True, if you need a range slider.
41 | */
42 | range: boolean;
43 |
44 | /**
45 | * True, if your slider needs a tooltip.
46 | */
47 | tooltip: boolean;
48 |
49 | /**
50 | * Provide custom icons as a replacement for the default ones.
51 | */
52 | knobIcon: RenderProp | RenderProp;
53 | };
54 |
55 | export type SliderUIStateProps = Partial<
56 | Pick
57 | > & {};
58 |
--------------------------------------------------------------------------------
/src/circular-progress/CircularProgress.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { CircularProgressBar } from "./CircularProgressBar";
4 | import { CircularProgressBarWrapper } from "./CircularProgressBarWrapper";
5 | import { CircularProgressHint } from "./CircularProgressHint";
6 | import {
7 | CircularProgressProps,
8 | useCircularProgressProps,
9 | } from "./CircularProgressProps";
10 | import { CircularProgressTrack } from "./CircularProgressTrack";
11 | import { CircularProgressWrapper } from "./CircularProgressWrapper";
12 |
13 | export const CircularProgress = React.forwardRef<
14 | HTMLDivElement,
15 | CircularProgressProps
16 | >((props, ref) => {
17 | const {
18 | wrapperProps,
19 | hintProps,
20 | barWrapperProps,
21 | trackProps,
22 | barProps,
23 | uiProps,
24 | } = useCircularProgressProps(props);
25 | const { hint, state } = uiProps;
26 |
27 | return (
28 |
29 | {hint && !state.isIndeterminate ? (
30 |
31 | ) : null}
32 |
33 |
34 |
35 |
36 |
37 | );
38 | });
39 |
40 | CircularProgress.displayName = "CircularProgress";
41 |
--------------------------------------------------------------------------------
/src/circular-progress/CircularProgressHint.ts:
--------------------------------------------------------------------------------
1 | import { createElement, createHook } from "ariakit-utils/system";
2 | import { As, Props } from "ariakit-utils/types";
3 |
4 | import { BoxOptions, useBox } from "../box";
5 | import { useTheme } from "../theme";
6 | import { createComponent, cx } from "../utils";
7 |
8 | import { CircularProgressUIProps } from "./CircularProgressProps";
9 |
10 | export const useCircularProgressHint = createHook(
11 | ({ state, size, themeColor, hint, ...props }) => {
12 | const theme = useTheme("circularProgress");
13 | const className = cx(
14 | theme.hint,
15 | size ? theme.size[size].hint : "",
16 | themeColor ? theme.themeColor[themeColor].hint : "",
17 | props.className,
18 | );
19 |
20 | props = { ...props, className };
21 | props = useBox(props);
22 |
23 | return props;
24 | },
25 | );
26 |
27 | export const CircularProgressHint =
28 | createComponent(props => {
29 | const htmlProps = useCircularProgressHint(props);
30 |
31 | return createElement("span", htmlProps);
32 | }, "CircularProgressHint");
33 |
34 | export type CircularProgressHintOptions = BoxOptions