wilday_ui 0.6.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0928d2614b52a959cfdf1a406c10f1de6f291788965ddaba3f48a08fb22283e2'
4
- data.tar.gz: 977b7bf2c02855534294786824da27fdcd9fa1779f50eff26a8418af2998d938
3
+ metadata.gz: 6aae81001c80b4c0fd86eaca5391e6de697a87b88e38215bd1889a70163dafe7
4
+ data.tar.gz: 87cff2dba0f7408ae84456cec4b6aac1927f1bcc27ad09309091c2b43c3df45a
5
5
  SHA512:
6
- metadata.gz: 295649d8662a2057527c9a89e140a0a219f329d8133c8c25a843deb337a48b857c21a569ff0afca74ec2604e75f9c0ebbd7f4ba73cfc52700b64f4b4ee436b44
7
- data.tar.gz: d4b5d7f4194d2f925c2ea5fa5f48368d4049e5b45c2b88ea59d468d5a93a10c0ce1ea4df426b07765af3c78a842cd62b43d49ded19b18a6581ce7735efb29b27
6
+ metadata.gz: '09d8ec007fb7c0757f65ded7d2e059281752c2fdc07cee90aea77dc82b008adb9e07c6161cd527635ceb289121a030b29234a6d5c306a24e68b3d9378e0bfc0e'
7
+ data.tar.gz: da49ca71e648b9e527d02668a83cc6130dcb53ada46f195e9bb19dc4e3a5cf716b9d0b7353f4e68cfdc01416c6bdc5b8a15afc8ea349ea9fe8053be3c74bf318
@@ -2708,11 +2708,471 @@ var dropdown_controller_default = class extends Controller {
2708
2708
  }
2709
2709
  };
2710
2710
 
