ropav 0.1.3 → 0.1.5

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 (88) hide show
  1. package/README.md +16 -0
  2. package/dist/alert.css +18 -18
  3. package/dist/alert.js +15 -10
  4. package/dist/avatar.css +19 -19
  5. package/dist/avatar.js +14 -9
  6. package/dist/badge.css +16 -16
  7. package/dist/badge.js +12 -7
  8. package/dist/base.css +196 -56
  9. package/dist/button-link.css +32 -28
  10. package/dist/button-link.js +9 -5
  11. package/dist/button.css +32 -28
  12. package/dist/button.js +9 -5
  13. package/dist/checkbox.css +32 -32
  14. package/dist/checkbox.js +17 -9
  15. package/dist/chevron-right.js +12 -0
  16. package/dist/collectionNavigation.js +120 -0
  17. package/dist/color-input.js +2 -1
  18. package/dist/componentColors.js +94 -22
  19. package/dist/components/alert/types.d.ts +1 -0
  20. package/dist/components/alert/useAlertColor.d.ts +1 -1
  21. package/dist/components/avatar/types.d.ts +1 -0
  22. package/dist/components/avatar/useAvatarColor.d.ts +1 -1
  23. package/dist/components/badge/types.d.ts +1 -0
  24. package/dist/components/badge/useBadgeColor.d.ts +1 -1
  25. package/dist/components/button/types.d.ts +1 -0
  26. package/dist/components/button/useButtonColor.d.ts +1 -1
  27. package/dist/components/button-link/types.d.ts +1 -0
  28. package/dist/components/checkbox/types.d.ts +1 -0
  29. package/dist/components/dropdown-menu/dropdown-menu-primitive-core.d.ts +1 -0
  30. package/dist/components/dropdown-menu/dropdown-menu-utils.d.ts +0 -2
  31. package/dist/components/dropdown-menu/index.d.ts +1 -0
  32. package/dist/components/dropdown-menu/types.d.ts +4 -0
  33. package/dist/components/dropdown-menu/useDropdownMenuInteractions.d.ts +2 -1
  34. package/dist/components/dropdown-menu/useDropdownMenuNavigation.d.ts +1 -0
  35. package/dist/components/icon-button/types.d.ts +1 -0
  36. package/dist/components/pagination/index.d.ts +4 -0
  37. package/dist/components/pagination/index.js +2 -0
  38. package/dist/components/pagination/pagination.d.ts +49 -0
  39. package/dist/components/pagination/types.d.ts +54 -0
  40. package/dist/components/pagination/usePagination.d.ts +19 -0
  41. package/dist/components/radio/types.d.ts +3 -0
  42. package/dist/components/scroll-area/scroll-area.d.ts +37 -3
  43. package/dist/components/scroll-area/types.d.ts +1 -0
  44. package/dist/components/scroll-area/useScrollArea.d.ts +4 -0
  45. package/dist/components/scroll-area/useScrollAreaControls.d.ts +4 -0
  46. package/dist/components/scroll-area/useScrollAreaPresentation.d.ts +1 -1
  47. package/dist/components/select/useSelect.d.ts +1 -1
  48. package/dist/components/slider/range-slider-tooltip.d.ts +2 -0
  49. package/dist/components/slider/types.d.ts +1 -1
  50. package/dist/components/slider/useRangeSlider.d.ts +2 -0
  51. package/dist/components/slider/useSlider.d.ts +2 -0
  52. package/dist/components/toast/types.d.ts +2 -0
  53. package/dist/components/toast/useToastColor.d.ts +1 -1
  54. package/dist/components/tooltip/types.d.ts +1 -0
  55. package/dist/components/tooltip/useTooltip.d.ts +1 -1
  56. package/dist/dropdown-menu.js +55 -30
  57. package/dist/icon-button.css +39 -35
  58. package/dist/icon-button.js +9 -5
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.js +2 -1
  61. package/dist/input.js +2 -1
  62. package/dist/number-input.js +2 -1
  63. package/dist/pagination.css +140 -0
  64. package/dist/pagination.js +442 -0
  65. package/dist/radio.js +15 -5
  66. package/dist/scroll-area.css +25 -25
  67. package/dist/scroll-area.js +102 -19
  68. package/dist/select.js +65 -46
  69. package/dist/slider.css +191 -191
  70. package/dist/slider.js +49 -31
  71. package/dist/switch.js +2 -1
  72. package/dist/tabs.css +13 -13
  73. package/dist/tabs.js +38 -9
  74. package/dist/textarea.js +2 -1
  75. package/dist/toast.css +26 -26
  76. package/dist/toast.js +16 -9
  77. package/dist/tooltip.css +12 -12
  78. package/dist/tooltip.js +13 -8
  79. package/dist/unplugin-icons.js +38 -25
  80. package/dist/useButtonColor.js +6 -3
  81. package/dist/useControllableValue.js +27 -0
  82. package/dist/useFormControl.js +2 -27
  83. package/dist/utils/componentColors.d.ts +14 -1
  84. package/docs/public-styles-api.md +1 -1
  85. package/docs/public-tokens.md +648 -508
  86. package/package.json +8 -2
  87. package/src/styles/_tokens.scss +459 -319
  88. package/src/styles/styles-manifest.json +1122 -2
