@springbrand/gravel 0.1.3-alpha.2 → 0.1.3-alpha.3

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.
Files changed (32) hide show
  1. package/dist/components/ui-base/index.d.ts +1 -0
  2. package/dist/components/ui-base/responsive-dialog/index.d.ts +55 -0
  3. package/dist/components/ui-block/background/index.d.ts +8 -0
  4. package/dist/components/ui-block/cover/index.d.ts +17 -0
  5. package/dist/components/ui-block/index.d.ts +4 -0
  6. package/dist/components/ui-block/sparkles/index.d.ts +13 -0
  7. package/dist/components/ui-block/spotlight/index.d.ts +13 -0
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.js +1 -9
  10. package/package.json +3 -11
  11. package/dist/_virtual/_commonjsHelpers.js +0 -8
  12. package/dist/_virtual/timezone.js +0 -4
  13. package/dist/_virtual/utc.js +0 -4
  14. package/dist/components/runtime-site/action/index.js +0 -57
  15. package/dist/components/runtime-site/floating-booking-bubble/api/booking-public.js +0 -147
  16. package/dist/components/runtime-site/floating-booking-bubble/booking-form-field.js +0 -102
  17. package/dist/components/runtime-site/floating-booking-bubble/bubble-container.js +0 -89
  18. package/dist/components/runtime-site/floating-booking-bubble/bubble-trigger.js +0 -41
  19. package/dist/components/runtime-site/floating-booking-bubble/dayjs-tz.js +0 -9
  20. package/dist/components/runtime-site/floating-booking-bubble/index.js +0 -146
  21. package/dist/components/runtime-site/floating-booking-bubble/public-appointment-model.js +0 -92
  22. package/dist/components/runtime-site/floating-booking-bubble/public-availability-model.js +0 -14
  23. package/dist/components/runtime-site/floating-booking-bubble/public-service-detail-model.js +0 -33
  24. package/dist/components/runtime-site/floating-booking-bubble/public-service-model.js +0 -19
  25. package/dist/components/runtime-site/floating-booking-bubble/step-1-service-picker.js +0 -83
  26. package/dist/components/runtime-site/floating-booking-bubble/step-2-time-picker.js +0 -151
  27. package/dist/components/runtime-site/floating-booking-bubble/step-3-details-form.js +0 -142
  28. package/dist/components/runtime-site/floating-booking-bubble/step-4-confirm.js +0 -122
  29. package/dist/components/runtime-site/floating-booking-bubble/use-booking-flow.js +0 -287
  30. package/dist/components/runtime-site/runtime-host-provider/index.js +0 -20
  31. package/dist/node_modules/.pnpm/dayjs@1.11.20/node_modules/dayjs/plugin/timezone.js +0 -67
  32. package/dist/node_modules/.pnpm/dayjs@1.11.20/node_modules/dayjs/plugin/utc.js +0 -79
