diff --git a/packages/example/src/ShadcnApp.tsx b/packages/example/src/ShadcnApp.tsx index f07bca9..f08f912 100644 --- a/packages/example/src/ShadcnApp.tsx +++ b/packages/example/src/ShadcnApp.tsx @@ -6,17 +6,19 @@ import formConfig from './basic.json'; import { HeadlessWizard } from './Wizards/HeadlessWizard'; import { AllOfExamples } from './Wizards/AllOfExamples'; +import { ShaniForm } from './Wizards/ShaniForm'; import { defaultFields, SelectField } from '@tutim/shadcn-ui'; const contextOptions = { - clientId: '2', + clientId: '3', forms: { ['form-config-1337']: formConfig }, }; const examples: Record JSX.Element> = { HeadlessWizard, AllOfExamples, + ShaniForm, }; const options = Object.keys(examples).map((key, ix) => ({ value: key, label: `${ix}) => ${key}` })); diff --git a/packages/example/src/ShaniApp.tsx b/packages/example/src/ShaniApp.tsx new file mode 100644 index 0000000..fcd8b37 --- /dev/null +++ b/packages/example/src/ShaniApp.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { BrowserRouter } from 'react-router-dom'; +import { TutimProvider } from '@tutim/headless'; +import '@tutim/shadcn-ui/dist/output.css'; +import formConfig from './basic.json'; + +import { HeadlessWizard } from './Wizards/HeadlessWizard'; +import { AllOfExamples } from './Wizards/AllOfExamples'; +import { ShaniForm } from './Wizards/ShaniForm'; + +import { defaultFields, SelectField } from '@tutim/shadcn-ui'; +import { defaultFields as defaultFieldsMatirial, SelectField as SelectFieldMatirial } from '@tutim/fields'; //material-ui + +const contextOptions = { + clientId: '3', + forms: { ['form-config-1337']: formConfig }, +}; + +const examples: Record JSX.Element> = { + HeadlessWizard, + AllOfExamples, + ShaniForm, +}; + +const options = Object.keys(examples).map((key, ix) => ({ value: key, label: `${ix}) => ${key}` })); + +function App(): React.ReactNode { + const [exampleKey, setExample] = React.useState(options[options.length - 1].value); + const Example = examples[exampleKey]; + + return ( + +
+
+

left side:Shadcn UI | right side:MatiralUI

