@leavepulse/ui 0.37.6 → 0.37.7
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/{LpDatePicker-BPbvu3cZ.js → LpDatePicker-CwOToxGq.js} +8 -7
- package/dist/chunks/LpTimeField-K6nAGboX.js +90 -0
- package/dist/component-names.d.ts +1 -1
- package/dist/components/LpDatePicker.vue.js +1 -1
- package/dist/components/LpTimeField.vue.d.ts +24 -0
- package/dist/components/LpTimeField.vue.js +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +69 -67
- package/package.json +1 -1
- package/src/component-names.ts +1 -0
- package/src/components/LpDatePicker.vue +11 -9
- package/src/components/LpTimeField.vue +89 -0
- package/src/index.ts +1 -0
|
@@ -3,13 +3,13 @@ import { PopoverRoot, PopoverTrigger, PopoverPortal, PopoverContent } from "reka
|
|
|
3
3
|
import { POPOVER_PANEL } from "../components/dropdown.js";
|
|
4
4
|
import { _ as _sfc_main$2 } from "./LpCalendar-B7Ko5RdR.js";
|
|
5
5
|
import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
|
|
6
|
+
import { _ as _sfc_main$3 } from "./LpTimeField-K6nAGboX.js";
|
|
6
7
|
const _hoisted_1 = ["disabled"];
|
|
7
8
|
const _hoisted_2 = ["onKeydown"];
|
|
8
9
|
const _hoisted_3 = {
|
|
9
10
|
key: 0,
|
|
10
11
|
class: "flex items-center gap-2 border-t border-line px-3 py-2"
|
|
11
12
|
};
|
|
12
|
-
const _hoisted_4 = ["value", "disabled"];
|
|
13
13
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
14
14
|
__name: "LpDatePicker",
|
|
15
15
|
props: {
|
|
@@ -133,13 +133,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
133
133
|
size: 15,
|
|
134
134
|
class: "shrink-0 text-muted"
|
|
135
135
|
}),
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
value: minute.value,
|
|
136
|
+
createVNode(_sfc_main$3, {
|
|
137
|
+
"model-value": minute.value || void 0,
|
|
139
138
|
disabled: !day.value,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
icon: false,
|
|
140
|
+
size: "sm",
|
|
141
|
+
class: "flex-1",
|
|
142
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = (at) => onTime(at || ""))
|
|
143
|
+
}, null, 8, ["model-value", "disabled"]),
|
|
143
144
|
createElementVNode("button", {
|
|
144
145
|
type: "button",
|
|
145
146
|
class: "shrink-0 rounded-control px-2 py-1 text-xs text-muted transition-colors hover:text-ink",
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { defineComponent, computed, openBlock, createBlock, unref, normalizeClass, withCtx, createCommentVNode, createElementBlock, Fragment, renderList, createTextVNode, toDisplayString } from "vue";
|
|
2
|
+
import { Time } from "@internationalized/date";
|
|
3
|
+
import { TimeFieldRoot, TimeFieldInput } from "reka-ui";
|
|
4
|
+
import { _ as _sfc_main$1 } from "./LpIcon-CCnX5_2j.js";
|
|
5
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
6
|
+
__name: "LpTimeField",
|
|
7
|
+
props: {
|
|
8
|
+
modelValue: {},
|
|
9
|
+
disabled: { type: Boolean },
|
|
10
|
+
invalid: { type: Boolean },
|
|
11
|
+
size: { default: "md" },
|
|
12
|
+
hourCycle: { default: 24 },
|
|
13
|
+
locale: {},
|
|
14
|
+
icon: { type: Boolean, default: true }
|
|
15
|
+
},
|
|
16
|
+
emits: ["update:modelValue"],
|
|
17
|
+
setup(__props, { emit: __emit }) {
|
|
18
|
+
const props = __props;
|
|
19
|
+
const emit = __emit;
|
|
20
|
+
const value = computed(() => {
|
|
21
|
+
const match = /^(\d{2}):(\d{2})/.exec(props.modelValue || "");
|
|
22
|
+
return match ? new Time(Number(match[1]), Number(match[2])) : void 0;
|
|
23
|
+
});
|
|
24
|
+
function onUpdate(next) {
|
|
25
|
+
if (!next || typeof next !== "object" || !("hour" in next) || !("minute" in next)) {
|
|
26
|
+
emit("update:modelValue", void 0);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
30
|
+
emit("update:modelValue", `${pad(next.hour)}:${pad(next.minute)}`);
|
|
31
|
+
}
|
|
32
|
+
const shellSize = {
|
|
33
|
+
sm: "h-(--size-control-sm) text-xs",
|
|
34
|
+
md: "h-(--size-control-md) text-sm",
|
|
35
|
+
lg: "h-(--size-control-lg) text-sm"
|
|
36
|
+
};
|
|
37
|
+
return (_ctx, _cache) => {
|
|
38
|
+
return openBlock(), createBlock(unref(TimeFieldRoot), {
|
|
39
|
+
"model-value": value.value,
|
|
40
|
+
"hour-cycle": __props.hourCycle,
|
|
41
|
+
locale: __props.locale,
|
|
42
|
+
granularity: "minute",
|
|
43
|
+
disabled: __props.disabled,
|
|
44
|
+
class: normalizeClass(["flex w-full items-center gap-0.5 rounded-control border bg-surface-soft px-3 text-ink transition-colors duration-[var(--duration-fast)] focus-within:ring-2 focus-within:ring-ring data-[disabled]:cursor-not-allowed data-[disabled]:opacity-55", [
|
|
45
|
+
shellSize[__props.size],
|
|
46
|
+
__props.invalid ? "border-danger focus-within:ring-danger-soft" : "border-line focus-within:border-brand"
|
|
47
|
+
]]),
|
|
48
|
+
"onUpdate:modelValue": onUpdate
|
|
49
|
+
}, {
|
|
50
|
+
default: withCtx(({ segments }) => [
|
|
51
|
+
__props.icon ? (openBlock(), createBlock(_sfc_main$1, {
|
|
52
|
+
key: 0,
|
|
53
|
+
name: "lucide:clock",
|
|
54
|
+
size: 15,
|
|
55
|
+
class: "mr-1.5 shrink-0 text-muted"
|
|
56
|
+
})) : createCommentVNode("", true),
|
|
57
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(segments, (item) => {
|
|
58
|
+
return openBlock(), createElementBlock(Fragment, {
|
|
59
|
+
key: item.part
|
|
60
|
+
}, [
|
|
61
|
+
item.part === "literal" ? (openBlock(), createBlock(unref(TimeFieldInput), {
|
|
62
|
+
key: 0,
|
|
63
|
+
part: item.part,
|
|
64
|
+
class: "text-muted"
|
|
65
|
+
}, {
|
|
66
|
+
default: withCtx(() => [
|
|
67
|
+
createTextVNode(toDisplayString(item.value), 1)
|
|
68
|
+
]),
|
|
69
|
+
_: 2
|
|
70
|
+
}, 1032, ["part"])) : (openBlock(), createBlock(unref(TimeFieldInput), {
|
|
71
|
+
key: 1,
|
|
72
|
+
part: item.part,
|
|
73
|
+
class: "rounded-sm px-0.5 tabular-nums outline-none focus:bg-brand-soft focus:text-brand data-[placeholder]:text-muted"
|
|
74
|
+
}, {
|
|
75
|
+
default: withCtx(() => [
|
|
76
|
+
createTextVNode(toDisplayString(item.value), 1)
|
|
77
|
+
]),
|
|
78
|
+
_: 2
|
|
79
|
+
}, 1032, ["part"]))
|
|
80
|
+
], 64);
|
|
81
|
+
}), 128))
|
|
82
|
+
]),
|
|
83
|
+
_: 1
|
|
84
|
+
}, 8, ["model-value", "hour-cycle", "locale", "disabled", "class"]);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
export {
|
|
89
|
+
_sfc_main as _
|
|
90
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const COMPONENT_NAMES: readonly ["LayoutCanvas", "LayoutNode", "LpActionBar", "LpAddressInput", "LpAlert", "LpAppShell", "LpAutocomplete", "LpAvatar", "LpBadge", "LpBreadcrumbs", "LpButton", "LpCalendar", "LpCard", "LpChart", "LpCheckbox", "LpCodeBlock", "LpColorPicker", "LpCommandPalette", "LpConfirmDialog", "LpContextMenu", "LpDatePicker", "LpDisclosure", "LpDivider", "LpDrawer", "LpDropdownMenu", "LpDropzone", "LpEmptyState", "LpFileTree", "LpFileTreeNode", "LpFormField", "LpIcon", "LpImageEditor", "LpInfraNode", "LpInput", "LpLaneNode", "LpLightbox", "LpLink", "LpLogViewer", "LpMapPicker", "LpMediaGallery", "LpModal", "LpModalNav", "LpNotificationBell", "LpNumberField", "LpNumberFlow", "LpOtpInput", "LpPagination", "LpPasswordInput", "LpPhoneInput", "LpPie", "LpPopover", "LpProgress", "LpRadio", "LpRadioGroup", "LpRollingText", "LpScrollArea", "LpSection", "LpSegmented", "LpSelect", "LpServiceNode", "LpShift", "LpShortcutsDialog", "LpSidebar", "LpSidebarNav", "LpSkeleton", "LpSlider", "LpSparkline", "LpStat", "LpStepper", "LpSwitch", "LpTable", "LpTableOfContents", "LpTabs", "LpTextarea", "LpThemeSwitcher", "LpTilt", "LpToaster", "LpTooltip", "LpTopologyCanvas", "LpUptimeBar", "LpWaypointEdge"];
|
|
1
|
+
export declare const COMPONENT_NAMES: readonly ["LayoutCanvas", "LayoutNode", "LpActionBar", "LpAddressInput", "LpAlert", "LpAppShell", "LpAutocomplete", "LpAvatar", "LpBadge", "LpBreadcrumbs", "LpButton", "LpCalendar", "LpCard", "LpChart", "LpCheckbox", "LpCodeBlock", "LpColorPicker", "LpCommandPalette", "LpConfirmDialog", "LpContextMenu", "LpDatePicker", "LpDisclosure", "LpDivider", "LpDrawer", "LpDropdownMenu", "LpDropzone", "LpEmptyState", "LpFileTree", "LpFileTreeNode", "LpFormField", "LpIcon", "LpImageEditor", "LpInfraNode", "LpInput", "LpLaneNode", "LpLightbox", "LpLink", "LpLogViewer", "LpMapPicker", "LpMediaGallery", "LpModal", "LpModalNav", "LpNotificationBell", "LpNumberField", "LpNumberFlow", "LpOtpInput", "LpPagination", "LpPasswordInput", "LpPhoneInput", "LpPie", "LpPopover", "LpProgress", "LpRadio", "LpRadioGroup", "LpRollingText", "LpScrollArea", "LpSection", "LpSegmented", "LpSelect", "LpServiceNode", "LpShift", "LpShortcutsDialog", "LpSidebar", "LpSidebarNav", "LpSkeleton", "LpSlider", "LpSparkline", "LpStat", "LpStepper", "LpSwitch", "LpTable", "LpTableOfContents", "LpTabs", "LpTextarea", "LpThemeSwitcher", "LpTilt", "LpTimeField", "LpToaster", "LpTooltip", "LpTopologyCanvas", "LpUptimeBar", "LpWaypointEdge"];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
/** Selected time "HH:mm" (v-model). */
|
|
3
|
+
modelValue?: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
invalid?: boolean;
|
|
6
|
+
size?: "sm" | "md" | "lg";
|
|
7
|
+
/** 24 or 12-hour clock, independent of the browser locale. */
|
|
8
|
+
hourCycle?: 12 | 24;
|
|
9
|
+
/** Locale for segment order and the AM/PM marker in 12-hour mode. */
|
|
10
|
+
locale?: string;
|
|
11
|
+
/** Show the clock icon at the start of the field. */
|
|
12
|
+
icon?: boolean;
|
|
13
|
+
};
|
|
14
|
+
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
|
|
15
|
+
"update:modelValue": (value: string | undefined) => any;
|
|
16
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
17
|
+
"onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
|
|
18
|
+
}>, {
|
|
19
|
+
size: "sm" | "md" | "lg";
|
|
20
|
+
icon: boolean;
|
|
21
|
+
hourCycle: 12 | 24;
|
|
22
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
23
|
+
declare const _default: typeof __VLS_export;
|
|
24
|
+
export default _default;
|
package/dist/index.d.ts
CHANGED
|
@@ -62,6 +62,7 @@ export { default as LpModalNav } from './components/LpModalNav.vue';
|
|
|
62
62
|
export { default as LpNotificationBell } from './components/LpNotificationBell.vue';
|
|
63
63
|
export type { NotificationItem, NotificationLabels, } from './components/LpNotificationBell.vue';
|
|
64
64
|
export { default as LpNumberField } from './components/LpNumberField.vue';
|
|
65
|
+
export { default as LpTimeField } from './components/LpTimeField.vue';
|
|
65
66
|
export { default as LpNumberFlow } from './components/LpNumberFlow.vue';
|
|
66
67
|
export { default as LpOtpInput } from './components/LpOtpInput.vue';
|
|
67
68
|
export { default as LpPagination } from './components/LpPagination.vue';
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import { DEFAULT_SWATCHES, clampHsv, formatColor, hsvToHsl, hsvToRgb, isLight, n
|
|
|
21
21
|
import { default as default3 } from "./components/LpCommandPalette.vue.js";
|
|
22
22
|
import { _ as _17 } from "./chunks/LpConfirmDialog-BH7az_E7.js";
|
|
23
23
|
import { _ as _18 } from "./chunks/LpContextMenu-CwW1QXe_.js";
|
|
24
|
-
import { _ as _19 } from "./chunks/LpDatePicker-
|
|
24
|
+
import { _ as _19 } from "./chunks/LpDatePicker-CwOToxGq.js";
|
|
25
25
|
import { _ as _20 } from "./chunks/LpDisclosure-ChQYmjlR.js";
|
|
26
26
|
import { _ as _21 } from "./chunks/LpDivider-CUX46KR0.js";
|
|
27
27
|
import { _ as _22 } from "./chunks/LpDrawer-E67O8fFP.js";
|
|
@@ -44,43 +44,44 @@ import { _ as _34 } from "./chunks/LpModal-Dq_qXN8-.js";
|
|
|
44
44
|
import { _ as _35 } from "./chunks/LpModalNav-CqxXbTkl.js";
|
|
45
45
|
import { _ as _36 } from "./chunks/LpNotificationBell-DyGGsMAM.js";
|
|
46
46
|
import { _ as _37 } from "./chunks/LpNumberField-CWuX08iX.js";
|
|
47
|
-
import { _ as _38 } from "./chunks/
|
|
48
|
-
import { _ as _39 } from "./chunks/
|
|
49
|
-
import { _ as _40 } from "./chunks/
|
|
50
|
-
import { _ as _41 } from "./chunks/
|
|
51
|
-
import { _ as _42 } from "./chunks/
|
|
52
|
-
import { _ as _43 } from "./chunks/
|
|
47
|
+
import { _ as _38 } from "./chunks/LpTimeField-K6nAGboX.js";
|
|
48
|
+
import { _ as _39 } from "./chunks/LpNumberFlow-amWYaeuA.js";
|
|
49
|
+
import { _ as _40 } from "./chunks/LpOtpInput-y2v-pmiN.js";
|
|
50
|
+
import { _ as _41 } from "./chunks/LpPagination-5FxjmmB5.js";
|
|
51
|
+
import { _ as _42 } from "./chunks/LpPasswordInput--sjYCkLS.js";
|
|
52
|
+
import { _ as _43 } from "./chunks/LpPie-D6OnzwlJ.js";
|
|
53
|
+
import { _ as _44 } from "./chunks/LpPhoneInput-BDSKVl_z.js";
|
|
53
54
|
import { flagEmoji, loadCountries, matchCountryByValue } from "./components/countries.js";
|
|
54
|
-
import { _ as
|
|
55
|
-
import { _ as
|
|
56
|
-
import { _ as
|
|
57
|
-
import { _ as
|
|
58
|
-
import { _ as
|
|
59
|
-
import { _ as
|
|
60
|
-
import { _ as
|
|
61
|
-
import { _ as
|
|
62
|
-
import { _ as
|
|
63
|
-
import { _ as
|
|
64
|
-
import { _ as
|
|
55
|
+
import { _ as _45 } from "./chunks/LpPopover-8268UmlC.js";
|
|
56
|
+
import { _ as _46 } from "./chunks/LpProgress-Btq5W4Ut.js";
|
|
57
|
+
import { _ as _47 } from "./chunks/LpRadio-B5AfqTpZ.js";
|
|
58
|
+
import { _ as _48 } from "./chunks/LpRadioGroup-xPIuVDO_.js";
|
|
59
|
+
import { _ as _49 } from "./chunks/LpRollingText-CM5gkSeF.js";
|
|
60
|
+
import { _ as _50 } from "./chunks/LpScrollArea-D8xyKXcF.js";
|
|
61
|
+
import { _ as _51 } from "./chunks/LpSegmented-fV0Sk92p.js";
|
|
62
|
+
import { _ as _52 } from "./chunks/LpSection-aM6J_u51.js";
|
|
63
|
+
import { _ as _53 } from "./chunks/LpSelect-ANIVtrpM.js";
|
|
64
|
+
import { _ as _54 } from "./chunks/LpServiceNode-D8uJ8sGk.js";
|
|
65
|
+
import { _ as _55 } from "./chunks/LpShift-DXNsauQZ.js";
|
|
65
66
|
import { default as default6 } from "./components/LpShortcutsDialog.vue.js";
|
|
66
|
-
import { _ as
|
|
67
|
-
import { _ as
|
|
68
|
-
import { _ as
|
|
69
|
-
import { _ as
|
|
70
|
-
import { _ as
|
|
71
|
-
import { _ as
|
|
72
|
-
import { _ as
|
|
67
|
+
import { _ as _56 } from "./chunks/LpSidebar-B1wLj-B2.js";
|
|
68
|
+
import { _ as _57 } from "./chunks/LpSkeleton-CTI-vBgW.js";
|
|
69
|
+
import { _ as _58 } from "./chunks/LpSlider-BwNIBkAK.js";
|
|
70
|
+
import { _ as _59 } from "./chunks/LpSparkline-C6xQ2dwv.js";
|
|
71
|
+
import { _ as _60 } from "./chunks/LpStat-CQaW8R--.js";
|
|
72
|
+
import { _ as _61 } from "./chunks/LpStepper-Bk-XaQYU.js";
|
|
73
|
+
import { _ as _62 } from "./chunks/LpSwitch-xgnRU2k0.js";
|
|
73
74
|
import { default as default7 } from "./components/LpTable.vue.js";
|
|
74
|
-
import { _ as
|
|
75
|
-
import { _ as
|
|
76
|
-
import { _ as
|
|
75
|
+
import { _ as _63 } from "./chunks/LpTableOfContents-CjvxPMpU.js";
|
|
76
|
+
import { _ as _64 } from "./chunks/LpTabs-Cefe_lys.js";
|
|
77
|
+
import { _ as _65 } from "./chunks/LpTextarea-t7F6gv8E.js";
|
|
77
78
|
import { p as presets, a as parseTheme, s as serializeTheme } from "./chunks/LpThemeSwitcher-Cue-myST.js";
|
|
78
|
-
import { D, _ as
|
|
79
|
-
import { _ as
|
|
80
|
-
import { _ as
|
|
81
|
-
import { _ as
|
|
82
|
-
import { _ as
|
|
83
|
-
import { _ as
|
|
79
|
+
import { D, _ as _66, N, T, b, c, d, e, f, g, i, l, h, j, n, r, t, k, m, u, v } from "./chunks/LpThemeSwitcher-Cue-myST.js";
|
|
80
|
+
import { _ as _67 } from "./chunks/LpTilt-DuyKbpkA.js";
|
|
81
|
+
import { _ as _68 } from "./chunks/LpToaster-gDB1EaU3.js";
|
|
82
|
+
import { _ as _69 } from "./chunks/LpTooltip-hCLPAqMG.js";
|
|
83
|
+
import { _ as _70 } from "./chunks/LpTopologyCanvas-Cm1L39uL.js";
|
|
84
|
+
import { _ as _71 } from "./chunks/LpUptimeBar-DvAMno0S.js";
|
|
84
85
|
import { deserializeLayout, serializeLayout } from "./layout/tree.js";
|
|
85
86
|
import { addLeaf, addTab, countBlocks, countLeaves, makeLayout, moveLeaf, removeBlock, removeLeaf, reorderTab, resizeAt, setActiveTab } from "./layout/tree.js";
|
|
86
87
|
import { blockTitle, defineBlocks } from "./layout/registry.js";
|
|
@@ -174,41 +175,42 @@ export {
|
|
|
174
175
|
_35 as LpModalNav,
|
|
175
176
|
_36 as LpNotificationBell,
|
|
176
177
|
_37 as LpNumberField,
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
178
|
+
_39 as LpNumberFlow,
|
|
179
|
+
_40 as LpOtpInput,
|
|
180
|
+
_41 as LpPagination,
|
|
181
|
+
_42 as LpPasswordInput,
|
|
182
|
+
_44 as LpPhoneInput,
|
|
183
|
+
_43 as LpPie,
|
|
184
|
+
_45 as LpPopover,
|
|
185
|
+
_46 as LpProgress,
|
|
186
|
+
_47 as LpRadio,
|
|
187
|
+
_48 as LpRadioGroup,
|
|
188
|
+
_49 as LpRollingText,
|
|
189
|
+
_50 as LpScrollArea,
|
|
190
|
+
_52 as LpSection,
|
|
191
|
+
_51 as LpSegmented,
|
|
192
|
+
_53 as LpSelect,
|
|
193
|
+
_54 as LpServiceNode,
|
|
194
|
+
_55 as LpShift,
|
|
194
195
|
default6 as LpShortcutsDialog,
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
196
|
+
_56 as LpSidebar,
|
|
197
|
+
_57 as LpSkeleton,
|
|
198
|
+
_58 as LpSlider,
|
|
199
|
+
_59 as LpSparkline,
|
|
200
|
+
_60 as LpStat,
|
|
201
|
+
_61 as LpStepper,
|
|
202
|
+
_62 as LpSwitch,
|
|
202
203
|
default7 as LpTable,
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
_68 as
|
|
210
|
-
_69 as
|
|
211
|
-
_70 as
|
|
204
|
+
_63 as LpTableOfContents,
|
|
205
|
+
_64 as LpTabs,
|
|
206
|
+
_65 as LpTextarea,
|
|
207
|
+
_66 as LpThemeSwitcher,
|
|
208
|
+
_67 as LpTilt,
|
|
209
|
+
_38 as LpTimeField,
|
|
210
|
+
_68 as LpToaster,
|
|
211
|
+
_69 as LpTooltip,
|
|
212
|
+
_70 as LpTopologyCanvas,
|
|
213
|
+
_71 as LpUptimeBar,
|
|
212
214
|
N as NO_BACKDROP_ATTR,
|
|
213
215
|
OSM_TILES,
|
|
214
216
|
T as THEME_COOKIE,
|
package/package.json
CHANGED
package/src/component-names.ts
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
* min/max + isDisabled forwarded to the calendar. Themed like the other inputs.
|
|
7
7
|
*
|
|
8
8
|
* With `time`, the model carries a minute too ("YYYY-MM-DDTHH:mm") and the
|
|
9
|
-
* popover grows a time row under the calendar. Anything that
|
|
10
|
-
* rather than a day — an expiry, a scheduled start — would
|
|
11
|
-
* to a native `datetime-local`, which the browser paints in
|
|
12
|
-
* chrome, breaking the form it sits in. Picking a day keeps the time already
|
|
9
|
+
* popover grows a time row (LpTimeField) under the calendar. Anything that
|
|
10
|
+
* needs a moment rather than a day — an expiry, a scheduled start — would
|
|
11
|
+
* otherwise fall back to a native `datetime-local`, which the browser paints in
|
|
12
|
+
* its own locale and chrome, breaking the form it sits in. Picking a day keeps the time already
|
|
13
13
|
* chosen (default `defaultTime`), so the popover closes on the first click for
|
|
14
14
|
* the common case.
|
|
15
15
|
*/
|
|
@@ -18,6 +18,7 @@ import { computed, ref } from "vue"
|
|
|
18
18
|
import { POPOVER_PANEL } from "./dropdown"
|
|
19
19
|
import LpCalendar from "./LpCalendar.vue"
|
|
20
20
|
import LpIcon from "./LpIcon.vue"
|
|
21
|
+
import LpTimeField from "./LpTimeField.vue"
|
|
21
22
|
|
|
22
23
|
const props = withDefaults(
|
|
23
24
|
defineProps<{
|
|
@@ -152,12 +153,13 @@ function clear() {
|
|
|
152
153
|
/>
|
|
153
154
|
<div v-if="time" class="flex items-center gap-2 border-t border-line px-3 py-2">
|
|
154
155
|
<LpIcon name="lucide:clock" :size="15" class="shrink-0 text-muted" />
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
:value="minute"
|
|
156
|
+
<LpTimeField
|
|
157
|
+
:model-value="minute || undefined"
|
|
158
158
|
:disabled="!day"
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
:icon="false"
|
|
160
|
+
size="sm"
|
|
161
|
+
class="flex-1"
|
|
162
|
+
@update:model-value="(at) => onTime(at || '')"
|
|
161
163
|
/>
|
|
162
164
|
<button
|
|
163
165
|
type="button"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/*
|
|
3
|
+
* Time-of-day field: hour and minute segments, typed or stepped with the arrow
|
|
4
|
+
* keys (reka TimeField). The model is "HH:mm" (v-model), the same shape a
|
|
5
|
+
* native `<input type="time">` produces, so it drops into a form that used one.
|
|
6
|
+
*
|
|
7
|
+
* It exists because the native input is painted by the browser in the user's
|
|
8
|
+
* system locale — a 24-hour app shows "--:-- --" with an AM/PM segment, in the
|
|
9
|
+
* browser's chrome rather than the kit's. Here the clock is fixed by
|
|
10
|
+
* `hourCycle` (24 by default) and the segments are themed like every other
|
|
11
|
+
* field.
|
|
12
|
+
*/
|
|
13
|
+
import { Time } from "@internationalized/date"
|
|
14
|
+
import { TimeFieldInput, TimeFieldRoot } from "reka-ui"
|
|
15
|
+
import { computed } from "vue"
|
|
16
|
+
import LpIcon from "./LpIcon.vue"
|
|
17
|
+
|
|
18
|
+
const props = withDefaults(
|
|
19
|
+
defineProps<{
|
|
20
|
+
/** Selected time "HH:mm" (v-model). */
|
|
21
|
+
modelValue?: string
|
|
22
|
+
disabled?: boolean
|
|
23
|
+
invalid?: boolean
|
|
24
|
+
size?: "sm" | "md" | "lg"
|
|
25
|
+
/** 24 or 12-hour clock, independent of the browser locale. */
|
|
26
|
+
hourCycle?: 12 | 24
|
|
27
|
+
/** Locale for segment order and the AM/PM marker in 12-hour mode. */
|
|
28
|
+
locale?: string
|
|
29
|
+
/** Show the clock icon at the start of the field. */
|
|
30
|
+
icon?: boolean
|
|
31
|
+
}>(),
|
|
32
|
+
{ size: "md", hourCycle: 24, icon: true },
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
const emit = defineEmits<{
|
|
36
|
+
(e: "update:modelValue", value: string | undefined): void
|
|
37
|
+
}>()
|
|
38
|
+
|
|
39
|
+
const value = computed(() => {
|
|
40
|
+
const match = /^(\d{2}):(\d{2})/.exec(props.modelValue || "")
|
|
41
|
+
return match ? new Time(Number(match[1]), Number(match[2])) : undefined
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
function onUpdate(next: unknown) {
|
|
45
|
+
if (!next || typeof next !== "object" || !("hour" in next) || !("minute" in next)) {
|
|
46
|
+
emit("update:modelValue", undefined)
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
const pad = (n: unknown) => String(n).padStart(2, "0")
|
|
50
|
+
emit("update:modelValue", `${pad(next.hour)}:${pad(next.minute)}`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const shellSize = {
|
|
54
|
+
sm: "h-(--size-control-sm) text-xs",
|
|
55
|
+
md: "h-(--size-control-md) text-sm",
|
|
56
|
+
lg: "h-(--size-control-lg) text-sm",
|
|
57
|
+
}
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<TimeFieldRoot
|
|
62
|
+
v-slot="{ segments }"
|
|
63
|
+
:model-value="value"
|
|
64
|
+
:hour-cycle="hourCycle"
|
|
65
|
+
:locale="locale"
|
|
66
|
+
granularity="minute"
|
|
67
|
+
:disabled="disabled"
|
|
68
|
+
class="flex w-full items-center gap-0.5 rounded-control border bg-surface-soft px-3 text-ink transition-colors duration-[var(--duration-fast)] focus-within:ring-2 focus-within:ring-ring data-[disabled]:cursor-not-allowed data-[disabled]:opacity-55"
|
|
69
|
+
:class="[
|
|
70
|
+
shellSize[size],
|
|
71
|
+
invalid ? 'border-danger focus-within:ring-danger-soft' : 'border-line focus-within:border-brand',
|
|
72
|
+
]"
|
|
73
|
+
@update:model-value="onUpdate"
|
|
74
|
+
>
|
|
75
|
+
<LpIcon v-if="icon" name="lucide:clock" :size="15" class="mr-1.5 shrink-0 text-muted" />
|
|
76
|
+
<template v-for="item in segments" :key="item.part">
|
|
77
|
+
<TimeFieldInput v-if="item.part === 'literal'" :part="item.part" class="text-muted">
|
|
78
|
+
{{ item.value }}
|
|
79
|
+
</TimeFieldInput>
|
|
80
|
+
<TimeFieldInput
|
|
81
|
+
v-else
|
|
82
|
+
:part="item.part"
|
|
83
|
+
class="rounded-sm px-0.5 tabular-nums outline-none focus:bg-brand-soft focus:text-brand data-[placeholder]:text-muted"
|
|
84
|
+
>
|
|
85
|
+
{{ item.value }}
|
|
86
|
+
</TimeFieldInput>
|
|
87
|
+
</template>
|
|
88
|
+
</TimeFieldRoot>
|
|
89
|
+
</template>
|
package/src/index.ts
CHANGED
|
@@ -112,6 +112,7 @@ export type {
|
|
|
112
112
|
NotificationLabels,
|
|
113
113
|
} from "./components/LpNotificationBell.vue"
|
|
114
114
|
export { default as LpNumberField } from "./components/LpNumberField.vue"
|
|
115
|
+
export { default as LpTimeField } from "./components/LpTimeField.vue"
|
|
115
116
|
export { default as LpNumberFlow } from "./components/LpNumberFlow.vue"
|
|
116
117
|
export { default as LpOtpInput } from "./components/LpOtpInput.vue"
|
|
117
118
|
export { default as LpPagination } from "./components/LpPagination.vue"
|