wilday_ui 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/builds/wilday_ui/index.js +223 -0
- data/app/assets/builds/wilday_ui/index.js.map +3 -3
- data/app/assets/stylesheets/wilday_ui/components/button/features/clipboard.css +108 -0
- data/app/assets/stylesheets/wilday_ui/components/button/features/confirmation.css +136 -0
- data/app/assets/stylesheets/wilday_ui/components/button/features/variants.css +5 -0
- data/app/assets/stylesheets/wilday_ui/components/button/index.css +3 -0
- data/app/assets/stylesheets/wilday_ui/tokens/colors.css +109 -0
- data/app/helpers/wilday_ui/application_helper.rb +1 -0
- data/app/helpers/wilday_ui/components/button_helper.rb +120 -2
- data/app/helpers/wilday_ui/theme_helper.rb +19 -0
- data/app/javascript/wilday_ui/controllers/clipboard_controller.js +76 -0
- data/app/javascript/wilday_ui/controllers/confirmation_controller.js +216 -0
- data/app/javascript/wilday_ui/controllers/index.js +4 -1
- data/lib/wilday_ui/version.rb +1 -1
- metadata +8 -2
| @@ -0,0 +1,108 @@ | |
| 1 | 
            +
            .w-button-feedback {
         | 
| 2 | 
            +
              position: absolute;
         | 
| 3 | 
            +
              padding: 0.5rem 1rem;
         | 
| 4 | 
            +
              background: rgba(0, 0, 0, 0.8);
         | 
| 5 | 
            +
              color: white;
         | 
| 6 | 
            +
              border-radius: 4px;
         | 
| 7 | 
            +
              font-size: 0.875rem;
         | 
| 8 | 
            +
              pointer-events: none;
         | 
| 9 | 
            +
              opacity: 0;
         | 
| 10 | 
            +
              transition: opacity 0.2s ease;
         | 
| 11 | 
            +
              z-index: 50;
         | 
| 12 | 
            +
              white-space: nowrap;
         | 
| 13 | 
            +
            }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            /* Basic positions */
         | 
| 16 | 
            +
            .w-button-feedback-top {
         | 
| 17 | 
            +
              bottom: 100%;
         | 
| 18 | 
            +
              left: 50%;
         | 
| 19 | 
            +
              transform: translateX(-50%);
         | 
| 20 | 
            +
              margin-bottom: 0.5rem;
         | 
| 21 | 
            +
            }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            .w-button-feedback-bottom {
         | 
| 24 | 
            +
              top: 100%;
         | 
| 25 | 
            +
              left: 50%;
         | 
| 26 | 
            +
              transform: translateX(-50%);
         | 
| 27 | 
            +
              margin-top: 0.5rem;
         | 
| 28 | 
            +
            }
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            .w-button-feedback-left {
         | 
| 31 | 
            +
              right: 100%;
         | 
| 32 | 
            +
              top: 50%;
         | 
| 33 | 
            +
              transform: translateY(-50%);
         | 
| 34 | 
            +
              margin-right: 0.5rem;
         | 
| 35 | 
            +
            }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            .w-button-feedback-right {
         | 
| 38 | 
            +
              left: 100%;
         | 
| 39 | 
            +
              top: 50%;
         | 
| 40 | 
            +
              transform: translateY(-50%);
         | 
| 41 | 
            +
              margin-left: 0.5rem;
         | 
| 42 | 
            +
            }
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            /* Start/End modifiers */
         | 
| 45 | 
            +
            .w-button-feedback-top.w-button-feedback-start,
         | 
| 46 | 
            +
            .w-button-feedback-bottom.w-button-feedback-start {
         | 
| 47 | 
            +
              left: 0;
         | 
| 48 | 
            +
              transform: translateX(0);
         | 
| 49 | 
            +
            }
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            .w-button-feedback-top.w-button-feedback-end,
         | 
| 52 | 
            +
            .w-button-feedback-bottom.w-button-feedback-end {
         | 
| 53 | 
            +
              left: auto;
         | 
| 54 | 
            +
              right: 0;
         | 
| 55 | 
            +
              transform: translateX(0);
         | 
| 56 | 
            +
            }
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            .w-button-feedback-left.w-button-feedback-start,
         | 
| 59 | 
            +
            .w-button-feedback-right.w-button-feedback-start {
         | 
| 60 | 
            +
              top: 0;
         | 
| 61 | 
            +
              transform: translateY(0);
         | 
| 62 | 
            +
            }
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            .w-button-feedback-left.w-button-feedback-end,
         | 
| 65 | 
            +
            .w-button-feedback-right.w-button-feedback-end {
         | 
| 66 | 
            +
              top: auto;
         | 
| 67 | 
            +
              bottom: 0;
         | 
| 68 | 
            +
              transform: translateY(0);
         | 
| 69 | 
            +
            }
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            /* Show state */
         | 