+ setExample(e.target.value), + }} + /> +
+
+ + {} + + + + {} + +
+
+
+ ); +} + +export default App; diff --git a/packages/example/src/Wizards/ShaniForm.tsx b/packages/example/src/Wizards/ShaniForm.tsx new file mode 100644 index 0000000..b340e92 --- /dev/null +++ b/packages/example/src/Wizards/ShaniForm.tsx @@ -0,0 +1,95 @@ +import React from 'react'; +import { FormConfig, Field } from '@tutim/types'; +import { TutimWizard } from '@tutim/headless'; +import { SimpleButton } from '@tutim/shadcn-ui'; + +const config: FormConfig = { + fields: [ + { + key: 'MultiCheckboxField', + label: 'Multi-Checkbox', + type: 'multi-checkbox', + options: [ + { value: '1', label: '1' }, + { value: '2', label: '2', disabled: true }, + ], + custom: { orientation: 'vertical' }, + }, + { + key: 'MultiSelectField', + label: 'TextField', + type: 'multi-select', + options: [ + { value: '1', label: '1' }, + { value: '2', label: '2', disabled: true }, + { value: '3', label: '3' }, + { value: '11', label: '11' }, + { value: '112', label: '112' }, + { value: '22', label: '22' }, + { value: '2222', label: '2222' }, + ], + }, + { + key: 'MultiTextField', + label: 'TextField', + type: 'multi-text', + options: [ + { value: '1', label: '1' }, + { value: '2', label: '2', disabled: true }, + ], + }, + { + key: 'NumberField', + label: 'TextField', + type: 'number', + }, + { + key: 'PasswordField', + label: 'TextField', + type: 'password', + }, + ], + wizard: { + steps: [ + { + label: 'Basic', + fields: ['MultiCheckboxField', 'MultiSelectField', 'MultiTextField', 'NumberField', 'PasswordField'], + }, + ], + orientation: 'vertical', + }, + meta: { + title: 'Example Title', + }, +}; + +const CustomField: Field = ({ inputProps }) => { + const { value, onChange } = inputProps; + const onClick = () => onChange(value + 2); + return ; +}; + +const customField = { + key: 'clicker', + label: 'Click Me', + type: 'custom', + defaultValue: 0, + Field: CustomField, +}; + +const newConfig = { ...config, fields: [...config.fields, customField] }; + +const initialValues = { + firstName: 'sami', + agree: true, + enable: true, + hosting: 'cloud', +}; + +export const ShaniForm = (): JSX.Element => { + const onSubmit = (data: any) => { + alert(JSON.stringify(data)); + }; + + return ; +}; diff --git a/packages/example/src/main.tsx b/packages/example/src/main.tsx index 2a74c20..6dc576d 100644 --- a/packages/example/src/main.tsx +++ b/packages/example/src/main.tsx @@ -1,6 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; // import App from './App'; -import App from './ShadcnApp'; +// import App from './ShadcnApp'; +import App from './ShaniApp'; ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(); diff --git a/packages/shadcn-ui/src/exports/Fields/MultiChecboxField.tsx b/packages/shadcn-ui/src/exports/Fields/MultiChecboxField.tsx index d6c146e..4a6c52c 100644 --- a/packages/shadcn-ui/src/exports/Fields/MultiChecboxField.tsx +++ b/packages/shadcn-ui/src/exports/Fields/MultiChecboxField.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Field } from '@tutim/types'; -import { Checkbox, FormControlLabel, Grid, FormGroup } from '@mui/material'; +import { Checkbox } from '../../components'; import { FieldWrapper } from './FieldWrapper'; const handleChange = (optionValue, currentValue, onChange) => { @@ -17,27 +17,29 @@ export const MultiCheckboxField: Field = ({ fieldConfig, inputProps: { value = [ const isHorizontal = custom?.orientation === 'vertical' ? false : true; const childOptions = options.map((option) => ( - - handleChange(option.value, value, onChange)} - disabled={isDisabled || option.disabled} - /> - } - label={option.label} +
+ handleChange(option.value, value, onChange)} + disabled={isDisabled || option.disabled} + className="m-1 border-black" /> - + +
)); return ( - - - {childOptions} - - +
+ {childOptions} +
); }; diff --git a/packages/shadcn-ui/src/exports/Fields/MultiSelectField.tsx b/packages/shadcn-ui/src/exports/Fields/MultiSelectField.tsx index e035e57..bc15334 100644 --- a/packages/shadcn-ui/src/exports/Fields/MultiSelectField.tsx +++ b/packages/shadcn-ui/src/exports/Fields/MultiSelectField.tsx @@ -1,29 +1,149 @@ +import { useState } from 'react'; import { Field } from '@tutim/types'; -import { TextField, Autocomplete } from '@mui/material'; import { FieldWrapper } from './FieldWrapper'; +import { Button, Input } from '../../components'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../components'; +import { X, ChevronDown } from 'lucide-react'; + +enum Title { + Clear = 'clear', + Open = 'open', +} + +const style = { + disabled: 'pointer-events-none opacity-60 ', + options: + 'absolute m-0 p-0 list-none max-h-60 overflow-y-auto border border-gray-200 rounded-md drop-shadow-md w-full left-0 top-full mt-1 z-50', + option: 'py-1 px-2 cursor-pointer', + highlight: 'bg-blue-600', +}; + +const ButtonStyle: React.FC<{ title: Title; onClick: () => void }> = ({ title, onClick }) => { + const handleClick = (event) => { + event.stopPropagation(); + onClick(); + }; + + return ( + + + + + + +

{title}

+
+
+
+ ); +}; + +const OptionBtn: React.FC<{ option: string; onClick: (key: string) => void }> = ({ option, onClick }) => { + const handleClick = (e: React.MouseEvent) => { + e.stopPropagation(); + onClick(option); + }; + return ( + + ); +}; export const MultiSelectField: Field = ({ fieldConfig, inputProps: { value = [], onChange }, fieldState }) => { const { isDisabled, options = [] } = fieldConfig; + const [open, setOpen] = useState(false); + const [hover, setHover] = useState(0); + const [optionsArr, setOptions] = useState(options); const handleChange = (event, newValue) => { onChange(newValue.map((option) => option.value)); }; + const onInputChange = (event: React.ChangeEvent) => { + event.stopPropagation(); + + if (event.currentTarget.value !== '') { + const currLength: number = event.currentTarget.value.length; + setOpen(true); + setOptions( + options.filter((option) => option.label.substring(0, currLength).includes(event.currentTarget?.value)) + ); + } else { + setOpen(false); + setOptions(options); + } + }; + + const clearOptions = (optionKey?: string | undefined) => { + if (!optionKey) onChange(undefined); + else onChange(value.filter((option) => option !== optionKey)); + }; + + const addNewValue = (newValue: string) => { + if (value.find((i) => i == newValue)) { + onChange(value.filter((option) => option !== newValue)); + setOpen(false); + return; + } + onChange([...value, newValue]); + setOpen(false); + }; + return ( - value.includes(option.value))} - onChange={handleChange} - getOptionLabel={(option) => option.label} - renderInput={(params) => ( - - )} - fullWidth - size="small" - disabled={isDisabled} - /> +
setOpen(false)} + > + + {value[0] ? ( + value.map((val) => clearOptions(val)} />) + ) : ( + <> + )} + onInputChange(e)} + /> + + + {value.length !== 0 && clearOptions()} title={Title.Clear} />} + setOpen(!open)} /> +
    + {optionsArr.map((option, index) => ( +
  • { + e.stopPropagation(); + addNewValue(option.label); + }} + onMouseOver={() => setHover(index)} + > + {option.label} +
  • + ))} +
