stalefish 8.0.3 → 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,9 +105,25 @@ 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 }) => {
109
- let el = html`
110
- <div ${wrapperStyle ? { 'class': wrapperStyle } : ''} style="min-height: 55px; display: inline-block; width: calc(100% - 10px); margin: 40px 5px 5px 5px;">
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
+ // Determine whether we should force Flatpickr on mobile/touch devices.
110
+ // By default we enable Flatpickr everywhere (disableMobile: true) so that
111
+ // environments that would otherwise show the native date/time inputs will
112
+ // still initialize the Flatpickr widget. Consumers can override by passing
113
+ // { disableMobile: false } inside flatpickrConfig.
114
+ const resolvedDisableMobile = flatpickrConfig && typeof flatpickrConfig.disableMobile !== 'undefined'
115
+ ? flatpickrConfig.disableMobile
116
+ : true
117
+
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;">
111
127
  <div style="display: inline-block; width: 100%; text-align: left; position: relative; padding: 0;">
112
128
  <div class="${styles.icon}">${timeOnly ? timeIcon({ colour: '#ccc' }) : calendarIcon({ colour: '#ccc' })}</div>
113
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>` : ''}
@@ -120,7 +136,7 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
120
136
  }}>clear</div>` : ''}
121
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 => {
122
138
  e.target.parentNode.parentNode._flatpickr && e.target.parentNode.parentNode._flatpickr.set('onValueUpdate', (fpDate, dateString) => {
123
- let fauxE = {
139
+ const fauxE = {
124
140
  currentTarget: {
125
141
  validity: {
126
142
  valid: true
@@ -131,30 +147,48 @@ export default ({ wrapperStyle = null, holdingPen, label, placeholder, property,
131
147
  formField(holdingPen, property)(fauxE)
132
148
  onchange && onchange(fauxE)
133
149
  })
134
- }} onchange=${e => { change({ e, holdingPen, property, label: styles.label }); onchange && onchange(e) }} oninput=${e => { e.target.defaultValue = ''; oninput && oninput(e) }} placeholder="${placeholder || ''}${required ? ' *' : ''}" type="${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 />
135
151
  </div>
136
152
  </div>
137
153
  `
138
154
 
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, {
144
- wrap: true,
145
- onValueUpdate: (fpDate, dateString) => {
146
- let fauxE = {
147
- currentTarget: {
148
- validity: {
149
- 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
+ }
150
184
  },
151
- value: dateString
152
- }
153
- }
154
- formField(holdingPen, property)(fauxE)
155
- onchange && onchange(fauxE)
185
+ timeOnly ? { noCalendar: true, enableTime: true } : null
186
+ )
187
+ )
156
188
  }
157
- }, timeOnly ? { noCalendar: true, enableTime: true } : null))
189
+ // Defer to next frame to ensure the element is connected
190
+ window.requestAnimationFrame(doAttach)
191
+ }
158
192
 
159
193
  return el
160
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stalefish",
3
- "version": "8.0.3",
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",