edvoyui-component-library-test-flight 0.0.132 → 0.0.134

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.
@@ -0,0 +1,5 @@
1
+ import _sfc_main from "/Volumes/work/repos/edvoy-ui-v2/src/components/tabs/EUITabOutline.vue?vue&type=script&setup=true&lang.ts";
2
+ export * from "/Volumes/work/repos/edvoy-ui-v2/src/components/tabs/EUITabOutline.vue?vue&type=script&setup=true&lang.ts";
3
+ import "/Volumes/work/repos/edvoy-ui-v2/src/components/tabs/EUITabOutline.vue?vue&type=style&index=0&lang.scss";
4
+ export default _sfc_main;
5
+ //# sourceMappingURL=EUITabOutline.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EUITabOutline.vue.d.ts","sourceRoot":"","sources":["../../src/components/tabs/EUITabOutline.vue"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,0GAA0G,CAAC;AACjI,cAAc,0GAA0G,CAAC;AACzH,OAAO,wGAAwG,CAAC;AAChH,eAAe,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "edvoyui-component-library-test-flight",
3
3
  "private": false,
4
- "version": "0.0.132",
4
+ "version": "0.0.134",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist/",
@@ -5,9 +5,78 @@
5
5
  >
6
6
  Edvoy User Interface
7
7
  </h1>
8
+
9
+ <div class="mb-10">
10
+ <EUITabOutline
11
+ activeColor="purple"
12
+ size="sm"
13
+ :items="allDays"
14
+ :defaultActive="activeTab"
15
+ @update:activeTabItem="onchangeActiveTab"
16
+ >
17
+ <template v-slot:content="{ data, activeName }">
18
+ <div class="space-y-4">
19
+ <span class="text-red-400">{{ data.name }} - {{ activeName }}</span>
20
+ <p> Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sit odio
21
+ quia, obcaecati suscipit, praesentium temporibus, non placeat
22
+ reprehenderit commodi ut adipisci consequatur laboriosam? Est
23
+ perspiciatis vero illo repudiandae quis explicabo.</p>
24
+
25
+ <p> Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sit odio
26
+ quia, obcaecati suscipit, praesentium temporibus, non placeat
27
+ reprehenderit commodi ut adipisci consequatur laboriosam? Est
28
+ perspiciatis vero illo repudiandae quis explicabo.</p>
29
+ </div>
30
+ </template>
31
+ </EUITabOutline>
32
+ </div>
33
+
34
+ <div>
35
+ <EUIButtonGroup
36
+ activeColor="purple"
37
+ size="sm"
38
+ :rounded="false"
39
+ :items="allDays"
40
+ :defaultActive="activeDays"
41
+ @update:activeButton="onchangeDays"
42
+ >
43
+ <template #before>
44
+ <div
45
+ class="px-2 text-sm font-normal leading-tight tracking-wide text-black me-4 font-inter"
46
+ >
47
+ Renewals due in <span class="font-bold text-red-500 text-xxs"> {{ activeDays }}</span>
48
+ </div>
49
+ </template>
50
+ <template #default="{ data, activeName}">
51
+ {{ data.name }} <small :class="activeName === data.name ? 'opacity-100': 'opacity-75'">({{ data.count }})</small>
52
+ </template>
53
+ </EUIButtonGroup>
54
+ </div>
8
55
  </div>
9
56
  </template>
10
57
  <script setup lang="ts">
58
+ import { ref } from "vue";
59
+ import EUITabOutline from "./tabs/EUITabOutline.vue";
60
+ import EUIButtonGroup from "./button/EUIButtonGroup.vue";
61
+
62
+ const allDays = ref([
63
+ { name: "7 days", count: 5 },
64
+ { name: "15 days", count: 10 },
65
+ { name: "16-30 days", count: 20 },
66
+ { name: "31-60 days", count: 121 },
67
+ { name: "61-90 days", count: 40 },
68
+ ]);
69
+
70
+ const activeDays = ref(allDays.value[0].name);
71
+ const activeTab = ref(allDays.value[3].name)
72
+
73
+ const onchangeActiveTab = (val: any) => {
74
+ activeTab.value = val.name;
75
+ };
76
+
77
+ const onchangeDays = (val:any) => {
78
+ activeDays.value = val.name
79
+ }
11
80
  </script>
12
81
  <style lang="scss"></style>
13
82
 
@@ -1,15 +1,23 @@
1
1
  <template>
2
- <div
3
- class="inline-flex items-center gap-2 px-2 py-2 overflow-hidden transition-all duration-200 ease-in bg-white rounded-full shadow-xl w-max shadow-purple-50"
4
- :class="[rounded ? 'rounded-full' : 'rounded-lg']"
2
+ <div>
3
+ <div
4
+ class="inline-flex items-center gap-2 px-2 py-2 overflow-hidden transition-all duration-200 ease-in bg-white shadow-xl w-max shadow-purple-50"
5
+ :class="[rounded ? 'rounded-full' : 'rounded-lg']"
6
+ v-bind="$attrs"
5
7
  >
