pxd 0.0.40 → 0.0.41

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.
Files changed (101) hide show
  1. package/README.md +9 -3
  2. package/dist/components/active-graph/index.vue +9 -4
  3. package/dist/components/backtop/index.vue +75 -0
  4. package/dist/components/badge/index.vue +9 -7
  5. package/dist/components/book/index.vue +2 -2
  6. package/dist/components/browser/index.vue +1 -1
  7. package/dist/components/checkbox/index.vue +1 -1
  8. package/dist/components/command-menu/index.vue +15 -24
  9. package/dist/components/command-menu-item/index.vue +5 -15
  10. package/dist/components/countdown/index.vue +2 -1
  11. package/dist/components/drawer/index.vue +2 -2
  12. package/dist/components/error/index.vue +1 -1
  13. package/dist/components/fader/index.vue +24 -11
  14. package/dist/components/index.d.ts +3 -0
  15. package/dist/components/index.js +3 -0
  16. package/dist/components/input/index.vue +18 -10
  17. package/dist/components/intersection-observer/index.vue +3 -3
  18. package/dist/components/kbd/index.vue +7 -6
  19. package/dist/components/{intersection-observer/content.vue → keep-alive-container/index.vue} +3 -1
  20. package/dist/components/list/index.vue +4 -4
  21. package/dist/components/list-item/index.vue +21 -8
  22. package/dist/components/loading-bar/index.vue +11 -18
  23. package/dist/components/menu/index.vue +15 -15
  24. package/dist/components/message/index.vue +9 -9
  25. package/dist/components/modal/index.vue +8 -10
  26. package/dist/components/note/index.vue +1 -1
  27. package/dist/components/overlay/index.vue +71 -19
  28. package/dist/components/popover/index.vue +76 -74
  29. package/dist/components/progress/index.vue +1 -1
  30. package/dist/components/radio/index.vue +1 -1
  31. package/dist/components/scrollable/index.vue +43 -24
  32. package/dist/components/slider/index.vue +7 -7
  33. package/dist/components/switch/index.vue +1 -1
  34. package/dist/components/time-picker/index.vue +281 -0
  35. package/dist/components/tooltip/index.vue +1 -1
  36. package/dist/composables/use-browser-observer.d.ts +4 -4
  37. package/dist/composables/use-countdown.d.ts +6 -0
  38. package/dist/composables/use-countdown.js +21 -7
  39. package/dist/composables/use-delay-destroy.d.ts +2 -2
  40. package/dist/composables/use-delay-destroy.js +13 -9
  41. package/dist/composables/use-focus-trap.d.ts +2 -2
  42. package/dist/composables/use-focus-trap.js +5 -5
  43. package/dist/composables/use-pointer-gesture.d.ts +2 -2
  44. package/dist/composables/use-pointer-gesture.js +1 -1
  45. package/dist/composables/use-repeat-action.d.ts +2 -2
  46. package/dist/composables/use-repeat-action.js +5 -5
  47. package/dist/contexts/list.d.ts +1 -0
  48. package/dist/contexts/list.js +4 -0
  49. package/dist/index.d.ts +1 -1
  50. package/dist/index.js +1 -1
  51. package/dist/locales/en-us.d.ts +12 -7
  52. package/dist/locales/en-us.js +14 -9
  53. package/dist/locales/zh-cn.d.ts +12 -7
  54. package/dist/locales/zh-cn.js +14 -9
  55. package/dist/src/components/active-graph/index.vue.d.ts +6 -4
  56. package/dist/src/components/backtop/index.vue.d.ts +20 -0
  57. package/dist/src/components/badge/index.vue.d.ts +1 -0
  58. package/dist/src/components/command-menu-item/index.vue.d.ts +11 -9
  59. package/dist/src/components/drawer/index.vue.d.ts +2 -2
  60. package/dist/src/components/fader/index.vue.d.ts +2 -3
  61. package/dist/src/components/input/index.vue.d.ts +9 -4
  62. package/dist/src/components/kbd/index.vue.d.ts +7 -5
  63. package/dist/src/components/keep-alive-container/index.vue.d.ts +12 -0
  64. package/dist/src/components/menu/index.vue.d.ts +2 -2
  65. package/dist/src/components/message/index.vue.d.ts +5 -5
  66. package/dist/src/components/modal/index.vue.d.ts +2 -2
  67. package/dist/src/components/overlay/index.vue.d.ts +1 -0
  68. package/dist/src/components/popover/index.vue.d.ts +4 -5
  69. package/dist/src/components/time-picker/index.vue.d.ts +25 -0
  70. package/dist/src/composables/use-browser-observer.d.ts +4 -4
  71. package/dist/src/composables/use-countdown.d.ts +6 -0
  72. package/dist/src/composables/use-delay-destroy.d.ts +2 -2
  73. package/dist/src/composables/use-focus-trap.d.ts +2 -2
  74. package/dist/src/composables/use-pointer-gesture.d.ts +2 -2
  75. package/dist/src/composables/use-repeat-action.d.ts +2 -2
  76. package/dist/src/contexts/list.d.ts +1 -0
  77. package/dist/src/locales/en-us.d.ts +12 -7
  78. package/dist/src/types/components/time-picker.d.ts +4 -0
  79. package/dist/src/utils/event.d.ts +1 -0
  80. package/dist/src/utils/format.d.ts +1 -0
  81. package/dist/src/utils/ref.d.ts +2 -5
  82. package/dist/src/utils/regexp.d.ts +4 -0
  83. package/dist/styles/styles.css +1 -1
  84. package/dist/styles/tw.css +14 -0
  85. package/dist/types/components/time-picker.d.ts +4 -0
  86. package/dist/types/components/time-picker.js +0 -0
  87. package/dist/types/shared/utils.d.ts +5 -2
  88. package/dist/utils/event.d.ts +1 -0
  89. package/dist/utils/event.js +3 -0
  90. package/dist/utils/format.d.ts +1 -0
  91. package/dist/utils/format.js +3 -0
  92. package/dist/utils/ref.d.ts +2 -5
  93. package/dist/utils/regexp.d.ts +4 -0
  94. package/dist/utils/regexp.js +4 -0
  95. package/dist/utils/uid.js +1 -1
  96. package/package.json +7 -7
  97. package/volar.d.ts +3 -0
  98. package/dist/contexts/command-menu.d.ts +0 -6
  99. package/dist/contexts/command-menu.js +0 -5
  100. package/dist/src/contexts/command-menu.d.ts +0 -6
  101. /package/dist/{src/components/intersection-observer/content.vue.d.ts → dist/components/keep-alive-container/index.vue.d.ts} +0 -0