2711
+ // app/javascript/wilday_ui/controllers/clipboard_controller.js
2712
+ var clipboard_controller_default = class extends Controller {
2713
+ static targets = ["button", "feedback"];
2714
+ static values = {
2715
+ text: String,
2716
+ feedbackText: { type: String, default: "Copied!" },
2717
+ feedbackPosition: { type: String, default: "top" },
2718
+ feedbackDuration: { type: Number, default: 2e3 }
2719
+ };
2720
+ connect() {
2721
+ }
2722
+ async copy(event) {
2723
+ event.preventDefault();
2724
+ try {
2725
+ await navigator.clipboard.writeText(this.textValue);
2726
+ this.showFeedback();
2727
+ } catch (err) {
2728
+ console.error("Failed to copy text:", err);
2729
+ this.fallbackCopy();
2730
+ }
2731
+ }
2732
+ fallbackCopy() {
2733
+ const textArea = document.createElement("textarea");
2734
+ textArea.value = this.textValue;
2735
+ textArea.style.position = "fixed";
2736
+ textArea.style.left = "-9999px";
2737
+ document.body.appendChild(textArea);
2738
+ textArea.select();
2739
+ try {
2740
+ document.execCommand("copy");
2741
+ this.showFeedback();
2742
+ } catch (err) {
2743
+ console.error("Fallback: Oops, unable to copy", err);
2744
+ }
2745
+ document.body.removeChild(textArea);
2746
+ }
2747
+ showFeedback() {
2748
+ const feedback = this.hasFeedbackTarget ? this.feedbackTarget : this.createFeedbackElement();
2749
+ feedback.textContent = this.feedbackTextValue;
2750
+ feedback.className = "w-button-feedback";
2751
+ const positionClasses = this.feedbackPositionValue.split("-");
2752
+ positionClasses.forEach((pos) => {
2753
+ feedback.classList.add(`w-button-feedback-${pos}`);
2754
+ });
2755
+ feedback.classList.add("w-button-feedback-show");
2756
+ setTimeout(() => {
2757
+ feedback.classList.remove("w-button-feedback-show");
2758
+ }, this.feedbackDurationValue);
2759
+ }
2760
+ createFeedbackElement() {
2761
+ const feedback = document.createElement("div");
2762
+ feedback.classList.add("w-button-feedback");
2763
+ feedback.setAttribute("data-clipboard-target", "feedback");
2764
+ this.element.appendChild(feedback);
2765
+ return feedback;
2766
+ }
2767
+ };
2768
+
2769
+ // app/javascript/wilday_ui/controllers/confirmation_controller.js
2770
+ var confirmation_controller_default = class extends Controller {
2771
+ static targets = ["dialog", "confirmButton", "cancelButton"];
2772
+ static values = {
2773
+ title: String,
2774
+ message: String,
2775
+ iconColor: String,
2776
+ confirmText: String,
2777
+ cancelText: String,
2778
+ confirmStyles: String,
2779
+ cancelStyles: String
2780
+ };
2781
+ // Store the original event to be used later
2782
+ originalEvent = null;
2783
+ connect() {
2784
+ if (!this.hasDialogTarget) {
2785
+ this.element.insertAdjacentHTML("beforeend", this.dialogHTML);
2786
+ }
2787
+ }
2788
+ disconnect() {
2789
+ this.originalEvent = null;
2790
+ this.isConfirmed = false;
2791
+ }
2792
+ showDialog(event) {
2793
+ if (this.isConfirmed) {
2794
+ this.isConfirmed = false;
2795
+ return;
2796
+ }
2797
+ event.preventDefault();
2798
+ this.originalEvent = {
2799
+ type: event.type,
2800
+ element: event.currentTarget,
2801
+ ctrlKey: event.ctrlKey,
2802
+ metaKey: event.metaKey
2803
+ };
2804
+ this.dialogTarget.showModal();
2805
+ this.focusConfirmButton();
2806
+ }
2807
+ confirm(event) {
2808
+ event.preventDefault();
2809
+ this.dialogTarget.close();
2810
+ if (this.originalEvent?.element) {
2811
+ const element = this.originalEvent.element;
2812
+ if (this.hasTurbo && !element.hasAttribute("data-turbo") && !element.hasAttribute("data-turbo-method")) {
2813
+ this.resumeOriginalEvent();
2814
+ return;
2815
+ }
2816
+ const confirmEvent = new CustomEvent("confirm", {
2817
+ bubbles: true,
2818
+ cancelable: true,
2819
+ detail: {
2820
+ element,
2821
+ originalEvent: this.originalEvent
2822
+ }
2823
+ });
2824
+ const wasHandled = !element.dispatchEvent(confirmEvent);
2825
+ if (wasHandled) return;
2826
+ this.resumeOriginalEvent();
2827
+ }
2828
+ }
2829
+ resumeOriginalEvent() {
2830
+ if (!this.originalEvent) return;
2831
+ const element = this.originalEvent.element;
2832
+ this.isConfirmed = true;
2833
+ if (element.closest("form")) {
2834
+ const form = element.closest("form");
2835
+ const submitEvent = new Event("submit", {
2836
+ bubbles: true,
2837
+ cancelable: true
2838
+ });
2839
+ form.dispatchEvent(submitEvent);
2840
+ this.originalEvent = null;
2841
+ return;
2842
+ }
2843
+ if (element.tagName === "A" || element.hasAttribute("href")) {
2844
+ const click = new MouseEvent("click", {
2845
+ bubbles: true,
2846
+ cancelable: true,
2847
+ ctrlKey: this.originalEvent.ctrlKey,
2848
+ metaKey: this.originalEvent.metaKey
2849
+ });
2850
+ element.dispatchEvent(click);
2851
+ this.originalEvent = null;
2852
+ return;
2853
+ }
2854
+ if (!element.closest("form") && !(element.tagName === "A" || element.hasAttribute("href"))) {
2855
+ element.click();
2856
+ this.originalEvent = null;
2857
+ return;
2858
+ }
2859
+ }
2860
+ cancel(event) {
2861
+ event.preventDefault();
2862
+ this.closeDialog();
2863
+ }
2864
+ closeDialog() {
2865
+ this.dialogTarget.close();
2866
+ this.originalEvent = null;
2867
+ }
2868
+ handleKeydown(event) {
2869
+ if (event.key === "Escape") {
2870
+ this.cancel(event);
2871
+ }
2872
+ }
2873
+ handleClickOutside(event) {
2874
+ if (event.target === this.dialogTarget) {
2875
+ this.cancel(event);
2876
+ }
2877
+ }
2878
+ focusConfirmButton() {
2879
+ this.confirmButtonTarget.focus();
2880
+ }
2881
+ get hasTurbo() {
2882
+ return typeof Turbo !== "undefined";
2883
+ }
2884
+ get dialogHTML() {
2885
+ return `
2886
+ <dialog class="w-button-confirmation-dialog"
2887
+ data-confirmation-target="dialog"
2888
+ data-action="click->confirmation#handleClickOutside keydown->confirmation#handleKeydown">
2889
+ <div class="w-button-confirmation-dialog-content">
2890
+ <div class="w-button-confirmation-dialog-icon ${this.iconColorValue}">
2891
+ ${this.iconHTML}
2892
+ </div>
2893
+
2894
+ <h3 class="w-button-confirmation-dialog-title">
2895
+ ${this.titleValue}
2896
+ </h3>
2897
+
2898
+ <div class="w-button-confirmation-dialog-message">
2899
+ ${this.messageValue}
2900
+ </div>
2901
+
2902
+ <div class="w-button-confirmation-dialog-actions">
2903
+ <button data-confirmation-target="cancelButton"
2904
+ data-action="click->confirmation#cancel"
2905
+ class="w-button w-button-subtle w-button-medium w-button-rounded"
2906
+ style="${this.cancelStylesValue}">
2907
+ ${this.cancelTextValue}
2908
+ </button>
2909
+
2910
+ <button data-confirmation-target="confirmButton"
2911
+ data-action="click->confirmation#confirm"
2912
+ class="w-button w-button-solid w-button-medium w-button-rounded"
2913
+ style="${this.confirmStylesValue}">
2914
+ ${this.confirmTextValue}
2915
+ </button>
2916
+ </div>
2917
+ </div>
2918
+ </dialog>
2919
+ `;
2920
+ }
2921
+ get iconHTML() {
2922
+ const icons = {
2923
+ info: '<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>',
2924
+ success: '<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>',
2925
+ warning: '<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>',
2926
+ danger: '<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>'
2927
+ };
2928
+ return icons[this.iconColorValue] || icons.info;
2929
+ }
2930
+ };
2931
+
2932
+ // app/javascript/wilday_ui/controllers/tooltip_controller.js
2933
+ var tooltip_controller_default = class extends Controller {
2934
+ static targets = ["trigger"];
2935
+ static values = {
2936
+ content: String,
2937
+ position: { type: String, default: "top" },
2938
+ align: { type: String, default: "center" },
2939
+ trigger: { type: String, default: "hover" },
2940
+ showDelay: { type: Number, default: 0 },
2941
+ hideDelay: { type: Number, default: 0 },
2942
+ offset: { type: Number, default: 8 },
2943
+ theme: { type: String, default: "light" },
2944
+ size: { type: String, default: "md" },
2945
+ arrow: { type: Boolean, default: false },
2946
+ customStyle: String
2947
+ };
2948
+ connect() {
2949
+ this.tooltipElement = null;
2950
+ this.showTimeoutId = null;
2951
+ this.hideTimeoutId = null;
2952
+ this.setupTooltip();
2953
+ this.scrollHandler = () => {
2954
+ if (this.tooltipElement.style.display !== "none") {
2955
+ const triggerRect = this.triggerTarget.getBoundingClientRect();
2956
+ const isInViewport = triggerRect.top >= 0 && triggerRect.left >= 0 && triggerRect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && triggerRect.right <= (window.innerWidth || document.documentElement.clientWidth);
2957
+ if (isInViewport) {
2958
+ this.position();
2959
+ } else {
2960
+ this.hide();
2961
+ }
2962
+ }
2963
+ };
2964
+ window.addEventListener("scroll", this.scrollHandler);
2965
+ }
2966
+ disconnect() {
2967
+ if (this.clickOutsideHandler) {
2968
+ document.removeEventListener("click", this.clickOutsideHandler);
2969
+ }
2970
+ window.removeEventListener("scroll", this.scrollHandler);
2971
+ this.removeTooltip();
2972
+ }
2973
+ setupTooltip() {
2974
+ this.tooltipElement = this.createTooltipElement();
2975
+ document.body.appendChild(this.tooltipElement);
2976
+ if (this.triggerValue === "hover") {
2977
+ this.triggerTarget.addEventListener("mouseenter", () => this.show());
2978
+ this.triggerTarget.addEventListener("mouseleave", () => this.hide());
2979
+ this.triggerTarget.addEventListener("focusin", () => this.show());
2980
+ this.triggerTarget.addEventListener("focusout", () => this.hide());
2981
+ } else if (this.triggerValue === "click") {
2982
+ const hasDropdown = this.element.hasAttribute("data-controller") && this.element.getAttribute("data-controller").includes("dropdown");
2983
+ const hasClipboard = this.element.hasAttribute("data-controller") && this.element.getAttribute("data-controller").includes("clipboard");
2984
+ if (hasDropdown || hasClipboard) {
2985
+ this.triggerTarget.addEventListener("mouseenter", () => this.show());
2986
+ this.triggerTarget.addEventListener("mouseleave", () => this.hide());
2987
+ } else {
2988
+ this.triggerTarget.addEventListener("click", (e) => {
2989
+ e.stopPropagation();
2990
+ this.toggle();
2991
+ });
2992
+ this.clickOutsideHandler = (e) => {
2993
+ if (!this.triggerTarget.contains(e.target) && !this.tooltipElement.contains(e.target)) {
2994
+ this.hide();
2995
+ }
2996
+ };
2997
+ document.addEventListener("click", this.clickOutsideHandler);
2998
+ }
2999
+ }
3000
+ }
3001
+ createTooltipElement() {
3002
+ const tooltip = document.createElement("div");
3003
+ tooltip.id = this.triggerTarget.getAttribute("aria-describedby");
3004
+ tooltip.className = `w-tooltip w-tooltip-${this.themeValue} w-tooltip-size-${this.sizeValue}`;
3005
+ if (this.arrowValue) tooltip.classList.add("w-tooltip-arrow");
3006
+ tooltip.setAttribute("role", "tooltip");
3007
+ tooltip.setAttribute("data-position", this.positionValue);
3008
+ tooltip.setAttribute("data-align", this.alignValue);
3009
+ tooltip.innerHTML = this.contentValue;
3010
+ if (this.hasCustomStyleValue && this.customStyleValue) {
3011
+ tooltip.style.cssText += this.customStyleValue;
3012
+ }
3013
+ tooltip.style.display = "none";
3014
+ return tooltip;
3015
+ }
3016
+ show() {
3017
+ clearTimeout(this.hideTimeoutId);
3018
+ this.showTimeoutId = setTimeout(() => {
3019
+ this.tooltipElement.style.transform = "none";
3020
+ this.tooltipElement.style.visibility = "hidden";
3021
+ this.tooltipElement.style.display = "block";
3022
+ this.tooltipElement.offsetHeight;
3023
+ this.position();
3024
+ this.tooltipElement.style.visibility = "visible";
3025
+ requestAnimationFrame(() => {
3026
+ this.tooltipElement.classList.add("w-tooltip-visible");
3027
+ });
3028
+ }, this.showDelayValue);
3029
+ }
3030
+ hide() {
3031
+ clearTimeout(this.showTimeoutId);
3032
+ this.hideTimeoutId = setTimeout(() => {
3033
+ this.tooltipElement.classList.remove("w-tooltip-visible");
3034
+ setTimeout(() => {
3035
+ this.tooltipElement.style.display = "none";
3036
+ }, 150);
3037
+ }, this.hideDelayValue);
3038
+ }
3039
+ toggle() {
3040
+ if (this.tooltipElement.style.display === "none") {
3041
+ this.show();
3042
+ } else {
3043
+ this.hide();
3044
+ }
3045
+ }
3046
+ position() {
3047
+ const triggerRect = this.triggerTarget.getBoundingClientRect();
3048
+ const tooltipRect = this.tooltipElement.getBoundingClientRect();
3049
+ const viewportHeight = window.innerHeight;
3050
+ const viewportWidth = window.innerWidth;
3051
+ const arrowOffset = this.arrowValue ? 2 : 0;
3052
+ const scrollX = window.pageXOffset || document.documentElement.scrollLeft;
3053
+ const scrollY = window.pageYOffset || document.documentElement.scrollTop;
3054
+ console.log("=== Initial Values ===");
3055
+ console.log("Viewport Height:", viewportHeight);
3056
+ console.log("Viewport Width:", viewportWidth);
3057
+ console.log("Trigger Top:", triggerRect.top);
3058
+ console.log("Trigger Bottom:", triggerRect.bottom);
3059
+ console.log("Trigger Left:", triggerRect.left);
3060
+ console.log("Trigger Right:", triggerRect.right);
3061
+ console.log("Tooltip Height:", tooltipRect.height);
3062
+ console.log("Tooltip Width:", tooltipRect.width);
3063
+ let position = this.positionValue;
3064
+ let top, left;
3065
+ const spaceBelow = viewportHeight - triggerRect.bottom;
3066
+ const spaceAbove = triggerRect.top;
3067
+ const spaceRight = viewportWidth - triggerRect.right;
3068
+ const spaceLeft = triggerRect.left;
3069
+ const requiredSpaceVertical = tooltipRect.height + this.offsetValue + arrowOffset;
3070
+ const requiredSpaceHorizontal = tooltipRect.width + this.offsetValue + arrowOffset;
3071
+ console.log("\n=== Space Calculation ===");
3072
+ console.log("Space Above:", spaceAbove);
3073
+ console.log("Space Below:", spaceBelow);
3074
+ console.log("Space Left:", spaceLeft);
3075
+ console.log("Space Right:", spaceRight);
3076
+ console.log("Required Space Vertical:", requiredSpaceVertical);
3077
+ console.log("Required Space Horizontal:", requiredSpaceHorizontal);
3078
+ if (position === "right" && spaceRight >= requiredSpaceHorizontal) {
3079
+ position = "right";
3080
+ console.log("Using right - sufficient space");
3081
+ } else if (position === "left" && spaceLeft >= requiredSpaceHorizontal) {
3082
+ position = "left";
3083
+ console.log("Using left - sufficient space");
3084
+ } else if (position === "top" && spaceAbove >= requiredSpaceVertical) {
3085
+ position = "top";
3086
+ console.log("Using top - sufficient space");
3087
+ } else if (position === "bottom" && spaceBelow >= requiredSpaceVertical) {
3088
+ position = "bottom";
3089
+ console.log("Using bottom - sufficient space");
3090
+ } else if (spaceBelow >= requiredSpaceVertical) {
3091
+ position = "bottom";
3092
+ console.log("Fallback to bottom - sufficient space");
3093
+ } else {
3094
+ position = "top";
3095
+ console.log("Fallback to top - insufficient space below");
3096
+ }
3097
+ switch (position) {
3098
+ case "top":
3099
+ top = triggerRect.top - tooltipRect.height - this.offsetValue - arrowOffset;
3100
+ if (this.alignValue === "end") {
3101
+ left = triggerRect.right - tooltipRect.width;
3102
+ } else if (this.alignValue === "center") {
3103
+ left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
3104
+ } else {
3105
+ left = triggerRect.left;
3106
+ }
3107
+ break;
3108
+ case "bottom":
3109
+ top = triggerRect.bottom + this.offsetValue + arrowOffset;
3110
+ if (this.alignValue === "end") {
3111
+ left = triggerRect.right - tooltipRect.width;
3112
+ } else if (this.alignValue === "center") {
3113
+ left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
3114
+ } else {
3115
+ left = triggerRect.left;
3116
+ }
3117
+ break;
3118
+ case "left":
3119
+ left = triggerRect.left - tooltipRect.width - this.offsetValue - arrowOffset;
3120
+ if (this.alignValue === "end") {
3121
+ top = triggerRect.bottom - tooltipRect.height;
3122
+ } else if (this.alignValue === "center") {
3123
+ top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;
3124
+ } else {
3125
+ top = triggerRect.top;
3126
+ }
3127
+ break;
3128
+ case "right":
3129
+ left = triggerRect.right + this.offsetValue + arrowOffset;
3130
+ if (this.alignValue === "end") {
3131
+ top = triggerRect.bottom - tooltipRect.height;
3132
+ } else if (this.alignValue === "center") {
3133
+ top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;
3134
+ } else {
3135
+ top = triggerRect.top;
3136
+ }
3137
+ break;
3138
+ }
3139
+ if (top < 0) {
3140
+ top = this.offsetValue;
3141
+ } else if (top + tooltipRect.height > viewportHeight) {
3142
+ top = viewportHeight - tooltipRect.height - this.offsetValue;
3143
+ }
3144
+ if (left < 0) {
3145
+ left = this.offsetValue;
3146
+ } else if (left + tooltipRect.width > viewportWidth) {
3147
+ left = viewportWidth - tooltipRect.width - this.offsetValue;
3148
+ }
3149
+ console.log("\n=== Final Position ===");
3150
+ console.log("Position:", position);
3151
+ console.log("Top:", top);
3152
+ console.log("Left:", left);
3153
+ console.log("Alignment:", this.alignValue);
3154
+ top += scrollY;
3155
+ left += scrollX;
3156
+ this.tooltipElement.setAttribute("data-position", position);
3157
+ this.tooltipElement.style.top = `${top}px`;
3158
+ this.tooltipElement.style.left = `${left}px`;
3159
+ }
3160
+ removeTooltip() {
3161
+ if (this.tooltipElement) {
3162
+ this.tooltipElement.remove();
3163
+ this.tooltipElement = null;
3164
+ }
3165
+ }
3166
+ };
3167
+
2711
3168
  // app/javascript/wilday_ui/controllers/index.js
2712
3169
  var application = Application.start();
2713
3170
  window.Stimulus = application;
2714
3171
  application.register("button", ButtonController);
2715
3172
  application.register("dropdown", dropdown_controller_default);
3173
+ application.register("clipboard", clipboard_controller_default);
3174
+ application.register("confirmation", confirmation_controller_default);
3175
+ application.register("tooltip", tooltip_controller_default);
2716
3176
 
2717
3177
  // app/javascript/wilday_ui/components/button.js
2718
3178
  document.addEventListener("DOMContentLoaded", () => {