@nixweb/nixloc-ui 1.3.0 → 1.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nixweb/nixloc-ui",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Componentes UI",
5
5
  "author": "Fábio Ávila <fabio@nixweb.com.br>",
6
6
  "private": false,
@@ -0,0 +1,210 @@
1
+ <template>
2
+ <div class="button-inline-group" ref="wrap">
3
+ <button class="button-inline-trigger" title="Mais opções" @click.stop="toggleMenu" ref="triggerBtn">
4
+ <i class="fa-solid fa-ellipsis-vertical"></i>
5
+ </button>
6
+
7
+ <transition name="button-inline-fade">
8
+ <div v-if="showMenu" class="button-inline-popover-fixed" :style="popoverStyle" ref="popover" role="menu">
9
+ <div class="button-inline-popover-inner">
10
+ <div class="button-inline-buttons">
11
+ <button v-for="(btn, i) in buttons" :key="btn.id || i" class="button-inline-btn"
12
+ :title="btn.title" :style="buttonStyle(btn, i)" @click="onAction(btn)">
13
+ <i :class="btn.icon"></i>
14
+ </button>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ </transition>
19
+ </div>
20
+ </template>
21
+
22
+ <script>
23
+
24
+ import { mapMutations } from "vuex";
25
+
26
+ export default {
27
+ name: "ButtonGroupInline",
28
+ props: {
29
+ buttons: { type: Array, required: true },
30
+ defaultSize: { type: Number, default: 35 }
31
+ },
32
+ data() {
33
+ return {
34
+ showMenu: false,
35
+ popoverStyle: {
36
+ position: "fixed",
37
+ top: "0px",
38
+ left: "0px",
39
+ transform: "translateX(-50%)",
40
+ zIndex: 9999
41
+ }
42
+ };
43
+ },
44
+ methods: {
45
+ ...mapMutations("generic", ["addEvent"]),
46
+ toggleMenu() {
47
+ this.showMenu = !this.showMenu;
48
+ if (this.showMenu) {
49
+ this.$nextTick(() => {
50
+ this.positionPopover();
51
+ window.addEventListener("scroll", this.positionPopover, true);
52
+ window.addEventListener("resize", this.positionPopover, true);
53
+ document.addEventListener("click", this.onOutsideClick, true);
54
+ document.addEventListener("keydown", this.onKeydown, true);
55
+ });
56
+ } else {
57
+ this.unbindGlobal();
58
+ }
59
+ },
60
+ positionPopover() {
61
+ const trigger = this.$refs.triggerBtn;
62
+ const pop = this.$refs.popover;
63
+ if (!trigger || !pop) return;
64
+
65
+ const rect = trigger.getBoundingClientRect();
66
+ let top = rect.bottom + 6;
67
+ let center = rect.left + rect.width / 2;
68
+
69
+ const popWidth = pop.offsetWidth || 0;
70
+ const vw = window.innerWidth || document.documentElement.clientWidth;
71
+ const margin = 8;
72
+
73
+ const minCenter = margin + popWidth / 2;
74
+ const maxCenter = vw - margin - popWidth / 2;
75
+ center = Math.max(minCenter, Math.min(maxCenter, center));
76
+
77
+ const popHeight = pop.offsetHeight || 0;
78
+ const vh = window.innerHeight || document.documentElement.clientHeight;
79
+ const spaceBelow = vh - rect.bottom;
80
+ const spaceAbove = rect.top;
81
+
82
+ if (spaceBelow < popHeight + 12 && spaceAbove > popHeight + 12) {
83
+ top = rect.top - 6 - popHeight;
84
+ }
85
+
86
+ this.popoverStyle = {
87
+ position: "fixed",
88
+ top: `${Math.round(top)}px`,
89
+ left: `${Math.round(center)}px`,
90
+ transform: "translateX(-50%)",
91
+ zIndex: 9999
92
+ };
93
+ },
94
+ onOutsideClick(e) {
95
+ const wrap = this.$refs.wrap;
96
+ const pop = this.$refs.popover;
97
+ if ((wrap && wrap.contains(e.target)) || (pop && pop.contains(e.target))) return;
98
+ this.showMenu = false;
99
+ this.unbindGlobal();
100
+
101
+ },
102
+ onKeydown(e) {
103
+ if (e.key === "Escape") {
104
+ this.showMenu = false;
105
+ this.unbindGlobal();
106
+ }
107
+ },
108
+ unbindGlobal() {
109
+ window.removeEventListener("scroll", this.positionPopover, true);
110
+ window.removeEventListener("resize", this.positionPopover, true);
111
+ document.removeEventListener("click", this.onOutsideClick, true);
112
+ document.removeEventListener("keydown", this.onKeydown, true);
113
+ },
114
+ onAction(btn) {
115
+ this.$emit("action", btn);
116
+ this.showMenu = false;
117
+ this.unbindGlobal();
118
+ this.addEvent({ name: btn.eventName, data: btn.eventData });
119
+ },
120
+ buttonStyle(btn, i) {
121
+ const size = btn.size || this.defaultSize;
122
+ return {
123
+ backgroundColor: btn.color || "#577696",
124
+ width: size + "px",
125
+ height: size + "px",
126
+ transitionDelay: `${i * 45}ms`
127
+ };
128
+ }
129
+ },
130
+ beforeDestroy() {
131
+ this.unbindGlobal();
132
+ }
133
+ };
134
+ </script>
135
+
136
+ <style scoped>
137
+ .button-inline-group {
138
+ position: relative;
139
+ display: inline-block;
140
+ }
141
+
142
+ .button-inline-trigger {
143
+ display: inline-flex;
144
+ align-items: center;
145
+ justify-content: center;
146
+ width: 34px;
147
+ height: 34px;
148
+ border-radius: 50%;
149
+ background: transparent;
150
+ border: none;
151
+ color: #9b9ea3;
152
+ font-size: 16px;
153
+ cursor: pointer;
154
+ transition: all 0.2s ease;
155
+ }
156
+
157
+ .button-inline-trigger:hover {
158
+ background: #f3f4f6;
159
+ color: #111827;
160
+ }
161
+
162
+ .button-inline-popover-fixed {
163
+ position: fixed;
164
+ pointer-events: auto;
165
+ }
166
+
167
+ .button-inline-popover-inner {
168
+ background: #ffffff;
169
+ border: 1px solid #e6ebf2;
170
+ border-radius: 50px;
171
+ box-shadow: 0 8px 24px rgba(16, 24, 40, 0.12);
172
+ padding: 2px;
173
+ }
174
+
175
+ .button-inline-buttons {
176
+ display: flex;
177
+ justify-content: center;
178
+ align-items: center;
179
+ gap: 12px;
180
+ padding: 4px;
181
+ }
182
+
183
+ .button-inline-btn {
184
+ border-radius: 50%;
185
+ border: none;
186
+ color: #fff;
187
+ display: flex;
188
+ align-items: center;
189
+ justify-content: center;
190
+ font-size: 15px;
191
+ cursor: pointer;
192
+ transition: all 0.18s ease;
193
+ }
194
+
195
+ .button-inline-btn:hover {
196
+ filter: brightness(0.9);
197
+ transform: translateY(-2px);
198
+ }
199
+
200
+ /* Fade animado */
201
+ .button-inline-fade-enter-active,
202
+ .button-inline-fade-leave-active {
203
+ transition: opacity 0.25s ease;
204
+ }
205
+
206
+ .button-inline-fade-enter,
207
+ .button-inline-fade-leave-to {
208
+ opacity: 0;
209
+ }
210
+ </style>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="form-group">
3
- <label>
3
+ <label v-if="title">
4
4
  <span class="title">{{ title }} </span>
5
5
  <span class="required" v-if="required">*</span>
6
6
  <Tip :field="field" :formName="formName" />