@@ -0,0 +1 @@
1
+ export { ResponsiveDialog, ResponsiveDialogTrigger, ResponsiveDialogClose, ResponsiveDialogContent, ResponsiveDialogHeader, ResponsiveDialogFooter, ResponsiveDialogTitle, ResponsiveDialogDescription, } from "./responsive-dialog/index.tsx";
@@ -0,0 +1,55 @@
1
+ import * as React from "react";
2
+ type ResponsiveMode = "auto" | "dialog" | "drawer";
3
+ type ResponsiveDialogProps = {
4
+ /** 'auto' 会按 useIsMobile() 判断;也可强制 'dialog' / 'drawer' */
5
+ mode?: ResponsiveMode;
6
+ open?: boolean;
7
+ defaultOpen?: boolean;
8
+ onOpenChange?: (open: boolean) => void;
9
+ modal?: boolean;
10
+ children?: React.ReactNode;
11
+ /** drawer 模式透传:方向、snap 等 */
12
+ drawerProps?: Record<string, any>;
13
+ /** dialog 模式透传 */
14
+ dialogProps?: Record<string, any>;
15
+ };
16
+ declare function ResponsiveDialog({ mode, children, drawerProps, dialogProps, ...props }: ResponsiveDialogProps): import("react/jsx-runtime").JSX.Element;
17
+ type TriggerProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
18
+ asChild?: boolean;
19
+ children?: React.ReactNode;
20
+ };
21
+ declare function ResponsiveDialogTrigger(props: TriggerProps): import("react/jsx-runtime").JSX.Element;
22
+ type CloseProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
23
+ asChild?: boolean;
24
+ children?: React.ReactNode;
25
+ };
26
+ declare function ResponsiveDialogClose(props: CloseProps): import("react/jsx-runtime").JSX.Element;
27
+ type ResponsiveDialogContentProps = React.HTMLAttributes<HTMLDivElement> & {
28
+ /** dialog 专属:是否展示右上角关闭按钮 */
29
+ showCloseButton?: boolean;
30
+ /** 仅 dialog 模式追加的 className */
31
+ dialogClassName?: string;
32
+ /** 仅 drawer 模式追加的 className */
33
+ drawerClassName?: string;
34
+ onEscapeKeyDown?: (e: KeyboardEvent) => void;
35
+ onPointerDownOutside?: (e: Event) => void;
36
+ };
37
+ declare function ResponsiveDialogContent({ className, dialogClassName, drawerClassName, children, showCloseButton, onEscapeKeyDown, onPointerDownOutside, ...props }: ResponsiveDialogContentProps): import("react/jsx-runtime").JSX.Element;
38
+ type HeaderProps = React.ComponentProps<"div">;
39
+ declare function ResponsiveDialogHeader(props: HeaderProps): import("react/jsx-runtime").JSX.Element;
40
+ type FooterProps = React.ComponentProps<"div"> & {
41
+ /** dialog 专属 */
42
+ showCloseButton?: boolean;
43
+ };
44
+ declare function ResponsiveDialogFooter({ showCloseButton, className, ...props }: FooterProps): import("react/jsx-runtime").JSX.Element;
45
+ type TitleProps = React.HTMLAttributes<HTMLHeadingElement> & {
46
+ asChild?: boolean;
47
+ children?: React.ReactNode;
48
+ };
49
+ declare function ResponsiveDialogTitle(props: TitleProps): import("react/jsx-runtime").JSX.Element;
50
+ type DescriptionProps = React.HTMLAttributes<HTMLParagraphElement> & {
51
+ asChild?: boolean;
52
+ children?: React.ReactNode;
53
+ };
54
+ declare function ResponsiveDialogDescription(props: DescriptionProps): import("react/jsx-runtime").JSX.Element;
55
+ export { ResponsiveDialog, ResponsiveDialogTrigger, ResponsiveDialogClose, ResponsiveDialogContent, ResponsiveDialogHeader, ResponsiveDialogFooter, ResponsiveDialogTitle, ResponsiveDialogDescription, };
@@ -0,0 +1,8 @@
1
+ import type { ReactNode } from "react";
2
+ interface IBlurryBackgroundProps {
3
+ children?: ReactNode;
4
+ primaryColor?: string;
5
+ secondaryColor?: string;
6
+ }
7
+ export default function Background({ children, primaryColor, secondaryColor, }: IBlurryBackgroundProps): import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,17 @@
1
+ import { motion } from "motion/react";
2
+ import React from "react";
3
+ export declare const Cover: ({ children, className, }: {
4
+ children?: React.ReactNode;
5
+ className?: string;
6
+ }) => import("react/jsx-runtime").JSX.Element;
7
+ export declare const Beam: ({ className, delay, duration, hovered, width, ...svgProps }: {
8
+ className?: string;
9
+ delay?: number;
10
+ duration?: number;
11
+ hovered?: boolean;
12
+ width?: number;
13
+ } & React.ComponentProps<typeof motion.svg>) => import("react/jsx-runtime").JSX.Element;
14
+ export declare const CircleIcon: ({ className, }: {
15
+ className?: string;
16
+ delay?: number;
17
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ export { default as Background } from "./background/index.tsx";
2
+ export { Cover } from "./cover/index.tsx";
3
+ export { SparklesCore } from "./sparkles/index.tsx";
4
+ export { Spotlight } from "./spotlight/index.tsx";
@@ -0,0 +1,13 @@
1
+ type ParticlesProps = {
2
+ id?: string;
3
+ className?: string;
4
+ background?: string;
5
+ particleSize?: number;
6
+ minSize?: number;
7
+ maxSize?: number;
8
+ speed?: number;
9
+ particleColor?: string;
10
+ particleDensity?: number;
11
+ };
12
+ export declare const SparklesCore: (props: ParticlesProps) => import("react/jsx-runtime").JSX.Element;
13
+ export {};
@@ -0,0 +1,13 @@
1
+ type SpotlightProps = {
2
+ gradientFirst?: string;
3
+ gradientSecond?: string;
4
+ gradientThird?: string;
5
+ translateY?: number;
6
+ width?: number;
7
+ height?: number;
8
+ smallWidth?: number;
9
+ duration?: number;
10
+ xOffset?: number;
11
+ };
12
+ export declare const Spotlight: ({ gradientFirst, gradientSecond, gradientThird, translateY, width, height, smallWidth, duration, xOffset, }?: SpotlightProps) => import("react/jsx-runtime").JSX.Element | null;
13
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from "./components/ui-base/index.ts";
2
+ export * from "./components/ui-block/index.ts";
package/dist/index.js CHANGED
@@ -1,17 +1,11 @@
1
1
  import { default as default2 } from "./components/ui-block/background/index.js";
2
- import { Action } from "./components/runtime-site/action/index.js";
3
2
  import { Cover } from "./components/ui-block/cover/index.js";
4
- import { FloatingBookingBubble, FloatingBookingBubbleDefaults } from "./components/runtime-site/floating-booking-bubble/index.js";
5
3
  import { ResponsiveDialog, ResponsiveDialogClose, ResponsiveDialogContent, ResponsiveDialogDescription, ResponsiveDialogFooter, ResponsiveDialogHeader, ResponsiveDialogTitle, ResponsiveDialogTrigger } from "./components/ui-base/responsive-dialog/index.js";
6
- import { RuntimeHostProvider, useRuntimeHost } from "./components/runtime-site/runtime-host-provider/index.js";
7
4
  import { SparklesCore } from "./components/ui-block/sparkles/index.js";
8
5
  import { Spotlight } from "./components/ui-block/spotlight/index.js";
9
6
  export {
10
- Action,
11
7
  default2 as Background,
12
8
  Cover,
13
- FloatingBookingBubble,
14
- FloatingBookingBubbleDefaults,
15
9
  ResponsiveDialog,
16
10
  ResponsiveDialogClose,
17
11
  ResponsiveDialogContent,
@@ -20,8 +14,6 @@ export {
20
14
  ResponsiveDialogHeader,
21
15
  ResponsiveDialogTitle,
22
16
  ResponsiveDialogTrigger,
23
- RuntimeHostProvider,
24
17
  SparklesCore,
25
- Spotlight,
26
- useRuntimeHost
18
+ Spotlight
27
19
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springbrand/gravel",
3
- "version": "0.1.3-alpha.2",
3
+ "version": "0.1.3-alpha.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -38,19 +38,11 @@
38
38
  "types": "./dist/components/ui-base/*/index.d.ts",
39
39
  "import": "./dist/components/ui-base/*/index.js",
40
40
  "default": "./dist/components/ui-base/*/index.js"
41
- },
42
- "./components/runtime-site/*": {
43
- "types": "./dist/components/runtime-site/*/index.d.ts",
44
- "import": "./dist/components/runtime-site/*/index.js",
45
- "default": "./dist/components/runtime-site/*/index.js"
46
41
  }
47
42
  },
48
43
  "dependencies": {
49
44
  "@springbrand/site-block": "0.1.3-alpha.2",
50
- "@springbrand/utils": "0.1.1",
51
- "dayjs": "^1.11.0",
52
- "lucide-react": ">=0.400.0",
53
- "zod": "4.3.6"
45
+ "@springbrand/utils": "0.1.1"
54
46
  },
55
47
  "peerDependencies": {
56
48
  "@tsparticles/engine": "^3.0.0",
@@ -73,5 +65,5 @@
73
65
  "optional": true
74
66
  }
75
67
  },
76
- "gitHead": "c26dcdbc771b8c99b11c5073cb158d8bcd8d9c84"
68
+ "gitHead": "b7a0bc2ff49d1ad39bcb241f46ad4467fa6f9430"
77
69
  }
