From d1bd7551fad9b4975e2f5f4b63b5b1b82eb44bed Mon Sep 17 00:00:00 2001 From: alekseishmidko Date: Thu, 26 Feb 2026 13:34:54 +0700 Subject: [PATCH] =?UTF-8?q?feat:=20[EV-8830]=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE?= =?UTF-8?q?=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=BA=D0=B0=D1=81=D1=82?= =?UTF-8?q?=D0=BE=D0=BC=D0=B8=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D1=8D=D0=BB=D0=B5=D0=BC=D0=B5=D0=BD=D1=82=D1=8B=20?= =?UTF-8?q?=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/box/Box.stories.tsx | 111 ++++++++++++++++++++++++- src/components/box/Box.tsx | 10 ++- src/components/types.ts | 9 +- src/components/use-list-style/index.ts | 60 +++++++++++++ tailwind.config.ts | 13 +++ 5 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 src/components/use-list-style/index.ts diff --git a/src/components/box/Box.stories.tsx b/src/components/box/Box.stories.tsx index 85e0ccce..50063cb7 100644 --- a/src/components/box/Box.stories.tsx +++ b/src/components/box/Box.stories.tsx @@ -2,7 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import { forwardRef, useState } from "react"; import type { UIKitIndentations } from "~/components"; -import { Flex, UIKitProvider } from "~/components"; +import { Flex, Typography, UIKitProvider } from "~/components"; import { createTheme } from "~/components/ui-kit-provider/createTheme"; import { Box } from "./Box"; @@ -493,3 +493,112 @@ export const FromBottomAnimation: Story = { return ; }, }; + +export const ListWithDisc: Story = { + render() { + return ( + + {["list disc", "list disc", "list disc"].map((item, index) => ( + + {item} + + ))} + + ); + }, +}; +export const ListWithDecimal: Story = { + render() { + return ( + + {["list decimal", "list decimal", "list decimal"].map((item, index) => ( + + {item} + + ))} + + ); + }, +}; +export const ListWithPositionExample: Story = { + render() { + return ( +
+ + {["list inside", "list inside", "list inside"].map((item, index) => ( + + {item} + + ))} + +
+ + {["list outside", "list outside", "list outside"].map( + (item, index) => ( + + {item} + + ), + )} + +
+ ); + }, +}; +export const CustomList: Story = { + render() { + return ( + + {["CustomList", "CustomList", "CustomList"].map((item, index) => ( + + {item} + + ))} + + ); + }, +}; diff --git a/src/components/box/Box.tsx b/src/components/box/Box.tsx index 82f55358..96ae388c 100644 --- a/src/components/box/Box.tsx +++ b/src/components/box/Box.tsx @@ -12,6 +12,7 @@ import { useAnimation } from "~/components/use-animation"; import { useBorder } from "~/components/use-border"; import { useCssEffects } from "~/components/use-css-effects"; import { useCursor } from "~/components/use-cursor"; +import { useListStyle } from "~/components/use-list-style"; import { useOutline } from "~/components/use-outline"; import { useResolvedAttributes } from "~/components/use-resolved-attributes"; @@ -26,6 +27,7 @@ import type { UiKitDisplayProps, UiKitEffectProps, UIKitIndentationsProps, + UiKitListStyleProps, UiKitOutlineProps, UiKitPositionProps, UiKitTypographyProps, @@ -46,6 +48,7 @@ export type DefaultProps = Partial< UiKitEffectProps & UiKitAnimationProps & UiKitCursorProps & + UiKitListStyleProps & UiKitDataAttributesProps & UiKitTypographyProps & { border?: UiKitBorderProps } & Omit< UiKitBackgroundProps, @@ -190,6 +193,10 @@ export const Box = forwardRef( }); // cursor const cursor = useCursor({ m: rest, md, d }); + + // list style + const listStyle = useListStyle({ m: rest, md, d }); + const resolvedProps = useResolvedAttributes(rest); const Root = as ?? "div"; return ( @@ -203,7 +210,7 @@ export const Box = forwardRef( className={ `${display.classNames} ${effects.className} ${outline.className} ${border.className} ` + `${spacing.className} ${positionStyles.className} ${background.className} ` + - `${dimension.className} ${typography.classNames} ${groupParent ? "group" : ""} ${cursor.className} ${animation.className} ${className ?? ""}` + `${dimension.className} ${typography.classNames} ${groupParent ? "group" : ""} ${cursor.className} ${listStyle.className} ${animation.className} ${className ?? ""}` } onClick={(e) => { onClick?.(e); @@ -218,6 +225,7 @@ export const Box = forwardRef( ...typography.styles, ...effects.style, ...cursor.style, + ...listStyle.style, ...animation.style, ...(rest.style as object), }} diff --git a/src/components/types.ts b/src/components/types.ts index c48cb0ae..04e7c4b6 100644 --- a/src/components/types.ts +++ b/src/components/types.ts @@ -257,7 +257,8 @@ export type UiKitDisplayProps = { | "table" | "table-cell" | "grid" - | "table-row"; + | "table-row" + | "list-item"; }; export type UiKitTypographyProps = { @@ -319,6 +320,12 @@ export type UiKitOutlineProps = { outlineOffset?: string; outlineStyle?: "none" | "solid" | "dashed" | "dotted" | "double"; }; +export type UiKitListStyleProps = { + listStyle?: { + position?: "inside" | "outside"; + type?: "none" | "disc" | "decimal"; + }; +}; export type UiKitCursorProps = { cursor?: diff --git a/src/components/use-list-style/index.ts b/src/components/use-list-style/index.ts new file mode 100644 index 00000000..3c1fcf42 --- /dev/null +++ b/src/components/use-list-style/index.ts @@ -0,0 +1,60 @@ +import type { UiKitListStyleProps } from "~/components"; + +type UseListStyleBaseProps = { + m?: UiKitListStyleProps; + md?: UiKitListStyleProps; + d?: UiKitListStyleProps; +}; + +type UseListStyleProps = UseListStyleBaseProps; + +type UseListStyleOutput = { + style?: Record; + className?: string; +}; + +export const useListStyle = (props: UseListStyleProps): UseListStyleOutput => { + let className = ""; + const style: UseListStyleOutput["style"] = {}; + + // type + if (props.m?.listStyle?.type) { + className += `list-${props.m.listStyle.type} `; + } + const mdType = props.md?.listStyle?.type ?? props.m?.listStyle?.type; + if ( + props.md?.listStyle?.type && + props.md.listStyle.type !== props.m?.listStyle?.type + ) { + className += `md:list-${props.md.listStyle.type} `; + } + if (props.d?.listStyle?.type && props.d.listStyle.type !== mdType) { + className += `lg:list-${props.d.listStyle.type} `; + } + + // position + if (props.m?.listStyle?.position) { + className += `list-${props.m.listStyle.position} `; + } + const mdPosition = + props.md?.listStyle?.position ?? props.m?.listStyle?.position; + if ( + props.md?.listStyle?.position && + props.md.listStyle?.position !== props.m?.listStyle?.position + ) { + className += `md:list-${props.md.listStyle.position} `; + } + if ( + props.d?.listStyle?.position && + props.d.listStyle.position !== mdPosition + ) { + className += `lg:list-${props.d.listStyle.position} `; + } + + // --------------------------------------------------------------------------- + + return { + className: className.trim(), + style, + }; +}; diff --git a/tailwind.config.ts b/tailwind.config.ts index abf190de..2b61a8a4 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -123,6 +123,18 @@ const generateCursorClasses = (): Array => { const dCursors = initialCursors.map((cursor) => `lg:${cursor}`); return initialCursors.concat(mdCursors).concat(dCursors); }; +const generateListStyleClasses = (): Array => { + const initialListStyle = [ + "list-none", + "list-disc", + "list-decimal", + "list-inside", + "list-outside", + ]; + const mdListStyles = initialListStyle.map((item) => `md:${item}`); + const dListStyles = initialListStyle.map((item) => `lg:${item}`); + return initialListStyle.concat(mdListStyles).concat(dListStyles); +}; const generateFlex = (): Array => { return [ "gap-[var(--gap)]", @@ -636,6 +648,7 @@ export default { ...generateTypography(), ...generateEffectClasses(), ...generateCursorClasses(), + ...generateListStyleClasses(), ...generateAnimationClasses(), ], theme: {