6
8
  <slot name="before" />
7
9
  <nav class="relative z-0 inline-flex flex-row items-center gap-2">
8
- <div id="nav-indicator" :class="[getBtnClass(activeBtnName), rounded ? 'rounded-full' : 'rounded-lg']"></div>
10
+ <div
11
+ id="nav-indicator"
12
+ :class="[
13
+ getBtnClass(activeBtnName),
14
+ rounded ? 'rounded-full' : 'rounded-lg',
15
+ ]"
16
+ ></div>
9
17
  <button
10
18
  v-for="(data, index) in items"
11
19
  :key="`data-${index}`"
12
- v-bind="$attrs"
20
+ v-bind="buttonAttrs"
13
21
  :type="type"
14
22
  :size="size"
15
23
  :iconType="iconType"
@@ -31,7 +39,9 @@
31
39
  v-if="iconType === 'icon' || iconType === 'startIcon'"
32
40
  :class="[iconWidth]"
33
41
  />
34
- <slot :data="data" :activeName="activeBtnName"> {{ data?.name }} </slot>
42
+ <slot :data="data" :activeName="activeBtnName">
43
+ {{ data?.name }}
44
+ </slot>
35
45
  <component
36
46
  :is="icon"
37
47
  v-if="iconType === 'endIcon'"
@@ -63,6 +73,7 @@
63
73
  </nav>
64
74
  <slot name="after" />
65
75
  </div>
76
+ </div>
66
77
  </template>
67
78
 
68
79
  <script setup lang="ts">
@@ -74,6 +85,7 @@ import {
74
85
  reactive,
75
86
  ref,
76
87
  toRefs,
88
+ useAttrs,
77
89
  } from "vue";
78
90
 
