@leavepulse/ui 0.37.6 → 0.37.8
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/assets/{LpImageEditor-BsSwej47.css → LpImageEditor-D-s8tNGO.css} +6 -6
- 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/LpImageEditor.vue.d.ts +27 -2
- package/dist/components/LpImageEditor.vue.js +9 -3
- 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/LpImageEditor.vue +22 -3
- package/src/components/LpTimeField.vue +89 -0
- package/src/index.ts +1 -0
|
@@ -2,22 +2,22 @@
|
|
|
2
2
|
/* The picture settles into the frame instead of appearing in it. Scale rather
|
|
3
3
|
than a slide: the frame is the fixed thing here and the image lives inside
|
|
4
4
|
it, so anything that moved would read as a crop that had shifted. */
|
|
5
|
-
.lp-editor__image[data-v-
|
|
6
|
-
animation: lp-editor-in-
|
|
5
|
+
.lp-editor__image[data-v-667d4388] {
|
|
6
|
+
animation: lp-editor-in-667d4388 var(--duration-slow) var(--ease-settle) both;
|
|
7
7
|
}
|
|
8
|
-
.lp-editor__image--waiting[data-v-
|
|
8
|
+
.lp-editor__image--waiting[data-v-667d4388] {
|
|
9
9
|
opacity: 0;
|
|
10
10
|
animation: none;
|
|
11
11
|
}
|
|
12
|
-
@keyframes lp-editor-in-
|
|
12
|
+
@keyframes lp-editor-in-667d4388 {
|
|
13
13
|
from {
|
|
14
14
|
opacity: 0;
|
|
15
15
|
scale: 1.04;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
@media (prefers-reduced-motion: reduce) {
|
|
19
|
-
.lp-editor__image[data-v-
|
|
20
|
-
.lp-editor__image--waiting[data-v-
|
|
19
|
+
.lp-editor__image[data-v-667d4388],
|
|
20
|
+
.lp-editor__image--waiting[data-v-667d4388] {
|
|
21
21
|
opacity: 1;
|
|
22
22
|
scale: 1;
|
|
23
23
|
animation: none;
|
|
@@ -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"];
|
|
@@ -15,7 +15,19 @@ declare const __VLS_export: import('vue').DefineComponent<{
|
|
|
15
15
|
aspect?: "free" | "square" | "4:3" | "3:4" | "16:9" | number;
|
|
16
16
|
/** Longest edge of the exported image. Larger sources are scaled down. */
|
|
17
17
|
maxEdge?: number;
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Encoding of the export; read the result's `blob.type` for the one used.
|
|
20
|
+
*
|
|
21
|
+
* JPEG, the default, is the smallest for photographs, the case this was
|
|
22
|
+
* built for. It has no alpha channel, though: a transparent PNG comes back
|
|
23
|
+
* with its background filled black, and a logo or an icon is ruined by the
|
|
24
|
+
* crop. "source" keeps the picture's own format where a canvas can write it
|
|
25
|
+
* (PNG, JPEG, WebP) and falls back to PNG for the ones it cannot (GIF, BMP,
|
|
26
|
+
* SVG), so transparency survives either way. An animated GIF still comes
|
|
27
|
+
* back as its first frame: a canvas holds one picture.
|
|
28
|
+
*/
|
|
29
|
+
type?: "image/jpeg" | "image/png" | "image/webp" | "source";
|
|
30
|
+
/** Quality of a lossy export (JPEG, WebP); PNG ignores it. */
|
|
19
31
|
quality?: number;
|
|
20
32
|
/**
|
|
21
33
|
* Labels for the toolbar. Defaulted in English rather than left blank: an
|
|
@@ -61,7 +73,19 @@ declare const __VLS_export: import('vue').DefineComponent<{
|
|
|
61
73
|
aspect?: "free" | "square" | "4:3" | "3:4" | "16:9" | number;
|
|
62
74
|
/** Longest edge of the exported image. Larger sources are scaled down. */
|
|
63
75
|
maxEdge?: number;
|
|
64
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* Encoding of the export; read the result's `blob.type` for the one used.
|
|
78
|
+
*
|
|
79
|
+
* JPEG, the default, is the smallest for photographs, the case this was
|
|
80
|
+
* built for. It has no alpha channel, though: a transparent PNG comes back
|
|
81
|
+
* with its background filled black, and a logo or an icon is ruined by the
|
|
82
|
+
* crop. "source" keeps the picture's own format where a canvas can write it
|
|
83
|
+
* (PNG, JPEG, WebP) and falls back to PNG for the ones it cannot (GIF, BMP,
|
|
84
|
+
* SVG), so transparency survives either way. An animated GIF still comes
|
|
85
|
+
* back as its first frame: a canvas holds one picture.
|
|
86
|
+
*/
|
|
87
|
+
type?: "image/jpeg" | "image/png" | "image/webp" | "source";
|
|
88
|
+
/** Quality of a lossy export (JPEG, WebP); PNG ignores it. */
|
|
65
89
|
quality?: number;
|
|
66
90
|
/**
|
|
67
91
|
* Labels for the toolbar. Defaulted in English rather than left blank: an
|
|
@@ -73,6 +97,7 @@ declare const __VLS_export: import('vue').DefineComponent<{
|
|
|
73
97
|
/** Fade the picture in when the editor first comes into view. */
|
|
74
98
|
animate?: boolean;
|
|
75
99
|
}> & Readonly<{}>, {
|
|
100
|
+
type: "image/jpeg" | "image/png" | "image/webp" | "source";
|
|
76
101
|
animate: boolean;
|
|
77
102
|
labels: Partial<Record<"rotateLeft" | "rotateRight" | "zoomIn" | "zoomOut" | "reset" | "canvas", string>>;
|
|
78
103
|
aspect: "free" | "square" | "4:3" | "3:4" | "16:9" | number;
|
|
@@ -7,7 +7,7 @@ import "reka-ui";
|
|
|
7
7
|
import { _ as _sfc_main$2 } from "../chunks/LpIcon-CCnX5_2j.js";
|
|
8
8
|
import { useMergedAttrs } from "../composables/useMergedClass.js";
|
|
9
9
|
import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper-1tPrXgE0.js";
|
|
10
|
-
import '../assets/LpImageEditor-
|
|
10
|
+
import '../assets/LpImageEditor-D-s8tNGO.css';const _hoisted_1 = ["aria-label"];
|
|
11
11
|
const _hoisted_2 = ["src"];
|
|
12
12
|
const _hoisted_3 = {
|
|
13
13
|
key: 0,
|
|
@@ -25,6 +25,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
25
25
|
file: {},
|
|
26
26
|
aspect: { default: "free" },
|
|
27
27
|
maxEdge: { default: 2400 },
|
|
28
|
+
type: { default: "image/jpeg" },
|
|
28
29
|
quality: { default: 0.9 },
|
|
29
30
|
labels: { default: () => ({}) },
|
|
30
31
|
animate: { type: Boolean, default: true }
|
|
@@ -164,9 +165,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
164
165
|
const readY = (turned ? centreX : centreY) - readH / 2;
|
|
165
166
|
ctx.drawImage(picture, readX, readY, readW, readH, -readW / 2, -readH / 2, readW, readH);
|
|
166
167
|
return await new Promise(
|
|
167
|
-
(resolve) => canvas.toBlob(resolve,
|
|
168
|
+
(resolve) => canvas.toBlob(resolve, outputType.value, props.quality)
|
|
168
169
|
);
|
|
169
170
|
}
|
|
171
|
+
const ENCODABLE = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
|
|
172
|
+
const outputType = computed(() => {
|
|
173
|
+
if (props.type !== "source") return props.type;
|
|
174
|
+
return ENCODABLE.has(props.file.type) ? props.file.type : "image/png";
|
|
175
|
+
});
|
|
170
176
|
function clamp(value, low, high) {
|
|
171
177
|
return Math.min(Math.max(value, low), Math.max(low, high));
|
|
172
178
|
}
|
|
@@ -357,7 +363,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
357
363
|
};
|
|
358
364
|
}
|
|
359
365
|
});
|
|
360
|
-
const LpImageEditor = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-
|
|
366
|
+
const LpImageEditor = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-667d4388"]]);
|
|
361
367
|
export {
|
|
362
368
|
LpImageEditor as default
|
|
363
369
|
};
|
|
@@ -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"
|
|
@@ -48,7 +48,19 @@ const props = withDefaults(
|
|
|
48
48
|
aspect?: "free" | "square" | "4:3" | "3:4" | "16:9" | number
|
|
49
49
|
/** Longest edge of the exported image. Larger sources are scaled down. */
|
|
50
50
|
maxEdge?: number
|
|
51
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Encoding of the export; read the result's `blob.type` for the one used.
|
|
53
|
+
*
|
|
54
|
+
* JPEG, the default, is the smallest for photographs, the case this was
|
|
55
|
+
* built for. It has no alpha channel, though: a transparent PNG comes back
|
|
56
|
+
* with its background filled black, and a logo or an icon is ruined by the
|
|
57
|
+
* crop. "source" keeps the picture's own format where a canvas can write it
|
|
58
|
+
* (PNG, JPEG, WebP) and falls back to PNG for the ones it cannot (GIF, BMP,
|
|
59
|
+
* SVG), so transparency survives either way. An animated GIF still comes
|
|
60
|
+
* back as its first frame: a canvas holds one picture.
|
|
61
|
+
*/
|
|
62
|
+
type?: "image/jpeg" | "image/png" | "image/webp" | "source"
|
|
63
|
+
/** Quality of a lossy export (JPEG, WebP); PNG ignores it. */
|
|
52
64
|
quality?: number
|
|
53
65
|
/**
|
|
54
66
|
* Labels for the toolbar. Defaulted in English rather than left blank: an
|
|
@@ -62,7 +74,7 @@ const props = withDefaults(
|
|
|
62
74
|
/** Fade the picture in when the editor first comes into view. */
|
|
63
75
|
animate?: boolean
|
|
64
76
|
}>(),
|
|
65
|
-
{ aspect: "free", maxEdge: 2400, quality: 0.9, labels: () => ({}), animate: true },
|
|
77
|
+
{ aspect: "free", maxEdge: 2400, type: "image/jpeg", quality: 0.9, labels: () => ({}), animate: true },
|
|
66
78
|
)
|
|
67
79
|
|
|
68
80
|
// Same rule as the rest of the kit: the entrance belongs to arrival, not to
|
|
@@ -289,10 +301,17 @@ async function exportImage(): Promise<Blob | null> {
|
|
|
289
301
|
ctx.drawImage(picture, readX, readY, readW, readH, -readW / 2, -readH / 2, readW, readH)
|
|
290
302
|
|
|
291
303
|
return await new Promise<Blob | null>((resolve) =>
|
|
292
|
-
canvas.toBlob(resolve,
|
|
304
|
+
canvas.toBlob(resolve, outputType.value, props.quality),
|
|
293
305
|
)
|
|
294
306
|
}
|
|
295
307
|
|
|
308
|
+
const ENCODABLE = new Set(["image/png", "image/jpeg", "image/webp"])
|
|
309
|
+
|
|
310
|
+
const outputType = computed(() => {
|
|
311
|
+
if (props.type !== "source") return props.type
|
|
312
|
+
return ENCODABLE.has(props.file.type) ? props.file.type : "image/png"
|
|
313
|
+
})
|
|
314
|
+
|
|
296
315
|
function clamp(value: number, low: number, high: number) {
|
|
297
316
|
return Math.min(Math.max(value, low), Math.max(low, high))
|
|
298
317
|
}
|
|
@@ -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"
|