@@ -1,8 +0,0 @@
1
- var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
2
- function getDefaultExportFromCjs(x) {
3
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
4
- }
5
- export {
6
- commonjsGlobal,
7
- getDefaultExportFromCjs
8
- };
@@ -1,4 +0,0 @@
1
- var timezone = { exports: {} };
2
- export {
3
- timezone as __module
4
- };
@@ -1,4 +0,0 @@
1
- var utc = { exports: {} };
2
- export {
3
- utc as __module
4
- };
@@ -1,57 +0,0 @@
1
- "use client";
2
- import { Children, cloneElement } from "react";
3
- import { useRuntimeHost } from "../runtime-host-provider/index.js";
4
- function createRuntimeActionContext(trigger, event) {
5
- const element = event.currentTarget;
6
- const ownerDocument = element.ownerDocument;
7
- return {
8
- trigger,
9
- event,
10
- element,
11
- ownerDocument,
12
- ownerWindow: ownerDocument.defaultView
13
- };
14
- }
15
- function Action({
16
- children,
17
- id,
18
- input,
19
- trigger = "click"
20
- }) {
21
- const runtimeHost = useRuntimeHost();
22
- const child = Children.only(children);
23
- const originalHandler = trigger === "click" ? child.props.onClick : trigger === "pointerDown" ? child.props.onPointerDown : child.props.onSubmit;
24
- const actionHandler = (event) => {
25
- var _a, _b;
26
- originalHandler == null ? void 0 : originalHandler(event);
27
- if (event.defaultPrevented || !id || !runtimeHost.actions) {
28
- return;
29
- }
30
- const context = createRuntimeActionContext(trigger, event);
31
- try {
32
- const result = runtimeHost.actions.runAction(id, input, context);
33
- void Promise.resolve(result).catch((error) => {
34
- var _a2, _b2;
35
- (_b2 = (_a2 = runtimeHost.actions) == null ? void 0 : _a2.onError) == null ? void 0 : _b2.call(_a2, error, context);
36
- });
37
- } catch (error) {
38
- (_b = (_a = runtimeHost.actions).onError) == null ? void 0 : _b.call(_a, error, context);
39
- }
40
- };
41
- if (trigger === "pointerDown") {
42
- return cloneElement(child, {
43
- onPointerDown: actionHandler
44
- });
45
- }
46
- if (trigger === "submit") {
47
- return cloneElement(child, {
48
- onSubmit: actionHandler
49
- });
50
- }
51
- return cloneElement(child, {
52
- onClick: actionHandler
53
- });
54
- }
55
- export {
56
- Action
57
- };
@@ -1,147 +0,0 @@
1
- import { PublicServiceModel } from "../public-service-model.js";
2
- import { PublicServiceDetailModel } from "../public-service-detail-model.js";
3
- import { PublicAvailabilityModel } from "../public-availability-model.js";
4
- import { PublicAppointmentModel } from "../public-appointment-model.js";
5
- class BookingApiError extends Error {
6
- constructor(kind, code, httpStatus, message, details) {
7
- super(message);
8
- this.kind = kind;
9
- this.code = code;
10
- this.httpStatus = httpStatus;
11
- this.details = details;
12
- this.name = "BookingApiError";
13
- }
14
- }
15
- function unwrapPublicRpc(wire, httpStatus) {
16
- if ((wire == null ? void 0 : wire.success) === true && wire.msg !== void 0) {
17
- return wire.msg;
18
- }
19
- throw new BookingApiError(
20
- "biz",
21
- (wire == null ? void 0 : wire.code) ?? "BOOKING_UNKNOWN_ERROR",
22
- httpStatus,
23
- (wire == null ? void 0 : wire.errMsg) ?? "Booking request failed",
24
- wire
25
- );
26
- }
27
- function normalizeBaseUrl(domain) {
28
- return (domain ?? "").replace(/\/$/, "");
29
- }
30
- async function publicFetch(domain, path, init) {
31
- const baseUrl = normalizeBaseUrl(domain);
32
- let res;
33
- try {
34
- res = await fetch(`${baseUrl}${path}`, {
35
- ...init,
36
- headers: {
37
- "Content-Type": "application/json",
38
- ...(init == null ? void 0 : init.headers) ?? {}
39
- }
40
- });
41
- } catch (err) {
42
- throw new BookingApiError(
43
- "network",
44
- "NETWORK_ERROR",
45
- null,
46
- err instanceof Error ? err.message : "Network error"
47
- );
48
- }
49
- if (!res.ok) {
50
- let body = null;
51
- try {
52
- body = await res.json();
53
- } catch {
54
- }
55
- const code = res.status === 429 ? "RATE_LIMITED" : "INTERNAL_ERROR";
56
- throw new BookingApiError(
57
- "http",
58
- code,
59
- res.status,
60
- `HTTP ${res.status}`,
61
- body
62
- );
63
- }
64
- let wire;
65
- try {
66
- wire = await res.json();
67
- } catch (err) {
68
- throw new BookingApiError(
69
- "network",
70
- "INVALID_JSON",
71
- res.status,
72
- err instanceof Error ? err.message : "Invalid JSON"
73
- );
74
- }
75
- return unwrapPublicRpc(wire, res.status);
76
- }
77
- async function fetchServices(domain, brandSlug) {
78
- const wire = await publicFetch(
79
- domain,
80
- `/api/public/booking/${encodeURIComponent(brandSlug)}/services`
81
- );
82
- return {
83
- services: wire.services.map(PublicServiceModel.fromWire),
84
- timezone: wire.timezone
85
- };
86
- }
87
- async function fetchServiceDetail(domain, brandSlug, serviceId) {
88
- const wire = await publicFetch(
89
- domain,
90
- `/api/public/booking/${encodeURIComponent(brandSlug)}/services/${serviceId}`
91
- );
92
- return {
93
- service: PublicServiceDetailModel.fromWire(wire.service),
94
- timezone: wire.timezone
95
- };
96
- }
97
- async function fetchAvailability(domain, brandSlug, params) {
98
- const qs = new URLSearchParams({
99
- service_id: String(params.service_id),
100
- from: params.from,
101
- to: params.to
102
- });
103
- const wire = await publicFetch(
104
- domain,
105
- `/api/public/booking/${encodeURIComponent(brandSlug)}/availability?${qs.toString()}`
106
- );
107
- return PublicAvailabilityModel.fromWire(wire);
108
- }
109
- async function submitAppointment(domain, brandSlug, body) {
110
- const wireBody = {
111
- service_id: body.service_id,
112
- scheduled_at: body.scheduled_at,
113
- contact: {
114
- name: [body.customer.first_name, body.customer.last_name].filter(Boolean).join(" ").trim(),
115
- email: body.customer.email,
116
- phone: body.customer.phone,
117
- metadata: {
118
- first_name: body.customer.first_name,
119
- last_name: body.customer.last_name,
120
- address: body.customer.address
121
- }
122
- },
123
- custom_answers: body.custom_answers.map((a) => ({
124
- question_id: a.questionId,
125
- label: a.label,
126
- answer: a.answer
127
- })),
128
- source_page: body.source_page
129
- };
130
- const wire = await publicFetch(
131
- domain,
132
- `/api/public/booking/${encodeURIComponent(brandSlug)}/appointments`,
133
- {
134
- method: "POST",
135
- body: JSON.stringify(wireBody)
136
- }
137
- );
138
- return PublicAppointmentModel.fromWire(wire.appointment);
139
- }
140
- export {
141
- BookingApiError,
142
- fetchAvailability,
143
- fetchServiceDetail,
144
- fetchServices,
145
- submitAppointment,
146
- unwrapPublicRpc
147
- };
@@ -1,102 +0,0 @@
1
- "use client";
2
- import { jsxs, jsx } from "react/jsx-runtime";
3
- import { Input } from "@springbrand/site-block/components/shadcn/input";
4
- import { Label } from "@springbrand/site-block/components/shadcn/label";
5
- import { Textarea } from "@springbrand/site-block/components/shadcn/textarea";
6
- import { RadioGroup, RadioGroupItem } from "@springbrand/site-block/components/shadcn/radio-group";
7
- import { Checkbox } from "@springbrand/site-block/components/shadcn/checkbox";
8
- import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@springbrand/site-block/components/shadcn/select";
9
- import { cn } from "@springbrand/site-block/lib/utils";
10
- function BookingFormField({
11
- question,
12
- value,
13
- onChange,
14
- error
15
- }) {
16
- const fieldId = `q-${question.id}`;
17
- const renderControl = () => {
18
- switch (question.type) {
19
- case "one_line":
20
- return /* @__PURE__ */ jsx(
21
- Input,
22
- {
23
- id: fieldId,
24
- value: value ?? "",
25
- onChange: (e) => onChange(e.target.value),
26
- "aria-invalid": !!error || void 0
27
- }
28
- );
29
- case "multi_line":
30
- return /* @__PURE__ */ jsx(
31
- Textarea,
32
- {
33
- id: fieldId,
34
- value: value ?? "",
35
- onChange: (e) => onChange(e.target.value),
36
- "aria-invalid": !!error || void 0
37
- }
38
- );
39
- case "radio":
40
- return /* @__PURE__ */ jsx(
41
- RadioGroup,
42
- {
43
- value: value ?? "",
44
- onValueChange: (v) => onChange(v),
45
- className: "gap-2",
46
- children: (question.options ?? []).map((opt) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
47
- /* @__PURE__ */ jsx(RadioGroupItem, { id: `${fieldId}-${opt.id}`, value: opt.id }),
48
- /* @__PURE__ */ jsx(Label, { htmlFor: `${fieldId}-${opt.id}`, className: "font-normal", children: opt.label })
49
- ] }, opt.id))
50
- }
51
- );
52
- case "checkboxes": {
53
- const arr = Array.isArray(value) ? value : [];
54
- return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: (question.options ?? []).map((opt) => {
55
- const checked = arr.includes(opt.id);
56
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
57
- /* @__PURE__ */ jsx(
58
- Checkbox,
59
- {
60
- id: `${fieldId}-${opt.id}`,
61
- checked,
62
- onCheckedChange: (c) => {
63
- const next = c ? [...arr, opt.id] : arr.filter((id) => id !== opt.id);
64
- onChange(next);
65
- }
66
- }
67
- ),
68
- /* @__PURE__ */ jsx(Label, { htmlFor: `${fieldId}-${opt.id}`, className: "font-normal", children: opt.label })
69
- ] }, opt.id);
70
- }) });
71
- }
72
- case "dropdown": {
73
- const options = question.options ?? [];
74
- return /* @__PURE__ */ jsxs(
75
- Select,
76
- {
77
- value: value ?? "",
78
- items: options.map((opt) => ({ label: opt.label, value: opt.id })),
79
- onValueChange: (v) => onChange(v),
80
- children: [
81
- /* @__PURE__ */ jsx(SelectTrigger, { id: fieldId, "aria-invalid": !!error || void 0, children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select…" }) }),
82
- /* @__PURE__ */ jsx(SelectContent, { children: options.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt.id, children: opt.label }, opt.id)) })
83
- ]
84
- }
85
- );
86
- }
87
- default:
88
- return null;
89
- }
90
- };
91
- return /* @__PURE__ */ jsxs("div", { className: cn("space-y-1.5", error && "[&>label]:text-destructive"), children: [
92
- /* @__PURE__ */ jsxs(Label, { htmlFor: fieldId, children: [
93
- question.label,
94
- question.required && /* @__PURE__ */ jsx("span", { className: "ml-0.5 text-destructive", children: "*" })
95
- ] }),
96
- renderControl(),
97
- error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error })
98
- ] });
99
- }
100
- export {
101
- BookingFormField
102
- };
@@ -1,89 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { X } from "lucide-react";
4
- import { useState, useEffect } from "react";
5
- import { Sheet, SheetContent } from "@springbrand/site-block/components/shadcn/sheet";
6
- import { Button } from "@springbrand/site-block/components/shadcn/button";
7
- import { cn } from "@springbrand/site-block/lib/utils";
8
- function BubbleContainer({
9
- open,
10
- onOpenChange,
11
- title,
12
- children,
13
- onBack,
14
- stepIndicator,
15
- className,
16
- container
17
- }) {
18
- const [isDesktop, setIsDesktop] = useState(false);
19
- const headerTitle = title ?? (onBack ? null : "Book");
20
- useEffect(() => {
21
- const targetWindow = resolveContainerWindow(container);
22
- if (!targetWindow) return;
23
- const mq = targetWindow.matchMedia("(min-width: 768px)");
24
- const update = () => setIsDesktop(mq.matches);
25
- update();
26
- mq.addEventListener("change", update);
27
- return () => mq.removeEventListener("change", update);
28
- }, [container]);
29
- return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
30
- SheetContent,
31
- {
32
- side: isDesktop ? "right" : "bottom",
33
- showCloseButton: false,
34
- container,
35
- className: cn(
36
- "z-[1001] p-0 flex flex-col gap-0 overflow-hidden",
37
- isDesktop ? (
38
- // 桌面 popover 与气泡按钮的相对位置:
39
- // - bottom-28 (112px) 让对话框底端高于按钮顶部 (72px) 约 40px,留出明显呼吸感
40
- // - right-8 (32px) 把对话框右边再让出一点,避免和屏幕右沿/按钮贴在一起
41
- // SheetContent 基类带 data-[side=right]:{inset-y-0,h-full,w-3/4},
42
- // 必须用 ! important 覆盖 top / bottom / 高宽,否则会被钉在 top:0 全高。
43
- "w-[400px]! sm:max-w-[420px] right-8 top-auto! bottom-28! h-[600px]! max-h-[calc(100vh-9rem)] rounded-2xl border shadow-2xl"
44
- ) : "h-[min(85svh,calc(100dvh-env(safe-area-inset-top)-0.75rem))] w-full rounded-t-2xl border-t",
45
- className
46
- ),
47
- overlayClassName: "z-[1000]",
48
- children: [
49
- /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between border-b px-4 h-12 shrink-0", children: [
50
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
51
- onBack && /* @__PURE__ */ jsx(
52
- Button,
53
- {
54
- type: "button",
55
- variant: "ghost",
56
- size: "sm",
57
- className: "-ml-2 h-8 px-2",
58
- onClick: onBack,
59
- children: "Back"
60
- }
61
- ),
62
- headerTitle && /* @__PURE__ */ jsx("span", { className: "font-semibold text-sm truncate", children: headerTitle })
63
- ] }),
64
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [
65
- stepIndicator && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: stepIndicator }),
66
- /* @__PURE__ */ jsx(
67
- "button",
68
- {
69
- type: "button",
70
- "aria-label": "Close",
71
- onClick: () => onOpenChange(false),
72
- className: "rounded-md p-1 text-muted-foreground hover:bg-muted hover:text-foreground",
73
- children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
74
- }
75
- )
76
- ] })
77
- ] }),
78
- /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain [-webkit-overflow-scrolling:touch]", children })
79
- ]
80
- }
81
- ) });
82
- }
83
- function resolveContainerWindow(container) {
84
- const element = container && "current" in container ? container.current : container;
85
- return (element == null ? void 0 : element.ownerDocument.defaultView) ?? null;
86
- }
87
- export {
88
- BubbleContainer
89
- };
@@ -1,41 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { Calendar } from "lucide-react";
4
- import { Button } from "@springbrand/site-block/components/shadcn/button";
5
- import { cn } from "@springbrand/site-block/lib/utils";
6
- function BubbleTrigger({
7
- label = "Book now",
8
- onClick,
9
- editorMode,
10
- className,
11
- style,
12
- ...domProps
13
- }) {
14
- return /* @__PURE__ */ jsx(
15
- "div",
16
- {
17
- ...domProps,
18
- className: cn(
19
- "fixed bottom-[calc(env(safe-area-inset-bottom)+1rem)] right-[calc(env(safe-area-inset-right)+1rem)] z-50 print:hidden sm:bottom-6 sm:right-6",
20
- editorMode && "group cursor-pointer outline-primary/40 rounded-full"
21
- ),
22
- onClick,
23
- children: /* @__PURE__ */ jsxs(
24
- Button,
25
- {
26
- type: "button",
27
- size: "lg",
28
- className: cn("rounded-full shadow-lg gap-2 px-5 h-12", className),
29
- style,
30
- children: [
31
- /* @__PURE__ */ jsx(Calendar, { className: "h-5 w-5" }),
32
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: label })
33
- ]
34
- }
35
- )
36
- }
37
- );
38
- }
39
- export {
40
- BubbleTrigger
41
- };
@@ -1,9 +0,0 @@
1
- import dayjs from "dayjs";
2
- import { default as default2 } from "dayjs";
3
- import utc from "../../../node_modules/.pnpm/dayjs@1.11.20/node_modules/dayjs/plugin/utc.js";
4
- import timezone from "../../../node_modules/.pnpm/dayjs@1.11.20/node_modules/dayjs/plugin/timezone.js";
5
- dayjs.extend(utc);
6
- dayjs.extend(timezone);
7
- export {
8
- default2 as default
9
- };