79
91
  interface Item {
@@ -87,8 +99,8 @@ const props = defineProps({
87
99
  default: () => [],
88
100
  },
89
101
  defaultActive: {
90
- type: String,
91
- default: "",
102
+ type:String,
103
+ default: '',
92
104
  },
93
105
  type: {
94
106
  type: String as PropType<"button" | "submit" | "reset">,
@@ -126,8 +138,17 @@ const props = defineProps({
126
138
  disabled: Boolean,
127
139
  });
128
140
 
141
+ defineOptions({
142
+ inheritAttrs: false, // 🛑 prevents auto-inheritance of $attrs to root
143
+ })
144
+ const attrs = useAttrs()
145
+ const buttonAttrs = computed(() => {
146
+ const { class: _class, style: _style, id: _id, ...rest } = attrs;
147
+ return rest;
148
+ });
149
+
129
150
  const emit = defineEmits<{
130
- (event: "update:clickedButton", activeTab: Item): void;
151
+ (event: "update:activeButton", activeButton: Item): void;
131
152
  }>();
132
153
 
133
154
  const { items, defaultActive } = toRefs(props);
@@ -141,9 +162,9 @@ const marker = (el: HTMLElement) => {
141
162
  }
142
163
  };
143
164
 
144
- const handleOnChange = (val:any) => {
165
+ const handleOnChange = (val: any) => {
145
166
  activeBtnName.value = val?.name;
146
- emit("update:clickedButton", val);
167
+ emit("update:activeButton", val);
147
168
  nextTick(() => {
148
169
  const activeBtn = document.querySelector(
149
170
  `nav button[data-name="${activeBtnName.value}"]`
@@ -24,6 +24,8 @@ export { default as EUISlideover } from "./slideover/EUISlideover.vue";
24
24
  export { default as EUIDatepicker } from "./datepicker/EUIDatepicker.vue";
25
25
 
26
26
  export { default as EUITabs } from "./tabs/EUITabs.vue";
27
+ export { default as EUITabOutline } from "./tabs/EUITabOutline.vue";
28
+
27
29
  export { default as EUIPillSelect } from "./pillSelect/EUIPillSelect.vue";
28
30
  export { default as EUITimeLine } from "./timeLine/EUITimeLine.vue";
29
31
  export { default as EUITag } from "./tag/EUITag.vue";
@@ -0,0 +1,263 @@
1
+ <template>
2
+ <div class="bg-white" v-bind="$attrs">
3
+ <div
4
+ class="relative z-10 inline-flex items-center w-full gap-2 pt-3 overflow-hidden transition-all duration-200 ease-in border border-b-0 border-solid rounded-t-xl isolate before:h-4 before:w-px before:bg-gray-200 before:-bottom-3 before:-left-px before:absolute after:h-4 after:w-px after:bg-gray-200 after:-bottom-3 after:-right-px after:absolute bg-gradient-to-b from-gray-100"
5
+ >
6
+ <nav
7
+ class="relative z-0 inline-flex flex-row items-center w-full gap-2 px-6"
8
+ >
9
+ <div
10
+ id="tab-indicator"
11
+ :style="{
12
+ '--border': allColor[activeColor],
13
+ }"
14
+ >
15
+ <span></span>
16
+ </div>
17
+ <button
18
+ v-for="(data, index) in items"
19
+ :key="`data-${index}`"
20
+ v-bind="buttonAttrs"
21
+ :data-tab="data.name"
22
+ :class="[
23
+ 'capitalize box-border border-none inline-flex flex-row gap-x-2 items-center',
24
+ getBtnClass(data.name || ''),
25
+ activeBtnName === data.name ? 'font-semibold' : 'font-normal',
26
+ ]"
27
+ :disabled="disabled"
28
+ :loading="loading"
29
+ @click="handleOnChange(data || '')"
30
+ style="transition: all 350ms cubic-bezier(0.15, 0.3, 0.25, 1)"
31
+ >
32
+ <component
33
+ :is="icon"
34
+ v-if="iconType === 'icon' || iconType === 'startIcon'"
35
+ :class="[iconWidth]"
36
+ />
37
+ <slot :data="data" :activeName="activeBtnName">
38
+ {{ data?.name }}
39
+ </slot>
40
+ <component
41
+ :is="icon"
42
+ v-if="iconType === 'endIcon'"
43
+ :class="[iconWidth]"
44
+ />
45
+ <svg
46
+ v-if="loading"
47
+ class="animate-spin"
48
+ :class="[iconWidth]"
49
+ xmlns="http://www.w3.org/2000/svg"
50
+ fill="none"
51
+ viewBox="0 0 24 24"
52
+ >
53
+ <circle
54
+ class="opacity-25"
55
+ cx="12"
56
+ cy="12"
57
+ r="10"
58
+ stroke="currentColor"
59
+ stroke-width="4"
60
+ />
61
+ <path
62
+ fill="currentColor"
63
+ class="opacity-75"
64
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
65
+ />
66
+ </svg>
67
+ </button>
68
+ </nav>
69
+ </div>
70
+
71
+ <div
72
+ class="relative z-0 px-4 py-4 -mt-px text-gray-500 border border-gray-200 border-solid rounded-b-xl"
73
+ >
74
+ <template v-for="(data, index) in items" :key="`data-${index}`">
75
+ <slot
76
+ v-if="data.name === activeBtnName"
77
+ name="content"
78
+ :data="data"
79
+ :activeName="activeBtnName"
80
+ >
81
+ {{ data.name }}
82
+ </slot>
83
+ </template>
84
+ </div>
85
+ </div>
86
+ </template>
87
+
88
+ <script setup lang="ts">
89
+ import {
90
+ computed,
91
+ nextTick,
92
+ onMounted,
93
+ PropType,
94
+ reactive,
95
+ ref,
96
+ toRefs,
97
+ useAttrs,
98
+ } from "vue";
99
+
100
+ interface Item {
101
+ name: string;
102
+ [key: string]: any;
103
+ }
104
+
105
+ const props = defineProps({
106
+ items: {
107
+ type: Array as () => Item[],
108
+ default: () => [],
109
+ },
110
+ defaultActive: {
111
+ type: String,
112
+ default: "",
113
+ },
114
+ type: {
115
+ type: String,
116
+ default: "button",
117
+ },
118
+ size: {
119
+ type: String as PropType<"sm" | "md" | "lg">,
120
+ default: "md",
121
+ },
122
+ activeColor: {
123
+ type: String as PropType<"success" | "black" | "purple" | "default">,
124
+ default: "black",
125
+ },
126
+ iconType: {
127
+ type: String as PropType<"startIcon" | "endIcon" | "icon">,
128
+ default: "",
129
+ },
130
+ icon: {
131
+ type: [String, Object, Function],
132
+ default: "",
133
+ },
134
+ loading: Boolean,
135
+ disabled: Boolean,
136
+ });
137
+
138
+ const emit = defineEmits<{
139
+ (event: "update:activeTabItem", activeTabItem: Item): void;
140
+ }>();
141
+
142
+ defineOptions({
143
+ inheritAttrs: false, // 🛑 prevents auto-inheritance of $attrs to root
144
+ });
145
+ const attrs = useAttrs();
146
+ const buttonAttrs = computed(() => {
147
+ const { class: _class, style: _style, id: _id, ...rest } = attrs;
148
+ return rest;
149
+ });
150
+
151
+ const { items, defaultActive } = toRefs(props);
152
+ const activeBtnName = ref(defaultActive.value || items.value[0]?.name || "");
153
+
154
+ const marker = (el: HTMLElement) => {
155
+ const indicator = document.querySelector("#tab-indicator") as HTMLElement;
156
+ if (indicator && el) {
157
+ indicator.style.left = el.offsetLeft + "px";
158
+ indicator.style.width = el.offsetWidth + "px";
159
+ }
160
+ };
161
+
162
+ const handleOnChange = (val: any) => {
163
+ activeBtnName.value = val?.name;
164
+ emit("update:activeTabItem", val);
165
+ nextTick(() => {
166
+ const activeBtn = document.querySelector(
167
+ `nav button[data-tab="${activeBtnName.value}"]`
168
+ );
169
+ if (activeBtn) marker(activeBtn as HTMLElement);
170
+ });
171
+ };
172
+
173
+ onMounted(() => {
174
+ nextTick(() => {
175
+ requestAnimationFrame(() => {
176
+ const activeBtn = document.querySelector(
177
+ `nav button[data-tab="${activeBtnName.value}"]`
178
+ );
179
+ if (activeBtn) marker(activeBtn as HTMLElement);
180
+ });
181
+ });
182
+ });
183
+
184
+ const btnColors = {
185
+ default: {
186
+ enabled: "text-gray-500 cursor-pointer hover:text-gray-700",
187
+ disabled: "bg-opacity-60 cursor-not-allowed text-gray-200 bg-gray-800",
188
+ },
189
+ black: {
190
+ enabled: "text-black cursor-pointer",
191
+ disabled: "cursor-not-allowed text-gray-300",
192
+ },
193
+ success: {
194
+ enabled: "text-green-600 cursor-pointer",
195
+ disabled: "cursor-not-allowed text-green-700/60",
196
+ },
197
+ purple: {
198
+ enabled: "text-purple-600 cursor-pointer",
199
+ disabled: "cursor-not-allowed text-purple-400",
200
+ },
201
+ };
202
+
203
+ const iconClasses = {
204
+ lg: props.iconType === "icon" ? "p-3" : "px-6 py-3",
205
+ md: props.iconType === "icon" ? "p-2" : "px-4 py-2",
206
+ sm: props.iconType === "icon" ? "p-1.5" : "px-4 py-1.5",
207
+ };
208
+
209
+ const iconWidthClasses = reactive({
210
+ sm: "w-5 h-5 text-current",
211
+ md: "w-6 h-6 text-current",
212
+ lg: "w-6 h-6 text-current",
213
+ });
214
+
215
+ const iconWidth = computed(() => {
216
+ return iconWidthClasses[props.size] || "";
217
+ });
218
+
219
+ const getBtnClass = (btnName: string) => {
220
+ const isActive = btnName === activeBtnName.value;
221
+ const colorKey = isActive ? props.activeColor : "default";
222
+ const state = props.disabled ? "disabled" : "enabled";
223
+ const colorClass = btnColors[colorKey] ? btnColors[colorKey][state] : "";
224
+ const sizeClass = props.size === "sm" ? "text-sm" : "text-base";
225
+ const typeClass = iconClasses[props.size] || "";
226
+ return `${colorClass} ${sizeClass} ${typeClass}`;
227
+ };
228
+
229
+ const allColor = {
230
+ purple: "#7c3aed",
231
+ success: "#16a34a",
232
+ black: "#000",
233
+ default: "#9ca3af",
234
+ };
235
+ </script>
236
+
237
+ <style lang="scss">
238
+ :root {
239
+ --clr: theme("colors.white");
240
+ }
241
+
242
+ #tab-indicator {
243
+ transition: all 350ms cubic-bezier(0.15, 0.3, 0.25, 1);
244
+ background-image: linear-gradient(90deg, #fff, #fff),
245
+ linear-gradient(to top, #e5e7eb, #e5e7eb, var(--border));
246
+ background-origin: border-box;
247
+ background-clip: padding-box, border-box;
248
+ @apply absolute left-0 w-auto h-full top-0 -z-[1] rounded-t-xl border-solid border-t-2 border bg-white p-2 border-transparent;
249
+ &::before {
250
+ content: "";
251
+ box-shadow: 5px 5px 0 5px var(--clr);
252
+ @apply absolute -bottom-px -left-3 size-3 bg-transparent border border-gray-200 border-solid border-l-0 border-t-0 rounded-br-2xl;
253
+ }
254
+ &::after {
255
+ content: "";
256
+ box-shadow: -5px 5px 0 5px var(--clr);
257
+ @apply absolute -bottom-px -right-3 size-3 bg-transparent border border-gray-200 border-solid border-r-0 border-t-0 rounded-bl-2xl;
258
+ }
259
+ span {
260
+ @apply bg-white w-full h-1 absolute -bottom-px inset-x-0 z-[1];
261
+ }
262
+ }
263
+ </style>