origam 2.17.0 → 2.18.0
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/CHANGELOG.md +744 -1
- package/dist/src/assets/css/main.css +1 -1
- package/dist/src/assets/css/tokens/dark.css +125 -24
- package/dist/src/assets/css/tokens/light.css +49 -12
- package/dist/src/assets/locales/en.json +21 -6
- package/dist/src/assets/locales/fr.json +21 -6
- package/dist/src/assets/scss/main.scss +10 -2
- package/dist/src/assets/scss/tokens/_dark.scss +2846 -12
- package/dist/src/assets/scss/tokens/_light.scss +49 -12
- package/dist/src/components/Alert/OrigamAlert.vue +6 -6
- package/dist/src/components/Avatar/OrigamAvatar.vue +15 -2
- package/dist/src/components/Badge/OrigamBadge.vue +7 -7
- package/dist/src/components/Breadcrumb/OrigamBreadcrumbItem.vue +23 -4
- package/dist/src/components/Btn/OrigamBtn.vue +21 -3
- package/dist/src/components/Btn/OrigamBtnGroup.vue +1 -1
- package/dist/src/components/Calendar/OrigamCalendar.vue +1 -1
- package/dist/src/components/Card/OrigamCard.vue +2 -0
- package/dist/src/components/Card/OrigamCardHeader.vue +7 -7
- package/dist/src/components/Carousel/OrigamCarousel.vue +14 -1
- package/dist/src/components/Chart/OrigamChartBoxPlot.vue +1 -1
- package/dist/src/components/Chart/OrigamChartBullet.vue +3 -2
- package/dist/src/components/Chart/OrigamChartCandlestick.vue +2 -2
- package/dist/src/components/Chart/OrigamChartCartesian.vue +49 -4
- package/dist/src/components/Chart/OrigamChartLegend.vue +39 -18
- package/dist/src/components/Chart/OrigamChartPareto.vue +7 -1
- package/dist/src/components/Chart/OrigamChartPictorial.vue +2 -2
- package/dist/src/components/Chart/OrigamChartRadar.vue +3 -1
- package/dist/src/components/Chart/OrigamChartSparkline.vue +3 -1
- package/dist/src/components/Chart/OrigamChartStreamgraph.vue +2 -1
- package/dist/src/components/Checkbox/OrigamCheckbox.vue +2 -0
- package/dist/src/components/Checkbox/OrigamCheckboxGroup.vue +36 -11
- package/dist/src/components/Chip/OrigamChip.vue +19 -4
- package/dist/src/components/Code/OrigamCode.vue +20 -3
- package/dist/src/components/ColorPickerField/OrigamColorPickerField.vue +43 -18
- package/dist/src/components/CommandPalette/OrigamCommandPalette.vue +3 -3
- package/dist/src/components/ConfirmWrapper/OrigamConfirmWrapper.vue +6 -6
- package/dist/src/components/ContextualMenu/OrigamContextualMenu.vue +0 -4
- package/dist/src/components/DataList/OrigamDataList.vue +2 -0
- package/dist/src/components/DataList/OrigamDataText.vue +6 -6
- package/dist/src/components/DataList/OrigamDataTitle.vue +6 -6
- package/dist/src/components/DataTable/OrigamDataTableHeaderCell.vue +1 -1
- package/dist/src/components/DataTable/OrigamDataTableHeadersCell.vue +4 -1
- package/dist/src/components/DatePicker/OrigamDatePicker.vue +2 -0
- package/dist/src/components/DatePicker/OrigamDatePickerHeader.vue +6 -6
- package/dist/src/components/DatePickerField/OrigamDatePickerField.vue +34 -14
- package/dist/src/components/Dialog/OrigamDialog.vue +25 -0
- package/dist/src/components/Dialog/OrigamDialogConfirmation.vue +6 -0
- package/dist/src/components/ExpansionPanel/OrigamExpansionPanel.vue +2 -0
- package/dist/src/components/ExpansionPanel/OrigamExpansionPanelHeader.vue +6 -6
- package/dist/src/components/Field/OrigamField.vue +83 -28
- package/dist/src/components/FileField/OrigamFileField.vue +20 -15
- package/dist/src/components/Icon/OrigamSvgIcon.vue +3 -1
- package/dist/src/components/Img/OrigamImg.vue +9 -2
- package/dist/src/components/InfiniteScroll/OrigamInfiniteScroll.vue +34 -18
- package/dist/src/components/InlineEdit/OrigamInlineEdit.vue +46 -5
- package/dist/src/components/Input/OrigamInput.vue +6 -6
- package/dist/src/components/List/OrigamListGroup.vue +4 -0
- package/dist/src/components/List/OrigamListItem.vue +68 -4
- package/dist/src/components/Masonry/OrigamMasonry.vue +19 -3
- package/dist/src/components/Menu/OrigamMenu.vue +79 -9
- package/dist/src/components/NumberField/OrigamNumberField.vue +26 -16
- package/dist/src/components/OtpInputField/OrigamOtpInputField.vue +48 -24
- package/dist/src/components/PasswordField/OrigamPasswordField.vue +20 -15
- package/dist/src/components/Radio/OrigamRadio.vue +2 -0
- package/dist/src/components/Radio/OrigamRadioGroup.vue +36 -11
- package/dist/src/components/RatingField/OrigamRatingField.vue +58 -7
- package/dist/src/components/RatingField/OrigamRatingFieldItem.vue +78 -30
- package/dist/src/components/Select/OrigamSelect.vue +57 -34
- package/dist/src/components/SliderField/OrigamSliderField.vue +20 -10
- package/dist/src/components/Snackbar/OrigamSnackbarGroup.vue +1 -1
- package/dist/src/components/Switch/OrigamSwitch.vue +2 -0
- package/dist/src/components/Switch/OrigamSwitchTrack.vue +20 -0
- package/dist/src/components/Tabs/OrigamTab.vue +7 -4
- package/dist/src/components/Tabs/OrigamTabPanel.vue +4 -2
- package/dist/src/components/Tabs/OrigamTabs.vue +7 -5
- package/dist/src/components/TextField/OrigamTextField.vue +20 -15
- package/dist/src/components/TextareaField/OrigamTextareaField.vue +20 -15
- package/dist/src/components/Transition/OrigamExpandX.vue +19 -3
- package/dist/src/components/Transition/OrigamExpandY.vue +19 -3
- package/dist/src/components/Transition/OrigamTranslateScale.vue +26 -4
- package/dist/src/components/Video/OrigamVideo.vue +3 -2
- package/dist/src/components/VirtualScroll/OrigamVirtualScroll.vue +1 -1
- package/dist/src/components/Window/OrigamWindow.vue +20 -3
- package/dist/src/composables/Commons/accessibleCommand.composable.cjs +26 -0
- package/dist/src/composables/Commons/accessibleCommand.composable.d.ts +78 -0
- package/dist/src/composables/Commons/accessibleCommand.composable.js +20 -0
- package/dist/src/composables/Commons/activator.composable.cjs +10 -1
- package/dist/src/composables/Commons/activator.composable.js +11 -2
- package/dist/src/composables/Commons/adjacent.composable.cjs +17 -0
- package/dist/src/composables/Commons/adjacent.composable.d.ts +12 -0
- package/dist/src/composables/Commons/adjacent.composable.js +17 -0
- package/dist/src/composables/Commons/adjacentInner.composable.cjs +20 -0
- package/dist/src/composables/Commons/adjacentInner.composable.d.ts +24 -5
- package/dist/src/composables/Commons/adjacentInner.composable.js +20 -0
- package/dist/src/composables/Commons/audio.composable.cjs +14 -1
- package/dist/src/composables/Commons/audio.composable.js +14 -1
- package/dist/src/composables/Commons/backButton.composable.cjs +3 -1
- package/dist/src/composables/Commons/backButton.composable.js +3 -1
- package/dist/src/composables/Commons/border.composable.d.ts +13 -0
- package/dist/src/composables/Commons/colorEffect.composable.cjs +58 -46
- package/dist/src/composables/Commons/colorEffect.composable.d.ts +10 -5
- package/dist/src/composables/Commons/colorEffect.composable.js +70 -46
- package/dist/src/composables/Commons/createLayout.composable.cjs +21 -12
- package/dist/src/composables/Commons/createLayout.composable.js +21 -12
- package/dist/src/composables/Commons/delay.composable.d.ts +16 -0
- package/dist/src/composables/Commons/dimension.composable.d.ts +11 -0
- package/dist/src/composables/Commons/elevation.composable.cjs +6 -2
- package/dist/src/composables/Commons/elevation.composable.d.ts +37 -1
- package/dist/src/composables/Commons/elevation.composable.js +7 -2
- package/dist/src/composables/Commons/goTo.composable.cjs +4 -2
- package/dist/src/composables/Commons/goTo.composable.js +5 -3
- package/dist/src/composables/Commons/group.composable.cjs +14 -14
- package/dist/src/composables/Commons/group.composable.js +14 -14
- package/dist/src/composables/Commons/hotkey.composable.d.ts +18 -7
- package/dist/src/composables/Commons/hydration.composable.d.ts +8 -0
- package/dist/src/composables/Commons/link.composable.d.ts +20 -0
- package/dist/src/composables/Commons/locationStrategies.composable.d.ts +17 -0
- package/dist/src/composables/Commons/message.composable.d.ts +19 -5
- package/dist/src/composables/Commons/position.composable.d.ts +17 -6
- package/dist/src/composables/Commons/refs.composable.d.ts +11 -5
- package/dist/src/composables/Commons/rounded.composable.d.ts +11 -1
- package/dist/src/composables/Commons/scrolling.composable.cjs +15 -12
- package/dist/src/composables/Commons/scrolling.composable.js +15 -12
- package/dist/src/composables/Commons/size.composable.d.ts +15 -0
- package/dist/src/composables/Commons/ssrBoot.composable.cjs +9 -1
- package/dist/src/composables/Commons/ssrBoot.composable.js +10 -2
- package/dist/src/composables/Commons/stack.composable.cjs +13 -1
- package/dist/src/composables/Commons/stack.composable.js +13 -1
- package/dist/src/composables/Commons/theme-props-resolver.composable.cjs +41 -32
- package/dist/src/composables/Commons/theme-props-resolver.composable.js +41 -32
- package/dist/src/composables/Commons/validation.composable.cjs +3 -3
- package/dist/src/composables/Commons/validation.composable.js +3 -3
- package/dist/src/composables/Commons/virtual.composable.cjs +24 -8
- package/dist/src/composables/Commons/virtual.composable.js +24 -8
- package/dist/src/composables/Masonry/masonry.composable.cjs +18 -11
- package/dist/src/composables/Masonry/masonry.composable.js +18 -11
- package/dist/src/composables/Parallax/parallax.composable.cjs +1 -1
- package/dist/src/composables/Parallax/parallax.composable.js +1 -1
- package/dist/src/composables/index.cjs +36 -0
- package/dist/src/composables/index.d.ts +3 -0
- package/dist/src/composables/index.js +3 -0
- package/dist/src/consts/Chart/chart-cartesian.const.cjs +5 -2
- package/dist/src/consts/Chart/chart-cartesian.const.d.ts +42 -0
- package/dist/src/consts/Chart/chart-cartesian.const.js +3 -0
- package/dist/src/consts/Commons/border.const.cjs +2 -1
- package/dist/src/consts/Commons/border.const.d.ts +19 -0
- package/dist/src/consts/Commons/border.const.js +15 -0
- package/dist/src/consts/Commons/elevation.const.cjs +5 -1
- package/dist/src/consts/Commons/elevation.const.d.ts +52 -2
- package/dist/src/consts/Commons/elevation.const.js +4 -0
- package/dist/src/consts/Commons/ripple.const.cjs +13 -3
- package/dist/src/consts/Commons/ripple.const.js +13 -3
- package/dist/src/consts/RatingField/rating-field.const.cjs +10 -0
- package/dist/src/consts/RatingField/rating-field.const.d.ts +36 -0
- package/dist/src/consts/RatingField/rating-field.const.js +12 -0
- package/dist/src/consts/index.cjs +11 -0
- package/dist/src/consts/index.d.ts +1 -0
- package/dist/src/consts/index.js +1 -0
- package/dist/src/directives/ClickOutside/clickOutside.directive.cjs +2 -0
- package/dist/src/directives/ClickOutside/clickOutside.directive.js +2 -0
- package/dist/src/directives/Ripple/ripple.directive.cjs +2 -0
- package/dist/src/directives/Ripple/ripple.directive.js +2 -0
- package/dist/src/enums/Commons/color.enum.cjs +0 -1
- package/dist/src/enums/Commons/color.enum.d.ts +14 -5
- package/dist/src/enums/Commons/color.enum.js +0 -1
- package/dist/src/enums/Sheet/sheet.enum.d.ts +1 -1
- package/dist/src/interfaces/Chart/chart-cartesian.interface.d.ts +6 -2
- package/dist/src/interfaces/Commons/activator.interface.d.ts +3 -2
- package/dist/src/interfaces/Commons/adjacent.interface.d.ts +29 -0
- package/dist/src/interfaces/Commons/group.interface.d.ts +13 -2
- package/dist/src/interfaces/Commons/ripple.interface.d.ts +16 -0
- package/dist/src/interfaces/Commons/scroll.interface.d.ts +3 -2
- package/dist/src/interfaces/DataTable/data-table-header.interface.d.ts +2 -2
- package/dist/src/interfaces/DatePicker/date-picker-month.interface.d.ts +2 -1
- package/dist/src/interfaces/Field/field.interface.d.ts +21 -1
- package/dist/src/interfaces/Menu/menu.interface.d.ts +28 -1
- package/dist/src/interfaces/OtpInputField/otp-input-field.interface.d.ts +21 -1
- package/dist/src/interfaces/RatingField/rating-field-item.interface.d.ts +16 -1
- package/dist/src/interfaces/index.cjs +11 -0
- package/dist/src/interfaces/index.d.ts +1 -0
- package/dist/src/interfaces/index.js +1 -0
- package/dist/src/themes/origam.theme.cjs +8 -14
- package/dist/src/themes/origam.theme.js +6 -8
- package/dist/src/types/Commons/color.type.d.ts +4 -3
- package/dist/src/types/Commons/commons.type.d.ts +33 -0
- package/dist/src/types/Commons/theme.type.d.ts +2 -1
- package/dist/src/types/Sheet/sheet.type.d.ts +2 -1
- package/dist/src/types/index.cjs +22 -0
- package/dist/src/types/index.d.ts +2 -0
- package/dist/src/types/index.js +2 -0
- package/dist/src/types/tokens.type.d.ts +1 -1
- package/dist/src/utils/Commons/a11y.util.cjs +35 -0
- package/dist/src/utils/Commons/a11y.util.d.ts +63 -0
- package/dist/src/utils/Commons/a11y.util.js +33 -0
- package/dist/src/utils/Commons/clickOutside.util.cjs +5 -1
- package/dist/src/utils/Commons/clickOutside.util.js +5 -1
- package/dist/src/utils/Commons/color.util.cjs +10 -5
- package/dist/src/utils/Commons/color.util.d.ts +34 -5
- package/dist/src/utils/Commons/color.util.js +9 -5
- package/dist/src/utils/Commons/goTo.util.cjs +31 -14
- package/dist/src/utils/Commons/goTo.util.d.ts +1 -1
- package/dist/src/utils/Commons/goTo.util.js +31 -16
- package/dist/src/utils/Commons/location.util.cjs +18 -3
- package/dist/src/utils/Commons/location.util.js +18 -3
- package/dist/src/utils/Commons/ripple.util.cjs +5 -1
- package/dist/src/utils/Commons/ripple.util.js +5 -1
- package/dist/src/utils/index.cjs +11 -0
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.js +1 -0
- package/package.json +13 -2
- package/dist/src/types/Commons/locale.type.cjs +0 -1
- package/dist/src/types/Commons/locale.type.d.ts +0 -0
- package/dist/src/types/Commons/locale.type.js +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
+
:id="styleId"
|
|
3
4
|
:aria-label="label || undefined"
|
|
4
5
|
:class="otpInputFieldClasses"
|
|
5
6
|
:style="otpInputFieldStyles"
|
|
@@ -148,7 +149,7 @@
|
|
|
148
149
|
</template>
|
|
149
150
|
|
|
150
151
|
<script lang="ts" setup>
|
|
151
|
-
import { computed, nextTick, ref, StyleValue, useAttrs, useSlots, watch } from "vue";
|
|
152
|
+
import { computed, nextTick, onBeforeUnmount, ref, StyleValue, useAttrs, useSlots, watch } from "vue";
|
|
152
153
|
import OrigamField from "../Field/OrigamField.vue";
|
|
153
154
|
import OrigamOverlay from "../Overlay/OrigamOverlay.vue";
|
|
154
155
|
import OrigamProgress from "../Progress/OrigamProgress.vue";
|
|
@@ -201,6 +202,21 @@ const props = defineProps({
|
|
|
201
202
|
prependInnerIcon: { type: null, required: false },
|
|
202
203
|
clearIcon: { type: null, required: false },
|
|
203
204
|
clearable: { type: Boolean, required: false },
|
|
205
|
+
prependInnerAriaLabel: { type: String, required: false },
|
|
206
|
+
appendInnerAriaLabel: { type: String, required: false },
|
|
207
|
+
border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true },
|
|
208
|
+
borderTop: { type: [Boolean, Number, String], required: false },
|
|
209
|
+
borderLeft: { type: [Boolean, Number, String], required: false },
|
|
210
|
+
borderBottom: { type: [Boolean, Number, String], required: false },
|
|
211
|
+
borderRight: { type: [Boolean, Number, String], required: false },
|
|
212
|
+
borderBlock: { type: [Boolean, Number, String], required: false },
|
|
213
|
+
borderInline: { type: [Boolean, Number, String], required: false },
|
|
214
|
+
borderColor: { type: String, required: false },
|
|
215
|
+
borderStyle: { type: String, required: false },
|
|
216
|
+
borderTopColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
217
|
+
borderRightColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
218
|
+
borderBottomColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
219
|
+
borderLeftColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
204
220
|
focused: { type: Boolean, required: false },
|
|
205
221
|
density: { type: null, required: false },
|
|
206
222
|
text: { type: String, required: false },
|
|
@@ -220,19 +236,6 @@ const props = defineProps({
|
|
|
220
236
|
paddingRight: { type: [Boolean, Number, String], required: false },
|
|
221
237
|
paddingBlock: { type: [Boolean, Number, String], required: false },
|
|
222
238
|
paddingInline: { type: [Boolean, Number, String], required: false },
|
|
223
|
-
border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true },
|
|
224
|
-
borderTop: { type: [Boolean, Number, String], required: false },
|
|
225
|
-
borderLeft: { type: [Boolean, Number, String], required: false },
|
|
226
|
-
borderBottom: { type: [Boolean, Number, String], required: false },
|
|
227
|
-
borderRight: { type: [Boolean, Number, String], required: false },
|
|
228
|
-
borderBlock: { type: [Boolean, Number, String], required: false },
|
|
229
|
-
borderInline: { type: [Boolean, Number, String], required: false },
|
|
230
|
-
borderColor: { type: String, required: false },
|
|
231
|
-
borderStyle: { type: String, required: false },
|
|
232
|
-
borderTopColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
233
|
-
borderRightColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
234
|
-
borderBottomColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
235
|
-
borderLeftColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
236
239
|
rounded: { type: [Boolean, Number, String, null], required: false, skipCheck: true },
|
|
237
240
|
roundedTopRight: { type: [Boolean, Number, String], required: false },
|
|
238
241
|
roundedTopLeft: { type: [Boolean, Number, String], required: false },
|
|
@@ -261,14 +264,26 @@ const props = defineProps({
|
|
|
261
264
|
readonly: { type: Boolean, required: false },
|
|
262
265
|
rules: { type: Array, required: false },
|
|
263
266
|
validateOn: { type: null, required: false },
|
|
264
|
-
validationValue: { type: null, required: false }
|
|
265
|
-
appendAvatar: { type: String, required: false },
|
|
266
|
-
appendIcon: { type: null, required: false },
|
|
267
|
-
prependAvatar: { type: String, required: false },
|
|
268
|
-
prependIcon: { type: null, required: false }
|
|
267
|
+
validationValue: { type: null, required: false }
|
|
269
268
|
});
|
|
270
269
|
const emits = defineEmits(["finish", "click:control", "mousedown:control", "update:modelValue", "update:focused", "click:appendInner", "click:prependInner", "click:clear"]);
|
|
271
270
|
defineSlots();
|
|
271
|
+
let disposed = false;
|
|
272
|
+
const frames = /* @__PURE__ */ new Set();
|
|
273
|
+
const scheduleFrame = (cb) => {
|
|
274
|
+
if (disposed) return;
|
|
275
|
+
const id2 = requestAnimationFrame(() => {
|
|
276
|
+
frames.delete(id2);
|
|
277
|
+
if (disposed) return;
|
|
278
|
+
cb();
|
|
279
|
+
});
|
|
280
|
+
frames.add(id2);
|
|
281
|
+
};
|
|
282
|
+
onBeforeUnmount(() => {
|
|
283
|
+
disposed = true;
|
|
284
|
+
for (const id2 of frames) cancelAnimationFrame(id2);
|
|
285
|
+
frames.clear();
|
|
286
|
+
});
|
|
272
287
|
const { filterProps } = useProps(props);
|
|
273
288
|
const { t } = useLocale();
|
|
274
289
|
const attrs = useAttrs();
|
|
@@ -376,12 +391,12 @@ const handleKeydown = (e) => {
|
|
|
376
391
|
if (focusIndex.value > 0 && e.key === "Backspace") {
|
|
377
392
|
target = "prev";
|
|
378
393
|
} else {
|
|
379
|
-
|
|
394
|
+
scheduleFrame(() => {
|
|
380
395
|
inputRef.value[index]?.select();
|
|
381
396
|
});
|
|
382
397
|
}
|
|
383
398
|
}
|
|
384
|
-
|
|
399
|
+
scheduleFrame(() => {
|
|
385
400
|
if (target != null) {
|
|
386
401
|
focusChild(contentRef.value, target);
|
|
387
402
|
}
|
|
@@ -454,7 +469,7 @@ const otpInputFieldClasses = computed(() => {
|
|
|
454
469
|
props.class
|
|
455
470
|
];
|
|
456
471
|
});
|
|
457
|
-
const { id: styleId, css, load, isLoaded, unload } = useStyle(otpInputFieldStyles);
|
|
472
|
+
const { id: styleId, css, load, isLoaded, unload } = useStyle(otpInputFieldStyles, () => props.id);
|
|
458
473
|
defineExpose(forwardRefs({
|
|
459
474
|
blur: () => {
|
|
460
475
|
inputRef.value?.forEach((input) => input.blur());
|
|
@@ -493,8 +508,17 @@ defineExpose(forwardRefs({
|
|
|
493
508
|
|
|
494
509
|
.origam-field {
|
|
495
510
|
height: 100%;
|
|
496
|
-
|
|
497
|
-
|
|
511
|
+
// ⛔ #800 — une cellule OTP n'a ni etiquette ni texte aligne au bord :
|
|
512
|
+
// son chiffre est CENTRE. Le plancher de degagement des coins d'
|
|
513
|
+
// `OrigamField` n'y protege de rien et decentre le chiffre de 2px
|
|
514
|
+
// (mesure Chromium : `padding-inline` 4px / 0px). On le neutralise
|
|
515
|
+
// explicitement. Jusqu'a #800 le meme rendu etait obtenu par un `0`
|
|
516
|
+
// SANS UNITE qui rendait la declaration invalide — le bon rendu
|
|
517
|
+
// reposait donc sur une erreur de parse, et serait tombe au premier
|
|
518
|
+
// refactor du `max()`.
|
|
519
|
+
--origam-field---corner-clearance: 0px;
|
|
520
|
+
--origam-field---padding-start: 0px;
|
|
521
|
+
--origam-field---padding-end: 0px;
|
|
498
522
|
}
|
|
499
523
|
|
|
500
524
|
&__divider {
|
|
@@ -318,6 +318,7 @@ import { useLocale } from "../../composables/Commons/locale.composable";
|
|
|
318
318
|
import { useProps } from "../../composables/Commons/props.composable";
|
|
319
319
|
import { useStyle } from "../../composables/Commons/style.composable";
|
|
320
320
|
import { useVModel } from "../../composables/Commons/vModel.composable";
|
|
321
|
+
import { BORDER_PROP_KEYS } from "../../consts/Commons/border.const";
|
|
321
322
|
import { DEFAULT_PASSWORD_REQUIREMENTS, REQUIREMENT_MIN_LENGTH, REQUIREMENT_NUMBER, REQUIREMENT_SPECIAL, REQUIREMENT_TINY, REQUIREMENT_UPPERCASE } from "../../consts/PasswordField/password-field.const";
|
|
322
323
|
import vIntersect from "../../directives/Intersect/intersect.directive";
|
|
323
324
|
import { DENSITY } from "../../enums/Commons/density.enum";
|
|
@@ -388,6 +389,21 @@ const props = defineProps({
|
|
|
388
389
|
prependInnerIcon: { type: null, required: false },
|
|
389
390
|
clearIcon: { type: null, required: false },
|
|
390
391
|
clearable: { type: Boolean, required: false },
|
|
392
|
+
prependInnerAriaLabel: { type: String, required: false },
|
|
393
|
+
appendInnerAriaLabel: { type: String, required: false },
|
|
394
|
+
border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true },
|
|
395
|
+
borderTop: { type: [Boolean, Number, String], required: false },
|
|
396
|
+
borderLeft: { type: [Boolean, Number, String], required: false },
|
|
397
|
+
borderBottom: { type: [Boolean, Number, String], required: false },
|
|
398
|
+
borderRight: { type: [Boolean, Number, String], required: false },
|
|
399
|
+
borderBlock: { type: [Boolean, Number, String], required: false },
|
|
400
|
+
borderInline: { type: [Boolean, Number, String], required: false },
|
|
401
|
+
borderColor: { type: String, required: false },
|
|
402
|
+
borderStyle: { type: String, required: false },
|
|
403
|
+
borderTopColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
404
|
+
borderRightColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
405
|
+
borderBottomColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
406
|
+
borderLeftColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
391
407
|
focused: { type: Boolean, required: false },
|
|
392
408
|
text: { type: String, required: false },
|
|
393
409
|
floating: { type: Boolean, required: false },
|
|
@@ -406,19 +422,6 @@ const props = defineProps({
|
|
|
406
422
|
paddingRight: { type: [Boolean, Number, String], required: false },
|
|
407
423
|
paddingBlock: { type: [Boolean, Number, String], required: false },
|
|
408
424
|
paddingInline: { type: [Boolean, Number, String], required: false },
|
|
409
|
-
border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true },
|
|
410
|
-
borderTop: { type: [Boolean, Number, String], required: false },
|
|
411
|
-
borderLeft: { type: [Boolean, Number, String], required: false },
|
|
412
|
-
borderBottom: { type: [Boolean, Number, String], required: false },
|
|
413
|
-
borderRight: { type: [Boolean, Number, String], required: false },
|
|
414
|
-
borderBlock: { type: [Boolean, Number, String], required: false },
|
|
415
|
-
borderInline: { type: [Boolean, Number, String], required: false },
|
|
416
|
-
borderColor: { type: String, required: false },
|
|
417
|
-
borderStyle: { type: String, required: false },
|
|
418
|
-
borderTopColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
419
|
-
borderRightColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
420
|
-
borderBottomColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
421
|
-
borderLeftColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
|
|
422
425
|
rounded: { type: [Boolean, Number, String, null], required: false, skipCheck: true, default: true },
|
|
423
426
|
roundedTopRight: { type: [Boolean, Number, String], required: false },
|
|
424
427
|
roundedTopLeft: { type: [Boolean, Number, String], required: false },
|
|
@@ -455,7 +458,9 @@ const props = defineProps({
|
|
|
455
458
|
appendAvatar: { type: String, required: false },
|
|
456
459
|
appendIcon: { type: null, required: false },
|
|
457
460
|
prependAvatar: { type: String, required: false },
|
|
458
|
-
prependIcon: { type: null, required: false }
|
|
461
|
+
prependIcon: { type: null, required: false },
|
|
462
|
+
prependAriaLabel: { type: String, required: false },
|
|
463
|
+
appendAriaLabel: { type: String, required: false }
|
|
459
464
|
});
|
|
460
465
|
const emits = defineEmits(["click:control", "mousedown:control", "update:strength", "update:focused", "click:appendInner", "click:prependInner", "click:clear", "update:modelValue", "click:append", "click:prepend"]);
|
|
461
466
|
defineSlots();
|
|
@@ -615,7 +620,7 @@ const enrichedRules = computed(() => {
|
|
|
615
620
|
});
|
|
616
621
|
const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
|
|
617
622
|
const inputProps = computed(() => {
|
|
618
|
-
return origamInputRef.value?.filterProps(props, ["modelValue", "class", "style", "focused"]);
|
|
623
|
+
return origamInputRef.value?.filterProps(props, ["modelValue", "class", "style", "focused", ...BORDER_PROP_KEYS]);
|
|
619
624
|
});
|
|
620
625
|
const fieldProps = computed(() => {
|
|
621
626
|
return origamFieldRef.value?.filterProps(props, ["class", "id", "active", "dirty", "disabled", "focused", "error", "style"]);
|
|
@@ -182,6 +182,8 @@ const props = defineProps({
|
|
|
182
182
|
appendIcon: { type: null, required: false },
|
|
183
183
|
prependAvatar: { type: String, required: false },
|
|
184
184
|
prependIcon: { type: null, required: false },
|
|
185
|
+
prependAriaLabel: { type: String, required: false },
|
|
186
|
+
appendAriaLabel: { type: String, required: false },
|
|
185
187
|
size: { type: null, required: false },
|
|
186
188
|
fontSize: { type: null, required: false },
|
|
187
189
|
fontWeight: { type: null, required: false },
|
|
@@ -13,16 +13,21 @@
|
|
|
13
13
|
v-bind="{id, messagesId, isDisabled, isReadonly, isValid}"
|
|
14
14
|
>
|
|
15
15
|
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
<div
|
|
17
|
+
:id="groupLabelId"
|
|
18
|
+
class="origam-radio-group__label"
|
|
19
19
|
>
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
<slot
|
|
21
|
+
name="label"
|
|
22
|
+
v-bind="{label, required}"
|
|
23
|
+
>
|
|
24
|
+
<origam-label
|
|
25
|
+
:required="required"
|
|
26
|
+
:text="label"
|
|
27
|
+
tag="span"
|
|
28
|
+
/>
|
|
29
|
+
</slot>
|
|
30
|
+
</div>
|
|
26
31
|
|
|
27
32
|
<origam-defaults-provider :defaults="radioDefaults">
|
|
28
33
|
<origam-selection-control-group
|
|
@@ -30,7 +35,7 @@
|
|
|
30
35
|
ref="origamSelectionControlGroupRef"
|
|
31
36
|
v-model="model"
|
|
32
37
|
:aria-describedby="messagesId"
|
|
33
|
-
:aria-labelledby="
|
|
38
|
+
:aria-labelledby="groupLabelledBy"
|
|
34
39
|
:disabled="isDisabled"
|
|
35
40
|
:items="items"
|
|
36
41
|
:multiple="false"
|
|
@@ -141,6 +146,8 @@ const props = defineProps({
|
|
|
141
146
|
appendIcon: { type: null, required: false },
|
|
142
147
|
prependAvatar: { type: String, required: false },
|
|
143
148
|
prependIcon: { type: null, required: false },
|
|
149
|
+
prependAriaLabel: { type: String, required: false },
|
|
150
|
+
appendAriaLabel: { type: String, required: false },
|
|
144
151
|
size: { type: null, required: false },
|
|
145
152
|
fontSize: { type: null, required: false },
|
|
146
153
|
fontWeight: { type: null, required: false },
|
|
@@ -161,7 +168,7 @@ const props = defineProps({
|
|
|
161
168
|
activeClass: { type: String, required: false },
|
|
162
169
|
items: { type: [Array, Object], required: false }
|
|
163
170
|
});
|
|
164
|
-
defineSlots();
|
|
171
|
+
const slots = defineSlots();
|
|
165
172
|
defineEmits(["update:modelValue"]);
|
|
166
173
|
const { filterProps } = useProps(props);
|
|
167
174
|
const origamSelectionControlGroupRef = ref();
|
|
@@ -172,6 +179,10 @@ const id = computed(() => {
|
|
|
172
179
|
return props.id || `radio-group-${uid}`;
|
|
173
180
|
});
|
|
174
181
|
const model = useVModel(props, "modelValue");
|
|
182
|
+
const groupLabelId = computed(() => `${id.value}-label`);
|
|
183
|
+
const groupLabelledBy = computed(() => {
|
|
184
|
+
return props.label || slots.label ? groupLabelId.value : void 0;
|
|
185
|
+
});
|
|
175
186
|
const [rootAttrs, controlAttrs] = filterInputAttrs(attrs);
|
|
176
187
|
const inputProps = computed(() => {
|
|
177
188
|
return origamInputRef.value?.filterProps(props, ["modelValue", "id", "focused", "style", "class"]);
|
|
@@ -213,3 +224,17 @@ defineExpose({
|
|
|
213
224
|
styleId
|
|
214
225
|
});
|
|
215
226
|
</script>
|
|
227
|
+
|
|
228
|
+
<style lang="scss" scoped>
|
|
229
|
+
/*
|
|
230
|
+
* Le wrapper n'existe que pour porter l'id cible d'`aria-labelledby`
|
|
231
|
+
* (#814). `display: contents` le retire de l'arbre des boites : les
|
|
232
|
+
* enfants du slot `label` restent les elements flex directs de
|
|
233
|
+
* `.origam-input__control`, donc la mise en page est inchangee — mesure
|
|
234
|
+
* avant/apres identique au pixel sur les variantes « Default » et
|
|
235
|
+
* « Slots - Label ».
|
|
236
|
+
*/
|
|
237
|
+
.origam-radio-group__label {
|
|
238
|
+
display: contents;
|
|
239
|
+
}
|
|
240
|
+
</style>
|
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
:id="id"
|
|
4
4
|
ref="origamInputRef"
|
|
5
5
|
v-model="model"
|
|
6
|
+
:aria-labelledby="groupLabelledBy"
|
|
7
|
+
:aria-readonly="readonly || undefined"
|
|
6
8
|
:class="ratingFieldClasses"
|
|
7
9
|
:style="ratingFieldStyles"
|
|
10
|
+
role="radiogroup"
|
|
8
11
|
v-bind="{...rootAttrs, ...inputProps}"
|
|
9
12
|
>
|
|
10
13
|
<template
|
|
@@ -19,12 +22,15 @@
|
|
|
19
22
|
name="default"
|
|
20
23
|
v-bind="{id,messagesId,isDisabled,isReadonly,isValid}"
|
|
21
24
|
>
|
|
22
|
-
<div
|
|
25
|
+
<div
|
|
26
|
+
:id="groupLabelId"
|
|
27
|
+
class="origam-rating-field__label"
|
|
28
|
+
>
|
|
23
29
|
<slot name="label">
|
|
24
30
|
<origam-label
|
|
25
|
-
:for="id"
|
|
26
31
|
:required="required"
|
|
27
32
|
:text="label"
|
|
33
|
+
tag="span"
|
|
28
34
|
/>
|
|
29
35
|
</slot>
|
|
30
36
|
</div>
|
|
@@ -158,7 +164,7 @@
|
|
|
158
164
|
</template>
|
|
159
165
|
|
|
160
166
|
<script lang="ts" setup>
|
|
161
|
-
import { computed, ref, shallowRef, StyleValue, useAttrs, useSlots } from "vue";
|
|
167
|
+
import { computed, nextTick, ref, shallowRef, StyleValue, useAttrs, useSlots } from "vue";
|
|
162
168
|
import OrigamBtn from "../Btn/OrigamBtn.vue";
|
|
163
169
|
import OrigamInput from "../Input/OrigamInput.vue";
|
|
164
170
|
import OrigamLabel from "../Label/OrigamLabel.vue";
|
|
@@ -167,8 +173,14 @@ import { useLocale } from "../../composables/Commons/locale.composable";
|
|
|
167
173
|
import { useProps } from "../../composables/Commons/props.composable";
|
|
168
174
|
import { useStyle } from "../../composables/Commons/style.composable";
|
|
169
175
|
import { useVModel } from "../../composables/Commons/vModel.composable";
|
|
176
|
+
import {
|
|
177
|
+
RATING_FIELD_ENABLED_RADIO_SELECTOR,
|
|
178
|
+
RATING_FIELD_MUTATING_KEYS,
|
|
179
|
+
RATING_FIELD_ROOT_SELECTOR
|
|
180
|
+
} from "../../consts/RatingField/rating-field.const";
|
|
170
181
|
import { BLOCK } from "../../enums/Commons/anchor.enum";
|
|
171
182
|
import { DENSITY } from "../../enums/Commons/density.enum";
|
|
183
|
+
import { KEYBOARD_VALUES } from "../../enums/Commons/hotkey.enum";
|
|
172
184
|
import { MDI_ICONS } from "../../enums/Commons/mdi.enum";
|
|
173
185
|
import { SIZES } from "../../enums/Commons/size.enum";
|
|
174
186
|
import { VARIANT } from "../../enums/Commons/variant.enum";
|
|
@@ -253,6 +265,8 @@ const props = defineProps({
|
|
|
253
265
|
appendIcon: { type: null, required: false },
|
|
254
266
|
prependAvatar: { type: String, required: false },
|
|
255
267
|
prependIcon: { type: null, required: false },
|
|
268
|
+
prependAriaLabel: { type: String, required: false },
|
|
269
|
+
appendAriaLabel: { type: String, required: false },
|
|
256
270
|
size: { type: null, required: false, default: SIZES.DEFAULT },
|
|
257
271
|
fontSize: { type: null, required: false },
|
|
258
272
|
fontWeight: { type: null, required: false },
|
|
@@ -286,6 +300,21 @@ const name = computed(() => {
|
|
|
286
300
|
return props.name ?? `origam-rating-${getUid()}`;
|
|
287
301
|
});
|
|
288
302
|
const hoverIndex = shallowRef(-1);
|
|
303
|
+
const handleKeydown = (e) => {
|
|
304
|
+
if (props.disabled || props.readonly) {
|
|
305
|
+
if (RATING_FIELD_MUTATING_KEYS.includes(e.key)) e.preventDefault();
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (e.key !== KEYBOARD_VALUES.HOME && e.key !== KEYBOARD_VALUES.END) return;
|
|
309
|
+
const group = e.target?.closest(RATING_FIELD_ROOT_SELECTOR);
|
|
310
|
+
if (!group) return;
|
|
311
|
+
const radios = Array.from(group.querySelectorAll(RATING_FIELD_ENABLED_RADIO_SELECTOR));
|
|
312
|
+
if (!radios.length) return;
|
|
313
|
+
e.preventDefault();
|
|
314
|
+
const target = e.key === KEYBOARD_VALUES.HOME ? radios[0] : radios[radios.length - 1];
|
|
315
|
+
target.focus();
|
|
316
|
+
if (!target.checked) target.click();
|
|
317
|
+
};
|
|
289
318
|
const itemState = computed(() => {
|
|
290
319
|
return increments.value.map((value) => {
|
|
291
320
|
const isFilled = normalizedValue.value >= value;
|
|
@@ -303,20 +332,38 @@ const eventState = computed(() => {
|
|
|
303
332
|
const onMouseleave = () => {
|
|
304
333
|
hoverIndex.value = -1;
|
|
305
334
|
};
|
|
306
|
-
const onClick = () => {
|
|
307
|
-
if (props.disabled
|
|
308
|
-
|
|
335
|
+
const onClick = (e) => {
|
|
336
|
+
if (!props.disabled && !props.readonly) {
|
|
337
|
+
model.value = normalizedValue.value === value && props.clearable ? 0 : value;
|
|
338
|
+
}
|
|
339
|
+
void nextTick(() => resyncRadios(e?.target));
|
|
340
|
+
};
|
|
341
|
+
const onChange = (e) => {
|
|
342
|
+
if (!props.disabled && !props.readonly) {
|
|
343
|
+
model.value = value;
|
|
344
|
+
}
|
|
345
|
+
void nextTick(() => resyncRadios(e?.target));
|
|
309
346
|
};
|
|
310
347
|
return {
|
|
311
348
|
onMouseenter: props.hover ? onMouseenter : void 0,
|
|
312
349
|
onMouseleave: props.hover ? onMouseleave : void 0,
|
|
313
|
-
onClick
|
|
350
|
+
onClick,
|
|
351
|
+
onChange,
|
|
352
|
+
onKeydown: handleKeydown
|
|
314
353
|
};
|
|
315
354
|
});
|
|
316
355
|
});
|
|
317
356
|
const isChecked = (value) => {
|
|
318
357
|
return normalizedValue.value === value;
|
|
319
358
|
};
|
|
359
|
+
const resyncRadios = (source) => {
|
|
360
|
+
const group = source?.closest(RATING_FIELD_ROOT_SELECTOR);
|
|
361
|
+
if (!group) return;
|
|
362
|
+
group.querySelectorAll('input[type="radio"]').forEach((radio) => {
|
|
363
|
+
const shouldBeChecked = isChecked(parseFloat(radio.value));
|
|
364
|
+
if (radio.checked !== shouldBeChecked) radio.checked = shouldBeChecked;
|
|
365
|
+
});
|
|
366
|
+
};
|
|
320
367
|
const hasLabels = computed(() => {
|
|
321
368
|
return !!props.itemLabels?.length || slots.itemLabel;
|
|
322
369
|
});
|
|
@@ -346,6 +393,10 @@ const ratingFieldClasses = computed(() => {
|
|
|
346
393
|
];
|
|
347
394
|
});
|
|
348
395
|
const { id, css, load, isLoaded, unload } = useStyle(ratingFieldStyles, () => props.id);
|
|
396
|
+
const groupLabelId = computed(() => `${id.value}-label`);
|
|
397
|
+
const groupLabelledBy = computed(() => {
|
|
398
|
+
return props.label || slots.label ? groupLabelId.value : void 0;
|
|
399
|
+
});
|
|
349
400
|
defineExpose({
|
|
350
401
|
filterProps,
|
|
351
402
|
css,
|
|
@@ -4,37 +4,39 @@
|
|
|
4
4
|
:class="ratingFieldItemClasses"
|
|
5
5
|
:style="ratingFieldItemStyles"
|
|
6
6
|
>
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<span class="origam-rating-field-item__hidden">{{ t(itemAriaLabel, value, length) }}</span>
|
|
12
|
-
<slot
|
|
13
|
-
v-if="showStar"
|
|
14
|
-
name="item"
|
|
15
|
-
v-bind="{props: ratingBtnProps, value}"
|
|
7
|
+
<template v-if="showStar">
|
|
8
|
+
<label
|
|
9
|
+
:for="id"
|
|
10
|
+
class="origam-rating-field-item__label"
|
|
16
11
|
>
|
|
17
|
-
<origam-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
<span class="origam-rating-field-item__hidden">{{ t(itemAriaLabel, value, length) }}</span>
|
|
13
|
+
<slot
|
|
14
|
+
name="item"
|
|
15
|
+
v-bind="{props: ratingBtnProps, value}"
|
|
16
|
+
>
|
|
17
|
+
<origam-btn
|
|
18
|
+
ref="origamBtnRef"
|
|
19
|
+
v-bind="{...ratingBtnProps}"
|
|
20
|
+
@click="handleClick"
|
|
21
|
+
@mouseenter="handleMouseEnter"
|
|
22
|
+
@mouseleave="handleMouseLeave"
|
|
23
|
+
/>
|
|
24
|
+
</slot>
|
|
25
|
+
</label>
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
<input
|
|
28
|
+
:id="id"
|
|
29
|
+
:checked="checked"
|
|
30
|
+
:disabled="disabled"
|
|
31
|
+
:name="name"
|
|
32
|
+
:readonly="readonly"
|
|
33
|
+
:value="value"
|
|
34
|
+
class="origam-rating-field-item__hidden"
|
|
35
|
+
type="radio"
|
|
36
|
+
@change="handleChange"
|
|
37
|
+
@keydown="handleKeydown"
|
|
38
|
+
/>
|
|
39
|
+
</template>
|
|
38
40
|
</component>
|
|
39
41
|
</template>
|
|
40
42
|
|
|
@@ -105,7 +107,7 @@ const props = defineProps({
|
|
|
105
107
|
roundedBottomRight: { type: [Boolean, Number, String], required: false },
|
|
106
108
|
elevation: { type: [Number, String], required: false }
|
|
107
109
|
});
|
|
108
|
-
const emits = defineEmits(["mouseenter", "mouseleave", "click"]);
|
|
110
|
+
const emits = defineEmits(["mouseenter", "mouseleave", "change", "keydown", "click"]);
|
|
109
111
|
defineSlots();
|
|
110
112
|
const { filterProps } = useProps(props);
|
|
111
113
|
const { t } = useLocale();
|
|
@@ -128,6 +130,12 @@ const handleMouseLeave = (e) => {
|
|
|
128
130
|
const handleClick = (e) => {
|
|
129
131
|
emits("click", e);
|
|
130
132
|
};
|
|
133
|
+
const handleChange = (e) => {
|
|
134
|
+
emits("change", e);
|
|
135
|
+
};
|
|
136
|
+
const handleKeydown = (e) => {
|
|
137
|
+
emits("keydown", e);
|
|
138
|
+
};
|
|
131
139
|
const ratingFieldItemStyles = computed(() => {
|
|
132
140
|
return [
|
|
133
141
|
props.style
|
|
@@ -157,6 +165,30 @@ defineExpose({
|
|
|
157
165
|
|
|
158
166
|
<style lang="scss" scoped>
|
|
159
167
|
.origam-rating-field-item {
|
|
168
|
+
/*
|
|
169
|
+
* #812 — WCAG 2.4.7 (Focus Visible).
|
|
170
|
+
*
|
|
171
|
+
* The control a keyboard user focuses is the native
|
|
172
|
+
* `<input type="radio">`, and `&__hidden` below makes it
|
|
173
|
+
* `height:0; width:0; opacity:0`. Putting it back in the tab order
|
|
174
|
+
* without this rule would have swapped one defect for another: the
|
|
175
|
+
* group would become operable while the focus indicator landed on a
|
|
176
|
+
* 0x0 transparent element. That is the trade #810 refused to make and
|
|
177
|
+
* #812 names explicitly.
|
|
178
|
+
*
|
|
179
|
+
* `:has()` is the CSS-first answer — the ring is painted on the STAR,
|
|
180
|
+
* which is the box the user actually sees, while focus stays on the
|
|
181
|
+
* input that owns the radio semantics. No JS, no second focusable
|
|
182
|
+
* element, no `tabindex` bookkeeping.
|
|
183
|
+
*
|
|
184
|
+
* `:focus-visible` (not `:focus`) so a mouse click on a star does not
|
|
185
|
+
* leave a ring behind — the browser's own heuristic, not ours.
|
|
186
|
+
*/
|
|
187
|
+
&:has(:focus-visible) {
|
|
188
|
+
outline: var(--origam-border__width---2, 2px) solid var(--origam-color__border---focus, currentColor);
|
|
189
|
+
outline-offset: var(--origam-space---1, 4px);
|
|
190
|
+
}
|
|
191
|
+
|
|
160
192
|
&__label {
|
|
161
193
|
cursor: pointer;
|
|
162
194
|
|
|
@@ -184,6 +216,22 @@ defineExpose({
|
|
|
184
216
|
clip-path: polygon(0 0, 50% 0, 50% 100%, 0 100%);
|
|
185
217
|
z-index: 1;
|
|
186
218
|
|
|
219
|
+
/*
|
|
220
|
+
* #812 — a `clip-path` clips the element's OWN outline too, not
|
|
221
|
+
* just its descendants. Measured: with the shared
|
|
222
|
+
* `outline-offset: 4px` above, focusing a half-step radio painted
|
|
223
|
+
* a ring entirely outside the polygon — computed `outline-width`
|
|
224
|
+
* read `2px` while the screenshot showed nothing at all. That is
|
|
225
|
+
* the exact shape of a false green: the property is set, the pixel
|
|
226
|
+
* is not there.
|
|
227
|
+
*
|
|
228
|
+
* An INSET offset puts the ring back inside the clipped region, so
|
|
229
|
+
* it survives and outlines precisely the half the step selects.
|
|
230
|
+
*/
|
|
231
|
+
&:has(:focus-visible) {
|
|
232
|
+
outline-offset: calc(-1 * var(--origam-border__width---2, 2px));
|
|
233
|
+
}
|
|
234
|
+
|
|
187
235
|
&,
|
|
188
236
|
&:hover {
|
|
189
237
|
:deep(.origam-btn__overlay) {
|