| [ | ||
| { | ||
| "theme": "Singularity", | ||
| "class": "dyvix-select-lens", | ||
| "input-class": "dyvix-select-input-lens", | ||
| "dropdown-class": "dyvix-select-dropdown-lens", | ||
| "default-animation": "bubble" | ||
| } | ||
| ] |
| import { | ||
| EvaluateFailure, | ||
| GuardStatus, | ||
| allowsNull | ||
| } from '../../utils/DyvixGuard'; | ||
| import { ValidatAndLoadJSON } from '../../utils/Smart Json Caching/SJCManager'; | ||
| const component = 'Select'; | ||
| const CacheMapping = { | ||
| animation: { | ||
| jsonpath: '../../components/animations.json', | ||
| csspath: null | ||
| }, | ||
| theme: { | ||
| jsonpath: '../../components/select/dependencies/themes.json', | ||
| csspath: '../../components/select/dependencies/style/themes.css' | ||
| } | ||
| }; | ||
| const supportedTypes = ['select', 'autocomplete']; | ||
| export async function ValidateSelect( | ||
| elements, | ||
| type, | ||
| animation, | ||
| theme, | ||
| callback, | ||
| instance | ||
| ) { | ||
| let normalizedAnimation = animation?.trim().toLowerCase(); | ||
| const normalizedTheme = | ||
| theme?.trim().charAt(0).toUpperCase() + theme.trim().slice(1); | ||
| const isTheme = await ValidatAndLoadJSON( | ||
| CacheMapping, | ||
| normalizedTheme, | ||
| callback, | ||
| 'theme', | ||
| component, | ||
| instance | ||
| ); | ||
| if (normalizedAnimation === '!/' && isTheme?.config?.theme) { | ||
| normalizedAnimation = isTheme?.config?.theme['default-animation']; | ||
| } | ||
| const isAnimation = await ValidatAndLoadJSON( | ||
| CacheMapping, | ||
| normalizedAnimation, | ||
| callback, | ||
| 'animation', | ||
| component | ||
| ); | ||
| if (!isAnimation.status && !allowsNull(normalizedAnimation)) { | ||
| return { | ||
| status: GuardStatus.Error, | ||
| error: 'Please provide a valid animation.' | ||
| }; | ||
| } | ||
| if (!Array.isArray(elements)) { | ||
| return { | ||
| status: GuardStatus.Error, | ||
| error: 'Elements should be included as an array.' | ||
| }; | ||
| } | ||
| if (!supportedTypes.includes(type)) { | ||
| return { | ||
| status: GuardStatus.Error, | ||
| error: 'Please provide a valid select type.' | ||
| }; | ||
| } | ||
| return { status: GuardStatus.Success }; | ||
| } |
+6
-0
@@ -32,1 +32,7 @@ # Contributors | ||
| - [@LuisOrlando-code](https://github.com/LuisOrlando-code) | ||
| - [@hakkiai](https://github.com/hakkiai) | ||
| - [@Pranay-Kamble](https://github.com/Pranay-Kamble) | ||
| - [@LateeshaNarnolia104](https://github.com/LateeshaNarnolia104) | ||
| - [@TaH00R](https://github.com/TaH00R) | ||
| - [@arishaix](https://github.com/arishaix) | ||
| - [@uttam12331](https://github.com/uttam12331) |
+1
-1
| { | ||
| "name": "dyvix-ui", | ||
| "version": "0.3.5", | ||
| "version": "0.3.6", | ||
| "description": "Dyvix is an open source, modern, config-driven, animated component UI library. Beautiful by default, customizable by design.", | ||
@@ -5,0 +5,0 @@ "main": "src/index.jsx", |
@@ -155,1 +155,40 @@ .dyvix-label-lens { | ||
| } | ||
| .dyvix-label-neon { | ||
| font-family: 'Geist'; | ||
| color: #4deeea; | ||
| text-shadow: | ||
| 0 0 8px rgba(77, 238, 234, 0.7), | ||
| 0 0 20px rgba(240, 0, 255, 0.45); | ||
| transition: | ||
| color 0.3s ease-in-out, | ||
| text-shadow 0.3s ease-in-out, | ||
| transform 0.3s ease-in-out; | ||
| } | ||
| .dyvix-label-neon:hover { | ||
| color: #f000ff; | ||
| text-shadow: | ||
| 0 0 12px rgba(77, 238, 234, 0.9), | ||
| 0 0 30px rgba(240, 0, 255, 0.75); | ||
| transform: translateY(-1px); | ||
| } | ||
| .dyvix-label-aurora { | ||
| font-family: 'Geist'; | ||
| color: #00ea8d; | ||
| text-shadow: | ||
| 0 0 8px rgba(0, 234, 141, 0.55), | ||
| 0 0 22px rgba(181, 61, 255, 0.35); | ||
| transition: | ||
| color 0.3s ease-in-out, | ||
| text-shadow 0.3s ease-in-out, | ||
| transform 0.3s ease-in-out; | ||
| } | ||
| .dyvix-label-aurora:hover { | ||
| color: #b53dff; | ||
| text-shadow: | ||
| 0 0 12px rgba(0, 234, 141, 0.75), | ||
| 0 0 34px rgba(181, 61, 255, 0.55); | ||
| transform: translateY(-1px); | ||
| } |
@@ -46,3 +46,13 @@ [ | ||
| "default-animation": "glide" | ||
| }, | ||
| { | ||
| "theme": "Neon", | ||
| "class": "dyvix-label-neon", | ||
| "default-animation": "pulse" | ||
| }, | ||
| { | ||
| "theme": "Aurora", | ||
| "class": "dyvix-label-aurora", | ||
| "default-animation": "aurora" | ||
| } | ||
| ] |
@@ -57,3 +57,3 @@ .dyvix-modal-wrapper { | ||
| } | ||
| .modal:not([class*='dyvix-modal-']) .modal-element::placeholder{ | ||
| .modal:not([class*='dyvix-modal-']) .modal-element::placeholder { | ||
| color: #1a1a1a !important; | ||
@@ -60,0 +60,0 @@ } |
@@ -159,4 +159,3 @@ import elementsData from './dependencies/elements.json'; | ||
| const newErrors = handleValidation(data); | ||
| const allow = | ||
| Object.values(newErrors).every((val) => val === null); | ||
| const allow = Object.values(newErrors).every((val) => val === null); | ||
| if (typeof onSubmit === 'function' && allow) { | ||
@@ -173,2 +172,18 @@ onSubmit(data); | ||
| const currentPreset = configs['preset']; | ||
| const themeTextStyle = { | ||
| color: currentTheme?.['text-color'] | ||
| }; | ||
| const themeInputStyle = { | ||
| ...(currentTheme?.['input-background'] && { | ||
| background: currentTheme['input-background'] | ||
| }), | ||
| ...(currentTheme?.['input-color'] && { | ||
| color: currentTheme['input-color'] | ||
| }), | ||
| ...(currentTheme?.['input-border'] && { | ||
| border: currentTheme['input-border'] | ||
| }) | ||
| }; | ||
| const serilaizedclassName = | ||
@@ -324,3 +339,5 @@ className + | ||
| )} | ||
| <h3 id="modal-header">{title}</h3> | ||
| <h3 id="modal-header" style={themeTextStyle}> | ||
| {title} | ||
| </h3> | ||
| {fields?.map((field, i) => { | ||
@@ -394,7 +411,10 @@ const elementDef = | ||
| fontSize: fontSize, | ||
| fontWeight: fontWeight | ||
| fontWeight: fontWeight, | ||
| ...(elementDef['tag'] !== 'DyvixInput' && { | ||
| ...themeInputStyle | ||
| }) | ||
| }, | ||
| ...ariaAttributes, | ||
| ...(id && id !== '!/' && { id: id }), | ||
| ...(elementDef['is_custom'] && {animation: null}), | ||
| ...(elementDef['is_custom'] && { animation: null }), | ||
| ...(elementDef['supports-placeholder'] && { | ||
@@ -437,3 +457,5 @@ placeholder: field.placeholder[j], | ||
| }, | ||
| ...((theme === '!/' || !theme) && {background: "transparent"} ) | ||
| ...((theme === '!/' || !theme) && { | ||
| background: 'transparent' | ||
| }) | ||
| }) | ||
@@ -461,3 +483,7 @@ }; | ||
| ) : field.type === 'checkbox' ? ( | ||
| <label key={j} className="modal-checkbox-label"> | ||
| <label | ||
| key={j} | ||
| className="modal-checkbox-label" | ||
| style={themeTextStyle} | ||
| > | ||
| <Tag {...Tagprobs} /> | ||
@@ -464,0 +490,0 @@ {field.placeholder?.[j]} |
| .dyvix-select-wrapper { | ||
| width: 12rem; | ||
| width: fit-content; | ||
| height: fit-content; | ||
| position: relative; | ||
| z-index: 1; | ||
| } | ||
| .dyvix-select { | ||
| width: 100%; | ||
| transition: all 0.5s ease-in-out; | ||
| } | ||
| .dyvix-select-wrapper:hover { | ||
| transform: scale(1.02); | ||
| .dyvix-select-input { | ||
| background-color: rgba(255, 255, 255, 0.02); | ||
| border: 2px solid rgb(26, 27, 27); | ||
| border-radius: 8px; | ||
| box-sizing: border-box; | ||
| width: 100%; | ||
| height: 40px; | ||
| min-width: 50px; | ||
| padding: 0 12px; | ||
| color: #b9f7ff; | ||
| outline: none; | ||
| box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3); | ||
| transition: all 0.15s cubic-bezier(0.2, 0.2, 0.65, 0.3); | ||
| } | ||
| .dyvi-select { | ||
| width: 12rem; | ||
| border: 1px solid rgba(255, 255, 255, 0.2); | ||
| border-radius: 0.75rem; | ||
| height: 30px; | ||
| margin: 0 auto; | ||
| background: transparent; | ||
| padding: 0.5rem 1rem; | ||
| .dyvix-select-input:hover { | ||
| border: 2px solid rgb(194, 239, 255); | ||
| box-shadow: | ||
| inset 0 2px 4px rgba(0, 0, 0, 0.3), | ||
| 0 0 10px rgba(185, 247, 255, 0.15); | ||
| cursor: text; | ||
| } | ||
| .dyvi-select:focus { | ||
| outline: none; | ||
| border-color: #0ea5e9; | ||
| .dyvix-select-input:focus { | ||
| background-color: rgba(255, 255, 255, 0.1); | ||
| border: 3px solid rgb(168, 231, 254); | ||
| border-color: #b9f7ff; | ||
| box-shadow: | ||
| inset 0 2px 4px rgba(0, 0, 0, 0.3), | ||
| 0 0 12px rgba(185, 247, 255, 0.2); | ||
| } | ||
| .dyvix-select-input::placeholder { | ||
| color: rgba(255, 255, 255, 0.4); | ||
| font-size: 0.9rem; | ||
| } | ||
| .dyvix-dropdown-select { | ||
| position: absolute; | ||
| list-style: none; | ||
| top: 100%; | ||
| left: 0; | ||
| width: 100%; | ||
| margin: 2px 0 0 0; | ||
| list-style: none !important; | ||
| text-align: left; | ||
| width: 90px; | ||
| max-height: 60px; | ||
| max-height: 150px; | ||
| overflow-y: auto; | ||
| z-index: 1000; | ||
| padding: 0; | ||
| border-radius: 5px; | ||
| background-color: whitesmoke; | ||
| border: solid 1px #e2e8f0; | ||
| margin-left: 10px; | ||
| margin-top: 0.1rem; | ||
| padding: 4px 0; | ||
| border-radius: 8px; | ||
| background: whitesmoke; | ||
| border: 1px solid #e2e8f0; | ||
| box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); | ||
| } | ||
@@ -47,10 +74,10 @@ .dyvix-dropdown-select::-webkit-scrollbar { | ||
| .dyvix-dropdown-select li { | ||
| background-color: whitesmoke; | ||
| border-bottom: gainsboro 0.1px solid; | ||
| height: 20px !important; | ||
| font-size: xx-small; | ||
| font-family: 'Inter', 'Segoe UI', sans-serif; | ||
| font-weight: 500; | ||
| letter-spacing: 0.5px; | ||
| margin-left: 0.4rem; | ||
| background-color: transparent; | ||
| color: #fff; | ||
| border-bottom: 1px solid rgb(35, 40, 45); | ||
| padding: 10px 12px; | ||
| font-size: 0.9rem; | ||
| font-family: 'Inter', sans-serif; | ||
| cursor: pointer; | ||
| margin-left: 0; | ||
| } | ||
@@ -57,0 +84,0 @@ .dyvix-dropdown-select li:active { |
| import './dependencies/style/styles.css'; | ||
| import React from 'react'; | ||
| import SelectEngine from './SelectEngine'; | ||
| import animationsData from '../animations.json'; | ||
| import { useGSAP } from '@gsap/react'; | ||
| import { gsap } from 'gsap'; | ||
| import { EvaluateFailure, GuardStatus } from '../../utils/DyvixGuard'; | ||
| import { ValidateSelect } from './validation'; | ||
| import Version from '../../../package.json'; | ||
| const supportedTypes = ['select', 'autocomplete']; | ||
| const validAnimations = animationsData.map((e) => e.animation); | ||
| /** | ||
@@ -20,3 +19,3 @@ * @param {Object} props | ||
| */ | ||
| function DynamicSelect({ | ||
| function DyvixSelect({ | ||
| elements = [], | ||
@@ -26,5 +25,7 @@ onChange, | ||
| animation = 'fade', | ||
| theme = '!/', | ||
| className, | ||
| placeholder = '', | ||
| ...props | ||
| style, | ||
| ...rest | ||
| }) { | ||
@@ -40,10 +41,8 @@ type = type.includes('-') ? type.split('-')[1] : type; | ||
| }); | ||
| const selectWrapperRef = React.useRef(null); | ||
| const selectRef = React.useRef(null); | ||
| const [configs, SetConfig] = React.useState({}); | ||
| const instanceId = React.useId(); | ||
| const dropdownSelectRef = React.useRef(null); | ||
| const is_valid = ValidateInput(elements, type, animation); | ||
| if (is_valid.status === -1) { | ||
| console.error(is_valid.error); | ||
| return null; | ||
| } | ||
| function onChangeInternalCallback(data) { | ||
@@ -99,6 +98,33 @@ onChange(data); | ||
| }; | ||
| const currentAnimation = animationsData.find( | ||
| (e) => e.animation.trim().toLowerCase() === animation.trim().toLowerCase() | ||
| ); | ||
| const currentAnimation = animation ? configs['animation'] : null; | ||
| const currentTheme = theme !== '!/' ? configs['theme'] : null; | ||
| className = | ||
| `dyvix-select-wrapper ${currentTheme?.class ?? ''} ${className !== '' ? ` ${className}` : ''}`.trim(); | ||
| const dropdownThemeClass = currentTheme?.['dropdown-class']; | ||
| const inputThemeClass = currentTheme?.['input-class']; | ||
| React.useEffect(() => { | ||
| async function validate() { | ||
| const validator = await ValidateSelect( | ||
| elements, | ||
| type, | ||
| animation, | ||
| theme, | ||
| SetConfig, | ||
| instanceId | ||
| ); | ||
| if (validator.status === GuardStatus.Error) { | ||
| return EvaluateFailure(validator.error, validator.status); | ||
| } | ||
| } | ||
| validate(); | ||
| return () => { | ||
| const key = `DYVIX_${Version['version']}_Select_theme_${instanceId}`; | ||
| const ele = document.getElementById(key); | ||
| if (ele) ele.remove(); | ||
| }; | ||
| }, [animation, theme]); | ||
| function HandleKey(e, controller) { | ||
@@ -145,5 +171,5 @@ if (Select.is_open == false) return; | ||
| useGSAP(() => { | ||
| if (!selectRef.current || !currentAnimation) return; | ||
| if (!selectWrapperRef.current || !currentAnimation) return; | ||
| gsap.fromTo(selectRef.current, currentAnimation.from, { | ||
| gsap.fromTo(selectWrapperRef.current, currentAnimation.from, { | ||
| ...currentAnimation.to, | ||
@@ -154,38 +180,54 @@ duration: currentAnimation['default-duration'], | ||
| }, [currentAnimation]); | ||
| const props = { | ||
| className: className, | ||
| style: style | ||
| }; | ||
| const inputProps = { | ||
| autoComplete: 'off', | ||
| role: 'combobox', | ||
| 'aria-autocomplete': 'list', | ||
| 'aria-expanded': Select.is_open, | ||
| 'aria-haspopup': 'listbox', | ||
| className: `dyvix-select-input ${inputThemeClass}`.trim(), | ||
| type: 'text', | ||
| ...rest, | ||
| ref: selectRef, | ||
| placeholder: placeholder || undefined, | ||
| onChange: (e) => { | ||
| PopulateSelect(e.target.value, SetSelect, elements); | ||
| onChangeInternalCallback(e.target.value); | ||
| }, | ||
| onFocus: (e) => { | ||
| TranslateEngineType(e.target.value, 'focus', SetSelect); | ||
| if (rest.onFocus) rest.onFocus(e); | ||
| }, | ||
| onBlur: (e) => { | ||
| TranslateEngineType(e.target.value, 'blur', SetSelect); | ||
| if (rest.onBlur) rest.onBlur(e); | ||
| }, | ||
| onKeyDown: (e) => { | ||
| HandleKey(e, SetSelect); | ||
| if (rest.onKeyDown) rest.onKeyDown(e); | ||
| } | ||
| }; | ||
| const engineProps = { | ||
| elements: Select.elements, | ||
| is_open: Select.is_open, | ||
| is_rendered: Select.is_rendered, | ||
| inputRef: selectRef, | ||
| activeIndex: Select.activeIndex, | ||
| ref: dropdownSelectRef, | ||
| ...(dropdownThemeClass && { className: dropdownThemeClass }), | ||
| controller: SetSelect, | ||
| OnChangeCallback: (value) => onChangeInternalCallback(value), | ||
| placeholder: placeholder || undefined | ||
| }; | ||
| return ( | ||
| <div className={`${className} dyvix-select-wrapper`}> | ||
| <input | ||
| autoComplete="off" | ||
| role="combobox" | ||
| aria-autocomplete="list" | ||
| aria-expanded={Select.is_open} | ||
| aria-haspopup="listbox" | ||
| className={`dyvi-select`} | ||
| type="text" | ||
| ref={selectRef} | ||
| placeholder={placeholder} | ||
| onChange={(e) => { | ||
| PopulateSelect(e.target.value, SetSelect, elements); | ||
| onChangeInternalCallback(e.target.value); | ||
| }} | ||
| onFocus={(e) => { | ||
| TranslateEngineType(e.target.value, 'focus', SetSelect); | ||
| }} | ||
| onBlur={(e) => { | ||
| TranslateEngineType(e.target.value, 'blur', SetSelect); | ||
| }} | ||
| onKeyDown={(e) => HandleKey(e, SetSelect)} | ||
| /> | ||
| <SelectEngine | ||
| elements={Select.elements} | ||
| is_open={Select.is_open} | ||
| is_rendered={Select.is_rendered} | ||
| inputRef={selectRef} | ||
| activeIndex={Select.activeIndex} | ||
| ref={dropdownSelectRef} | ||
| controller={SetSelect} | ||
| OnChangeCallback={(value) => onChangeInternalCallback(value)} | ||
| placeholder={placeholder} | ||
| /> | ||
| <div {...props} ref={selectWrapperRef}> | ||
| <div className="dyvix-select"> | ||
| <input {...inputProps} /> | ||
| </div> | ||
| <SelectEngine {...engineProps} /> | ||
| </div> | ||
@@ -195,15 +237,2 @@ ); | ||
| function ValidateInput(elements, type, animation) { | ||
| if (!Array.isArray(elements)) { | ||
| return { status: -1, error: 'Elements should be included as an array.' }; | ||
| } | ||
| if (!supportedTypes.includes(type)) { | ||
| return { status: -1, error: 'Please provide a valid select type.' }; | ||
| } | ||
| if (animation !== '!/' && !validAnimations.includes(animation)) { | ||
| return { status: -1, error: 'Please provide a valid animation.' }; | ||
| } | ||
| return { status: 1 }; | ||
| } | ||
| export default DynamicSelect; | ||
| export default DyvixSelect; |
@@ -13,3 +13,3 @@ import './dependencies/style/styles.css'; | ||
| selectedElement = '', | ||
| placeholder = 'Select...', | ||
| placeholder = '', | ||
| controller, | ||
@@ -19,3 +19,4 @@ activeIndex, | ||
| OnChangeCallback, | ||
| type | ||
| type, | ||
| className | ||
| }, | ||
@@ -55,3 +56,4 @@ ref | ||
| duration: 1.1, | ||
| ease: 'power2.inOut' | ||
| ease: 'power2.inOut', | ||
| overwrite: 'auto' | ||
| } | ||
@@ -64,3 +66,4 @@ ); | ||
| duration: 0.3, | ||
| ease: 'power2.inOut' | ||
| ease: 'power2.inOut', | ||
| overwrite: 'auto' | ||
| }); | ||
@@ -71,13 +74,2 @@ } | ||
| useEffect(() => { | ||
| const observer = new ResizeObserver(() => { | ||
| ref.current.style.width = inputRef.current.offsetWidth - 20 + 'px'; | ||
| ref.current.style.marginLeft = 5; | ||
| }); | ||
| observer.observe(inputRef.current); | ||
| return () => observer.disconnect(); | ||
| }, []); | ||
| useEffect(() => { | ||
| if (activeIndex >= 0 && itemsRef.current[activeIndex]) { | ||
@@ -92,9 +84,4 @@ itemsRef.current[activeIndex].scrollIntoView({ block: 'nearest' }); | ||
| <ul | ||
| className="dyvix-dropdown-select" | ||
| className={`dyvix-dropdown-select ${className}`.trim()} | ||
| role="listbox" | ||
| style={ | ||
| is_open | ||
| ? { background: 'whitesmoke', border: '1px solid #e2e8f0' } | ||
| : { background: 'transparent', border: 'none' } | ||
| } | ||
| ref={ref} | ||
@@ -110,3 +97,8 @@ > | ||
| index === activeIndex | ||
| ? { backgroundColor: '#e0f7fa', cursor: 'pointer' } | ||
| ? { | ||
| backgroundColor: | ||
| 'var(--dyvix-select-active-bg, #e0f7fa)', | ||
| color: 'var(--dyvix-select-active-text, #141618)', | ||
| cursor: 'pointer' | ||
| } | ||
| : {} | ||
@@ -113,0 +105,0 @@ } |
@@ -64,2 +64,10 @@ .dyvix-table-wrapper { | ||
| } | ||
| .dyvix-table-sort-icon { | ||
| min-width: 16px; | ||
| max-width: 16px; | ||
| } | ||
| .table-sortable { | ||
| cursor: pointer; | ||
| user-select: none; | ||
| } | ||
| @media (max-width: 640px) { | ||
@@ -66,0 +74,0 @@ .dyvix-table-wrapper { |
@@ -23,2 +23,3 @@ .dyvix-table-lens { | ||
| } | ||
| .dyvix-table-crimson { | ||
@@ -43,1 +44,255 @@ border-radius: 1rem; | ||
| } | ||
| .dyvix-table-midnight { | ||
| border-radius: 1rem; | ||
| font-family: 'Geist'; | ||
| background: radial-gradient(circle at center, #00024d 0%, #000000 100%); | ||
| border: 1px solid rgba(112, 168, 247, 0.3); | ||
| color: #c8d8f8; | ||
| box-shadow: | ||
| 0 0 40px 5px rgba(99, 102, 241, 0.2), | ||
| inset 0 0 15px rgba(112, 168, 247, 0.1); | ||
| -webkit-box-shadow: | ||
| 0 0 40px 5px rgba(99, 102, 241, 0.2), | ||
| inset 0 0 15px rgba(112, 168, 247, 0.1); | ||
| -moz-box-shadow: | ||
| 0 0 40px 5px rgba(99, 102, 241, 0.2), | ||
| inset 0 0 15px rgba(112, 168, 247, 0.1); | ||
| backdrop-filter: blur(10px); | ||
| transition: | ||
| transform 0.5s cubic-bezier(0.17, 0.88, 0.3, 1.67), | ||
| box-shadow 0.5s ease-in-out, | ||
| border-color 0.3s ease-in-out; | ||
| } | ||
| .dyvix-table-midnight:hover { | ||
| background: radial-gradient(circle at 40% 40%, #000375 0%, #000000 100%); | ||
| border-color: rgba(112, 168, 247, 0.6); | ||
| box-shadow: | ||
| 0 0 60px 10px rgba(99, 102, 241, 0.4), | ||
| inset 0 0 20px rgba(112, 168, 247, 0.2); | ||
| -webkit-box-shadow: | ||
| 0 0 60px 10px rgba(99, 102, 241, 0.4), | ||
| inset 0 0 20px rgba(112, 168, 247, 0.2); | ||
| -moz-box-shadow: | ||
| 0 0 60px 10px rgba(99, 102, 241, 0.4), | ||
| inset 0 0 20px rgba(112, 168, 247, 0.2); | ||
| transform: translateY(-3px) scale(1.005); | ||
| } | ||
| .dyvix-table-forest { | ||
| border-radius: 1rem; | ||
| font-family: 'Geist'; | ||
| background: #1f3b2c; | ||
| background: radial-gradient( | ||
| circle, | ||
| rgba(31, 59, 44, 1) 14%, | ||
| rgba(31, 59, 44, 1) 24%, | ||
| rgba(75, 58, 42, 1) 71% | ||
| ); | ||
| border: 3px double #86a86b; | ||
| color: #d4eec4; | ||
| box-shadow: inset 0px 0px 30px 10px rgba(163, 236, 101, 0.15); | ||
| -webkit-box-shadow: inset 0px 0px 30px 10px rgba(163, 236, 101, 0.15); | ||
| -moz-box-shadow: inset 0px 0px 30px 10px rgba(163, 236, 101, 0.15); | ||
| transition: | ||
| transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275), | ||
| box-shadow 0.3s ease, | ||
| border-color 0.3s ease; | ||
| } | ||
| .dyvix-table-forest:hover { | ||
| border-color: #a3ec65; | ||
| box-shadow: inset 0px 0px 50px 15px rgba(163, 236, 101, 0.28); | ||
| -webkit-box-shadow: inset 0px 0px 50px 15px rgba(163, 236, 101, 0.28); | ||
| -moz-box-shadow: inset 0px 0px 50px 15px rgba(163, 236, 101, 0.28); | ||
| transform: translateY(-2px) scale(1.005); | ||
| } | ||
| .dyvix-table-sunset { | ||
| border-radius: 1rem; | ||
| font-family: 'Geist'; | ||
| background: #1a0a00; | ||
| background: linear-gradient( | ||
| 135deg, | ||
| #1a0a00 0%, | ||
| #3d1a00 40%, | ||
| #6b2d00 70%, | ||
| #8b3a00 100% | ||
| ); | ||
| border: 1px solid rgba(255, 198, 15, 0.1); | ||
| border-bottom: 4px solid #a84600; | ||
| color: #ffd89b; | ||
| box-shadow: 0px 15px 38px -10px rgba(255, 198, 15, 0.5); | ||
| -webkit-box-shadow: 0px 15px 38px -10px rgba(255, 198, 15, 0.5); | ||
| -moz-box-shadow: 0px 15px 38px -10px rgba(255, 198, 15, 0.5); | ||
| transition: | ||
| transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), | ||
| box-shadow 0.3s ease-in-out, | ||
| border-radius 0.2s ease-in-out; | ||
| } | ||
| .dyvix-table-sunset:hover { | ||
| transform: translateY(-2px); | ||
| box-shadow: 0 20px 50px -10px rgba(255, 198, 15, 0.6); | ||
| -webkit-box-shadow: 0 20px 50px -10px rgba(255, 198, 15, 0.6); | ||
| -moz-box-shadow: 0 20px 50px -10px rgba(255, 198, 15, 0.6); | ||
| border-radius: 0.9rem; | ||
| } | ||
| .dyvix-table-ocean { | ||
| border-radius: 1rem; | ||
| font-family: 'Geist'; | ||
| background: linear-gradient(200deg, #001220, #023862); | ||
| border: 2px solid rgba(0, 150, 255, 0.3); | ||
| color: #e0f7ff; | ||
| box-shadow: | ||
| 0 0 50px rgba(0, 100, 255, 0.15), | ||
| inset 0 0 30px rgba(0, 150, 255, 0.05); | ||
| -webkit-box-shadow: | ||
| 0 0 50px rgba(0, 100, 255, 0.15), | ||
| inset 0 0 30px rgba(0, 150, 255, 0.05); | ||
| -moz-box-shadow: | ||
| 0 0 50px rgba(0, 100, 255, 0.15), | ||
| inset 0 0 30px rgba(0, 150, 255, 0.05); | ||
| transition: | ||
| box-shadow 0.3s ease-in-out, | ||
| border 0.2s ease-in-out, | ||
| transform 0.4s; | ||
| } | ||
| .dyvix-table-ocean:hover { | ||
| border: 3px solid rgba(0, 150, 255, 0.6); | ||
| box-shadow: | ||
| 0 0 70px rgba(0, 100, 255, 0.25), | ||
| inset 0 0 40px rgba(0, 150, 255, 0.08); | ||
| -webkit-box-shadow: | ||
| 0 0 70px rgba(0, 100, 255, 0.25), | ||
| inset 0 0 40px rgba(0, 150, 255, 0.08); | ||
| -moz-box-shadow: | ||
| 0 0 70px rgba(0, 100, 255, 0.25), | ||
| inset 0 0 40px rgba(0, 150, 255, 0.08); | ||
| transform: translateY(-2px) scale(1.005); | ||
| } | ||
| .dyvix-table-neon { | ||
| border-radius: 1rem; | ||
| font-family: 'Geist'; | ||
| background: radial-gradient( | ||
| circle, | ||
| rgba(77, 238, 234, 0.15) 0%, | ||
| rgba(112, 186, 239, 0.1) 43%, | ||
| rgba(240, 0, 255, 0.15) 100% | ||
| ); | ||
| border: 2px solid rgba(77, 238, 234, 0.5); | ||
| color: #e0fffe; | ||
| box-shadow: | ||
| 0 0 40px rgba(252, 46, 255, 0.3), | ||
| 0 0 80px rgba(77, 238, 234, 0.1), | ||
| inset 0 0 20px rgba(112, 186, 239, 0.05); | ||
| -webkit-box-shadow: | ||
| 0 0 40px rgba(252, 46, 255, 0.3), | ||
| 0 0 80px rgba(77, 238, 234, 0.1), | ||
| inset 0 0 20px rgba(112, 186, 239, 0.05); | ||
| -moz-box-shadow: | ||
| 0 0 40px rgba(252, 46, 255, 0.3), | ||
| 0 0 80px rgba(77, 238, 234, 0.1), | ||
| inset 0 0 20px rgba(112, 186, 239, 0.05); | ||
| transition: | ||
| transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), | ||
| box-shadow 0.3s ease, | ||
| border-color 0.3s ease, | ||
| border-radius 0.2s ease-in-out; | ||
| } | ||
| .dyvix-table-neon:hover { | ||
| border-color: rgba(77, 238, 234, 0.8); | ||
| border-radius: 0.75rem; | ||
| box-shadow: | ||
| 0 0 60px rgba(252, 46, 255, 0.5), | ||
| 0 0 120px rgba(77, 238, 234, 0.2), | ||
| inset 0 0 30px rgba(112, 186, 239, 0.1); | ||
| -webkit-box-shadow: | ||
| 0 0 60px rgba(252, 46, 255, 0.5), | ||
| 0 0 120px rgba(77, 238, 234, 0.2), | ||
| inset 0 0 30px rgba(112, 186, 239, 0.1); | ||
| -moz-box-shadow: | ||
| 0 0 60px rgba(252, 46, 255, 0.5), | ||
| 0 0 120px rgba(77, 238, 234, 0.2), | ||
| inset 0 0 30px rgba(112, 186, 239, 0.1); | ||
| transform: translateY(-2px) scale(1.009); | ||
| } | ||
| .dyvix-table-blade { | ||
| border-radius: 0px; | ||
| font-family: 'Geist'; | ||
| background-color: #0a0a0a; | ||
| color: #e2e8f0; | ||
| border-left: 3px solid #e2e8f0; | ||
| border-top: 3px solid #e2e8f0; | ||
| border-right: 1px solid #ffffff20; | ||
| border-bottom: 1px solid #ffffff20; | ||
| box-shadow: -4px -4px 20px rgba(255, 255, 255, 0.05); | ||
| -webkit-box-shadow: -4px -4px 20px rgba(255, 255, 255, 0.05); | ||
| -moz-box-shadow: -4px -4px 20px rgba(255, 255, 255, 0.05); | ||
| transition: | ||
| border-left 0.1s ease-in-out, | ||
| border-top 0.1s ease-in-out, | ||
| box-shadow 0.2s ease-in-out, | ||
| transform 0.3s ease-in-out; | ||
| } | ||
| .dyvix-table-blade:hover { | ||
| border-left: 4px solid #ffffff; | ||
| border-top: 4px solid #ffffff; | ||
| box-shadow: -6px -6px 30px rgba(255, 255, 255, 0.1); | ||
| -webkit-box-shadow: -6px -6px 30px rgba(255, 255, 255, 0.1); | ||
| -moz-box-shadow: -6px -6px 30px rgba(255, 255, 255, 0.1); | ||
| transform: translateY(-2px) scale(1.005); | ||
| } | ||
| .dyvix-table-aurora { | ||
| font-family: 'Geist'; | ||
| background: linear-gradient(90deg, #14e81e 0%, #00ea8d 21%, #01b1b3 46%, #017ed5 76%, #b53dff 100%) border-box; | ||
| color: #e6fffb; | ||
| border-image: linear-gradient( | ||
| 90deg, | ||
| rgba(20, 232, 30, 1) 0%, | ||
| rgba(0, 234, 141, 1) 21%, | ||
| rgba(1, 177, 179, 1) 46%, | ||
| rgba(1, 126, 213, 1) 76%, | ||
| rgba(181, 61, 255, 1) 100% | ||
| ) | ||
| 1; | ||
| box-shadow: 0px 0px 35px 0px rgba(1, 176, 179, 0.35); | ||
| -webkit-box-shadow: 0px 0px 35px 0px rgba(1, 176, 179, 0.35); | ||
| -moz-box-shadow: 0px 0px 35px 0px rgba(1, 176, 179, 0.35); | ||
| transition: | ||
| box-shadow 0.4s ease-in-out, | ||
| -webkit-box-shadow 0.4s ease-in-out, | ||
| -moz-box-shadow 0.4s ease-in-out, | ||
| transform 0.3s ease-in-out; | ||
| } | ||
| .dyvix-table-aurora:hover { | ||
| box-shadow: 0px 0px 55px 0px rgba(1, 176, 179, 0.55); | ||
| -webkit-box-shadow: 0px 0px 55px 0px rgba(1, 176, 179, 0.55); | ||
| -moz-box-shadow: 0px 0px 55px 0px rgba(1, 176, 179, 0.55); | ||
| transform: translateY(-2px) scale(1.005); | ||
| } |
@@ -11,3 +11,38 @@ [ | ||
| "default-animation": "float" | ||
| }, | ||
| { | ||
| "theme": "Midnight", | ||
| "class": "dyvix-table-midnight", | ||
| "default-animation": "drift" | ||
| }, | ||
| { | ||
| "theme": "Forest", | ||
| "class": "dyvix-table-forest", | ||
| "default-animation": "glide" | ||
| }, | ||
| { | ||
| "theme": "Sunset", | ||
| "class": "dyvix-table-sunset", | ||
| "default-animation": "drop" | ||
| }, | ||
| { | ||
| "theme": "Ocean", | ||
| "class": "dyvix-table-ocean", | ||
| "default-animation": "flip" | ||
| }, | ||
| { | ||
| "theme": "Neon", | ||
| "class": "dyvix-table-neon", | ||
| "default-animation": "pulse" | ||
| }, | ||
| { | ||
| "theme": "Blade", | ||
| "class": "dyvix-table-blade", | ||
| "default-animation": "drift" | ||
| }, | ||
| { | ||
| "theme": "Aurora", | ||
| "class": "dyvix-table-aurora", | ||
| "default-animation": "aurora" | ||
| } | ||
| ] |
@@ -40,2 +40,3 @@ import React from 'react'; | ||
| const [configs, SetConfig] = React.useState({}); | ||
| const [sortConfig, setSortConfig] = React.useState([]); | ||
| const tableRef = React.useRef(); | ||
@@ -56,5 +57,54 @@ const [isValid, SetIsvalid] = React.useState(false); | ||
| }; | ||
| const processedData = React.useMemo(() => { | ||
| if (!data || !columns) return []; | ||
| if (!sortConfig.length) return data; | ||
| return [...data].sort((a, b) => { | ||
| for (const { key, direction } of sortConfig) { | ||
| if (direction === 'none') continue; | ||
| const aVal = a[key]; | ||
| const bVal = b[key]; | ||
| let result = 0; | ||
| if (typeof aVal === 'number' && typeof bVal === 'number') { | ||
| result = aVal - bVal; | ||
| } else { | ||
| result = String(aVal).localeCompare(String(bVal)); | ||
| } | ||
| if (result !== 0) return direction === 'asc' ? result : -result; | ||
| } | ||
| return 0; | ||
| }); | ||
| }, [columns, data, isValid, sortConfig]); | ||
| const ConstructTable = () => { | ||
| const bodyRows = data.map((row) => columns.map((col) => row[col.key])); | ||
| const bodyRows = processedData.map((row) => | ||
| columns.map((col) => row[col.key]) | ||
| ); | ||
| const handleSortClick = (key) => { | ||
| const isfound = sortConfig?.find((config) => config['key'] === key); | ||
| if (isfound) { | ||
| setSortConfig((prev) => | ||
| prev.map((config) => { | ||
| if (config.key !== key) return config; | ||
| if (config.direction === 'asc') | ||
| return { ...config, direction: 'desc' }; | ||
| if (config.direction === 'desc') | ||
| return { ...config, direction: 'none' }; | ||
| return { ...config, direction: 'asc' }; | ||
| }) | ||
| ); | ||
| } else { | ||
| const index = columns.findIndex((col) => col['key'] === key); | ||
| setSortConfig((prev) => [ | ||
| ...(prev || []), | ||
| { key: key, direction: 'asc', index: index } | ||
| ]); | ||
| } | ||
| }; | ||
| return ( | ||
@@ -65,5 +115,29 @@ <> | ||
| {columns.map((col, i) => { | ||
| const isColumnSortable = col.sortable === true; | ||
| const activeSort = isColumnSortable | ||
| ? sortConfig.find((config) => config.key === col.key) | ||
| : null; | ||
| let sortIndicator = null; | ||
| if (activeSort) { | ||
| if (activeSort.direction === 'asc') { | ||
| sortIndicator = ' ▲'; | ||
| } else if (activeSort.direction === 'desc') { | ||
| sortIndicator = ' ▼'; | ||
| } | ||
| } | ||
| return ( | ||
| <DyvixTableHead key={col.key || i}> | ||
| <DyvixTableHead | ||
| key={col.key || i} | ||
| {...(isColumnSortable && { | ||
| onClick: () => handleSortClick(col.key), | ||
| className: 'table-sortable' | ||
| })} | ||
| > | ||
| {typeof col === 'string' ? col : col.label} | ||
| {isColumnSortable && ( | ||
| <span className="dyvix-table-sort-icon"> | ||
| {sortIndicator || ' ↕'} | ||
| </span> | ||
| )} | ||
| </DyvixTableHead> | ||
@@ -115,3 +189,3 @@ ); | ||
| }; | ||
| }, [animation, columns, data]); | ||
| }, [animation, theme, columns, data]); | ||
| useGSAP(() => { | ||
@@ -128,3 +202,3 @@ if (!tableRef.current || !currentAnimation) return; | ||
| () => (columns && isValid ? ConstructTable() : null), | ||
| [columns, isValid] | ||
| [columns, isValid, sortConfig] | ||
| ); | ||
@@ -131,0 +205,0 @@ children = children ? children : resultJSX; |
@@ -69,3 +69,7 @@ import { | ||
| const isMalformed = columns.some( | ||
| (col) => typeof col !== 'object' || col === null || col.key === undefined | ||
| (col) => | ||
| typeof col !== 'object' || | ||
| col === null || | ||
| col.key === undefined || | ||
| (col.sortable !== undefined && typeof col.sortable !== 'boolean') | ||
| ); | ||
@@ -72,0 +76,0 @@ |
+1
-1
| export { default as Modal } from './components/modal/modal'; | ||
| export { default as DynamicSelect } from './components/select/SelectCompiler'; | ||
| export { default as DyvixSelect } from './components/select/SelectCompiler'; | ||
| export * from './constants'; | ||
@@ -4,0 +4,0 @@ export { default as DyvixToastContainer } from './components/toast/toastContainer'; |
@@ -16,2 +16,4 @@ import buttonThemesJSON from '../../components/button/dependencies/themes.json?raw'; | ||
| import tableThemesCSS from '../../components/table/dependencies/style/themes.css?raw'; | ||
| import selectThemesJSON from '../../components/select/dependencies/themes.json?raw'; | ||
| import selectThemesCSS from '../../components/select/dependencies/style/themes.css?raw'; | ||
@@ -27,3 +29,4 @@ export const JSON_LIBRARY = { | ||
| '../../components/label/dependencies/themes.json': labelThemesJSON, | ||
| '../../components/table/dependencies/themes.json': tableThemesJSON | ||
| '../../components/table/dependencies/themes.json': tableThemesJSON, | ||
| '../../components/select/dependencies/themes.json': selectThemesJSON | ||
| }; | ||
@@ -37,3 +40,4 @@ | ||
| '../../components/label/dependencies/style/themes.css': labelThemesCSS, | ||
| '../../components/table/dependencies/style/themes.css': tableThemesCSS | ||
| '../../components/table/dependencies/style/themes.css': tableThemesCSS, | ||
| '../../components/select/dependencies/style/themes.css': selectThemesCSS | ||
| }; |
193921
10.18%66
3.13%6449
9.75%