| 72 | 
            +
            .w-button-feedback-show {
         | 
| 73 | 
            +
              opacity: 1;
         | 
| 74 | 
            +
            }
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            /* Optional: Add arrow indicators */
         | 
| 77 | 
            +
            .w-button-feedback::before {
         | 
| 78 | 
            +
              content: "";
         | 
| 79 | 
            +
              position: absolute;
         | 
| 80 | 
            +
              width: 8px;
         | 
| 81 | 
            +
              height: 8px;
         | 
| 82 | 
            +
              background: inherit;
         | 
| 83 | 
            +
              transform: rotate(45deg);
         | 
| 84 | 
            +
            }
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            .w-button-feedback-top::before {
         | 
| 87 | 
            +
              bottom: -4px;
         | 
| 88 | 
            +
              left: 50%;
         | 
| 89 | 
            +
              margin-left: -4px;
         | 
| 90 | 
            +
            }
         | 
| 91 | 
            +
             | 
| 92 | 
            +
            .w-button-feedback-bottom::before {
         | 
| 93 | 
            +
              top: -4px;
         | 
| 94 | 
            +
              left: 50%;
         | 
| 95 | 
            +
              margin-left: -4px;
         | 
| 96 | 
            +
            }
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            .w-button-feedback-left::before {
         | 
| 99 | 
            +
              right: -4px;
         | 
| 100 | 
            +
              top: 50%;
         | 
| 101 | 
            +
              margin-top: -4px;
         | 
| 102 | 
            +
            }
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            .w-button-feedback-right::before {
         | 
| 105 | 
            +
              left: -4px;
         | 
| 106 | 
            +
              top: 50%;
         | 
| 107 | 
            +
              margin-top: -4px;
         | 
| 108 | 
            +
            }
         | 
| @@ -0,0 +1,136 @@ | |
| 1 | 
            +
            .w-button-confirmation-dialog {
         | 
| 2 | 
            +
              padding: 0;
         | 
| 3 | 
            +
              border: none;
         | 
| 4 | 
            +
              border-radius: 0.5rem;
         | 
| 5 | 
            +
              box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1);
         | 
| 6 | 
            +
              max-width: 28rem;
         | 
| 7 | 
            +
              width: 90vw;
         | 
