maquinaweb-ui 2.75.1 → 2.76.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/actions.js +0 -1
- package/dist/actions.js.map +1 -1
- package/dist/analytics/core.d.ts.map +1 -1
- package/dist/analytics/core.js +0 -1
- package/dist/analytics/core.js.map +1 -1
- package/dist/analytics/delegated-clicks.d.ts.map +1 -1
- package/dist/analytics/delegated-clicks.js +0 -1
- package/dist/analytics/delegated-clicks.js.map +1 -1
- package/dist/analytics/provider.d.ts +2 -2
- package/dist/analytics/provider.d.ts.map +1 -1
- package/dist/analytics/provider.js +0 -1
- package/dist/analytics/provider.js.map +1 -1
- package/dist/analytics/types.d.ts.map +1 -1
- package/dist/analytics.js +0 -1
- package/dist/container-animation/container-animation.d.ts +2 -2
- package/dist/container-animation/container-animation.d.ts.map +1 -1
- package/dist/container-animation/container-animation.js +1 -2
- package/dist/container-animation/container-animation.js.map +1 -1
- package/dist/container-animation.js +0 -1
- package/dist/date-field/DateField.d.ts +2 -2
- package/dist/date-field/DateField.d.ts.map +1 -1
- package/dist/date-field/DateField.js +0 -1
- package/dist/date-field/DateField.js.map +1 -1
- package/dist/date-field.js +0 -1
- package/dist/date-hour-field/DateHourField.d.ts +2 -2
- package/dist/date-hour-field/DateHourField.d.ts.map +1 -1
- package/dist/date-hour-field/DateHourField.js +0 -1
- package/dist/date-hour-field/DateHourField.js.map +1 -1
- package/dist/date-hour-field/time-wheel-column.js.map +1 -1
- package/dist/date-hour-field.js +0 -1
- package/dist/input-suggest/input-suggest.d.ts +2 -2
- package/dist/input-suggest/input-suggest.d.ts.map +1 -1
- package/dist/input-suggest/input-suggest.js +6 -7
- package/dist/input-suggest/input-suggest.js.map +1 -1
- package/dist/input-suggest.js +0 -1
- package/dist/kanban-dnd/constants.js +1 -4
- package/dist/kanban-dnd/constants.js.map +1 -1
- package/dist/kanban-dnd/context.d.ts +0 -4
- package/dist/kanban-dnd/context.d.ts.map +1 -1
- package/dist/kanban-dnd/context.js +0 -1
- package/dist/kanban-dnd/context.js.map +1 -1
- package/dist/kanban-dnd/drag-preview.js +4 -4
- package/dist/kanban-dnd/drag-preview.js.map +1 -1
- package/dist/kanban-dnd/drop-animation.js.map +1 -1
- package/dist/kanban-dnd/kanban-card-item.d.ts +2 -2
- package/dist/kanban-dnd/kanban-card-item.d.ts.map +1 -1
- package/dist/kanban-dnd/kanban-card-item.js +0 -1
- package/dist/kanban-dnd/kanban-card-item.js.map +1 -1
- package/dist/kanban-dnd/kanban-dnd-monitor.d.ts +2 -2
- package/dist/kanban-dnd/kanban-dnd-monitor.d.ts.map +1 -1
- package/dist/kanban-dnd/kanban-dnd-monitor.js +0 -1
- package/dist/kanban-dnd/kanban-dnd-monitor.js.map +1 -1
- package/dist/kanban-dnd/kanban-dropzone.d.ts +2 -2
- package/dist/kanban-dnd/kanban-dropzone.d.ts.map +1 -1
- package/dist/kanban-dnd/kanban-dropzone.js +0 -1
- package/dist/kanban-dnd/kanban-dropzone.js.map +1 -1
- package/dist/kanban-dnd/kanban-selector.d.ts +2 -2
- package/dist/kanban-dnd/kanban-selector.d.ts.map +1 -1
- package/dist/kanban-dnd/kanban-selector.js +0 -1
- package/dist/kanban-dnd/kanban-selector.js.map +1 -1
- package/dist/kanban-dnd/move-cards.d.ts.map +1 -1
- package/dist/kanban-dnd/move-cards.js.map +1 -1
- package/dist/kanban-dnd/types.d.ts.map +1 -1
- package/dist/kanban-dnd/use-kanban-column-dnd.d.ts.map +1 -1
- package/dist/kanban-dnd/use-kanban-column-dnd.js +0 -1
- package/dist/kanban-dnd/use-kanban-column-dnd.js.map +1 -1
- package/dist/kanban-dnd/use-kanban-selector-auto-scroll.js.map +1 -1
- package/dist/kanban-dnd.d.ts +0 -1
- package/dist/kanban-dnd.js +0 -1
- package/dist/landing-text/client-landing-text.js +0 -1
- package/dist/landing-text/client-landing-text.js.map +1 -1
- package/dist/landing-text/landing-content.d.ts +0 -2
- package/dist/landing-text/landing-content.d.ts.map +1 -1
- package/dist/landing-text/landing-content.js.map +1 -1
- package/dist/landing-text/landing-text.d.ts +2 -2
- package/dist/landing-text/landing-text.d.ts.map +1 -1
- package/dist/landing-text/landing-text.js +1 -1
- package/dist/landing-text/landing-text.js.map +1 -1
- package/dist/landing-text/server-landing-text.d.ts +2 -2
- package/dist/landing-text/server-landing-text.d.ts.map +1 -1
- package/dist/landing-text/server-landing-text.js +1 -1
- package/dist/landing-text/server-landing-text.js.map +1 -1
- package/dist/landing-text/types.d.ts.map +1 -1
- package/dist/node_modules/framer-motion/dist/es/utils/use-in-view.js +0 -1
- package/dist/node_modules/framer-motion/dist/es/utils/use-in-view.js.map +1 -1
- package/dist/node_modules/framer-motion/dist/types/index.d.ts +4 -0
- package/dist/node_modules/framer-motion/dist/types.d-DOCC-kZB.d.ts +1 -0
- package/dist/node_modules/motion/dist/react.d.ts +2 -0
- package/dist/node_modules/motion-dom/dist/index.d.ts +1001 -0
- package/dist/node_modules/motion-dom/dist/index.d.ts.map +1 -0
- package/dist/node_modules/motion-utils/dist/index.d.ts +17 -0
- package/dist/node_modules/motion-utils/dist/index.d.ts.map +1 -0
- package/dist/page-header/page-header.d.ts +2 -2
- package/dist/page-header/page-header.d.ts.map +1 -1
- package/dist/page-header/page-header.js.map +1 -1
- package/dist/page-header.js +0 -1
- package/dist/remote-selector/remote-selector.d.ts +3 -3
- package/dist/remote-selector/remote-selector.d.ts.map +1 -1
- package/dist/remote-selector/remote-selector.js +3 -4
- package/dist/remote-selector/remote-selector.js.map +1 -1
- package/dist/remote-selector.js +0 -1
- package/dist/server-infinite-scroll/server-infinite-scroll-items.d.ts +2 -2
- package/dist/server-infinite-scroll/server-infinite-scroll-items.d.ts.map +1 -1
- package/dist/server-infinite-scroll/server-infinite-scroll-items.js.map +1 -1
- package/dist/server-infinite-scroll/server-infinite-scroll-list.d.ts +2 -2
- package/dist/server-infinite-scroll/server-infinite-scroll-list.d.ts.map +1 -1
- package/dist/server-infinite-scroll/server-infinite-scroll-list.js +6 -7
- package/dist/server-infinite-scroll/server-infinite-scroll-list.js.map +1 -1
- package/dist/server-infinite-scroll/server-infinite-scroll-observer.d.ts +2 -2
- package/dist/server-infinite-scroll/server-infinite-scroll-observer.d.ts.map +1 -1
- package/dist/server-infinite-scroll/server-infinite-scroll-observer.js +0 -1
- package/dist/server-infinite-scroll/server-infinite-scroll-observer.js.map +1 -1
- package/dist/server-infinite-scroll/server-infinite-scroll.d.ts +2 -2
- package/dist/server-infinite-scroll/server-infinite-scroll.d.ts.map +1 -1
- package/dist/server-infinite-scroll/types.d.ts.map +1 -1
- package/dist/split-text-poor/split-text-poor.d.ts.map +1 -1
- package/dist/split-text-poor/split-text-poor.js +1 -2
- package/dist/split-text-poor/split-text-poor.js.map +1 -1
- package/dist/split-text-poor.js +0 -1
- package/dist/src/hooks/get-mask-options.js.map +1 -1
- package/dist/src/hooks/is-server.js +1 -2
- package/dist/src/hooks/is-server.js.map +1 -1
- package/dist/src/hooks/use-money-input.js +1 -3
- package/dist/src/hooks/use-money-input.js.map +1 -1
- package/dist/src/hooks/with-mask.d.ts +0 -1
- package/dist/src/hooks/with-mask.d.ts.map +1 -1
- package/dist/src/hooks/with-mask.js +2 -2
- package/dist/src/hooks/with-mask.js.map +1 -1
- package/dist/text-field/TextField.d.ts +5 -5
- package/dist/text-field/TextField.d.ts.map +1 -1
- package/dist/text-field/TextField.js +8 -9
- package/dist/text-field/TextField.js.map +1 -1
- package/dist/text-field.js +0 -1
- package/dist/toggle-field/ToggleField.d.ts.map +1 -1
- package/dist/toggle-field/ToggleField.js +1 -2
- package/dist/toggle-field/ToggleField.js.map +1 -1
- package/dist/toggle-field/ToggleGroup.d.ts +6 -6
- package/dist/toggle-field/ToggleGroup.d.ts.map +1 -1
- package/dist/toggle-field/ToggleGroup.js +2 -3
- package/dist/toggle-field/ToggleGroup.js.map +1 -1
- package/dist/toggle-field.js +0 -1
- package/dist/ui/badge.js +1 -1
- package/dist/ui/badge.js.map +1 -1
- package/dist/ui/button.js +1 -1
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/calendar.js +8 -9
- package/dist/ui/calendar.js.map +1 -1
- package/dist/ui/checkbox.js +1 -2
- package/dist/ui/checkbox.js.map +1 -1
- package/dist/ui/command.js +5 -6
- package/dist/ui/command.js.map +1 -1
- package/dist/ui/content-help.js.map +1 -1
- package/dist/ui/form.js +4 -5
- package/dist/ui/form.js.map +1 -1
- package/dist/ui/input-date-field.js +1 -1
- package/dist/ui/input-date-field.js.map +1 -1
- package/dist/ui/input-help.js +0 -1
- package/dist/ui/input-help.js.map +1 -1
- package/dist/ui/input.js +1 -1
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/label.js +1 -2
- package/dist/ui/label.js.map +1 -1
- package/dist/ui/popover.js +1 -2
- package/dist/ui/popover.js.map +1 -1
- package/dist/ui/scroll-area.js +1 -2
- package/dist/ui/scroll-area.js.map +1 -1
- package/dist/ui/selector.d.ts +0 -2
- package/dist/ui/selector.d.ts.map +1 -1
- package/dist/ui/selector.js +3 -4
- package/dist/ui/selector.js.map +1 -1
- package/dist/ui/tooltip.js +2 -3
- package/dist/ui/tooltip.js.map +1 -1
- package/dist/ui/tree-item-renderer.js +1 -3
- package/dist/ui/tree-item-renderer.js.map +1 -1
- package/package.json +16 -16
package/dist/actions.js
CHANGED
package/dist/actions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.js","names":[],"sources":["../src/components/actions.ts"],"sourcesContent":["'use server';\n\nimport { updateTag } from 'next/cache';\n\nexport async function refreshTag(tag: string | string[]) {\n if (Array.isArray(tag)) {\n tag.forEach((t) => updateTag(t));\n } else {\n updateTag(tag);\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"actions.js","names":[],"sources":["../src/components/actions.ts"],"sourcesContent":["'use server';\n\nimport { updateTag } from 'next/cache';\n\nexport async function refreshTag(tag: string | string[]) {\n if (Array.isArray(tag)) {\n tag.forEach((t) => updateTag(t));\n } else {\n updateTag(tag);\n }\n}\n"],"mappings":";;;;;AAIA,eAAsB,WAAW,KAAwB;AACvD,KAAI,MAAM,QAAQ,IAAI,CACpB,KAAI,SAAS,MAAM,UAAU,EAAE,CAAC;KAEhC,WAAU,IAAI"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","names":[],"sources":["../../src/components/analytics/core.ts"],"
|
|
1
|
+
{"version":3,"file":"core.d.ts","names":[],"sources":["../../src/components/analytics/core.ts"],"mappings":";;;iBAsBgB,iBAAA,CAAkB,MAAA;AAAA,iBAQlB,qBAAA,CAAsB,GAAA,WAAc,gBAAA;AAAA,iBAYpC,mBAAA,CACd,cAAA,UACA,GAAA,UACA,SAAA;AAAA,iBAKc,YAAA,CAAa,SAAA,WAAoB,mBAAA;AAAA,iBAqCjC,sBAAA,CACd,QAAA,GAAW,iBAAA,GACV,iBAAA;AAAA,cAaG,sBAAA;EAAA,QACI,MAAA;EAAA,QAIA,KAAA;EAAA,QACA,UAAA;cAEI,MAAA,EAAQ,eAAA;EAYpB,YAAA,CAAa,MAAA,EAAQ,eAAA;EAAA,YAaT,SAAA,CAAA;EAAA,YASA,iBAAA,CAAA;EAAA,YAIA,iBAAA,CAAA;EAAA,QAIJ,YAAA;EAAA,QAaA,UAAA;EAAA,QA8BA,qBAAA;EAAA,QAeA,OAAA;EAYF,KAAA,CAAA,GAAK,OAAA;EAAA,QAgCH,UAAA;EA8BR,aAAA,CAAc,IAAA,GAAO,iBAAA;EAOrB,UAAA,CACE,SAAA,UACA,UAAA,GAAa,MAAA,mBACb,OAAA,GAAU,iBAAA;EAcZ,eAAA,CACE,cAAA,UACA,UAAA,GAAa,MAAA,mBACb,eAAA;AAAA;AAAA,iBAkBY,mBAAA,CAAoB,MAAA,EAAQ,eAAA,GAAe,sBAAA;AAAA,iBAU3C,kBAAA,CAAA,GAAkB,sBAAA;AAAA,iBAIlB,aAAA,CAAc,IAAA,GAAO,iBAAA;AAAA,iBAIrB,UAAA,CACd,SAAA,UACA,UAAA,GAAa,MAAA,mBACb,OAAA,GAAU,iBAAA;AAAA,iBAKI,eAAA,CACd,cAAA,UACA,UAAA,GAAa,MAAA,mBACb,eAAA"}
|
package/dist/analytics/core.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.js","names":["nextSession: PersistedSession","analyticsClient: AnalyticsBrowserClient | null"],"sources":["../../src/components/analytics/core.ts"],"sourcesContent":["'use client';\n\nimport type {\n AnalyticsConfig,\n AnalyticsConversionPayload,\n AnalyticsDeviceInfo,\n AnalyticsEventPayload,\n AnalyticsEventType,\n AnalyticsPageInfo,\n AnalyticsUtmInfo,\n TrackEventOptions,\n} from './types';\n\ntype PersistedSession = {\n id: string;\n startedAt: number;\n lastActivityAt: number;\n utm: AnalyticsUtmInfo;\n};\n\nconst DEFAULT_SESSION_TIMEOUT = 1000 * 60 * 30;\n\nexport function createAnalyticsId(prefix: string) {\n if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {\n return `${prefix}_${crypto.randomUUID()}`;\n }\n\n return `${prefix}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport function parseUtmParamsFromUrl(url: string): AnalyticsUtmInfo {\n const searchParams = new URL(url, 'https://placeholder.local').searchParams;\n\n return {\n source: searchParams.get('utm_source') || undefined,\n medium: searchParams.get('utm_medium') || undefined,\n campaign: searchParams.get('utm_campaign') || undefined,\n term: searchParams.get('utm_term') || undefined,\n content: searchParams.get('utm_content') || undefined,\n };\n}\n\nexport function shouldRotateSession(\n lastActivityAt: number,\n now: number,\n timeoutMs: number\n) {\n return now - lastActivityAt >= timeoutMs;\n}\n\nexport function detectDevice(userAgent: string): AnalyticsDeviceInfo {\n const ua = userAgent.toLowerCase();\n\n const type =\n ua.includes('bot') || ua.includes('crawler')\n ? 'bot'\n : /tablet|ipad/.test(ua)\n ? 'tablet'\n : /mobi|android|iphone/.test(ua)\n ? 'mobile'\n : 'desktop';\n\n const browser = ua.includes('edg/')\n ? 'Edge'\n : ua.includes('chrome/')\n ? 'Chrome'\n : ua.includes('firefox/')\n ? 'Firefox'\n : ua.includes('safari/') && !ua.includes('chrome/')\n ? 'Safari'\n : 'Unknown';\n\n const os = ua.includes('windows')\n ? 'Windows'\n : ua.includes('mac os') || ua.includes('macintosh')\n ? 'macOS'\n : ua.includes('iphone') || ua.includes('ipad')\n ? 'iOS'\n : ua.includes('android')\n ? 'Android'\n : ua.includes('linux')\n ? 'Linux'\n : 'Unknown';\n\n return { type, browser, os };\n}\n\nexport function getCurrentPageSnapshot(\n fallback?: AnalyticsPageInfo\n): AnalyticsPageInfo {\n if (typeof window === 'undefined') {\n return fallback || {};\n }\n\n return {\n path:\n fallback?.path ||\n `${window.location.pathname}${window.location.search || ''}`,\n title: fallback?.title || document.title,\n };\n}\n\nclass AnalyticsBrowserClient {\n private config: Required<\n Pick<AnalyticsConfig, 'sessionTimeoutMs' | 'storageKeyPrefix'>\n > &\n Omit<AnalyticsConfig, 'sessionTimeoutMs' | 'storageKeyPrefix'>;\n private queue: AnalyticsEventPayload[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(config: AnalyticsConfig) {\n this.config = {\n enabled: config.enabled ?? true,\n endpoint: config.endpoint,\n siteKey: config.siteKey,\n sessionTimeoutMs: config.sessionTimeoutMs ?? DEFAULT_SESSION_TIMEOUT,\n storageKeyPrefix: config.storageKeyPrefix ?? 'mw.analytics',\n delegatedClickTracking: config.delegatedClickTracking ?? true,\n inferClickEvents: config.inferClickEvents ?? true,\n };\n }\n\n updateConfig(config: AnalyticsConfig) {\n this.config = {\n ...this.config,\n ...config,\n enabled: config.enabled ?? this.config.enabled,\n sessionTimeoutMs: config.sessionTimeoutMs ?? this.config.sessionTimeoutMs,\n storageKeyPrefix: config.storageKeyPrefix ?? this.config.storageKeyPrefix,\n delegatedClickTracking:\n config.delegatedClickTracking ?? this.config.delegatedClickTracking,\n inferClickEvents: config.inferClickEvents ?? this.config.inferClickEvents,\n };\n }\n\n private get isEnabled() {\n return Boolean(\n this.config.enabled &&\n this.config.endpoint &&\n this.config.siteKey &&\n typeof window !== 'undefined'\n );\n }\n\n private get visitorStorageKey() {\n return `${this.config.storageKeyPrefix}.visitor`;\n }\n\n private get sessionStorageKey() {\n return `${this.config.storageKeyPrefix}.session`;\n }\n\n private getVisitorId() {\n const existingVisitorId = window.localStorage.getItem(\n this.visitorStorageKey\n );\n if (existingVisitorId) {\n return existingVisitorId;\n }\n\n const visitorId = createAnalyticsId('visitor');\n window.localStorage.setItem(this.visitorStorageKey, visitorId);\n return visitorId;\n }\n\n private getSession(now = Date.now()) {\n const rawSession = window.localStorage.getItem(this.sessionStorageKey);\n if (rawSession) {\n try {\n const persistedSession = JSON.parse(rawSession) as PersistedSession;\n if (\n !shouldRotateSession(\n persistedSession.lastActivityAt,\n now,\n this.config.sessionTimeoutMs\n )\n ) {\n return persistedSession;\n }\n } catch {}\n }\n\n const nextSession: PersistedSession = {\n id: createAnalyticsId('session'),\n startedAt: now,\n lastActivityAt: now,\n utm: parseUtmParamsFromUrl(window.location.href),\n };\n window.localStorage.setItem(\n this.sessionStorageKey,\n JSON.stringify(nextSession)\n );\n return nextSession;\n }\n\n private updateSessionActivity(session: PersistedSession, now = Date.now()) {\n const nextSession = {\n ...session,\n lastActivityAt: now,\n utm: Object.values(session.utm || {}).some(Boolean)\n ? session.utm\n : parseUtmParamsFromUrl(window.location.href),\n };\n window.localStorage.setItem(\n this.sessionStorageKey,\n JSON.stringify(nextSession)\n );\n return nextSession;\n }\n\n private enqueue(event: AnalyticsEventPayload) {\n this.queue.push(event);\n\n if (this.flushTimer) {\n return;\n }\n\n this.flushTimer = setTimeout(() => {\n void this.flush();\n }, 300);\n }\n\n async flush() {\n if (!this.isEnabled || this.queue.length === 0) {\n this.flushTimer = null;\n return;\n }\n\n const payload = JSON.stringify({\n siteKey: this.config.siteKey,\n events: [...this.queue],\n });\n\n this.queue = [];\n this.flushTimer = null;\n\n if (\n typeof navigator !== 'undefined' &&\n typeof navigator.sendBeacon === 'function'\n ) {\n const blob = new Blob([payload], { type: 'application/json' });\n if (navigator.sendBeacon(this.config.endpoint!, blob)) {\n return;\n }\n }\n\n await fetch(this.config.endpoint!, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: payload,\n keepalive: true,\n }).catch(() => null);\n }\n\n private buildEvent(\n eventType: AnalyticsEventType,\n eventName: string,\n page?: AnalyticsPageInfo,\n properties?: Record<string, unknown>,\n conversion?: AnalyticsConversionPayload\n ): AnalyticsEventPayload | null {\n if (!this.isEnabled) {\n return null;\n }\n\n const now = Date.now();\n const visitorId = this.getVisitorId();\n const session = this.updateSessionActivity(this.getSession(now), now);\n\n return {\n visitorId,\n sessionId: session.id,\n eventType,\n eventName,\n occurredAt: new Date(now).toISOString(),\n page: getCurrentPageSnapshot(page),\n referrer: document.referrer || undefined,\n utm: session.utm,\n device: detectDevice(navigator.userAgent),\n properties,\n conversion,\n };\n }\n\n trackPageView(page?: AnalyticsPageInfo) {\n const event = this.buildEvent('page_view', 'page_view', page);\n if (event) {\n this.enqueue(event);\n }\n }\n\n trackEvent(\n eventName: string,\n properties?: Record<string, unknown>,\n options?: TrackEventOptions\n ) {\n const event = this.buildEvent(\n options?.eventType ?? 'custom',\n eventName,\n options?.page,\n properties\n );\n\n if (event) {\n this.enqueue(event);\n }\n }\n\n trackConversion(\n conversionName: string,\n properties?: Record<string, unknown>,\n conversionValue?: number | string | null\n ) {\n const event = this.buildEvent(\n 'conversion',\n conversionName,\n undefined,\n properties,\n { name: conversionName, value: conversionValue }\n );\n\n if (event) {\n this.enqueue(event);\n }\n }\n}\n\nlet analyticsClient: AnalyticsBrowserClient | null = null;\n\nexport function initializeAnalytics(config: AnalyticsConfig) {\n if (!analyticsClient) {\n analyticsClient = new AnalyticsBrowserClient(config);\n } else {\n analyticsClient.updateConfig(config);\n }\n\n return analyticsClient;\n}\n\nexport function getAnalyticsClient() {\n return analyticsClient;\n}\n\nexport function trackPageView(page?: AnalyticsPageInfo) {\n analyticsClient?.trackPageView(page);\n}\n\nexport function trackEvent(\n eventName: string,\n properties?: Record<string, unknown>,\n options?: TrackEventOptions\n) {\n analyticsClient?.trackEvent(eventName, properties, options);\n}\n\nexport function trackConversion(\n conversionName: string,\n properties?: Record<string, unknown>,\n conversionValue?: number | string | null\n) {\n analyticsClient?.trackConversion(conversionName, properties, conversionValue);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.js","names":[],"sources":["../../src/components/analytics/core.ts"],"sourcesContent":["'use client';\n\nimport type {\n AnalyticsConfig,\n AnalyticsConversionPayload,\n AnalyticsDeviceInfo,\n AnalyticsEventPayload,\n AnalyticsEventType,\n AnalyticsPageInfo,\n AnalyticsUtmInfo,\n TrackEventOptions,\n} from './types';\n\ntype PersistedSession = {\n id: string;\n startedAt: number;\n lastActivityAt: number;\n utm: AnalyticsUtmInfo;\n};\n\nconst DEFAULT_SESSION_TIMEOUT = 1000 * 60 * 30;\n\nexport function createAnalyticsId(prefix: string) {\n if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {\n return `${prefix}_${crypto.randomUUID()}`;\n }\n\n return `${prefix}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport function parseUtmParamsFromUrl(url: string): AnalyticsUtmInfo {\n const searchParams = new URL(url, 'https://placeholder.local').searchParams;\n\n return {\n source: searchParams.get('utm_source') || undefined,\n medium: searchParams.get('utm_medium') || undefined,\n campaign: searchParams.get('utm_campaign') || undefined,\n term: searchParams.get('utm_term') || undefined,\n content: searchParams.get('utm_content') || undefined,\n };\n}\n\nexport function shouldRotateSession(\n lastActivityAt: number,\n now: number,\n timeoutMs: number\n) {\n return now - lastActivityAt >= timeoutMs;\n}\n\nexport function detectDevice(userAgent: string): AnalyticsDeviceInfo {\n const ua = userAgent.toLowerCase();\n\n const type =\n ua.includes('bot') || ua.includes('crawler')\n ? 'bot'\n : /tablet|ipad/.test(ua)\n ? 'tablet'\n : /mobi|android|iphone/.test(ua)\n ? 'mobile'\n : 'desktop';\n\n const browser = ua.includes('edg/')\n ? 'Edge'\n : ua.includes('chrome/')\n ? 'Chrome'\n : ua.includes('firefox/')\n ? 'Firefox'\n : ua.includes('safari/') && !ua.includes('chrome/')\n ? 'Safari'\n : 'Unknown';\n\n const os = ua.includes('windows')\n ? 'Windows'\n : ua.includes('mac os') || ua.includes('macintosh')\n ? 'macOS'\n : ua.includes('iphone') || ua.includes('ipad')\n ? 'iOS'\n : ua.includes('android')\n ? 'Android'\n : ua.includes('linux')\n ? 'Linux'\n : 'Unknown';\n\n return { type, browser, os };\n}\n\nexport function getCurrentPageSnapshot(\n fallback?: AnalyticsPageInfo\n): AnalyticsPageInfo {\n if (typeof window === 'undefined') {\n return fallback || {};\n }\n\n return {\n path:\n fallback?.path ||\n `${window.location.pathname}${window.location.search || ''}`,\n title: fallback?.title || document.title,\n };\n}\n\nclass AnalyticsBrowserClient {\n private config: Required<\n Pick<AnalyticsConfig, 'sessionTimeoutMs' | 'storageKeyPrefix'>\n > &\n Omit<AnalyticsConfig, 'sessionTimeoutMs' | 'storageKeyPrefix'>;\n private queue: AnalyticsEventPayload[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(config: AnalyticsConfig) {\n this.config = {\n enabled: config.enabled ?? true,\n endpoint: config.endpoint,\n siteKey: config.siteKey,\n sessionTimeoutMs: config.sessionTimeoutMs ?? DEFAULT_SESSION_TIMEOUT,\n storageKeyPrefix: config.storageKeyPrefix ?? 'mw.analytics',\n delegatedClickTracking: config.delegatedClickTracking ?? true,\n inferClickEvents: config.inferClickEvents ?? true,\n };\n }\n\n updateConfig(config: AnalyticsConfig) {\n this.config = {\n ...this.config,\n ...config,\n enabled: config.enabled ?? this.config.enabled,\n sessionTimeoutMs: config.sessionTimeoutMs ?? this.config.sessionTimeoutMs,\n storageKeyPrefix: config.storageKeyPrefix ?? this.config.storageKeyPrefix,\n delegatedClickTracking:\n config.delegatedClickTracking ?? this.config.delegatedClickTracking,\n inferClickEvents: config.inferClickEvents ?? this.config.inferClickEvents,\n };\n }\n\n private get isEnabled() {\n return Boolean(\n this.config.enabled &&\n this.config.endpoint &&\n this.config.siteKey &&\n typeof window !== 'undefined'\n );\n }\n\n private get visitorStorageKey() {\n return `${this.config.storageKeyPrefix}.visitor`;\n }\n\n private get sessionStorageKey() {\n return `${this.config.storageKeyPrefix}.session`;\n }\n\n private getVisitorId() {\n const existingVisitorId = window.localStorage.getItem(\n this.visitorStorageKey\n );\n if (existingVisitorId) {\n return existingVisitorId;\n }\n\n const visitorId = createAnalyticsId('visitor');\n window.localStorage.setItem(this.visitorStorageKey, visitorId);\n return visitorId;\n }\n\n private getSession(now = Date.now()) {\n const rawSession = window.localStorage.getItem(this.sessionStorageKey);\n if (rawSession) {\n try {\n const persistedSession = JSON.parse(rawSession) as PersistedSession;\n if (\n !shouldRotateSession(\n persistedSession.lastActivityAt,\n now,\n this.config.sessionTimeoutMs\n )\n ) {\n return persistedSession;\n }\n } catch {}\n }\n\n const nextSession: PersistedSession = {\n id: createAnalyticsId('session'),\n startedAt: now,\n lastActivityAt: now,\n utm: parseUtmParamsFromUrl(window.location.href),\n };\n window.localStorage.setItem(\n this.sessionStorageKey,\n JSON.stringify(nextSession)\n );\n return nextSession;\n }\n\n private updateSessionActivity(session: PersistedSession, now = Date.now()) {\n const nextSession = {\n ...session,\n lastActivityAt: now,\n utm: Object.values(session.utm || {}).some(Boolean)\n ? session.utm\n : parseUtmParamsFromUrl(window.location.href),\n };\n window.localStorage.setItem(\n this.sessionStorageKey,\n JSON.stringify(nextSession)\n );\n return nextSession;\n }\n\n private enqueue(event: AnalyticsEventPayload) {\n this.queue.push(event);\n\n if (this.flushTimer) {\n return;\n }\n\n this.flushTimer = setTimeout(() => {\n void this.flush();\n }, 300);\n }\n\n async flush() {\n if (!this.isEnabled || this.queue.length === 0) {\n this.flushTimer = null;\n return;\n }\n\n const payload = JSON.stringify({\n siteKey: this.config.siteKey,\n events: [...this.queue],\n });\n\n this.queue = [];\n this.flushTimer = null;\n\n if (\n typeof navigator !== 'undefined' &&\n typeof navigator.sendBeacon === 'function'\n ) {\n const blob = new Blob([payload], { type: 'application/json' });\n if (navigator.sendBeacon(this.config.endpoint!, blob)) {\n return;\n }\n }\n\n await fetch(this.config.endpoint!, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: payload,\n keepalive: true,\n }).catch(() => null);\n }\n\n private buildEvent(\n eventType: AnalyticsEventType,\n eventName: string,\n page?: AnalyticsPageInfo,\n properties?: Record<string, unknown>,\n conversion?: AnalyticsConversionPayload\n ): AnalyticsEventPayload | null {\n if (!this.isEnabled) {\n return null;\n }\n\n const now = Date.now();\n const visitorId = this.getVisitorId();\n const session = this.updateSessionActivity(this.getSession(now), now);\n\n return {\n visitorId,\n sessionId: session.id,\n eventType,\n eventName,\n occurredAt: new Date(now).toISOString(),\n page: getCurrentPageSnapshot(page),\n referrer: document.referrer || undefined,\n utm: session.utm,\n device: detectDevice(navigator.userAgent),\n properties,\n conversion,\n };\n }\n\n trackPageView(page?: AnalyticsPageInfo) {\n const event = this.buildEvent('page_view', 'page_view', page);\n if (event) {\n this.enqueue(event);\n }\n }\n\n trackEvent(\n eventName: string,\n properties?: Record<string, unknown>,\n options?: TrackEventOptions\n ) {\n const event = this.buildEvent(\n options?.eventType ?? 'custom',\n eventName,\n options?.page,\n properties\n );\n\n if (event) {\n this.enqueue(event);\n }\n }\n\n trackConversion(\n conversionName: string,\n properties?: Record<string, unknown>,\n conversionValue?: number | string | null\n ) {\n const event = this.buildEvent(\n 'conversion',\n conversionName,\n undefined,\n properties,\n { name: conversionName, value: conversionValue }\n );\n\n if (event) {\n this.enqueue(event);\n }\n }\n}\n\nlet analyticsClient: AnalyticsBrowserClient | null = null;\n\nexport function initializeAnalytics(config: AnalyticsConfig) {\n if (!analyticsClient) {\n analyticsClient = new AnalyticsBrowserClient(config);\n } else {\n analyticsClient.updateConfig(config);\n }\n\n return analyticsClient;\n}\n\nexport function getAnalyticsClient() {\n return analyticsClient;\n}\n\nexport function trackPageView(page?: AnalyticsPageInfo) {\n analyticsClient?.trackPageView(page);\n}\n\nexport function trackEvent(\n eventName: string,\n properties?: Record<string, unknown>,\n options?: TrackEventOptions\n) {\n analyticsClient?.trackEvent(eventName, properties, options);\n}\n\nexport function trackConversion(\n conversionName: string,\n properties?: Record<string, unknown>,\n conversionValue?: number | string | null\n) {\n analyticsClient?.trackConversion(conversionName, properties, conversionValue);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegated-clicks.d.ts","names":[],"sources":["../../src/components/analytics/delegated-clicks.ts"],"
|
|
1
|
+
{"version":3,"file":"delegated-clicks.d.ts","names":[],"sources":["../../src/components/analytics/delegated-clicks.ts"],"mappings":";;;KAgBK,iCAAA;EACH,gBAAA;AAAA;AAAA,iBAkac,0BAAA,CACd,OAAA,GAAS,iCAAA;AAAA,iBAiBK,mBAAA,CAAoB,KAAA,EAAO,wBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegated-clicks.js","names":["clickTrackingOptions: Required<BindAnalyticsClickTrackingOptions>","url: URL | null","state: Record<string, string | boolean | undefined>","INFERRED_EVENT_NAMES: Record<string, string>"],"sources":["../../src/components/analytics/delegated-clicks.ts"],"sourcesContent":["'use client';\n\nimport { getAnalyticsClient, trackConversion, trackEvent } from './core';\nimport type {\n AnalyticsAttributesInput,\n AnalyticsConversionPayload,\n AnalyticsEventType,\n} from './types';\n\ntype DelegatedAnalyticsData = {\n eventName?: string;\n eventType: Exclude<AnalyticsEventType, 'conversion' | 'page_view'>;\n properties?: Record<string, unknown>;\n conversion?: AnalyticsConversionPayload;\n};\n\ntype BindAnalyticsClickTrackingOptions = {\n inferClickEvents?: boolean;\n};\n\nconst TRACKABLE_SELECTOR = [\n '[data-analytics-event]',\n '[data-analytics-conversion]',\n].join(',');\n\nconst CLICKABLE_ELEMENT_SELECTOR = [\n // Native HTML interactive elements\n 'a',\n 'area[href]',\n 'button',\n 'summary',\n 'input[type=\"submit\"]',\n 'input[type=\"button\"]',\n 'input[type=\"reset\"]',\n 'input[type=\"image\"]',\n // ARIA widget roles\n '[role=\"button\"]',\n '[role=\"link\"]',\n '[role=\"menuitem\"]',\n '[role=\"menuitemcheckbox\"]',\n '[role=\"menuitemradio\"]',\n '[role=\"tab\"]',\n '[role=\"switch\"]',\n '[role=\"checkbox\"]',\n '[role=\"radio\"]',\n '[role=\"option\"]',\n '[role=\"treeitem\"]',\n '[role=\"combobox\"]',\n // Custom focusable elements\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n\nconst INTERACTIVE_SELECTOR = [\n 'a[href]',\n 'area[href]',\n 'button',\n 'summary',\n 'input[type=\"submit\"]',\n 'input[type=\"button\"]',\n 'input[type=\"reset\"]',\n 'input[type=\"image\"]',\n '[role=\"button\"]',\n '[role=\"link\"]',\n '[role=\"menuitem\"]',\n '[role=\"menuitemcheckbox\"]',\n '[role=\"menuitemradio\"]',\n '[role=\"tab\"]',\n '[role=\"switch\"]',\n '[role=\"checkbox\"]',\n '[role=\"radio\"]',\n '[role=\"option\"]',\n '[role=\"treeitem\"]',\n '[role=\"combobox\"]',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[data-analytics-event]',\n '[data-analytics-conversion]',\n].join(',');\n\nlet clickTrackingOptions: Required<BindAnalyticsClickTrackingOptions> = {\n inferClickEvents: true,\n};\n\nfunction parseJsonObject(value: string | undefined) {\n if (!value) {\n return undefined;\n }\n\n try {\n const parsed = JSON.parse(value);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction parseConversion(element: HTMLElement) {\n const conversionName = element.dataset.analyticsConversion;\n if (!conversionName) {\n return undefined;\n }\n\n return {\n name: conversionName,\n value: element.dataset.analyticsConversionValue || undefined,\n };\n}\n\nfunction parseEventType(value: string | undefined) {\n return value === 'custom' || value === 'cta_click' ? value : 'cta_click';\n}\n\nfunction normalizeText(value: string | null | undefined, maxLength = 160) {\n const normalized = value?.replace(/\\s+/g, ' ').trim();\n if (!normalized) {\n return undefined;\n }\n\n return normalized.length > maxLength\n ? `${normalized.slice(0, maxLength - 1)}…`\n : normalized;\n}\n\nfunction resolveAriaLabelledBy(element: HTMLElement) {\n const ids = element.getAttribute('aria-labelledby');\n if (!ids) return undefined;\n\n const text = ids\n .split(/\\s+/)\n .map((id) => document.getElementById(id)?.textContent)\n .filter(Boolean)\n .join(' ');\n\n return normalizeText(text);\n}\n\nfunction getInputValue(element: HTMLElement) {\n if (element instanceof HTMLInputElement) {\n return normalizeText(element.value) || normalizeText(element.placeholder);\n }\n\n if (element instanceof HTMLSelectElement) {\n return normalizeText(element.options[element.selectedIndex]?.text);\n }\n\n return undefined;\n}\n\nfunction getElementLabel(element: HTMLElement) {\n return (\n normalizeText(element.dataset.analyticsLabel) ||\n normalizeText(element.dataset.title) ||\n normalizeText(element.getAttribute('aria-label')) ||\n resolveAriaLabelledBy(element) ||\n normalizeText(element.getAttribute('title')) ||\n normalizeText(element.getAttribute('name')) ||\n getInputValue(element) ||\n normalizeText(element.innerText || element.textContent)\n );\n}\n\nconst SECTION_SELECTOR = [\n '[data-analytics-section]',\n '[data-section]',\n // HTML5 semantic elements\n 'section',\n 'nav',\n 'header',\n 'footer',\n 'main',\n 'aside',\n 'form',\n // ARIA landmark roles\n '[role=\"navigation\"]',\n '[role=\"banner\"]',\n '[role=\"contentinfo\"]',\n '[role=\"complementary\"]',\n '[role=\"region\"]',\n '[role=\"search\"]',\n '[role=\"form\"]',\n // ARIA container/widget roles\n '[role=\"tablist\"]',\n '[role=\"menu\"]',\n '[role=\"menubar\"]',\n '[role=\"toolbar\"]',\n '[role=\"listbox\"]',\n '[role=\"tree\"]',\n '[role=\"dialog\"]',\n '[role=\"alertdialog\"]',\n].join(',');\n\nfunction getClosestSectionLabel(element: HTMLElement) {\n const section = element.closest<HTMLElement>(SECTION_SELECTOR);\n\n if (!section) {\n return undefined;\n }\n\n return (\n normalizeText(section.dataset.analyticsSection) ||\n normalizeText(section.dataset.section) ||\n normalizeText(section.getAttribute('aria-label')) ||\n normalizeText(section.getAttribute('aria-roledescription')) ||\n normalizeText(section.getAttribute('id'))\n );\n}\n\nfunction getInteractionKind(element: HTMLElement) {\n if (\n element instanceof HTMLAnchorElement ||\n element instanceof HTMLAreaElement\n ) {\n return 'link';\n }\n\n if (element instanceof HTMLButtonElement) {\n return 'button';\n }\n\n if (element instanceof HTMLInputElement) {\n const type = element.type?.toLowerCase();\n if (\n type === 'submit' ||\n type === 'button' ||\n type === 'reset' ||\n type === 'image'\n ) {\n return 'button';\n }\n return 'input';\n }\n\n if (element.tagName === 'SUMMARY') {\n return 'summary';\n }\n\n const role = element.getAttribute('role');\n switch (role) {\n case 'button':\n return 'button';\n case 'link':\n return 'link';\n case 'menuitem':\n case 'menuitemcheckbox':\n case 'menuitemradio':\n return 'menu-item';\n case 'tab':\n return 'tab';\n case 'switch':\n case 'checkbox':\n case 'radio':\n return 'toggle';\n case 'option':\n case 'treeitem':\n return 'option';\n case 'combobox':\n return 'combobox';\n default:\n return 'element';\n }\n}\n\nfunction getHrefProperties(element: HTMLElement) {\n const rawHref =\n element instanceof HTMLAnchorElement ||\n element instanceof HTMLAreaElement\n ? element.href\n : element.getAttribute('href');\n\n if (!rawHref) {\n return {};\n }\n\n let url: URL | null = null;\n try {\n url = new URL(rawHref, window.location.href);\n } catch {}\n\n return {\n href: element.getAttribute('href') || undefined,\n href_host: url?.host || undefined,\n href_path: url ? `${url.pathname}${url.search || ''}` : undefined,\n is_external: url ? url.origin !== window.location.origin : undefined,\n target: element.getAttribute('target') || undefined,\n };\n}\n\nfunction getAriaState(element: HTMLElement) {\n const state: Record<string, string | boolean | undefined> = {};\n\n const expanded = element.getAttribute('aria-expanded');\n if (expanded) state.aria_expanded = expanded === 'true';\n\n const pressed = element.getAttribute('aria-pressed');\n if (pressed) state.aria_pressed = pressed === 'true';\n\n const selected = element.getAttribute('aria-selected');\n if (selected) state.aria_selected = selected === 'true';\n\n const checked = element.getAttribute('aria-checked');\n if (checked) state.aria_checked = checked === 'true' ? true : checked;\n\n if (\n element.hasAttribute('disabled') ||\n element.getAttribute('aria-disabled') === 'true'\n ) {\n state.disabled = true;\n }\n\n return state;\n}\n\nfunction inferElementProperties(element: HTMLElement) {\n return {\n label: getElementLabel(element),\n title: normalizeText(element.getAttribute('title')),\n aria_label: normalizeText(element.getAttribute('aria-label')),\n data_title: normalizeText(element.dataset.title),\n id: normalizeText(element.id),\n name: normalizeText(element.getAttribute('name')),\n role: normalizeText(element.getAttribute('role')),\n element_type: getInteractionKind(element),\n tag_name: element.tagName.toLowerCase(),\n section: getClosestSectionLabel(element),\n ...getHrefProperties(element),\n ...getAriaState(element),\n };\n}\n\nconst INFERRED_EVENT_NAMES: Record<string, string> = {\n link: 'link_click',\n tab: 'tab_click',\n 'menu-item': 'menu_item_click',\n toggle: 'toggle_click',\n option: 'option_click',\n summary: 'summary_click',\n combobox: 'combobox_click',\n};\n\nfunction getInferredEventName(element: HTMLElement) {\n const kind = getInteractionKind(element);\n return INFERRED_EVENT_NAMES[kind] || 'button_click';\n}\n\nfunction getDelegatedAnalyticsData(\n element: HTMLElement,\n interactiveElement: HTMLElement\n): DelegatedAnalyticsData {\n const explicitProperties = parseJsonObject(\n element.dataset.analyticsProperties\n );\n const analyticsLabel = normalizeText(element.dataset.analyticsLabel);\n const conversionLabel = normalizeText(\n element.dataset.analyticsConversionLabel\n );\n\n return {\n eventName:\n element.dataset.analyticsEvent ||\n (clickTrackingOptions.inferClickEvents\n ? getInferredEventName(interactiveElement)\n : undefined),\n eventType: parseEventType(element.dataset.analyticsEventType),\n properties: {\n ...inferElementProperties(interactiveElement),\n ...explicitProperties,\n analytics_label:\n analyticsLabel ||\n (explicitProperties?.analytics_label as string | undefined),\n conversion_label:\n conversionLabel ||\n (explicitProperties?.conversion_label as string | undefined),\n },\n conversion: parseConversion(element),\n };\n}\n\nfunction findTrackableElement(target: EventTarget | null) {\n if (!(target instanceof Element)) {\n return null;\n }\n\n const explicitElement = target.closest<HTMLElement>(TRACKABLE_SELECTOR);\n if (explicitElement) {\n return explicitElement;\n }\n\n if (!clickTrackingOptions.inferClickEvents) {\n return null;\n }\n\n return target.closest<HTMLElement>(INTERACTIVE_SELECTOR);\n}\n\nfunction handleDelegatedClick(event: MouseEvent) {\n const element = findTrackableElement(event.target);\n if (\n !element ||\n event.defaultPrevented ||\n element.dataset.analyticsDisabled === 'true'\n ) {\n return;\n }\n\n const target = event.target instanceof Element ? event.target : null;\n const interactiveElement = target?.closest<HTMLElement>(\n CLICKABLE_ELEMENT_SELECTOR\n );\n if (\n !interactiveElement ||\n (!element.contains(interactiveElement) &&\n !interactiveElement.contains(element))\n ) {\n return;\n }\n\n const data = getDelegatedAnalyticsData(element, interactiveElement);\n if (data.eventName) {\n trackEvent(data.eventName, data.properties, {\n eventType: data.eventType,\n });\n }\n\n if (data.conversion) {\n trackConversion(\n data.conversion.name,\n data.properties,\n data.conversion.value\n );\n }\n\n void getAnalyticsClient()?.flush();\n}\n\nexport function bindAnalyticsClickTracking(\n options: BindAnalyticsClickTrackingOptions = {}\n) {\n if (typeof document === 'undefined') {\n return () => {};\n }\n\n clickTrackingOptions = {\n inferClickEvents: options.inferClickEvents ?? true,\n };\n\n document.addEventListener('click', handleDelegatedClick);\n\n return () => {\n document.removeEventListener('click', handleDelegatedClick);\n };\n}\n\nexport function analyticsAttributes(input: AnalyticsAttributesInput) {\n const conversion =\n typeof input.conversion === 'string'\n ? { name: input.conversion, value: input.conversionValue }\n : input.conversion;\n\n return {\n 'data-analytics-event': input.event,\n 'data-analytics-event-type': input.eventType,\n 'data-analytics-label': input.label,\n 'data-analytics-properties': input.properties\n ? JSON.stringify(input.properties)\n : undefined,\n 'data-analytics-conversion': conversion?.name,\n 'data-analytics-conversion-label': input.conversionLabel,\n 'data-analytics-conversion-value': conversion?.value ?? undefined,\n } satisfies Record<string, string | number | undefined | null>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"delegated-clicks.js","names":[],"sources":["../../src/components/analytics/delegated-clicks.ts"],"sourcesContent":["'use client';\n\nimport { getAnalyticsClient, trackConversion, trackEvent } from './core';\nimport type {\n AnalyticsAttributesInput,\n AnalyticsConversionPayload,\n AnalyticsEventType,\n} from './types';\n\ntype DelegatedAnalyticsData = {\n eventName?: string;\n eventType: Exclude<AnalyticsEventType, 'conversion' | 'page_view'>;\n properties?: Record<string, unknown>;\n conversion?: AnalyticsConversionPayload;\n};\n\ntype BindAnalyticsClickTrackingOptions = {\n inferClickEvents?: boolean;\n};\n\nconst TRACKABLE_SELECTOR = [\n '[data-analytics-event]',\n '[data-analytics-conversion]',\n].join(',');\n\nconst CLICKABLE_ELEMENT_SELECTOR = [\n // Native HTML interactive elements\n 'a',\n 'area[href]',\n 'button',\n 'summary',\n 'input[type=\"submit\"]',\n 'input[type=\"button\"]',\n 'input[type=\"reset\"]',\n 'input[type=\"image\"]',\n // ARIA widget roles\n '[role=\"button\"]',\n '[role=\"link\"]',\n '[role=\"menuitem\"]',\n '[role=\"menuitemcheckbox\"]',\n '[role=\"menuitemradio\"]',\n '[role=\"tab\"]',\n '[role=\"switch\"]',\n '[role=\"checkbox\"]',\n '[role=\"radio\"]',\n '[role=\"option\"]',\n '[role=\"treeitem\"]',\n '[role=\"combobox\"]',\n // Custom focusable elements\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n\nconst INTERACTIVE_SELECTOR = [\n 'a[href]',\n 'area[href]',\n 'button',\n 'summary',\n 'input[type=\"submit\"]',\n 'input[type=\"button\"]',\n 'input[type=\"reset\"]',\n 'input[type=\"image\"]',\n '[role=\"button\"]',\n '[role=\"link\"]',\n '[role=\"menuitem\"]',\n '[role=\"menuitemcheckbox\"]',\n '[role=\"menuitemradio\"]',\n '[role=\"tab\"]',\n '[role=\"switch\"]',\n '[role=\"checkbox\"]',\n '[role=\"radio\"]',\n '[role=\"option\"]',\n '[role=\"treeitem\"]',\n '[role=\"combobox\"]',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[data-analytics-event]',\n '[data-analytics-conversion]',\n].join(',');\n\nlet clickTrackingOptions: Required<BindAnalyticsClickTrackingOptions> = {\n inferClickEvents: true,\n};\n\nfunction parseJsonObject(value: string | undefined) {\n if (!value) {\n return undefined;\n }\n\n try {\n const parsed = JSON.parse(value);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction parseConversion(element: HTMLElement) {\n const conversionName = element.dataset.analyticsConversion;\n if (!conversionName) {\n return undefined;\n }\n\n return {\n name: conversionName,\n value: element.dataset.analyticsConversionValue || undefined,\n };\n}\n\nfunction parseEventType(value: string | undefined) {\n return value === 'custom' || value === 'cta_click' ? value : 'cta_click';\n}\n\nfunction normalizeText(value: string | null | undefined, maxLength = 160) {\n const normalized = value?.replace(/\\s+/g, ' ').trim();\n if (!normalized) {\n return undefined;\n }\n\n return normalized.length > maxLength\n ? `${normalized.slice(0, maxLength - 1)}…`\n : normalized;\n}\n\nfunction resolveAriaLabelledBy(element: HTMLElement) {\n const ids = element.getAttribute('aria-labelledby');\n if (!ids) return undefined;\n\n const text = ids\n .split(/\\s+/)\n .map((id) => document.getElementById(id)?.textContent)\n .filter(Boolean)\n .join(' ');\n\n return normalizeText(text);\n}\n\nfunction getInputValue(element: HTMLElement) {\n if (element instanceof HTMLInputElement) {\n return normalizeText(element.value) || normalizeText(element.placeholder);\n }\n\n if (element instanceof HTMLSelectElement) {\n return normalizeText(element.options[element.selectedIndex]?.text);\n }\n\n return undefined;\n}\n\nfunction getElementLabel(element: HTMLElement) {\n return (\n normalizeText(element.dataset.analyticsLabel) ||\n normalizeText(element.dataset.title) ||\n normalizeText(element.getAttribute('aria-label')) ||\n resolveAriaLabelledBy(element) ||\n normalizeText(element.getAttribute('title')) ||\n normalizeText(element.getAttribute('name')) ||\n getInputValue(element) ||\n normalizeText(element.innerText || element.textContent)\n );\n}\n\nconst SECTION_SELECTOR = [\n '[data-analytics-section]',\n '[data-section]',\n // HTML5 semantic elements\n 'section',\n 'nav',\n 'header',\n 'footer',\n 'main',\n 'aside',\n 'form',\n // ARIA landmark roles\n '[role=\"navigation\"]',\n '[role=\"banner\"]',\n '[role=\"contentinfo\"]',\n '[role=\"complementary\"]',\n '[role=\"region\"]',\n '[role=\"search\"]',\n '[role=\"form\"]',\n // ARIA container/widget roles\n '[role=\"tablist\"]',\n '[role=\"menu\"]',\n '[role=\"menubar\"]',\n '[role=\"toolbar\"]',\n '[role=\"listbox\"]',\n '[role=\"tree\"]',\n '[role=\"dialog\"]',\n '[role=\"alertdialog\"]',\n].join(',');\n\nfunction getClosestSectionLabel(element: HTMLElement) {\n const section = element.closest<HTMLElement>(SECTION_SELECTOR);\n\n if (!section) {\n return undefined;\n }\n\n return (\n normalizeText(section.dataset.analyticsSection) ||\n normalizeText(section.dataset.section) ||\n normalizeText(section.getAttribute('aria-label')) ||\n normalizeText(section.getAttribute('aria-roledescription')) ||\n normalizeText(section.getAttribute('id'))\n );\n}\n\nfunction getInteractionKind(element: HTMLElement) {\n if (\n element instanceof HTMLAnchorElement ||\n element instanceof HTMLAreaElement\n ) {\n return 'link';\n }\n\n if (element instanceof HTMLButtonElement) {\n return 'button';\n }\n\n if (element instanceof HTMLInputElement) {\n const type = element.type?.toLowerCase();\n if (\n type === 'submit' ||\n type === 'button' ||\n type === 'reset' ||\n type === 'image'\n ) {\n return 'button';\n }\n return 'input';\n }\n\n if (element.tagName === 'SUMMARY') {\n return 'summary';\n }\n\n const role = element.getAttribute('role');\n switch (role) {\n case 'button':\n return 'button';\n case 'link':\n return 'link';\n case 'menuitem':\n case 'menuitemcheckbox':\n case 'menuitemradio':\n return 'menu-item';\n case 'tab':\n return 'tab';\n case 'switch':\n case 'checkbox':\n case 'radio':\n return 'toggle';\n case 'option':\n case 'treeitem':\n return 'option';\n case 'combobox':\n return 'combobox';\n default:\n return 'element';\n }\n}\n\nfunction getHrefProperties(element: HTMLElement) {\n const rawHref =\n element instanceof HTMLAnchorElement ||\n element instanceof HTMLAreaElement\n ? element.href\n : element.getAttribute('href');\n\n if (!rawHref) {\n return {};\n }\n\n let url: URL | null = null;\n try {\n url = new URL(rawHref, window.location.href);\n } catch {}\n\n return {\n href: element.getAttribute('href') || undefined,\n href_host: url?.host || undefined,\n href_path: url ? `${url.pathname}${url.search || ''}` : undefined,\n is_external: url ? url.origin !== window.location.origin : undefined,\n target: element.getAttribute('target') || undefined,\n };\n}\n\nfunction getAriaState(element: HTMLElement) {\n const state: Record<string, string | boolean | undefined> = {};\n\n const expanded = element.getAttribute('aria-expanded');\n if (expanded) state.aria_expanded = expanded === 'true';\n\n const pressed = element.getAttribute('aria-pressed');\n if (pressed) state.aria_pressed = pressed === 'true';\n\n const selected = element.getAttribute('aria-selected');\n if (selected) state.aria_selected = selected === 'true';\n\n const checked = element.getAttribute('aria-checked');\n if (checked) state.aria_checked = checked === 'true' ? true : checked;\n\n if (\n element.hasAttribute('disabled') ||\n element.getAttribute('aria-disabled') === 'true'\n ) {\n state.disabled = true;\n }\n\n return state;\n}\n\nfunction inferElementProperties(element: HTMLElement) {\n return {\n label: getElementLabel(element),\n title: normalizeText(element.getAttribute('title')),\n aria_label: normalizeText(element.getAttribute('aria-label')),\n data_title: normalizeText(element.dataset.title),\n id: normalizeText(element.id),\n name: normalizeText(element.getAttribute('name')),\n role: normalizeText(element.getAttribute('role')),\n element_type: getInteractionKind(element),\n tag_name: element.tagName.toLowerCase(),\n section: getClosestSectionLabel(element),\n ...getHrefProperties(element),\n ...getAriaState(element),\n };\n}\n\nconst INFERRED_EVENT_NAMES: Record<string, string> = {\n link: 'link_click',\n tab: 'tab_click',\n 'menu-item': 'menu_item_click',\n toggle: 'toggle_click',\n option: 'option_click',\n summary: 'summary_click',\n combobox: 'combobox_click',\n};\n\nfunction getInferredEventName(element: HTMLElement) {\n const kind = getInteractionKind(element);\n return INFERRED_EVENT_NAMES[kind] || 'button_click';\n}\n\nfunction getDelegatedAnalyticsData(\n element: HTMLElement,\n interactiveElement: HTMLElement\n): DelegatedAnalyticsData {\n const explicitProperties = parseJsonObject(\n element.dataset.analyticsProperties\n );\n const analyticsLabel = normalizeText(element.dataset.analyticsLabel);\n const conversionLabel = normalizeText(\n element.dataset.analyticsConversionLabel\n );\n\n return {\n eventName:\n element.dataset.analyticsEvent ||\n (clickTrackingOptions.inferClickEvents\n ? getInferredEventName(interactiveElement)\n : undefined),\n eventType: parseEventType(element.dataset.analyticsEventType),\n properties: {\n ...inferElementProperties(interactiveElement),\n ...explicitProperties,\n analytics_label:\n analyticsLabel ||\n (explicitProperties?.analytics_label as string | undefined),\n conversion_label:\n conversionLabel ||\n (explicitProperties?.conversion_label as string | undefined),\n },\n conversion: parseConversion(element),\n };\n}\n\nfunction findTrackableElement(target: EventTarget | null) {\n if (!(target instanceof Element)) {\n return null;\n }\n\n const explicitElement = target.closest<HTMLElement>(TRACKABLE_SELECTOR);\n if (explicitElement) {\n return explicitElement;\n }\n\n if (!clickTrackingOptions.inferClickEvents) {\n return null;\n }\n\n return target.closest<HTMLElement>(INTERACTIVE_SELECTOR);\n}\n\nfunction handleDelegatedClick(event: MouseEvent) {\n const element = findTrackableElement(event.target);\n if (\n !element ||\n event.defaultPrevented ||\n element.dataset.analyticsDisabled === 'true'\n ) {\n return;\n }\n\n const target = event.target instanceof Element ? event.target : null;\n const interactiveElement = target?.closest<HTMLElement>(\n CLICKABLE_ELEMENT_SELECTOR\n );\n if (\n !interactiveElement ||\n (!element.contains(interactiveElement) &&\n !interactiveElement.contains(element))\n ) {\n return;\n }\n\n const data = getDelegatedAnalyticsData(element, interactiveElement);\n if (data.eventName) {\n trackEvent(data.eventName, data.properties, {\n eventType: data.eventType,\n });\n }\n\n if (data.conversion) {\n trackConversion(\n data.conversion.name,\n data.properties,\n data.conversion.value\n );\n }\n\n void getAnalyticsClient()?.flush();\n}\n\nexport function bindAnalyticsClickTracking(\n options: BindAnalyticsClickTrackingOptions = {}\n) {\n if (typeof document === 'undefined') {\n return () => {};\n }\n\n clickTrackingOptions = {\n inferClickEvents: options.inferClickEvents ?? true,\n };\n\n document.addEventListener('click', handleDelegatedClick);\n\n return () => {\n document.removeEventListener('click', handleDelegatedClick);\n };\n}\n\nexport function analyticsAttributes(input: AnalyticsAttributesInput) {\n const conversion =\n typeof input.conversion === 'string'\n ? { name: input.conversion, value: input.conversionValue }\n : input.conversion;\n\n return {\n 'data-analytics-event': input.event,\n 'data-analytics-event-type': input.eventType,\n 'data-analytics-label': input.label,\n 'data-analytics-properties': input.properties\n ? JSON.stringify(input.properties)\n : undefined,\n 'data-analytics-conversion': conversion?.name,\n 'data-analytics-conversion-label': input.conversionLabel,\n 'data-analytics-conversion-value': conversion?.value ?? undefined,\n } satisfies Record<string, string | number | undefined | null>;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnalyticsConfig } from "./types.js";
|
|
2
2
|
import { trackConversion, trackEvent, trackPageView } from "./core.js";
|
|
3
|
-
import * as
|
|
3
|
+
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/components/analytics/provider.d.ts
|
|
6
6
|
declare function AnalyticsProvider({
|
|
@@ -9,7 +9,7 @@ declare function AnalyticsProvider({
|
|
|
9
9
|
}: {
|
|
10
10
|
children: React.ReactNode;
|
|
11
11
|
config?: AnalyticsConfig;
|
|
12
|
-
}):
|
|
12
|
+
}): _$react_jsx_runtime0.JSX.Element;
|
|
13
13
|
declare function useAnalytics(): {
|
|
14
14
|
enabled: boolean;
|
|
15
15
|
trackPageView: typeof trackPageView;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","names":[],"sources":["../../src/components/analytics/provider.tsx"],"
|
|
1
|
+
{"version":3,"file":"provider.d.ts","names":[],"sources":["../../src/components/analytics/provider.tsx"],"mappings":";;;;;iBA6DgB,iBAAA,CAAA;EACd,QAAA;EACA,MAAA,EAAQ;AAAA;EAER,QAAA,EAAU,KAAA,CAAM,SAAA;EAChB,MAAA,GAAS,eAAA;AAAA,IACV,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAwCe,YAAA,CAAA"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import { initializeAnalytics, trackConversion, trackEvent, trackPageView } from "./core.js";
|
|
5
4
|
import { bindAnalyticsClickTracking } from "./delegated-clicks.js";
|
|
6
5
|
import { Suspense, createContext, useContext, useEffect, useMemo, useRef } from "react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","names":["trackPageViewCore","trackEventCore","trackConversionCore"],"sources":["../../src/components/analytics/provider.tsx"],"sourcesContent":["'use client';\n\nimport {\n Suspense,\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport { usePathname, useSearchParams } from 'next/navigation';\n\nimport {\n initializeAnalytics,\n trackConversion as trackConversionCore,\n trackEvent as trackEventCore,\n trackPageView as trackPageViewCore,\n} from './core';\nimport { bindAnalyticsClickTracking } from './delegated-clicks';\nimport type { AnalyticsConfig, TrackEventOptions } from './types';\n\nfunction getEnvConfig(): AnalyticsConfig {\n const siteKey = process.env.NEXT_PUBLIC_ANALYTICS_SITE_KEY;\n const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;\n\n return {\n enabled: Boolean(siteKey),\n endpoint: baseUrl ? `${baseUrl}/public/analytics/collect/` : undefined,\n siteKey: siteKey || undefined,\n };\n}\n\nconst AnalyticsContext = createContext({\n enabled: false,\n trackPageView: trackPageViewCore,\n trackEvent: trackEventCore,\n trackConversion: trackConversionCore,\n});\n\nfunction AnalyticsPageViewTracker({ config }: { config: AnalyticsConfig }) {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n const routeKey = `${pathname}${searchParams.toString() ? `?${searchParams.toString()}` : ''}`;\n const lastRouteRef = useRef('');\n\n useEffect(() => {\n if (!config.enabled || !config.endpoint || !config.siteKey) {\n return;\n }\n\n if (lastRouteRef.current === routeKey) {\n return;\n }\n\n lastRouteRef.current = routeKey;\n trackPageViewCore();\n }, [config.enabled, config.endpoint, config.siteKey, routeKey]);\n\n return null;\n}\n\nexport function AnalyticsProvider({\n children,\n config: configOverride,\n}: {\n children: React.ReactNode;\n config?: AnalyticsConfig;\n}) {\n const config = useMemo(\n () => ({ ...getEnvConfig(), ...configOverride }),\n [configOverride]\n );\n\n useEffect(() => {\n initializeAnalytics(config);\n }, [config]);\n\n useEffect(() => {\n if (config.delegatedClickTracking === false) {\n return;\n }\n\n return bindAnalyticsClickTracking({\n inferClickEvents: config.inferClickEvents,\n });\n }, [config.delegatedClickTracking, config.inferClickEvents]);\n\n const value = useMemo(\n () => ({\n enabled: Boolean(config.enabled && config.endpoint && config.siteKey),\n trackPageView: trackPageViewCore,\n trackEvent: trackEventCore,\n trackConversion: trackConversionCore,\n }),\n [config.enabled, config.endpoint, config.siteKey]\n );\n\n return (\n <AnalyticsContext.Provider value={value}>\n <Suspense>\n <AnalyticsPageViewTracker config={config} />\n </Suspense>\n {children}\n </AnalyticsContext.Provider>\n );\n}\n\nexport function useAnalytics() {\n return useContext(AnalyticsContext);\n}\n\nexport type AnalyticsHook = {\n enabled: boolean;\n trackPageView: (page?: { path?: string; title?: string }) => void;\n trackEvent: (\n eventName: string,\n properties?: Record<string, unknown>,\n options?: TrackEventOptions\n ) => void;\n trackConversion: (\n conversionName: string,\n properties?: Record<string, unknown>,\n conversionValue?: number | string | null\n ) => void;\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"provider.js","names":["trackPageViewCore","trackEventCore","trackConversionCore"],"sources":["../../src/components/analytics/provider.tsx"],"sourcesContent":["'use client';\n\nimport {\n Suspense,\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport { usePathname, useSearchParams } from 'next/navigation';\n\nimport {\n initializeAnalytics,\n trackConversion as trackConversionCore,\n trackEvent as trackEventCore,\n trackPageView as trackPageViewCore,\n} from './core';\nimport { bindAnalyticsClickTracking } from './delegated-clicks';\nimport type { AnalyticsConfig, TrackEventOptions } from './types';\n\nfunction getEnvConfig(): AnalyticsConfig {\n const siteKey = process.env.NEXT_PUBLIC_ANALYTICS_SITE_KEY;\n const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;\n\n return {\n enabled: Boolean(siteKey),\n endpoint: baseUrl ? `${baseUrl}/public/analytics/collect/` : undefined,\n siteKey: siteKey || undefined,\n };\n}\n\nconst AnalyticsContext = createContext({\n enabled: false,\n trackPageView: trackPageViewCore,\n trackEvent: trackEventCore,\n trackConversion: trackConversionCore,\n});\n\nfunction AnalyticsPageViewTracker({ config }: { config: AnalyticsConfig }) {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n const routeKey = `${pathname}${searchParams.toString() ? `?${searchParams.toString()}` : ''}`;\n const lastRouteRef = useRef('');\n\n useEffect(() => {\n if (!config.enabled || !config.endpoint || !config.siteKey) {\n return;\n }\n\n if (lastRouteRef.current === routeKey) {\n return;\n }\n\n lastRouteRef.current = routeKey;\n trackPageViewCore();\n }, [config.enabled, config.endpoint, config.siteKey, routeKey]);\n\n return null;\n}\n\nexport function AnalyticsProvider({\n children,\n config: configOverride,\n}: {\n children: React.ReactNode;\n config?: AnalyticsConfig;\n}) {\n const config = useMemo(\n () => ({ ...getEnvConfig(), ...configOverride }),\n [configOverride]\n );\n\n useEffect(() => {\n initializeAnalytics(config);\n }, [config]);\n\n useEffect(() => {\n if (config.delegatedClickTracking === false) {\n return;\n }\n\n return bindAnalyticsClickTracking({\n inferClickEvents: config.inferClickEvents,\n });\n }, [config.delegatedClickTracking, config.inferClickEvents]);\n\n const value = useMemo(\n () => ({\n enabled: Boolean(config.enabled && config.endpoint && config.siteKey),\n trackPageView: trackPageViewCore,\n trackEvent: trackEventCore,\n trackConversion: trackConversionCore,\n }),\n [config.enabled, config.endpoint, config.siteKey]\n );\n\n return (\n <AnalyticsContext.Provider value={value}>\n <Suspense>\n <AnalyticsPageViewTracker config={config} />\n </Suspense>\n {children}\n </AnalyticsContext.Provider>\n );\n}\n\nexport function useAnalytics() {\n return useContext(AnalyticsContext);\n}\n\nexport type AnalyticsHook = {\n enabled: boolean;\n trackPageView: (page?: { path?: string; title?: string }) => void;\n trackEvent: (\n eventName: string,\n properties?: Record<string, unknown>,\n options?: TrackEventOptions\n ) => void;\n trackConversion: (\n conversionName: string,\n properties?: Record<string, unknown>,\n conversionValue?: number | string | null\n ) => void;\n};\n"],"mappings":";;;;;;;;;AAqBA,SAAS,eAAgC;CACvC,MAAM,UAAU,QAAQ,IAAI;CAC5B,MAAM,UAAU,QAAQ,IAAI;AAE5B,QAAO;EACL,SAAS,QAAQ,QAAQ;EACzB,UAAU,UAAU,GAAG,QAAQ,8BAA8B;EAC7D,SAAS,WAAW;EACrB;;AAGH,MAAM,mBAAmB,cAAc;CACrC,SAAS;CACMA;CACHC;CACKC;CAClB,CAAC;AAEF,SAAS,yBAAyB,EAAE,UAAuC;CACzE,MAAM,WAAW,aAAa;CAC9B,MAAM,eAAe,iBAAiB;CACtC,MAAM,WAAW,GAAG,WAAW,aAAa,UAAU,GAAG,IAAI,aAAa,UAAU,KAAK;CACzF,MAAM,eAAe,OAAO,GAAG;AAE/B,iBAAgB;AACd,MAAI,CAAC,OAAO,WAAW,CAAC,OAAO,YAAY,CAAC,OAAO,QACjD;AAGF,MAAI,aAAa,YAAY,SAC3B;AAGF,eAAa,UAAU;AACvB,iBAAmB;IAClB;EAAC,OAAO;EAAS,OAAO;EAAU,OAAO;EAAS;EAAS,CAAC;AAE/D,QAAO;;AAGT,SAAgB,kBAAkB,EAChC,UACA,QAAQ,kBAIP;CACD,MAAM,SAAS,eACN;EAAE,GAAG,cAAc;EAAE,GAAG;EAAgB,GAC/C,CAAC,eAAe,CACjB;AAED,iBAAgB;AACd,sBAAoB,OAAO;IAC1B,CAAC,OAAO,CAAC;AAEZ,iBAAgB;AACd,MAAI,OAAO,2BAA2B,MACpC;AAGF,SAAO,2BAA2B,EAChC,kBAAkB,OAAO,kBAC1B,CAAC;IACD,CAAC,OAAO,wBAAwB,OAAO,iBAAiB,CAAC;CAE5D,MAAM,QAAQ,eACL;EACL,SAAS,QAAQ,OAAO,WAAW,OAAO,YAAY,OAAO,QAAQ;EACtDF;EACHC;EACKC;EAClB,GACD;EAAC,OAAO;EAAS,OAAO;EAAU,OAAO;EAAQ,CAClD;AAED,QACE,qBAAC,iBAAiB,UAAlB;EAAkC;YAAlC,CACE,oBAAC,UAAD,YACE,oBAAC,0BAAD,EAAkC,QAAU,GACnC,GACV,SACyB;;;AAIhC,SAAgB,eAAe;AAC7B,QAAO,WAAW,iBAAiB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/components/analytics/types.ts"],"
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/components/analytics/types.ts"],"mappings":";KAAY,kBAAA;AAAA,KAMA,mBAAA;EACV,IAAA;EACA,OAAA;EACA,EAAA;AAAA;AAAA,KAGU,gBAAA;EACV,MAAA;EACA,MAAA;EACA,QAAA;EACA,IAAA;EACA,OAAA;AAAA;AAAA,KAGU,iBAAA;EACV,IAAA;EACA,KAAA;AAAA;AAAA,KAGU,0BAAA;EACV,IAAA;EACA,KAAA;AAAA;AAAA,KAGU,qBAAA;EACV,SAAA;EACA,SAAA;EACA,SAAA,EAAW,kBAAA;EACX,SAAA;EACA,UAAA;EACA,IAAA,EAAM,iBAAA;EACN,QAAA;EACA,GAAA,GAAM,gBAAA;EACN,MAAA,GAAS,mBAAA;EACT,UAAA,GAAa,MAAA;EACb,UAAA,GAAa,0BAAA;AAAA;AAAA,KAGH,eAAA;EACV,QAAA;EACA,OAAA;EACA,OAAA;EACA,gBAAA;EACA,gBAAA;EACA,sBAAA;EACA,gBAAA;AAAA;AAAA,KAGU,iBAAA;EACV,SAAA,GAAY,OAAA,CAAQ,kBAAA;EACpB,IAAA,GAAO,iBAAA;EACP,UAAA,GAAa,MAAA;AAAA;AAAA,KAGH,wBAAA;EACV,KAAA;EACA,SAAA,GAAY,OAAA,CAAQ,kBAAA;EACpB,KAAA;EACA,UAAA,GAAa,MAAA;EACb,UAAA,GAAa,0BAAA;EACb,eAAA;EACA,eAAA;AAAA"}
|
package/dist/analytics.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import { createAnalyticsId, detectDevice, getAnalyticsClient, getCurrentPageSnapshot, initializeAnalytics, parseUtmParamsFromUrl, shouldRotateSession, trackConversion, trackEvent, trackPageView } from "./analytics/core.js";
|
|
5
4
|
import { analyticsAttributes, bindAnalyticsClickTracking } from "./analytics/delegated-clicks.js";
|
|
6
5
|
import { AnalyticsProvider, useAnalytics } from "./analytics/provider.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComponentProps, ElementType } from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/container-animation/container-animation.d.ts
|
|
5
5
|
type ContainerAnimationProps<T extends ElementType = 'div'> = ComponentProps<'div'> & ComponentProps<T> & {
|
|
@@ -23,7 +23,7 @@ declare const ContainerAnimation: <T extends ElementType = "div">({
|
|
|
23
23
|
distance,
|
|
24
24
|
hideNotInView,
|
|
25
25
|
...props
|
|
26
|
-
}: ContainerAnimationProps<T>) =>
|
|
26
|
+
}: ContainerAnimationProps<T>) => _$react_jsx_runtime0.JSX.Element;
|
|
27
27
|
//#endregion
|
|
28
28
|
export { ContainerAnimation, ContainerAnimationProps };
|
|
29
29
|
//# sourceMappingURL=container-animation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-animation.d.ts","names":[],"sources":["../../src/components/container-animation/container-animation.tsx"],"
|
|
1
|
+
{"version":3,"file":"container-animation.d.ts","names":[],"sources":["../../src/components/container-animation/container-animation.tsx"],"mappings":";;;;KAiDY,uBAAA,WAAkC,WAAA,YAC5C,cAAA,UACE,cAAA,CAAe,CAAA;EACb,QAAA;EACA,KAAA;EACA,KAAA;EACA,QAAA;EACA,QAAA;EACA,aAAA;EACA,EAAA,GAAK,CAAA;EACL,SAAA;AAAA;AAAA,cAGA,kBAAA,aAAgC,WAAA;EAAqB,SAAA;EAAA,QAAA;EAAA,QAAA;EAAA,KAAA;EAAA,KAAA;EAAA,QAAA;EAAA,EAAA,EAAA,EAAA;EAAA,QAAA;EAAA,aAAA;EAAA,GAAA;AAAA,GAWxD,uBAAA,CAAwB,CAAA,MAAE,oBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import { cn } from "../src/lib/utils.js";
|
|
5
4
|
import { useInView } from "../node_modules/framer-motion/dist/es/utils/use-in-view.js";
|
|
6
5
|
import { useRef } from "react";
|
|
@@ -33,7 +32,7 @@ const getVariants = (position, space, delay) => {
|
|
|
33
32
|
}
|
|
34
33
|
};
|
|
35
34
|
};
|
|
36
|
-
const ContainerAnimation = ({ className, children, position = "top", delay = 0, space = 20, duration = .8, as: As = "div", distance = [95, 5], hideNotInView = false
|
|
35
|
+
const ContainerAnimation = ({ className, children, position = "top", delay = 0, space = 20, duration = .8, as: As = "div", distance = [95, 5], hideNotInView = false, ...props }) => {
|
|
37
36
|
const ref = useRef(null);
|
|
38
37
|
const isInView = useInView(ref, {
|
|
39
38
|
once: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-animation.js","names":[],"sources":["../../src/components/container-animation/container-animation.tsx"],"sourcesContent":["'use client';\n\nimport { type ComponentProps, type ElementType, useRef } from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { useInView } from 'motion/react';\nimport * as motion from 'motion/react-m';\n\nconst getVariants = (\n position: 'top' | 'bottom' | 'left' | 'right',\n space: number,\n delay: number\n) => {\n const directions = {\n top: {\n transform: `translateY(${space}px)`,\n },\n bottom: {\n transform: `translateY(-${space}px)`,\n },\n left: {\n transform: `translateX(${space}px)`,\n },\n right: {\n transform: `translateX(-${space}px)`,\n },\n };\n\n const dir = directions[position] || directions.top;\n\n return {\n hidden: {\n opacity: 0,\n filter: 'blur(6px)',\n ...dir,\n },\n visible: {\n opacity: 1,\n filter: 'blur(0px)',\n transform: 'translateY(0px) translateX(0px)',\n transition: {\n delay,\n duration: 0.5,\n staggerChildren: 0.1,\n },\n },\n };\n};\n\nexport type ContainerAnimationProps<T extends ElementType = 'div'> =\n ComponentProps<'div'> &\n ComponentProps<T> & {\n position?: 'top' | 'bottom' | 'left' | 'right';\n delay?: number;\n space?: number;\n duration?: number;\n distance?: [number, number];\n hideNotInView?: boolean;\n as?: T | string;\n className?: string;\n };\n\nconst ContainerAnimation = <T extends ElementType = 'div'>({\n className,\n children,\n position = 'top',\n delay = 0,\n space = 20,\n duration = 0.8,\n as: As = 'div',\n distance = [95, 5],\n hideNotInView = false,\n ...props\n}: ContainerAnimationProps<T>) => {\n const ref = useRef<HTMLElement>(null);\n const isInView = useInView(ref, {\n once: true,\n margin:\n `-${100 - (distance[0] || 0)}% 0% -${(distance[1] as number) || 0}% 0%` as any,\n });\n\n const variants = getVariants(position, space, delay);\n\n return (\n <motion.div\n animate={isInView ? 'visible' : 'hidden'}\n className={cn('initial-opacity', className)}\n initial=\"hidden\"\n transition={{ duration }}\n variants={variants}\n {...props}\n ref={ref}\n >\n {(!hideNotInView || isInView) && children}\n </motion.div>\n );\n};\n\nexport { ContainerAnimation };\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"container-animation.js","names":[],"sources":["../../src/components/container-animation/container-animation.tsx"],"sourcesContent":["'use client';\n\nimport { type ComponentProps, type ElementType, useRef } from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { useInView } from 'motion/react';\nimport * as motion from 'motion/react-m';\n\nconst getVariants = (\n position: 'top' | 'bottom' | 'left' | 'right',\n space: number,\n delay: number\n) => {\n const directions = {\n top: {\n transform: `translateY(${space}px)`,\n },\n bottom: {\n transform: `translateY(-${space}px)`,\n },\n left: {\n transform: `translateX(${space}px)`,\n },\n right: {\n transform: `translateX(-${space}px)`,\n },\n };\n\n const dir = directions[position] || directions.top;\n\n return {\n hidden: {\n opacity: 0,\n filter: 'blur(6px)',\n ...dir,\n },\n visible: {\n opacity: 1,\n filter: 'blur(0px)',\n transform: 'translateY(0px) translateX(0px)',\n transition: {\n delay,\n duration: 0.5,\n staggerChildren: 0.1,\n },\n },\n };\n};\n\nexport type ContainerAnimationProps<T extends ElementType = 'div'> =\n ComponentProps<'div'> &\n ComponentProps<T> & {\n position?: 'top' | 'bottom' | 'left' | 'right';\n delay?: number;\n space?: number;\n duration?: number;\n distance?: [number, number];\n hideNotInView?: boolean;\n as?: T | string;\n className?: string;\n };\n\nconst ContainerAnimation = <T extends ElementType = 'div'>({\n className,\n children,\n position = 'top',\n delay = 0,\n space = 20,\n duration = 0.8,\n as: As = 'div',\n distance = [95, 5],\n hideNotInView = false,\n ...props\n}: ContainerAnimationProps<T>) => {\n const ref = useRef<HTMLElement>(null);\n const isInView = useInView(ref, {\n once: true,\n margin:\n `-${100 - (distance[0] || 0)}% 0% -${(distance[1] as number) || 0}% 0%` as any,\n });\n\n const variants = getVariants(position, space, delay);\n\n return (\n <motion.div\n animate={isInView ? 'visible' : 'hidden'}\n className={cn('initial-opacity', className)}\n initial=\"hidden\"\n transition={{ duration }}\n variants={variants}\n {...props}\n ref={ref}\n >\n {(!hideNotInView || isInView) && children}\n </motion.div>\n );\n};\n\nexport { ContainerAnimation };\n"],"mappings":";;;;;;;;;AAQA,MAAM,eACJ,UACA,OACA,UACG;CACH,MAAM,aAAa;EACjB,KAAK,EACH,WAAW,cAAc,MAAM,MAChC;EACD,QAAQ,EACN,WAAW,eAAe,MAAM,MACjC;EACD,MAAM,EACJ,WAAW,cAAc,MAAM,MAChC;EACD,OAAO,EACL,WAAW,eAAe,MAAM,MACjC;EACF;AAID,QAAO;EACL,QAAQ;GACN,SAAS;GACT,QAAQ;GACR,GANQ,WAAW,aAAa,WAAW;GAO5C;EACD,SAAS;GACP,SAAS;GACT,QAAQ;GACR,WAAW;GACX,YAAY;IACV;IACA,UAAU;IACV,iBAAiB;IAClB;GACF;EACF;;AAgBH,MAAM,sBAAqD,EACzD,WACA,UACA,WAAW,OACX,QAAQ,GACR,QAAQ,IACR,WAAW,IACX,IAAI,KAAK,OACT,WAAW,CAAC,IAAI,EAAE,EAClB,gBAAgB,OAChB,GAAG,YAC6B;CAChC,MAAM,MAAM,OAAoB,KAAK;CACrC,MAAM,WAAW,UAAU,KAAK;EAC9B,MAAM;EACN,QACE,IAAI,OAAO,SAAS,MAAM,GAAG,QAAS,SAAS,MAAiB,EAAE;EACrE,CAAC;CAEF,MAAM,WAAW,YAAY,UAAU,OAAO,MAAM;AAEpD,QACE,oBAAC,OAAO,KAAR;EACE,SAAS,WAAW,YAAY;EAChC,WAAW,GAAG,mBAAmB,UAAU;EAC3C,SAAQ;EACR,YAAY,EAAE,UAAU;EACd;EACV,GAAI;EACC;aAEH,CAAC,iBAAiB,aAAa;EACtB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FieldPath, FieldValues, UseControllerProps } from "react-hook-form";
|
|
2
|
-
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
+
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
3
|
import { Matcher } from "react-day-picker";
|
|
4
4
|
|
|
5
5
|
//#region src/components/date-field/DateField.d.ts
|
|
@@ -29,7 +29,7 @@ declare function DateField<TFieldValues extends FieldValues = FieldValues, TFiel
|
|
|
29
29
|
required,
|
|
30
30
|
help,
|
|
31
31
|
dateOnly
|
|
32
|
-
}: DateFieldProps<TFieldValues, TFieldName>): react_jsx_runtime0.JSX.Element;
|
|
32
|
+
}: DateFieldProps<TFieldValues, TFieldName>): _$react_jsx_runtime0.JSX.Element;
|
|
33
33
|
//#endregion
|
|
34
34
|
export { DateField, DateFieldProps };
|
|
35
35
|
//# sourceMappingURL=DateField.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateField.d.ts","names":[],"sources":["../../src/components/date-field/DateField.tsx"],"
|
|
1
|
+
{"version":3,"file":"DateField.d.ts","names":[],"sources":["../../src/components/date-field/DateField.tsx"],"mappings":";;;;;UA4BiB,cAAA,sBACM,WAAA,GAAc,WAAA,qBAChB,SAAA,CAAU,YAAA,IAAgB,SAAA,CAAU,YAAA,WAC/C,IAAA,CAAK,kBAAA,CAAmB,YAAA,EAAc,UAAA;EAC9C,KAAA;EACA,WAAA;EACA,WAAA;EACA,SAAA;EACA,QAAA,GAAW,OAAA,GAAU,OAAA;EACrB,aAAA;EACA,YAAA,GAAe,IAAA;EACf,QAAA,GAAW,IAAA;EACX,QAAA;EACA,IAAA;EAX6C;EAa7C,QAAA;AAAA;AAAA,iBAGO,SAAA,sBACc,WAAA,GAAc,WAAA,qBAChB,SAAA,CAAU,YAAA,IAAgB,SAAA,CAAU,YAAA,EAAA,CAAA;EAEvD,IAAA;EACA,KAAA;EACA,WAAA;EACA,aAAA;EACA,QAAA;EACA,SAAA;EACA,QAAA;EACA,YAAA;EACA,QAAA;EACA,IAAA;EACA;AAAA,GACC,cAAA,CAAe,YAAA,EAAc,UAAA,IAAW,oBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateField.js","names":[],"sources":["../../src/components/date-field/DateField.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\n\nimport {\n type FieldPath,\n type FieldValues,\n type UseControllerProps,\n useController,\n useFormContext,\n} from 'react-hook-form';\n\nimport { Calendar } from '@/ui/calendar';\nimport {\n FormDescription,\n FormFieldContext,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/ui/form';\nimport { InputDateField } from '@/ui/input-date-field';\nimport { InputHelp } from '@/ui/input-help';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/ui/popover';\n\nimport { cn } from '@/lib/utils';\nimport { ptBR } from 'date-fns/locale';\nimport type { Matcher } from 'react-day-picker';\n\nexport interface DateFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> extends Omit<UseControllerProps<TFieldValues, TFieldName>, 'disabled'> {\n label: string;\n description?: string;\n placeholder?: string;\n className?: string;\n disabled?: Matcher | Matcher[] | undefined;\n inputDisabled?: boolean;\n initialValue?: Date;\n endMonth?: Date;\n required?: boolean;\n help?: string;\n /** Quando true, o valor será formatado como string YYYY-MM-DD ao invés de Date com horário */\n dateOnly?: boolean;\n}\n\nfunction DateField<\n TFieldValues extends FieldValues = FieldValues,\n TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n name,\n label,\n description,\n inputDisabled,\n endMonth,\n className,\n disabled,\n initialValue,\n required,\n help,\n dateOnly,\n}: DateFieldProps<TFieldValues, TFieldName>) {\n const form = useFormContext();\n const { field, fieldState } = useController({\n name,\n defaultValue: initialValue as any,\n rules: { required },\n control: form.control,\n });\n\n const [isOpen, setIsOpen] = useState(false);\n const handleSelect = (date: Date | undefined) => {\n if (dateOnly && date) {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n field.onChange(`${year}-${month}-${day}`);\n } else {\n field.onChange(date);\n }\n setIsOpen(false);\n };\n\n return (\n <FormFieldContext.Provider value={{ name }}>\n <FormItem className={className} id={`date-${name.replace('.', '-')}`}>\n <div className=\"flex items-end gap-1.5\">\n <FormLabel htmlFor={name}>\n {label}:\n {required && (\n <span className=\"text-red-500 text-lg leading-[1px]\">*</span>\n )}\n </FormLabel>\n\n <InputHelp help={help} name={name} />\n </div>\n\n <Popover onOpenChange={setIsOpen} open={!inputDisabled && isOpen}>\n <PopoverTrigger\n className=\"w-full mt-0! outline-hidden\"\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n }}\n tabIndex={-1}\n >\n <InputDateField\n className={cn(fieldState.error && 'border-destructive')}\n dateOnly={dateOnly}\n disabled={inputDisabled}\n field={field}\n id={name}\n onFinish={() => setIsOpen(false)}\n onFocus={() => setIsOpen(true)}\n />\n </PopoverTrigger>\n <PopoverContent\n className=\"flex justify-center w-fit p-0\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <Calendar\n defaultMonth={field.value || new Date()}\n disabled={disabled}\n endMonth={endMonth}\n key={`${name}-${field.value?.toString()}`}\n locale={ptBR}\n mode=\"single\"\n onSelect={handleSelect}\n selected={field.value}\n />\n </PopoverContent>\n </Popover>\n\n <FormDescription>{description}</FormDescription>\n {fieldState.error && <FormMessage />}\n </FormItem>\n </FormFieldContext.Provider>\n );\n}\n\nexport { DateField };\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"DateField.js","names":[],"sources":["../../src/components/date-field/DateField.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\n\nimport {\n type FieldPath,\n type FieldValues,\n type UseControllerProps,\n useController,\n useFormContext,\n} from 'react-hook-form';\n\nimport { Calendar } from '@/ui/calendar';\nimport {\n FormDescription,\n FormFieldContext,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/ui/form';\nimport { InputDateField } from '@/ui/input-date-field';\nimport { InputHelp } from '@/ui/input-help';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/ui/popover';\n\nimport { cn } from '@/lib/utils';\nimport { ptBR } from 'date-fns/locale';\nimport type { Matcher } from 'react-day-picker';\n\nexport interface DateFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> extends Omit<UseControllerProps<TFieldValues, TFieldName>, 'disabled'> {\n label: string;\n description?: string;\n placeholder?: string;\n className?: string;\n disabled?: Matcher | Matcher[] | undefined;\n inputDisabled?: boolean;\n initialValue?: Date;\n endMonth?: Date;\n required?: boolean;\n help?: string;\n /** Quando true, o valor será formatado como string YYYY-MM-DD ao invés de Date com horário */\n dateOnly?: boolean;\n}\n\nfunction DateField<\n TFieldValues extends FieldValues = FieldValues,\n TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n name,\n label,\n description,\n inputDisabled,\n endMonth,\n className,\n disabled,\n initialValue,\n required,\n help,\n dateOnly,\n}: DateFieldProps<TFieldValues, TFieldName>) {\n const form = useFormContext();\n const { field, fieldState } = useController({\n name,\n defaultValue: initialValue as any,\n rules: { required },\n control: form.control,\n });\n\n const [isOpen, setIsOpen] = useState(false);\n const handleSelect = (date: Date | undefined) => {\n if (dateOnly && date) {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n field.onChange(`${year}-${month}-${day}`);\n } else {\n field.onChange(date);\n }\n setIsOpen(false);\n };\n\n return (\n <FormFieldContext.Provider value={{ name }}>\n <FormItem className={className} id={`date-${name.replace('.', '-')}`}>\n <div className=\"flex items-end gap-1.5\">\n <FormLabel htmlFor={name}>\n {label}:\n {required && (\n <span className=\"text-red-500 text-lg leading-[1px]\">*</span>\n )}\n </FormLabel>\n\n <InputHelp help={help} name={name} />\n </div>\n\n <Popover onOpenChange={setIsOpen} open={!inputDisabled && isOpen}>\n <PopoverTrigger\n className=\"w-full mt-0! outline-hidden\"\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n }}\n tabIndex={-1}\n >\n <InputDateField\n className={cn(fieldState.error && 'border-destructive')}\n dateOnly={dateOnly}\n disabled={inputDisabled}\n field={field}\n id={name}\n onFinish={() => setIsOpen(false)}\n onFocus={() => setIsOpen(true)}\n />\n </PopoverTrigger>\n <PopoverContent\n className=\"flex justify-center w-fit p-0\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <Calendar\n defaultMonth={field.value || new Date()}\n disabled={disabled}\n endMonth={endMonth}\n key={`${name}-${field.value?.toString()}`}\n locale={ptBR}\n mode=\"single\"\n onSelect={handleSelect}\n selected={field.value}\n />\n </PopoverContent>\n </Popover>\n\n <FormDescription>{description}</FormDescription>\n {fieldState.error && <FormMessage />}\n </FormItem>\n </FormFieldContext.Provider>\n );\n}\n\nexport { DateField };\n"],"mappings":";;;;;;;;;;;;;;AA8CA,SAAS,UAGP,EACA,MACA,OACA,aACA,eACA,UACA,WACA,UACA,cACA,UACA,MACA,YAC2C;CAC3C,MAAM,OAAO,gBAAgB;CAC7B,MAAM,EAAE,OAAO,eAAe,cAAc;EAC1C;EACA,cAAc;EACd,OAAO,EAAE,UAAU;EACnB,SAAS,KAAK;EACf,CAAC;CAEF,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAC3C,MAAM,gBAAgB,SAA2B;AAC/C,MAAI,YAAY,MAAM;GACpB,MAAM,OAAO,KAAK,aAAa;GAC/B,MAAM,QAAQ,OAAO,KAAK,UAAU,GAAG,EAAE,CAAC,SAAS,GAAG,IAAI;GAC1D,MAAM,MAAM,OAAO,KAAK,SAAS,CAAC,CAAC,SAAS,GAAG,IAAI;AACnD,SAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM;QAEzC,OAAM,SAAS,KAAK;AAEtB,YAAU,MAAM;;AAGlB,QACE,oBAAC,iBAAiB,UAAlB;EAA2B,OAAO,EAAE,MAAM;YACxC,qBAAC,UAAD;GAAqB;GAAW,IAAI,QAAQ,KAAK,QAAQ,KAAK,IAAI;aAAlE;IACE,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,qBAAC,WAAD;MAAW,SAAS;gBAApB;OACG;OAAM;OACN,YACC,oBAAC,QAAD;QAAM,WAAU;kBAAqC;QAAQ;OAErD;SAEZ,oBAAC,WAAD;MAAiB;MAAY;MAAQ,EACjC;;IAEN,qBAAC,SAAD;KAAS,cAAc;KAAW,MAAM,CAAC,iBAAiB;eAA1D,CACE,oBAAC,gBAAD;MACE,WAAU;MACV,UAAU,UAAU;AAClB,aAAM,gBAAgB;AACtB,aAAM,iBAAiB;;MAEzB,UAAU;gBAEV,oBAAC,gBAAD;OACE,WAAW,GAAG,WAAW,SAAS,qBAAqB;OAC7C;OACV,UAAU;OACH;OACP,IAAI;OACJ,gBAAgB,UAAU,MAAM;OAChC,eAAe,UAAU,KAAK;OAC9B;MACa,GACjB,oBAAC,gBAAD;MACE,WAAU;MACV,kBAAkB,MAAM,EAAE,gBAAgB;gBAE1C,oBAAC,UAAD;OACE,cAAc,MAAM,yBAAS,IAAI,MAAM;OAC7B;OACA;OAEV,QAAQ;OACR,MAAK;OACL,UAAU;OACV,UAAU,MAAM;OAChB,EALK,GAAG,KAAK,GAAG,MAAM,OAAO,UAAU,GAKvC;MACa,EACT;;IAEV,oBAAC,iBAAD,YAAkB,aAA8B;IAC/C,WAAW,SAAS,oBAAC,aAAD,EAAe;IAC3B;;EACe"}
|
package/dist/date-field.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FieldPath, FieldValues, UseControllerProps } from "react-hook-form";
|
|
2
|
-
import * as
|
|
2
|
+
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
3
|
import { Matcher } from "react-day-picker";
|
|
4
4
|
|
|
5
5
|
//#region src/components/date-hour-field/DateHourField.d.ts
|
|
@@ -29,7 +29,7 @@ declare function DateHourField<TFieldValues extends FieldValues = FieldValues, T
|
|
|
29
29
|
help,
|
|
30
30
|
hourPlaceholder,
|
|
31
31
|
valueType
|
|
32
|
-
}: DateHourFieldProps<TFieldValues, TFieldName>):
|
|
32
|
+
}: DateHourFieldProps<TFieldValues, TFieldName>): _$react_jsx_runtime0.JSX.Element;
|
|
33
33
|
//#endregion
|
|
34
34
|
export { DateHourField, DateHourFieldProps };
|
|
35
35
|
//# sourceMappingURL=DateHourField.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateHourField.d.ts","names":[],"sources":["../../src/components/date-hour-field/DateHourField.tsx"],"
|
|
1
|
+
{"version":3,"file":"DateHourField.d.ts","names":[],"sources":["../../src/components/date-hour-field/DateHourField.tsx"],"mappings":";;;;;UA4CiB,kBAAA,sBACM,WAAA,GAAc,WAAA,qBAChB,SAAA,CAAU,YAAA,IAAgB,SAAA,CAAU,YAAA,WAC/C,IAAA,CAAK,kBAAA,CAAmB,YAAA,EAAc,UAAA;EAC9C,KAAA;EACA,WAAA;EACA,SAAA;EACA,QAAA,GAAW,OAAA,GAAU,OAAA;EACrB,aAAA;EACA,YAAA,GAAe,IAAA;EACf,QAAA,GAAW,IAAA;EACX,QAAA;EACA,IAAA;EACA,eAAA;EACA,SAAA;AAAA;AAAA,iBAGO,aAAA,sBACc,WAAA,GAAc,WAAA,qBAChB,SAAA,CAAU,YAAA,IAAgB,SAAA,CAAU,YAAA,EAAA,CAAA;EAEvD,IAAA;EACA,KAAA;EACA,WAAA;EACA,aAAA;EACA,QAAA;EACA,SAAA;EACA,QAAA;EACA,YAAA;EACA,QAAA;EACA,IAAA;EACA,eAAA;EACA;AAAA,GACC,kBAAA,CAAmB,YAAA,EAAc,UAAA,IAAW,oBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateHourField.js","names":[],"sources":["../../src/components/date-hour-field/DateHourField.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\n\nimport {\n type FieldPath,\n type FieldValues,\n type UseControllerProps,\n useController,\n useFormContext,\n} from 'react-hook-form';\nimport withMask from '@/hooks/with-mask';\n\nimport { Calendar } from '@/ui/calendar';\nimport {\n FormDescription,\n FormFieldContext,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/ui/form';\nimport { Input } from '@/ui/input';\nimport { InputDateField } from '@/ui/input-date-field';\nimport { InputHelp } from '@/ui/input-help';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/ui/popover';\n\nimport { cn } from '@/lib/utils';\nimport { ptBR } from 'date-fns/locale';\nimport type { Matcher } from 'react-day-picker';\nimport {\n type ParsedTime,\n HOUR_OPTIONS,\n MINUTE_OPTIONS,\n formatDateTimeAsTime,\n formatDateTimeAsLocalString,\n formatTimeValue,\n getFallbackTime,\n mergeDateAndTime,\n normalizeDateValue,\n parseTime,\n sanitizeTimeInput,\n} from './date-hour-field.utils';\nimport { TimeWheelColumn } from './time-wheel-column';\n\nexport interface DateHourFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> extends Omit<UseControllerProps<TFieldValues, TFieldName>, 'disabled'> {\n label: string;\n description?: string;\n className?: string;\n disabled?: Matcher | Matcher[] | undefined;\n inputDisabled?: boolean;\n initialValue?: Date;\n endMonth?: Date;\n required?: boolean;\n help?: string;\n hourPlaceholder?: string;\n valueType?: 'date' | 'local-string';\n}\n\nfunction DateHourField<\n TFieldValues extends FieldValues = FieldValues,\n TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n name,\n label,\n description,\n inputDisabled,\n endMonth,\n className,\n disabled,\n initialValue,\n required,\n help,\n hourPlaceholder = 'Hora',\n valueType = 'local-string',\n}: DateHourFieldProps<TFieldValues, TFieldName>) {\n const form = useFormContext();\n const { field, fieldState } = useController({\n name,\n defaultValue: initialValue as any,\n rules: { required },\n control: form.control,\n });\n\n const [isOpen, setIsOpen] = useState(false);\n const [timeValue, setTimeValue] = useState('');\n\n const valueAsDate = normalizeDateValue(field.value);\n const selectedTime = parseTime(timeValue);\n\n useEffect(() => {\n if (!valueAsDate) {\n setTimeValue('');\n return;\n }\n\n const nextValue = formatDateTimeAsTime(valueAsDate);\n setTimeValue((currentValue) =>\n currentValue === nextValue ? currentValue : nextValue\n );\n }, [valueAsDate]);\n\n const updateFieldTime = (timePatch: Partial<ParsedTime>) => {\n const fallbackTime = getFallbackTime(valueAsDate);\n const baseTime = selectedTime ?? fallbackTime;\n\n const nextTime = {\n hours: baseTime.hours,\n minutes: baseTime.minutes,\n ...timePatch,\n };\n\n const nextDate = new Date(valueAsDate ?? new Date());\n nextDate.setHours(nextTime.hours, nextTime.minutes, 0, 0);\n\n setTimeValue(formatTimeValue(nextTime.hours, nextTime.minutes));\n if (valueType === 'local-string') {\n field.onChange(formatDateTimeAsLocalString(nextDate));\n return;\n }\n\n field.onChange(nextDate);\n };\n\n const handleDateSelect = (date: Date | undefined) => {\n if (!date) {\n setTimeValue('');\n field.onChange(undefined);\n return;\n }\n\n const mergedDate = mergeDateAndTime(date, timeValue, valueAsDate);\n setTimeValue(formatDateTimeAsTime(mergedDate));\n if (valueType === 'local-string') {\n field.onChange(formatDateTimeAsLocalString(mergedDate));\n return;\n }\n\n field.onChange(mergedDate);\n };\n\n const handleTimeInputChange = (nextValue: string) => {\n const sanitizedValue = sanitizeTimeInput(nextValue);\n setTimeValue(sanitizedValue);\n\n if (sanitizedValue.length !== 5) return;\n\n const parsedTime = parseTime(sanitizedValue);\n if (!parsedTime) return;\n\n updateFieldTime(parsedTime);\n };\n\n const handleHourSelect = (hourLabel: string) => {\n const selectedHourValue = Number(hourLabel);\n if (Number.isNaN(selectedHourValue)) return;\n\n updateFieldTime({ hours: selectedHourValue });\n };\n\n const handleMinuteSelect = (minuteLabel: string) => {\n const selectedMinuteValue = Number(minuteLabel);\n if (Number.isNaN(selectedMinuteValue)) return;\n\n updateFieldTime({ minutes: selectedMinuteValue });\n };\n\n return (\n <FormFieldContext.Provider value={{ name }}>\n <FormItem\n className={className}\n id={`date-hour-${name.replace('.', '-')}`}\n >\n <div className=\"flex items-end gap-1.5\">\n <FormLabel htmlFor={name}>\n {label}:\n {required && (\n <span className=\"text-red-500 text-lg leading-px\">*</span>\n )}\n </FormLabel>\n\n <InputHelp help={help} name={name} />\n </div>\n\n <Popover modal onOpenChange={setIsOpen} open={!inputDisabled && isOpen}>\n <PopoverTrigger asChild>\n <div\n className=\"flex w-full items-center\"\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n }}\n >\n <div className=\"w-full\">\n <InputDateField\n className={cn(\n 'border-r-0! rounded-r-none',\n fieldState.error && 'border-destructive'\n )}\n disabled={inputDisabled}\n field={{\n ...field,\n onChange(nextValue) {\n const normalizedDate = normalizeDateValue(nextValue);\n if (!normalizedDate) {\n setTimeValue('');\n field.onChange(undefined);\n return;\n }\n\n const mergedDate = mergeDateAndTime(\n normalizedDate,\n timeValue,\n valueAsDate\n );\n\n setTimeValue(formatDateTimeAsTime(mergedDate));\n if (valueType === 'local-string') {\n field.onChange(formatDateTimeAsLocalString(mergedDate));\n return;\n }\n\n field.onChange(mergedDate);\n },\n value: valueAsDate,\n }}\n id={name}\n onFocus={() => setIsOpen(true)}\n />\n </div>\n\n <Input\n className={cn(\n 'w-28 min-w-28 border-l rounded-l-none',\n fieldState.error && 'border-destructive'\n )}\n disabled={inputDisabled}\n id={`${name}-hour`}\n onChange={(event) => handleTimeInputChange(event.target.value)}\n onFocus={() => setIsOpen(true)}\n placeholder={hourPlaceholder}\n ref={\n withMask('99:99', {\n clearMaskOnLostFocus: true,\n showMaskOnFocus: false,\n showMaskOnHover: false,\n undoOnEscape: false,\n }) as any\n }\n value={timeValue}\n />\n </div>\n </PopoverTrigger>\n\n <PopoverContent\n className=\"flex w-fit gap-2 p-0 items-center\"\n onOpenAutoFocus={(event) => event.preventDefault()}\n >\n <Calendar\n defaultMonth={valueAsDate || new Date()}\n disabled={disabled}\n endMonth={endMonth}\n key={`${name}-${valueAsDate?.toString()}-${timeValue}`}\n locale={ptBR}\n mode=\"single\"\n onSelect={handleDateSelect}\n selected={valueAsDate}\n />\n\n <div className=\"relative shrink-0 my-auto border-l p-3 pr-3 \">\n <div className=\"flex gap-2\">\n <TimeWheelColumn\n isOpen={isOpen}\n label=\"Hora\"\n onSelect={handleHourSelect}\n options={HOUR_OPTIONS}\n selectedValue={selectedTime?.hours}\n />\n\n <TimeWheelColumn\n isOpen={isOpen}\n label=\"Min\"\n onSelect={handleMinuteSelect}\n options={MINUTE_OPTIONS}\n selectedValue={selectedTime?.minutes}\n />\n </div>\n </div>\n </PopoverContent>\n </Popover>\n\n <FormDescription>{description}</FormDescription>\n {fieldState.error && <FormMessage />}\n </FormItem>\n </FormFieldContext.Provider>\n );\n}\n\nexport { DateHourField };\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA6DA,SAAS,cAGP,EACA,MACA,OACA,aACA,eACA,UACA,WACA,UACA,cACA,UACA,MACA,kBAAkB,QAClB,YAAY,kBACmC;CAC/C,MAAM,OAAO,gBAAgB;CAC7B,MAAM,EAAE,OAAO,eAAe,cAAc;EAC1C;EACA,cAAc;EACd,OAAO,EAAE,UAAU;EACnB,SAAS,KAAK;EACf,CAAC;CAEF,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAC3C,MAAM,CAAC,WAAW,gBAAgB,SAAS,GAAG;CAE9C,MAAM,cAAc,mBAAmB,MAAM,MAAM;CACnD,MAAM,eAAe,UAAU,UAAU;AAEzC,iBAAgB;AACd,MAAI,CAAC,aAAa;AAChB,gBAAa,GAAG;AAChB;;EAGF,MAAM,YAAY,qBAAqB,YAAY;AACnD,gBAAc,iBACZ,iBAAiB,YAAY,eAAe,UAC7C;IACA,CAAC,YAAY,CAAC;CAEjB,MAAM,mBAAmB,cAAmC;EAC1D,MAAM,eAAe,gBAAgB,YAAY;EACjD,MAAM,WAAW,gBAAgB;EAEjC,MAAM,WAAW;GACf,OAAO,SAAS;GAChB,SAAS,SAAS;GAClB,GAAG;GACJ;EAED,MAAM,WAAW,IAAI,KAAK,+BAAe,IAAI,MAAM,CAAC;AACpD,WAAS,SAAS,SAAS,OAAO,SAAS,SAAS,GAAG,EAAE;AAEzD,eAAa,gBAAgB,SAAS,OAAO,SAAS,QAAQ,CAAC;AAC/D,MAAI,cAAc,gBAAgB;AAChC,SAAM,SAAS,4BAA4B,SAAS,CAAC;AACrD;;AAGF,QAAM,SAAS,SAAS;;CAG1B,MAAM,oBAAoB,SAA2B;AACnD,MAAI,CAAC,MAAM;AACT,gBAAa,GAAG;AAChB,SAAM,SAAS,OAAU;AACzB;;EAGF,MAAM,aAAa,iBAAiB,MAAM,WAAW,YAAY;AACjE,eAAa,qBAAqB,WAAW,CAAC;AAC9C,MAAI,cAAc,gBAAgB;AAChC,SAAM,SAAS,4BAA4B,WAAW,CAAC;AACvD;;AAGF,QAAM,SAAS,WAAW;;CAG5B,MAAM,yBAAyB,cAAsB;EACnD,MAAM,iBAAiB,kBAAkB,UAAU;AACnD,eAAa,eAAe;AAE5B,MAAI,eAAe,WAAW,EAAG;EAEjC,MAAM,aAAa,UAAU,eAAe;AAC5C,MAAI,CAAC,WAAY;AAEjB,kBAAgB,WAAW;;CAG7B,MAAM,oBAAoB,cAAsB;EAC9C,MAAM,oBAAoB,OAAO,UAAU;AAC3C,MAAI,OAAO,MAAM,kBAAkB,CAAE;AAErC,kBAAgB,EAAE,OAAO,mBAAmB,CAAC;;CAG/C,MAAM,sBAAsB,gBAAwB;EAClD,MAAM,sBAAsB,OAAO,YAAY;AAC/C,MAAI,OAAO,MAAM,oBAAoB,CAAE;AAEvC,kBAAgB,EAAE,SAAS,qBAAqB,CAAC;;AAGnD,QACE,oBAAC,iBAAiB;EAAS,OAAO,EAAE,MAAM;YACxC,qBAAC;GACY;GACX,IAAI,aAAa,KAAK,QAAQ,KAAK,IAAI;;IAEvC,qBAAC;KAAI,WAAU;gBACb,qBAAC;MAAU,SAAS;;OACjB;OAAM;OACN,YACC,oBAAC;QAAK,WAAU;kBAAkC;SAAQ;;OAElD,EAEZ,oBAAC;MAAgB;MAAY;OAAQ;MACjC;IAEN,qBAAC;KAAQ;KAAM,cAAc;KAAW,MAAM,CAAC,iBAAiB;gBAC9D,oBAAC;MAAe;gBACd,qBAAC;OACC,WAAU;OACV,UAAU,UAAU;AAClB,cAAM,gBAAgB;AACtB,cAAM,iBAAiB;;kBAGzB,oBAAC;QAAI,WAAU;kBACb,oBAAC;SACC,WAAW,GACT,8BACA,WAAW,SAAS,qBACrB;SACD,UAAU;SACV,OAAO;UACL,GAAG;UACH,SAAS,WAAW;WAClB,MAAM,iBAAiB,mBAAmB,UAAU;AACpD,eAAI,CAAC,gBAAgB;AACnB,yBAAa,GAAG;AAChB,kBAAM,SAAS,OAAU;AACzB;;WAGF,MAAM,aAAa,iBACjB,gBACA,WACA,YACD;AAED,wBAAa,qBAAqB,WAAW,CAAC;AAC9C,eAAI,cAAc,gBAAgB;AAChC,kBAAM,SAAS,4BAA4B,WAAW,CAAC;AACvD;;AAGF,iBAAM,SAAS,WAAW;;UAE5B,OAAO;UACR;SACD,IAAI;SACJ,eAAe,UAAU,KAAK;UAC9B;SACE,EAEN,oBAAC;QACC,WAAW,GACT,yCACA,WAAW,SAAS,qBACrB;QACD,UAAU;QACV,IAAI,GAAG,KAAK;QACZ,WAAW,UAAU,sBAAsB,MAAM,OAAO,MAAM;QAC9D,eAAe,UAAU,KAAK;QAC9B,aAAa;QACb,KACE,SAAS,SAAS;SAChB,sBAAsB;SACtB,iBAAiB;SACjB,iBAAiB;SACjB,cAAc;SACf,CAAC;QAEJ,OAAO;SACP;QACE;OACS,EAEjB,qBAAC;MACC,WAAU;MACV,kBAAkB,UAAU,MAAM,gBAAgB;iBAElD,oBAAC;OACC,cAAc,+BAAe,IAAI,MAAM;OAC7B;OACA;OAEV,QAAQ;OACR,MAAK;OACL,UAAU;OACV,UAAU;SAJL,GAAG,KAAK,GAAG,aAAa,UAAU,CAAC,GAAG,YAK3C,EAEF,oBAAC;OAAI,WAAU;iBACb,qBAAC;QAAI,WAAU;mBACb,oBAAC;SACS;SACR,OAAM;SACN,UAAU;SACV,SAAS;SACT,eAAe,cAAc;UAC7B,EAEF,oBAAC;SACS;SACR,OAAM;SACN,UAAU;SACV,SAAS;SACT,eAAe,cAAc;UAC7B;SACE;QACF;OACS;MACT;IAEV,oBAAC,6BAAiB,cAA8B;IAC/C,WAAW,SAAS,oBAAC,gBAAc;;IAC3B;GACe"}
|
|
1
|
+
{"version":3,"file":"DateHourField.js","names":[],"sources":["../../src/components/date-hour-field/DateHourField.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\n\nimport {\n type FieldPath,\n type FieldValues,\n type UseControllerProps,\n useController,\n useFormContext,\n} from 'react-hook-form';\nimport withMask from '@/hooks/with-mask';\n\nimport { Calendar } from '@/ui/calendar';\nimport {\n FormDescription,\n FormFieldContext,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/ui/form';\nimport { Input } from '@/ui/input';\nimport { InputDateField } from '@/ui/input-date-field';\nimport { InputHelp } from '@/ui/input-help';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/ui/popover';\n\nimport { cn } from '@/lib/utils';\nimport { ptBR } from 'date-fns/locale';\nimport type { Matcher } from 'react-day-picker';\nimport {\n type ParsedTime,\n HOUR_OPTIONS,\n MINUTE_OPTIONS,\n formatDateTimeAsTime,\n formatDateTimeAsLocalString,\n formatTimeValue,\n getFallbackTime,\n mergeDateAndTime,\n normalizeDateValue,\n parseTime,\n sanitizeTimeInput,\n} from './date-hour-field.utils';\nimport { TimeWheelColumn } from './time-wheel-column';\n\nexport interface DateHourFieldProps<\n TFieldValues extends FieldValues = FieldValues,\n TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> extends Omit<UseControllerProps<TFieldValues, TFieldName>, 'disabled'> {\n label: string;\n description?: string;\n className?: string;\n disabled?: Matcher | Matcher[] | undefined;\n inputDisabled?: boolean;\n initialValue?: Date;\n endMonth?: Date;\n required?: boolean;\n help?: string;\n hourPlaceholder?: string;\n valueType?: 'date' | 'local-string';\n}\n\nfunction DateHourField<\n TFieldValues extends FieldValues = FieldValues,\n TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n name,\n label,\n description,\n inputDisabled,\n endMonth,\n className,\n disabled,\n initialValue,\n required,\n help,\n hourPlaceholder = 'Hora',\n valueType = 'local-string',\n}: DateHourFieldProps<TFieldValues, TFieldName>) {\n const form = useFormContext();\n const { field, fieldState } = useController({\n name,\n defaultValue: initialValue as any,\n rules: { required },\n control: form.control,\n });\n\n const [isOpen, setIsOpen] = useState(false);\n const [timeValue, setTimeValue] = useState('');\n\n const valueAsDate = normalizeDateValue(field.value);\n const selectedTime = parseTime(timeValue);\n\n useEffect(() => {\n if (!valueAsDate) {\n setTimeValue('');\n return;\n }\n\n const nextValue = formatDateTimeAsTime(valueAsDate);\n setTimeValue((currentValue) =>\n currentValue === nextValue ? currentValue : nextValue\n );\n }, [valueAsDate]);\n\n const updateFieldTime = (timePatch: Partial<ParsedTime>) => {\n const fallbackTime = getFallbackTime(valueAsDate);\n const baseTime = selectedTime ?? fallbackTime;\n\n const nextTime = {\n hours: baseTime.hours,\n minutes: baseTime.minutes,\n ...timePatch,\n };\n\n const nextDate = new Date(valueAsDate ?? new Date());\n nextDate.setHours(nextTime.hours, nextTime.minutes, 0, 0);\n\n setTimeValue(formatTimeValue(nextTime.hours, nextTime.minutes));\n if (valueType === 'local-string') {\n field.onChange(formatDateTimeAsLocalString(nextDate));\n return;\n }\n\n field.onChange(nextDate);\n };\n\n const handleDateSelect = (date: Date | undefined) => {\n if (!date) {\n setTimeValue('');\n field.onChange(undefined);\n return;\n }\n\n const mergedDate = mergeDateAndTime(date, timeValue, valueAsDate);\n setTimeValue(formatDateTimeAsTime(mergedDate));\n if (valueType === 'local-string') {\n field.onChange(formatDateTimeAsLocalString(mergedDate));\n return;\n }\n\n field.onChange(mergedDate);\n };\n\n const handleTimeInputChange = (nextValue: string) => {\n const sanitizedValue = sanitizeTimeInput(nextValue);\n setTimeValue(sanitizedValue);\n\n if (sanitizedValue.length !== 5) return;\n\n const parsedTime = parseTime(sanitizedValue);\n if (!parsedTime) return;\n\n updateFieldTime(parsedTime);\n };\n\n const handleHourSelect = (hourLabel: string) => {\n const selectedHourValue = Number(hourLabel);\n if (Number.isNaN(selectedHourValue)) return;\n\n updateFieldTime({ hours: selectedHourValue });\n };\n\n const handleMinuteSelect = (minuteLabel: string) => {\n const selectedMinuteValue = Number(minuteLabel);\n if (Number.isNaN(selectedMinuteValue)) return;\n\n updateFieldTime({ minutes: selectedMinuteValue });\n };\n\n return (\n <FormFieldContext.Provider value={{ name }}>\n <FormItem\n className={className}\n id={`date-hour-${name.replace('.', '-')}`}\n >\n <div className=\"flex items-end gap-1.5\">\n <FormLabel htmlFor={name}>\n {label}:\n {required && (\n <span className=\"text-red-500 text-lg leading-px\">*</span>\n )}\n </FormLabel>\n\n <InputHelp help={help} name={name} />\n </div>\n\n <Popover modal onOpenChange={setIsOpen} open={!inputDisabled && isOpen}>\n <PopoverTrigger asChild>\n <div\n className=\"flex w-full items-center\"\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n }}\n >\n <div className=\"w-full\">\n <InputDateField\n className={cn(\n 'border-r-0! rounded-r-none',\n fieldState.error && 'border-destructive'\n )}\n disabled={inputDisabled}\n field={{\n ...field,\n onChange(nextValue) {\n const normalizedDate = normalizeDateValue(nextValue);\n if (!normalizedDate) {\n setTimeValue('');\n field.onChange(undefined);\n return;\n }\n\n const mergedDate = mergeDateAndTime(\n normalizedDate,\n timeValue,\n valueAsDate\n );\n\n setTimeValue(formatDateTimeAsTime(mergedDate));\n if (valueType === 'local-string') {\n field.onChange(formatDateTimeAsLocalString(mergedDate));\n return;\n }\n\n field.onChange(mergedDate);\n },\n value: valueAsDate,\n }}\n id={name}\n onFocus={() => setIsOpen(true)}\n />\n </div>\n\n <Input\n className={cn(\n 'w-28 min-w-28 border-l rounded-l-none',\n fieldState.error && 'border-destructive'\n )}\n disabled={inputDisabled}\n id={`${name}-hour`}\n onChange={(event) => handleTimeInputChange(event.target.value)}\n onFocus={() => setIsOpen(true)}\n placeholder={hourPlaceholder}\n ref={\n withMask('99:99', {\n clearMaskOnLostFocus: true,\n showMaskOnFocus: false,\n showMaskOnHover: false,\n undoOnEscape: false,\n }) as any\n }\n value={timeValue}\n />\n </div>\n </PopoverTrigger>\n\n <PopoverContent\n className=\"flex w-fit gap-2 p-0 items-center\"\n onOpenAutoFocus={(event) => event.preventDefault()}\n >\n <Calendar\n defaultMonth={valueAsDate || new Date()}\n disabled={disabled}\n endMonth={endMonth}\n key={`${name}-${valueAsDate?.toString()}-${timeValue}`}\n locale={ptBR}\n mode=\"single\"\n onSelect={handleDateSelect}\n selected={valueAsDate}\n />\n\n <div className=\"relative shrink-0 my-auto border-l p-3 pr-3 \">\n <div className=\"flex gap-2\">\n <TimeWheelColumn\n isOpen={isOpen}\n label=\"Hora\"\n onSelect={handleHourSelect}\n options={HOUR_OPTIONS}\n selectedValue={selectedTime?.hours}\n />\n\n <TimeWheelColumn\n isOpen={isOpen}\n label=\"Min\"\n onSelect={handleMinuteSelect}\n options={MINUTE_OPTIONS}\n selectedValue={selectedTime?.minutes}\n />\n </div>\n </div>\n </PopoverContent>\n </Popover>\n\n <FormDescription>{description}</FormDescription>\n {fieldState.error && <FormMessage />}\n </FormItem>\n </FormFieldContext.Provider>\n );\n}\n\nexport { DateHourField };\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-wheel-column.js","names":[],"sources":["../../src/components/date-hour-field/time-wheel-column.tsx"],"sourcesContent":["import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';\nimport useEmblaCarousel from 'embla-carousel-react';\nimport { useEffect, useMemo } from 'react';\n\nimport { cn } from '@/lib/utils';\n\ntype TimeWheelColumnProps = {\n isOpen: boolean;\n label: string;\n options: string[];\n selectedValue?: number;\n onSelect: (value: string) => void;\n};\n\nfunction TimeWheelColumn({\n isOpen,\n label,\n options,\n selectedValue,\n onSelect,\n}: TimeWheelColumnProps) {\n const plugins = useMemo(() => [WheelGesturesPlugin()], []);\n const [emblaRef, emblaApi] = useEmblaCarousel(\n {\n axis: 'y',\n align: 'center',\n containScroll: 'keepSnaps',\n dragFree: true,\n },\n plugins\n );\n\n useEffect(() => {\n if (!emblaApi || !isOpen) return;\n\n emblaApi.reInit();\n\n if (selectedValue === undefined) {\n emblaApi.scrollTo(0, true);\n return;\n }\n\n emblaApi.scrollTo(selectedValue, true);\n }, [emblaApi, isOpen, selectedValue]);\n\n return (\n <div className=\"relative w-16\">\n <p className=\"text-muted-foreground mb-2 text-[11px] font-semibold tracking-[0.12em] uppercase\">\n {label}\n </p>\n\n <div className=\"pointer-events-none absolute inset-x-0 top-6 z-20 h-12 bg-linear-to-b from-popover to-transparent\" />\n <div className=\"pointer-events-none absolute inset-x-0 bottom-0 z-20 h-12 bg-linear-to-t from-popover to-transparent\" />\n\n <div className=\"h-48 overflow-hidden\" ref={emblaRef}>\n <div className=\"flex h-full flex-col gap-1 py-4\">\n {options.map((optionLabel) => (\n <div className=\"shrink-0 basis-8 \" key={optionLabel}>\n <button\n className={cn(\n 'h-full w-full rounded-md text-xs font-medium transition-colors',\n selectedValue === Number(optionLabel)\n ? 'border-primary bg-primary text-primary-foreground'\n : 'border-border bg-background hover:bg-accent hover:text-accent-foreground'\n )}\n onClick={() => onSelect(optionLabel)}\n type=\"button\"\n >\n {optionLabel}\n </button>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n\nexport { TimeWheelColumn };\n"],"mappings":";;;;;;;AAcA,SAAS,gBAAgB,EACvB,QACA,OACA,SACA,eACA,YACuB;CAEvB,MAAM,CAAC,UAAU,YAAY,iBAC3B;EACE,MAAM;EACN,OAAO;EACP,eAAe;EACf,UAAU;EACX,EAPa,cAAc,CAAC,qBAAqB,CAAC,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"time-wheel-column.js","names":[],"sources":["../../src/components/date-hour-field/time-wheel-column.tsx"],"sourcesContent":["import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';\nimport useEmblaCarousel from 'embla-carousel-react';\nimport { useEffect, useMemo } from 'react';\n\nimport { cn } from '@/lib/utils';\n\ntype TimeWheelColumnProps = {\n isOpen: boolean;\n label: string;\n options: string[];\n selectedValue?: number;\n onSelect: (value: string) => void;\n};\n\nfunction TimeWheelColumn({\n isOpen,\n label,\n options,\n selectedValue,\n onSelect,\n}: TimeWheelColumnProps) {\n const plugins = useMemo(() => [WheelGesturesPlugin()], []);\n const [emblaRef, emblaApi] = useEmblaCarousel(\n {\n axis: 'y',\n align: 'center',\n containScroll: 'keepSnaps',\n dragFree: true,\n },\n plugins\n );\n\n useEffect(() => {\n if (!emblaApi || !isOpen) return;\n\n emblaApi.reInit();\n\n if (selectedValue === undefined) {\n emblaApi.scrollTo(0, true);\n return;\n }\n\n emblaApi.scrollTo(selectedValue, true);\n }, [emblaApi, isOpen, selectedValue]);\n\n return (\n <div className=\"relative w-16\">\n <p className=\"text-muted-foreground mb-2 text-[11px] font-semibold tracking-[0.12em] uppercase\">\n {label}\n </p>\n\n <div className=\"pointer-events-none absolute inset-x-0 top-6 z-20 h-12 bg-linear-to-b from-popover to-transparent\" />\n <div className=\"pointer-events-none absolute inset-x-0 bottom-0 z-20 h-12 bg-linear-to-t from-popover to-transparent\" />\n\n <div className=\"h-48 overflow-hidden\" ref={emblaRef}>\n <div className=\"flex h-full flex-col gap-1 py-4\">\n {options.map((optionLabel) => (\n <div className=\"shrink-0 basis-8 \" key={optionLabel}>\n <button\n className={cn(\n 'h-full w-full rounded-md text-xs font-medium transition-colors',\n selectedValue === Number(optionLabel)\n ? 'border-primary bg-primary text-primary-foreground'\n : 'border-border bg-background hover:bg-accent hover:text-accent-foreground'\n )}\n onClick={() => onSelect(optionLabel)}\n type=\"button\"\n >\n {optionLabel}\n </button>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n\nexport { TimeWheelColumn };\n"],"mappings":";;;;;;;AAcA,SAAS,gBAAgB,EACvB,QACA,OACA,SACA,eACA,YACuB;CAEvB,MAAM,CAAC,UAAU,YAAY,iBAC3B;EACE,MAAM;EACN,OAAO;EACP,eAAe;EACf,UAAU;EACX,EAPa,cAAc,CAAC,qBAAqB,CAAC,EAAE,EAAE,CAQhD,CACR;AAED,iBAAgB;AACd,MAAI,CAAC,YAAY,CAAC,OAAQ;AAE1B,WAAS,QAAQ;AAEjB,MAAI,kBAAkB,QAAW;AAC/B,YAAS,SAAS,GAAG,KAAK;AAC1B;;AAGF,WAAS,SAAS,eAAe,KAAK;IACrC;EAAC;EAAU;EAAQ;EAAc,CAAC;AAErC,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,KAAD;IAAG,WAAU;cACV;IACC;GAEJ,oBAAC,OAAD,EAAK,WAAU,qGAAsG;GACrH,oBAAC,OAAD,EAAK,WAAU,wGAAyG;GAExH,oBAAC,OAAD;IAAK,WAAU;IAAuB,KAAK;cACzC,oBAAC,OAAD;KAAK,WAAU;eACZ,QAAQ,KAAK,gBACZ,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,UAAD;OACE,WAAW,GACT,mEACA,kBAAkB,OAAO,YAAY,GACjC,sDACA,2EACL;OACD,eAAe,SAAS,YAAY;OACpC,MAAK;iBAEJ;OACM;MACL,EAbkC,YAalC,CACN;KACE;IACF;GACF"}
|
package/dist/date-hour-field.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Mask, Options } from "../src/hooks/with-mask.js";
|
|
2
2
|
import { FieldPath, FieldValues, UseControllerProps } from "react-hook-form";
|
|
3
3
|
import { Dispatch, SetStateAction } from "react";
|
|
4
|
-
import * as
|
|
4
|
+
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
5
5
|
import { PopoverProps } from "@radix-ui/react-popover";
|
|
6
6
|
|
|
7
7
|
//#region src/components/input-suggest/input-suggest.d.ts
|
|
@@ -71,7 +71,7 @@ declare function InputSuggest<TFieldValues extends FieldValues = FieldValues, TF
|
|
|
71
71
|
debounceTime,
|
|
72
72
|
maxWait,
|
|
73
73
|
...props
|
|
74
|
-
}: InputSuggestProps<TFieldValues, TFieldName> & PopoverProps):
|
|
74
|
+
}: InputSuggestProps<TFieldValues, TFieldName> & PopoverProps): _$react_jsx_runtime0.JSX.Element;
|
|
75
75
|
//#endregion
|
|
76
76
|
export { InputSuggest, InputSuggestProps };
|
|
77
77
|
//# sourceMappingURL=input-suggest.d.ts.map
|