utilikit-1.0.0/modules/utilikit_playground/js/utilikit.playground-enhanced.js

modules/utilikit_playground/js/utilikit.playground-enhanced.js
/**
 * @file
 * Enhanced UtiliKit Playground functionality.
 *
 * Provides interactive playground features including preset examples,
 * visual class builder, color palette, viewport controls, responsive
 * helpers, and comprehensive style inspection tools.
 */

(function(Drupal, once, drupalSettings) {
  'use strict';

  /**
   * Preset examples configuration object.
   *
   * Contains predefined HTML and class combinations for common UI patterns
   * like cards, hero sections, forms, grids, and pricing components.
   *
   * @type {Object.<string, Object>}
   */
  const presetExamples = {
    card: {
      basic: 'uk-pd--32 uk-bg--ffffff uk-br--16 uk-bs--solid uk-bw--1 uk-bc--e9ecef',
      html: `<div class="utilikit uk-pd--32 uk-bg--ffffff uk-br--16 uk-bs--solid uk-bw--1 uk-bc--e9ecef">
  <h3 class="utilikit uk-fs--28 uk-fw--700 uk-tc--1a202c uk-mg--b-16">Premium Features</h3>
  <p class="utilikit uk-tc--64748b uk-lh--1d8 uk-mg--b-24">Get access to advanced tools and analytics to supercharge your workflow.</p>
  <div class="utilikit uk-dp--flex uk-gp--12">
    <button class="utilikit uk-pd--12-24 uk-bg--3b82f6 uk-tc--ffffff uk-br--8 uk-bw--0 uk-fw--600 uk-cu--pointer">Get Started</button>
    <button class="utilikit uk-pd--12-24 uk-bg--ffffff uk-tc--3b82f6 uk-br--8 uk-bs--solid uk-bw--2 uk-bc--3b82f6 uk-fw--600 uk-cu--pointer">Learn More</button>
  </div>
</div>`
    },

    hero: {
      basic: 'uk-pd--80-20 uk-bg--1e40af uk-tc--ffffff uk-ta--center',
      html: `<section class="utilikit uk-pd--80-20 uk-bg--1e40af uk-tc--ffffff uk-ta--center">
  <h1 class="utilikit uk-fs--56 uk-fw--800 uk-mg--b-24">Welcome to UtiliKit</h1>
  <p class="utilikit uk-fs--24 uk-mg--b-32 uk-xw--800 uk-mg--r-auto uk-mg--l-auto uk-op--90">Build beautiful, responsive interfaces with utility-first CSS classes</p>
  <button class="utilikit uk-pd--16-40 uk-bg--ffffff uk-tc--1e40af uk-br--32 uk-fw--700 uk-fs--18 uk-cu--pointer">Start Building →</button>
</section>`
    },

    flex: {
      basic: 'uk-dp--flex uk-gp--20 uk-fx--wrap',
      html: `<div class="utilikit uk-dp--flex uk-gp--20 uk-fx--wrap">
  <div class="utilikit uk-fg--1 uk-nw--300 uk-pd--20 uk-bg--f8f9fa uk-br--8">
    <h3 class="utilikit uk-fs--18 uk-fw--600 uk-mg--b-12">Column 1</h3>
    <p class="utilikit uk-tc--6c757d">Flexible column with minimum width</p>
  </div>
  <div class="utilikit uk-fg--1 uk-nw--300 uk-pd--20 uk-bg--e9ecef uk-br--8">
    <h3 class="utilikit uk-fs--18 uk-fw--600 uk-mg--b-12">Column 2</h3>
    <p class="utilikit uk-tc--6c757d">Equal width columns that wrap</p>
  </div>
  <div class="utilikit uk-fg--1 uk-nw--300 uk-pd--20 uk-bg--dee2e6 uk-br--8">
    <h3 class="utilikit uk-fs--18 uk-fw--600 uk-mg--b-12">Column 3</h3>
    <p class="utilikit uk-tc--6c757d">Responsive flex layout</p>
  </div>
</div>`
    },

    grid: {
      basic: 'uk-dp--grid uk-gc--repeat-auto-fit-minmax-280px-1fr uk-gp--24',
      html: `<div class="utilikit uk-dp--grid uk-gc--repeat-auto-fit-minmax-280px-1fr uk-gp--24">
  <!-- Card 1 -->
  <div class="utilikit uk-pd--24 uk-bg--ffffff uk-br--12 uk-bs--solid uk-bw--1 uk-bc--e2e8f0">
    <div class="utilikit uk-fs--48 uk-fw--700 uk-tc--3b82f6 uk-mg--b-16">01</div>
    <h3 class="utilikit uk-fs--20 uk-fw--700 uk-tc--1a202c uk-mg--b-8">Design System</h3>
    <p class="utilikit uk-tc--64748b uk-lh--1d6">Consistent components and patterns for scalable interfaces.</p>
  </div>

  <!-- Card 2 -->
  <div class="utilikit uk-pd--24 uk-bg--ffffff uk-br--12 uk-bs--solid uk-bw--1 uk-bc--e2e8f0">
    <div class="utilikit uk-fs--48 uk-fw--700 uk-tc--10b981 uk-mg--b-16">02</div>
    <h3 class="utilikit uk-fs--20 uk-fw--700 uk-tc--1a202c uk-mg--b-8">Responsive Grid</h3>
    <p class="utilikit uk-tc--64748b uk-lh--1d6">Auto-adjusting layouts that adapt to any screen size.</p>
  </div>

  <!-- Card 3 -->
  <div class="utilikit uk-pd--24 uk-bg--ffffff uk-br--12 uk-bs--solid uk-bw--1 uk-bc--e2e8f0">
    <div class="utilikit uk-fs--48 uk-fw--700 uk-tc--f59e0b uk-mg--b-16">03</div>
    <h3 class="utilikit uk-fs--20 uk-fw--700 uk-tc--1a202c uk-mg--b-8">Utility Classes</h3>
    <p class="utilikit uk-tc--64748b uk-lh--1d6">Build complex layouts with simple, composable classes.</p>
  </div>

  <!-- Card 4 -->
  <div class="utilikit uk-pd--24 uk-bg--ffffff uk-br--12 uk-bs--solid uk-bw--1 uk-bc--e2e8f0">
    <div class="utilikit uk-fs--48 uk-fw--700 uk-tc--8b5cf6 uk-mg--b-16">04</div>
    <h3 class="utilikit uk-fs--20 uk-fw--700 uk-tc--1a202c uk-mg--b-8">Fast Development</h3>
    <p class="utilikit uk-tc--64748b uk-lh--1d6">Ship faster with pre-built utilities and instant preview.</p>
  </div>

  <!-- Card 5 -->
  <div class="utilikit uk-pd--24 uk-bg--ffffff uk-br--12 uk-bs--solid uk-bw--1 uk-bc--e2e8f0">
    <div class="utilikit uk-fs--48 uk-fw--700 uk-tc--ef4444 uk-mg--b-16">05</div>
    <h3 class="utilikit uk-fs--20 uk-fw--700 uk-tc--1a202c uk-mg--b-8">Modern Stack</h3>
    <p class="utilikit uk-tc--64748b uk-lh--1d6">Built for Drupal 11 with the latest web standards.</p>
  </div>

  <!-- Card 6 -->
  <div class="utilikit uk-pd--24 uk-bg--ffffff uk-br--12 uk-bs--solid uk-bw--1 uk-bc--e2e8f0">
    <div class="utilikit uk-fs--48 uk-fw--700 uk-tc--06b6d4 uk-mg--b-16">06</div>
    <h3 class="utilikit uk-fs--20 uk-fw--700 uk-tc--1a202c uk-mg--b-8">Zero Config</h3>
    <p class="utilikit uk-tc--64748b uk-lh--1d6">Works out of the box with smart defaults and easy setup.</p>
  </div>
</div>`
    },

    form: {
      basic: 'uk-dp--flex uk-fd--column uk-gp--20 uk-xw--480 uk-mg--0-auto',
      html: `<form class="utilikit uk-dp--flex uk-fd--column uk-gp--20 uk-xw--480 uk-mg--0-auto uk-pd--32 uk-bg--ffffff uk-br--12 uk-bs--solid uk-bw--1 uk-bc--e2e8f0">
  <h2 class="utilikit uk-fs--28 uk-fw--700 uk-tc--1a202c uk-mg--b-8">Create Account</h2>

  <div class="utilikit uk-dp--grid">
    <label class="utilikit uk-dp--inline-block uk-mg--b-8 uk-fw--600 uk-fs--14 uk-tc--475569">Full Name</label>
    <input type="text" class="utilikit uk-wd--100pr uk-pd--12-16 uk-br--8 uk-bs--solid uk-bw--1 uk-bc--cbd5e1 uk-fs--16" placeholder="John Doe">
  </div>

  <div class="utilikit uk-dp--grid">
    <label class="utilikit uk-dp--inline-block uk-mg--b-8 uk-fw--600 uk-fs--14 uk-tc--475569">Email Address</label>
    <input type="email" class="utilikit uk-wd--100pr uk-pd--12-16 uk-br--8 uk-bs--solid uk-bw--1 uk-bc--cbd5e1 uk-fs--16" placeholder="john@example.com">
  </div>

  <div class="utilikit uk-dp--grid">
    <label class="utilikit uk-dp--inline-block uk-mg--b-8 uk-fw--600 uk-fs--14 uk-tc--475569">Phone Number</label>
    <input type="tel" class="utilikit uk-wd--100pr uk-pd--12-16 uk-br--8 uk-bs--solid uk-bw--1 uk-bc--cbd5e1 uk-fs--16" placeholder="+1 (555) 123-4567">
  </div>

  <div class="utilikit uk-dp--grid">
    <label class="utilikit uk-dp--inline-block uk-mg--b-8 uk-fw--600 uk-fs--14 uk-tc--475569">Password</label>
    <input type="password" class="utilikit uk-wd--100pr uk-pd--12-16 uk-br--8 uk-bs--solid uk-bw--1 uk-bc--cbd5e1 uk-fs--16" placeholder="••••••••">
  </div>

  <button type="submit" class="utilikit uk-pd--14-28 uk-bg--3b82f6 uk-tc--ffffff uk-br--8 uk-bw--0 uk-fw--600 uk-fs--16 uk-cu--pointer uk-mg--t-8">Create Account</button>
</form>`
    },

    pricing: {
      basic: 'uk-pd--32 uk-sm-pd--48 uk-bg--ffffff uk-dp--grid uk-br--16 uk-ta--center uk-ps--relative uk-ov--hidden',
      html: `<div class="utilikit uk-dp--grid uk-pd--32 uk-sm-pd--48 uk-bg--ffffff uk-br--16 uk-ta--center uk-ps--relative uk-ov--hidden">
  <div class="utilikit uk-ps--absolute uk-tp--20 uk-ri--20 uk-pd--8-16 uk-bg--ff6348 uk-tc--ffffff uk-br--20 uk-fs--12 uk-fw--700 uk-rt--25">POPULAR</div>

  <h3 class="utilikit uk-fs--16 uk-fw--600 uk-tc--6c757d uk-mg--b-16 uk-ls--2" style="text-transform: uppercase;">Professional</h3>

  <div class="utilikit uk-mg--b-24">
    <span class="utilikit uk-fs--24 uk-fw--600 uk-tc--6c757d uk-va--top">$</span>
    <span class="utilikit uk-fs--56 uk-sm-fs--72 uk-fw--900 uk-tc--1a1a2e uk-lh--1">49</span>
    <span class="utilikit uk-fs--18 uk-tc--6c757d">/month</span>
  </div>

  <ul class="utilikit uk-dp--grid uk-mg--b-32 uk-ta--left uk-pd--0" style="list-style: none;">
    <li class="utilikit uk-pd--12-0 uk-tc--495057 uk-fs--16">✓ Unlimited projects</li>
    <li class="utilikit uk-pd--12-0 uk-tc--495057 uk-fs--16">✓ Advanced analytics</li>
    <li class="utilikit uk-pd--12-0 uk-tc--495057 uk-fs--16">✓ 24/7 Priority support</li>
    <li class="utilikit uk-pd--12-0 uk-tc--495057 uk-fs--16">✓ Custom integrations</li>
    <li class="utilikit uk-pd--12-0 uk-tc--495057 uk-fs--16">✓ White-label options</li>
  </ul>

  <button class="utilikit uk-wd--100pr uk-pd--16-32 uk-tc--ffffff uk-bg--007bff uk-bw--2 uk-br--8 uk-fw--700 uk-fs--16 uk-cu--pointer uk-pd--20 uk-bs--solid">
    Start Free Trial
  </button>

  <p class="utilikit uk-fs--14 uk-tc--6c757d uk-mg--t-16">No credit card required</p>
</div>`
    }
  };

  /**
   * Enhanced UtiliKit Playground Drupal behavior.
   *
   * Initializes all interactive playground features including preset examples,
   * visual class builder, color palette, viewport controls, and more.
   *
   * @type {Drupal~behavior}
   *
   * @prop {Drupal~behaviorAttach} attach
   *   Attaches enhanced playground functionality to playground wrapper elements.
   */
  Drupal.behaviors.utilikitPlaygroundEnhanced = {
    attach: function(context, settings) {
      once('utilikitPlaygroundEnhanced', '.utilikit-playground-wrapper', context).forEach(wrapper => {
        // Initialize all enhancements
        initPresetExamples(wrapper);
        initClassBuilder(wrapper);
        initColorPalette(wrapper);
        initViewportControls(wrapper);
        initQuickActions(wrapper);
        initTutorial();
        enhanceFormSubmit(wrapper);
        initResetEnhancements(wrapper);
      });
    }
  };

  /**
   * Initializes preset example functionality.
   *
   * Sets up click handlers for preset buttons that load predefined HTML
   * and class combinations into the playground form.
   *
   * @param {Element} wrapper
   *   The playground wrapper element containing preset buttons.
   */
  function initPresetExamples(wrapper) {
    wrapper.querySelectorAll('.preset-btn').forEach(btn => {
      btn.addEventListener('click', function() {
        const preset = presetExamples[this.dataset.preset];
        if (!preset) return;

        // Remove active class from all preset buttons
        wrapper.querySelectorAll('.preset-btn').forEach(b => b.classList.remove('active'));

        // Add active class to clicked button
        this.classList.add('active');

        const modeSelect = document.getElementById('utilikit-mode');
        const classInput = document.getElementById('utilikit-class-input');
        const htmlInput = document.getElementById('utilikit-html-input');

        if (preset.html && htmlInput) {
          modeSelect.value = 'advanced';
          modeSelect.dispatchEvent(new Event('change'));
          htmlInput.value = preset.html;
        } else if (preset.basic && classInput) {
          modeSelect.value = 'basic';
          modeSelect.dispatchEvent(new Event('change'));
          classInput.value = preset.basic;
        }

        // Submit form
        document.getElementById('utilikit-preview-form').dispatchEvent(new Event('submit'));

        // Keep the success flash for visual feedback
        this.classList.add('success-flash');
        setTimeout(() => this.classList.remove('success-flash'), 500);
      });
    });
  }

  /**
   * Initializes the visual class builder interface.
   *
   * Sets up toggle functionality for the class builder panel and handles
   * clicking on class chips to build utility class combinations visually.
   *
   * @param {Element} wrapper
   *   The playground wrapper element containing builder controls.
   */
  function initClassBuilder(wrapper) {
    const builder = document.getElementById('class-builder');
    const builderBtn = wrapper.querySelector('[data-action="builder"]');
    const classInput = document.getElementById('utilikit-class-input');
    const selectedClasses = window.utilikitPlaygroundState?.selectedClasses || new Set();

    builderBtn?.addEventListener('click', () => {
      const isVisible = builder.style.display !== 'none';
      builder.style.display = isVisible ? 'none' : 'block';
      builderBtn.classList.toggle('active', !isVisible);
    });

    wrapper.querySelectorAll('.builder-chip').forEach(chip => {
      chip.addEventListener('click', function() {
        const className = this.dataset.class;

        if (this.classList.contains('active')) {
          this.classList.remove('active');
          selectedClasses.delete(className);
        } else {
          this.classList.add('active');
          selectedClasses.add(className);
        }

        classInput.value = Array.from(selectedClasses).join(' ');
        document.getElementById('utilikit-preview-form').dispatchEvent(new Event('submit'));
      });
    });
  }

  /**
   * Initializes the color palette functionality.
   *
   * Sets up click handlers for color swatches that update color inputs
   * and copy hex values to clipboard with visual feedback.
   *
   * @param {Element} wrapper
   *   The playground wrapper element containing color controls.
   */
  function initColorPalette(wrapper) {
    const colorPicker = document.getElementById('utilikit-color-picker');
    const colorValue = document.getElementById('utilikit-color-value');

    wrapper.querySelectorAll('.color-swatch').forEach(swatch => {
      swatch.addEventListener('click', function() {
        const color = this.dataset.color;
        colorPicker.value = color;
        colorValue.value = color;

        // Visual feedback
        wrapper.querySelectorAll('.color-swatch').forEach(s => s.classList.remove('selected'));
        this.classList.add('selected');

        // Copy hex without #
        const hexValue = color.replace('#', '');
        navigator.clipboard.writeText(hexValue).catch(() => {
          // Fallback
          colorValue.select();
          document.execCommand('copy');
        });

        // Animate
        this.style.transform = 'scale(1.3)';
        setTimeout(() => this.style.transform = '', 200);
      });
    });
  }

  /**
   * Initializes viewport control functionality.
   *
   * Sets up viewport simulation buttons (mobile, tablet, desktop) that
   * resize the preview frame and update size indicators.
   *
   * @param {Element} wrapper
   *   The playground wrapper element containing viewport controls.
   */
  function initViewportControls(wrapper) {
    const viewportBtns = wrapper.querySelectorAll('.viewport-btn');
    const previewFrame = document.getElementById('utilikit-preview-box');
    const sizeIndicator = wrapper.querySelector('.viewport-size-indicator');

    viewportBtns.forEach(btn => {
      btn.addEventListener('click', function() {
        const viewport = this.dataset.viewport;

        viewportBtns.forEach(b => b.classList.remove('active'));
        this.classList.add('active');

        previewFrame.className = `preview-frame ${viewport} utilikit-preview-output`;

        const sizes = {
          mobile: '375px',
          tablet: '768px',
          desktop: '1200px'
        };
        sizeIndicator.textContent = sizes[viewport];
      });
    });
  }

  /**
   * Initializes quick action buttons and responsive helper tools.
   *
   * Sets up tutorial launch, responsive helper toggle, and responsive
   * class converter with click-to-copy functionality.
   *
   * @param {Element} wrapper
   *   The playground wrapper element containing quick action controls.
   */
  function initQuickActions(wrapper) {
    // Tutorial button
    const tutorialBtn = wrapper.querySelector('[data-action="tutorial"]');
    tutorialBtn?.addEventListener('click', () => {
      document.getElementById('tutorial-overlay').classList.add('active');
    });

    // Responsive helper button
    const responsiveBtn = wrapper.querySelector('[data-action="responsive"]');
    const responsiveHelper = document.getElementById('responsive-helper');

    responsiveBtn?.addEventListener('click', () => {
      const isVisible = responsiveHelper.style.display !== 'none';
      responsiveHelper.style.display = isVisible ? 'none' : 'block';
      responsiveBtn.classList.toggle('active', !isVisible);
    });

    // Responsive converter
    const responsiveInput = document.getElementById('responsive-input');
    const responsiveOutput = document.getElementById('responsive-output');

    responsiveInput?.addEventListener('input', (e) => {
      const value = e.target.value.trim();

      if (value.startsWith('uk-') && value.includes('--')) {
        const breakpoints = ['sm', 'md', 'lg', 'xl', 'xxl'];
        let html = '<div class="responsive-variant" data-class="' + value + '">';
        html += '<span class="prefix">base:</span>';
        html += '<span class="class-name">' + value + '</span>';
        html += '</div>';

        breakpoints.forEach(bp => {
          const responsiveClass = value.replace('uk-', `uk-${bp}-`);
          html += '<div class="responsive-variant" data-class="' + responsiveClass + '">';
          html += '<span class="prefix">' + bp + ':</span>';
          html += '<span class="class-name">' + responsiveClass + '</span>';
          html += '</div>';
        });

        responsiveOutput.innerHTML = html;

        // Add click handlers to copy classes
        responsiveOutput.querySelectorAll('.responsive-variant').forEach(variant => {
          variant.addEventListener('click', function() {
            const className = this.dataset.class;
            const classInput = document.getElementById('utilikit-class-input');

            // Add to existing classes
            const currentClasses = classInput.value.trim();
            classInput.value = currentClasses ? currentClasses + ' ' + className : className;

            // Visual feedback
            this.style.background = '#28a745';
            this.style.color = 'white';
            setTimeout(() => {
              this.style.background = '';
              this.style.color = '';
            }, 300);

            // Copy to clipboard
            navigator.clipboard.writeText(className).catch(() => {});
          });
        });
      } else {
        responsiveOutput.innerHTML = '<p style="color: #6c757d; font-size: 13px;">Enter a valid UtiliKit class (e.g., uk-pd--20)</p>';
      }
    });
  }

  /**
   * Initializes the tutorial overlay and welcome experience.
   *
   * Shows tutorial on first visit and sets up close handlers for
   * tutorial overlay with local storage tracking.
   */
  function initTutorial() {
    const overlay = document.getElementById('tutorial-overlay');
    const closeBtn = document.getElementById('tutorial-close');
    const startBtn = document.getElementById('tutorial-start');

    // Show tutorial on first visit
    if (!localStorage.getItem('utilikit-tutorial-seen')) {
      setTimeout(() => overlay.classList.add('active'), 500);
    }

    const closeTutorial = () => {
      overlay.classList.remove('active');
      localStorage.setItem('utilikit-tutorial-seen', 'true');
    };

    closeBtn?.addEventListener('click', closeTutorial);
    startBtn?.addEventListener('click', closeTutorial);
    overlay?.addEventListener('click', (e) => {
      if (e.target === overlay) closeTutorial();
    });
  }

  /**
   * Enhances form submission with style inspector updates.
   *
   * Adds post-submit handlers to update the style inspector and
   * rendered HTML display after form submission.
   *
   * @param {Element} wrapper
   *   The playground wrapper element containing the form.
   */
  function enhanceFormSubmit(wrapper) {
    const form = document.getElementById('utilikit-preview-form');
    const renderedHtml = document.getElementById('utilikit-rendered-html');

    // Add style inspector update after form submits
    if (form) {
      form.addEventListener('submit', () => {
        setTimeout(() => {
          updateStyleInspector();

          // Update rendered HTML section
          const previewBox = document.getElementById('utilikit-preview-box');
          if (previewBox && renderedHtml) {
            const element = previewBox.querySelector('.utilikit, [class*="uk-"]');
            if (element) {
              renderedHtml.textContent = element.outerHTML;
            }
          }
        }, 100);
      });
    }
  }

  /**
   * Initializes enhanced reset functionality with state management.
   *
   * Sets up reset button to clear all playground state including
   * visual builder selections, autocomplete, and visibility states.
   *
   * @param {Element} wrapper
   *   The playground wrapper element containing reset controls.
   */
  function initResetEnhancements(wrapper) {
    const resetBtn = document.getElementById('utilikit-reset-btn');
    if (!resetBtn) return;

    // Store references to stateful components
    const stateManager = {
      selectedClasses: new Set(), // For visual builder
      autocompleteIndex: -1,      // For autocomplete
      responsiveHelperVisible: false,
      builderVisible: false,
    };

    // Make state manager accessible to other functions
    window.utilikitPlaygroundState = stateManager;

    // Listen for reset events
    resetBtn.addEventListener('click', function() {
      // Clear preset button active states
      wrapper.querySelectorAll('.preset-btn').forEach(btn => {
        btn.classList.remove('active');
      });

      // Clear visual builder active states
      wrapper.querySelectorAll('.builder-chip').forEach(chip => {
        chip.classList.remove('active');
      });

      // Clear color palette selections
      wrapper.querySelectorAll('.color-swatch').forEach(swatch => {
        swatch.classList.remove('selected');
      });

      // Clear quick action button states
      wrapper.querySelectorAll('.quick-action-btn').forEach(btn => {
        btn.classList.remove('active');
      });

      // Clear visual builder state
      stateManager.selectedClasses.clear();

      // Reset autocomplete state
      stateManager.autocompleteIndex = -1;

      // Reset visibility states
      stateManager.responsiveHelperVisible = false;
      stateManager.builderVisible = false;

      // Clear any temporary animations
      clearAllAnimations();

      // Reset any modified DOM elements
      resetDOMElements();

      // Clear any event listeners that might interfere
      cleanupEventListeners();
    });
  }

  /**
   * Clears all ongoing CSS animations and transitions.
   *
   * Removes any temporary animation or transition styles that might
   * interfere with the reset state.
   */
  function clearAllAnimations() {
    // Clear any ongoing animations
    document.querySelectorAll('*').forEach(el => {
      if (el.style.transition) {
        el.style.transition = '';
      }
      if (el.style.animation) {
        el.style.animation = '';
      }
    });
  }

  /**
   * Resets DOM elements to their default state.
   *
   * Removes temporary classes and data attributes that were added
   * during user interactions.
   */
  function resetDOMElements() {
    // Reset any dynamically added classes
    document.querySelectorAll('[class*="success-"], [class*="error-"], [class*="active-"]').forEach(el => {
      const classes = Array.from(el.classList);
      classes.forEach(cls => {
        if (cls.includes('success-') || cls.includes('error-') || cls.includes('active-')) {
          el.classList.remove(cls);
        }
      });
    });

    // Clear any data attributes used for state
    document.querySelectorAll('[data-state], [data-active], [data-selected]').forEach(el => {
      delete el.dataset.state;
      delete el.dataset.active;
      delete el.dataset.selected;
    });
  }

  /**
   * Updates the style inspector panel with current element styles.
   *
   * Analyzes the preview element's computed styles and applied classes,
   * then displays them in organized groups for debugging.
   */
  function updateStyleInspector() {
    const preview = document.getElementById('utilikit-preview-box');
    const breakdown = document.getElementById('style-breakdown');

    if (!preview || !breakdown) return;

    const element = preview.querySelector('.utilikit, [class*="uk-"]');
    if (!element) return;

    const computed = window.getComputedStyle(element);
    const classes = Array.from(element.classList).filter(c => c.startsWith('uk-'));

    const styleGroups = {
      'Box Model': ['padding', 'margin', 'width', 'height'],
      'Typography': ['font-size', 'font-weight', 'line-height', 'color', 'text-align'],
      'Background': ['background-color', 'opacity'],
      'Border': ['border', 'border-radius'],
      'Layout': ['display', 'flex-direction', 'justify-content', 'align-items', 'gap']
    };

    let html = '<div class="class-breakdown">';
    html += '<div class="style-group-title">Applied Classes</div>';

    classes.forEach(cls => {
      const effect = getClassEffect(cls);
      html += `
        <div class="class-item">
          <span class="class-name">${cls}</span>
          <span class="class-arrow">→</span>
          <span class="class-effect">${effect}</span>
        </div>
      `;
    });
    html += '</div>';

    Object.entries(styleGroups).forEach(([group, properties]) => {
      const values = properties.map(prop => {
        const value = computed[prop];
        return value && value !== 'none' && value !== '0px' ? { prop, value } : null;
      }).filter(Boolean);

      if (values.length > 0) {
        html += `
          <div class="style-group">
            <div class="style-group-title">${group}</div>
            ${values.map(({ prop, value }) => `
              <div class="style-item">
                <span class="style-property">${prop}:</span>
                <span class="style-value">${value}</span>
              </div>
            `).join('')}
          </div>
        `;
      }
    });

    breakdown.innerHTML = html;
  }

  /**
   * Converts a UtiliKit class name to a readable CSS property description.
   *
   * Parses UtiliKit utility class syntax to determine the CSS property
   * and value being applied, including handling directional and
   * responsive variants.
   *
   * @param {string} className
   *   The UtiliKit class name to analyze (e.g., 'uk-pd--20').
   *
   * @returns {string}
   *   Human-readable description of the CSS effect.
   */
  function getClassEffect(className) {
    const parts = className.split('--');
    if (parts.length !== 2) return 'Custom style';

    const [prefix, value] = parts;
    const prop = getPropertyName(className);

    if (value === 'auto') return `${prop}: auto`;
    if (value.includes('-')) {
      const subParts = value.split('-');
      if (['t', 'r', 'b', 'l'].includes(subParts[0])) {
        const sideMap = { t: 'top', r: 'right', b: 'bottom', l: 'left' };
        return `${prop}-${sideMap[subParts[0]]}: ${subParts[1]}px`;
      }
    }

    const unit = value.endsWith('pr') ? '%' : 'px';
    const numValue = value.replace('pr', '');
    return `${prop}: ${numValue}${unit}`;
  }

})(Drupal, once, drupalSettings);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc