UNPKG

@rxxuzi/gumi

Version:

Clean & minimal design system with delightful interactions

376 lines 12.9 kB
// gumi.ts // Gumi.js v1.0.0 - Main Entry Point // Core utilities import * as dom from './core/dom'; import * as animation from './core/animation'; // Components import { ThemeManager } from './components/theme'; import { Modal } from './components/modal'; import { Toast } from './components/toast'; import { Tabs } from './components/tabs'; import { Accordion } from './components/accordion'; import { Dropdown } from './components/dropdown'; import { Progress } from './components/progress'; import { FormValidator } from './components/form'; import { Sidebar } from './components/sidebar'; import { CodeCopy } from './components/code-copy'; // Utils import * as helpers from './utils/helpers'; import { icons } from './utils/icons'; // Main Gumi object class Gumi { constructor() { this.version = '1.0.0'; this.modals = new Map(); this.dropdowns = new Map(); this.tabs = new Map(); this.accordions = new Map(); this.sidebars = new Map(); // DOM utilities this.$ = dom.$; this.$$ = dom.$$; this.ready = dom.ready; this.on = dom.on; this.off = dom.off; this.trigger = dom.trigger; this.createElement = dom.createElement; // Animation methods this.animate = animation.animate; this.fadeIn = animation.fadeIn; this.fadeOut = animation.fadeOut; this.slideUp = animation.slideUp; this.slideDown = animation.slideDown; this.scaleIn = animation.scaleIn; this.scaleOut = animation.scaleOut; this.slideIn = animation.slideIn; this.bounce = animation.bounce; this.shake = animation.shake; this.pulse = animation.pulse; // Utility methods this.show = dom.show; this.hide = dom.hide; this.toggle = dom.toggle; // Helpers this.debounce = helpers.debounce; this.throttle = helpers.throttle; this.copyToClipboard = helpers.copyToClipboard; // Icons this.icons = icons; this.theme = new ThemeManager(); this.init(); } /** * Initialize Gumi.js */ init() { dom.ready(() => { // Setup smooth scroll this.setupSmoothScroll(); // Setup focus rings this.setupFocusRings(); // Setup preloaded animations this.setupPreloadedAnimations(); // Initialize components this.initializeComponents(); console.log(`🍬 Gumi.js v${this.version} initialized`); }); } /** * Setup smooth scrolling for anchor links */ setupSmoothScroll() { dom.on(document, 'click', 'a[href^="#"]', (e) => { e.preventDefault(); const target = e.target; const link = target.closest('a[href^="#"]'); if (!link) return; const href = link.getAttribute('href'); if (!href) return; const targetEl = dom.$(href); if (targetEl) { targetEl.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); } /** * Setup enhanced focus rings */ setupFocusRings() { let isKeyboard = false; dom.on(document, 'keydown', () => { isKeyboard = true; }); dom.on(document, 'mousedown', () => { isKeyboard = false; }); dom.on(document, 'focusin', (e) => { if (isKeyboard) { dom.addClass(e.target, 'gumi-focus-visible'); } }); dom.on(document, 'focusout', (e) => { dom.removeClass(e.target, 'gumi-focus-visible'); }); } /** * Setup animations triggered by CSS classes */ setupPreloadedAnimations() { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const el = entry.target; if (el.classList.contains('gumi-fade-in')) { animation.fadeIn(el); } if (el.classList.contains('gumi-slide-up')) { el.style.transform = 'translateY(30px)'; el.style.opacity = '0'; animation.animate(el, [ { transform: 'translateY(30px)', opacity: 0 }, { transform: 'translateY(0)', opacity: 1 } ], { duration: 600 }); } if (el.classList.contains('gumi-slide-down')) { animation.slideDown(el); } if (el.classList.contains('gumi-scale-in')) { animation.scaleIn(el); } observer.unobserve(el); } }); }, { threshold: 0.1 }); const animatedElements = dom.$$('.gumi-fade-in, .gumi-slide-up, .gumi-slide-down, .gumi-scale-in'); animatedElements.forEach(el => observer.observe(el)); } /** * Initialize all components */ initializeComponents() { // Initialize modals Modal.initFromTriggers('[data-modal]').forEach(modal => { const id = modal.element.id; if (id) this.modals.set(id, modal); }); // Initialize dropdowns Dropdown.initFromAttributes('[data-dropdown]').forEach(dropdown => { const id = helpers.generateId('dropdown'); this.dropdowns.set(id, dropdown); }); // Initialize tabs Tabs.initAll('.tabs').forEach(tabs => { const id = helpers.generateId('tabs'); this.tabs.set(id, tabs); }); // Initialize accordions Accordion.initAll('.accordion').forEach(accordion => { const id = helpers.generateId('accordion'); this.accordions.set(id, accordion); }); // Initialize sidebars Sidebar.initFromAttributes('[data-sidebar]').forEach(sidebar => { const id = helpers.generateId('sidebar'); this.sidebars.set(id, sidebar); }); // Initialize code copy buttons CodeCopy.initAll('pre, .code-block'); // Setup switch listeners this.setupSwitches(); } /** * Setup switch/toggle functionality */ setupSwitches() { const switches = dom.$$('.switch input'); switches.forEach(switchInput => { dom.on(switchInput, 'change', () => { const event = new CustomEvent('gumi-switch-change', { detail: { checked: switchInput.checked } }); switchInput.dispatchEvent(event); }); }); } // Theme methods setTheme(theme) { this.theme.setTheme(theme); } toggleTheme() { this.theme.toggleTheme(); } getTheme() { return this.theme.getTheme(); } // Modal methods modal(selector, options) { const el = dom.$(selector); if (!el) return; const modal = new Modal(el, options); this.modals.set(el.id || helpers.generateId('modal'), modal); const triggers = dom.$$(`[data-modal="${selector}"]`); triggers.forEach(trigger => { dom.on(trigger, 'click', (e) => { e.preventDefault(); modal.open(); }); }); } openModal(selector) { const el = dom.$(selector); if (!el) return; let modal = Array.from(this.modals.values()).find(m => m.element === el); if (!modal) { modal = new Modal(el); this.modals.set(el.id || helpers.generateId('modal'), modal); } modal.open(); } closeModal(selector) { const el = dom.$(selector); if (!el) return; const modal = Array.from(this.modals.values()).find(m => m.element === el); if (modal) { modal.close(); } } // Toast methods toast(message, options) { return Toast.show(message, options); } // Progress methods setProgress(selector, value) { Progress.setProgress(selector, value); // Update data attribute for color progression const element = dom.$(selector); if (element) { element.setAttribute('data-progress', Math.round(value).toString()); } } // Form validation validateForm(selector) { return FormValidator.validateForm(selector); } // Dropdown methods dropdown(trigger, menu, options) { const triggerEl = dom.$(trigger); if (!triggerEl) return; const menuSelector = menu || triggerEl.getAttribute('data-dropdown'); if (!menuSelector) return; const menuEl = dom.$(menuSelector); if (!menuEl) return; const dropdown = new Dropdown(triggerEl, menuEl, options); this.dropdowns.set(helpers.generateId('dropdown'), dropdown); } // Lazy loading lazyLoad(selector = 'img[data-src]') { const images = dom.$$(selector); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; const src = img.getAttribute('data-src'); if (src) { img.src = src; img.removeAttribute('data-src'); dom.addClass(img, 'gumi-loaded'); } observer.unobserve(img); } }); }); images.forEach(img => observer.observe(img)); } // Parallax effect parallax(selector, options = {}) { const elements = dom.$$(selector); const speed = options.speed || 0.5; const updateParallax = () => { const scrollY = window.pageYOffset; elements.forEach(el => { const rect = el.getBoundingClientRect(); const elementTop = rect.top + scrollY; const windowHeight = window.innerHeight; if (rect.bottom >= 0 && rect.top <= windowHeight) { const yPos = (scrollY - elementTop) * speed; el.style.transform = `translateY(${yPos}px)`; } }); }; dom.on(window, 'scroll', helpers.debounce(updateParallax, 10)); updateParallax(); } // Ripple effect ripple(selector) { const buttons = dom.$$(selector); buttons.forEach(button => { dom.on(button, 'click', (e) => { animation.ripple(e, button); }); }); } // Loading state loading(element, isLoading = true) { const el = dom.$(element); if (!el) return; if (isLoading) { el.disabled = true; el.setAttribute('data-loading', 'true'); const originalContent = el.innerHTML; el.setAttribute('data-original-content', originalContent); el.innerHTML = `<span class="spinner"></span> Loading...`; } else { el.disabled = false; el.removeAttribute('data-loading'); const originalContent = el.getAttribute('data-original-content'); if (originalContent) { el.innerHTML = originalContent; el.removeAttribute('data-original-content'); } } } // Sidebar methods sidebar(selector) { return Sidebar.init(selector); } openSidebar(selector) { const sidebar = Array.from(this.sidebars.values()).find(s => s.element === dom.$(selector)); if (sidebar) sidebar.open(); } closeSidebar(selector) { const sidebar = Array.from(this.sidebars.values()).find(s => s.element === dom.$(selector)); if (sidebar) sidebar.close(); } toggleSidebar(selector) { const sidebar = Array.from(this.sidebars.values()).find(s => s.element === dom.$(selector)); if (sidebar) sidebar.toggle(); } } // Create global instance const gumi = new Gumi(); // Export for module usage export default gumi; // Export components for advanced usage export { ThemeManager, Modal, Toast, Tabs, Accordion, Dropdown, Progress, FormValidator, Sidebar, CodeCopy }; // Make available globally for browser usage if (typeof window !== 'undefined') { window.gumi = gumi; } //# sourceMappingURL=gumi.js.map