stalefish 8.0.4 → 8.0.5

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.
@@ -4,7 +4,7 @@ import { attachFlatpickr } from '../adapters/flatpickr.mjs'
4
4
  import calendarIcon from './icons/calendarIcon.mjs'
5
5
  import timeIcon from './icons/timeIcon.mjs'
6
6
 
7
- let styles = css`
7
+ const styles = css`
8
8
  .textfield {
9
9
  padding: 10px;
10
10
  border: solid 5px #c9c9c9;
@@ -80,7 +80,7 @@ let styles = css`
80
80
  `
81
81
 
82
82
  function change ({ e, holdingPen, property }) {
83
- let ff = formField(holdingPen, property)(e)
83
+ const ff = formField(holdingPen, property)(e)
84
84
  // e.target.focus()
85
85
  return ff
86
86
  }
@@ -105,7 +105,7 @@ function detectTouchscreen () {
105
105
  return result
106
106
  }
107
107
 
108
- export default ({ wrapperStyle = null, holdingPen, label, placeholder, property, required, pattern, permanentTopPlaceholder = true, permanentTopLabel = false, flatpickrConfig = {}, timeOnly = false, disabled, disableClear = false, onchange, oninput }) => {
108
+ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property, required, pattern, permanentTopPlaceholder = true, permanentTopLabel = false, flatpickrConfig = {}, timeOnly = false, disabled, disableClear = false, onchange, oninput, uniqueKey }) => {
109
109
  // Determine whether we should force Flatpickr on mobile/touch devices.
110
110
  // By default we enable Flatpickr everywhere (disableMobile: true) so that
111
111
  // environments that would otherwise show the native date/time inputs will
@@ -115,8 +115,15 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
115
115
  ? flatpickrConfig.disableMobile
116
116
  : true
117
117
 
118
- let el = html`
119
- <div ${wrapperStyle ? { 'class': wrapperStyle } : ''} style="min-height: 55px; display: inline-block; width: calc(100% - 10px); margin: 40px 5px 5px 5px;">
118
+ // Create a stable id for the outer wrapper so we can query a real DOM node
119
+ // after the template is rendered. Prefer the provided uniqueKey from callers
120
+ // (report-pal already supplies it), otherwise fall back to property/name.
121
+ const wrapperId = `sf-flatpickr-${uniqueKey || property || Math.random().toString(36).slice(2)}`
122
+
123
+ const inputType = resolvedDisableMobile ? 'text' : (detectTouchscreen() ? (timeOnly ? 'time' : 'date') : 'text')
124
+
125
+ const el = html`
126
+ <div id="${wrapperId}" data-flatpickr-wrapper class="${wrapperStyle}" style="min-height: 55px; display: inline-block; width: calc(100% - 10px); margin: 40px 5px 5px 5px;">
120
127
  <div style="display: inline-block; width: 100%; text-align: left; position: relative; padding: 0;">
121
128
  <div class="${styles.icon}">${timeOnly ? timeIcon({ colour: '#ccc' }) : calendarIcon({ colour: '#ccc' })}</div>
122
129
  ${label ? html`<span class="${styles.label}" style="opacity: ${holdingPen[property] === 0 || holdingPen[property] || (permanentTopPlaceholder || permanentTopLabel) ? 1 : 0}; font-size: 16px; font-weight: normal; color: #999; margin-left: 5px; padding: 9px; background-color: rgba(255,255,255,0.8); position: absolute; top: -36px;">${label}${required ? ' *' : ''}</span>` : ''}
@@ -129,7 +136,7 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
129
136
  }}>clear</div>` : ''}
130
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' } : ''} onfocus=${e => {
131
138
  e.target.parentNode.parentNode._flatpickr && e.target.parentNode.parentNode._flatpickr.set('onValueUpdate', (fpDate, dateString) => {
132
- let fauxE = {
139
+ const fauxE = {
133
140
  currentTarget: {
134
141
  validity: {
135
142
  valid: true
@@ -140,30 +147,48 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
140
147
  formField(holdingPen, property)(fauxE)
141
148
  onchange && onchange(fauxE)
142
149
  })
143
- }} onchange=${e => { change({ e, holdingPen, property, label: styles.label }); onchange && onchange(e) }} oninput=${e => { e.target.defaultValue = ''; oninput && oninput(e) }} placeholder="${placeholder || ''}${required ? ' *' : ''}" type="${resolvedDisableMobile ? 'text' : (detectTouchscreen() ? (timeOnly ? 'time' : 'date') : 'text')}" ${pattern ? { pattern } : ''} value="${holdingPen[property] || ''}" data-input />
150
+ }} onchange=${e => { change({ e, holdingPen, property, label: styles.label }); onchange && onchange(e) }} oninput=${e => { e.target.defaultValue = ''; oninput && oninput(e) }} placeholder="${placeholder || ''}${required ? ' *' : ''}" type="${inputType}" ${pattern ? { pattern } : ''} value="${holdingPen[property] || ''}" data-input />
144
151
  </div>
145
152
  </div>
146
153
  `
147
154
 
148
- // Attach flatpickr instance to the OUTER WRAPPER element (not the fragment) so
149
- // internal clear/close handlers can access it consistently via parent wrappers.
150
- // Using `this` or the fragment caused errors after migrating to halfcab/lit.
151
- const wrapper = el.firstElementChild || el
152
- attachFlatpickr(wrapper, flatpickr, Object.assign({}, { disableMobile: resolvedDisableMobile }, flatpickrConfig, {
153
- wrap: true,
154
- onValueUpdate: (fpDate, dateString) => {
155
- let fauxE = {
156
- currentTarget: {
157
- validity: {
158
- valid: true
155
+ // Attach flatpickr instance to the OUTER WRAPPER element after it is actually
156
+ // in the DOM. Passing the TemplateResult directly would not work because the
157
+ // adapter expects a real Element. We defer with requestAnimationFrame and
158
+ // query by id.
159
+ if (typeof window !== 'undefined') {
160
+ const doAttach = () => {
161
+ const wrapperEl = document.getElementById(wrapperId)
162
+ if (!wrapperEl) return
163
+ attachFlatpickr(
164
+ wrapperEl,
165
+ flatpickr,
166
+ Object.assign(
167
+ {},
168
+ { disableMobile: resolvedDisableMobile },
169
+ flatpickrConfig,
170
+ {
171
+ wrap: true,
172
+ onValueUpdate: (fpDate, dateString) => {
173
+ const fauxE = {
174
+ currentTarget: {
175
+ validity: {
176
+ valid: true
177
+ },
178
+ value: dateString
179
+ }
180
+ }
181
+ formField(holdingPen, property)(fauxE)
182
+ onchange && onchange(fauxE)
183
+ }
159
184
  },
160
- value: dateString
161
- }
162
- }
163
- formField(holdingPen, property)(fauxE)
164
- onchange && onchange(fauxE)
185
+ timeOnly ? { noCalendar: true, enableTime: true } : null
186
+ )
187
+ )
165
188
  }
166
- }, timeOnly ? { noCalendar: true, enableTime: true } : null))
189
+ // Defer to next frame to ensure the element is connected
190
+ window.requestAnimationFrame(doAttach)
191
+ }
167
192
 
168
193
  return el
169
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stalefish",
3
- "version": "8.0.4",
3
+ "version": "8.0.5",
4
4
  "description": "Simple function based component library for halfcab tagged template literals",
5
5
  "main": "index.mjs",
6
6
  "module": "index.mjs",