package/README.md CHANGED
@@ -27,14 +27,20 @@ pnpm dev
27
27
 
28
28
  ### Build
29
29
 
30
- #### Core
30
+ #### Core only
31
31
 
32
32
  ```shell
33
- pnpm build
33
+ pnpm build:lib
34
34
  ```
35
35
 
36
- #### Docs
36
+ #### Docs only
37
37
 
38
38
  ```shell
39
39
  pnpm build:docs
40
40
  ```
41
+
42
+ #### Deploy
43
+
44
+ ```shell
45
+ pnpm build
46
+ ```
@@ -3,6 +3,7 @@ import { computed, onBeforeUnmount, shallowRef } from "vue";
3
3
  import { useConfigProvider } from "../../composables/use-config-provider-context";
4
4
  import { useDelayChange } from "../../composables/use-delay-change";
5
5
  import { getAllDatesBetween } from "../../utils/date";
6
+ import { getCssUnitValue } from "../../utils/format";
6
7
  import { getColorByThreshold } from "../../utils/get";
7
8
  defineOptions({
8
9
  name: "PActiveGraph"
@@ -29,7 +30,9 @@ const props = defineProps({
29
30
  graphOnly: { type: Boolean, required: false, default: false },
30
31
  transpose: { type: Boolean, required: false },
31
32
  tooltip: { type: Boolean, required: false, default: true },
32
- tooltipText: { type: String, required: false, default: "{COUNT} on {DATE}" }
33
+ tooltipText: { type: String, required: false, default: "{COUNT} on {DATE}" },
34
+ fieldNames: { type: Object, required: false },
35
+ itemRadius: { type: [String, Number], required: false }
33
36
  });
34
37
  const emits = defineEmits(["cell-click"]);
35
38
  const config = useConfigProvider();
@@ -37,8 +40,9 @@ const CELL_GAP = 3;
37
40
  const CELL_SIZE = 12;
38
41
  const rangedDates = computed(() => getAllDatesBetween(props.startDate, props.endDate));
39
42
  const dateCountMap = computed(() => {
43
+ const { date, count } = props.fieldNames || { date: "date", count: "count" };
40
44
  return props.data.reduce((acc, cur) => {
41
- acc[cur.date] = (acc[cur.date] || 0) + cur.count;
45
+ acc[cur[date]] = (acc[cur[date]] || 0) + cur[count];
42
46
  return acc;
43
47
  }, {});
44
48
  });
@@ -283,6 +287,7 @@ onBeforeUnmount(() => {
283
287
  <tbody
284
288
  ref="tbodyRef"
285
289
  class="text-xs"
290
+ :style="{ '--item-radius': getCssUnitValue(itemRadius, '2px') }"
286
291
  @click="onCellClick"
287
292
  @pointerover.capture="onMouseOver"
288
293
  >
@@ -296,7 +301,7 @@ onBeforeUnmount(() => {
296
301
  <td
297
302
  v-for="col of row"
298
303
  :key="col.date"
299
- class="pxd-active-graph--item rounded-xs w-3 min-w-3 bg-gray-alpha-200 motion-safe:transition-colors"
304
+ class="pxd-active-graph--item w-3 min-w-3 rounded-(--item-radius) bg-gray-alpha-200 motion-safe:transition-colors"
300
305
  :data-date="col.date"
301
306
  :class="{ 'pointer-events-none opacity-0': col.hidden }"
302
307
  :style="`background: ${col.color}`"
@@ -313,7 +318,7 @@ onBeforeUnmount(() => {
313
318
  <td
314
319
  v-for="color in props.colors"
315
320
  :key="color"
316
- class="w-3 h-3 rounded-xs bg-gray-alpha-200 motion-safe:transition-colors"
321
+ class="w-3 h-3 rounded-(--item-radius) bg-gray-alpha-200 motion-safe:transition-colors"
317
322
  :style="`background-color: ${color}`"
318
323
  />
319
324
 
@@ -0,0 +1,75 @@
1
+ <script setup>
2
+ import ArrowIcon from "@gdsicon/vue/arrow-up";
3
+ import { computed, onBeforeUnmount, onMounted, shallowRef } from "vue";
4
+ import { getScrollContainer, getScrollElByContainer } from "../../utils/dom";
5
+ import { optimizedOff, optimizedOn } from "../../utils/event";
6
+ import { getCssUnitValue } from "../../utils/format";
7
+ import PButton from "../button/index.vue";
8
+ defineOptions({
9
+ name: "PBacktop",
10
+ inheritAttrs: false
11
+ });
12
+ const props = defineProps({
13
+ right: { type: [String, Number], required: false },
14
+ bottom: { type: [String, Number], required: false },
15
+ zIndex: { type: [String, Number], required: false },
16
+ visibleThreshold: { type: Number, required: false, default: 30 }
17
+ });
18
+ let scrollContainer;
19
+ let scrollContainerEl;
20
+ const scrollTop = shallowRef(0);
21
+ const wrapperRef = shallowRef();
22
+ const computedStyle = computed(() => {
23
+ return {
24
+ zIndex: props.zIndex,
25
+ right: getCssUnitValue(props.right),
26
+ bottom: getCssUnitValue(props.bottom)
27
+ };
28
+ });
29
+ function updateScrollTop() {
30
+ if (!scrollContainerEl) {
31
+ return;
32
+ }
33
+ scrollTop.value = scrollContainerEl.scrollTop;
34
+ }
35
+ function onBacktopClick() {
36
+ if (!scrollContainer) {
37
+ return;
38
+ }
39
+ scrollContainer.scrollTo({
40
+ top: 0,
41
+ left: 0,
42
+ behavior: "smooth"
43
+ });
44
+ }
45
+ onMounted(() => {
46
+ scrollContainer = getScrollContainer(wrapperRef.value);
47
+ scrollContainerEl = getScrollElByContainer(scrollContainer);
48
+ updateScrollTop();
49
+ optimizedOn(scrollContainer, "scroll", updateScrollTop, { passive: true });
50
+ });
51
+ onBeforeUnmount(() => {
52
+ optimizedOff(scrollContainer, "scroll", updateScrollTop, { passive: true });
53
+ scrollContainer = null;
54
+ scrollContainerEl = null;
55
+ });
56
+ </script>
57
+
58
+ <template>
59
+ <Transition name="pxd-transition--fade-scale" appear>
60
+ <div
61
+ v-show="scrollTop >= visibleThreshold"
62
+ ref="wrapperRef"
63
+ class="right-6 bottom-6 fixed z-1"
64
+ :style="computedStyle"
65
+ v-bind="$attrs"
66
+ @click="onBacktopClick"
67
+ >
68
+ <slot>
69
+ <PButton class="shadow-sm" shape="rounded" icon>
70
+ <ArrowIcon />
71
+ </PButton>
72
+ </slot>
73
+ </div>
74
+ </Transition>
75
+ </template>
@@ -9,10 +9,11 @@ const props = defineProps({
9
9
  as: { type: null, required: false, default: "span" },
10
10
  variant: { type: null, required: false, default: "gray" },
11
11
  size: { type: null, required: false },
12
- href: { type: String, required: false }
12
+ href: { type: String, required: false },
13
+ to: { type: String, required: false }
13
14
  });
14
15
  const SIZES = {
15
- sm: "px-1.5 h-5 text-xs",
16
+ sm: "px-2 h-5 text-xs",
16
17
  md: "px-2.5 h-6 text-xs",
17
18
  lg: "px-3 h-7.5 text-sm"
18
19
  };
@@ -42,7 +43,7 @@ const VARIANTS = {
42
43
  const config = useConfigProvider();
43
44
  const computedClass = computed(() => {
44
45
  const classes = [
45
- "pxd-badge px-2.5 font-medium h-6 font-sans gap-1 inline-flex items-center justify-center rounded-full !no-underline motion-safe:transition-all",
46
+ "pxd-badge font-medium font-sans gap-1 inline-flex items-center justify-center rounded-full text-nowrap whitespace-nowrap !no-underline motion-safe:transition-all",
46
47
  getFallbackValue(props.variant, VARIANTS, "gray"),
47
48
  getFallbackValue(props.size, SIZES, config.size),
48
49
  props.variant
@@ -50,13 +51,14 @@ const computedClass = computed(() => {
50
51
  return classes.join(" ");
51
52
  });
52
53
  const badgeAttrs = computed(() => {
53
- if (props.as === "router-link" || props.as === "RouterLink") {
54
+ const { as, href, to } = props;
55
+ if (as === "router-link" || as === "RouterLink") {
54
56
  return {
55
- to: props.href
57
+ to: href || to
56
58
  };
57
- } else if (props.as === "a") {
59
+ } else if (as === "a") {
58
60
  return {
59
- href: props.href
61
+ href: href || to
60
62
  };
61
63
  }
62
64
  return {};
@@ -48,7 +48,7 @@ const computedClass = computed(() => {
48
48
  <div class="pxd-book--content translate-z-0 absolute flex size-full min-w-full flex-col overflow-hidden bg-background-200">
49
49
  <div
50
50
  v-if="variant === 'stripe'"
51
- class="translate-z-0 relative flex w-full flex-1 overflow-hidden"
51
+ class="translate-z-0 relative flex w-full flex-1 shrink-0 overflow-hidden"
52
52
  style="background-color: var(--bc, var(--color-amber-600))"
53
53
  >
54
54
  <div class="absolute flex w-full flex-col object-cover">
@@ -60,7 +60,7 @@ const computedClass = computed(() => {
60
60
 
61
61
  <div
62
62
  :class="{ 'pxd-book--cover-simple': variant === 'simple' }"
63
- class="translate-z-0 relative flex w-full flex-1 overflow-hidden"
63
+ class="translate-z-0 relative flex w-full flex-1 shrink-0 overflow-hidden"
64
64
  >
65
65
  <div aria-hidden="true" class="pxd-book--spine h-full opacity-20" />
66
66
 
@@ -32,7 +32,7 @@ const { isCopied, copyText } = useCopyClick();
32
32
  </div>
33
33
  </div>
34
34
 
35
- <div class="gap-4 min-w-0 md:first:max-w-[140px] md:last:max-w-[140px] flex flex-1 items-center justify-center max-md:first:flex-none first:justify-start last:justify-end">
35
+ <div class="gap-4 min-w-0 md:first:max-w-[140px] md:last:max-w-[140px] flex flex-1 shrink-0 items-center justify-center max-md:first:flex-none first:justify-start last:justify-end">
36
36
  <div class="lg:max-w-xs pl-2.5 pr-1 py-1 flex w-full items-center justify-between rounded-full border border-gray-400 bg-background-200">
37
37
  <LockClosedIcon class="text-sm text-foreground-secondary" />
38
38
 
@@ -99,7 +99,7 @@ defineExpose({
99
99
  <span v-else class="size-3" />
100
100
  </span>
101
101
 
102
- <span class="text-sm flex-1 empty:hidden">
102
+ <span class="text-sm flex-1 shrink-0 empty:hidden">
103
103
  <slot>
104
104
  {{ label }}
105
105
  </slot>
@@ -1,8 +1,8 @@
1
1
  <script setup>
2
- import { computed, nextTick, shallowRef } from "vue";
2
+ import { nextTick, shallowRef } from "vue";
3
3
  import { useConfigProvider } from "../../composables/use-config-provider-context";
4
4
  import { useModelValue } from "../../composables/use-model-value";
5
- import { provideCommandMenuContext } from "../../contexts/command-menu";
5
+ import { provideListFilterValue } from "../../contexts/list";
6
6
  import { debounce } from "../../utils/debounce";
7
7
  import { throttle } from "../../utils/throttle";
8
8
  import { getUniqueId } from "../../utils/uid";
@@ -30,14 +30,8 @@ const uniqueId = getUniqueId();
30
30
  const config = useConfigProvider();
31
31
  const modelValue = useModelValue(props, emits);
32
32
  const listRef = shallowRef();
33
- const isEmptyResult = shallowRef(false);
34
33
  const filterKeyword = shallowRef("");
35
- const filterKeywordRegex = computed(() => {
36
- if (!filterKeyword.value) {
37
- return null;
38
- }
39
- return new RegExp(filterKeyword.value, "i");
40
- });
34
+ const isEmptyResult = shallowRef(false);
41
35
  const onKeywordChange = throttle(async (ev) => {
42
36
  const inputValue = ev.target.value.trim();
43
37
  filterKeyword.value = inputValue;
@@ -47,27 +41,24 @@ const onKeywordChange = throttle(async (ev) => {
47
41
  }
48
42
  await nextTick();
49
43
  list.updateListItem();
50
- list.setActiveValue();
44
+ list.setActiveValueToFirst();
51
45
  isEmptyResult.value = list.isNoVisibleItem();
52
- }, 300, { edges: ["leading", "trailing"] });
53
- const closeModal = debounce(() => {
46
+ }, 200, { edges: ["leading", "trailing"] });
47
+ const hideModal = debounce(() => {
54
48
  modelValue.value = false;
55
49
  filterKeyword.value = "";
56
50
  emits("hide");
57
51
  }, 500, { edges: ["leading"] });
58
- function onShowModal() {
52
+ function showModal() {
59
53
  emits("show");
60
54
  }
61
55
  function onListItemSelect(ev, item) {
62
56
  emits("select", ev, item);
63
57
  if (props.closeOnSelectItem) {
64
- closeModal();
58
+ hideModal();
65
59
  }
66
60
  }
67
- provideCommandMenuContext({
68
- filterKeyword,
69
- filterKeywordRegex
70
- });
61
+ provideListFilterValue(filterKeyword);
71
62
  </script>
72
63
 
73
64
  <template>
@@ -79,11 +70,11 @@ provideCommandMenuContext({
79
70
  wrapper-class="sm:top-1/6 sm:translate-y-0"
80
71
  :close-on-press-escape="closeOnPressEscape"
81
72
  :close-on-click-overlay="closeOnClickOverlay"
82
- @show="onShowModal"
83
- @hide="closeModal"
73
+ @show="showModal"
74
+ @hide="hideModal"
84
75
  >
85
76
  <template #header>
86
- <label :for="uniqueId" class="py-3 px-4 -mx-6 -my-4 gap-3 flex items-center border-b">
77
+ <label :for="uniqueId" class="py-3 px-4 -mx-6 -my-4 gap-3 flex items-center border-b bg-background-100">
87
78
  <input
88
79
  :id="uniqueId"
89
80
  :value="filterKeyword"
@@ -98,7 +89,7 @@ provideCommandMenuContext({
98
89
  spellcheck="false"
99
90
  type="text"
100
91
  name="command-menu-filter-input"
101
- class="h-7 flex-1 appearance-none border-none bg-transparent text-foreground outline-none"
92
+ class="h-7 flex-1 shrink-0 appearance-none border-none bg-transparent text-foreground outline-none"
102
93
  @input="onKeywordChange"
103
94
  >
104
95
 
@@ -106,7 +97,7 @@ provideCommandMenuContext({
106
97
  v-if="closeOnPressEscape"
107
98
  size="xs"
108
99
  class="!px-0 text-xs shrink-0"
109
- @click="closeModal"
100
+ @click="hideModal"
110
101
  >
111
102
  Esc
112
103
  </PButton>
@@ -123,7 +114,7 @@ provideCommandMenuContext({
123
114
  >
124
115
  <slot />
125
116
 
126
- <p v-if="isEmptyResult" class="py-8 text-sm text-center text-foreground-secondary">
117
+ <p v-if="isEmptyResult" class="py-7.5 text-sm text-center text-foreground-secondary">
127
118
  {{ config.locale.empty.search }} <span class="text-foreground">"{{ filterKeyword }}"</span>
128
119
  </p>
129
120
  </PList>
@@ -1,23 +1,13 @@
1
1
  <script setup>
2
- import { computed } from "vue";
3
- import { useCommandMenuContext } from "../../contexts/command-menu";
4
2
  import PListItem from "../list-item/index.vue";
5
3
  defineOptions({
6
- name: "PCommandMenuItem"
7
- });
8
- const props = defineProps({
9
- as: { type: null, required: false },
10
- type: { type: null, required: false },
11
- label: { type: null, required: false },
12
- disabled: { type: null, required: false },
13
- description: { type: null, required: false }
14
- });
15
- const commandMenuContext = useCommandMenuContext();
16
- const isVisible = computed(() => {
17
- return !commandMenuContext?.filterKeyword.value || commandMenuContext?.filterKeywordRegex.value?.test(String(props.label));
4
+ name: "PCommandMenuItem",
5
+ inheritAttrs: false
18
6
  });
19
7
  </script>
20
8
 
21
9
  <template>
22
- <PListItem v-if="isVisible" v-bind="props" />
10
+ <PListItem v-bind="$attrs">
11
+ <slot />
12
+ </PListItem>
23
13
  </template>
@@ -18,7 +18,8 @@ const props = defineProps({
18
18
  autoReset: { type: Boolean, required: false, default: true },
19
19
  durations: { type: Number, required: false, default: 0 },
20
20
  precision: { type: Number, required: false, default: 0 },
21
- millisecond: { type: Boolean, required: false, default: true }
21
+ millisecond: { type: Boolean, required: false, default: true },
22
+ intuitive: { type: Boolean, required: false }
22
23
  });
23
24
  const emits = defineEmits(["change", "reset", "finish"]);
24
25
  dayjs.extend(dayjsDurationPlugin);
@@ -27,7 +27,7 @@ const props = defineProps({
27
27
  closeOnPressEscape: { type: Boolean, required: false, default: true },
28
28
  closeOnClickOverlay: { type: Boolean, required: false, default: true }
29
29
  });
30
- const emits = defineEmits(["show", "hide", "visible-change", "click-outside", "update:modelValue"]);
30
+ const emits = defineEmits(["show", "hide", "outside-click", "visible-change", "update:modelValue"]);
31
31
  const drawerRef = shallowRef();
32
32
  const isVisible = useModelValue(props, emits);
33
33
  useFocusTrap(drawerRef);
@@ -47,7 +47,7 @@ const computedStyle = computed(() => {
47
47
  return styles;
48
48
  });
49
49
  function onOverlayClick(ev) {
50
- emits("click-outside", ev);
50
+ emits("outside-click", ev);
51
51
  if (!isTruthyProp(props.closeOnClickOverlay) || isTruthyProp(props.loading)) {
52
52
  return;
53
53
  }
@@ -30,7 +30,7 @@ const computedClass = computed(() => {
30
30
  <div :class="computedClass">
31
31
  <StopIcon class="size-4 mr-2 mt-(--mt) shrink-0" />
32
32
 
33
- <div class="flex-1">
33
+ <div class="flex-1 shrink-0">
34
34
  <b v-if="label || error?.label" class="font-medium whitespace-nowrap">{{ label || error?.label }}:</b>
35
35
 
36
36
  <slot>
@@ -1,8 +1,9 @@
1
1
  <script setup>
2
2
  import { computed, onBeforeUnmount, shallowRef, watch } from "vue";
3
3
  import { useResizeObserver } from "../../composables/use-browser-observer";
4
- import { off, on } from "../../utils/event";
4
+ import { optimizedOff, optimizedOn } from "../../utils/event";
5
5
  import { getCssUnitValue } from "../../utils/format";
6
+ import { unrefElement } from "../../utils/ref";
6
7
  import { throttleByRaf } from "../../utils/throttle";
7
8
  defineOptions({
8
9
  name: "PFader"
@@ -10,7 +11,7 @@ defineOptions({
10
11
  const props = defineProps({
11
12
  size: { type: Number, required: false },
12
13
  color: { type: String, required: false },
13
- container: { type: null, required: true },
14
+ container: { type: null, required: false },
14
15
  direction: { type: String, required: false, default: "both" }
15
16
  });
16
17
  const fader = shallowRef({
@@ -19,13 +20,25 @@ const fader = shallowRef({
19
20
  right: false,
20
21
  bottom: false
21
22
  });
23
+ const DIFF_THRESHOLD = 1;
22
24
  const computedStyle = computed(() => ({
23
25
  "--fader-color": props.color,
24
26
  "--fader-size": getCssUnitValue(props.size)
25
27
  }));
26
- const DIFF_THRESHOLD = 1;
28
+ const formattedContainer = computed(() => {
29
+ const { container } = props;
30
+ if (typeof container === "string") {
31
+ return document.querySelector(container);
32
+ } else {
33
+ return unrefElement(container);
34
+ }
35
+ });
27
36
  const onContainerScroll = throttleByRaf(() => {
28
- const { size = 16, container } = props;
37
+ const container = formattedContainer.value;
38
+ if (!container) {
39
+ return;
40
+ }
41
+ const { size = 16 } = props;
29
42
  const { scrollLeft, scrollWidth, clientWidth, scrollTop, clientHeight, scrollHeight } = container;
30
43
  fader.value = {
31
44
  left: scrollLeft >= size,
@@ -34,19 +47,19 @@ const onContainerScroll = throttleByRaf(() => {
34
47
  bottom: scrollTop + clientHeight < scrollHeight - DIFF_THRESHOLD
35
48
  };
36
49
  });
37
- useResizeObserver(() => props.container, onContainerScroll);
38
- watch(() => props.container, (container, oldDom) => {
50
+ useResizeObserver(() => formattedContainer.value, onContainerScroll);
51
+ watch(() => formattedContainer.value, (container, oldDom) => {
39
52
  if (oldDom) {
40
- off(oldDom, "scroll", onContainerScroll);
53
+ optimizedOff(oldDom, "scroll", onContainerScroll);
41
54
  return;
42
55
  }
43
56
  if (!container) {
44
57
  return;
45
58
  }
46
- on(container, "scroll", onContainerScroll);
47
- });
59
+ optimizedOn(container, "scroll", onContainerScroll);
60
+ }, { immediate: true });
48
61
  onBeforeUnmount(() => {
49
- off(props.container, "scroll", onContainerScroll);
62
+ optimizedOff(formattedContainer.value, "scroll", onContainerScroll);
50
63
  });
51
64
  </script>
52
65
 
@@ -69,7 +82,7 @@ onBeforeUnmount(() => {
69
82
  border-radius: inherit;
70
83
  background: linear-gradient(var(--dir), transparent, var(--fader-color, var(--color-gray-200)));
71
84
  mask-image: linear-gradient(var(--dir-revert), var(--fader-color, var(--color-gray-200)) 50%, transparent);
72
- transition: opacity var(--default-transition-timing-function) var(--default-transition-duration);
85
+ transition: opacity var(--default-transition-duration) var(--default-transition-timing-function);
73
86
  opacity: 0;
74
87
  }
75
88
 
@@ -1,6 +1,7 @@
1
1
  export { default as ActiveGraph } from './active-graph/index.vue';
2
2
  export { default as Avatar } from './avatar/index.vue';
3
3
  export { default as AvatarGroup } from './avatar-group/index.vue';
4
+ export { default as Backtop } from './backtop/index.vue';
4
5
  export { default as Badge } from './badge/index.vue';
5
6
  export { default as Book } from './book/index.vue';
6
7
  export { default as Browser } from './browser/index.vue';
@@ -31,6 +32,7 @@ export { default as HoldButton } from './hold-button/index.vue';
31
32
  export { default as Input } from './input/index.vue';
32
33
  export { default as IntersectionObserver } from './intersection-observer/index.vue';
33
34
  export { default as Kbd } from './kbd/index.vue';
35
+ export { default as KeepAliveContainer } from './keep-alive-container/index.vue';
34
36
  export { default as LinkButton } from './link-button/index.vue';
35
37
  export { default as List } from './list/index.vue';
36
38
  export { default as ListItem } from './list-item/index.vue';
@@ -67,6 +69,7 @@ export { default as Teleport } from './teleport/index.vue';
67
69
  export { default as Text } from './text/index.vue';
68
70
  export { default as Textarea } from './textarea/index.vue';
69
71
  export { default as ThemeSwitcher } from './theme-switcher/index.vue';
72
+ export { default as TimePicker } from './time-picker/index.vue';
70
73
  export { default as Toggle } from './toggle/index.vue';
71
74
  export { default as Tooltip } from './tooltip/index.vue';
72
75
  export { default as VirtualList } from './virtual-list/index.vue';
@@ -1,6 +1,7 @@
1
1
  export { default as ActiveGraph } from "./active-graph/index.vue";
2
2
  export { default as Avatar } from "./avatar/index.vue";
3
3
  export { default as AvatarGroup } from "./avatar-group/index.vue";
4
+ export { default as Backtop } from "./backtop/index.vue";
4
5
  export { default as Badge } from "./badge/index.vue";
5
6
  export { default as Book } from "./book/index.vue";
6
7
  export { default as Browser } from "./browser/index.vue";
@@ -31,6 +32,7 @@ export { default as HoldButton } from "./hold-button/index.vue";
31
32
  export { default as Input } from "./input/index.vue";
32
33
  export { default as IntersectionObserver } from "./intersection-observer/index.vue";
33
34
  export { default as Kbd } from "./kbd/index.vue";
35
+ export { default as KeepAliveContainer } from "./keep-alive-container/index.vue";
34
36
  export { default as LinkButton } from "./link-button/index.vue";
35
37
  export { default as List } from "./list/index.vue";
36
38
  export { default as ListItem } from "./list-item/index.vue";
@@ -67,6 +69,7 @@ export { default as Teleport } from "./teleport/index.vue";
67
69
  export { default as Text } from "./text/index.vue";
68
70
  export { default as Textarea } from "./textarea/index.vue";
69
71
  export { default as ThemeSwitcher } from "./theme-switcher/index.vue";
72
+ export { default as TimePicker } from "./time-picker/index.vue";
70
73
  export { default as Toggle } from "./toggle/index.vue";
71
74
  export { default as Tooltip } from "./tooltip/index.vue";
72
75
  export { default as VirtualList } from "./virtual-list/index.vue";
@@ -34,13 +34,13 @@ const props = defineProps({
34
34
  maxlength: { type: [Number, String], required: false },
35
35
  modelValue: { type: [String, Number, Array, null], required: false, default: "" },
36
36
  allowClear: { type: Boolean, required: false },
37
- placeholder: { type: String, required: false },
37
+ placeholder: { type: String, required: false, default: "" },
38
38
  prefixStyle: { type: Boolean, required: false, default: true },
39
39
  suffixStyle: { type: Boolean, required: false, default: true },
40
40
  parser: { type: Function, required: false },
41
41
  formatter: { type: Function, required: false }
42
42
  });
43
- const emits = defineEmits(["update:modelValue", "focus", "blur", "change", "keydown", "input", "compositionstart", "compositionupdate", "compositionend"]);
43
+ const emits = defineEmits(["click", "input", "change", "focus", "blur", "keydown", "update:modelValue", "compositionstart", "compositionupdate", "compositionend"]);
44
44
  const SIZES = {
45
45
  xs: "h-6 text-xs",
46
46
  sm: "h-7.5 text-sm",
@@ -97,6 +97,12 @@ function onFocus(event) {
97
97
  function onBlur(event) {
98
98
  emits("blur", event);
99
99
  }
100
+ function onChange(event) {
101
+ emits("change", getValueFromEvent(event));
102
+ }
103
+ function onClick(event) {
104
+ emits("click", event);
105
+ }
100
106
  async function onInput(event) {
101
107
  const ev = event;
102
108
  if (ev.isComposing || isComposing.value) {
@@ -105,9 +111,6 @@ async function onInput(event) {
105
111
  const value = getValueFromEvent(event);
106
112
  computedModelValue.value = value;
107
113
  emits("input", value);
108
- if (value !== computedModelValue.value) {
109
- emits("change", value);
110
- }
111
114
  await nextTick();
112
115
  setNativeInputValue(value);
113
116
  }
@@ -135,6 +138,7 @@ function toggleType() {
135
138
  isPasswordVisible.value = !isPasswordVisible.value;
136
139
  }
137
140
  function clearValue() {
141
+ setNativeInputValue("");
138
142
  computedModelValue.value = "";
139
143
  }
140
144
  const blur = () => inputRef.value?.blur();
@@ -151,12 +155,13 @@ defineExpose({
151
155
  blur,
152
156
  focus,
153
157
  select,
154
- clear: clearValue
158
+ clear: clearValue,
159
+ setInputValue: setNativeInputValue
155
160
  });
156
161
  </script>
157
162
 
158
163
  <template>
159
- <label class="pxd-input block w-full max-w-full" :for="uniqueId" @dragstart.prevent>
164
+ <label class="pxd-input block w-full max-w-full" :for="uniqueId" @click="onClick" @dragstart.prevent>
160
165
  <div v-if="label || $slots.label" class="pxd-form--label">
161
166
  <slot name="label">{{ label }}</slot>
162
167
  </div>
@@ -166,6 +171,7 @@ defineExpose({
166
171
  v-if="$slots.prefix"
167
172
  class="pxd-input--prefix text-sm flex h-full items-center text-gray-700"
168
173
  :class="{ 'px-3 rounded-l-inherit border-r border-gray-300 bg-background-200': prefixStyle }"
174
+ @click.stop
169
175
  >
170
176
  <slot name="prefix" />
171
177
  </div>
@@ -194,6 +200,7 @@ defineExpose({
194
200
  @blur="onBlur"
195
201
  @focus="onFocus"
196
202
  @input="onInput"
203
+ @change="onChange"
197
204
  @keydown="onKeydown"
198
205
  @compositionstart="onCompositionStart"
199
206
  @compositionupdate="onCompositionUpdate"
@@ -203,13 +210,13 @@ defineExpose({
203
210
  <div
204
211
  v-if="password || allowClear"
205
212
  v-show="computedModelValue"
206
- class="pxd-input--icon right-0 top-0 flex aspect-square h-full cursor-pointer items-center justify-center rounded-r-inherit text-foreground-secondary"
213
+ class="pxd-input--icon right-0 top-0 flex aspect-square h-full cursor-pointer items-center justify-center rounded-r-inherit text-gray-700"
207
214
  >
208
- <div v-if="password" class="p-1 rounded-sm hover:bg-background-hover hover:text-foreground active:bg-background-active motion-safe:transition-colors" @click.prevent="toggleType">
215
+ <div v-if="password" class="p-1 rounded-sm hover:bg-background-hover hover:text-foreground active:bg-background-active motion-safe:transition-colors" @click.stop.prevent="toggleType">
209
216
  <EyeOffIcon v-if="isPasswordVisible" class="size-3" />
210
217
  <EyeIcon v-else class="size-3" />
211
218
  </div>
212
- <div v-if="allowClear" class="p-1 rounded-sm hover:bg-background-hover hover:text-foreground active:bg-background-active motion-safe:transition-colors" @click.prevent="clearValue">
219
+ <div v-if="allowClear" class="p-1 rounded-sm hover:bg-background-hover hover:text-foreground active:bg-background-active motion-safe:transition-colors" @click.stop.prevent="clearValue">
213
220
  <CrossIcon class="size-3" />
214
221
  </div>
215
222
  </div>
@@ -218,6 +225,7 @@ defineExpose({
218
225
  v-if="$slots.suffix"
219
226
  class="pxd-input--suffix text-sm flex h-full items-center text-gray-700"
220
227
  :class="{ 'px-3 rounded-r-inherit border-l border-gray-300 bg-background-200': suffixStyle }"
228
+ @click.stop
221
229
  >
222
230
  <slot name="suffix" />
223
231
  </div>
@@ -2,7 +2,7 @@
2
2
  import { nextTick, shallowRef } from "vue";
3
3
  import { useIntersectionObserver } from "../../composables/use-browser-observer";
4
4
  import { getCssUnitValue } from "../../utils/format";
5
- import KeepAliveContent from "./content.vue";
5
+ import PKeepAliveContainer from "../keep-alive-container/index.vue";
6
6
  defineOptions({
7
7
  name: "PIntersectionObserver"
8
8
  });
@@ -53,9 +53,9 @@ useIntersectionObserver(containerRef, ([{ isIntersecting }]) => {
53
53
  <template>
54
54
  <div ref="containerRef" class="pxd-intersection-observer" :style="containerSize">
55
55
  <KeepAlive v-if="keepAlive">
56
- <KeepAliveContent v-if="isVisible">
56
+ <PKeepAliveContainer v-if="isVisible">
57
57
  <slot />
58
- </KeepAliveContent>
58
+ </PKeepAliveContainer>
59
59
  </KeepAlive>
60
60
  <template v-else>
61
61
  <slot v-if="isVisible" />