@sbc-connect/nuxt-forms 0.2.1 → 0.4.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @sbc-connect/nuxt-forms
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#118](https://github.com/bcgov/connect-nuxt/pull/118) [`41e58f4`](https://github.com/bcgov/connect-nuxt/commit/41e58f44e6d216e7de568bccb2e240b2d89b8408) Thanks [@deetz99](https://github.com/deetz99)! - Remove now unnecessary css module workaround.
8
+
9
+ - [#117](https://github.com/bcgov/connect-nuxt/pull/117) [`e3da105`](https://github.com/bcgov/connect-nuxt/commit/e3da1056247f5c502578dc70f95375e66e3cc1da) Thanks [@deetz99](https://github.com/deetz99)! - Update all dependencies
10
+
11
+ - [#114](https://github.com/bcgov/connect-nuxt/pull/114) [`fe3eef1`](https://github.com/bcgov/connect-nuxt/commit/fe3eef1b39cc5883cc5e8560efe0dd89d04d0455) Thanks [@cameron-eyds](https://github.com/cameron-eyds)! - Minor styling update, lower level of error styling on FieldSet wrapper
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [[`41e58f4`](https://github.com/bcgov/connect-nuxt/commit/41e58f44e6d216e7de568bccb2e240b2d89b8408), [`e3da105`](https://github.com/bcgov/connect-nuxt/commit/e3da1056247f5c502578dc70f95375e66e3cc1da)]:
16
+ - @sbc-connect/nuxt-base@0.6.0
17
+
18
+ ## 0.3.0
19
+
20
+ ### Minor Changes
21
+
22
+ - [#108](https://github.com/bcgov/connect-nuxt/pull/108) [`8571754`](https://github.com/bcgov/connect-nuxt/commit/8571754160242c3233838fc039fd1a01ff9d7a82) Thanks [@cameron-eyds](https://github.com/cameron-eyds)! - Implements account creation in Auth and Country Code/Country Flag components in Forms
23
+
24
+ ### Patch Changes
25
+
26
+ - [#115](https://github.com/bcgov/connect-nuxt/pull/115) [`dd17349`](https://github.com/bcgov/connect-nuxt/commit/dd173497255f35415b468e17f7192722f604d3c8) Thanks [@deetz99](https://github.com/deetz99)! - Relax postal code mask, different validation message for incorrect format vs invalid postal code
27
+
28
+ - Updated dependencies [[`d9d6356`](https://github.com/bcgov/connect-nuxt/commit/d9d63560e27117c43b9e8e54d363c3fdbb620049)]:
29
+ - @sbc-connect/nuxt-base@0.5.0
30
+
3
31
  ## 0.2.1
4
32
 
5
33
  ### Patch Changes
@@ -34,15 +34,17 @@ const bodyClass = bodyClassMap[bodyVariant]
34
34
  >
35
35
  <div
36
36
  class="flex flex-col gap-1"
37
- :class="{ 'w-full sm:w-1/4 pb-0': orientation === 'horizontal' }"
37
+ :class="{ 'w-full sm:basis-1/4 pb-0': orientation === 'horizontal' }"
38
38
  >
39
39
  <legend
40
40
  :id="legendId"
41
41
  class="text-base text-neutral-highlighted font-bold"
42
- :class="[{ 'text-red-600': !!error }]"
43
42
  >
44
43
  <slot name="label">
45
- <div class="flex flex-wrap gap-4">
44
+ <div
45
+ class="flex flex-wrap gap-4"
46
+ :class="[{ 'text-red-600': !!error }]"
47
+ >
46
48
  <span>{{ label }}</span>
47
49
  <span
48
50
  v-if="!!error && showErrorMsg"
@@ -30,7 +30,7 @@ const model = defineModel<string | undefined>({
30
30
  : $t('connect.label.postalCode')
31
31
  "
32
32
  :mask="country === 'CA'
33
- ? '@#@ #@#'
33
+ ? '*** ***'
34
34
  : country === 'US'
35
35
  ? '#####-####'
36
36
  : undefined"
@@ -20,12 +20,12 @@ const {
20
20
  <span
21
21
  aria-hidden="true"
22
22
  class="text-base text-neutral-highlighted font-bold"
23
- :class="[
24
- { 'text-red-600': !!error },
25
- { 'w-full sm:w-1/4': orientation === 'horizontal' },
26
- ]"
23
+ :class="{ 'w-full sm:basis-1/4': orientation === 'horizontal' }"
27
24
  >
28
- <div class="flex flex-wrap gap-4">
25
+ <div
26
+ class="flex flex-wrap gap-4"
27
+ :class="{ 'text-red-600': !!error }"
28
+ >
29
29
  <span>{{ label }}</span>
30
30
  <span
31
31
  v-if="!!error && showErrorMsg"
@@ -0,0 +1,124 @@
1
+ <script setup lang="ts">
2
+ import countryList from 'country-codes-list'
3
+ import CountryFlag from '#forms/app/components/Connect/Form/Phone/CountryFlag.vue'
4
+ import type { PhoneCountry } from '#forms/app/interfaces/phone-country'
5
+
6
+ defineProps<{
7
+ isInvalid: boolean | undefined
8
+ }>()
9
+
10
+ const countryCallingCode = defineModel<string | undefined>('countryCallingCode', { required: false })
11
+ watch(countryCallingCode, (val) => {
12
+ // this is needed for when something outside this component changes the callingCode model value
13
+ if (!val) {
14
+ countryIso2.value = undefined
15
+ } else if (selectedCountry.value?.callingCode !== val) {
16
+ countryIso2.value = search(val)[0]?.iso2
17
+ }
18
+ })
19
+
20
+ const countryIso2 = defineModel<string | undefined>('countryIso2', { required: false })
21
+ watch(countryIso2, (val) => {
22
+ if (!val) {
23
+ selectedCountry.value = undefined
24
+ } else if (val && selectedCountry.value?.iso2 !== val) {
25
+ selectCountry(val)
26
+ }
27
+ })
28
+
29
+ const selectedCountry = ref<PhoneCountry | undefined>(undefined)
30
+ watch(selectedCountry, (newVal) => {
31
+ if (newVal?.callingCode !== countryCallingCode.value) {
32
+ countryCallingCode.value = newVal?.callingCode
33
+ }
34
+ if (newVal?.iso2 !== countryIso2.value) {
35
+ countryIso2.value = newVal?.iso2
36
+ }
37
+ })
38
+
39
+ const _countryListOptions = countryList.customList(
40
+ 'countryCode', '{countryCallingCode},{countryNameEn},{countryNameLocal}')
41
+
42
+ const manualInput = (event: Event) => {
43
+ selectedCountry.value = {
44
+ callingCode: event.target.value
45
+ }
46
+ }
47
+
48
+ const countryListOptions: Array<PhoneCountry> = Object.keys(_countryListOptions).map((key) => {
49
+ const [callingCode, nameEn, nameLocal] = _countryListOptions[key].split(',')
50
+ return {
51
+ iso2: key,
52
+ callingCode,
53
+ label: `+${callingCode}`,
54
+ nameLocal,
55
+ nameEn
56
+ }
57
+ }).sort((a, b) => a.callingCode.localeCompare(b.callingCode))
58
+
59
+ const search = (q: string) => countryListOptions.filter((lo) => {
60
+ return lo.callingCode.includes(q)
61
+ || lo.iso2?.includes(q)
62
+ || lo.nameLocal?.includes(q)
63
+ || lo.nameEn?.includes(q)
64
+ || lo.label?.includes(q)
65
+ })
66
+
67
+ const selectCountry = (iso2: string) => {
68
+ selectedCountry.value = countryListOptions.find(item => item.iso2 === iso2)
69
+ }
70
+
71
+ onMounted(() => {
72
+ if (countryIso2.value !== undefined) {
73
+ selectCountry(countryIso2.value)
74
+ } else if (countryCallingCode.value) {
75
+ // Set a country based on the calling code if available
76
+ const iso2 = search(countryCallingCode.value)[0]?.iso2
77
+ if (iso2) {
78
+ selectCountry(iso2)
79
+ } else {
80
+ selectedCountry.value = {
81
+ callingCode: countryCallingCode.value,
82
+ label: `+${countryCallingCode.value}`
83
+ }
84
+ }
85
+ }
86
+ })
87
+ </script>
88
+
89
+ <template>
90
+ <UInputMenu
91
+ v-model="selectedCountry"
92
+ :items="countryListOptions"
93
+ :color="selectedCountry?.callingCode ? 'primary' : ''"
94
+ :search="search"
95
+ :label-key="''"
96
+ :trailing-icon="'i-mdi-chevron-down'"
97
+ class="cursor-pointer"
98
+ :aria-required="true"
99
+ :aria-invalid="isInvalid"
100
+ :aria-label="$t('connect.label.countryCode')"
101
+ @input="manualInput($event)"
102
+ >
103
+ <template v-if="!!selectedCountry?.iso2" #leading="{ modelValue }">
104
+ <div class="flex">
105
+ <CountryFlag
106
+ :tooltip-text="selectedCountry?.nameEn"
107
+ :country-code-iso2letter="selectedCountry?.iso2"
108
+ />
109
+ <span class="ml-2 mt-2 truncate">{{ modelValue.label }}</span>
110
+ </div>
111
+ </template>
112
+
113
+ <template #item="{ item }">
114
+ <div class="flex items-end cursor-pointer">
115
+ <CountryFlag
116
+ :tooltip-text="item.nameLocal"
117
+ :country-code-iso2letter="item.iso2"
118
+ />
119
+ <span class="ml-2 truncate">{{ item.label }}</span>
120
+ <span class="sr-only">{{ item.nameLocal }}</span>
121
+ </div>
122
+ </template>
123
+ </UInputMenu>
124
+ </template>
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ import CountryFlag from 'vue-country-flag-next'
3
+
4
+ defineProps<{
5
+ countryCodeIso2letter: string
6
+ }>()
7
+ </script>
8
+
9
+ <template>
10
+ <CountryFlag
11
+ class="mb-2"
12
+ :country="countryCodeIso2letter"
13
+ />
14
+ </template>
@@ -0,0 +1,2 @@
1
+ <!-- Placeholder for compound phone component -->
2
+ <!-- This component will be used to capture phone number details including country code, number input and ext. -->
@@ -0,0 +1,14 @@
1
+ export interface Phone {
2
+ countryIso2?: string
3
+ countryCode?: string
4
+ number: string
5
+ extension?: string
6
+ }
7
+
8
+ export interface PhoneCountry {
9
+ callingCode: string
10
+ iso2?: string
11
+ label?: string
12
+ nameLocal?: string
13
+ nameEn?: string
14
+ }
@@ -0,0 +1,13 @@
1
+ import type { FormErrorEvent } from '@nuxt/ui'
2
+
3
+ export function onFormSubmitError(event: FormErrorEvent) {
4
+ if (event?.errors?.[0]?.id) {
5
+ const element = document.getElementById(event.errors[0].id)
6
+ if (element) {
7
+ element.scrollIntoView({ behavior: 'smooth', block: 'center' })
8
+ setTimeout(() => {
9
+ element.focus({ preventScroll: true })
10
+ }, 0)
11
+ }
12
+ }
13
+ }
@@ -5,6 +5,7 @@ import { z } from 'zod'
5
5
  * Ref: https://en.wikipedia.org/wiki/Postal_codes_in_Canada
6
6
  */
7
7
  const CanadaPostalCodeRegex = /^[ABCEGHJ-NPRSTVXY][0-9][ABCEGHJ-NPRSTV-Z][ ]?[0-9][ABCEGHJ-NPRSTV-Z][0-9]$/i
8
+ const CanadaPostalCodeFormatOnlyRegex = /^[A-Z][0-9][A-Z][ ]?[0-9][A-Z][0-9]$/i
8
9
 
9
10
  /**
10
11
  * US ZIP code regex (eg, accepts 12345 or 12345-6789).
@@ -78,12 +79,18 @@ export function getRequiredAddressSchema() {
78
79
  }
79
80
 
80
81
  if (country === 'CA') {
81
- if (!CanadaPostalCodeRegex.test(postalCode)) {
82
+ if (!CanadaPostalCodeFormatOnlyRegex.test(postalCode)) {
82
83
  ctx.addIssue({
83
84
  code: 'custom',
84
85
  message: t('connect.validation.invalidPostalCodeFormat'),
85
86
  path: ['postalCode']
86
87
  })
88
+ } else if (!CanadaPostalCodeRegex.test(postalCode)) {
89
+ ctx.addIssue({
90
+ code: 'custom',
91
+ message: t('connect.validation.invalidPostalCode'),
92
+ path: ['postalCode']
93
+ })
87
94
  }
88
95
  } else if (country === 'US') {
89
96
  if (!USZipCodeRegex.test(postalCode)) {
@@ -7,6 +7,7 @@ export default {
7
7
  city: 'City',
8
8
  code: 'Code',
9
9
  country: 'Country',
10
+ countryCode: 'Country Code',
10
11
  deliveryAddress: 'Delivery Address',
11
12
  deliveryInstructions: 'Delivery Instructions',
12
13
  deliveryInstructionsOpt: 'Delivery Instructions (Optional)',
@@ -39,8 +40,9 @@ export default {
39
40
  maxChars: 'Maximum 0 characters | Maximum 1 character | Maximum {count} characters', // 0/1 most likely will never be used but required for pluralization
40
41
  minChars: 'Minimum 0 characters | Minimum 1 character | Minimum {count} characters', // 0/1 most likely will never be used but required for pluralization
41
42
  required: 'Required',
42
- invalidPostalCodeFormat: 'Invalid Postal Code format (e.g., 1X1 X1X)',
43
- invalidZipCodeFormat: 'Invalid ZIP Code format (e.g., 12345 or 12345-6789)'
43
+ invalidPostalCode: 'Enter a valid postal code',
44
+ invalidPostalCodeFormat: 'Format must be A1A 1A1',
45
+ invalidZipCodeFormat: 'Format must be 12345 or 12345-6789'
44
46
  }
45
47
  }
46
48
  }
package/package.json CHANGED
@@ -1,23 +1,24 @@
1
1
  {
2
2
  "name": "@sbc-connect/nuxt-forms",
3
3
  "type": "module",
4
- "version": "0.2.1",
4
+ "version": "0.4.0",
5
5
  "repository": "github:bcgov/connect-nuxt",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "./nuxt.config.ts",
8
8
  "devDependencies": {
9
9
  "@axe-core/playwright": "4.11.0",
10
- "@vitest/coverage-v8": "3.2.4",
11
10
  "dotenv": "17.2.3",
12
- "nuxt": "4.1.3",
11
+ "nuxt": "4.2.2",
13
12
  "typescript": "5.9.3",
14
- "vue-tsc": "3.1.2",
15
- "@sbc-connect/playwright-config": "0.0.8",
16
- "@sbc-connect/vitest-config": "0.0.6",
17
- "@sbc-connect/eslint-config": "0.0.8"
13
+ "vue-tsc": "3.2.1",
14
+ "@sbc-connect/eslint-config": "0.0.8",
15
+ "@sbc-connect/playwright-config": "0.1.0",
16
+ "@sbc-connect/vitest-config": "0.1.0"
18
17
  },
19
18
  "dependencies": {
20
- "@sbc-connect/nuxt-base": "0.4.0"
19
+ "country-codes-list": "2.0.0",
20
+ "vue-country-flag-next": "2.3.2",
21
+ "@sbc-connect/nuxt-base": "0.6.0"
21
22
  },
22
23
  "scripts": {
23
24
  "preinstall": "npx only-allow pnpm",
@@ -1,15 +0,0 @@
1
- import { defineNuxtModule, createResolver } from 'nuxt/kit'
2
-
3
- export default defineNuxtModule({
4
- meta: {
5
- name: 'form-assets',
6
- configKey: 'formAssets'
7
- },
8
- defaults: {},
9
- async setup(_options, _nuxt) {
10
- console.info('Setting up **form** assets module')
11
- const resolver = createResolver(import.meta.url)
12
-
13
- _nuxt.options.css.push(resolver.resolve('./runtime/assets/connect-form-tw.css'))
14
- }
15
- })
@@ -1,2 +0,0 @@
1
- @import "#connect-theme";
2
- @source "../../../../app";