+
); }; diff --git a/packages/shadcn-ui/src/exports/Fields/MultiTextField.tsx b/packages/shadcn-ui/src/exports/Fields/MultiTextField.tsx index 06b69b4..e57d2e6 100644 --- a/packages/shadcn-ui/src/exports/Fields/MultiTextField.tsx +++ b/packages/shadcn-ui/src/exports/Fields/MultiTextField.tsx @@ -1,23 +1,107 @@ +import { useEffect, useState } from 'react'; import { Field } from '@tutim/types'; -import { TextField as MuiTextField, Autocomplete } from '@mui/material'; import { FieldWrapper } from './FieldWrapper'; +import { Button, Input } from '../../components'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../components'; +import { X } from 'lucide-react'; + +const style = { + disabled: 'pointer-events-none opacity-60 ', +}; + +const ClearBtn: React.FC<{ onClick?: () => void }> = ({ onClick }) => { + return ( + + + + + + +

Clear

+
+
+
+ ); +}; + +const OptionBtn: React.FC<{ option: string; onClick: (key: string) => void }> = ({ option, onClick }) => { + const handleClick = () => { + onClick(option); + }; + return ( + + ); +}; export const MultiTextField: Field = ({ fieldConfig, inputProps: { value = [], onChange }, fieldState }) => { const { isDisabled } = fieldConfig; + const [currValue, setCurrValue] = useState(''); + const [duplicates, setDuplicate] = useState(false); + + const clearOptions = (optionKey?: string | undefined) => { + if (!optionKey) onChange(undefined); + else onChange(value.filter((option) => option !== optionKey)); + }; + + useEffect(() => { + setDuplicate(false); + + const handleKeyPress = (event: KeyboardEvent) => { + event.stopPropagation(); + if (event.key === 'Enter' && currValue !== '') { + console.log('Enter', value, currValue); + if (!value.includes(currValue)) { + onChange([...value, currValue]); + setCurrValue(''); + } else setDuplicate(true); + } + }; + + document.addEventListener('keydown', handleKeyPress); + return () => { + document.removeEventListener('keydown', handleKeyPress); + }; + }, [currValue]); return ( - onChange(value)} - value={value} - multiple - options={[]} - freeSolo - renderInput={(params) => } - fullWidth - size="small" - disabled={isDisabled} - /> +
+ + {value[0] ? ( + value.map((val) => clearOptions(val)} />) + ) : ( + <> + )} + ) => { + e.stopPropagation(); + setCurrValue(e.target.value); + }} + value={currValue} + /> + + + {value.length !== 0 && clearOptions()} />} +
); }; diff --git a/packages/shadcn-ui/src/exports/Fields/NumberField.tsx b/packages/shadcn-ui/src/exports/Fields/NumberField.tsx index a805824..737b5ed 100644 --- a/packages/shadcn-ui/src/exports/Fields/NumberField.tsx +++ b/packages/shadcn-ui/src/exports/Fields/NumberField.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Field } from '@tutim/types'; -import { TextField as MuiTextField } from '@mui/material'; +import { Input } from '../../components/ui/input'; import { FieldWrapper } from './FieldWrapper'; export const NumberField: Field = ({ fieldConfig, inputProps: { value, onChange }, fieldState }) => { @@ -12,19 +12,15 @@ export const NumberField: Field = ({ fieldConfig, inputProps: { value, onChange return ( - ); diff --git a/packages/shadcn-ui/src/exports/Fields/PasswordField.tsx b/packages/shadcn-ui/src/exports/Fields/PasswordField.tsx index 7fd98bb..13fab70 100644 --- a/packages/shadcn-ui/src/exports/Fields/PasswordField.tsx +++ b/packages/shadcn-ui/src/exports/Fields/PasswordField.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Field } from '@tutim/types'; -import { TextField as MuiTextField } from '@mui/material'; +import { Input } from '../../components/ui/input'; import { FieldWrapper } from './FieldWrapper'; export const PasswordField: Field = ({ fieldConfig, inputProps: { value, onChange }, fieldState }) => { @@ -12,19 +12,15 @@ export const PasswordField: Field = ({ fieldConfig, inputProps: { value, onChang return ( - );