stalefish 8.0.6 → 8.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/dateTimePicker.mjs +53 -13
- package/package.json +1 -1
|
@@ -117,8 +117,28 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
|
|
|
117
117
|
|
|
118
118
|
// Create a stable id for the outer wrapper so we can query a real DOM node
|
|
119
119
|
// after the template is rendered. Prefer the provided uniqueKey from callers
|
|
120
|
-
//
|
|
121
|
-
|
|
120
|
+
// but DO NOT require it. For robustness, memoize a per-(holdingPen, property)
|
|
121
|
+
// id so re-renders don't generate new ids and callers don't have to pass
|
|
122
|
+
// uniqueKey.
|
|
123
|
+
const ID_MAP_SYMBOL = Symbol.for('stalefish.flatpickr.idMap')
|
|
124
|
+
if (holdingPen && !holdingPen[ID_MAP_SYMBOL]) {
|
|
125
|
+
Object.defineProperty(holdingPen, ID_MAP_SYMBOL, {
|
|
126
|
+
value: {},
|
|
127
|
+
enumerable: false,
|
|
128
|
+
configurable: false,
|
|
129
|
+
writable: false
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
const memoId = (() => {
|
|
133
|
+
if (!holdingPen || !property) return null
|
|
134
|
+
const map = holdingPen[ID_MAP_SYMBOL]
|
|
135
|
+
if (!map) return null
|
|
136
|
+
if (!map[property]) {
|
|
137
|
+
map[property] = `sf-flatpickr-${property}-${Math.random().toString(36).slice(2)}`
|
|
138
|
+
}
|
|
139
|
+
return map[property]
|
|
140
|
+
})()
|
|
141
|
+
const wrapperId = `sf-flatpickr-${uniqueKey || memoId || property || Math.random().toString(36).slice(2)}`
|
|
122
142
|
|
|
123
143
|
const inputType = resolvedDisableMobile ? 'text' : (detectTouchscreen() ? (timeOnly ? 'time' : 'date') : 'text')
|
|
124
144
|
|
|
@@ -134,7 +154,21 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
|
|
|
134
154
|
e.target.parentNode.parentNode._flatpickr.close()
|
|
135
155
|
return false
|
|
136
156
|
}}>clear</div>` : ''}
|
|
137
|
-
<input data-gramm="false" ?disabled=${disabled} style="${disabled ? 'cursor: not-allowed; opacity: 0.3;' : ''}" class="${styles.textfield} ${fieldIsTouched(holdingPen, property) === true ? styles.touched : ''}" ${required ? { required: 'required' } : ''} onchange=${e => {
|
|
157
|
+
<input data-gramm="false" ?disabled=${disabled} style="${disabled ? 'cursor: not-allowed; opacity: 0.3;' : ''}" class="${styles.textfield} ${fieldIsTouched(holdingPen, property) === true ? styles.touched : ''}" ${required ? { required: 'required' } : ''} onchange=${e => {
|
|
158
|
+
// Guard against re-render while Flatpickr popup is open: native input onchange
|
|
159
|
+
// can fire on spinner clicks, which would propagate to the parent onchange
|
|
160
|
+
// and trigger a re-render tearing down the popup. If the picker is open,
|
|
161
|
+
// ignore this native onchange and let flatpickr's onClose handler sync state.
|
|
162
|
+
const wrapperEl = e.target && e.target.parentNode && e.target.parentNode.parentNode
|
|
163
|
+
const fp = wrapperEl && wrapperEl._flatpickr
|
|
164
|
+
if (fp && fp.isOpen) {
|
|
165
|
+
e.stopPropagation()
|
|
166
|
+
e.preventDefault()
|
|
167
|
+
return false
|
|
168
|
+
}
|
|
169
|
+
change({ e, holdingPen, property, label: styles.label })
|
|
170
|
+
onchange && onchange(e)
|
|
171
|
+
}} oninput=${e => { e.target.defaultValue = ''; oninput && oninput(e) }} placeholder="${placeholder || ''}${required ? ' *' : ''}" type="${inputType}" ${pattern ? { pattern } : ''} .value=${holdingPen[property] || ''} data-input />
|
|
138
172
|
</div>
|
|
139
173
|
</div>
|
|
140
174
|
`
|
|
@@ -144,7 +178,7 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
|
|
|
144
178
|
// adapter expects a real Element. We defer with requestAnimationFrame and
|
|
145
179
|
// query by id.
|
|
146
180
|
if (typeof window !== 'undefined') {
|
|
147
|
-
const
|
|
181
|
+
const attachNow = () => {
|
|
148
182
|
const wrapperEl = document.getElementById(wrapperId)
|
|
149
183
|
if (!wrapperEl) return
|
|
150
184
|
attachFlatpickr(
|
|
@@ -166,14 +200,13 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
|
|
|
166
200
|
flatpickrConfig,
|
|
167
201
|
{
|
|
168
202
|
wrap: true,
|
|
169
|
-
|
|
203
|
+
// Avoid triggering rerenders on every spinner click which would
|
|
204
|
+
// destroy and recreate the popup, making it seem to "disappear".
|
|
205
|
+
// We update holdingPen once on close instead.
|
|
206
|
+
onValueUpdate: () => {},
|
|
207
|
+
onClose: (selectedDates, dateString) => {
|
|
170
208
|
const fauxE = {
|
|
171
|
-
currentTarget: {
|
|
172
|
-
validity: {
|
|
173
|
-
valid: true
|
|
174
|
-
},
|
|
175
|
-
value: dateString
|
|
176
|
-
}
|
|
209
|
+
currentTarget: { validity: { valid: true }, value: dateString }
|
|
177
210
|
}
|
|
178
211
|
formField(holdingPen, property)(fauxE)
|
|
179
212
|
onchange && onchange(fauxE)
|
|
@@ -183,8 +216,15 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
|
|
|
183
216
|
)
|
|
184
217
|
)
|
|
185
218
|
}
|
|
186
|
-
|
|
187
|
-
|
|
219
|
+
|
|
220
|
+
// Try immediate attach if the element is already in the DOM and connected;
|
|
221
|
+
// otherwise, defer to the next frame as a fallback.
|
|
222
|
+
const immediateEl = typeof document !== 'undefined' ? document.getElementById(wrapperId) : null
|
|
223
|
+
if (immediateEl && immediateEl.isConnected) {
|
|
224
|
+
attachNow()
|
|
225
|
+
} else {
|
|
226
|
+
window.requestAnimationFrame(attachNow)
|
|
227
|
+
}
|
|
188
228
|
}
|
|
189
229
|
|
|
190
230
|
return el
|