| 8 | 
            +
              background: var(--w-color-light-50, #ffffff);
         | 
| 9 | 
            +
            }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            .w-button-confirmation-dialog::backdrop {
         | 
| 12 | 
            +
              background-color: rgb(0 0 0 / 0.4);
         | 
| 13 | 
            +
              backdrop-filter: blur(4px);
         | 
| 14 | 
            +
            }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            .w-button-confirmation-dialog-content {
         | 
| 17 | 
            +
              padding: 1.5rem;
         | 
| 18 | 
            +
            }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            .w-button-confirmation-dialog-icon {
         | 
| 21 | 
            +
              margin-bottom: 1rem;
         | 
| 22 | 
            +
              width: 2.5rem;
         | 
| 23 | 
            +
              height: 2.5rem;
         | 
| 24 | 
            +
            }
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            .w-button-confirmation-dialog-icon svg {
         | 
| 27 | 
            +
              width: 100%;
         | 
| 28 | 
            +
              height: 100%;
         | 
| 29 | 
            +
            }
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            .w-button-confirmation-dialog-icon.info {
         | 
| 32 | 
            +
              color: var(--w-color-info-500);
         | 
| 33 | 
            +
            }
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            .w-button-confirmation-dialog-icon.success {
         | 
| 36 | 
            +
              color: var(--w-color-success-500);
         | 
| 37 | 
            +
            }
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            .w-button-confirmation-dialog-icon.warning {
         | 
| 40 | 
            +
              color: var(--w-color-warning-500);
         | 
| 41 | 
            +
            }
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            .w-button-confirmation-dialog-icon.danger {
         | 
| 44 | 
            +
              color: var(--w-color-danger-500);
         | 
| 45 | 
            +
            }
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            .w-button-confirmation-dialog-title {
         | 
| 48 | 
            +
              font-size: 1.125rem;
         | 
| 49 | 
            +
              font-weight: 600;
         | 
| 50 | 
            +
              color: var(--w-color-dark-800, #1f2937); /* Darker text for better contrast */
         | 
| 51 | 
            +
              margin-bottom: 0.5rem;
         | 
| 52 | 
            +
            }
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            .w-button-confirmation-dialog-message {
         | 
| 55 | 
            +
              color: var(--w-color-dark-600, #4b5563); /* Adjusted for better readability */
         | 
| 56 | 
            +
              margin-bottom: 1.5rem;
         | 
| 57 | 
            +
              line-height: 1.5;
         | 
| 58 | 
            +
            }
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            .w-button-confirmation-dialog-actions {
         | 
| 61 | 
            +
              display: flex;
         | 
| 62 | 
            +
              justify-content: flex-end;
         | 
| 63 | 
            +
              gap: 0.75rem;
         | 
| 64 | 
            +
            }
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            /* Mobile Responsive Styles */
         | 
| 67 | 
            +
            @media (max-width: 640px) {
         | 
| 68 | 
            +
              .w-button-confirmation-dialog {
         | 
| 69 | 
            +
                width: 95vw; /* Slightly wider on mobile */
         | 
| 70 | 
            +
                margin: 1rem;
         | 
| 71 | 
            +
                max-height: 90vh; /* Prevent overflow on small screens */
         | 
| 72 | 
            +
                overflow-y: auto; /* Allow scrolling if content is too tall */
         | 
| 73 | 
            +
                position: fixed;
         | 
| 74 | 
            +
                top: 50%;
         | 
| 75 | 
            +
                left: 50%;
         | 
| 76 | 
            +
                transform: translate(-50%, -50%);
         | 
| 77 | 
            +
                margin: 0;
         | 
| 78 | 
            +
              }
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              .w-button-confirmation-dialog-content {
         | 
| 81 | 
            +
                padding: 1rem; /* Slightly smaller padding on mobile */
         | 
| 82 | 
            +
              }
         | 
| 83 | 
            +
             | 
| 84 | 
            +
              .w-button-confirmation-dialog-actions {
         | 
| 85 | 
            +
                flex-direction: column-reverse; /* Stack buttons vertically */
         | 
| 86 | 
            +
                gap: 0.5rem; /* Smaller gap between buttons */
         | 
| 87 | 
            +
                padding: 1rem; /* Add padding around buttons */
         | 
| 88 | 
            +
              }
         | 
| 89 | 
            +
             | 
| 90 | 
            +
              .w-button-confirmation-dialog-actions button {
         | 
| 91 | 
            +
                width: 100%; /* Full width buttons */
         | 
| 92 | 
            +
                margin: 0; /* Remove any margins */
         | 
| 93 | 
            +
              }
         | 
| 94 | 
            +
             | 
| 95 | 
            +
              .w-button-confirmation-dialog-icon {
         | 
| 96 | 
            +
                margin-bottom: 0.75rem; /* Slightly reduced spacing */
         | 
| 97 | 
            +
                width: 2rem; /* Slightly smaller icon */
         | 
| 98 | 
            +
                height: 2rem;
         | 
| 99 | 
            +
              }
         | 
| 100 | 
            +
             | 
| 101 | 
            +
              .w-button-confirmation-dialog-title {
         | 
| 102 | 
            +
                font-size: 1rem; /* Slightly smaller title */
         | 
| 103 | 
            +
              }
         | 
| 104 | 
            +
             | 
| 105 | 
            +
              .w-button-confirmation-dialog-message {
         | 
| 106 | 
            +
                font-size: 0.875rem; /* Slightly smaller message text */
         | 
| 107 | 
            +
              }
         | 
| 108 | 
            +
            }
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            /* Handle very small screens */
         | 
| 111 | 
            +
            @media (max-width: 360px) {
         | 
| 112 | 
            +
              .w-button-confirmation-dialog {
         | 
| 113 | 
            +
                width: 98vw;
         | 
| 114 | 
            +
                margin: 0.5rem;
         | 
| 115 | 
            +
              }
         | 
| 116 | 
            +
            }
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            /* Handle landscape orientation */
         | 
| 119 | 
            +
            @media (max-height: 600px) and (orientation: landscape) {
         | 
| 120 | 
            +
              .w-button-confirmation-dialog {
         | 
| 121 | 
            +
                max-height: 95vh;
         | 
| 122 | 
            +
                display: flex;
         | 
| 123 | 
            +
                flex-direction: row;
         | 
| 124 | 
            +
              }
         | 
| 125 | 
            +
             | 
| 126 | 
            +
              .w-button-confirmation-dialog-content {
         | 
| 127 | 
            +
                flex: 1;
         | 
| 128 | 
            +
                padding: 1rem;
         | 
| 129 | 
            +
              }
         | 
| 130 | 
            +
             | 
| 131 | 
            +
              .w-button-confirmation-dialog-actions {
         | 
| 132 | 
            +
                padding: 1rem;
         | 
| 133 | 
            +
                flex-direction: column;
         | 
| 134 | 
            +
                justify-content: center;
         | 
| 135 | 
            +
              }
         | 
| 136 | 
            +
            }
         | 
| @@ -152,6 +152,11 @@ a.w-button.w-button-no-underline:hover { | |
| 152 152 | 
             
              color: #000000;
         | 
| 153 153 | 
             
            }
         | 
| 154 154 |  | 
| 155 | 
            +
            /* Override underline for plain buttons */
         | 
| 156 | 
            +
            a.w-button-plain.w-button-underline {
         | 
| 157 | 
            +
              text-decoration: none;
         | 
| 158 | 
            +
            }
         | 
| 159 | 
            +
             | 
| 155 160 | 
             
            .w-button-plain:focus-visible {
         | 
| 156 161 | 
             
              outline: 2px solid #1a1a1a;
         | 
| 157 162 | 
             
              outline-offset: 2px;
         | 
| @@ -0,0 +1,109 @@ | |
| 1 | 
            +
            :root {
         | 
| 2 | 
            +
              /* Primary Colors */
         | 
| 3 | 
            +
              --w-color-primary-50: #e5f0ff;
         | 
| 4 | 
            +
              --w-color-primary-100: #cce0ff;
         | 
| 5 | 
            +
              --w-color-primary-200: #99c2ff;
         | 
| 6 | 
            +
              --w-color-primary-300: #66a3ff;
         | 
| 7 | 
            +
              --w-color-primary-400: #3385ff;
         | 
| 8 | 
            +
              --w-color-primary-500: #0066ff;
         | 
| 9 | 
            +
              --w-color-primary-600: #0052cc;
         | 
| 10 | 
            +
              --w-color-primary-700: #003d99;
         | 
| 11 | 
            +
              --w-color-primary-800: #002966;
         | 
| 12 | 
            +
              --w-color-primary-900: #001433;
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              /* Secondary Colors */
         | 
| 15 | 
            +
              --w-color-secondary-50: #f8f9fa;
         | 
| 16 | 
            +
              --w-color-secondary-100: #e9ecef;
         | 
| 17 | 
            +
              --w-color-secondary-200: #dee2e6;
         | 
| 18 | 
            +
              --w-color-secondary-300: #ced4da;
         | 
| 19 | 
            +
              --w-color-secondary-400: #adb5bd;
         | 
| 20 | 
            +
              --w-color-secondary-500: #6c757d;
         | 
| 21 | 
            +
              --w-color-secondary-600: #5a6268;
         | 
| 22 | 
            +
              --w-color-secondary-700: #495057;
         | 
| 23 | 
            +
              --w-color-secondary-800: #343a40;
         | 
| 24 | 
            +
              --w-color-secondary-900: #212529;
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              /* Success Colors */
         | 
| 27 | 
            +
              --w-color-success-50: #ecfdf5;
         | 
| 28 | 
            +
              --w-color-success-100: #d1fae5;
         | 
| 29 | 
            +
              --w-color-success-200: #a7f3d0;
         | 
| 30 | 
            +
              --w-color-success-300: #6ee7b7;
         | 
| 31 | 
            +
              --w-color-success-400: #34d399;
         | 
| 32 | 
            +
              --w-color-success-500: #10b981;
         | 
| 33 | 
            +
              --w-color-success-600: #059669;
         | 
| 34 | 
            +
              --w-color-success-700: #047857;
         | 
| 35 | 
            +
              --w-color-success-800: #065f46;
         | 
| 36 | 
            +
              --w-color-success-900: #064e3b;
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              /* Danger Colors */
         | 
| 39 | 
            +
              --w-color-danger-50: #fee2e2;
         | 
| 40 | 
            +
              --w-color-danger-100: #fecaca;
         | 
| 41 | 
            +
              --w-color-danger-200: #fca5a5;
         | 
| 42 | 
            +
              --w-color-danger-300: #f87171;
         | 
| 43 | 
            +
              --w-color-danger-400: #ef4444;
         | 
| 44 | 
            +
              --w-color-danger-500: #dc2626;
         | 
| 45 | 
            +
              --w-color-danger-600: #b91c1c;
         | 
| 46 | 
            +
              --w-color-danger-700: #991b1b;
         | 
| 47 | 
            +
              --w-color-danger-800: #7f1d1d;
         | 
| 48 | 
            +
              --w-color-danger-900: #450a0a;
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              /* Warning Colors */
         | 
| 51 | 
            +
              --w-color-warning-50: #fffbeb;
         | 
| 52 | 
            +
              --w-color-warning-100: #fef3c7;
         | 
| 53 | 
            +
              --w-color-warning-200: #fde68a;
         | 
| 54 | 
            +
              --w-color-warning-300: #fcd34d;
         | 
| 55 | 
            +
              --w-color-warning-400: #fbbf24;
         | 
| 56 | 
            +
              --w-color-warning-500: #f59e0b;
         | 
| 57 | 
            +
              --w-color-warning-600: #d97706;
         | 
| 58 | 
            +
              --w-color-warning-700: #b45309;
         | 
| 59 | 
            +
              --w-color-warning-800: #92400e;
         | 
| 60 | 
            +
              --w-color-warning-900: #78350f;
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              /* Info Colors */
         | 
| 63 | 
            +
              --w-color-info-50: #eff6ff;
         | 
| 64 | 
            +
              --w-color-info-100: #dbeafe;
         | 
| 65 | 
            +
              --w-color-info-200: #bfdbfe;
         | 
| 66 | 
            +
              --w-color-info-300: #93c5fd;
         | 
| 67 | 
            +
              --w-color-info-400: #60a5fa;
         | 
| 68 | 
            +
              --w-color-info-500: #3b82f6;
         | 
| 69 | 
            +
              --w-color-info-600: #2563eb;
         | 
| 70 | 
            +
              --w-color-info-700: #1d4ed8;
         | 
| 71 | 
            +
              --w-color-info-800: #1e40af;
         | 
| 72 | 
            +
              --w-color-info-900: #1e3a8a;
         | 
| 73 | 
            +
             | 
| 74 | 
            +
              /* Light Colors */
         | 
| 75 | 
            +
              --w-color-light-50: #ffffff;
         | 
| 76 | 
            +
              --w-color-light-100: #f8f9fa;
         | 
| 77 | 
            +
              --w-color-light-200: #f1f3f5;
         | 
| 78 | 
            +
              --w-color-light-300: #e9ecef;
         | 
| 79 | 
            +
              --w-color-light-400: #dee2e6;
         | 
| 80 | 
            +
              --w-color-light-500: #ced4da;
         | 
| 81 | 
            +
              --w-color-light-600: #adb5bd;
         | 
| 82 | 
            +
              --w-color-light-700: #868e96;
         | 
| 83 | 
            +
              --w-color-light-800: #495057;
         | 
| 84 | 
            +
              --w-color-light-900: #212529;
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              /* Dark Colors */
         | 
| 87 | 
            +
              --w-color-dark-50: #f9fafb;
         | 
| 88 | 
            +
              --w-color-dark-100: #f3f4f6;
         | 
| 89 | 
            +
              --w-color-dark-200: #e5e7eb;
         | 
| 90 | 
            +
              --w-color-dark-300: #d1d5db;
         | 
| 91 | 
            +
              --w-color-dark-400: #1f2937;
         | 
| 92 | 
            +
              --w-color-dark-500: #111827;
         | 
| 93 | 
            +
              --w-color-dark-600: #0f172a;
         | 
| 94 | 
            +
              --w-color-dark-700: #0a0f1a;
         | 
| 95 | 
            +
              --w-color-dark-800: #060912;
         | 
| 96 | 
            +
              --w-color-dark-900: #030509;
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              /* Link Colors */
         | 
| 99 | 
            +
              --w-color-link-50: #eff6ff;
         | 
| 100 | 
            +
              --w-color-link-100: #dbeafe;
         | 
| 101 | 
            +
              --w-color-link-200: #bfdbfe;
         | 
| 102 | 
            +
              --w-color-link-300: #93c5fd;
         | 
| 103 | 
            +
              --w-color-link-400: #60a5fa;
         | 
| 104 | 
            +
              --w-color-link-500: #2563eb;
         | 
| 105 | 
            +
              --w-color-link-600: #1d4ed8;
         | 
| 106 | 
            +
              --w-color-link-700: #1e40af;
         | 
| 107 | 
            +
              --w-color-link-800: #1e3a8a;
         | 
| 108 | 
            +
              --w-color-link-900: #1e3a8a;
         | 
| 109 | 
            +
            }
         | 
| @@ -11,6 +11,16 @@ module WildayUi | |
| 11 11 | 
             
                      wrapper_required: false,
         | 
| 12 12 | 
             
                      stimulus_controller: "button",
         | 
| 13 13 | 
             
                      default_stimulus_action: "click->button#toggleLoading"
         | 
| 14 | 
            +
                    },
         | 
| 15 | 
            +
                    copy_to_clipboard: {
         | 
| 16 | 
            +
                      wrapper_required: true,
         | 
| 17 | 
            +
                      stimulus_controller: "clipboard button",
         | 
| 18 | 
            +
                      default_stimulus_action: "click->clipboard#copy click->button#toggleLoading"
         | 
| 19 | 
            +
                    },
         | 
| 20 | 
            +
                    confirm: {
         | 
| 21 | 
            +
                      wrapper_required: true,
         | 
| 22 | 
            +
                      stimulus_controller: "confirmation",
         | 
| 23 | 
            +
                      default_stimulus_action: "click->confirmation#showDialog"
         | 
| 14 24 | 
             
                    }
         | 
| 15 25 | 
             
                    # Add more features here as needed
         | 
| 16 26 | 
             
                    # tooltip: {
         | 
| @@ -42,6 +52,8 @@ module WildayUi | |
| 42 52 | 
             
                    dropdown_items: nil,
         | 
| 43 53 | 
             
                    dropdown_icon: nil,
         | 
| 44 54 | 
             
                    theme: nil,
         | 
| 55 | 
            +
                    copy_to_clipboard: nil,
         | 
| 56 | 
            +
                    confirm: nil,
         | 
| 45 57 | 
             
                    **options
         | 
| 46 58 | 
             
                  )
         | 
| 47 59 | 
             
                    content_for(:head) { stylesheet_link_tag "wilday_ui/components/button/index", media: "all" }
         | 
| @@ -68,7 +80,7 @@ module WildayUi | |
| 68 80 | 
             
                    gradient_class = get_gradient_class(gradient)
         | 
| 69 81 |  | 
| 70 82 | 
             
                    # Setup features that require Stimulus controllers
         | 
| 71 | 
            -
                    active_features = determine_active_features(loading, dropdown, loading_text, use_default_controller)
         | 
| 83 | 
            +
                    active_features = determine_active_features(loading, dropdown, loading_text, copy_to_clipboard, confirm, use_default_controller)
         | 
| 72 84 |  | 
| 73 85 | 
             
                    setup_features(active_features, options, use_default_controller, loading_text)
         | 
| 74 86 |  | 
| @@ -84,6 +96,24 @@ module WildayUi | |
| 84 96 | 
             
                      )
         | 