package/dist/radio.js CHANGED
@@ -3,7 +3,8 @@ import { t as bem } from "./bem.js";
3
3
  import { n as useStylesApi, t as presence } from "./styles-api.js";
4
4
  import { n as getComponentColorValue, r as getComponentContrastColor } from "./componentColors.js";
5
5
  import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
6
- import { i as useFormControl, o as useControllableValue } from "./useFormControl.js";
6
+ import { t as useControllableValue } from "./useControllableValue.js";
7
+ import { i as useFormControl } from "./useFormControl.js";
7
8
  import { t as useControlState } from "./useControlState.js";
8
9
  import { child, computed, createIf, createSlot, defineVaporComponent, inject, next, onBeforeUnmount, onMounted, provide, ref, renderEffect, setDynamicProps, setInsertionState, setStaticTemplateRef, shallowRef, template, unref, useId } from "vue";
9
10
  //#region src/components/radio/types.ts
@@ -17,13 +18,16 @@ var radioGroupParts = ["root"];
17
18
  var radioGroupKey = Symbol("radioGroup");
18
19
  //#endregion
19
20
  //#region src/components/radio/useRadio.ts
20
- function getRadioColorStyle(color, autoContrast) {
21
+ function getRadioColorStyle(color, autoContrast, contrastColor) {
21
22
  const colorValue = getComponentColorValue(color);
22
23
  if (color && !colorValue) return void 0;
23
- if (!colorValue && !autoContrast) return void 0;
24
+ if (!colorValue && autoContrast === false && contrastColor === void 0) return void 0;
24
25
  const style = {};
25
26
  if (colorValue) style["--_rp-radio-color"] = colorValue;
26
- if (autoContrast) style["--_rp-radio-on-color"] = getComponentContrastColor(color ?? "primary", { autoContrast });
27
+ if (autoContrast !== false || contrastColor !== void 0) style["--_rp-radio-on-color"] = getComponentContrastColor(color ?? "primary", {
28
+ autoContrast,
29
+ contrastColor
30
+ });
27
31
  return style;
28
32
  }
29
33
  function useRadio(props, emitChange) {
@@ -39,6 +43,7 @@ function useRadio(props, emitChange) {
39
43
  const variant = computed(() => props.variant ?? group?.variant);
40
44
  const color = computed(() => props.color ?? group?.color);
41
45
  const autoContrast = computed(() => props.autoContrast ?? group?.autoContrast);
46
+ const contrastColor = computed(() => props.contrastColor ?? group?.contrastColor);
42
47
  const size = computed(() => props.size ?? group?.size);
43
48
  const rootClass = computed(() => bem("rp-radio", {
44
49
  checked: isChecked.value,
@@ -47,7 +52,7 @@ function useRadio(props, emitChange) {
47
52
  [variant.value ?? ""]: Boolean(variant.value),
48
53
  [`size-${size.value}`]: Boolean(size.value)
49
54
  }));
50
- const rootStyle = computed(() => getRadioColorStyle(color.value, autoContrast.value));
55
+ const rootStyle = computed(() => getRadioColorStyle(color.value, autoContrast.value, contrastColor.value));
51
56
  function onSelect(event) {
52
57
  if (isDisabled.value) return;
53
58
  group?.select(props.value);
@@ -163,6 +168,9 @@ function useRadioGroup(props, emitUpdate) {
163
168
  get autoContrast() {
164
169
  return props.autoContrast;
165
170
  },
171
+ get contrastColor() {
172
+ return props.contrastColor;
173
+ },
166
174
  get size() {
167
175
  return props.size;
168
176
  },
@@ -205,6 +213,7 @@ var radio_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
205
213
  type: Boolean,
206
214
  default: void 0
207
215
  },
216
+ contrastColor: {},
208
217
  size: { default: void 0 },
209
218
  disabled: {
210
219
  type: Boolean,
@@ -325,6 +334,7 @@ var radio_group_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__
325
334
  type: Boolean,
326
335
  default: void 0
327
336
  },
337
+ contrastColor: {},
328
338
  size: { default: void 0 },
329
339
  orientation: { default: "vertical" },
330
340
  disabled: {
@@ -1,5 +1,5 @@
1
1
  @layer ropav.components {
2
- .rp-scroll-area[data-v-bf91f9cc] {
2
+ .rp-scroll-area[data-v-f5c4e940] {
3
3
  --_rp-scroll-area-scrollbar-size: 10px;
4
4
  --_rp-scroll-area-scrollbar-padding: 2px;
5
5
  --_rp-scroll-area-thumb-bg: var(--rp-color-dimmed);
@@ -11,7 +11,7 @@
11
11
  min-width: 0;
12
12
  overflow: hidden;
13
13
  }
14
- .rp-scroll-area__viewport[data-v-bf91f9cc] {
14
+ .rp-scroll-area__viewport[data-v-f5c4e940] {
15
15
  box-sizing: border-box;
16
16
  flex: 1 1 auto;
17
17
  width: 100%;
@@ -22,33 +22,33 @@
22
22
  scrollbar-width: none;
23
23
  outline: none;
24
24
  }
25
- .rp-scroll-area__viewport[data-v-bf91f9cc]::-webkit-scrollbar {
25
+ .rp-scroll-area__viewport[data-v-f5c4e940]::-webkit-scrollbar {
26
26
  display: none;
27
27
  }
28
- .rp-scroll-area__viewport[data-v-bf91f9cc]:focus-visible {
28
+ .rp-scroll-area__viewport[data-v-f5c4e940]:focus-visible {
29
29
  outline: var(--rp-border-width-medium) solid var(--rp-color-focus-ring);
30
30
  outline-offset: calc(-1 * var(--rp-border-width-medium));
31
31
  }
32
- .rp-scroll-area[data-scrollbars=both] .rp-scroll-area__viewport[data-v-bf91f9cc] {
32
+ .rp-scroll-area[data-scrollbars=both] .rp-scroll-area__viewport[data-v-f5c4e940] {
33
33
  overflow: scroll;
34
34
  }
35
- .rp-scroll-area[data-scrollbars=x] .rp-scroll-area__viewport[data-v-bf91f9cc] {
35
+ .rp-scroll-area[data-scrollbars=x] .rp-scroll-area__viewport[data-v-f5c4e940] {
36
36
  overflow-x: scroll;
37
37
  overflow-y: hidden;
38
38
  }
39
- .rp-scroll-area[data-scrollbars=y] .rp-scroll-area__viewport[data-v-bf91f9cc] {
39
+ .rp-scroll-area[data-scrollbars=y] .rp-scroll-area__viewport[data-v-f5c4e940] {
40
40
  overflow-x: hidden;
41
41
  overflow-y: scroll;
42
42
  }
43
- .rp-scroll-area[data-scrollbars=none] .rp-scroll-area__viewport[data-v-bf91f9cc] {
43
+ .rp-scroll-area[data-scrollbars=none] .rp-scroll-area__viewport[data-v-f5c4e940] {
44
44
  overflow: hidden;
45
45
  }
46
- .rp-scroll-area__content[data-v-bf91f9cc] {
46
+ .rp-scroll-area__content[data-v-f5c4e940] {
47
47
  display: table;
48
48
  box-sizing: border-box;
49
49
  min-width: 100%;
50
50
  }
51
- .rp-scroll-area__scrollbar[data-v-bf91f9cc] {
51
+ .rp-scroll-area__scrollbar[data-v-f5c4e940] {
52
52
  position: absolute;
53
53
  z-index: 1;
54
54
  box-sizing: border-box;
@@ -60,54 +60,54 @@
60
60
  user-select: none;
61
61
  transition: opacity var(--rp-transition-fast);
62
62
  }
63
- .rp-scroll-area__scrollbar[data-visible][data-v-bf91f9cc] {
63
+ .rp-scroll-area__scrollbar[data-visible][data-v-f5c4e940] {
64
64
  opacity: 1;
65
65
  pointer-events: auto;
66
66
  }
67
- .rp-scroll-area__scrollbar[data-v-bf91f9cc]:focus-visible {
67
+ .rp-scroll-area__scrollbar[data-v-f5c4e940]:focus-visible {
68
68
  outline: var(--rp-border-width-medium) solid var(--rp-color-focus-ring);
69
69
  outline-offset: calc(-1 * var(--rp-border-width-medium));
70
70
  }
71
- .rp-scroll-area__scrollbar--horizontal[data-v-bf91f9cc] {
71
+ .rp-scroll-area__scrollbar--horizontal[data-v-f5c4e940] {
72
72
  inset-inline: 0;
73
73
  bottom: 0;
74
74
  align-items: center;
75
75
  width: auto;
76
76
  height: var(--_rp-scroll-area-scrollbar-size);
77
77
  }
78
- .rp-scroll-area__scrollbar--vertical[data-v-bf91f9cc] {
78
+ .rp-scroll-area__scrollbar--vertical[data-v-f5c4e940] {
79
79
  inset-block: 0;
80
80
  inset-inline-end: 0;
81
81
  justify-content: center;
82
82
  width: var(--_rp-scroll-area-scrollbar-size);
83
83
  height: auto;
84
84
  }
85
- .rp-scroll-area[data-scrollbar-y-active] .rp-scroll-area__scrollbar--horizontal[data-v-bf91f9cc] {
85
+ .rp-scroll-area[data-scrollbar-y-active] .rp-scroll-area__scrollbar--horizontal[data-v-f5c4e940] {
86
86
  inset-inline-end: var(--_rp-scroll-area-scrollbar-size);
87
87
  }
88
- .rp-scroll-area[data-scrollbar-x-active] .rp-scroll-area__scrollbar--vertical[data-v-bf91f9cc] {
88
+ .rp-scroll-area[data-scrollbar-x-active] .rp-scroll-area__scrollbar--vertical[data-v-f5c4e940] {
89
89
  inset-block-end: var(--_rp-scroll-area-scrollbar-size);
90
90
  }
91
- .rp-scroll-area__thumb[data-v-bf91f9cc] {
91
+ .rp-scroll-area__thumb[data-v-f5c4e940] {
92
92
  flex: 0 0 auto;
93
93
  background: var(--_rp-scroll-area-thumb-bg);
94
94
  border-radius: var(--rp-radius-full);
95
95
  transition: background-color var(--rp-transition-fast);
96
96
  }
97
- .rp-scroll-area__scrollbar:hover .rp-scroll-area__thumb[data-v-bf91f9cc], .rp-scroll-area__scrollbar:focus-visible .rp-scroll-area__thumb[data-v-bf91f9cc] {
97
+ .rp-scroll-area__scrollbar:hover .rp-scroll-area__thumb[data-v-f5c4e940], .rp-scroll-area__scrollbar:focus-visible .rp-scroll-area__thumb[data-v-f5c4e940] {
98
98
  background: var(--_rp-scroll-area-thumb-bg-hover);
99
99
  }
100
- .rp-scroll-area__scrollbar--horizontal .rp-scroll-area__thumb[data-v-bf91f9cc] {
100
+ .rp-scroll-area__scrollbar--horizontal .rp-scroll-area__thumb[data-v-f5c4e940] {
101
101
  width: var(--_rp-scroll-area-thumb-size);
102
102
  height: 100%;
103
103
  transform: translateX(var(--_rp-scroll-area-thumb-offset));
104
104
  }
105
- .rp-scroll-area__scrollbar--vertical .rp-scroll-area__thumb[data-v-bf91f9cc] {
105
+ .rp-scroll-area__scrollbar--vertical .rp-scroll-area__thumb[data-v-f5c4e940] {
106
106
  width: 100%;
107
107
  height: var(--_rp-scroll-area-thumb-size);
108
108
  transform: translateY(var(--_rp-scroll-area-thumb-offset));
109
109
  }
110
- .rp-scroll-area__corner[data-v-bf91f9cc] {
110
+ .rp-scroll-area__corner[data-v-f5c4e940] {
111
111
  position: absolute;
112
112
  right: 0;
113
113
  bottom: 0;
@@ -118,13 +118,13 @@
118
118
  pointer-events: none;
119
119
  transition: opacity var(--rp-transition-fast);
120
120
  }
121
- .rp-scroll-area__corner[data-visible][data-v-bf91f9cc] {
121
+ .rp-scroll-area__corner[data-visible][data-v-f5c4e940] {
122
122
  opacity: 1;
123
123
  }
124
124
  @media (prefers-reduced-motion: reduce) {
125
- .rp-scroll-area__scrollbar[data-v-bf91f9cc],
126
- .rp-scroll-area__corner[data-v-bf91f9cc],
127
- .rp-scroll-area__thumb[data-v-bf91f9cc] {
125
+ .rp-scroll-area__scrollbar[data-v-f5c4e940],
126
+ .rp-scroll-area__corner[data-v-f5c4e940],
127
+ .rp-scroll-area__thumb[data-v-f5c4e940] {
128
128
  transition: none;
129
129
  }
130
130
  }
@@ -38,14 +38,62 @@ function getLengthValue(value) {
38
38
  //#endregion
39
39
  //#region src/components/scroll-area/useScrollAreaControls.ts
40
40
  function useScrollAreaControls(options) {
41
+ let previousPosition = {
42
+ x: 0,
43
+ y: 0
44
+ };
41
45
  function onViewportScroll(event) {
42
46
  options.metrics.update();
43
47
  options.showDuringScroll();
48
+ const position = {
49
+ x: options.metrics.getPosition("x"),
50
+ y: options.metrics.getPosition("y")
51
+ };
52
+ const reachedBoundaries = getReachedBoundaries(position);
53
+ previousPosition = position;
44
54
  options.emitScroll(event);
45
55
  options.emitPositionChange({
46
56
  x: options.metrics.metrics.x,
47
57
  y: options.metrics.metrics.y
48
58
  });
59
+ for (const boundary of reachedBoundaries) emitReachedBoundary(boundary, event);
60
+ }
61
+ function getReachedBoundaries(position) {
62
+ const boundaries = [];
63
+ if (options.metrics.getOverflow("y")) {
64
+ const maxPosition = options.metrics.getMaxPosition("y");
65
+ if (position.y <= 1 && previousPosition.y > 1) boundaries.push("top");
66
+ if (position.y >= maxPosition - 1 && previousPosition.y < maxPosition - 1) boundaries.push("bottom");
67
+ }
68
+ if (options.metrics.getOverflow("x")) {
69
+ const maxPosition = options.metrics.getMaxPosition("x");
70
+ const reachedStart = position.x <= 1 && previousPosition.x > 1;
71
+ const reachedEnd = position.x >= maxPosition - 1 && previousPosition.x < maxPosition - 1;
72
+ if (reachedStart || reachedEnd) {
73
+ const viewport = options.viewportRef.value;
74
+ const view = viewport?.ownerDocument.defaultView;
75
+ const rtl = viewport ? view?.getComputedStyle(viewport).direction === "rtl" : false;
76
+ if (reachedStart) boundaries.push(rtl ? "right" : "left");
77
+ if (reachedEnd) boundaries.push(rtl ? "left" : "right");
78
+ }
79
+ }
80
+ return boundaries;
81
+ }
82
+ function emitReachedBoundary(boundary, event) {
83
+ switch (boundary) {
84
+ case "top":
85
+ options.emitReachTop(event);
86
+ break;
87
+ case "bottom":
88
+ options.emitReachBottom(event);
89
+ break;
90
+ case "left":
91
+ options.emitReachLeft(event);
92
+ break;
93
+ case "right":
94
+ options.emitReachRight(event);
95
+ break;
96
+ }
49
97
  }
50
98
  function writeAxisPosition(axis, value) {
51
99
  const viewport = options.viewportRef.value;
@@ -446,7 +494,11 @@ function useScrollArea(options) {
446
494
  metrics: measurements,
447
495
  showDuringScroll: visibility.showDuringScroll,
448
496
  emitScroll: options.emitScroll,
449
- emitPositionChange: options.emitPositionChange
497
+ emitPositionChange: options.emitPositionChange,
498
+ emitReachTop: options.emitReachTop,
499
+ emitReachBottom: options.emitReachBottom,
500
+ emitReachLeft: options.emitReachLeft,
501
+ emitReachRight: options.emitReachRight
450
502
  });
451
503
  const pointer = useScrollAreaPointer({
452
504
  horizontalScrollbarRef,
@@ -523,7 +575,17 @@ function useScrollAreaPresentation(props, scrollArea) {
523
575
  }
524
576
  };
525
577
  });
526
- const contentAttrs = computed(() => getPartAttrs("content", { class: "rp-scroll-area__content" }));
578
+ const contentAttrs = computed(() => {
579
+ const { class: compatibilityClass, style: compatibilityStyle, ...attrs } = props.contentAttrs ?? {};
580
+ return {
581
+ ...attrs,
582
+ ...getPartAttrs("content", {
583
+ class: "rp-scroll-area__content",
584
+ compatibilityClass,
585
+ compatibilityStyle
586
+ })
587
+ };
588
+ });
527
589
  const horizontalScrollbarAttrs = computed(() => getScrollbarAttrs("x"));
528
590
  const verticalScrollbarAttrs = computed(() => getScrollbarAttrs("y"));
529
591
  const horizontalThumbAttrs = computed(() => getThumbAttrs("x"));
@@ -592,9 +654,9 @@ function hasAccessibleName(props, attrs) {
592
654
  }
593
655
  //#endregion
594
656
  //#region src/components/scroll-area/scroll-area.vue?vue&type=script&setup=true&vapor=true&lang.ts
595
- var t0 = template("<div data-v-bf91f9cc><div data-v-bf91f9cc></div>");
596
- var t1 = template("<div data-v-bf91f9cc>");
597
- var t2 = template("<div data-v-bf91f9cc><div data-v-bf91f9cc><div data-v-bf91f9cc></div></div>", 1);
657
+ var t0 = template("<div data-v-f5c4e940><div data-v-f5c4e940></div>");
658
+ var t1 = template("<div data-v-f5c4e940>");
659
+ var t2 = template("<div data-v-f5c4e940><div data-v-f5c4e940><div data-v-f5c4e940></div></div>", 1);
598
660
  delegateEvents("pointerdown", "keydown");
599
661
  //#endregion
600
662
  //#region src/components/scroll-area/scroll-area.vue
@@ -603,33 +665,54 @@ var scroll_area_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__
603
665
  inheritAttrs: false,
604
666
  __name: "scroll-area",
605
667
  props: {
606
- id: {},
668
+ id: String,
607
669
  embedded: {
608
670
  type: Boolean,
609
671
  default: false
610
672
  },
611
- type: { default: "hover" },
673
+ type: {
674
+ type: String,
675
+ default: "hover"
676
+ },
612
677
  scrollbars: {
613
- type: Boolean,
678
+ type: [String, Boolean],
614
679
  default: "both"
615
680
  },
616
- scrollbarSize: { default: 10 },
617
- scrollHideDelay: { default: 600 },
618
- ariaLabel: {},
619
- ariaLabelledby: {},
620
- ariaDescribedby: {},
621
- viewportAttrs: {},
622
- classNames: {},
623
- styles: {}
681
+ scrollbarSize: {
682
+ type: [Number, String],
683
+ default: 10
684
+ },
685
+ scrollHideDelay: {
686
+ type: Number,
687
+ default: 600
688
+ },
689
+ ariaLabel: String,
690
+ ariaLabelledby: String,
691
+ ariaDescribedby: String,
692
+ viewportAttrs: Object,
693
+ contentAttrs: Object,
694
+ classNames: Object,
695
+ styles: Object
624
696
  },
625
- emits: ["scroll", "scrollPositionChange"],
697
+ emits: [
698
+ "scroll",
699
+ "scrollPositionChange",
700
+ "reachTop",
701
+ "reachBottom",
702
+ "reachLeft",
703
+ "reachRight"
704
+ ],
626
705
  setup(__props, { expose: __expose, emit: __emit }) {
627
706
  const props = __props;
628
707
  const emit = __emit;
629
708
  const scrollArea = useScrollArea({
630
709
  props,
631
710
  emitScroll: (event) => emit("scroll", event),
632
- emitPositionChange: (position) => emit("scrollPositionChange", position)
711
+ emitPositionChange: (position) => emit("scrollPositionChange", position),
712
+ emitReachTop: (event) => emit("reachTop", event),
713
+ emitReachBottom: (event) => emit("reachBottom", event),
714
+ emitReachLeft: (event) => emit("reachLeft", event),
715
+ emitReachRight: (event) => emit("reachRight", event)
633
716
  });
634
717
  const { rootRef, viewportRef, contentRef, horizontalScrollbarRef, verticalScrollbarRef, renderHorizontalScrollbar, renderVerticalScrollbar, onScrollbarKeydown, onScrollbarWheel, onScrollbarPointerdown, onThumbPointerdown, scrollTo, scrollBy, update } = scrollArea;
635
718
  const { rootAttrs, viewportAttrs, contentAttrs, horizontalScrollbarAttrs, verticalScrollbarAttrs, horizontalThumbAttrs, verticalThumbAttrs, cornerAttrs, slotProps } = useScrollAreaPresentation(props, scrollArea);
@@ -691,6 +774,6 @@ var scroll_area_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__
691
774
  _setTemplateRef(n14, rootRef, null, "rootRef");
692
775
  return n14;
693
776
  }
694
- }), [["__scopeId", "data-v-bf91f9cc"]]);
777
+ }), [["__scopeId", "data-v-f5c4e940"]]);
695
778
  //#endregion
696
779
  export { scroll_area_default as t };
package/dist/select.js CHANGED
@@ -3,10 +3,12 @@ import { t as x_default } from "./x.js";
3
3
  import { t as bem } from "./bem.js";
4
4
  import { n as useStylesApi, t as presence } from "./styles-api.js";
5
5
  import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
6
- import { i as useFormControl, o as useControllableValue } from "./useFormControl.js";
6
+ import { t as useControllableValue } from "./useControllableValue.js";
7
+ import { i as useFormControl } from "./useFormControl.js";
7
8
  import { t as useControlState } from "./useControlState.js";
9
+ import { n as getNextEnabledIndex, r as useTypeahead, t as getEnabledIndexes } from "./collectionNavigation.js";
8
10
  import { t as scroll_area_default } from "./scroll-area.js";
9
- import { VaporTransition, child, computed, createComponent, createFor, createIf, createInvoker, createSlot, createTemplateRefSetter, defineVaporComponent, delegateEvents, extend, markRaw, next, nextTick, on, onBeforeUnmount, onMounted, ref, renderEffect, setDynamicProps, setInsertionState, setProp, setText, setValue, template, toDisplayString, txt, unref, useId, watch, watchEffect, withModifiers, withVaporModifiers } from "vue";
11
+ import { VaporTransition, child, computed, createComponent, createFor, createIf, createInvoker, createSlot, createTemplateRefSetter, defineVaporComponent, delegateEvents, extend, markRaw, next, nextTick, on, onBeforeUnmount, onMounted, ref, renderEffect, setDynamicProps, setInsertionState, setProp, setText, setValue, shallowRef, template, toDisplayString, txt, unref, useId, watch, watchEffect, withModifiers, withVaporModifiers } from "vue";
10
12
  //#region ~icons/lucide/chevrons-up-down
11
13
  var t0$1 = template("<svg viewBox=\"0 0 24 24\"width=1.2em height=1.2em><path fill=none stroke=currentColor stroke-linecap=round stroke-linejoin=round stroke-width=2 d=\"m7 15l5 5l5-5M7 9l5-5l5 5\">", 3, 1);
12
14
  function render(_ctx) {
@@ -39,61 +41,61 @@ function useClickOutside(target, active, callback) {
39
41
  });
40
42
  }
41
43
  //#endregion
42
- //#region src/composables/useListNavigation.ts
43
- function useListNavigation(options) {
44
- const localFocusedIndex = ref(-1);
44
+ //#region src/composables/useCollectionNavigation.ts
45
+ function useCollectionNavigation(options) {
46
+ const activeKey = shallowRef(null);
47
+ const isDisabled = options.isDisabled ?? (() => false);
45
48
  const loop = options.loop ?? true;
46
- const enabledIndexes = computed(() => options.items().map((item, index) => item.disabled ? -1 : index).filter((index) => index >= 0));
47
- function resetFocus() {
48
- localFocusedIndex.value = -1;
49
+ const activeIndex = computed(() => {
50
+ if (activeKey.value == null) return -1;
51
+ return options.items().findIndex((item) => options.getKey(item) === activeKey.value && !isDisabled(item));
52
+ });
53
+ const enabledIndexes = computed(() => getEnabledIndexes(options.items(), isDisabled));
54
+ function resetActive() {
55
+ activeKey.value = null;
49
56
  }
50
- function setNearest(index, direction) {
51
- const indexes = enabledIndexes.value;
52
- if (indexes.length === 0) {
53
- resetFocus();
54
- return;
55
- }
56
- if (options.items()[index] && !options.items()[index]?.disabled) {
57
- localFocusedIndex.value = index;
58
- return;
59
- }
60
- let next;
61
- if (direction === 1) next = indexes.find((i) => i > index);
62
- else for (let i = indexes.length - 1; i >= 0; i -= 1) {
63
- const candidate = indexes[i];
64
- if (candidate < index) {
65
- next = candidate;
66
- break;
67
- }
68
- }
69
- if (next !== void 0) localFocusedIndex.value = next;
70
- else if (loop) localFocusedIndex.value = direction === 1 ? indexes[0] : indexes[indexes.length - 1];
57
+ function setActiveIndex(index) {
58
+ const item = options.items()[index];
59
+ if (!item || isDisabled(item)) return false;
60
+ activeKey.value = options.getKey(item);
61
+ return true;
71
62
  }
72
63
  function focusSelected() {
73
64
  const items = options.items();
74
- const selectedIndex = options.isSelected ? items.findIndex((item) => options.isSelected(item) && !item.disabled) : -1;
75
- if (selectedIndex >= 0) localFocusedIndex.value = selectedIndex;
65
+ const selectedIndex = options.isSelected ? items.findIndex((item) => options.isSelected(item) && !isDisabled(item)) : -1;
66
+ if (selectedIndex >= 0) setActiveIndex(selectedIndex);
76
67
  else focusFirst();
77
68
  }
78
69
  function focusFirst() {
79
70
  const first = enabledIndexes.value[0];
80
- localFocusedIndex.value = first ?? -1;
71
+ if (first === void 0) resetActive();
72
+ else setActiveIndex(first);
81
73
  }
82
74
  function focusLast() {
83
75
  const indexes = enabledIndexes.value;
84
- localFocusedIndex.value = indexes[indexes.length - 1] ?? -1;
76
+ const last = indexes[indexes.length - 1];
77
+ if (last === void 0) resetActive();
78
+ else setActiveIndex(last);
85
79
  }
86
- function moveFocus(delta) {
87
- if (localFocusedIndex.value < 0) {
88
- if (delta === 1) focusFirst();
80
+ function moveFocus(direction) {
81
+ if (activeIndex.value < 0) {
82
+ if (direction === 1) focusFirst();
89
83
  else focusLast();
90
84
  return;
91
85
  }
92
- setNearest(localFocusedIndex.value + delta, delta);
86
+ const nextIndex = getNextEnabledIndex(options.items(), activeIndex.value, direction, isDisabled, loop);
87
+ if (nextIndex === void 0) resetActive();
88
+ else setActiveIndex(nextIndex);
93
89
  }
90
+ watch(activeIndex, (index) => {
91
+ if (activeKey.value != null && index < 0) resetActive();
92
+ }, { flush: "sync" });
94
93
  return {
95
- focusedIndex: localFocusedIndex,
96
- resetFocus,
94
+ activeKey,
95
+ activeIndex,
96
+ enabledIndexes,
97
+ resetActive,
98
+ setActiveIndex,
97
99
  focusSelected,
98
100
  focusFirst,
99
101
  focusLast,
@@ -109,8 +111,8 @@ function getSelectDisplayLabel(options, value) {
109
111
  if (!hasSelectValue(value)) return "";
110
112
  return options?.find((option) => option.value === value)?.label ?? "";
111
113
  }
112
- function getSelectActiveDescendantId(baseId, focusedIndex) {
113
- return focusedIndex < 0 ? void 0 : `${baseId}-option-${focusedIndex}`;
114
+ function getSelectActiveDescendantId(baseId, focusedIndex, isOpen) {
115
+ return !isOpen || focusedIndex < 0 ? void 0 : `${baseId}-option-${focusedIndex}`;
114
116
  }
115
117
  function useSelect(props, emitUpdate, getValue = () => props.modelValue ?? null, triggerRef = ref(null)) {
116
118
  const selectRef = ref(null);
@@ -120,12 +122,26 @@ function useSelect(props, emitUpdate, getValue = () => props.modelValue ?? null,
120
122
  const control = useControlState(props);
121
123
  const visibleOptions = computed(() => props.options ?? []);
122
124
  const value = computed(getValue);
123
- const navigation = useListNavigation({
125
+ const navigation = useCollectionNavigation({
124
126
  items: () => visibleOptions.value,
127
+ getKey: (item) => item.value,
128
+ isDisabled: (item) => Boolean(item.disabled),
125
129
  isSelected: (item) => item.value === value.value
126
130
  });
127
- const focusedIndex = navigation.focusedIndex;
128
- const activeDescendantId = computed(() => getSelectActiveDescendantId(selectId, focusedIndex.value));
131
+ const focusedIndex = navigation.activeIndex;
132
+ const selectedIndex = computed(() => visibleOptions.value.findIndex((option) => option.value === value.value && !option.disabled));
133
+ const activeDescendantId = computed(() => getSelectActiveDescendantId(selectId, focusedIndex.value, isOpen.value));
134
+ const typeahead = useTypeahead({
135
+ items: () => visibleOptions.value,
136
+ activeIndex: () => isOpen.value ? focusedIndex.value : selectedIndex.value,
137
+ getKey: (item) => item.value,
138
+ getTextValue: (item) => item.label,
139
+ isDisabled: (item) => Boolean(item.disabled),
140
+ onMatch(item, index) {
141
+ if (isOpen.value) navigation.setActiveIndex(index);
142
+ else if (item.value !== value.value) emitUpdate(item.value);
143
+ }
144
+ });
129
145
  const rootClass = computed(() => bem("rp-select", {
130
146
  open: isOpen.value,
131
147
  [`size-${props.size}`]: Boolean(props.size),
@@ -141,12 +157,14 @@ function useSelect(props, emitUpdate, getValue = () => props.modelValue ?? null,
141
157
  }
142
158
  function open() {
143
159
  if (control.disabled || isOpen.value) return;
160
+ typeahead.reset();
144
161
  isOpen.value = true;
145
162
  navigation.focusSelected();
146
163
  }
147
164
  function close() {
148
165
  isOpen.value = false;
149
- navigation.resetFocus();
166
+ navigation.resetActive();
167
+ typeahead.reset();
150
168
  }
151
169
  function toggle() {
152
170
  if (control.disabled) return;
@@ -168,7 +186,7 @@ function useSelect(props, emitUpdate, getValue = () => props.modelValue ?? null,
168
186
  focusTrigger();
169
187
  }
170
188
  function onOptionMouseenter(option, index) {
171
- if (!option.disabled) focusedIndex.value = index;
189
+ if (!option.disabled) navigation.setActiveIndex(index);
172
190
  }
173
191
  function onFocusout(event) {
174
192
  const nextTarget = event.relatedTarget;
@@ -181,6 +199,7 @@ function useSelect(props, emitUpdate, getValue = () => props.modelValue ?? null,
181
199
  }
182
200
  function onTriggerKeydown(e) {
183
201
  if (control.disabled) return;
202
+ if (typeahead.handleKey(e)) return;
184
203
  switch (e.key) {
185
204
  case "Enter":
186
205
  e.preventDefault();