| .dyvix-input-wrapper { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 5px; | ||
| position: relative; | ||
| max-width: 250px; | ||
| width: 100%; | ||
| } | ||
| .dyvix-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); | ||
| } | ||
| .dyvix-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); | ||
| } | ||
| .dyvix-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-input::placeholder { | ||
| color: rgba(255, 255, 255, 0.2); | ||
| font-size: 0.9rem; | ||
| } |
| [ | ||
| { | ||
| "type": "text", | ||
| "class": "dyvix-input-text" | ||
| }, | ||
| { | ||
| "type": "password", | ||
| "class": "dyvix-input-password" | ||
| }, | ||
| { | ||
| "type": "email", | ||
| "class": "dyvix-input-email" | ||
| }, | ||
| { | ||
| "type": "number", | ||
| "class": "dyvix-input-number" | ||
| }, | ||
| { | ||
| "type": "tel", | ||
| "class": "dyvix-input-tel" | ||
| }, | ||
| { | ||
| "type": "url", | ||
| "class": "dyvix-input-url" | ||
| }, | ||
| { | ||
| "type": "search", | ||
| "class": "dyvix-input-search" | ||
| }, | ||
| { | ||
| "type": "date", | ||
| "class": "dyvix-input-date" | ||
| }, | ||
| { | ||
| "type": "datetime-local", | ||
| "class": "dyvix-input-datetime" | ||
| } | ||
| ] |
| import gsap from 'gsap'; | ||
| import { useGSAP } from '@gsap/react'; | ||
| import './dependencies/style/style.css'; | ||
| import React from 'react'; | ||
| import { Validateinput } from './validation'; | ||
| /** | ||
| * @param {Object} props | ||
| * @param {string} [props.type] - Input type, defaults to 'text' | ||
| * @param {string} [props.placeholder] - Input placeholder text | ||
| * @param {string} [props.autoComplete] - Input autoComplete attribute | ||
| * @param {string} [props.background] - Input background color | ||
| * @param {string} [props.color] - Input color | ||
| * @param {string} [props.animation] - Animation name, defaults to fade | ||
| * @param {string} [props.className] - Input className | ||
| * @param {string} [props.name] - Input name | ||
| * @param {string} [props.id] - Input id | ||
| * @param {boolean} [props.disabled] - Disables the input when true | ||
| * @param {string} [props['aria-label']] - Accessible label for the input | ||
| * @param {Function} [props.onFocus] - Focus event callback | ||
| * @param {Function} [props.onBlur] - Blur event callback | ||
| * @param {Function} [props.onChange] - Change event callback, receives the event object | ||
| * @param {Object} [props.style] - Inline style overrides | ||
| */ | ||
| function DyvixInput({ | ||
| type = 'text', | ||
| placeholder, | ||
| autoComplete, | ||
| background, | ||
| color, | ||
| animation = 'fade', | ||
| className = '', | ||
| name, | ||
| id, | ||
| disabled, | ||
| 'aria-label': ariaLabel, | ||
| onFocus, | ||
| onBlur, | ||
| onChange, | ||
| style, | ||
| ...rest | ||
| }) { | ||
| const inputRef = React.useRef(null); | ||
| const [configs, SetConfig] = React.useState({}); | ||
| const instanceId = React.useId(); | ||
| React.useEffect(() => { | ||
| async function GetFields() { | ||
| const data = await Validateinput( | ||
| animation, | ||
| '', | ||
| type, | ||
| SetConfig, | ||
| instanceId | ||
| ); | ||
| } | ||
| GetFields(); | ||
| }, [type, animation]); | ||
| const currentAnimation = animation ? configs['animation'] : null; | ||
| const currentType = type ? configs['type'] : null; | ||
| const inputClasses = | ||
| `dyvix-input ${currentType?.class ?? ''} ${className}`.trim(); | ||
| const props = { | ||
| className: inputClasses, | ||
| type: currentType?.type, | ||
| ...(placeholder && { placeholder: placeholder }), | ||
| ...(name && { name: name }), | ||
| ...(id && { id: id }), | ||
| ...(autoComplete && { autoComplete: autoComplete }), | ||
| ...(disabled === true && { disabled: true }), | ||
| ...(ariaLabel && { 'aria-label': ariaLabel }), | ||
| style: { | ||
| ...(background && { background: background }), | ||
| ...(color && { color: color }), | ||
| ...style | ||
| } | ||
| }; | ||
| function handleBlur(e) { | ||
| if (typeof onBlur === 'function') { | ||
| onBlur(e); | ||
| } | ||
| } | ||
| function handleFocus(e) { | ||
| if (typeof onFocus === 'function') { | ||
| onFocus(e); | ||
| } | ||
| } | ||
| function handleChange(e) { | ||
| if (typeof onChange === 'function') { | ||
| onChange(e); | ||
| } | ||
| } | ||
| useGSAP(() => { | ||
| if (!inputRef.current || !currentAnimation) return; | ||
| gsap.fromTo(inputRef.current, currentAnimation.from, { | ||
| ...currentAnimation.to, | ||
| duration: currentAnimation['default-duration'], | ||
| ease: currentAnimation.ease | ||
| }); | ||
| }, [currentAnimation]); | ||
| return ( | ||
| <div className="dyvix-input-wrapper" ref={inputRef} {...rest}> | ||
| <input | ||
| {...props} | ||
| onFocus={(e) => handleFocus(e)} | ||
| onBlur={(e) => handleBlur(e)} | ||
| onChange={(e) => handleChange(e)} | ||
| ></input> | ||
| </div> | ||
| ); | ||
| } | ||
| export default DyvixInput; |
| import { | ||
| EvaluateFailure, | ||
| GaurdStatus, | ||
| allowsNull | ||
| } from '../../utils/DyvixGuard'; | ||
| import { ValidatAndLoadJSON } from '../../utils/Smart Json Caching/SJCManager'; | ||
| const component = 'Input'; | ||
| const CacheMapping = { | ||
| theme: { | ||
| jsonpath: '../../components/input/dependencies/themes.json', | ||
| csspath: '../../components/input/dependencies/style/themes.css' | ||
| }, | ||
| type: { | ||
| jsonpath: '../../components/input/dependencies/types.json', | ||
| csspath: null | ||
| }, | ||
| animation: { | ||
| jsonpath: '../../components/animations.json', | ||
| csspath: null | ||
| } | ||
| }; | ||
| export async function Validateinput( | ||
| animation, | ||
| theme, | ||
| type, | ||
| callback, | ||
| instance | ||
| ) { | ||
| let normalizedAnimation = animation?.trim().toLowerCase(); | ||
| let normalizedType = type?.trim().toLowerCase(); | ||
| const [isAnimation, isType] = await Promise.all([ | ||
| ValidatAndLoadJSON( | ||
| CacheMapping, | ||
| normalizedAnimation, | ||
| callback, | ||
| 'animation', | ||
| component | ||
| ), | ||
| ValidatAndLoadJSON( | ||
| CacheMapping, | ||
| normalizedType, | ||
| callback, | ||
| 'type', | ||
| component | ||
| ) | ||
| ]); | ||
| if (!isAnimation.status && !allowsNull(normalizedAnimation)) { | ||
| return { | ||
| status: GaurdStatus.Error, | ||
| error: 'Please provide a valid animation.' | ||
| }; | ||
| } | ||
| if (!isType.status && !allowsNull(normalizedType)) { | ||
| return { | ||
| status: GaurdStatus.Error, | ||
| error: 'Please provide a valid type.' | ||
| }; | ||
| } | ||
| return { status: GaurdStatus.Success }; | ||
| } |
| import buttonThemesJSON from '../../components/button/dependencies/themes.json?raw'; | ||
| import buttonThemesCSS from '../../components/button/dependencies/style/themes.css?raw'; | ||
| import modalThemesJSON from '../../components/modal/dependencies/themes.json?raw'; | ||
| import modalThemesCSS from '../../components/modal/dependencies/style/themes.css?raw'; | ||
| import modalPresetsJSON from '../../components/modal/dependencies/presets.json?raw'; | ||
| import animationsJSON from '../../components/animations.json?raw'; | ||
| import fileThemesJSON from '../../components/file/dependencies/themes.json?raw'; | ||
| import fileThemesCSS from '../../components/file/dependencies/style/themes.css?raw'; | ||
| import inputTypesJSON from '../../components/input/dependencies/types.json?raw'; | ||
| export const JSON_LIBRARY = { | ||
| '../../components/button/dependencies/themes.json': buttonThemesJSON, | ||
| '../../components/modal/dependencies/themes.json': modalThemesJSON, | ||
| '../../components/modal/dependencies/presets.json': modalPresetsJSON, | ||
| '../../components/animations.json': animationsJSON, | ||
| '../../components/file/dependencies/themes.json': fileThemesJSON, | ||
| '../../components/input/dependencies/types.json': inputTypesJSON | ||
| }; | ||
| export const CSS_LIBRARY = { | ||
| '../../components/button/dependencies/style/themes.css': buttonThemesCSS, | ||
| '../../components/modal/dependencies/style/themes.css': modalThemesCSS, | ||
| '../../components/file/dependencies/style/themes.css': fileThemesCSS | ||
| }; |
+7
-6
| { | ||
| "name": "dyvix-ui", | ||
| "version": "0.3.0", | ||
| "version": "0.3.1", | ||
| "description": "Dyvix is an open source, modern, config-driven, animated component UI library. Beautiful by default, customizable by design.", | ||
@@ -12,4 +12,4 @@ "main": "src/index.jsx", | ||
| "peerDependencies": { | ||
| "react": "^19.2.4", | ||
| "react-dom": "^19.2.4" | ||
| "react": "^19.2.6", | ||
| "react-dom": "^19.2.6" | ||
| }, | ||
@@ -19,4 +19,4 @@ "devDependencies": { | ||
| "prettier": "^3.8.1", | ||
| "react": "^19.2.4", | ||
| "react-dom": "^19.2.4", | ||
| "react": "^19.2.6", | ||
| "react-dom": "^19.2.6", | ||
| "vite": "8.0.8", | ||
@@ -37,3 +37,4 @@ "vitepress": "^1.6.4" | ||
| "gsap": "^3.14.2", | ||
| "idb-keyval": "^6.2.2" | ||
| "idb-keyval": "^6.2.2", | ||
| "sugar-high": "^1.1.0" | ||
| }, | ||
@@ -40,0 +41,0 @@ "scripts": { |
@@ -28,2 +28,17 @@ [ | ||
| { | ||
| "element": "textarea", | ||
| "tag": "textarea", | ||
| "default-class": "modal-textarea", | ||
| "aria": { | ||
| "role": "textbox", | ||
| "aria-label": "" | ||
| }, | ||
| "supports-placeholder": true, | ||
| "supports_type": false, | ||
| "supports_autocomplete": true, | ||
| "is_custom": false, | ||
| "requires-options": false, | ||
| "r-variant": true | ||
| }, | ||
| { | ||
| "element": "select", | ||
@@ -30,0 +45,0 @@ "tag": "select", |
@@ -184,1 +184,6 @@ .dyvix-modal-wrapper { | ||
| } | ||
| .modal-textarea { | ||
| max-height: 70px; | ||
| min-height: 35px; | ||
| resize: vertical; | ||
| } |
@@ -70,3 +70,4 @@ export function ExecuteValidator(value, validators) { | ||
| isRequired: (value, options = {}) => ({ | ||
| status: value !== null && value !== undefined && String(value).trim().length > 0, | ||
| status: | ||
| value !== null && value !== undefined && String(value).trim().length > 0, | ||
| error: 'This field is required.' | ||
@@ -73,0 +74,0 @@ }), |
@@ -9,2 +9,3 @@ import { validType, eleData, validRules } from './modal'; | ||
| import { ValidatAndLoadJSON } from '../../utils/Smart Json Caching/SJCManager'; | ||
| import { DYVIX_MODAL_PRESET, DYVIX_MODAL_TYPE } from '../../constants'; | ||
@@ -39,17 +40,11 @@ const CacheMapping = { | ||
| }; | ||
| // auto generate these soon | ||
| const supportedTypes = [ | ||
| 'text', | ||
| 'select', | ||
| 'd-select', | ||
| 'autocomplete', | ||
| 'email', | ||
| 'password', | ||
| 'search', | ||
| 'url', | ||
| 'tel', | ||
| 'checkbox' | ||
| ]; | ||
| let supportedTypes = null; | ||
| let config = null; | ||
| async function getSupportedElements() { | ||
| const { DYVIX_MODAL_ELEMENT } = await import('../../constants.js'); | ||
| return Object.values(DYVIX_MODAL_ELEMENT) | ||
| } | ||
| export async function SerializeData( | ||
@@ -81,2 +76,3 @@ title, | ||
| ); | ||
| supportedTypes= await getSupportedElements(); | ||
@@ -301,11 +297,11 @@ if (validator.status === GaurdStatus.Error) { | ||
| } | ||
| if(element.match && element.match !== "!/") | ||
| { | ||
| const matchTargets = typeof element.match === 'string' ? [element.match] : element.match; | ||
| for(const matchId of matchTargets) | ||
| { | ||
| if (matchId === "!/") continue; | ||
| const exist = elements.find(e => Array.isArray(e.id) ? e.id.includes(matchId): e.id === matchId) | ||
| if(!exist) | ||
| { | ||
| if (element.match && element.match !== '!/') { | ||
| const matchTargets = | ||
| typeof element.match === 'string' ? [element.match] : element.match; | ||
| for (const matchId of matchTargets) { | ||
| if (matchId === '!/') continue; | ||
| const exist = elements.find((e) => | ||
| Array.isArray(e.id) ? e.id.includes(matchId) : e.id === matchId | ||
| ); | ||
| if (!exist) { | ||
| return { | ||
@@ -341,4 +337,3 @@ status: GaurdStatus.Error, | ||
| typeof ele.validation === 'string' ? [ele.validation] : ele.validation, | ||
| match: | ||
| typeof ele.match === 'string' ? [ele.match] : ele.match, | ||
| match: typeof ele.match === 'string' ? [ele.match] : ele.match | ||
| })); | ||
@@ -366,2 +361,2 @@ } | ||
| return { status: GaurdStatus.Success }; | ||
| } | ||
| } |
@@ -94,3 +94,4 @@ import elementsData from './dependencies/elements.json'; | ||
| const matchToName = matchToFields.name[matchToIndex]; | ||
| const matchToPlaceholder = matchToFields.placeholder[matchToIndex]; | ||
| const matchToPlaceholder = | ||
| matchToFields.placeholder[matchToIndex]; | ||
| const sourceValue = data[field.name[i]]; | ||
@@ -146,3 +147,5 @@ const targetValue = data[matchToName]; | ||
| const validation = handleValidation(data); | ||
| const allow = Object.values(errors).every(val => val === null) && Object.keys(errors).length > 0; | ||
| const allow = | ||
| Object.values(errors).every((val) => val === null) && | ||
| Object.keys(errors).length > 0; | ||
@@ -149,0 +152,0 @@ if (typeof onSubmit === 'function' && allow) { |
@@ -25,2 +25,2 @@ .dyvix-top-left { | ||
| transform: translateX(-50%); | ||
| } | ||
| } |
@@ -100,2 +100,2 @@ .dyvix-toast-container { | ||
| box-shadow: inset 0 0 4px rgba(2, 3, 5, 0.848); | ||
| } | ||
| } |
+1
-0
@@ -53,2 +53,3 @@ //AUTO GENERATED BY DYVIX UI ENGINE - DO NOT MANUALLY EDIT. | ||
| "TEL": "tel", | ||
| "TEXTAREA": "textarea", | ||
| "SELECT": "select", | ||
@@ -55,0 +56,0 @@ "D_SELECT": "d-select", |
+1
-0
@@ -8,1 +8,2 @@ export { default as Modal } from './components/modal/modal'; | ||
| export { default as DyvixFile } from './components/file/file'; | ||
| export { default as DyvixInput } from './components//input/input'; |
| import { EvaluateFailure, GaurdStatus } from '../DyvixGuard'; | ||
| import Version from '../../../package.json'; | ||
| import { set, get } from 'idb-keyval'; | ||
| import { CSS_LIBRARY, JSON_LIBRARY } from './SJCRegistry'; | ||
| export const CACHETYPE = { CSS: 'css', Default: 'default' }; | ||
@@ -78,3 +78,3 @@ const VERSION = Version['version']; | ||
| const cachedData = await get(keys[2]); | ||
| if (cachedData) { | ||
@@ -85,3 +85,4 @@ JsonArray = cachedData.JSON; | ||
| const rawJSONText = await extractFile(jsonpath); | ||
| JsonArray = JSON.parse(rawJSONText); | ||
| JsonArray = | ||
| typeof rawJSONText === 'string' ? JSON.parse(rawJSONText) : rawJSONText; | ||
| if (type === CACHETYPE.CSS) { | ||
@@ -201,11 +202,35 @@ rawCSS = await extractFile(csspath); | ||
| async function extractFile(path) { | ||
| if (!path) { | ||
| console.warn('DyvixUI: Invalid path'); | ||
| return null; | ||
| } | ||
| let content = null; | ||
| if (path.endsWith('.css')) { | ||
| content = CSS_LIBRARY[path]; | ||
| } else if (path.endsWith('.json')) { | ||
| content = JSON_LIBRARY[path]; | ||
| } | ||
| if (content) return content; | ||
| // dev fallback only | ||
| try { | ||
| const module = await import(/* @vite-ignore */ `${path}?raw`); | ||
| return module.default || module; | ||
| } catch (error) { | ||
| console.log('DyvixUI Sys error'); | ||
| const response = await fetch(path); | ||
| if (!response.ok) { | ||
| console.warn(`DyvixUI: Content not found at ${path}`); | ||
| return null; | ||
| } | ||
| const text = await response.text(); | ||
| if (text.trim().startsWith('<')) { | ||
| console.warn(`DyvixUI: Got HTML instead of content at ${path}`); | ||
| return null; | ||
| } | ||
| return text; | ||
| } catch { | ||
| console.warn(`DyvixUI: Failed to fetch ${path}`); | ||
| return null; | ||
| } | ||
| } | ||
| function generateCacheKey(component, utility) { | ||
@@ -220,8 +245,3 @@ const key = `DYVIX_${VERSION}_${component}_${utility}`; | ||
| if (Csspath !== null) { | ||
| try { | ||
| const module = await import(/* @vite-ignore */ `${Csspath}?raw`); | ||
| rawCSS = module.default || module; | ||
| } catch (error) { | ||
| console.log('DyvixUI Sys error'); | ||
| } | ||
| rawCSS = extractFile(Csspath); | ||
| } else if (cssblock !== null) { | ||
@@ -228,0 +248,0 @@ rawCSS = cssblock; |
Network access
Supply chain riskThis module accesses the network.
130540
7.44%47
11.9%4304
7.76%6
20%1
Infinity%+ Added
+ Added