| 85 97 | 
             
                    end
         | 
| 86 98 |  | 
| 99 | 
            +
                    if copy_to_clipboard
         | 
| 100 | 
            +
                      setup_clipboard_options(
         | 
| 101 | 
            +
                        options,
         | 
| 102 | 
            +
                        additional_classes,
         | 
| 103 | 
            +
                        copy_to_clipboard,
         | 
| 104 | 
            +
                        wrapper_data
         | 
| 105 | 
            +
                      )
         | 
| 106 | 
            +
                    end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                    if confirm
         | 
| 109 | 
            +
                      setup_confirmation_options(
         | 
| 110 | 
            +
                        options,
         | 
| 111 | 
            +
                        additional_classes,
         | 
| 112 | 
            +
                        confirm,
         | 
| 113 | 
            +
                        wrapper_data
         | 
| 114 | 
            +
                      )
         | 
| 115 | 
            +
                    end
         | 
| 116 | 
            +
             | 
| 87 117 | 
             
                    # Setup wrapper options if any feature requires it
         | 
| 88 118 | 
             
                    wrapper_options = setup_wrapper_options(
         | 
| 89 119 | 
             
                      active_features,
         | 
| @@ -267,10 +297,12 @@ module WildayUi | |
| 267 297 | 
             
                    styles.map { |k, v| "#{k}: #{v}" }.join(";")
         | 
| 268 298 | 
             
                  end
         | 
| 269 299 |  | 
| 270 | 
            -
                  def determine_active_features(loading, dropdown, loading_text = nil, use_default_controller = true)
         | 
| 300 | 
            +
                  def determine_active_features(loading, dropdown, loading_text = nil, copy_to_clipboard = nil, confirm = nil, use_default_controller = true)
         | 
| 271 301 | 
             
                    features = {}
         | 
| 272 302 | 
             
                    features[:loading] = true if (loading || loading_text.present?) && use_default_controller
         | 
| 273 303 | 
             
                    features[:dropdown] = true if dropdown && use_default_controller
         | 
| 304 | 
            +
                    features[:copy_to_clipboard] = true if copy_to_clipboard.present? && use_default_controller
         | 
| 305 | 
            +
                    features[:confirm] = true if confirm.present? && use_default_controller
         | 
| 274 306 | 
             
                    features
         | 
| 275 307 | 
             
                  end
         | 
| 276 308 |  | 
| @@ -389,6 +421,92 @@ module WildayUi | |
| 389 421 | 
             
                    "#{base}#{index}"
         | 
| 390 422 | 
             
                  end
         | 
| 391 423 |  | 
| 424 | 
            +
                  def setup_clipboard_options(options, additional_classes, copy_to_clipboard, wrapper_data)
         | 
| 425 | 
            +
                    return unless copy_to_clipboard.present?
         | 
| 426 | 
            +
             | 
| 427 | 
            +
                    clipboard_config = normalize_clipboard_options(copy_to_clipboard)
         | 
| 428 | 
            +
             | 
| 429 | 
            +
                    wrapper_data.merge!(
         | 
| 430 | 
            +
                      controller: "clipboard button",
         | 
| 431 | 
            +
                      clipboard_text_value: clipboard_config[:text],
         | 
| 432 | 
            +
                      clipboard_feedback_text_value: clipboard_config[:feedback_text],
         | 
| 433 | 
            +
                      clipboard_feedback_position_value: clipboard_config[:position],
         | 
| 434 | 
            +
                      clipboard_feedback_duration_value: clipboard_config[:duration]
         | 
| 435 | 
            +
                    )
         | 
| 436 | 
            +
             | 
| 437 | 
            +
                    options[:data][:clipboard_target] = "button"
         | 
| 438 | 
            +
                    options[:data][:button_target] = "button"
         | 
| 439 | 
            +
                  end
         | 
| 440 | 
            +
             | 
| 441 | 
            +
                  def normalize_clipboard_options(options)
         | 
| 442 | 
            +
                    if options.is_a?(Hash)
         | 
| 443 | 
            +
                      {
         | 
| 444 | 
            +
                        text: options[:text],
         | 
| 445 | 
            +
                        feedback_text: options[:feedback_text] || "Copied!",
         | 
| 446 | 
            +
                        position: options[:position] || "top",
         | 
| 447 | 
            +
                        duration: options[:duration] || 2000
         | 
| 448 | 
            +
                      }
         | 
| 449 | 
            +
                    else
         | 
| 450 | 
            +
                      {
         | 
| 451 | 
            +
                        text: options.to_s,
         | 
| 452 | 
            +
                        feedback_text: "Copied!",
         | 
| 453 | 
            +
                        position: "top",
         | 
| 454 | 
            +
                        duration: 2000
         | 
| 455 | 
            +
                      }
         | 
| 456 | 
            +
                    end
         | 
| 457 | 
            +
                  end
         | 
| 458 | 
            +
             | 
| 459 | 
            +
                  def setup_confirmation_options(options, additional_classes, confirm, wrapper_data)
         | 
| 460 | 
            +
                    return unless confirm.present?
         | 
| 461 | 
            +
             | 
| 462 | 
            +
                    confirm_config = normalize_confirmation_options(confirm)
         | 
| 463 | 
            +
             | 
| 464 | 
            +
                    # Use the same theme processing as regular buttons
         | 
| 465 | 
            +
                    confirm_theme_styles = process_theme(:solid, { name: confirm_config[:variant] })
         | 
| 466 | 
            +
                    cancel_theme_styles = process_theme(:subtle, { name: :secondary })
         | 
| 467 | 
            +
             | 
| 468 | 
            +
                    wrapper_data.merge!(
         | 
| 469 | 
            +
                      controller: "confirmation",
         | 
| 470 | 
            +
                      confirmation_title_value: confirm_config[:title],
         | 
| 471 | 
            +
                      confirmation_message_value: confirm_config[:message],
         | 
| 472 | 
            +
                      confirmation_icon_color_value: confirm_config[:variant],
         | 
| 473 | 
            +
                      confirmation_confirm_text_value: confirm_config[:confirm_text],
         | 
| 474 | 
            +
                      confirmation_cancel_text_value: confirm_config[:cancel_text],
         | 
| 475 | 
            +
                      confirmation_confirm_styles_value: confirm_theme_styles,
         | 
| 476 | 
            +
                      confirmation_cancel_styles_value: cancel_theme_styles
         | 
| 477 | 
            +
                    )
         | 
| 478 | 
            +
             | 
| 479 | 
            +
                    # Only add loading state if enabled
         | 
| 480 | 
            +
                    if confirm_config[:loading]
         | 
| 481 | 
            +
                      wrapper_data.merge!(
         | 
| 482 | 
            +
                        confirmation_loading_value: "true",
         | 
| 483 | 
            +
                        confirmation_loading_text_value: confirm_config[:loading_text]
         | 
| 484 | 
            +
                      )
         | 
| 485 | 
            +
                    end
         | 
| 486 | 
            +
                  end
         | 
| 487 | 
            +
             | 
| 488 | 
            +
                  def normalize_confirmation_options(options)
         | 
| 489 | 
            +
                    if options.is_a?(String)
         | 
| 490 | 
            +
                      {
         | 
| 491 | 
            +
                        title: "Confirm Action",
         | 
| 492 | 
            +
                        message: options,
         | 
| 493 | 
            +
                        variant: :info,
         | 
| 494 | 
            +
                        confirm_text: "Confirm",
         | 
| 495 | 
            +
                        cancel_text: "Cancel"
         | 
| 496 | 
            +
                      }
         | 
| 497 | 
            +
                    else
         | 
| 498 | 
            +
                      {
         | 
| 499 | 
            +
                        title: options[:title] || "Confirm Action",
         | 
| 500 | 
            +
                        message: options[:message],
         | 
| 501 | 
            +
                        variant: options[:variant] || :info,
         | 
| 502 | 
            +
                        confirm_text: options[:confirm_text] || "Confirm",
         | 
| 503 | 
            +
                        cancel_text: options[:cancel_text] || "Cancel",
         | 
| 504 | 
            +
                        loading: options[:loading] || false,
         | 
| 505 | 
            +
                        loading_text: options[:loading_text] || "Processing..."
         | 
| 506 | 
            +
                      }
         | 
| 507 | 
            +
                    end
         | 
| 508 | 
            +
                  end
         | 
| 509 | 
            +
             | 
| 392 510 | 
             
                  def render_button(content, variant_class, size_class, radius_class, gradient_class, icon, icon_position, icon_only,
         | 
| 393 511 | 
             
                                   loading, loading_text, additional_classes, disabled, options, href, underline,
         | 
| 394 512 | 
             
                                   dropdown, dropdown_items, dropdown_icon, wrapper_options)
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module WildayUi
         | 
| 2 | 
            +
              module ThemeHelper
         | 
| 3 | 
            +
                def generate_theme_css_variables
         | 
| 4 | 
            +
                  colors = WildayUi::Config::Theme.configuration.colors
         | 
| 5 | 
            +
                  css_vars = colors.map do |color_name, shades|
         | 
| 6 | 
            +
                    shades.map do |shade, value|
         | 
| 7 | 
            +
                      "--w-color-#{color_name}-#{shade}: #{value};"
         | 
| 8 | 
            +
                    end
         | 
| 9 | 
            +
                  end.flatten.join("\n")
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  "<style>:root { #{css_vars} }</style>".html_safe
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                # Helper to get specific color value
         | 
| 15 | 
            +
                def theme_color(name, shade = "500")
         | 
| 16 | 
            +
                  WildayUi::Config::Theme.configuration.colors.dig(name.to_s, shade.to_s)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,76 @@ | |
| 1 | 
            +
            import { Controller } from "@hotwired/stimulus";
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            export default class extends Controller {
         | 
| 4 | 
            +
              static targets = ["button", "feedback"];
         | 
| 5 | 
            +
              static values = {
         | 
| 6 | 
            +
                text: String,
         | 
| 7 | 
            +
                feedbackText: { type: String, default: "Copied!" },
         | 
| 8 | 
            +
                feedbackPosition: { type: String, default: "top" },
         | 
| 9 | 
            +
                feedbackDuration: { type: Number, default: 2000 },
         | 
| 10 | 
            +
              };
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              connect() {
         | 
| 13 | 
            +
                // Optional: Initialize any necessary setup
         | 
| 14 | 
            +
              }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              async copy(event) {
         | 
| 17 | 
            +
                event.preventDefault();
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                try {
         | 
| 20 | 
            +
                  await navigator.clipboard.writeText(this.textValue);
         | 
| 21 | 
            +
                  this.showFeedback();
         | 
| 22 | 
            +
                } catch (err) {
         | 
| 23 | 
            +
                  console.error("Failed to copy text:", err);
         | 
| 24 | 
            +
                  // Fallback for older browsers
         | 
| 25 | 
            +
                  this.fallbackCopy();
         | 
| 26 | 
            +
                }
         | 
| 27 | 
            +
              }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              fallbackCopy() {
         | 
| 30 | 
            +
                const textArea = document.createElement("textarea");
         | 
| 31 | 
            +
                textArea.value = this.textValue;
         | 
| 32 | 
            +
                textArea.style.position = "fixed";
         | 
| 33 | 
            +
                textArea.style.left = "-9999px";
         | 
| 34 | 
            +
                document.body.appendChild(textArea);
         | 
| 35 | 
            +
                textArea.select();
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                try {
         | 
| 38 | 
            +
                  document.execCommand("copy");
         | 
| 39 | 
            +
                  this.showFeedback();
         | 
| 40 | 
            +
                } catch (err) {
         | 
| 41 | 
            +
                  console.error("Fallback: Oops, unable to copy", err);
         | 
| 42 | 
            +
                }
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                document.body.removeChild(textArea);
         | 
| 45 | 
            +
              }
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              showFeedback() {
         | 
| 48 | 
            +
                const feedback = this.hasFeedbackTarget
         | 
| 49 | 
            +
                  ? this.feedbackTarget
         | 
| 50 | 
            +
                  : this.createFeedbackElement();
         | 
| 51 | 
            +
                feedback.textContent = this.feedbackTextValue;
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                // Remove any existing position classes
         | 
| 54 | 
            +
                feedback.className = "w-button-feedback";
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                // Add position-specific classes
         | 
| 57 | 
            +
                const positionClasses = this.feedbackPositionValue.split("-");
         | 
| 58 | 
            +
                positionClasses.forEach((pos) => {
         | 
| 59 | 
            +
                  feedback.classList.add(`w-button-feedback-${pos}`);
         | 
| 60 | 
            +
                });
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                feedback.classList.add("w-button-feedback-show");
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                setTimeout(() => {
         | 
| 65 | 
            +
                  feedback.classList.remove("w-button-feedback-show");
         | 
| 66 | 
            +
                }, this.feedbackDurationValue);
         | 
| 67 | 
            +
              }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              createFeedbackElement() {
         | 
| 70 | 
            +
                const feedback = document.createElement("div");
         | 
| 71 | 
            +
                feedback.classList.add("w-button-feedback");
         | 
| 72 | 
            +
                feedback.setAttribute("data-clipboard-target", "feedback");
         | 
| 73 | 
            +
                this.element.appendChild(feedback);
         | 
| 74 | 
            +
                return feedback;
         | 
| 75 | 
            +
              }
         | 
| 76 | 
            +
            }
         |