stalefish 8.0.2 → 8.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Flatpickr adapter for Stalefish (halfcab/lit-based)
3
+ *
4
+ * Goals:
5
+ * - Always initialize flatpickr on a real Element (not a DocumentFragment/TemplateResult)
6
+ * - Defer initialization until the node is connected, to be SSR/DOM-safe
7
+ * - Store the instance on the wrapper element (`wrapper._flatpickr`) consistently
8
+ * - Provide simple attach/detach helpers for reuse across components
9
+ *
10
+ * Usage:
11
+ * import flatpickr from 'flatpickr'
12
+ * import { attachFlatpickr, detachFlatpickr } from '../adapters/flatpickr.mjs'
13
+ *
14
+ * const wrapper = el.firstElementChild // your component's outer <div>
15
+ * const instance = attachFlatpickr(wrapper, flatpickr, { wrap: true, ...options })
16
+ * // later on removal:
17
+ * detachFlatpickr(wrapper)
18
+ */
19
+
20
+ /**
21
+ * Resolves the actual wrapper Element to pass to flatpickr.
22
+ * Accepts either an Element, or a container whose firstElementChild is the wrapper.
23
+ * Falls back to querySelector for common markers if necessary.
24
+ * @param {any} node
25
+ * @returns {Element|null}
26
+ */
27
+ function resolveWrapperElement (node) {
28
+ if (!node) return null
29
+ // If it's already an Element (HTMLElement/SVGElement), use it directly
30
+ if (typeof Element !== 'undefined' && node instanceof Element) return node
31
+ // If it's a container/fragment with a firstElementChild, use that
32
+ if (node.firstElementChild) return node.firstElementChild
33
+ // Last resort: try to find a likely wrapper inside
34
+ if (node.querySelector) {
35
+ return node.querySelector('[data-flatpickr-wrapper], [data-input]')
36
+ }
37
+ return null
38
+ }
39
+
40
+ /**
41
+ * Attaches or updates a flatpickr instance on the given wrapper/container.
42
+ * The instance is stored on `wrapperEl._flatpickr`.
43
+ *
44
+ * @param {Element|any} wrapperOrContainer - An Element or a container whose firstElementChild is the wrapper
45
+ * @param {Function} flatpickrLib - The flatpickr factory function (import flatpickr from 'flatpickr')
46
+ * @param {Object} config - Flatpickr configuration options
47
+ * @returns {Object|null} flatpickr instance, or null if deferred/not created
48
+ */
49
+ export function attachFlatpickr (wrapperOrContainer, flatpickrLib, config = {}) {
50
+ if (typeof window === 'undefined') return null // SSR guard
51
+ if (!flatpickrLib) return null
52
+
53
+ const wrapperEl = resolveWrapperElement(wrapperOrContainer)
54
+ if (!wrapperEl) return null
55
+
56
+ // If instance already exists, try to update options where supported
57
+ if (wrapperEl._flatpickr) {
58
+ try {
59
+ // Not all options are dynamically settable, but this is a safe best-effort
60
+ wrapperEl._flatpickr.set(config)
61
+ } catch (e) {
62
+ try {
63
+ wrapperEl._flatpickr.destroy()
64
+ } catch (_) {}
65
+ wrapperEl._flatpickr = null
66
+ }
67
+ }
68
+
69
+ const init = () => {
70
+ // Ensure wrap:true is preserved if provided; caller decides
71
+ const instance = flatpickrLib(wrapperEl, config)
72
+ wrapperEl._flatpickr = instance
73
+ return instance
74
+ }
75
+
76
+ // If not connected yet, defer until the next frame when likely connected
77
+ if (!wrapperEl.isConnected) {
78
+ requestAnimationFrame(() => {
79
+ if (!wrapperEl._flatpickr && wrapperEl.isConnected) {
80
+ try { init() } catch (e) { /* swallow init errors in deferred path */ }
81
+ }
82
+ })
83
+ return null
84
+ }
85
+
86
+ return init()
87
+ }
88
+
89
+ /**
90
+ * Destroys and detaches a flatpickr instance from the wrapper element, if present.
91
+ * @param {Element|any} wrapperOrContainer
92
+ */
93
+ export function detachFlatpickr (wrapperOrContainer) {
94
+ const wrapperEl = resolveWrapperElement(wrapperOrContainer)
95
+ if (wrapperEl && wrapperEl._flatpickr) {
96
+ try { wrapperEl._flatpickr.destroy() } catch (e) {}
97
+ try { delete wrapperEl._flatpickr } catch (e) { wrapperEl._flatpickr = null }
98
+ }
99
+ }
100
+
101
+ export default {
102
+ attachFlatpickr,
103
+ detachFlatpickr
104
+ }
@@ -1,5 +1,6 @@
1
1
  import { html, css, formField, fieldIsTouched } from 'halfcab'
2
2
  import flatpickr from 'flatpickr'
3
+ import { attachFlatpickr } from '../adapters/flatpickr.mjs'
3
4
  import calendarIcon from './icons/calendarIcon.mjs'
4
5
  import timeIcon from './icons/timeIcon.mjs'
5
6
 
@@ -135,7 +136,11 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
135
136
  </div>
136
137
  `
137
138
 
138
- this.flatpickr = flatpickr(el, Object.assign(flatpickrConfig, {
139
+ // Attach flatpickr instance to the OUTER WRAPPER element (not the fragment) so
140
+ // internal clear/close handlers can access it consistently via parent wrappers.
141
+ // Using `this` or the fragment caused errors after migrating to halfcab/lit.
142
+ const wrapper = el.firstElementChild || el
143
+ attachFlatpickr(wrapper, flatpickr, Object.assign({}, flatpickrConfig, {
139
144
  wrap: true,
140
145
  onValueUpdate: (fpDate, dateString) => {
141
146
  let fauxE = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stalefish",
3
- "version": "8.0.2",
3
+ "version": "8.0.3",
4
4
  "description": "Simple function based component library for halfcab tagged template literals",
5
5
  "main": "index.mjs",
6
6
  "module": "index.mjs",