stalefish 8.0.4 → 8.0.6

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>` : ''}
@@ -127,43 +134,58 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
127
134
  e.target.parentNode.parentNode._flatpickr.close()
128
135
  return false
129
136
  }}>clear</div>` : ''}
130
- <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
- e.target.parentNode.parentNode._flatpickr && e.target.parentNode.parentNode._flatpickr.set('onValueUpdate', (fpDate, dateString) => {
132
- let fauxE = {
133
- currentTarget: {
134
- validity: {
135
- valid: true
136
- },
137
- value: dateString
138
- }
139
- }
140
- formField(holdingPen, property)(fauxE)
141
- onchange && onchange(fauxE)
142
- })
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 />
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 => { 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
138
  </div>
145
139
  </div>
146
140
  `
147
141
 
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
142
+ // Attach flatpickr instance to the OUTER WRAPPER element after it is actually
143
+ // in the DOM. Passing the TemplateResult directly would not work because the
144
+ // adapter expects a real Element. We defer with requestAnimationFrame and
145
+ // query by id.
146
+ if (typeof window !== 'undefined') {
147
+ const doAttach = () => {
148
+ const wrapperEl = document.getElementById(wrapperId)
149
+ if (!wrapperEl) return
150
+ attachFlatpickr(
151
+ wrapperEl,
152
+ flatpickr,
153
+ Object.assign(
154
+ {},
155
+ { disableMobile: resolvedDisableMobile },
156
+ // Provide sensible defaults for time-only pickers; allow user config to override
157
+ timeOnly
158
+ ? {
159
+ dateFormat: flatpickrConfig && flatpickrConfig.dateFormat ? flatpickrConfig.dateFormat : 'H:i',
160
+ defaultDate:
161
+ flatpickrConfig && typeof flatpickrConfig.defaultDate !== 'undefined'
162
+ ? flatpickrConfig.defaultDate
163
+ : (holdingPen && property && holdingPen[property] ? holdingPen[property] : undefined)
164
+ }
165
+ : null,
166
+ flatpickrConfig,
167
+ {
168
+ wrap: true,
169
+ onValueUpdate: (fpDate, dateString) => {
170
+ const fauxE = {
171
+ currentTarget: {
172
+ validity: {
173
+ valid: true
174
+ },
175
+ value: dateString
176
+ }
177
+ }
178
+ formField(holdingPen, property)(fauxE)
179
+ onchange && onchange(fauxE)
180
+ }
159
181
  },
160
- value: dateString
161
- }
162
- }
163
- formField(holdingPen, property)(fauxE)
164
- onchange && onchange(fauxE)
182
+ timeOnly ? { noCalendar: true, enableTime: true } : null
183
+ )
184
+ )
165
185
  }
166
- }, timeOnly ? { noCalendar: true, enableTime: true } : null))
186
+ // Defer to next frame to ensure the element is connected
187
+ window.requestAnimationFrame(doAttach)
188
+ }
167
189
 
168
190
  return el
169
191
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stalefish",
3
- "version": "8.0.4",
3
+ "version": "8.0.6",
4
4
  "description": "Simple function based component library for halfcab tagged template literals",
5
5
  "main": "index.mjs",
6
6
  "module": "index.mjs",