-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor: init new base input elements * chore: configuration changes * feat: slots implement + modals rework init * chore: icons fixes + modals rework fixes + sidebar&utils improvements * fix: slots filling and saving fixes * chore: add slot condition settings & rework condition modal & add shadcn/ui * chore: add quiet save handlers * chore: slots components refactor & add condition icons
- Loading branch information
Showing
57 changed files
with
2,467 additions
and
425 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"$schema": "https://ui.shadcn.com/schema.json", | ||
"style": "default", | ||
"rsc": false, | ||
"tsx": true, | ||
"tailwind": { | ||
"config": "tailwind.config.js", | ||
"css": "src/index.css", | ||
"baseColor": "neutral", | ||
"cssVariables": false, | ||
"prefix": "" | ||
}, | ||
"aliases": { | ||
"components": "@/components", | ||
"utils": "@/lib/utils", | ||
"ui": "@/components/ui", | ||
"lib": "@/lib", | ||
"hooks": "@/hooks" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import * as Popover from "@radix-ui/react-popover" | ||
import classNames from "classnames" | ||
import { CheckIcon } from "lucide-react" | ||
import React, { ReactNode, useCallback, useEffect, useRef, useState } from "react" | ||
|
||
interface ComboboxProps { | ||
items: string[] | ||
placeholder?: string | ||
selected: string | ||
setSelected: (value: string) => void | ||
startContent?: ReactNode // Дополнительный контент в начале input | ||
endContent?: ReactNode // Дополнительный контент в конце input | ||
} | ||
|
||
const DefCombobox: React.FC<ComboboxProps> = ({ | ||
selected, | ||
setSelected, | ||
items, | ||
placeholder = "Select an option", | ||
endContent, | ||
startContent, | ||
}) => { | ||
const [inputValue, setInputValue] = useState("") | ||
const [isOpen, setIsOpen] = useState(false) | ||
const [filteredItems, setFilteredItems] = useState(items) | ||
const [highlightedIndex, setHighlightedIndex] = useState(-1) | ||
const containerRef = useRef<HTMLDivElement>(null) | ||
const inputRef = useRef<HTMLInputElement>(null) | ||
|
||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
const value = e.target.value | ||
setInputValue(value) | ||
setFilteredItems(items.filter((item) => item.toLowerCase().includes(value.toLowerCase()))) | ||
setHighlightedIndex(-1) // Сбрасываем выделение | ||
setIsOpen(true) | ||
} | ||
|
||
const handleSelectItem = useCallback( | ||
(item: string) => { | ||
setInputValue(item) | ||
setSelected(item) | ||
setIsOpen(false) | ||
}, | ||
[setSelected] | ||
) | ||
|
||
useEffect(() => { | ||
if (isOpen && inputRef.current) { | ||
inputRef.current.focus() // Ставим фокус обратно на input при открытии | ||
} | ||
}, [isOpen]) | ||
|
||
useEffect(() => { | ||
const handleKeyDown = (e: KeyboardEvent) => { | ||
if (isOpen) { | ||
if (e.key === "ArrowDown") { | ||
setHighlightedIndex((prev) => Math.min(prev + 1, filteredItems.length - 1)) | ||
e.preventDefault() // Предотвращаем прокрутку страницы | ||
} else if (e.key === "ArrowUp") { | ||
setHighlightedIndex((prev) => Math.max(prev - 1, 0)) | ||
e.preventDefault() // Предотвращаем прокрутку страницы | ||
} else if (e.key === "Enter" && highlightedIndex >= 0) { | ||
handleSelectItem(filteredItems[highlightedIndex]) | ||
e.preventDefault() // Предотвращаем отправку формы, если она есть | ||
} | ||
} | ||
} | ||
window.addEventListener("keydown", handleKeyDown) | ||
|
||
return () => { | ||
window.removeEventListener("keydown", handleKeyDown) | ||
} | ||
}, [isOpen, highlightedIndex, filteredItems, handleSelectItem]) | ||
|
||
return ( | ||
<div className='combobox-container'> | ||
<div | ||
ref={containerRef} | ||
className='w-full flex items-center justify-between bg-background p-2 rounded-lg border border-input-border hover:bg-bg-secondary transition-colors'> | ||
{startContent && <span style={{ marginRight: "8px" }}>{startContent}</span>} | ||
<input | ||
ref={inputRef} | ||
type='text' | ||
value={inputValue} | ||
onChange={handleInputChange} | ||
placeholder={placeholder} | ||
className='w-full bg-transparent outline-none placeholder:text-input-border text-sm' | ||
/> | ||
{endContent && <span style={{ marginLeft: "8px" }}>{endContent}</span>} | ||
</div> | ||
|
||
{/* Popover for dropdown menu */} | ||
<Popover.Root | ||
open={isOpen} | ||
onOpenChange={setIsOpen}> | ||
<Popover.Trigger asChild> | ||
<div /> | ||
</Popover.Trigger> | ||
|
||
<Popover.Content | ||
onOpenAutoFocus={(e) => e.preventDefault()} | ||
align='start' | ||
side='bottom' | ||
style={{ | ||
width: containerRef.current?.offsetWidth ?? "320px", | ||
}} | ||
className={`mt-2 bg-background border border-input-border rounded-lg py-1 z-[9999] overflow-x-hidden *:text-sm`}> | ||
{filteredItems.length ? ( | ||
filteredItems.map((item, index) => ( | ||
<div | ||
key={item} | ||
className={classNames( | ||
"flex items-center justify-between hover:bg-bg-secondary py-1 px-3 cursor-pointer transition-colors", | ||
highlightedIndex === index && "bg-bg-secondary" | ||
)} | ||
onClick={() => handleSelectItem(item)}> | ||
{item} | ||
{selected === item && <CheckIcon className='size-4' />} | ||
</div> | ||
)) | ||
) : ( | ||
<div className='p-2'>No items found</div> | ||
)} | ||
</Popover.Content> | ||
</Popover.Root> | ||
|
||
{/* Стили для компонента */} | ||
</div> | ||
) | ||
} | ||
|
||
export default DefCombobox |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { Input, InputProps, InputSlots, SlotsToClasses } from "@nextui-org/react" | ||
import classNames from "classnames" | ||
|
||
|
||
// const DefInput = ({ className, label, labelClassName, wrapperClassName, ...props }: DefInputType) => { | ||
// return ( | ||
// <div className={classNames("flex flex-col w-full", wrapperClassName)}> | ||
// <label className={classNames("text-sm text-input-border-focus font-medium", labelClassName)}>{label}</label> | ||
// <input | ||
// className={classNames( | ||
// "min-h-10 h-10 bg-input-background text-input-foreground border border-input-border focus:border-input-border-focus focus:outline-input-border-focus placeholder:text-input-border-focus rounded-[8px] px-3.5", | ||
// className | ||
// )} | ||
// {...props} | ||
// /> | ||
// </div> | ||
// ) | ||
// } | ||
|
||
const defInputStyles: SlotsToClasses<InputSlots> = { | ||
label: "text-black/50 dark:text-white/90", | ||
input: [ | ||
"bg-transparent", | ||
"placeholder:text-input-border-focus", | ||
], | ||
innerWrapper: "bg-transparent", | ||
inputWrapper: [ | ||
"min-h-10 h-10", | ||
"px-3.5", | ||
"rounded-[8px]", | ||
"shadow-none", | ||
"bg-input-background", | ||
"border border-input-border", | ||
"hover:bg-transparent", | ||
"group-data-[focus=true]:bg-input-background", | ||
"group-data-[hover=true]:bg-input-background-disabled", | ||
"!cursor-text", | ||
], | ||
} | ||
|
||
const DefInput = ({ className, ...props }: InputProps) => { | ||
return ( | ||
<Input | ||
labelPlacement="outside" | ||
classNames={defInputStyles} | ||
className={classNames("w-full", className)} | ||
{...props} | ||
/> | ||
) | ||
} | ||
|
||
export default DefInput |
Oops, something went wrong.