diff --git a/packages/react-component-manifests/src/manifests/Accordion/Accordion.manifest.ts b/packages/react-component-manifests/src/manifests/Accordion/Accordion.manifest.ts index 5f9cd8f99..0ece9c3f1 100644 --- a/packages/react-component-manifests/src/manifests/Accordion/Accordion.manifest.ts +++ b/packages/react-component-manifests/src/manifests/Accordion/Accordion.manifest.ts @@ -33,15 +33,15 @@ const customTreeOptions: CustomPropsTreeOptions = { collapse: { type: "boolean" }, bordered: { type: "boolean" }, ghost: { type: "boolean" }, - defaultActiveKey: { type: "array_number" }, + defaultActiveKey: { type: "array" }, expandIcon: { type: "static_asset" }, - items: { type: "array_map", singleObjectName: "item", attributes: [ { fieldName: "title", type: "text" }, { fieldName: "description", type: "text" }, + { fieldName: "key", type: "text" }, { fieldName: "collapsible", type: "enum", @@ -71,6 +71,7 @@ const compManifest: ReactComponentManifestSchema = { { title: `One`, description: `Content of Accordion 1`, + key: "1", collapsible: "header", showArrow: true, }, diff --git a/packages/react-component-manifests/src/manifests/Accordion/Accordion.tsx b/packages/react-component-manifests/src/manifests/Accordion/Accordion.tsx index 4720388db..0923f3e42 100644 --- a/packages/react-component-manifests/src/manifests/Accordion/Accordion.tsx +++ b/packages/react-component-manifests/src/manifests/Accordion/Accordion.tsx @@ -11,23 +11,21 @@ export type ExpandIconPosition = "start" | "end"; export type Size = "large" | "middle" | "small"; -export type AccordionItem = { - title: string; - description?: string; - key: string | number; - collapsible?: CollapsibleTypes; - showArrow?: boolean; -}; - const Accordion = forwardRef< HTMLDivElement, { styles: React.CSSProperties; custom: { - items: AccordionItem[]; + items: { + title: string; + description?: string; + collapsible?: CollapsibleTypes; + showArrow?: boolean; + key: string | number; + }[]; bordered?: boolean; collapse?: boolean; - defaultActiveKey?: string[] | string | number[] | number; + defaultActiveKey: string[] | string | number[] | number; expandIcon?: string; expandIconPosition?: ExpandIconPosition; ghost?: boolean; @@ -62,7 +60,7 @@ const Accordion = forwardRef< {props.custom?.items?.map((item, index) => ( diff --git a/packages/react-component-manifests/src/manifests/Menu/Menu.dev.tsx b/packages/react-component-manifests/src/manifests/Menu/Menu.dev.tsx new file mode 100644 index 000000000..30d5ce376 --- /dev/null +++ b/packages/react-component-manifests/src/manifests/Menu/Menu.dev.tsx @@ -0,0 +1,10 @@ +import { forwardRef } from "react"; +import Menu from "./Menu"; + +const DevMenu: typeof Menu = forwardRef((props, ref) => { + props.custom.items.forEach((item) => { + item.disabled = true; + }); + return ; +}); +export default DevMenu; diff --git a/packages/react-component-manifests/src/manifests/Menu/Menu.manifest.ts b/packages/react-component-manifests/src/manifests/Menu/Menu.manifest.ts index 33c18c576..69ab5fbfe 100644 --- a/packages/react-component-manifests/src/manifests/Menu/Menu.manifest.ts +++ b/packages/react-component-manifests/src/manifests/Menu/Menu.manifest.ts @@ -9,6 +9,7 @@ import CSSTreeId from "@atrilabs/app-design-forest/src/cssTree?id"; import CustomTreeId from "@atrilabs/app-design-forest/src/customPropsTree?id"; import { CSSTreeOptions } from "@atrilabs/app-design-forest"; import { CustomPropsTreeOptions } from "@atrilabs/app-design-forest"; +import Joi from "joi"; const acceptsChild: AcceptsChildFunction = (info: any) => { if (info.childCoordinates.length === 0) { @@ -33,13 +34,37 @@ const cssTreeOptions: CSSTreeOptions = { const customTreeOptions: CustomPropsTreeOptions = { dataTypes: { - open: { type: "boolean" }, - src: { type: "static_asset" }, - iconHeight: { type: "number" }, - iconWidth: { type: "number" }, - strokeColor: { type: "color" }, - gap: { type: "number" }, - alignRight: { type: "boolean" }, + mode: { + type: "enum", + options: ["vertical", "horizontal", "inline"], + }, + theme: { + type: "enum", + options: ["light", "dark"], + }, + multiple: { type: "boolean" }, + selectable: { type: "boolean" }, + selectedKeys: { type: "array" }, + defaultOpenKeys: { type: "array" }, + defaultSelectedKeys: { type: "array" }, + expandIcon: { type: "static_asset" }, + openKeys: { type: "array" }, + items: { + type: "json", + schema: Joi.array() + .unique() + .items( + Joi.object({ + key: Joi.string(), + label: Joi.string().required(), + disabled: Joi.boolean(), + icon: Joi.string(), + type: Joi.string(), + children: Joi.link("#menuData"), + }) + ) + .id("menuData"), + }, }, }; @@ -57,9 +82,54 @@ const compManifest: ReactComponentManifestSchema = { custom: { treeId: CustomTreeId, initialValue: { - open: true, - iconHeight: 24, - iconWidth: 24, + items: [ + { + label: "Navigation One", + key: "mail", + icon: "", + }, + { + label: "Navigation Two", + key: "app", + icon: "", + disabled: true, + }, + { + label: "Navigation Three - Submenu", + key: "SubMenu", + icon: "", + children: [ + { + type: "group", + label: "Item 1", + children: [ + { + label: "Option 1", + key: "setting:1", + }, + { + label: "Option 2", + key: "setting:2", + }, + ], + }, + { + type: "group", + label: "Item 2", + children: [ + { + label: "Option 3", + key: "setting:3", + }, + { + label: "Option 4", + key: "setting:4", + }, + ], + }, + ], + }, + ], }, treeOptions: customTreeOptions, canvasOptions: { groupByBreakpoint: false }, @@ -67,6 +137,8 @@ const compManifest: ReactComponentManifestSchema = { }, attachCallbacks: { onClick: [{ type: "controlled", selector: ["custom", "open"] }], + onOpenChange: [{ type: "controlled", selector: ["custom", "open"] }], + onSelect: [{ type: "controlled", selector: ["custom", "open"] }], }, defaultCallbackHandlers: {}, acceptsChild, diff --git a/packages/react-component-manifests/src/manifests/Menu/Menu.tsx b/packages/react-component-manifests/src/manifests/Menu/Menu.tsx index 41150054f..e284b2081 100644 --- a/packages/react-component-manifests/src/manifests/Menu/Menu.tsx +++ b/packages/react-component-manifests/src/manifests/Menu/Menu.tsx @@ -1,5 +1,16 @@ -import React, { forwardRef, useCallback } from "react"; -import { ReactComponent as MenuIcon } from "./menu.svg"; +import React, { forwardRef, useMemo } from "react"; +import type { MenuProps } from "antd"; +import { Menu as AntdMenu } from "antd"; +import { ItemType } from "antd/es/menu/hooks/useItems"; + +interface Item { + key?: number; + label: string; + icon?: string; + disabled?: boolean; + children?: ItemType[]; + type?: string; +} const Menu = forwardRef< HTMLDivElement, @@ -7,59 +18,58 @@ const Menu = forwardRef< styles: React.CSSProperties; children: React.ReactNode[]; custom: { - open: boolean; - iconHeight: number; - iconWidth: number; - src?: string; - strokeColor?: string; - gap?: number; - alignRight?: boolean; + items: Item[]; + mode: "vertical" | "horizontal" | "inline"; + theme: "light" | "dark"; + multiple?: boolean; + defaultOpenKeys?: string[]; + defaultSelectedKeys?: string[]; + expandIcon?: string; + openKeys?: string[]; + selectable?: boolean; + selectedKeys: string[]; }; - onClick: (open: boolean) => void; + onClick: Function; + onOpenChange: Function; + onSelect: Function; className?: string; - } + } & MenuProps >((props, ref) => { - const onClick = useCallback(() => { - props.onClick(!props.custom.open); - }, [props]); - const gap = typeof props.custom.gap === "number" ? props.custom.gap : 0; + const { custom } = props; + const { items } = custom; + + const menuItems = useMemo(() => { + return items.map((item: Item) => { + return { + ...item, + icon: {item?.icon}, + } as ItemType; + }); + }, [items]); + return ( -
-
- {props.custom.src ? ( - menu icon - ) : ( - - )} -
-
- {props.children} -
+
+ + ) + } + openKeys={props.custom.openKeys} + selectable={props.custom.selectable} + selectedKeys={props.custom.selectedKeys} + onClick={props.onClick} + onOpenChange={props.onOpenChange} + onSelect={props.onSelect} + theme={props.custom.theme} + />
); }); diff --git a/packages/react-component-manifests/src/manifests/Modal/Modal.dev.tsx b/packages/react-component-manifests/src/manifests/Modal/Modal.dev.tsx new file mode 100644 index 000000000..43cf7ede8 --- /dev/null +++ b/packages/react-component-manifests/src/manifests/Modal/Modal.dev.tsx @@ -0,0 +1,35 @@ +import Modal from "./Modal"; +import React, { useState } from "react"; +import { Button } from "antd"; + +const DevModal: typeof Modal = React.forwardRef((props, ref) => { + const [isModalOpen, setIsModalOpen] = useState(false); + + const showModal = () => { + setIsModalOpen(true); + }; + + const handleOk = () => { + setIsModalOpen(false); + }; + + const handleCancel = () => { + setIsModalOpen(false); + }; + + return ( +
+ + +
+ ); +}); + +export default DevModal; diff --git a/packages/react-component-manifests/src/manifests/Modal/Modal.manifest.ts b/packages/react-component-manifests/src/manifests/Modal/Modal.manifest.ts index 461df7af9..c6ba283f6 100644 --- a/packages/react-component-manifests/src/manifests/Modal/Modal.manifest.ts +++ b/packages/react-component-manifests/src/manifests/Modal/Modal.manifest.ts @@ -22,17 +22,20 @@ const cssTreeOptions: CSSTreeOptions = { const customTreeOptions: CustomPropsTreeOptions = { dataTypes: { - modalSize: { type: "text" }, - okButtonColor: { type: "color" }, - okButtonBgColor: { type: "color" }, - okButtonBorderColor: { type: "color" }, - cancelButtonColor: { type: "color" }, - cancelButtonBgColor: { type: "color" }, - cancelButtonBorderColor: { type: "color" }, - closeModalAfter: { type: "number" }, + text: { type: "text" }, + content: { type: "large_text" }, + cancelText: { type: "text" }, + okText: { type: "text" }, + centered: { type: "boolean" }, + icon: { type: "static_asset" }, + closable: { type: "boolean" }, + closeIcon: { type: "static_asset" }, + destroyOnClose: { type: "boolean" }, + keyboard: { type: "boolean" }, + mask: { type: "boolean" }, + maskClosable: { type: "boolean" }, + zIndex: { type: "number" }, open: { type: "boolean" }, - body: { type: "large_text" }, - title: { type: "text" }, }, }; @@ -50,16 +53,12 @@ const compManifest: ReactComponentManifestSchema = { custom: { treeId: CustomTreeId, initialValue: { - modalSize: "50%", - okButtonColor: "#fff", - okButtonBgColor: "#1890ff", - okButtonBorderColor: "#1890ff", - cancelButtonColor: "#000", - cancelButtonBgColor: "#fff", - cancelButtonBorderColor: "#d9d9d9", - open: true, - body: "Type something here!", - title: "Some Title", + text: "Modal Title", + content: "Modal content", + maskClosable: true, + closable: true, + keyboard: true, + mask: true, }, treeOptions: customTreeOptions, canvasOptions: { groupByBreakpoint: false }, diff --git a/packages/react-component-manifests/src/manifests/Modal/Modal.tsx b/packages/react-component-manifests/src/manifests/Modal/Modal.tsx index fbde408d3..3e4d9b147 100644 --- a/packages/react-component-manifests/src/manifests/Modal/Modal.tsx +++ b/packages/react-component-manifests/src/manifests/Modal/Modal.tsx @@ -1,150 +1,82 @@ -import React, { forwardRef, useEffect, useState } from "react"; +import React, { forwardRef } from "react"; +import { Modal as AntdModal } from "antd"; const Modal = forwardRef< HTMLDivElement, { styles: React.CSSProperties; custom: { - modalSize: string; - okButtonColor: string; - okButtonBgColor: string; - okButtonBorderColor: string; - cancelButtonColor: string; - cancelButtonBgColor: string; - cancelButtonBorderColor: string; - closeModalAfter?: number; - open: boolean; - body: string; - title: string; + text?: string; + content?: string; + cancelText?: string; + okText?: string; + centered?: boolean; + closable?: boolean; + destroyOnClose?: boolean; + keyboard?: boolean; + mask?: boolean; + maskClosable?: boolean; + zIndex?: number; + type?: "info" | "success" | "error" | "warning" | "confirm"; + icon?: string; + closeIcon?: string; + open?: boolean; }; - onClick: (buttonClicked: "OK" | "Cancel") => void; + onCancel?: Function; + onOk?: Function; + afterClose: Function; className?: string; } >((props, ref) => { - const [open, setOpen] = useState(props.custom.open); - useEffect(() => { - setOpen(props.custom.open); - }, [props.custom.open]); + const handleOk = () => { + if (props.onOk) { + props.onOk(); + } + }; - useEffect(() => { - if (props.custom.closeModalAfter && open) { - setTimeout(() => { - setOpen(false); - }, props.custom.closeModalAfter); + const handleCancel = () => { + if (props.onCancel) { + props.onCancel(); } - }, [props.custom.closeModalAfter, open]); + }; return ( -
-
-
-
- {props.custom.title} +
+ + {props.custom.icon && ( + {props.custom.icon} + )} + {props.custom.text}
- -
-
-

- {props.custom.body || - "This component is a work in progress. This component needs React Portal"} -

-
-
- - -
-
+ } + open={props.custom.open} + onOk={handleOk} + onCancel={handleCancel} + cancelText={props.custom.cancelText} + okText={props.custom.okText} + centered={props.custom.centered} + closable={props.custom.closable} + destroyOnClose={props.custom.destroyOnClose} + keyboard={props.custom.keyboard} + mask={props.custom.mask} + maskClosable={props.custom.maskClosable} + zIndex={props.custom.zIndex} + closeIcon={ + props.custom.closeIcon && ( + {props.custom.closeIcon} + ) + } + > + {props.custom.icon !== undefined || "" ? ( +
{props.custom.content}
+ ) : ( +

{props.custom.content}

+ )} +
); }); diff --git a/packages/react-component-manifests/src/manifests/Rating/Rating.manifest.ts b/packages/react-component-manifests/src/manifests/Rating/Rating.manifest.ts index 0f1a72b1f..4324abb94 100644 --- a/packages/react-component-manifests/src/manifests/Rating/Rating.manifest.ts +++ b/packages/react-component-manifests/src/manifests/Rating/Rating.manifest.ts @@ -22,8 +22,13 @@ const cssTreeOptions: CSSTreeOptions = { const customTreeOptions: CustomPropsTreeOptions = { dataTypes: { - total: { type: "number" }, - rating: { type: "number" }, + allowHalf: { type: "boolean" }, + defaultValue: { type: "number" }, + disabled: { type: "boolean" }, + allowClear: { type: "boolean" }, + character: { type: "text" }, + toolTipInfo: { type: "array" }, + count: { type: "number" }, }, }; const compManifest: ReactComponentManifestSchema = { @@ -40,10 +45,8 @@ const compManifest: ReactComponentManifestSchema = { custom: { treeId: CustomTreeId, initialValue: { - total: 5, - rating: 3.5, - unratedColor: "#C4C4C4", - ratedColor: "#E5CF00", + defaultValue: 4, + count: 5, }, treeOptions: customTreeOptions, canvasOptions: { groupByBreakpoint: false }, diff --git a/packages/react-component-manifests/src/manifests/Rating/Rating.tsx b/packages/react-component-manifests/src/manifests/Rating/Rating.tsx index 9bc697641..87220d48b 100644 --- a/packages/react-component-manifests/src/manifests/Rating/Rating.tsx +++ b/packages/react-component-manifests/src/manifests/Rating/Rating.tsx @@ -1,22 +1,38 @@ -import React, { forwardRef } from "react"; -import { RatingContainer } from "./RatingContainer"; - +import React, { forwardRef, ReactNode, useState } from "react"; +import { Rate } from "antd"; const Rating = forwardRef< HTMLDivElement, { styles: React.CSSProperties; custom: { - total: number; - rating: number; - unratedColor: string; - ratedColor: string; + allowHalf?: boolean; + defaultValue?: number; + disabled?: boolean; + allowClear?: boolean; + character?: ReactNode; + toolTipInfo?: string[]; + count?: number; }; className?: string; } >((props, ref) => { + + const { custom } = props; + const [value, setValue] = useState(props.custom.defaultValue); return ( -
- +
+ + {props.custom?.toolTipInfo && value + ? props.custom?.toolTipInfo[value - 1] + : ""}
); }); diff --git a/packages/react-component-manifests/src/manifests/Rating/RatingContainer.tsx b/packages/react-component-manifests/src/manifests/Rating/RatingContainer.tsx deleted file mode 100644 index af31194bf..000000000 --- a/packages/react-component-manifests/src/manifests/Rating/RatingContainer.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from "react"; -import { StarHalfRated, StarRated, StarUnrated } from "./components"; -export const RatingContainer: React.FC = ({ - total, - rating, - unratedColor, - ratedColor, -}) => { - const fullRatings = Math.floor(rating); - const halfRatings = Math.ceil(rating) - fullRatings; - const nonRatings = total - Math.ceil(rating); - const fullRatingStars = Array.from(Array(fullRatings).keys()).map( - (_, index) => { - return ( - - ); - } - ); - const halfRatingStars = Array.from(Array(halfRatings).keys()).map( - (_, index) => { - return ( - - ); - } - ); - let nonRatingStars; - if (nonRatings >= 0) { - nonRatingStars = Array.from(Array(nonRatings).keys()).map((_, index) => { - return ( - - ); - }); - } - return ( -
- {fullRatingStars} - {halfRatingStars} - {nonRatingStars} -
- ); -}; -interface RatingContainerProp { - total: number; - rating: number; - unratedColor: string; - ratedColor: string; -} diff --git a/packages/react-component-manifests/src/manifests/Rating/components.tsx b/packages/react-component-manifests/src/manifests/Rating/components.tsx deleted file mode 100644 index 2cf6f4a5f..000000000 --- a/packages/react-component-manifests/src/manifests/Rating/components.tsx +++ /dev/null @@ -1,62 +0,0 @@ -export const StarUnrated: React.FC = ({ - unratedColor, - ratedColor, -}) => { - return ( - - - - ); -}; -export const StarHalfRated: React.FC = ({ - unratedColor, - ratedColor, -}) => { - return ( - - - - - ); -}; -export const StarRated: React.FC = ({ unratedColor, ratedColor }) => { - return ( - - - - ); -}; -interface Starprop { - unratedColor: string; - ratedColor: string; -} diff --git a/packages/react-component-manifests/src/manifests/Slider/Slider.dev.tsx b/packages/react-component-manifests/src/manifests/Slider/Slider.dev.tsx new file mode 100644 index 000000000..0382cc006 --- /dev/null +++ b/packages/react-component-manifests/src/manifests/Slider/Slider.dev.tsx @@ -0,0 +1,10 @@ +import { forwardRef } from "react"; +import Slider from "./Slider"; + +const DevSlider: typeof Slider = forwardRef((props, ref) => { + return ( + + ); +}); + +export default DevSlider; diff --git a/packages/react-component-manifests/src/manifests/Slider/Slider.manifest.ts b/packages/react-component-manifests/src/manifests/Slider/Slider.manifest.ts index 276a500c5..0b641d6b9 100644 --- a/packages/react-component-manifests/src/manifests/Slider/Slider.manifest.ts +++ b/packages/react-component-manifests/src/manifests/Slider/Slider.manifest.ts @@ -22,9 +22,29 @@ const cssTreeOptions: CSSTreeOptions = { const customTreeOptions: CustomPropsTreeOptions = { dataTypes: { - minValue: { type: "number" }, - maxValue: { type: "number" }, - value: { type: "number" }, + range: { type: "boolean" }, + value: { type: "array_number" }, + min: { type: "number" }, + max: { type: "number" }, + defaultValue: { type: "array_number" }, + disabled: { type: "boolean" }, + vertical: { type: "boolean" }, + draggableTrack: { type: "boolean" }, + reverse: { type: "boolean" }, + marks: { + type: "array_map", + singleObjectName: "mark", + attributes: [ + { + fieldName: "value", + type: "number", + }, + { + fieldName: "label", + type: "text", + }, + ], + }, }, }; @@ -36,7 +56,7 @@ const compManifest: ReactComponentManifestSchema = { styles: { treeId: CSSTreeId, initialValue: { - width: "400px", + margin: "0 30px", }, treeOptions: cssTreeOptions, canvasOptions: { groupByBreakpoint: true }, @@ -44,9 +64,8 @@ const compManifest: ReactComponentManifestSchema = { custom: { treeId: CustomTreeId, initialValue: { - minValue: 0, - maxValue: 100, - value: 50, + min: 0, + max: 100, }, treeOptions: customTreeOptions, canvasOptions: { groupByBreakpoint: false }, @@ -54,7 +73,7 @@ const compManifest: ReactComponentManifestSchema = { }, attachCallbacks: { onChange: [{ type: "controlled", selector: ["custom", "value"] }], - onFinish: [{ type: "do_nothing" }], + onAfterChange: [{ type: "do_nothing" }], }, defaultCallbackHandlers: {}, }, diff --git a/packages/react-component-manifests/src/manifests/Slider/Slider.tsx b/packages/react-component-manifests/src/manifests/Slider/Slider.tsx index a4ba46b9e..a7b5dc6e9 100644 --- a/packages/react-component-manifests/src/manifests/Slider/Slider.tsx +++ b/packages/react-component-manifests/src/manifests/Slider/Slider.tsx @@ -1,262 +1,83 @@ -import React, { forwardRef, useCallback, useMemo, useRef } from "react"; +import React, { forwardRef, useMemo } from "react"; +import { Slider as AntdSlider } from "antd"; +import type { SliderProps as RcSliderProps } from "rc-slider"; -function isStringANumber(value: string) { - return value.match(/^[0-9]+$/) === null ? false : true; +export type SliderMarks = RcSliderProps["marks"]; +interface SliderRange { + draggableTrack?: boolean; +} +export interface SliderBaseProps { + reverse?: boolean; + min?: number; + max?: number; + step?: null | number; + marks?: { + value: number; + style?: React.CSSProperties; + label: string; + }[]; + disabled?: boolean; + keyboard?: boolean; + vertical?: boolean; +} +export interface SliderSingleProps extends SliderBaseProps { + range?: false; + value?: number; + defaultValue?: number; + onChange?: (value: number) => void; + onAfterChange?: (value: number) => void; + handleStyle?: React.CSSProperties; + trackStyle?: React.CSSProperties; + railStyle?: React.CSSProperties; +} +export interface SliderRangeProps extends SliderBaseProps { + range: true | SliderRange; + value?: [number, number]; + defaultValue?: [number, number]; + onChange?: (value: [number, number]) => void; + onAfterChange?: (value: [number, number]) => void; + handleStyle?: React.CSSProperties[]; + trackStyle?: React.CSSProperties[]; + railStyle?: React.CSSProperties; } const Slider = forwardRef< HTMLDivElement, { styles: React.CSSProperties; - custom: { - value?: number; - maxValue?: number; - minValue?: number; - thickness?: string; - radius?: string; - trackColor?: string; - thumbColor?: string; - selectColor?: string; - }; - onChange?: (value: number) => void; - onFinish?: (value: number) => void; className?: string; + custom: SliderRangeProps | SliderSingleProps; } >((props, ref) => { - const trackRef = useRef(null); - const thumbRef = useRef(null); - - const maxValue = useMemo(() => { - if (props.custom.maxValue === undefined) { - return 100; - } - return props.custom.maxValue; - }, [props.custom]); - - const minValue = useMemo(() => { - if (props.custom.minValue === undefined) { - return 0; - } - return props.custom.minValue; - }, [props.custom]); - - const valueRange = useMemo(() => { - return maxValue - minValue; - }, [minValue, maxValue]); - - const value = useMemo(() => { - if (props.custom.value === undefined) { - return 50; - } - return props.custom.value; - }, [props.custom]); - - const trackColor = useMemo(() => { - if (props.custom.trackColor === undefined) { - return "#CCC"; - } - return props.custom.trackColor; - }, [props.custom]); - - const thumbColor = useMemo(() => { - if (props.custom.thumbColor === undefined) { - return "#91d5ff"; + // Update the key whenever props.custom.range changes to true + const sliderKey = useMemo(() => { + if (props.custom.range) { + return Math.random(); } - return props.custom.thumbColor; - }, [props.custom]); - - const selectColor = useMemo(() => { - if (props.custom.selectColor === undefined) { - return "#91d5ff"; - } - return props.custom.selectColor; - }, [props.custom]); - - const thickness = useMemo(() => { - if (props.custom.thickness === undefined) { - return "4px"; - } - if (isStringANumber(props.custom.thickness)) { - return `${parseFloat(props.custom.thickness)}px`; - } - return props.custom.thickness; - }, [props.custom]); - - const radius = useMemo(() => { - if (props.custom.radius === undefined) { - return "8px"; - } - if (isStringANumber(props.custom.radius)) { - return `${parseFloat(props.custom.radius)}px`; + }, [props.custom.range]); + + const marks: SliderMarks = useMemo(() => { + if (props.custom?.marks) { + return props.custom?.marks?.reduce( + (acc: { [key: number]: string }, { value, label }) => { + acc[value] = label; + return acc; + }, + {} + ); } - return props.custom.radius; - }, [props.custom]); - - const onMouseDown = useCallback( - (e: React.MouseEvent) => { - if (trackRef.current) { - const scale = - valueRange / trackRef.current.getBoundingClientRect().width; - const upperLimit = - trackRef.current.getBoundingClientRect().left + - trackRef.current.getBoundingClientRect().width; - const lowerLimit = trackRef.current.getBoundingClientRect().left; - const initialValue = value; - const startPostion = { x: e.pageX, y: e.pageY }; - const onMouseMove = (e: MouseEvent) => { - if (startPostion) { - if (e.pageX >= upperLimit) { - props.onChange?.(maxValue); - } else if (e.pageX <= lowerLimit) { - props.onChange?.(minValue); - } else { - const delta = e.pageX - startPostion.x; - const finalValue = initialValue + delta * scale; - if (finalValue <= maxValue && finalValue >= minValue) { - props.onChange?.(finalValue); - } - } - } - }; - const onMouseUp = () => { - // unsubscribe - window.removeEventListener("mousemove", onMouseMove); - window.removeEventListener("mouseup", onMouseUp); - const delta = e.pageX - startPostion.x; - const finalValue = initialValue + delta * scale; - props.onFinish?.(finalValue); - }; - // subscribe - window.addEventListener("mousemove", onMouseMove); - window.addEventListener("mouseup", onMouseUp); - } - }, - [value, props, maxValue, minValue, valueRange] - ); - - const thumbPosition = useMemo(() => { - const thumbRadius = thumbRef.current?.getBoundingClientRect().width || 0; - const scale = - valueRange / (trackRef.current?.getBoundingClientRect().width || 1); - console.log( - thumbRadius, - scale, - valueRange, - trackRef.current?.getBoundingClientRect().width || 1 - ); - // stop initial back display of image - if (value - minValue <= thumbRadius * scale) { - console.log("setting 0px", minValue, value); - return `0px`; - } - return `calc(${((value - minValue) / valueRange) * 100}% - 2 * ${radius})`; - }, [value, minValue, valueRange, radius]); - - const onTrackClicked = useCallback( - (e: React.MouseEvent) => { - console.log("onTack"); - const scale = - valueRange / (trackRef.current?.getBoundingClientRect().width || 1); - const lowerLimit = trackRef.current?.getBoundingClientRect().left || 0; - const finalValue = minValue + (e.pageX - lowerLimit) * scale; - props.onChange?.(finalValue); - props.onFinish?.(finalValue); - }, - [valueRange, props, minValue] - ); + }, [props.custom.marks]); return ( - <> - -
+ - {/** track */} -
- {/** selected track */} -
- {/** thumb */} -
-
- + {...props.custom} + key={sliderKey} + marks={marks} + /> +
); });