sprintify-ui 0.4.2 → 0.4.4

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": "sprintify-ui",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "scripts": {
5
5
  "build": "rimraf dist && vue-tsc && vite build",
6
6
  "build-fast": "rimraf dist && vite build",
@@ -41,7 +41,8 @@
41
41
  "dependencies": {
42
42
  "@headlessui/vue": "^1.7.12",
43
43
  "color2k": "^2.0.2",
44
- "tailwind-merge": "^1.12.0"
44
+ "tailwind-merge": "^1.12.0",
45
+ "vue-tippy": "^6.3.1"
45
46
  },
46
47
  "devDependencies": {
47
48
  "@babel/core": "^7.20.12",
@@ -3,6 +3,7 @@ import BaseClipboard from './BaseClipboard.vue';
3
3
  export default {
4
4
  title: 'Components/BaseClipboard',
5
5
  component: BaseClipboard,
6
+ args: {},
6
7
  argTypes: {},
7
8
  };
8
9
 
@@ -12,13 +13,13 @@ const Template = (args) => ({
12
13
  return { args };
13
14
  },
14
15
  template: `
15
- <BaseClipboard class="mb-3">
16
+ <BaseClipboard v-bind="args" class="mb-3">
16
17
  <span class="underline text-blue-600">{{ args.value }}</span>
17
18
  </BaseClipboard>
18
19
 
19
20
  <br>
20
21
 
21
- <BaseClipboard class="mb-3 border border-slate-200 rounded px-2 py-px">
22
+ <BaseClipboard v-bind="args" class="mb-3 border border-slate-200 rounded px-2 py-px">
22
23
  <BaseIcon icon="heroicons:server" class="mr-2 text-slate-500" />
23
24
  <span class="font-mono text-sm text-slate-600">{{ args.value }}</span>
24
25
  </BaseClipboard>
@@ -1,50 +1,18 @@
1
1
  <template>
2
2
  <button
3
+ ref="btn"
3
4
  type="button"
4
5
  class="relative inline-flex items-center"
5
- @click="copyText()"
6
- @mouseenter="showTooltip()"
7
- @mouseleave="hideTooltip()"
8
6
  >
9
7
  <slot />
10
- <transition
11
- enter-active-class="transition duration-200 ease-out"
12
- enter-from-class="transform scale-90 opacity-0"
13
- enter-to-class="transform scale-100 opacity-100"
14
- leave-active-class="transition duration-75 ease-in"
15
- leave-from-class="transform scale-100 opacity-100"
16
- leave-to-class="transform scale-90 opacity-0"
17
- >
18
- <div
19
- v-show="tooltipShown"
20
- class="pointer-events-none absolute left-full z-[1] items-center"
21
- >
22
- <div
23
- class="ml-2 whitespace-nowrap rounded bg-slate-900 bg-opacity-80 px-3 py-2 text-xs leading-tight text-white backdrop-blur"
24
- >
25
- <div
26
- v-if="showCopied"
27
- class="flex items-center"
28
- >
29
- <BaseIcon
30
- class="mr-1 text-green-500"
31
- icon="heroicons:check-circle-solid"
32
- />
33
- {{ t('sui.copied') }}
34
- </div>
35
- <div v-else>
36
- {{ t('sui.click_to_copy') }}
37
- </div>
38
- </div>
39
- </div>
40
- </transition>
41
8
  </button>
42
9
  </template>
43
10
 
44
11
  <script lang="ts" setup>
45
12
  import { t } from '@/i18n';
13
+ import { useTippy } from 'vue-tippy'
14
+ import 'tippy.js/dist/tippy.css'
46
15
 
47
- const tooltipShown = ref(false);
48
16
  const showCopied = ref(false);
49
17
 
50
18
  const props = defineProps({
@@ -54,6 +22,34 @@ const props = defineProps({
54
22
  },
55
23
  });
56
24
 
25
+ const btn = ref();
26
+
27
+ const content = computed(() => {
28
+ return showCopied.value ?
29
+ `<div class="flex items-center">
30
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 mr-1 text-green-500">
31
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
32
+ </svg>
33
+ ${t('sui.copied')}
34
+ </div>` :
35
+
36
+ t('sui.click_to_copy')
37
+ })
38
+
39
+ useTippy(btn, {
40
+ content: content,
41
+ placement: 'auto',
42
+ interactive: true,
43
+ hideOnClick: 'toggle',
44
+ trigger: 'mouseenter click',
45
+ allowHTML: true,
46
+ onTrigger(instance, event) {
47
+ if (event.type === 'click') {
48
+ copyText(instance)
49
+ }
50
+ },
51
+ })
52
+
57
53
  async function writeText(text: string) {
58
54
  if (
59
55
  typeof navigator === 'undefined' ||
@@ -66,31 +62,19 @@ async function writeText(text: string) {
66
62
  await navigator.clipboard.writeText(text);
67
63
  }
68
64
 
69
- let timeoutId = null as null | number;
65
+ let timeoutId = undefined as undefined | number;
70
66
 
71
- function showTooltip() {
72
- tooltipShown.value = true;
73
- }
67
+ function copyText(instance: any) {
74
68
 
75
- function hideTooltip() {
76
- tooltipShown.value = false;
77
- setTimeout(() => {
78
- showCopied.value = false;
79
- }, 200);
80
- if (timeoutId) {
81
- clearTimeout(timeoutId);
82
- }
83
- }
84
-
85
- function copyText() {
86
69
  writeText(props.value);
87
- showSuccessMessage();
70
+ showSuccessMessage(instance);
88
71
  }
89
72
 
90
- function showSuccessMessage() {
73
+ function showSuccessMessage(instance: any) {
91
74
  showCopied.value = true;
92
75
  timeoutId = setTimeout(() => {
93
- tooltipShown.value = false;
76
+ instance.hide();
77
+ clearTimeout(timeoutId);
94
78
  setTimeout(() => {
95
79
  showCopied.value = false;
96
80
  }, 200);
@@ -8,16 +8,6 @@ export default {
8
8
  showTooltip: {
9
9
  control: { type: 'boolean' },
10
10
  },
11
- tooltipPosition: {
12
- options: ['top', 'bottom', 'right', 'left'],
13
- control: { type: 'radio' },
14
- if: { arg: 'showTooltip' },
15
- },
16
- tooltipSize: {
17
- options: ['small', 'medium', 'large'],
18
- control: { type: 'radio' },
19
- if: { arg: 'showTooltip' },
20
- },
21
11
  },
22
12
  args: {
23
13
  value: DateTime.now().minus({ minutes: 2 }).toISO(),
@@ -37,8 +27,6 @@ const Template = (args) => ({
37
27
  export const Demo = Template.bind({});
38
28
  Demo.args = {
39
29
  showTooltip: true,
40
- tooltipPosition: 'top',
41
- tooltipSize: 'large',
42
30
  };
43
31
 
44
32
  const TemplateCustom = (args) => ({
@@ -1,10 +1,7 @@
1
1
  <template>
2
2
  <component
3
3
  :is="as"
4
- :aria-label="showTooltip ? tooltip : undefined"
5
- :data-microtip-position="showTooltip ? tooltipPosition : undefined"
6
- :data-microtip-size="showTooltip ? tooltipSize : undefined"
7
- :role="showTooltip ? 'tooltip' : undefined"
4
+ :ref="showTooltip ? 'tooltip' : ''"
8
5
  >
9
6
  <slot
10
7
  name="default"
@@ -22,7 +19,9 @@ import { t } from '@/i18n';
22
19
  import { useI18nStore } from '@/stores/i18n';
23
20
  import humanizeDuration from 'humanize-duration';
24
21
  import { DateTime } from 'luxon';
25
- import { PropType } from 'vue';
22
+ import { useTippy } from 'vue-tippy'
23
+ import 'tippy.js/dist/tippy.css'
24
+
26
25
  const props = defineProps({
27
26
  value: {
28
27
  required: true,
@@ -32,14 +31,6 @@ const props = defineProps({
32
31
  default: false,
33
32
  type: Boolean,
34
33
  },
35
- tooltipPosition: {
36
- default: 'top',
37
- type: String as PropType<'top' | 'right' | 'left' | 'bottom'>,
38
- },
39
- tooltipSize: {
40
- default: 'large',
41
- type: String as PropType<'small' | 'medium' | 'large'>,
42
- },
43
34
  timeZone: {
44
35
  default: 'utc',
45
36
  type: String,
@@ -50,6 +41,19 @@ const props = defineProps({
50
41
  },
51
42
  });
52
43
 
44
+ const tooltip = ref();
45
+
46
+ const tooltipContent = computed(() => {
47
+ return DateTime.fromISO(props.value)
48
+ .setLocale(useI18nStore().locale)
49
+ .toLocaleString(DateTime.DATETIME_FULL);
50
+ });
51
+
52
+ useTippy(tooltip, {
53
+ content: tooltipContent,
54
+ placement: 'auto',
55
+ })
56
+
53
57
  const now = ref(DateTime.now().toSeconds());
54
58
 
55
59
  function getMinutes(duration: number) {
@@ -111,11 +115,6 @@ const readableDate = computed(() => {
111
115
  return t('sui.x_ago', { duration: durationHuman });
112
116
  });
113
117
 
114
- const tooltip = computed(() => {
115
- return DateTime.fromISO(props.value)
116
- .setLocale(useI18nStore().locale)
117
- .toLocaleString(DateTime.DATETIME_FULL);
118
- });
119
118
 
120
119
  onBeforeUnmount(() => {
121
120
  clearInterval(intervalId);
@@ -47,10 +47,9 @@
47
47
  </div>
48
48
  <div class="shrink-0">
49
49
  <BaseIcon
50
- v-if="
51
- (optionProps.selected ?? false) ||
52
- (optionProps.option[valueKey] == null && newValue == null)
53
- "
50
+ v-if="(optionProps.selected ?? false) ||
51
+ (optionProps.option[valueKey] == null && newValue == null)
52
+ "
54
53
  icon="mdi:check-bold"
55
54
  class="h-4 w-4 text-slate-500"
56
55
  />
@@ -168,7 +167,7 @@ const autocompleteProps = computed(() => {
168
167
 
169
168
  if (!props.multiple) {
170
169
  newProps.showModelValue = false;
171
- newProps.showEmptyOption = true;
170
+ newProps.showEmptyOption = !props.required;
172
171
  newProps.emptyOptionLabel = props.emptyOptionLabel;
173
172
  }
174
173
 
@@ -20,7 +20,7 @@ const Template = (args) => ({
20
20
  return { args };
21
21
  },
22
22
  template: `
23
- <form @submit.prevent="" class="mt-10">
23
+ <form @submit.prevent="">
24
24
  <BaseInputLabel v-bind="args"></BaseInputLabel>
25
25
  <BaseInput required name="name" placeholder="Enter your first name"></BaseInput>
26
26
  </form>
@@ -1,10 +1,9 @@
1
1
  <template>
2
2
  <label :class="classes">
3
3
  <div
4
- class="relative"
4
+ :ref="help ? 'info' : ''"
5
+ class="relative inline-flex items-center"
5
6
  :class="[help ? 'cursor-help' : 'cursor-default']"
6
- @mouseenter="showTooltip = true"
7
- @mouseleave="showTooltip = false"
8
7
  >
9
8
  <span> {{ label }}</span>
10
9
 
@@ -18,58 +17,41 @@
18
17
  v-if="required"
19
18
  class="ml-0.5 text-red-600"
20
19
  > *</span>
21
-
22
- <Transition
23
- enter-active-class="transition duration-200 ease-out"
24
- enter-from-class="transform scale-95 opacity-0"
25
- enter-to-class="transform scale-100 opacity-100"
26
- leave-active-class="transition duration-75 ease-in"
27
- leave-from-class="transform scale-100 opacity-100"
28
- leave-to-class="transform scale-95 opacity-0"
29
- >
30
- <div
31
- v-if="showTooltip && help"
32
- class="pointer-events-none absolute bottom-[100%] left-0 z-[1] w-auto max-w-[300px]"
33
- >
34
- <div
35
- class="relative bottom-1 rounded-md bg-slate-700 py-1 px-2 text-xs leading-tight text-white"
36
- >
37
- {{ help }}
38
- </div>
39
- </div>
40
- </Transition>
41
20
  </div>
42
21
  </label>
43
22
  </template>
44
23
 
45
- <script lang="ts">
46
- import { defineComponent, PropType } from 'vue';
24
+ <script lang="ts" setup>
25
+ import { PropType } from 'vue';
47
26
  import { Icon as BaseIcon } from '@iconify/vue';
27
+ import { useTippy } from 'vue-tippy'
28
+ import 'tippy.js/dist/tippy.css'
48
29
 
49
- export default defineComponent({
50
- components: { BaseIcon },
51
- props: {
52
- required: {
53
- default: false,
54
- type: Boolean,
55
- },
56
- label: {
57
- required: true,
58
- type: String,
59
- },
60
- classes: {
61
- default: 'mb-1 block text-sm',
62
- type: String,
63
- },
64
- help: {
65
- default: null,
66
- type: [String, null] as PropType<string | null>,
67
- },
30
+ const props = defineProps({
31
+ required: {
32
+ default: false,
33
+ type: Boolean,
34
+ },
35
+ label: {
36
+ required: true,
37
+ type: String,
38
+ },
39
+ classes: {
40
+ default: 'mb-1 block text-sm',
41
+ type: String,
68
42
  },
69
- data() {
70
- return {
71
- showTooltip: false,
72
- };
43
+ help: {
44
+ default: null,
45
+ type: [String, null] as PropType<string | null>,
73
46
  },
74
47
  });
48
+
49
+ const info = ref();
50
+ const content = computed(() => { return props.help })
51
+
52
+ useTippy(info, {
53
+ content: content,
54
+ placement: 'auto',
55
+ })
56
+
75
57
  </script>