@citizenplane/pimp 18.1.0 → 18.1.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@citizenplane/pimp",
3
- "version": "18.1.0",
3
+ "version": "18.1.1",
4
4
  "scripts": {
5
5
  "dev": "storybook dev -p 8081",
6
6
  "build-storybook": "storybook build --output-dir ./docs",
@@ -4,33 +4,36 @@
4
4
  {{ capitalizedLabel }}
5
5
  </base-input-label>
6
6
  <div class="cpDate__inputs">
7
- <input
8
- v-model="day"
9
- v-maska
10
- :autocomplete="autocompleteFields.day"
11
- class="cpDate__day"
12
- data-maska="##"
13
- :disabled="disabled"
14
- inputmode="numeric"
15
- maxlength="2"
16
- :placeholder="dayInputPlaceholder"
17
- :required="required"
18
- />
19
- <div class="cpDate__divider" />
20
- <div class="cpDate__month" :class="selectDynamicClass">
21
- <select
22
- :id="cpDateId"
23
- v-model="month"
24
- :autocomplete="autocompleteFields.month"
7
+ <template v-for="(field, index) in orderedDateFields" :key="field">
8
+ <input
9
+ v-if="isDayField(field)"
10
+ v-model="day"
11
+ v-maska
12
+ :autocomplete="autocompleteFields.day"
13
+ class="cpDate__day"
14
+ data-maska="##"
25
15
  :disabled="disabled"
16
+ inputmode="numeric"
17
+ maxlength="2"
18
+ :placeholder="dayInputPlaceholder"
26
19
  :required="required"
27
- >
28
- <option value>{{ monthInputPlaceholder }}</option>
29
- <option v-for="(monthItem, index) in months" :key="index" :value="monthItem.value">
30
- {{ monthItem.label }}
31
- </option>
32
- </select>
33
- </div>
20
+ />
21
+ <div v-else class="cpDate__month" :class="selectDynamicClass">
22
+ <select
23
+ :id="cpDateId"
24
+ v-model="month"
25
+ :autocomplete="autocompleteFields.month"
26
+ :disabled="disabled"
27
+ :required="required"
28
+ >
29
+ <option value>{{ monthInputPlaceholder }}</option>
30
+ <option v-for="(monthItem, monthIndex) in months" :key="monthIndex" :value="monthItem.value">
31
+ {{ monthItem.label }}
32
+ </option>
33
+ </select>
34
+ </div>
35
+ <div v-if="shouldShowDivider(index)" class="cpDate__divider" />
36
+ </template>
34
37
  <div class="cpDate__divider" />
35
38
  <input
36
39
  v-model="year"
@@ -71,6 +74,7 @@ interface InputsOptions {
71
74
  monthInputPlaceholder?: string
72
75
  yearInputPlaceholder?: string
73
76
  }
77
+ type DateField = 'day' | 'month'
74
78
 
75
79
  interface Props {
76
80
  autocompleteBirthday?: boolean
@@ -265,6 +269,24 @@ const monthInputPlaceholder = computed(() => {
265
269
  return props.inputsOptions?.monthInputPlaceholder || 'Months'
266
270
  })
267
271
 
272
+ const isDayFirst = computed(() => {
273
+ const parts = new Intl.DateTimeFormat(props.locale, {
274
+ day: '2-digit',
275
+ month: '2-digit',
276
+ }).formatToParts(new Date(2024, 0, 31))
277
+
278
+ const dayIndex = parts.findIndex((part) => part.type === 'day')
279
+ const monthIndex = parts.findIndex((part) => part.type === 'month')
280
+
281
+ if (dayIndex === -1 || monthIndex === -1) return false
282
+
283
+ return dayIndex < monthIndex
284
+ })
285
+
286
+ const orderedDateFields = computed<DateField[]>(() => {
287
+ return isDayFirst.value ? ['day', 'month'] : ['month', 'day']
288
+ })
289
+
268
290
  const yearInputPlaceholder = computed(() => {
269
291
  return props.inputsOptions?.yearInputPlaceholder || 'YYYY'
270
292
  })
@@ -274,6 +296,10 @@ const handleUpdate = (): void => {
274
296
  emit('onValidation', isDateValid.value)
275
297
  }
276
298
 
299
+ const isDayField = (field: DateField): boolean => field === 'day'
300
+
301
+ const shouldShowDivider = (index: number): boolean => index < orderedDateFields.value.length - 1
302
+
277
303
  watch(day, handleUpdate)
278
304
  watch(month, handleUpdate)
279
305
  watch(year, handleUpdate)
@@ -296,6 +322,7 @@ watch(year, handleUpdate)
296
322
  }
297
323
 
298
324
  input[type='number'] {
325
+ appearance: textfield;
299
326
  -moz-appearance: textfield;
300
327
  }
301
328
 
@@ -140,6 +140,33 @@ export const States: Story = {
140
140
  }),
141
141
  }
142
142
 
143
+ /**
144
+ * Compares input ordering by locale (day/month in French, month/day in US English).
145
+ */
146
+ export const LocaleOrdering: Story = {
147
+ parameters: { controls: { disable: true } },
148
+ render: () => ({
149
+ components: { CpDate },
150
+ setup() {
151
+ const frenchDate = ref('')
152
+ const usDate = ref('')
153
+ return { frenchDate, usDate, docRowColumnStyle, dateStackStyle, docLabelStyle }
154
+ },
155
+ template: `
156
+ <div :style="docRowColumnStyle">
157
+ <div :style="dateStackStyle">
158
+ <span :style="docLabelStyle">fr-FR (day / month / year)</span>
159
+ <CpDate v-model="frenchDate" label="Date" locale="fr-FR" />
160
+ </div>
161
+ <div :style="dateStackStyle">
162
+ <span :style="docLabelStyle">en-US (month / day / year)</span>
163
+ <CpDate v-model="usDate" label="Date" locale="en-US" />
164
+ </div>
165
+ </div>
166
+ `,
167
+ }),
168
+ }
169
+
143
170
  /**
144
171
  * Combines a date input with a text input on the same line.
145
172
  */