@leavepulse/ui 0.53.0 → 0.54.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/dist/chunks/{LpAppShell-BmMYcEVx.js → LpAppShell-DcSXik4a.js} +1 -1
- package/dist/chunks/{LpAvatar-Cb1jtOVv.js → LpAvatar-LTvy0OkE.js} +1 -1
- package/dist/chunks/{LpCard-BdxkMXjo.js → LpCard-DbjO5yaF.js} +1 -1
- package/dist/chunks/{LpCheckbox-Bkj13CbW.js → LpCheckbox-DvVYeOD-.js} +2 -2
- package/dist/chunks/{LpColorPicker-BLqPX5Vw.js → LpColorPicker-D1sQqtXS.js} +1 -1
- package/dist/chunks/{LpContextMenu-1cKew_Dc.js → LpContextMenu-EF_90u3g.js} +5 -1
- package/dist/chunks/{LpFileTree-bk5VjBey.js → LpFileTree-3E4w4Rjr.js} +1 -1
- package/dist/chunks/{LpFileTreeNode-BvMSBM7X.js → LpFileTreeNode-B4uB8Ks_.js} +2 -2
- package/dist/chunks/{LpLogViewer-BDFXzvcl.js → LpLogViewer-BfgtXVKm.js} +1 -1
- package/dist/chunks/{LpModalNav-BAxC9et7.js → LpModalNav-aWwc_5CD.js} +1 -1
- package/dist/chunks/{LpNotificationBell-DsqSyMwS.js → LpNotificationBell-wZ3meeim.js} +1 -1
- package/dist/chunks/LpOtpInput-PbeNJ5In.js +131 -0
- package/dist/chunks/{LpPie-BdSnta11.js → LpPie-B7ti5qCH.js} +1 -1
- package/dist/chunks/{LpRadio-B5AfqTpZ.js → LpRadio-CWA5Eb3M.js} +2 -2
- package/dist/chunks/{LpRadioGroup-DmEW0l78.js → LpRadioGroup-CCn-Q2_c.js} +2 -2
- package/dist/chunks/{LpSidebar-DpEiGi8L.js → LpSidebar-C2oolgwy.js} +1 -1
- package/dist/chunks/{LpSidebarNav-BUuxipX-.js → LpSidebarNav-C9dHu-2b.js} +1 -1
- package/dist/chunks/{LpSwitch-OrcOJX9m.js → LpSwitch-DG2AhXIL.js} +2 -2
- package/dist/chunks/{LpTableFilter-BV8PpLM9.js → LpTableFilter-CrW7_Rj4.js} +1 -1
- package/dist/chunks/{LpTabs-UM0FQmPA.js → LpTabs-BMSBB78h.js} +44 -17
- package/dist/chunks/{LpThemeSwitcher-BbYFFT5w.js → LpThemeSwitcher-CPmhYOjX.js} +1 -1
- package/dist/components/LpAppShell.vue.js +1 -1
- package/dist/components/LpAvatar.vue.js +1 -1
- package/dist/components/LpCard.vue.js +1 -1
- package/dist/components/LpChart.vue.js +1 -1
- package/dist/components/LpCheckbox.vue.js +1 -1
- package/dist/components/LpColorPicker.vue.js +1 -1
- package/dist/components/LpCommandPalette.vue.js +1 -1
- package/dist/components/LpContextMenu.vue.d.ts +2 -2
- package/dist/components/LpContextMenu.vue.js +1 -1
- package/dist/components/LpFileTree.vue.js +1 -1
- package/dist/components/LpFileTreeNode.vue.js +1 -1
- package/dist/components/LpLogViewer.vue.js +1 -1
- package/dist/components/LpModalNav.vue.js +1 -1
- package/dist/components/LpNotificationBell.vue.js +1 -1
- package/dist/components/LpOtpInput.vue.d.ts +17 -0
- package/dist/components/LpOtpInput.vue.js +1 -1
- package/dist/components/LpPaletteHeader.vue.js +1 -1
- package/dist/components/LpPie.vue.js +1 -1
- package/dist/components/LpRadio.vue.js +1 -1
- package/dist/components/LpRadioGroup.vue.js +1 -1
- package/dist/components/LpSidebar.vue.js +1 -1
- package/dist/components/LpSidebarNav.vue.js +1 -1
- package/dist/components/LpSwitch.vue.js +1 -1
- package/dist/components/LpTable.vue.js +3 -3
- package/dist/components/LpTableFilter.vue.js +1 -1
- package/dist/components/LpTabs.vue.d.ts +10 -2
- package/dist/components/LpTabs.vue.js +1 -1
- package/dist/components/LpThemeSwitcher.vue.js +1 -1
- package/dist/components/otp.d.ts +2 -0
- package/dist/components/otp.js +17 -1
- package/dist/index.js +18 -18
- package/package.json +1 -1
- package/src/components/LpCheckbox.vue +2 -2
- package/src/components/LpContextMenu.vue +18 -1
- package/src/components/LpOtpInput.vue +84 -28
- package/src/components/LpRadio.vue +2 -2
- package/src/components/LpRadioGroup.vue +2 -2
- package/src/components/LpSwitch.vue +2 -2
- package/src/components/LpTabs.vue +60 -21
- package/src/components/otp.ts +29 -0
- package/dist/chunks/LpOtpInput-CziPF3Oq.js +0 -99
|
@@ -10,6 +10,14 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
10
10
|
mask?: boolean;
|
|
11
11
|
/** Allow letters too (backup codes). Default: digits only (TOTP). */
|
|
12
12
|
alphanumeric?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Turn typed letters into capitals, and open a phone's keyboard in capitals.
|
|
15
|
+
* Default: on with `alphanumeric`, where codes are printed in capitals and
|
|
16
|
+
* compared without regard to case; pass `false` for a case-sensitive code.
|
|
17
|
+
*/
|
|
18
|
+
uppercase?: boolean;
|
|
19
|
+
/** Draw a separator after every `group` cells (e.g. 3 for "123-456"). */
|
|
20
|
+
group?: number;
|
|
13
21
|
/** Error state — tints the cells red (e.g. wrong code). */
|
|
14
22
|
invalid?: boolean;
|
|
15
23
|
size?: "sm" | "md" | "lg";
|
|
@@ -26,6 +34,14 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
26
34
|
mask?: boolean;
|
|
27
35
|
/** Allow letters too (backup codes). Default: digits only (TOTP). */
|
|
28
36
|
alphanumeric?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Turn typed letters into capitals, and open a phone's keyboard in capitals.
|
|
39
|
+
* Default: on with `alphanumeric`, where codes are printed in capitals and
|
|
40
|
+
* compared without regard to case; pass `false` for a case-sensitive code.
|
|
41
|
+
*/
|
|
42
|
+
uppercase?: boolean;
|
|
43
|
+
/** Draw a separator after every `group` cells (e.g. 3 for "123-456"). */
|
|
44
|
+
group?: number;
|
|
29
45
|
/** Error state — tints the cells red (e.g. wrong code). */
|
|
30
46
|
invalid?: boolean;
|
|
31
47
|
size?: "sm" | "md" | "lg";
|
|
@@ -35,5 +51,6 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
35
51
|
}>, {
|
|
36
52
|
size: "sm" | "md" | "lg";
|
|
37
53
|
length: number;
|
|
54
|
+
uppercase: boolean;
|
|
38
55
|
alphanumeric: boolean;
|
|
39
56
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineComponent, computed, openBlock, createElementBlock, createElementVNode, renderSlot, createBlock, createVNode, createCommentVNode, toDisplayString } from "vue";
|
|
2
|
-
import { _ as _sfc_main$1 } from "../chunks/LpAvatar-
|
|
2
|
+
import { _ as _sfc_main$1 } from "../chunks/LpAvatar-LTvy0OkE.js";
|
|
3
3
|
import { _ as _sfc_main$2 } from "../chunks/LpIcon-DYtaid0K.js";
|
|
4
4
|
import { _ as _sfc_main$3 } from "../chunks/HighlightText-BvnYZkhi.js";
|
|
5
5
|
import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { defineComponent, computed, useAttrs, ref, shallowRef, watch, onMounted, onBeforeUnmount, openBlock, createElementBlock, normalizeClass, createVNode, withCtx, createTextVNode, toDisplayString, createCommentVNode, Fragment, renderList, createElementVNode, Transition, renderSlot, mergeProps, normalizeStyle, createBlock, TransitionGroup, unref, withModifiers, nextTick } from "vue";
|
|
2
|
-
import { _ as _sfc_main$7 } from "../chunks/LpCheckbox-
|
|
3
|
-
import { _ as _sfc_main$6 } from "../chunks/LpContextMenu-
|
|
2
|
+
import { _ as _sfc_main$7 } from "../chunks/LpCheckbox-DvVYeOD-.js";
|
|
3
|
+
import { _ as _sfc_main$6 } from "../chunks/LpContextMenu-EF_90u3g.js";
|
|
4
4
|
import { _ as _sfc_main$2 } from "../chunks/LpIcon-DYtaid0K.js";
|
|
5
5
|
import { _ as _sfc_main$a } from "../chunks/LpPagination-BcDlo3r_.js";
|
|
6
6
|
import { _ as _sfc_main$8 } from "../chunks/LpPopover-DCKeqiVn.js";
|
|
7
7
|
import { _ as _sfc_main$5 } from "../chunks/LpScrollArea-Hz3-JWUG.js";
|
|
8
8
|
import { _ as _sfc_main$4 } from "../chunks/LpRollingText-DB7upf-5.js";
|
|
9
9
|
import { _ as _sfc_main$3 } from "../chunks/LpShift-DXNsauQZ.js";
|
|
10
|
-
import { _ as _sfc_main$9 } from "../chunks/LpTableFilter-
|
|
10
|
+
import { _ as _sfc_main$9 } from "../chunks/LpTableFilter-CrW7_Rj4.js";
|
|
11
11
|
import { useAsyncTask } from "../composables/useAsyncTask.js";
|
|
12
12
|
import { useHotkeys } from "../composables/useHotkeys.js";
|
|
13
13
|
import { usePaintSelect } from "../composables/usePaintSelect.js";
|
|
@@ -3,6 +3,8 @@ export interface TabItem {
|
|
|
3
3
|
label: string;
|
|
4
4
|
/** Optional iconify name (e.g. "lucide:palette"), shown left of the label. */
|
|
5
5
|
icon?: string;
|
|
6
|
+
/** A small dot on the tab: something behind it wants a look (unread, a problem). */
|
|
7
|
+
dot?: boolean;
|
|
6
8
|
}
|
|
7
9
|
type __VLS_Props = {
|
|
8
10
|
modelValue?: string;
|
|
@@ -15,12 +17,18 @@ type __VLS_Props = {
|
|
|
15
17
|
* sliding pill marking the active one (for nav bars over a custom surface).
|
|
16
18
|
* "underline" is a flat row over a hairline baseline, marking the active
|
|
17
19
|
* tab with a sliding bottom bar instead of a pill (page-section nav style).
|
|
20
|
+
* "bottom" is a phone's bottom navigation: full width, equal-share tabs
|
|
21
|
+
* with the icon over the label, a sliding bar along the top edge marking
|
|
22
|
+
* the active one, and padding for the gesture strip and side insets of an
|
|
23
|
+
* edge-to-edge screen. Place it as the last row of the layout.
|
|
18
24
|
*/
|
|
19
|
-
variant?: "contained" | "plain" | "underline";
|
|
25
|
+
variant?: "contained" | "plain" | "underline" | "bottom";
|
|
20
26
|
/** Tint the active pill + label with the brand colour (nav-bar style). */
|
|
21
27
|
accent?: boolean;
|
|
22
28
|
/** Stretch the bar to full width with equal-share triggers. */
|
|
23
29
|
block?: boolean;
|
|
30
|
+
/** Accessible name of the tab list, e.g. "Main" for an app's navigation. */
|
|
31
|
+
label?: string;
|
|
24
32
|
};
|
|
25
33
|
declare var __VLS_51: {
|
|
26
34
|
value: string;
|
|
@@ -36,7 +44,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
36
44
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
37
45
|
}>, {
|
|
38
46
|
block: boolean;
|
|
39
|
-
variant: "contained" | "plain" | "underline";
|
|
47
|
+
variant: "contained" | "plain" | "underline" | "bottom";
|
|
40
48
|
accent: boolean;
|
|
41
49
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
42
50
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
package/dist/components/otp.d.ts
CHANGED
|
@@ -3,3 +3,5 @@ export type OtpCells = (string | number | undefined)[];
|
|
|
3
3
|
export declare function joinCells(cells: OtpCells): string;
|
|
4
4
|
/** Cells for a code given from outside, one character each. */
|
|
5
5
|
export declare function splitCode(code: string | undefined, length: number): string[];
|
|
6
|
+
export declare function upperCells<T extends OtpCells>(cells: T): T;
|
|
7
|
+
export declare function groupBreaks(length: number, group: number | undefined): Set<number>;
|
package/dist/components/otp.js
CHANGED
|
@@ -4,7 +4,23 @@ function joinCells(cells) {
|
|
|
4
4
|
function splitCode(code, length) {
|
|
5
5
|
return (code ?? "").split("").slice(0, length);
|
|
6
6
|
}
|
|
7
|
+
function upperCells(cells) {
|
|
8
|
+
const out = [];
|
|
9
|
+
cells.forEach((c, i) => {
|
|
10
|
+
out[i] = typeof c === "string" ? c.toUpperCase() : c;
|
|
11
|
+
});
|
|
12
|
+
out.length = cells.length;
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
function groupBreaks(length, group) {
|
|
16
|
+
const breaks = /* @__PURE__ */ new Set();
|
|
17
|
+
if (!group || group < 1 || group >= length) return breaks;
|
|
18
|
+
for (let i = group; i < length; i += group) breaks.add(i - 1);
|
|
19
|
+
return breaks;
|
|
20
|
+
}
|
|
7
21
|
export {
|
|
22
|
+
groupBreaks,
|
|
8
23
|
joinCells,
|
|
9
|
-
splitCode
|
|
24
|
+
splitCode,
|
|
25
|
+
upperCells
|
|
10
26
|
};
|
package/dist/index.js
CHANGED
|
@@ -4,21 +4,21 @@ import { _ as _3 } from "./chunks/LpMapPicker-Cc84LaM3.js";
|
|
|
4
4
|
import { OSM_TILES, createNominatimProvider, emptyAddress, formatAddress, project, tileUrl, unproject } from "./components/address.js";
|
|
5
5
|
import { _ as _4 } from "./chunks/LpActionBar-CnfFVIwC.js";
|
|
6
6
|
import { _ as _5 } from "./chunks/LpAlert-B6ilrM7T.js";
|
|
7
|
-
import { _ as _6 } from "./chunks/LpAppShell-
|
|
7
|
+
import { _ as _6 } from "./chunks/LpAppShell-DcSXik4a.js";
|
|
8
8
|
import { _ as _7 } from "./chunks/LpAutocomplete-C8IgSMsi.js";
|
|
9
|
-
import { _ as _8 } from "./chunks/LpAvatar-
|
|
9
|
+
import { _ as _8 } from "./chunks/LpAvatar-LTvy0OkE.js";
|
|
10
10
|
import { _ as _9 } from "./chunks/LpBadge-Fe0D1bYx.js";
|
|
11
11
|
import { _ as _10 } from "./chunks/LpBreadcrumbs-D4TsoFju.js";
|
|
12
12
|
import { _ as _11 } from "./chunks/LpButton-CKSwC6Mu.js";
|
|
13
13
|
import { _ as _12 } from "./chunks/LpCalendar-DrA2McTU.js";
|
|
14
|
-
import { _ as _13 } from "./chunks/LpCard-
|
|
14
|
+
import { _ as _13 } from "./chunks/LpCard-DbjO5yaF.js";
|
|
15
15
|
import { default as default2 } from "./components/LpChart.vue.js";
|
|
16
16
|
import { backgroundOf, csvField, downloadFile, fileStem, inlineSvg, resolveCssColor, svgToPng, toCsv } from "./components/exportData.js";
|
|
17
17
|
import { CHART_PALETTE, axisTicks, chartSummary, formatTick, markerIndex, niceScale, resolveSlices } from "./components/chart.js";
|
|
18
|
-
import { _ as _14 } from "./chunks/LpCheckbox-
|
|
18
|
+
import { _ as _14 } from "./chunks/LpCheckbox-DvVYeOD-.js";
|
|
19
19
|
import { _ as _15 } from "./chunks/LpCodeBlock-ca7ANFyW.js";
|
|
20
20
|
import { tokenizeLines } from "./components/codeHighlight.js";
|
|
21
|
-
import { _ as _16 } from "./chunks/LpColorPicker-
|
|
21
|
+
import { _ as _16 } from "./chunks/LpColorPicker-D1sQqtXS.js";
|
|
22
22
|
import { DEFAULT_SWATCHES, clampHsv, formatColor, hsvToHsl, hsvToRgb, isLight, normalizeHue, opaqueCss, parseColor, parseHex, rgbToHex, rgbToHsv } from "./components/color.js";
|
|
23
23
|
import { default as default3 } from "./components/LpCommandPalette.vue.js";
|
|
24
24
|
import { applyQueryFilters, highlightParts, parseCommandQuery, parsePaletteQuery, rankCommandItems } from "./components/commandSearch.js";
|
|
@@ -33,7 +33,7 @@ import { comboKeys, comboSteps } from "./components/keys.js";
|
|
|
33
33
|
import { _ as _18 } from "./chunks/LpConfirmDialog-Ca-CTlxT.js";
|
|
34
34
|
import { _ as _19 } from "./chunks/LpConfirmHost-BAaSaT2b.js";
|
|
35
35
|
import { confirm, useConfirm } from "./components/confirm.js";
|
|
36
|
-
import { _ as _20 } from "./chunks/LpContextMenu-
|
|
36
|
+
import { _ as _20 } from "./chunks/LpContextMenu-EF_90u3g.js";
|
|
37
37
|
import { _ as _21 } from "./chunks/LpDatePicker-BrdFtSTy.js";
|
|
38
38
|
import { _ as _22 } from "./chunks/LpDateRangePicker-Drd7EbIz.js";
|
|
39
39
|
import { _ as _23 } from "./chunks/LpRangeCalendar-DZuaRV0W.js";
|
|
@@ -44,7 +44,7 @@ import { _ as _26 } from "./chunks/LpDrawer-CBFVD624.js";
|
|
|
44
44
|
import { _ as _27 } from "./chunks/LpDropdownMenu-DrpJJBp0.js";
|
|
45
45
|
import { default as default9 } from "./components/LpDropzone.vue.js";
|
|
46
46
|
import { _ as _28 } from "./chunks/LpEmptyState-BJbZXC8D.js";
|
|
47
|
-
import { _ as _29 } from "./chunks/LpFileTree-
|
|
47
|
+
import { _ as _29 } from "./chunks/LpFileTree-3E4w4Rjr.js";
|
|
48
48
|
import { ancestorIds, checkStateOf, checkedCount, computeStats, fileIcon, formatModified, formatSize, sortNodes, subtreeIds, subtreeSize } from "./components/fileTree.js";
|
|
49
49
|
import { _ as _30 } from "./chunks/LpFieldNotice-wtieLUTj.js";
|
|
50
50
|
import { _ as _31 } from "./chunks/LpFormField-CtVYj6tO.js";
|
|
@@ -56,25 +56,25 @@ import { _ as _34 } from "./chunks/LpInput-D-YGQbEv.js";
|
|
|
56
56
|
import { _ as _35 } from "./chunks/LpLightbox-EVXzAq62.js";
|
|
57
57
|
import { fileNameOf } from "./components/lightbox.js";
|
|
58
58
|
import { _ as _36 } from "./chunks/LpLink-Krkjhe_y.js";
|
|
59
|
-
import { _ as _37 } from "./chunks/LpLogViewer-
|
|
59
|
+
import { _ as _37 } from "./chunks/LpLogViewer-BfgtXVKm.js";
|
|
60
60
|
import { countLevels, matchPositions, matchesTerm, ringWindow, stepMatch } from "./components/logSearch.js";
|
|
61
61
|
import { _ as _38 } from "./chunks/LpMediaGallery-BnlkN_1f.js";
|
|
62
62
|
import { _ as _39 } from "./chunks/LpModal-JNa3B_Lr.js";
|
|
63
|
-
import { _ as _40 } from "./chunks/LpModalNav-
|
|
64
|
-
import { _ as _41 } from "./chunks/LpNotificationBell-
|
|
63
|
+
import { _ as _40 } from "./chunks/LpModalNav-aWwc_5CD.js";
|
|
64
|
+
import { _ as _41 } from "./chunks/LpNotificationBell-wZ3meeim.js";
|
|
65
65
|
import { _ as _42 } from "./chunks/LpNumberField-B77O-z28.js";
|
|
66
66
|
import { _ as _43 } from "./chunks/LpTimeField-Cqe7fXnh.js";
|
|
67
67
|
import { _ as _44 } from "./chunks/LpNumberFlow-z4WPZcZu.js";
|
|
68
|
-
import { _ as _45 } from "./chunks/LpOtpInput-
|
|
68
|
+
import { _ as _45 } from "./chunks/LpOtpInput-PbeNJ5In.js";
|
|
69
69
|
import { _ as _46 } from "./chunks/LpPagination-BcDlo3r_.js";
|
|
70
70
|
import { _ as _47 } from "./chunks/LpPasswordInput-eKzQhbQP.js";
|
|
71
|
-
import { _ as _48 } from "./chunks/LpPie-
|
|
71
|
+
import { _ as _48 } from "./chunks/LpPie-B7ti5qCH.js";
|
|
72
72
|
import { _ as _49 } from "./chunks/LpPhoneInput-BCbrrhgE.js";
|
|
73
73
|
import { filterCountries, flagEmoji, loadCountries, matchCountryByValue } from "./components/countries.js";
|
|
74
74
|
import { _ as _50 } from "./chunks/LpPopover-DCKeqiVn.js";
|
|
75
75
|
import { _ as _51 } from "./chunks/LpProgress-CBU1iI69.js";
|
|
76
|
-
import { _ as _52 } from "./chunks/LpRadio-
|
|
77
|
-
import { _ as _53 } from "./chunks/LpRadioGroup-
|
|
76
|
+
import { _ as _52 } from "./chunks/LpRadio-CWA5Eb3M.js";
|
|
77
|
+
import { _ as _53 } from "./chunks/LpRadioGroup-CCn-Q2_c.js";
|
|
78
78
|
import { _ as _54 } from "./chunks/LpRollingText-DB7upf-5.js";
|
|
79
79
|
import { _ as _55 } from "./chunks/LpScrollArea-Hz3-JWUG.js";
|
|
80
80
|
import { _ as _56 } from "./chunks/LpSegmented-C09EEam2.js";
|
|
@@ -83,7 +83,7 @@ import { _ as _58 } from "./chunks/LpSelect-DNIL6MB9.js";
|
|
|
83
83
|
import { _ as _59 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
|
|
84
84
|
import { _ as _60 } from "./chunks/LpShift-DXNsauQZ.js";
|
|
85
85
|
import { default as default11 } from "./components/LpShortcutsDialog.vue.js";
|
|
86
|
-
import { _ as _61 } from "./chunks/LpSidebar-
|
|
86
|
+
import { _ as _61 } from "./chunks/LpSidebar-C2oolgwy.js";
|
|
87
87
|
import { _ as _62 } from "./chunks/LpSkeleton-BB6XIV-w.js";
|
|
88
88
|
import { _ as _63 } from "./chunks/LpSlider-Cuzmrd7p.js";
|
|
89
89
|
import { _ as _64 } from "./chunks/LpRangeSlider-C1yF9-nP.js";
|
|
@@ -92,15 +92,15 @@ import { formatClipTime, isNativeLoop, planLoop, seamProgress, seamReached } fro
|
|
|
92
92
|
import { _ as _66 } from "./chunks/LpSparkline-CB80N8SJ.js";
|
|
93
93
|
import { _ as _67 } from "./chunks/LpStat-B-7udBRP.js";
|
|
94
94
|
import { _ as _68 } from "./chunks/LpStepper-C7XiVKZj.js";
|
|
95
|
-
import { _ as _69 } from "./chunks/LpSwitch-
|
|
95
|
+
import { _ as _69 } from "./chunks/LpSwitch-DG2AhXIL.js";
|
|
96
96
|
import { default as default12 } from "./components/LpTable.vue.js";
|
|
97
97
|
import { compareValues } from "./components/tableSort.js";
|
|
98
98
|
import { _ as _70 } from "./chunks/LpTableOfContents-BUcAfGPQ.js";
|
|
99
|
-
import { _ as _71 } from "./chunks/LpTabs-
|
|
99
|
+
import { _ as _71 } from "./chunks/LpTabs-BMSBB78h.js";
|
|
100
100
|
import { _ as _72 } from "./chunks/LpTagsInput-D1SuqbhB.js";
|
|
101
101
|
import { addTags, splitTags } from "./components/tags.js";
|
|
102
102
|
import { _ as _73 } from "./chunks/LpTextarea-uuScWo6-.js";
|
|
103
|
-
import { _ as _74 } from "./chunks/LpThemeSwitcher-
|
|
103
|
+
import { _ as _74 } from "./chunks/LpThemeSwitcher-CPmhYOjX.js";
|
|
104
104
|
import { _ as _75 } from "./chunks/LpTilt-B7KHX1zH.js";
|
|
105
105
|
import { _ as _76 } from "./chunks/LpToaster-DTtWuKvq.js";
|
|
106
106
|
import { _ as _77 } from "./chunks/LpTooltip-CXVKcOXT.js";
|
package/package.json
CHANGED
|
@@ -35,7 +35,7 @@ const field = useFieldControl(() => ({ wrapped: false, id: props.id, disabled: p
|
|
|
35
35
|
|
|
36
36
|
// The label sits a fixed distance from the box; a dense list of options needs that closer.
|
|
37
37
|
const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
38
|
-
"group inline-flex cursor-pointer items-center gap-2 text-sm text-ink",
|
|
38
|
+
"group/check inline-flex cursor-pointer items-center gap-2 text-sm text-ink",
|
|
39
39
|
)
|
|
40
40
|
</script>
|
|
41
41
|
|
|
@@ -49,7 +49,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
49
49
|
:model-value="indeterminate ? 'indeterminate' : modelValue"
|
|
50
50
|
:disabled="field.disabled"
|
|
51
51
|
:aria-describedby="field.describedBy"
|
|
52
|
-
class="flex size-[18px] items-center justify-center rounded-[5px] border border-line-strong bg-surface-soft outline-none transition-[color,background-color,border-color,box-shadow,scale] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] not-data-[state=checked]:not-data-[state=indeterminate]:group-hover:border-brand active:scale-90 motion-reduce:active:scale-100 focus-visible:ring-2 focus-visible:ring-ring data-[state=checked]:border-transparent data-[state=checked]:bg-brand data-[state=indeterminate]:border-transparent data-[state=indeterminate]:bg-brand disabled:cursor-not-allowed disabled:opacity-55"
|
|
52
|
+
class="flex size-[18px] items-center justify-center rounded-[5px] border border-line-strong bg-surface-soft outline-none transition-[color,background-color,border-color,box-shadow,scale] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] not-data-[state=checked]:not-data-[state=indeterminate]:group-hover/check:border-brand active:scale-90 motion-reduce:active:scale-100 focus-visible:ring-2 focus-visible:ring-ring data-[state=checked]:border-transparent data-[state=checked]:bg-brand data-[state=indeterminate]:border-transparent data-[state=indeterminate]:bg-brand disabled:cursor-not-allowed disabled:opacity-55"
|
|
53
53
|
@update:model-value="onUpdate"
|
|
54
54
|
>
|
|
55
55
|
<CheckboxIndicator
|
|
@@ -79,6 +79,18 @@ function rememberField() {
|
|
|
79
79
|
: null
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/*
|
|
83
|
+
* A right-click the menu answers goes no further than its trigger. reka opens
|
|
84
|
+
* the menu a tick later, and only if nothing has called preventDefault by then;
|
|
85
|
+
* an app that silences the browser's own menu with a window listener (most
|
|
86
|
+
* desktop shells do) got there first, so the menu never opened while a long
|
|
87
|
+
* press, which reka times itself, still did. reka cancels the native menu on
|
|
88
|
+
* its own once it opens.
|
|
89
|
+
*/
|
|
90
|
+
function keepContextMenu(event: Event) {
|
|
91
|
+
if (enabled.value) event.stopPropagation()
|
|
92
|
+
}
|
|
93
|
+
|
|
82
94
|
function returnFocus(event: Event) {
|
|
83
95
|
const saved = field
|
|
84
96
|
field = null
|
|
@@ -95,7 +107,12 @@ function returnFocus(event: Event) {
|
|
|
95
107
|
late, losing its state and focus. A disabled trigger leaves the browser's
|
|
96
108
|
own menu in place. -->
|
|
97
109
|
<ContextMenuRoot>
|
|
98
|
-
<ContextMenuTrigger
|
|
110
|
+
<ContextMenuTrigger
|
|
111
|
+
as-child
|
|
112
|
+
:disabled="!enabled"
|
|
113
|
+
@contextmenu.capture="rememberField"
|
|
114
|
+
@contextmenu="keepContextMenu"
|
|
115
|
+
>
|
|
99
116
|
<slot />
|
|
100
117
|
</ContextMenuTrigger>
|
|
101
118
|
<ContextMenuPortal v-if="items.length">
|
|
@@ -14,12 +14,16 @@ export default { inheritAttrs: false }
|
|
|
14
14
|
* The kit-facing model is a single STRING (the joined code), not reka's per-cell
|
|
15
15
|
* array: `v-model` is "123456", and @complete fires that string once every cell
|
|
16
16
|
* is filled. Digits-only by default (TOTP); flip `alphanumeric` for backup codes.
|
|
17
|
+
*
|
|
18
|
+
* The cells share the row rather than keeping a fixed size: each grows to its
|
|
19
|
+
* size's width and no further, and shrinks with the row when the container is
|
|
20
|
+
* narrower, so eight cells fit a phone instead of running off its edge.
|
|
17
21
|
*/
|
|
18
22
|
import { PinInputInput, PinInputRoot } from "reka-ui"
|
|
19
23
|
import { computed, ref, watch } from "vue"
|
|
20
24
|
import { useFieldControl } from "../composables/useField"
|
|
21
25
|
import { useMergedAttrs } from "../composables/useMergedClass"
|
|
22
|
-
import { joinCells, splitCode, type OtpCells } from "./otp"
|
|
26
|
+
import { groupBreaks, joinCells, splitCode, upperCells, type OtpCells } from "./otp"
|
|
23
27
|
|
|
24
28
|
const props = withDefaults(
|
|
25
29
|
defineProps<{
|
|
@@ -32,11 +36,19 @@ const props = withDefaults(
|
|
|
32
36
|
mask?: boolean
|
|
33
37
|
/** Allow letters too (backup codes). Default: digits only (TOTP). */
|
|
34
38
|
alphanumeric?: boolean
|
|
39
|
+
/**
|
|
40
|
+
* Turn typed letters into capitals, and open a phone's keyboard in capitals.
|
|
41
|
+
* Default: on with `alphanumeric`, where codes are printed in capitals and
|
|
42
|
+
* compared without regard to case; pass `false` for a case-sensitive code.
|
|
43
|
+
*/
|
|
44
|
+
uppercase?: boolean
|
|
45
|
+
/** Draw a separator after every `group` cells (e.g. 3 for "123-456"). */
|
|
46
|
+
group?: number
|
|
35
47
|
/** Error state — tints the cells red (e.g. wrong code). */
|
|
36
48
|
invalid?: boolean
|
|
37
49
|
size?: "sm" | "md" | "lg"
|
|
38
50
|
}>(),
|
|
39
|
-
{ length: 6, size: "md", alphanumeric: false },
|
|
51
|
+
{ length: 6, size: "md", alphanumeric: false, uppercase: undefined },
|
|
40
52
|
)
|
|
41
53
|
|
|
42
54
|
const emit = defineEmits<{
|
|
@@ -45,6 +57,8 @@ const emit = defineEmits<{
|
|
|
45
57
|
(e: "complete", value: string): void
|
|
46
58
|
}>()
|
|
47
59
|
|
|
60
|
+
const upper = computed(() => props.alphanumeric && (props.uppercase ?? true))
|
|
61
|
+
|
|
48
62
|
// reka models the value as an array of per-cell strings; we bridge to a single
|
|
49
63
|
// string at the boundary so callers never touch the array shape.
|
|
50
64
|
//
|
|
@@ -52,7 +66,7 @@ const emit = defineEmits<{
|
|
|
52
66
|
// string on every render: clearing a middle cell leaves a gap the string cannot
|
|
53
67
|
// express, and re-splitting it shifted every later digit one cell left. The
|
|
54
68
|
// cells are only rebuilt when the model changes from outside.
|
|
55
|
-
const local = ref<
|
|
69
|
+
const local = ref<OtpCells>(splitCode(props.modelValue, props.length))
|
|
56
70
|
let emitted = props.modelValue ?? ""
|
|
57
71
|
watch(
|
|
58
72
|
() => props.modelValue ?? "",
|
|
@@ -68,11 +82,13 @@ watch(
|
|
|
68
82
|
local.value = local.value.slice(0, length)
|
|
69
83
|
},
|
|
70
84
|
)
|
|
85
|
+
// Typed as reka's text-mode array; numeric mode holds numbers and holes, which
|
|
86
|
+
// the helpers in ./otp are written for.
|
|
71
87
|
const cells = computed<string[]>({
|
|
72
|
-
get: () => local.value,
|
|
88
|
+
get: () => local.value as string[],
|
|
73
89
|
set: (arr) => {
|
|
74
|
-
local.value = arr
|
|
75
|
-
emitted = joinCells(
|
|
90
|
+
local.value = upper.value ? upperCells(arr) : arr
|
|
91
|
+
emitted = joinCells(local.value)
|
|
76
92
|
emit("update:modelValue", emitted)
|
|
77
93
|
},
|
|
78
94
|
})
|
|
@@ -84,23 +100,53 @@ const field = useFieldControl(() => ({
|
|
|
84
100
|
}))
|
|
85
101
|
|
|
86
102
|
function onComplete(arr: OtpCells) {
|
|
87
|
-
emit("complete", joinCells(arr))
|
|
103
|
+
emit("complete", joinCells(upper.value ? upperCells(arr) : arr))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const breaks = computed(() => groupBreaks(props.length, props.group))
|
|
107
|
+
|
|
108
|
+
/*
|
|
109
|
+
* Backspace, as a phone's keyboard sends it.
|
|
110
|
+
*
|
|
111
|
+
* reka handles Backspace on keydown, but an on-screen keyboard reports most
|
|
112
|
+
* keys as "Unidentified", so its handler never ran there: the browser deleted
|
|
113
|
+
* the character itself, and reka read the now-empty cell as typed input and
|
|
114
|
+
* moved the caret FORWARD — and an empty cell could not be backed out of at
|
|
115
|
+
* all. `beforeinput` names the deletion on every keyboard, so it is done here
|
|
116
|
+
* the way a hardware Backspace does it: clear this cell, or step back into
|
|
117
|
+
* the previous one and clear that. A hardware key never reaches this, since
|
|
118
|
+
* reka's keydown handler cancels it first.
|
|
119
|
+
*/
|
|
120
|
+
const root = ref<{ $el: HTMLElement } | null>(null)
|
|
121
|
+
function onBeforeInput(event: InputEvent, index: number) {
|
|
122
|
+
if (event.inputType !== "deleteContentBackward") return
|
|
123
|
+
event.preventDefault()
|
|
124
|
+
const target = event.target as HTMLInputElement
|
|
125
|
+
const next = [...local.value]
|
|
126
|
+
let clear = index
|
|
127
|
+
if (!target.value && index > 0) {
|
|
128
|
+
clear = index - 1
|
|
129
|
+
root.value?.$el.querySelectorAll("input")[clear]?.focus()
|
|
130
|
+
}
|
|
131
|
+
// Emptied the way reka empties a cell itself: numeric mode leaves a hole.
|
|
132
|
+
next[clear] = props.alphanumeric ? "" : undefined
|
|
133
|
+
cells.value = next as string[]
|
|
88
134
|
}
|
|
89
135
|
|
|
90
136
|
const cellSize = {
|
|
91
|
-
sm: "
|
|
92
|
-
md: "
|
|
93
|
-
lg: "
|
|
137
|
+
sm: "max-w-9 text-base",
|
|
138
|
+
md: "max-w-11 text-lg",
|
|
139
|
+
lg: "max-w-13 text-xl",
|
|
94
140
|
}
|
|
95
141
|
|
|
96
|
-
// The boxes sit on a fixed gap that a narrow form has to tighten.
|
|
97
142
|
const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
98
|
-
"flex items-center gap-2",
|
|
143
|
+
"flex min-w-0 max-w-full items-center gap-1.5 sm:gap-2",
|
|
99
144
|
)
|
|
100
145
|
</script>
|
|
101
146
|
|
|
102
147
|
<template>
|
|
103
148
|
<PinInputRoot
|
|
149
|
+
ref="root"
|
|
104
150
|
v-model="cells"
|
|
105
151
|
:type="alphanumeric ? 'text' : 'number'"
|
|
106
152
|
:mask="mask"
|
|
@@ -110,21 +156,31 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
110
156
|
v-bind="rest"
|
|
111
157
|
@complete="onComplete"
|
|
112
158
|
>
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
159
|
+
<template v-for="i in length" :key="i">
|
|
160
|
+
<PinInputInput
|
|
161
|
+
:index="i - 1"
|
|
162
|
+
:id="i === 1 ? field.id : undefined"
|
|
163
|
+
:aria-invalid="field.invalid || undefined"
|
|
164
|
+
:aria-describedby="field.describedBy"
|
|
165
|
+
:autocapitalize="upper ? 'characters' : 'none'"
|
|
166
|
+
autocorrect="off"
|
|
167
|
+
:spellcheck="false"
|
|
168
|
+
:class="[
|
|
169
|
+
cellSize[size],
|
|
170
|
+
'aspect-square h-auto min-w-0 flex-1 basis-0 p-0',
|
|
171
|
+
'rounded-control border bg-surface-soft text-center font-semibold text-ink caret-brand',
|
|
172
|
+
'outline-none transition-colors duration-[var(--duration-fast)]',
|
|
173
|
+
'focus:border-brand focus:ring-2 focus:ring-ring',
|
|
174
|
+
'disabled:cursor-not-allowed disabled:opacity-55',
|
|
175
|
+
field.invalid ? 'border-danger focus:border-danger focus:ring-danger-soft' : 'border-line',
|
|
176
|
+
]"
|
|
177
|
+
@beforeinput="onBeforeInput($event as InputEvent, i - 1)"
|
|
178
|
+
/>
|
|
179
|
+
<span
|
|
180
|
+
v-if="breaks.has(i - 1)"
|
|
181
|
+
aria-hidden="true"
|
|
182
|
+
class="h-0.5 w-2 shrink-0 rounded-full bg-muted opacity-60"
|
|
183
|
+
/>
|
|
184
|
+
</template>
|
|
129
185
|
</PinInputRoot>
|
|
130
186
|
</template>
|
|
@@ -18,7 +18,7 @@ const props = defineProps<{ value: string; label?: string; disabled?: boolean }>
|
|
|
18
18
|
// options needs to close up — `class="gap-1"` should win over the default.
|
|
19
19
|
const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
|
|
20
20
|
[
|
|
21
|
-
"group inline-flex cursor-pointer items-center gap-2 text-sm text-ink",
|
|
21
|
+
"group/radio inline-flex cursor-pointer items-center gap-2 text-sm text-ink",
|
|
22
22
|
props.disabled ? "cursor-not-allowed opacity-55" : "",
|
|
23
23
|
].join(" "),
|
|
24
24
|
)
|
|
@@ -32,7 +32,7 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(() =>
|
|
|
32
32
|
<RadioGroupItem
|
|
33
33
|
:value="value"
|
|
34
34
|
:disabled="disabled"
|
|
35
|
-
class="flex size-[18px] shrink-0 items-center justify-center rounded-full border border-line-strong bg-surface-soft outline-none transition-[color,border-color,box-shadow,scale] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] not-data-[state=checked]:group-hover:border-brand active:scale-90 motion-reduce:active:scale-100 focus-visible:ring-2 focus-visible:ring-ring data-[state=checked]:border-brand disabled:cursor-not-allowed disabled:opacity-55"
|
|
35
|
+
class="flex size-[18px] shrink-0 items-center justify-center rounded-full border border-line-strong bg-surface-soft outline-none transition-[color,border-color,box-shadow,scale] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] not-data-[state=checked]:group-hover/radio:border-brand active:scale-90 motion-reduce:active:scale-100 focus-visible:ring-2 focus-visible:ring-ring data-[state=checked]:border-brand disabled:cursor-not-allowed disabled:opacity-55"
|
|
36
36
|
>
|
|
37
37
|
<RadioGroupIndicator
|
|
38
38
|
class="flex data-[state=checked]:animate-[indicator-in_140ms_var(--ease-emphasized)]"
|
|
@@ -45,11 +45,11 @@ const { class: rootClass, attrs: rest } = useMergedAttrs(
|
|
|
45
45
|
<label
|
|
46
46
|
v-for="opt in options"
|
|
47
47
|
:key="opt.value"
|
|
48
|
-
class="group inline-flex cursor-pointer items-center gap-2 text-sm text-ink"
|
|
48
|
+
class="group/radio inline-flex cursor-pointer items-center gap-2 text-sm text-ink"
|
|
49
49
|
>
|
|
50
50
|
<RadioGroupItem
|
|
51
51
|
:value="opt.value"
|
|
52
|
-
class="flex size-[18px] items-center justify-center rounded-full border border-line-strong bg-surface-soft outline-none transition-[color,border-color,box-shadow,scale] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] not-data-[state=checked]:group-hover:border-brand active:scale-90 motion-reduce:active:scale-100 focus-visible:ring-2 focus-visible:ring-ring data-[state=checked]:border-brand disabled:cursor-not-allowed disabled:opacity-55"
|
|
52
|
+
class="flex size-[18px] items-center justify-center rounded-full border border-line-strong bg-surface-soft outline-none transition-[color,border-color,box-shadow,scale] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] not-data-[state=checked]:group-hover/radio:border-brand active:scale-90 motion-reduce:active:scale-100 focus-visible:ring-2 focus-visible:ring-ring data-[state=checked]:border-brand disabled:cursor-not-allowed disabled:opacity-55"
|
|
53
53
|
>
|
|
54
54
|
<RadioGroupIndicator
|
|
55
55
|
class="flex data-[state=checked]:animate-[indicator-in_140ms_var(--ease-emphasized)]"
|
|
@@ -33,9 +33,9 @@ const slots = useSlots()
|
|
|
33
33
|
const labelled = computed(() => Boolean(props.label || props.description || slots.default))
|
|
34
34
|
|
|
35
35
|
const TRACK =
|
|
36
|
-
"group inline-flex h-5 w-9 shrink-0 items-center rounded-pill border border-line bg-surface-soft px-0.5 outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-ring data-[state=checked]:border-transparent data-[state=checked]:bg-brand disabled:cursor-not-allowed disabled:opacity-55"
|
|
36
|
+
"group/switch inline-flex h-5 w-9 shrink-0 items-center rounded-pill border border-line bg-surface-soft px-0.5 outline-none transition-colors duration-[var(--duration-fast)] focus-visible:ring-2 focus-visible:ring-ring data-[state=checked]:border-transparent data-[state=checked]:bg-brand disabled:cursor-not-allowed disabled:opacity-55"
|
|
37
37
|
const THUMB =
|
|
38
|
-
"h-3.5 w-3.5 rounded-full bg-ink shadow transition-[translate,width,background-color] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] group-active:w-5 group-data-[state=checked]:translate-x-4 group-data-[state=checked]:bg-ink-inverse group-data-[state=checked]:group-active:translate-x-2.5 motion-reduce:group-active:w-3.5"
|
|
38
|
+
"h-3.5 w-3.5 rounded-full bg-ink shadow transition-[translate,width,background-color] duration-[var(--duration-fast)] ease-[var(--ease-emphasized)] group-active/switch:w-5 group-data-[state=checked]/switch:translate-x-4 group-data-[state=checked]/switch:bg-ink-inverse group-data-[state=checked]/switch:group-active/switch:translate-x-2.5 motion-reduce:group-active/switch:w-3.5"
|
|
39
39
|
|
|
40
40
|
// Bare, the switch is the root, so a consumer asking for a bigger track must not
|
|
41
41
|
// have to depend on stylesheet order to get it. With text, the row is the root
|