🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

dyvix-ui

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dyvix-ui - npm Package Compare versions

Comparing version
0.2.9
to
0.3.0
+25
src/components/toast/dependencies/style/positions.css
.dyvix-top-left {
top: 20px;
left: 20px;
}
.dyvix-top-right {
top: 20px;
right: 20px;
}
.dyvix-bottom-left {
bottom: 20px;
left: 20px;
}
.dyvix-bottom-right {
bottom: 20px;
right: 20px;
}
.dyvix-top-center {
top: 20px;
left: 50%;
transform: translateX(-50%);
}
+2
-0

@@ -16,1 +16,3 @@ # Contributors

- [@DevBadoory](https://github.com/DevBadoory)
- [@andoan16](https://github.com/andoan16)
- [@SlncTrZ](https://github.com/SlncTrZ)
+3
-2
{
"name": "dyvix-ui",
"version": "0.2.9",
"version": "0.3.0",
"description": "Dyvix is an open source, modern, config-driven, animated component UI library. Beautiful by default, customizable by design.",

@@ -34,3 +34,4 @@ "main": "src/index.jsx",

"@gsap/react": "^2.1.2",
"gsap": "^3.14.2"
"gsap": "^3.14.2",
"idb-keyval": "^6.2.2"
},

@@ -37,0 +38,0 @@ "scripts": {

@@ -15,5 +15,14 @@ <div align="center">

<p align="center">
<img src="https://raw.githubusercontent.com/younisdev/dyvix-ui/main/src/static/demo.gif" alt="Dyvix UI Demo" width="300" height="300" />
<img src="https://raw.githubusercontent.com/younisdev/dyvix-ui/main/src/static/demo.gif" alt="Dyvix UI Demo" width="350" height="300" />
</p>
## Features
- 🎨 **Multiple themes** - Singularity, Blade, Neon, Aurora, Sunset, Ocean, Forest, Midnight.
- ⚡ **Smart JSON Caching (SJC)** - Multi-tier (L1, L2, L3) system for near-zero latency delivery.
- ✨ **Rich animations** - bubble, fade, zoom, unfold, glitch.
- 🔧 **Config-driven components** - Flexible props for forms, modals, toasts
- ♿ **Accessible** - Built with accessibility in mind
- 📦 **Lightweight** - Minimal dependencies
# React

@@ -20,0 +29,0 @@

@@ -20,3 +20,3 @@ import React from 'react';

children = 'Click Me',
animation = 'fade',
animation = '!/',
className = '',

@@ -36,3 +36,2 @@ theme = '!/',

const currentAnimation = animation ? configs['animation'] : null;
function handleClick() {

@@ -39,0 +38,0 @@ if (typeof onClick === 'function') {

@@ -21,24 +21,25 @@ import {

export async function Validatebtn(animation, theme, callback, instance) {
const normalizedAnimation = animation?.trim().toLowerCase();
let normalizedAnimation = animation?.trim().toLowerCase();
const normalizedTheme =
theme?.trim().charAt(0).toUpperCase() + theme.trim().slice(1);
const [isAnimation, isTheme] = await Promise.all([
ValidatAndLoadJSON(
CacheMapping,
normalizedAnimation,
callback,
'animation',
component
),
ValidatAndLoadJSON(
CacheMapping,
normalizedTheme,
callback,
'theme',
component,
instance
)
]);
if (normalizedAnimation !== null && !isAnimation.status) {
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 {

@@ -45,0 +46,0 @@ status: GaurdStatus.Error,

@@ -8,5 +8,6 @@ .dyvix-file-lens {

-moz-box-shadow: 0 0 30px #b903e2;
transition: border-color 0.2s ease-in-out,
background 0.3s ease-in-out,
transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transition:
border-color 0.2s ease-in-out,
background 0.3s ease-in-out,
transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

@@ -18,3 +19,3 @@ .dyvix-file-lens p {

.dyvix-file-lens:hover {
border-color: #6a2a7a;
border-color: #6a2a7a;
background: rgb(47, 4, 47);

@@ -30,5 +31,6 @@ transform: scale(1.02);

background-color: #0a1429;
transition: border-radius 0.2s ease,
background-color 0.3s ease,
transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
transition:
border-radius 0.2s ease,
background-color 0.3s ease,
transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

@@ -42,3 +44,3 @@ .dyvix-file-industrial p {

border-radius: 10px;
background-color: #6b7280;
background-color: #6b7280;
transform: scale(1.03);

@@ -71,3 +73,5 @@ }

color: rgba(255, 69, 0, 0.9);
transition: color 0.2s ease-in-out, transform 0.22s ease-in-out;
transition:
color 0.2s ease-in-out,
transform 0.22s ease-in-out;
}

@@ -100,5 +104,6 @@ .dyvix-file-ember:hover {

-moz-box-shadow: -6px 2px 51px -7px rgba(213, 255, 248, 1) inset;
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 0.3s ease,
border-width 0.2s ease;
transition:
transform 0.4s cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 0.3s ease,
border-width 0.2s ease;
}

@@ -109,4 +114,4 @@ .dyvix-file-frost p {

transition:
text-shadow 0.3s ease-in-out,
color 0.2s ease-in-out;
text-shadow 0.3s ease-in-out,
color 0.2s ease-in-out;
}

@@ -169,5 +174,6 @@ .dyvix-file-frost:hover {

border-radius: 4rem;
transition: border-radius 0.2s ease-in-out,
transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
box-shadow 0.3s ease;
transition:
border-radius 0.2s ease-in-out,
transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
box-shadow 0.3s ease;
}

@@ -356,2 +362,2 @@ .dyvix-file-neon p {

transition: color 0.3s ease-in-out;
}
}

@@ -11,9 +11,9 @@ import React from 'react';

label = 'Upload File',
animation = '',
animation = '!/',
className = '',
theme = '',
theme = '!/',
background,
color,
multiple = false,
accept = "*/*",
accept = '*/*',
onUpload,

@@ -20,0 +20,0 @@ style,

@@ -21,24 +21,26 @@ import {

export async function Validatefile(animation, theme, callback, instance) {
const normalizedAnimation = animation?.trim().toLowerCase();
let normalizedAnimation = animation?.trim().toLowerCase();
const normalizedTheme =
theme?.trim().charAt(0).toUpperCase() + theme.trim().slice(1);
const [isAnimation, isTheme] = await Promise.all([
ValidatAndLoadJSON(
CacheMapping,
normalizedAnimation,
callback,
'animation',
component
),
ValidatAndLoadJSON(
CacheMapping,
normalizedTheme,
callback,
'theme',
component,
instance
)
]);
if (normalizedAnimation !== '' && !isAnimation.status) {
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 {

@@ -50,3 +52,3 @@ status: GaurdStatus.Error,

if (normalizedTheme !== '' && !isTheme.status) {
if (normalizedTheme !== '!/' && !isTheme.status) {
return {

@@ -53,0 +55,0 @@ status: GaurdStatus.Error,

@@ -9,3 +9,2 @@ [

"role": "textbox",
"aria-required": false,
"aria-label": ""

@@ -35,3 +34,2 @@ },

"role": "combobox",
"aria-required": false,
"aria-label": ""

@@ -52,3 +50,2 @@ },

"role": "combobox",
"aria-required": false,
"aria-label": ""

@@ -71,3 +68,2 @@ },

"role": "checkbox",
"aria-required": false,
"aria-label": ""

@@ -74,0 +70,0 @@ },

@@ -55,3 +55,75 @@ [

"default-title": "Login"
},
{
"preset": "ForgotPassword",
"fields": [
{
"type": "email",
"placeholder": "Email Address",
"validation": "email",
"id": "email",
"name": "email",
"amount": 1
}
],
"default-animation": "fade",
"default-theme": "Neon",
"default-title": "Forgot Password"
},
{
"preset": "ResetPassword",
"fields": [
{
"type": "password",
"placeholder": "New Password",
"validation": "password",
"id": "new-password",
"name": "newPassword",
"amount": 1
},
{
"type": "password",
"placeholder": "Confirm Password",
"id": "confirm-password",
"name": "confirmPassword",
"match": "new-password",
"amount": 1
}
],
"default-animation": "fade",
"default-theme": "Neon",
"default-title": "Reset Password"
},
{
"preset": "ChangePassword",
"fields": [
{
"type": "password",
"placeholder": "Current Password",
"validation": "password",
"id": "current-password",
"name": "currentPassword",
"amount": 1
},
{
"type": "password",
"placeholder": "New Password",
"validation": "password",
"id": "new-password",
"name": "newPassword",
"amount": 1
},
{
"type": "password",
"placeholder": "Confirm New Password",
"id": "confirm-new-password",
"name": "confirmNewPassword",
"match": "new-password",
"amount": 1
}
],
"default-animation": "fade",
"default-theme": "Neon",
"default-title": "Change Password"
}
]

@@ -19,3 +19,2 @@ export function ExecuteValidator(value, validators) {

export function ExecuteRegex(value, Rgx, errorMsg = 'Invalid format') {
console.log(Rgx);
const Regex = new RegExp(Rgx);

@@ -70,3 +69,11 @@ return { status: Regex.test(value), error: errorMsg };

error: 'Please enter a valid URL (e.g., https://example.com).'
}),
isRequired: (value, options = {}) => ({
status: value !== null && value !== undefined && String(value).trim().length > 0,
error: 'This field is required.'
}),
isDate: (value, options = {}) => ({
status: !isNaN(Date.parse(value)),
error: 'Please enter a valid date.'
})
};

@@ -17,3 +17,11 @@ [

"validators": ["isURL"]
},
{
"preset": "mandatory",
"validators": ["isRequired"]
},
{
"preset": "date",
"validators": ["isDate"]
}
]

@@ -33,2 +33,3 @@ import { validType, eleData, validRules } from './modal';

id: '!/',
match: '!/',
className: '!/',

@@ -108,3 +109,14 @@ validation: '!/',

) {
const [isAnimation, isTheme, isPreset] = await Promise.all([
const isTheme = await ValidatAndLoadJSON(
CacheMapping,
theme,
callback,
'theme',
component,
instance
);
if (animation === '!/') {
animation = isTheme.config.theme['default-animation'];
}
const [isAnimation, isPreset] = await Promise.all([
ValidatAndLoadJSON(

@@ -117,10 +129,2 @@ CacheMapping,

),
ValidatAndLoadJSON(
CacheMapping,
theme,
callback,
'theme',
component,
instance
),
ValidatAndLoadJSON(CacheMapping, preset, callback, 'preset', component)

@@ -297,2 +301,18 @@ ]);

}
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 {
status: GaurdStatus.Error,
error: `'${matchId}' is not a recognized target for matching.`
};
}
}
}
}

@@ -320,3 +340,5 @@

validation:
typeof ele.validation === 'string' ? [ele.validation] : ele.validation
typeof ele.validation === 'string' ? [ele.validation] : ele.validation,
match:
typeof ele.match === 'string' ? [ele.match] : ele.match,
}));

@@ -344,2 +366,2 @@ }

return { status: GaurdStatus.Success };
}
}

@@ -64,9 +64,10 @@ import elementsData from './dependencies/elements.json';

const [configs, SetConfig] = React.useState({});
const [fields, SetFields] = React.useState(null);
const [fields, SetFields] = React.useState([]);
const instanceId = React.useId();
const modalRef = React.useRef(null);
function handleInputChange(name, value) {
const validation = handleValidation();
const nextData = { ...data, [name]: value };
SetData(nextData);
const validation = handleValidation(nextData);
if (typeof onChange === 'function') {

@@ -82,7 +83,36 @@ onChange(nextData);

}
function handleValidation() {
function handleValidation(data) {
const newErrors = {};
for (const field of fields) {
if (Array.isArray(field.match)) {
for (const [i, matchTo] of field.match.entries()) {
if (matchTo) {
const matchToFields = fields.find((f) => f.id.includes(matchTo));
if (matchToFields) {
const matchToIndex = matchToFields.id.findIndex(
(f) => f === matchTo
);
const matchToName = matchToFields.name[matchToIndex];
const matchToPlaceholder = matchToFields.placeholder[matchToIndex];
const sourceValue = data[field.name[i]];
const targetValue = data[matchToName];
const serializeLabel = (str) => {
if (!str) return 'Field';
return str
.replace(/^(Enter|Type|Provide|Input|Your|Confirm)\s+/gi, '')
.trim();
};
const sourceLabel = serializeLabel(field.placeholder[i]);
const targetLabel = serializeLabel(matchToPlaceholder);
if (sourceValue && targetValue && sourceValue !== targetValue) {
newErrors[field.name[i]] =
`${sourceLabel} must match ${targetLabel}`;
}
}
}
}
}
if (!field.validation) continue;
for (const [index, currentName] of field.name.entries()) {
if (newErrors[currentName]) continue;
let currentValidation = field.validation[index];

@@ -107,3 +137,5 @@ let result = null;

if (result) {
newErrors[currentName] = result.status ? null : result.error;
if (!newErrors[currentName]) {
newErrors[currentName] = result.status ? null : result.error;
}
}

@@ -115,5 +147,6 @@ }

function handleSubmit() {
const validation = handleValidation();
const validation = handleValidation(data);
const allow = Object.values(errors).every(val => val === null) && Object.keys(errors).length > 0;
if (typeof onSubmit === 'function') {
if (typeof onSubmit === 'function' && allow) {
onSubmit(data);

@@ -127,5 +160,3 @@ }

const currentTheme = configs['theme'];
const animationQuery =
animation === '!/' ? currentTheme?.['default-animation'] : animation;
const currentAnimation = configs['animation']; // add default animation for this new update
const currentAnimation = configs['animation'];
const currentPreset = configs['preset'];

@@ -238,3 +269,9 @@ const serilaizedclassName =

{visibility && (
<div ref={modalRef} className="dyvix-modal-wrapper">
<div
ref={modalRef}
className="dyvix-modal-wrapper"
role="dialog"
aria-modal="true"
aria-labelledby="modal-header"
>
<div

@@ -317,3 +354,7 @@ className={`modal ${serilaizedclassName}`}

: [];
const fieldError = errors[name];
const ErrorId =
`${id && id !== '!/' ? id : field.placeholder[j]}-error`
.toLowerCase()
.replace(/[^a-z0-9-]/g, '-');
const Tagprobs = {

@@ -329,3 +370,4 @@ className: `modal-element ` + elementDef['default-class'],

...(elementDef['supports-placeholder'] && {
placeholder: field.placeholder[j]
placeholder: field.placeholder[j],
'aria-label': field.placeholder[j]
}),

@@ -341,5 +383,7 @@ ...(elementDef['supports_type'] && { type: field.type }),

className: 'modal-element'
}),
...(ErrorId && {
'aria-describedby': ErrorId
})
};
const fieldError = errors[name];

@@ -396,3 +440,5 @@ return (

)}
<span className="dyvix-error-text">{fieldError}</span>
<span className="dyvix-error-text" id={ErrorId}>
{fieldError}
</span>
</div>

@@ -399,0 +445,0 @@ );

@@ -5,3 +5,5 @@ const listeners = [];

success: (message) => emit({ message: message, type: 'Success' }),
error: (message) => emit({ message: message, type: 'Error' })
error: (message) => emit({ message: message, type: 'Error' }),
warning: (message) => emit({ message: message, type: 'Warning' }),
info: (message) => emit({ message: message, type: 'Info' })
};

@@ -8,0 +10,0 @@

@@ -33,2 +33,12 @@ .dyvix-toast-container {

}
.dyvix-toast-warning {
background-color: #fff3cd;
border: 1px solid rgba(255, 193, 7, 0.3);
}
.dyvix-toast-info {
background-color: #d1ecf1;
border: 1px solid rgba(23, 162, 184, 0.3);
}
.dyvix-toast-title {

@@ -66,2 +76,10 @@ width: 100%;

}
.toast-warning {
color: #ffc107;
}
.toast-info {
color: #17a2b8;
}
.toast-error .dyvix-toast-icon {

@@ -75,28 +93,11 @@ border-color: #ff3366;

}
/* move to positions.css ? */
.dyvix-top-right {
top: 1rem;
right: 1rem;
.toast-warning .dyvix-toast-icon {
border-color: #ffc107;
box-shadow: inset 0 0 4px rgba(5, 3, 2, 0.848);
}
.dyvix-top-left {
top: 1rem;
left: 1rem;
}
.dyvix-bottom-right {
bottom: 1rem;
right: 1rem;
}
.dyvix-bottom-left {
bottom: 1rem;
left: 1rem;
}
.dyvix-top-center {
top: 1rem;
left: 50%;
transform: translateX(-50%);
}
.dyvix-bottom-center {
bottom: 1rem;
left: 50%;
transform: translateX(-50%);
}
.toast-info .dyvix-toast-icon {
border-color: #17a2b8;
box-shadow: inset 0 0 4px rgba(2, 3, 5, 0.848);
}

@@ -9,3 +9,11 @@ [

"class": "dyvix-toast-success"
},
{
"type": "Warning",
"class": "dyvix-toast-warning"
},
{
"type": "Info",
"class": "dyvix-toast-info"
}
]
import './dependencies/style/style.css';
import './dependencies/style/positions.css';
import positionData from './dependencies/positions.json';

@@ -3,0 +4,0 @@ import TypesData from './dependencies/types.json';

//AUTO GENERATED BY DYVIX UI ENGINE - DO NOT MANUALLY EDIT.
/**
* @deprecated Use DYVIX_GLOBAL_THEME instead.
* This will be removed in V0.3.0.
*/
export const DYVIX_MODAL_THEME =
{
"SINGULARITY": "Singularity",
"INDUSTRIAL": "Industrial",
"EMBER": "Ember",
"FROST": "Frost",
"BLADE": "Blade",
"NEON": "Neon",
"AURORA": "Aurora",
"SUNSET": "Sunset",
"OCEAN": "Ocean",
"FOREST": "Forest",
"MIDNIGHT": "Midnight"
}
export const DYVIX_GLOBAL_THEME =

@@ -59,3 +41,5 @@ {

"NUMBER": "number",
"URL": "url"
"URL": "url",
"MANDATORY": "mandatory",
"DATE": "date"
}

@@ -78,3 +62,6 @@ export const DYVIX_MODAL_ELEMENT =

"REGISTER": "Register",
"LOGIN": "Login"
"LOGIN": "Login",
"FORGOTPASSWORD": "ForgotPassword",
"RESETPASSWORD": "ResetPassword",
"CHANGEPASSWORD": "ChangePassword"
}
import { EvaluateFailure, GaurdStatus } from '../DyvixGuard';
import Version from '../../../package.json';
import { set, get } from 'idb-keyval';

@@ -76,5 +77,5 @@ export const CACHETYPE = { CSS: 'css', Default: 'default' };

let keys = [key + '_L1', key + '_L2', key + '_L3'];
if (localStorage.getItem(keys[2])) {
const cachedData = JSON.parse(localStorage.getItem(keys[2]));
const cachedData = await get(keys[2]);
if (cachedData) {
JsonArray = cachedData.JSON;

@@ -95,3 +96,3 @@ rawCSS = cachedData.CSS;

localStorage.setItem(keys[2], JSON.stringify(value));
await set(keys[2], value);

@@ -98,0 +99,0 @@ if (!jsonResult) {