ropav 0.1.8 → 0.1.9
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/README.md +4 -3
- package/dist/calendar.css +44 -33
- package/dist/calendar.js +108 -83
- package/dist/components/calendar/index.d.ts +1 -1
- package/dist/components/calendar/types.d.ts +3 -0
- package/dist/components/date-picker/index.d.ts +1 -1
- package/dist/components/date-picker/types.d.ts +3 -1
- package/dist/components/slider/useSlider.d.ts +1 -1
- package/dist/components/slider/useSliderPointer.d.ts +15 -0
- package/dist/components/slider/useSliderValueState.d.ts +1 -0
- package/dist/components/toolbar/index.d.ts +3 -0
- package/dist/components/toolbar/index.js +2 -0
- package/dist/components/toolbar/toolbar.d.ts +24 -0
- package/dist/components/toolbar/types.d.ts +12 -0
- package/dist/components/toolbar/useToolbar.d.ts +7 -0
- package/dist/date-picker.css +8 -8
- package/dist/date-picker.js +4 -2
- package/dist/focusNavigation.js +12 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- package/dist/slider.css +78 -69
- package/dist/slider.js +91 -16
- package/dist/toolbar.css +15 -0
- package/dist/toolbar.js +143 -0
- package/dist/utils/dom/focusNavigation.d.ts +4 -1
- package/docs/public-styles-api.md +4 -1
- package/package.json +31 -39
- package/docs/code-architecture.md +0 -118
package/dist/slider.js
CHANGED
|
@@ -112,6 +112,63 @@ function getSliderTooltipAnchor(tooltip) {
|
|
|
112
112
|
return typeof tooltip === "object" && tooltip.anchor === "pointer" ? "pointer" : "thumb";
|
|
113
113
|
}
|
|
114
114
|
//#endregion
|
|
115
|
+
//#region src/components/slider/useSliderPointer.ts
|
|
116
|
+
function readPointerGeometry(track, orientation) {
|
|
117
|
+
const vertical = orientation === "vertical";
|
|
118
|
+
const thumbTravelRect = track.querySelector(".rp-slider__thumb")?.getBoundingClientRect();
|
|
119
|
+
const rect = thumbTravelRect && (vertical ? thumbTravelRect.height > 0 : thumbTravelRect.width > 0) ? thumbTravelRect : track.getBoundingClientRect();
|
|
120
|
+
const length = vertical ? rect.height : rect.width;
|
|
121
|
+
if (length <= 0) return;
|
|
122
|
+
return {
|
|
123
|
+
length,
|
|
124
|
+
start: vertical ? rect.bottom : rect.left,
|
|
125
|
+
vertical
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function getPointerValue(event, geometry, bounds, step) {
|
|
129
|
+
const pointerPosition = geometry.vertical ? event.clientY : event.clientX;
|
|
130
|
+
const ratio = clamp((geometry.vertical ? geometry.start - pointerPosition : pointerPosition - geometry.start) / geometry.length, 0, 1);
|
|
131
|
+
return normalizeSliderValue(bounds.min + ratio * (bounds.max - bounds.min), bounds.min, bounds.max, step);
|
|
132
|
+
}
|
|
133
|
+
function useSliderPointer(options) {
|
|
134
|
+
function refreshGeometry(currentSession) {
|
|
135
|
+
const geometry = readPointerGeometry(currentSession.track, options.orientation());
|
|
136
|
+
if (!geometry) return false;
|
|
137
|
+
currentSession.geometry = geometry;
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
function updateFromPointer(event, currentSession) {
|
|
141
|
+
options.updateValue(getPointerValue(event, currentSession.geometry, options.bounds.value, options.step.value));
|
|
142
|
+
}
|
|
143
|
+
const pointerSession = createPointerSession({
|
|
144
|
+
onStart(event, currentSession) {
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
options.inputRef.value?.focus({ preventScroll: true });
|
|
147
|
+
updateFromPointer(event, currentSession);
|
|
148
|
+
},
|
|
149
|
+
onUpdate: updateFromPointer,
|
|
150
|
+
refreshGeometry
|
|
151
|
+
});
|
|
152
|
+
function onPointerDown(event) {
|
|
153
|
+
return pointerSession.start(event, () => {
|
|
154
|
+
if (options.disabled()) return;
|
|
155
|
+
const track = event.currentTarget;
|
|
156
|
+
if (!track) return;
|
|
157
|
+
const geometry = readPointerGeometry(track, options.orientation());
|
|
158
|
+
if (!geometry) return;
|
|
159
|
+
return {
|
|
160
|
+
state: {
|
|
161
|
+
geometry,
|
|
162
|
+
track
|
|
163
|
+
},
|
|
164
|
+
target: track
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
onBeforeUnmount(pointerSession.stop);
|
|
169
|
+
return { onPointerDown };
|
|
170
|
+
}
|
|
171
|
+
//#endregion
|
|
115
172
|
//#region src/components/slider/useSliderPointerPreview.ts
|
|
116
173
|
function getPreviewRect(track, vertical) {
|
|
117
174
|
const travelRect = track.querySelector(".rp-slider__travel")?.getBoundingClientRect();
|
|
@@ -357,7 +414,11 @@ function useSliderValueState(props, onChange) {
|
|
|
357
414
|
function onInput(event) {
|
|
358
415
|
if (control.disabled) return;
|
|
359
416
|
const input = event.target;
|
|
360
|
-
|
|
417
|
+
updateValue(input.valueAsNumber);
|
|
418
|
+
}
|
|
419
|
+
function updateValue(value) {
|
|
420
|
+
if (control.disabled) return;
|
|
421
|
+
controllable.setValue(normalizeSliderValue(value, bounds.value.min, bounds.value.max, nativeStep.value));
|
|
361
422
|
}
|
|
362
423
|
useFormControl({
|
|
363
424
|
elements: () => [inputRef.value],
|
|
@@ -391,7 +452,8 @@ function useSliderValueState(props, onChange) {
|
|
|
391
452
|
markItems,
|
|
392
453
|
hasMarkLabels,
|
|
393
454
|
trackSlotProps,
|
|
394
|
-
onInput
|
|
455
|
+
onInput,
|
|
456
|
+
updateValue
|
|
395
457
|
};
|
|
396
458
|
}
|
|
397
459
|
//#endregion
|
|
@@ -436,6 +498,19 @@ function useSlider(props, onChange) {
|
|
|
436
498
|
invalid: valueState.control.invalid
|
|
437
499
|
}));
|
|
438
500
|
const trackStyle = computed(() => getSliderTrackStyle(props, valueState.valuePercent.value, tooltipState.tooltipPercent.value));
|
|
501
|
+
const pointerState = useSliderPointer({
|
|
502
|
+
bounds: valueState.bounds,
|
|
503
|
+
disabled: () => valueState.control.disabled,
|
|
504
|
+
inputRef: valueState.inputRef,
|
|
505
|
+
orientation: () => props.orientation,
|
|
506
|
+
step: valueState.nativeStep,
|
|
507
|
+
updateValue: valueState.updateValue
|
|
508
|
+
});
|
|
509
|
+
function onTrackPointerDown(event) {
|
|
510
|
+
const started = pointerState.onPointerDown(event);
|
|
511
|
+
tooltipState.onTooltipPointerDown(event);
|
|
512
|
+
return started;
|
|
513
|
+
}
|
|
439
514
|
return {
|
|
440
515
|
inputRef: valueState.inputRef,
|
|
441
516
|
focus: valueState.focus,
|
|
@@ -470,7 +545,7 @@ function useSlider(props, onChange) {
|
|
|
470
545
|
tooltipFormattedValue: tooltipState.tooltipFormattedValue,
|
|
471
546
|
tooltipContent: tooltipState.tooltipContent,
|
|
472
547
|
onInput: valueState.onInput,
|
|
473
|
-
|
|
548
|
+
onTrackPointerDown,
|
|
474
549
|
onTooltipPointerMove: tooltipState.onTooltipPointerMove,
|
|
475
550
|
onTooltipTrackEnter: tooltipState.onTooltipTrackEnter,
|
|
476
551
|
onTooltipTrackLeave: tooltipState.onTooltipTrackLeave,
|
|
@@ -481,17 +556,17 @@ function useSlider(props, onChange) {
|
|
|
481
556
|
}
|
|
482
557
|
//#endregion
|
|
483
558
|
//#region src/components/slider/slider.vue?vue&type=script&setup=true&vapor=true&lang.ts
|
|
484
|
-
var t0$2 = template("<span data-v-
|
|
485
|
-
var t1$2 = template("<span data-v-
|
|
486
|
-
var t2$2 = template("<span data-v-
|
|
487
|
-
var t3$2 = template("<span data-v-
|
|
488
|
-
var t4$2 = template("<span data-v-
|
|
489
|
-
var t5$1 = template("<span data-v-
|
|
490
|
-
var t6$1 = template("<span data-v-
|
|
491
|
-
var t7$1 = template("<span data-v-
|
|
492
|
-
var t8$1 = template("<span data-v-
|
|
559
|
+
var t0$2 = template("<span data-v-0fbfb274>");
|
|
560
|
+
var t1$2 = template("<span data-v-0fbfb274 class=rp-slider__header>");
|
|
561
|
+
var t2$2 = template("<span data-v-0fbfb274 class=\"rp-slider__track-layer rp-slider__track-underlay\"aria-hidden=true>");
|
|
562
|
+
var t3$2 = template("<span data-v-0fbfb274 class=\"rp-slider__track-layer rp-slider__track-overlay\"aria-hidden=true>");
|
|
563
|
+
var t4$2 = template("<span data-v-0fbfb274 class=rp-slider__travel aria-hidden=true>", 2);
|
|
564
|
+
var t5$1 = template("<span data-v-0fbfb274> ");
|
|
565
|
+
var t6$1 = template("<span data-v-0fbfb274><span data-v-0fbfb274 class=rp-slider__mark-dot></span>");
|
|
566
|
+
var t7$1 = template("<span data-v-0fbfb274 class=rp-slider__marks aria-hidden=true>");
|
|
567
|
+
var t8$1 = template("<span data-v-0fbfb274 class=rp-slider__tooltip-anchor aria-hidden=true></span>", 2);
|
|
493
568
|
var t9$1 = template(" ");
|
|
494
|
-
var t10 = template("<label data-v-
|
|
569
|
+
var t10 = template("<label data-v-0fbfb274><span data-v-0fbfb274><span data-v-0fbfb274 class=rp-slider__rail aria-hidden=true></span><!><span data-v-0fbfb274></span><!><input data-v-0fbfb274><!><span data-v-0fbfb274><span data-v-0fbfb274 class=rp-slider__thumb-content>", 1);
|
|
495
570
|
//#endregion
|
|
496
571
|
//#region src/components/slider/slider.vue
|
|
497
572
|
var slider_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineVaporComponent({
|
|
@@ -554,7 +629,7 @@ var slider_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
554
629
|
const slots = useSlots();
|
|
555
630
|
const props = __props;
|
|
556
631
|
const emit = __emit;
|
|
557
|
-
const { inputRef, focus, control, nativeMin, nativeMax, nativeStep, rootClass, normalizedValue, valuePercent, formattedValue, ariaValueText, markItems, thumbMode, trackSlotProps, trackStyle, trackHovered, dragging, tooltipVisible, tooltipOpen, tooltipAnchor, tooltipPlacement, tooltipId, tooltipColor, tooltipAutoContrast, tooltipContrastColor, tooltipOffset, tooltipOpenDelay, tooltipArrow, tooltipValue, tooltipPercent, tooltipFormattedValue, tooltipContent, onInput,
|
|
632
|
+
const { inputRef, focus, control, nativeMin, nativeMax, nativeStep, rootClass, normalizedValue, valuePercent, formattedValue, ariaValueText, markItems, thumbMode, trackSlotProps, trackStyle, trackHovered, dragging, tooltipVisible, tooltipOpen, tooltipAnchor, tooltipPlacement, tooltipId, tooltipColor, tooltipAutoContrast, tooltipContrastColor, tooltipOffset, tooltipOpenDelay, tooltipArrow, tooltipValue, tooltipPercent, tooltipFormattedValue, tooltipContent, onInput, onTrackPointerDown, onTooltipPointerMove, onTooltipTrackEnter, onTooltipTrackLeave, onTooltipFocusIn, onTooltipFocusOut, onTooltipKeydown } = useSlider(props, (value) => emit("update:modelValue", value));
|
|
558
633
|
const { getPartAttrs, getRootAttrs } = useStylesApi(props, "root");
|
|
559
634
|
const rootAttrs = computed(() => getRootAttrs({
|
|
560
635
|
class: [rootClass.value, { "rp-slider--custom-thumb": Boolean(slots.thumb) }],
|
|
@@ -741,7 +816,7 @@ var slider_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
741
816
|
}
|
|
742
817
|
});
|
|
743
818
|
});
|
|
744
|
-
on(n45, "pointerdown", (e) => unref(
|
|
819
|
+
on(n45, "pointerdown", (e) => unref(onTrackPointerDown)(e));
|
|
745
820
|
on(n45, "pointerenter", (e) => unref(onTooltipTrackEnter)(e));
|
|
746
821
|
on(n45, "pointerleave", (e) => unref(onTooltipTrackLeave)(e));
|
|
747
822
|
on(n45, "pointermove", (e) => unref(onTooltipPointerMove)(e));
|
|
@@ -750,7 +825,7 @@ var slider_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
750
825
|
on(n45, "keydown", (e) => unref(onTooltipKeydown)(e));
|
|
751
826
|
return n48;
|
|
752
827
|
}
|
|
753
|
-
}), [["__scopeId", "data-v-
|
|
828
|
+
}), [["__scopeId", "data-v-0fbfb274"]]);
|
|
754
829
|
//#endregion
|
|
755
830
|
//#region src/components/slider/useRangeSliderTooltipCollision.ts
|
|
756
831
|
var TOOLTIP_COLLISION_GAP = 4;
|
package/dist/toolbar.css
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
@layer ropav.components {
|
|
2
|
+
.rp-toolbar[data-v-34ce03a4] {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: var(--rp-spacing-2);
|
|
7
|
+
min-width: 0;
|
|
8
|
+
font-family: var(--rp-font-family);
|
|
9
|
+
}
|
|
10
|
+
.rp-toolbar--vertical[data-v-34ce03a4] {
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
align-items: stretch;
|
|
13
|
+
min-height: 0;
|
|
14
|
+
}
|
|
15
|
+
}
|
package/dist/toolbar.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import './toolbar.css';
|
|
2
|
+
import { t as useStylesApi } from "./styles-api.js";
|
|
3
|
+
import { t as bem } from "./bem.js";
|
|
4
|
+
import { t as isElement } from "./query.js";
|
|
5
|
+
import { n as setFocusNavigationTabStop, t as getFocusNavigationTarget } from "./focusNavigation.js";
|
|
6
|
+
import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
|
|
7
|
+
import { computed, createSlot, defineVaporComponent, onBeforeUnmount, onMounted, renderEffect, setDynamicProps, setInsertionState, setStaticTemplateRef, shallowRef, template } from "vue";
|
|
8
|
+
//#region src/components/toolbar/useToolbar.ts
|
|
9
|
+
var TOOLBAR_SELECTOR = "[role=\"toolbar\"]";
|
|
10
|
+
var TOOLBAR_ITEM_SELECTOR = [
|
|
11
|
+
"button",
|
|
12
|
+
"a[href]",
|
|
13
|
+
"input:not([type=\"hidden\"])",
|
|
14
|
+
"select",
|
|
15
|
+
"textarea",
|
|
16
|
+
"[contenteditable=\"true\"]",
|
|
17
|
+
"[role=\"button\"]",
|
|
18
|
+
"[role=\"checkbox\"]",
|
|
19
|
+
"[role=\"combobox\"]",
|
|
20
|
+
"[role=\"link\"]",
|
|
21
|
+
"[role=\"radio\"]",
|
|
22
|
+
"[role=\"slider\"]",
|
|
23
|
+
"[role=\"spinbutton\"]",
|
|
24
|
+
"[role=\"switch\"]",
|
|
25
|
+
"[tabindex]"
|
|
26
|
+
].join(",");
|
|
27
|
+
var TOOLBAR_NAVIGATION_OPTIONS = {
|
|
28
|
+
itemSelector: TOOLBAR_ITEM_SELECTOR,
|
|
29
|
+
collectionSelector: TOOLBAR_SELECTOR
|
|
30
|
+
};
|
|
31
|
+
function useToolbar(root, getOrientation) {
|
|
32
|
+
const activeItem = shallowRef(null);
|
|
33
|
+
let observer = null;
|
|
34
|
+
function setTabStop(item) {
|
|
35
|
+
const toolbar = root.value;
|
|
36
|
+
if (!toolbar) return null;
|
|
37
|
+
const nextItem = setFocusNavigationTabStop(toolbar, item, TOOLBAR_NAVIGATION_OPTIONS);
|
|
38
|
+
activeItem.value = nextItem;
|
|
39
|
+
return nextItem;
|
|
40
|
+
}
|
|
41
|
+
function syncTabStop() {
|
|
42
|
+
setTabStop(activeItem.value);
|
|
43
|
+
}
|
|
44
|
+
function onFocusin(event) {
|
|
45
|
+
const toolbar = root.value;
|
|
46
|
+
if (!toolbar || !isElement(event.target)) return;
|
|
47
|
+
const item = event.target.closest(TOOLBAR_ITEM_SELECTOR);
|
|
48
|
+
if (item?.closest(TOOLBAR_SELECTOR) === toolbar) setTabStop(item);
|
|
49
|
+
}
|
|
50
|
+
function onKeydown(event) {
|
|
51
|
+
const toolbar = root.value;
|
|
52
|
+
if (!toolbar) return;
|
|
53
|
+
const nextItem = getFocusNavigationTarget(event, toolbar, {
|
|
54
|
+
...TOOLBAR_NAVIGATION_OPTIONS,
|
|
55
|
+
orientation: getOrientation()
|
|
56
|
+
});
|
|
57
|
+
if (!nextItem) return;
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
setTabStop(nextItem);
|
|
60
|
+
nextItem.focus();
|
|
61
|
+
}
|
|
62
|
+
function focus() {
|
|
63
|
+
setTabStop(activeItem.value)?.focus();
|
|
64
|
+
}
|
|
65
|
+
onMounted(() => {
|
|
66
|
+
const toolbar = root.value;
|
|
67
|
+
if (!toolbar) return;
|
|
68
|
+
syncTabStop();
|
|
69
|
+
const MutationObserverConstructor = toolbar.ownerDocument.defaultView?.MutationObserver;
|
|
70
|
+
if (!MutationObserverConstructor) return;
|
|
71
|
+
observer = new MutationObserverConstructor(syncTabStop);
|
|
72
|
+
observer.observe(toolbar, {
|
|
73
|
+
attributes: true,
|
|
74
|
+
attributeFilter: [
|
|
75
|
+
"disabled",
|
|
76
|
+
"hidden",
|
|
77
|
+
"inert"
|
|
78
|
+
],
|
|
79
|
+
childList: true,
|
|
80
|
+
subtree: true
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
onBeforeUnmount(() => observer?.disconnect());
|
|
84
|
+
return {
|
|
85
|
+
focus,
|
|
86
|
+
onFocusin,
|
|
87
|
+
onKeydown
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/components/toolbar/toolbar.vue?vue&type=script&setup=true&vapor=true&lang.ts
|
|
92
|
+
var t0 = template("<div data-v-34ce03a4>", 1);
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region src/components/toolbar/toolbar.vue
|
|
95
|
+
var toolbar_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineVaporComponent({
|
|
96
|
+
name: "RpToolbar",
|
|
97
|
+
inheritAttrs: false,
|
|
98
|
+
__name: "toolbar",
|
|
99
|
+
props: {
|
|
100
|
+
id: {},
|
|
101
|
+
orientation: { default: "horizontal" },
|
|
102
|
+
ariaLabel: {},
|
|
103
|
+
describedby: {},
|
|
104
|
+
labelledby: {},
|
|
105
|
+
classNames: {},
|
|
106
|
+
styles: {}
|
|
107
|
+
},
|
|
108
|
+
setup(__props, { expose: __expose }) {
|
|
109
|
+
const props = __props;
|
|
110
|
+
const root = shallowRef(null);
|
|
111
|
+
const { focus, onFocusin, onKeydown } = useToolbar(root, () => props.orientation);
|
|
112
|
+
const rootClass = computed(() => bem("rp-toolbar", { vertical: props.orientation === "vertical" }));
|
|
113
|
+
const { getRootAttrs } = useStylesApi(props, "root");
|
|
114
|
+
const rootAttrs = computed(() => getRootAttrs({
|
|
115
|
+
id: props.id,
|
|
116
|
+
class: rootClass.value,
|
|
117
|
+
role: "toolbar",
|
|
118
|
+
"data-orientation": props.orientation,
|
|
119
|
+
"aria-orientation": props.orientation,
|
|
120
|
+
"aria-label": props.ariaLabel || void 0,
|
|
121
|
+
"aria-labelledby": props.labelledby,
|
|
122
|
+
"aria-describedby": props.describedby,
|
|
123
|
+
onFocusin,
|
|
124
|
+
onKeydown
|
|
125
|
+
}));
|
|
126
|
+
__expose({
|
|
127
|
+
nativeElement: root,
|
|
128
|
+
focus
|
|
129
|
+
});
|
|
130
|
+
const n1 = t0();
|
|
131
|
+
renderEffect(() => setDynamicProps(n1, [rootAttrs.value]));
|
|
132
|
+
setInsertionState(n1, null, 0);
|
|
133
|
+
createSlot("default", null, null, 1);
|
|
134
|
+
setStaticTemplateRef(n1, root, null, "root");
|
|
135
|
+
return n1;
|
|
136
|
+
}
|
|
137
|
+
}), [["__scopeId", "data-v-34ce03a4"]]);
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region src/components/toolbar/types.ts
|
|
140
|
+
var toolbarParts = ["root"];
|
|
141
|
+
var toolbarOrientations = ["horizontal", "vertical"];
|
|
142
|
+
//#endregion
|
|
143
|
+
export { toolbarParts as n, toolbar_default as r, toolbarOrientations as t };
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export type FocusNavigationOrientation = 'horizontal' | 'vertical';
|
|
2
|
-
export interface
|
|
2
|
+
export interface FocusNavigationCollectionOptions {
|
|
3
3
|
itemSelector: string;
|
|
4
4
|
collectionSelector: string;
|
|
5
|
+
}
|
|
6
|
+
export interface FocusNavigationOptions extends FocusNavigationCollectionOptions {
|
|
5
7
|
orientation: FocusNavigationOrientation;
|
|
6
8
|
}
|
|
9
|
+
export declare function setFocusNavigationTabStop<ElementType extends HTMLElement>(collection: HTMLElement, preferredItem: ElementType | null, options: FocusNavigationCollectionOptions): ElementType | null;
|
|
7
10
|
export declare function getFocusNavigationTarget<ElementType extends HTMLElement>(event: Pick<KeyboardEvent, 'key' | 'target'>, collection: HTMLElement, options: FocusNavigationOptions): ElementType | undefined;
|
|
@@ -81,6 +81,9 @@ Only independently useful semantic elements are public parts. Conditional parts
|
|
|
81
81
|
|
|
82
82
|
`ToastProvider` renders no DOM and therefore has no Styles API.
|
|
83
83
|
|
|
84
|
+
When `Calendar.showHeader` is `false`, the `header`, `previousControl` and `nextControl` parts are
|
|
85
|
+
not rendered. The `monthLabel` part remains as a visually hidden live label for the calendar grid.
|
|
86
|
+
|
|
84
87
|
## State attributes
|
|
85
88
|
|
|
86
89
|
Boolean states use presence semantics: the attribute value is empty when true and the attribute is absent when false or unknown. Enum values are lowercase kebab-case.
|
|
@@ -141,6 +144,6 @@ Place global resets in `reset` and application overrides in `app`. Import order
|
|
|
141
144
|
- Typed parts, state attributes, manifest entries, geometry variables and cascade layers form the current Public Styles API.
|
|
142
145
|
- Renaming or removing a documented part, state attribute or variable changes the public contract.
|
|
143
146
|
- Adding a public part, state attribute or variable extends the public contract.
|
|
144
|
-
- `tokens:check` compares the current manifest with the latest reachable `
|
|
147
|
+
- `tokens:check` compares the current manifest with the latest reachable `ropav@*` release tag that contains one. Until the first package-specific release exists, it falls back to legacy `v*` tags and their pre-monorepo manifest path. Released variables cannot be removed, renamed or changed semantically; adding a variable requires incrementing the manifest's `contractVersion`.
|
|
145
148
|
- Release tags must be available in the Git checkout that runs the check. `PUBLIC_STYLES_BASELINE_REF` can explicitly select another Git ref that contains a manifest.
|
|
146
149
|
- Internal DOM, selectors and undocumented variables are outside the public contract.
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ropav",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"packageManager": "pnpm@11.17.0",
|
|
7
6
|
"engines": {
|
|
8
7
|
"node": "^20.19.0 || ^22.13.0 || >=24.0.0"
|
|
9
8
|
},
|
|
@@ -213,6 +212,10 @@
|
|
|
213
212
|
"types": "./dist/components/toast/index.d.ts",
|
|
214
213
|
"import": "./dist/components/toast/index.js"
|
|
215
214
|
},
|
|
215
|
+
"./toolbar": {
|
|
216
|
+
"types": "./dist/components/toolbar/index.d.ts",
|
|
217
|
+
"import": "./dist/components/toolbar/index.js"
|
|
218
|
+
},
|
|
216
219
|
"./tooltip": {
|
|
217
220
|
"types": "./dist/components/tooltip/index.d.ts",
|
|
218
221
|
"import": "./dist/components/tooltip/index.js"
|
|
@@ -226,36 +229,6 @@
|
|
|
226
229
|
"./styles-manifest.json": "./src/styles/styles-manifest.json",
|
|
227
230
|
"./scss/*.scss": "./src/styles/*.scss"
|
|
228
231
|
},
|
|
229
|
-
"scripts": {
|
|
230
|
-
"dev": "pnpm run storybook",
|
|
231
|
-
"publication:sync": "node scripts/sync-package-publication.mjs --write",
|
|
232
|
-
"publication:check": "node scripts/sync-package-publication.mjs --check",
|
|
233
|
-
"publication:verify": "node scripts/verify-package-publication.mjs",
|
|
234
|
-
"tokens:build": "style-dictionary build --config scripts/tokens.config.mjs --silent",
|
|
235
|
-
"tokens:check": "node scripts/check-tokens.mjs",
|
|
236
|
-
"typecheck": "vue-tsc -b tsconfig.app.json tsconfig.node.json tsconfig.test.json",
|
|
237
|
-
"typecheck:storybook": "vue-tsc -p tsconfig.storybook.json --noEmit",
|
|
238
|
-
"lint": "oxlint",
|
|
239
|
-
"lint:fix": "oxlint --fix",
|
|
240
|
-
"format": "oxfmt",
|
|
241
|
-
"format:check": "oxfmt --check",
|
|
242
|
-
"test": "vitest run --project=unit --project=tooling",
|
|
243
|
-
"test:consumer-types:built": "tsc -p tests/fixtures/consumer-types/tsconfig.bundler.json && tsc -p tests/fixtures/consumer-types/tsconfig.nodenext.json",
|
|
244
|
-
"test:bundle:built": "node scripts/check-package-bundle.mjs",
|
|
245
|
-
"test:consumer-fixture:built": "node tests/fixtures/consumer-app/check.mjs && vue-tsc -p tests/fixtures/consumer-app/tsconfig.json --noEmit && vite build --config tests/fixtures/consumer-app/vite.config.ts && node tests/fixtures/consumer-app/assertions.mjs",
|
|
246
|
-
"test:package": "pnpm run build && pnpm run publication:verify && pnpm run test:bundle:built && pnpm run test:consumer-types:built && pnpm run test:consumer-fixture:built",
|
|
247
|
-
"test:watch": "vitest --project=unit --project=tooling",
|
|
248
|
-
"test:typecheck": "vitest run --project=unit --project=tooling --typecheck",
|
|
249
|
-
"test:storybook": "vitest run --project=storybook-light --project=storybook-dark",
|
|
250
|
-
"build": "pnpm run publication:check && pnpm run tokens:build && pnpm run tokens:check && pnpm run typecheck && vite build",
|
|
251
|
-
"verify": "pnpm run lint && pnpm run format:check && pnpm run typecheck:storybook && pnpm run test && pnpm run test:storybook && pnpm run test:package",
|
|
252
|
-
"prepublishOnly": "pnpm run verify",
|
|
253
|
-
"preview": "vite preview",
|
|
254
|
-
"storybook": "pnpm run tokens:build && storybook dev -p 6006 --no-open",
|
|
255
|
-
"build-storybook": "pnpm run tokens:build && pnpm run tokens:check && pnpm run typecheck:storybook && storybook build",
|
|
256
|
-
"changelog": "conventional-changelog -p conventionalcommits -i CHANGELOG.md -o CHANGELOG.md",
|
|
257
|
-
"release": "pnpm run verify && bumpp --git-check --all --commit \"chore(release): v%s\" --tag \"v%s\" --execute \"pnpm run changelog\""
|
|
258
|
-
},
|
|
259
232
|
"peerDependencies": {
|
|
260
233
|
"@vue/compiler-vapor": "3.6.0-rc.2",
|
|
261
234
|
"unplugin-icons": "^23.0.1",
|
|
@@ -284,12 +257,7 @@
|
|
|
284
257
|
"@vitest/browser-playwright": "^4.1.10",
|
|
285
258
|
"@vue/compiler-vapor": "3.6.0-rc.2",
|
|
286
259
|
"@vue/tsconfig": "^0.9.1",
|
|
287
|
-
"bumpp": "^12.0.0",
|
|
288
|
-
"conventional-changelog": "^8.1.0",
|
|
289
|
-
"conventional-changelog-conventionalcommits": "^10.2.1",
|
|
290
260
|
"jsdom": "^29.1.1",
|
|
291
|
-
"oxfmt": "^0.60.0",
|
|
292
|
-
"oxlint": "^1.75.0",
|
|
293
261
|
"playwright": "^1.61.1",
|
|
294
262
|
"sass-embedded": "^1.100.0",
|
|
295
263
|
"storybook": "^10.5.3",
|
|
@@ -305,6 +273,30 @@
|
|
|
305
273
|
},
|
|
306
274
|
"repository": {
|
|
307
275
|
"type": "git",
|
|
308
|
-
"url": "https://github.com/daopk/ropav"
|
|
276
|
+
"url": "https://github.com/daopk/ropav",
|
|
277
|
+
"directory": "packages/ropav"
|
|
278
|
+
},
|
|
279
|
+
"scripts": {
|
|
280
|
+
"dev": "pnpm run storybook",
|
|
281
|
+
"publication:sync": "node scripts/sync-package-publication.mjs --write",
|
|
282
|
+
"publication:check": "node scripts/sync-package-publication.mjs --check",
|
|
283
|
+
"publication:verify": "node scripts/verify-package-publication.mjs",
|
|
284
|
+
"tokens:build": "style-dictionary build --config scripts/tokens.config.mjs --silent",
|
|
285
|
+
"tokens:check": "node scripts/check-tokens.mjs",
|
|
286
|
+
"typecheck": "vue-tsc -b tsconfig.app.json tsconfig.node.json tsconfig.test.json",
|
|
287
|
+
"typecheck:storybook": "vue-tsc -p tsconfig.storybook.json --noEmit",
|
|
288
|
+
"test": "vitest run --project=unit --project=tooling",
|
|
289
|
+
"test:consumer-types:built": "tsc -p tests/fixtures/consumer-types/tsconfig.bundler.json && tsc -p tests/fixtures/consumer-types/tsconfig.nodenext.json",
|
|
290
|
+
"test:bundle:built": "node scripts/check-package-bundle.mjs",
|
|
291
|
+
"test:consumer-fixture:built": "node tests/fixtures/consumer-app/check.mjs && vue-tsc -p tests/fixtures/consumer-app/tsconfig.json --noEmit && vite build --config tests/fixtures/consumer-app/vite.config.ts && node tests/fixtures/consumer-app/assertions.mjs",
|
|
292
|
+
"test:package": "pnpm run build && pnpm run publication:verify && pnpm run test:bundle:built && pnpm run test:consumer-types:built && pnpm run test:consumer-fixture:built",
|
|
293
|
+
"test:watch": "vitest --project=unit --project=tooling",
|
|
294
|
+
"test:typecheck": "vitest run --project=unit --project=tooling --typecheck",
|
|
295
|
+
"test:storybook": "vitest run --project=storybook-light --project=storybook-dark",
|
|
296
|
+
"build": "pnpm run publication:check && pnpm run tokens:check && pnpm run typecheck && vite build",
|
|
297
|
+
"verify": "pnpm run typecheck:storybook && pnpm run test && pnpm run test:storybook && pnpm run test:package",
|
|
298
|
+
"preview": "vite preview",
|
|
299
|
+
"storybook": "pnpm run tokens:check && storybook dev -p 6006 --no-open",
|
|
300
|
+
"build-storybook": "pnpm run tokens:check && pnpm run typecheck:storybook && storybook build"
|
|
309
301
|
}
|
|
310
|
-
}
|
|
302
|
+
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
# Code architecture
|
|
2
|
-
|
|
3
|
-
This guide defines the source structure expected from contributors. The goal is a predictable
|
|
4
|
-
codebase where UI files describe rendering, behavior is testable through small interfaces, and
|
|
5
|
-
shared logic has one obvious home.
|
|
6
|
-
|
|
7
|
-
## Module seams
|
|
8
|
-
|
|
9
|
-
A module should hide a meaningful amount of behavior behind a small interface. Extract code around
|
|
10
|
-
a responsibility, not merely to reduce a line count. A useful extraction makes callers simpler and
|
|
11
|
-
lets tests exercise the same interface that production code uses.
|
|
12
|
-
|
|
13
|
-
Use this dependency direction:
|
|
14
|
-
|
|
15
|
-
```text
|
|
16
|
-
Vue components and component-local modules
|
|
17
|
-
-> internal composables
|
|
18
|
-
-> public composables
|
|
19
|
-
-> utilities
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
A higher layer may also import a lower layer directly. Lower layers must not import higher layers:
|
|
23
|
-
|
|
24
|
-
- `src/utils/` does not import components or composables.
|
|
25
|
-
- `src/composables/` does not import components or internal modules.
|
|
26
|
-
- `src/internal/` does not import components.
|
|
27
|
-
- Components may compose other components when the dependency remains acyclic.
|
|
28
|
-
|
|
29
|
-
## Where code belongs
|
|
30
|
-
|
|
31
|
-
| Location | Responsibility |
|
|
32
|
-
| ----------------------------------------- | --------------------------------------------------------------------- |
|
|
33
|
-
| `src/components/<name>/*.vue` | Template, bindings, slots, and lightweight view-derived state |
|
|
34
|
-
| `src/components/<name>/useX.ts` | Component-specific reactive state, lifecycle, and event orchestration |
|
|
35
|
-
| `src/components/<name>/<concern>Model.ts` | Pure behavior that encodes only that component's contract |
|
|
36
|
-
| `src/internal/composables/` | Shared reactive behavior that is not part of the package interface |
|
|
37
|
-
| `src/composables/` | Reusable public composables exported by the package |
|
|
38
|
-
| `src/utils/` | Reusable runtime helpers without component state or lifecycle |
|
|
39
|
-
| `src/utils/dom/` | Reusable helpers that operate on browser and DOM primitives |
|
|
40
|
-
| `tests/`, `tooling/`, `scripts/` | Test, build, and repository automation helpers |
|
|
41
|
-
|
|
42
|
-
Do not add catch-all `utils`, `helpers`, or `core` modules beside a component. Keep a pure helper
|
|
43
|
-
local when it expresses one component's contract, and give it a semantic name such as
|
|
44
|
-
`sliderModel`. Move it to `src/utils/` once more than one feature needs the behavior.
|
|
45
|
-
|
|
46
|
-
## Component shape
|
|
47
|
-
|
|
48
|
-
Production SFCs use `<script setup lang="ts" vapor>` and remain zero-VDOM. Do not use `h`, `VNode`,
|
|
49
|
-
`defineComponent`, `createVNode`, or related VDOM block helpers in production source.
|
|
50
|
-
|
|
51
|
-
Keep SFC blocks in this order:
|
|
52
|
-
|
|
53
|
-
1. `<template>`
|
|
54
|
-
2. `<script setup lang="ts" vapor>`
|
|
55
|
-
3. `<style>`
|
|
56
|
-
|
|
57
|
-
Within the script block, use this order:
|
|
58
|
-
|
|
59
|
-
1. Imports
|
|
60
|
-
2. `defineOptions`, props defaults, emits, and slots
|
|
61
|
-
3. Composable state and template refs
|
|
62
|
-
4. View-derived computed attributes
|
|
63
|
-
5. Small event adapters and `defineExpose`
|
|
64
|
-
|
|
65
|
-
A short computed value used only to bind the template can stay in the SFC. Move state transitions,
|
|
66
|
-
timers, document listeners, multi-step event handling, and reusable calculations behind a
|
|
67
|
-
composable or pure model interface.
|
|
68
|
-
|
|
69
|
-
## Function design
|
|
70
|
-
|
|
71
|
-
Oxlint enforces a conservative baseline of cyclomatic complexity 20, nesting depth 4, at most 5
|
|
72
|
-
parameters, and at most 250 non-blank, non-comment lines per function. These are upper bounds, not
|
|
73
|
-
targets.
|
|
74
|
-
|
|
75
|
-
- Give each function one reason to change.
|
|
76
|
-
- Prefer guard clauses over deeply nested branches.
|
|
77
|
-
- Use an options object when several parameters describe one concept.
|
|
78
|
-
- Split orchestration into named steps, while keeping the external interface small.
|
|
79
|
-
- Accept dependencies or callbacks at the module seam instead of constructing hard-to-test global
|
|
80
|
-
dependencies inside the implementation.
|
|
81
|
-
- Return observable results where practical; isolate side effects in lifecycle or event adapters.
|
|
82
|
-
|
|
83
|
-
Do not create shallow pass-through functions solely to satisfy a metric. A refactor should improve
|
|
84
|
-
the caller, the module interface, or the test surface.
|
|
85
|
-
|
|
86
|
-
## Imports and package interfaces
|
|
87
|
-
|
|
88
|
-
- Import utilities directly from their module, for example `@/utils/number`; do not add a utils
|
|
89
|
-
barrel.
|
|
90
|
-
- Component `index.ts` files define package-facing exports. Internal code should not import from the
|
|
91
|
-
root package barrel.
|
|
92
|
-
- Keep imports acyclic. If two modules need each other, move the shared behavior to the lowest
|
|
93
|
-
layer that owns the concept.
|
|
94
|
-
- Use `import type` for type-only dependencies.
|
|
95
|
-
|
|
96
|
-
## Testing
|
|
97
|
-
|
|
98
|
-
Test through the interface of the extracted module:
|
|
99
|
-
|
|
100
|
-
- Pure models and utilities use deterministic unit tests.
|
|
101
|
-
- Composables test returned state and commands, using the smallest host needed for lifecycle
|
|
102
|
-
behavior.
|
|
103
|
-
- Component tests cover DOM integration, events, accessibility, and public rendering contracts.
|
|
104
|
-
- Storybook tests cover visual and interaction scenarios that depend on real browser layout.
|
|
105
|
-
|
|
106
|
-
Tests should assert observable behavior rather than private implementation details. Refactoring a
|
|
107
|
-
module internally should not require rewriting its behavioral tests.
|
|
108
|
-
|
|
109
|
-
## Contributor checklist
|
|
110
|
-
|
|
111
|
-
Before opening a pull request:
|
|
112
|
-
|
|
113
|
-
- The SFC primarily adapts props, slots, and composable results to the template.
|
|
114
|
-
- New reusable helpers live in `src/utils/`; feature-only pure logic has a semantic local name.
|
|
115
|
-
- Dependency direction remains downward and acyclic.
|
|
116
|
-
- Functions stay below the enforced complexity, depth, length, and parameter limits.
|
|
117
|
-
- New behavior is tested at the module interface.
|
|
118
|
-
- `pnpm run verify` passes.
|