From 9d7cc062481464f6ed671f9102b5200fbf17051f Mon Sep 17 00:00:00 2001 From: Charline Mons <48532888+charlinemons@users.noreply.github.com> Date: Wed, 13 May 2026 12:02:01 -0400 Subject: [PATCH 1/2] feat: microbird brand variants for FieldGooglePlacesAutocomplete --- .../dist/brands/microbird-commercial.css | 4 ++ .../tokens/dist/brands/microbird-school.css | 4 ++ .../src/sets/brands/microbird-commercial.json | 21 ++++++ .../src/sets/brands/microbird-school.json | 21 ++++++ ...eldGooglePlacesAutocomplete.acorn.brand.ts | 47 ++++++++++++ ...Autocomplete.microbird-commercial.brand.ts | 16 +++++ ...acesAutocomplete.microbird-school.brand.ts | 16 +++++ .../brands/index.ts | 24 +++++++ .../FieldGooglePlacesAutocomplete/index.tsx | 34 ++++----- pnpm-lock.yaml | 71 ++++++++----------- 10 files changed, 198 insertions(+), 60 deletions(-) create mode 100644 packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.acorn.brand.ts create mode 100644 packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.microbird-commercial.brand.ts create mode 100644 packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.microbird-school.brand.ts create mode 100644 packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/index.ts diff --git a/packages/tokens/dist/brands/microbird-commercial.css b/packages/tokens/dist/brands/microbird-commercial.css index 2e1935e..9a10891 100644 --- a/packages/tokens/dist/brands/microbird-commercial.css +++ b/packages/tokens/dist/brands/microbird-commercial.css @@ -21,7 +21,11 @@ [data-pui-brand='microbird-commercial'] { --pui-color-interactive-on-primary: var(--pui-primitive-color-primary-1); --pui-color-button-secondary-outline: #22222233; + --pui-color-input-bg: #FFFFFF; + --pui-color-input-border: #22222233; + --pui-color-input-placeholder: var(--pui-primitive-color-primary-9); --pui-color-alertbar-first-fg: var(--pui-primitive-color-primary-1); + --pui-radius-input: 2rem; --pui-typo-heading-1-size: 6.25rem; --pui-typo-heading-1-weight: var(--pui-primitive-font-weight-semibold); --pui-typo-heading-1-tracking: -0.01em; diff --git a/packages/tokens/dist/brands/microbird-school.css b/packages/tokens/dist/brands/microbird-school.css index 3a37f3b..0d7a654 100644 --- a/packages/tokens/dist/brands/microbird-school.css +++ b/packages/tokens/dist/brands/microbird-school.css @@ -18,6 +18,10 @@ [data-pui-brand='microbird-school'] { --pui-color-fg-link-active: var(--pui-primitive-color-overlay-12); --pui-color-button-secondary-outline: #22222233; + --pui-color-input-bg: #FFFFFF; + --pui-color-input-border: #22222233; + --pui-color-input-placeholder: var(--pui-primitive-color-primary-9); + --pui-radius-input: 2rem; --pui-typo-heading-1-size: 6.25rem; --pui-typo-heading-1-weight: var(--pui-primitive-font-weight-semibold); --pui-typo-heading-1-tracking: -0.01em; diff --git a/packages/tokens/src/sets/brands/microbird-commercial.json b/packages/tokens/src/sets/brands/microbird-commercial.json index 0f08b03..81f9880 100644 --- a/packages/tokens/src/sets/brands/microbird-commercial.json +++ b/packages/tokens/src/sets/brands/microbird-commercial.json @@ -132,6 +132,27 @@ "$value": "#22222233", "$description": "Button outline border — overlay-12 at 20% opacity." } + }, + "input": { + "bg": { + "$value": "#FFFFFF", + "$description": "Input background is pure white on microbird (vs Acorn's default surface)." + }, + "border": { + "$value": "#22222233", + "$description": "Input border — overlay-12 at 20% opacity (matches button secondary-outline)." + }, + "placeholder": { + "$value": "{pui.primitive.color.primary.9}", + "$description": "Placeholder uses the brand primary-9 navy so the gmp shadow-DOM input picks it up through CSS-custom-property inheritance." + } + } + }, + "radius": { + "$type": "borderRadius", + "input": { + "$value": "2rem", + "$description": "Microbird inputs are pill-shaped (rounded-4xl). Cascades to the gmp shadow-DOM input via --pui-radius-input." } } } diff --git a/packages/tokens/src/sets/brands/microbird-school.json b/packages/tokens/src/sets/brands/microbird-school.json index fad1231..6585ef8 100644 --- a/packages/tokens/src/sets/brands/microbird-school.json +++ b/packages/tokens/src/sets/brands/microbird-school.json @@ -123,6 +123,27 @@ "$value": "#22222233", "$description": "Button outline border — overlay-12 at 20% opacity." } + }, + "input": { + "bg": { + "$value": "#FFFFFF", + "$description": "Input background is pure white on microbird (vs Acorn's default surface)." + }, + "border": { + "$value": "#22222233", + "$description": "Input border — overlay-12 at 20% opacity (matches button secondary-outline)." + }, + "placeholder": { + "$value": "{pui.primitive.color.primary.9}", + "$description": "Placeholder uses the brand primary-9 yellow so the gmp shadow-DOM input picks it up through CSS-custom-property inheritance." + } + } + }, + "radius": { + "$type": "borderRadius", + "input": { + "$value": "2rem", + "$description": "Microbird inputs are pill-shaped (rounded-4xl). Cascades to the gmp shadow-DOM input via --pui-radius-input." } } } diff --git a/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.acorn.brand.ts b/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.acorn.brand.ts new file mode 100644 index 0000000..db4ef31 --- /dev/null +++ b/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.acorn.brand.ts @@ -0,0 +1,47 @@ +import { cva } from '@/lib/cva'; + +/** + * Acorn brand FieldGooglePlacesAutocomplete container variants (default/base theme). + * + * Layered on top of `inputVariants` from FieldBaseInput — captures the overlay + * styling that is specific to this component (the real input lives inside the + * gmp-place-autocomplete shadow DOM, so we use `focus-within:*` rather than + * `focus:*` for the outer container). + * + * Semantic tokens used (brand-overridable via CSS): + * - bg-pui-bg-subtle / text-pui-fg-subtle / border-pui-bg-subtle (disabled) + * - border-pui-input-border-focus (focus-within border) + * - shadow-pui-input-focus (focus-within ring) + * - color-pui-feedback-error (error focus-within ring) + */ +export const fieldGooglePlacesAutocompleteAcornVariants = cva({ + base: ['pui:flex pui:items-center'], + variants: { + disabled: { + false: null, + true: 'pui:cursor-not-allowed pui:bg-pui-bg-subtle pui:text-pui-fg-subtle pui:border-pui-bg-subtle' + }, + error: { + false: null, + true: null + } + }, + compoundVariants: [ + { + disabled: false, + error: false, + class: + 'pui:focus-within:outline-none pui:focus-within:border-pui-input-border-focus pui:focus-within:shadow-pui-input-focus' + }, + { + disabled: false, + error: true, + class: + 'pui:focus-within:outline-none pui:focus-within:border-pui-input-border-focus pui:focus-within:shadow-[0_0_0_2px_var(--color-pui-feedback-error)]' + } + ], + defaultVariants: { + disabled: false, + error: false + } +}); diff --git a/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.microbird-commercial.brand.ts b/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.microbird-commercial.brand.ts new file mode 100644 index 0000000..50026b7 --- /dev/null +++ b/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.microbird-commercial.brand.ts @@ -0,0 +1,16 @@ +import { cva } from '@/lib/cva'; + +/** + * MicroBird Commercial brand FieldGooglePlacesAutocomplete container variants. + * + * Composed on top of Acorn via `compose()` in `brands/index.ts`. All + * brand-level differences (input bg, border, placeholder colour, radius) + * are handled via semantic CSS tokens overridden in + * `packages/tokens/src/sets/brands/microbird-commercial.json`. This file is + * kept as scaffolding so future class-level differences (typography, + * decoration, brand-specific structural overrides) can be added here + * without touching the registry. + */ +export const fieldGooglePlacesAutocompleteMicroBirdCommercialVariants = cva({ + base: [] +}); diff --git a/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.microbird-school.brand.ts b/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.microbird-school.brand.ts new file mode 100644 index 0000000..763b53b --- /dev/null +++ b/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/FieldGooglePlacesAutocomplete.microbird-school.brand.ts @@ -0,0 +1,16 @@ +import { cva } from '@/lib/cva'; + +/** + * MicroBird School brand FieldGooglePlacesAutocomplete container variants. + * + * Composed on top of Acorn via `compose()` in `brands/index.ts`. All + * brand-level differences (input bg, border, placeholder colour, radius) + * are handled via semantic CSS tokens overridden in + * `packages/tokens/src/sets/brands/microbird-school.json`. This file is + * kept as scaffolding so future class-level differences (typography, + * decoration, brand-specific structural overrides) can be added here + * without touching the registry. + */ +export const fieldGooglePlacesAutocompleteMicroBirdSchoolVariants = cva({ + base: [] +}); diff --git a/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/index.ts b/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/index.ts new file mode 100644 index 0000000..445d179 --- /dev/null +++ b/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/brands/index.ts @@ -0,0 +1,24 @@ +import { type BrandVariants } from '@/lib/brand-registry'; +import { compose } from '@/lib/cva'; +import { type VariantProps } from 'cva'; +import { fieldGooglePlacesAutocompleteAcornVariants } from './FieldGooglePlacesAutocomplete.acorn.brand'; +import { fieldGooglePlacesAutocompleteMicroBirdCommercialVariants } from './FieldGooglePlacesAutocomplete.microbird-commercial.brand'; +import { fieldGooglePlacesAutocompleteMicroBirdSchoolVariants } from './FieldGooglePlacesAutocomplete.microbird-school.brand'; + +export const fieldGooglePlacesAutocompleteBrandVariants = { + acorn: fieldGooglePlacesAutocompleteAcornVariants, + 'microbird-commercial': compose( + fieldGooglePlacesAutocompleteAcornVariants, + fieldGooglePlacesAutocompleteMicroBirdCommercialVariants + ), + 'microbird-school': compose( + fieldGooglePlacesAutocompleteAcornVariants, + fieldGooglePlacesAutocompleteMicroBirdSchoolVariants + ) +} as const satisfies BrandVariants< + typeof fieldGooglePlacesAutocompleteAcornVariants +>; + +export type FieldGooglePlacesAutocompleteVariantProps = VariantProps< + typeof fieldGooglePlacesAutocompleteAcornVariants +>; diff --git a/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/index.tsx b/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/index.tsx index 6b90075..e2d0652 100644 --- a/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/index.tsx +++ b/packages/ui/src/components/Field/FieldGooglePlacesAutocomplete/index.tsx @@ -1,6 +1,7 @@ 'use client'; import { useGoogleContext } from '@/components/GoogleProvider'; +import { getBrandVariant } from '@/lib/brand-registry'; import { cx } from '@/lib/cva'; import { type ForceRequiredProps } from '@perimetre/helpers/types'; import { useEffect, useLayoutEffect, useRef, useState } from 'react'; @@ -9,6 +10,7 @@ import { inputVariants } from '../FieldBaseInput'; import FieldContainer from '../FieldContainer'; import FieldLower, { type FieldLowerProps } from '../FieldLower'; import FieldUpper, { type FieldUpperProps } from '../FieldUpper'; +import { fieldGooglePlacesAutocompleteBrandVariants } from './brands'; export type FieldGooglePlacesAutocompleteProps = { containerClassName?: string; @@ -792,22 +794,17 @@ const FieldGooglePlacesAutocomplete: React.FC< aria-describedby={ariaDescribedBy} aria-invalid={!!error || undefined} id={`${name}-input`} - className={inputVariants({ - className: cx( - 'pui:flex pui:items-center', - disabled && - 'pui:cursor-not-allowed pui:bg-pui-bg-subtle pui:text-pui-fg-subtle pui:border-pui-bg-subtle', - !disabled && - 'pui:focus-within:outline-none pui:focus-within:border-pui-input-border-focus', - !disabled && - (error - ? 'pui:focus-within:shadow-[0_0_0_2px_var(--color-pui-feedback-error)]' - : 'pui:focus-within:shadow-pui-input-focus') - ), - error: !!error, - leading: !!leading, - trailing: !!trailing - })} + className={cx( + inputVariants({ + error: !!error, + leading: !!leading, + trailing: !!trailing + }), + getBrandVariant(fieldGooglePlacesAutocompleteBrandVariants)({ + disabled: !!disabled, + error: !!error + }) + )} > {/* Placeholder input — defines the container height and shows during SSR / before Google API loads. When a defaultValue is @@ -817,10 +814,13 @@ const FieldGooglePlacesAutocomplete: React.FC< =18.0.0' - version: 19.2.0 + version: 19.2.4 devDependencies: '@perimetre/eslint-config-base': specifier: workspace:* @@ -249,13 +249,13 @@ importers: dependencies: prettier: specifier: '>=3.0.0' - version: 3.6.2 + version: 3.8.1 prettier-plugin-organize-imports: specifier: ^4.3.0 - version: 4.3.0(prettier@3.6.2)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) prettier-plugin-tailwindcss: specifier: ^0.7.2 - version: 0.7.2(prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.3))(prettier@3.6.2) + version: 0.7.2(prettier-plugin-organize-imports@4.3.0(prettier@3.8.1)(typescript@5.9.3))(prettier@3.8.1) packages/service-builder: devDependencies: @@ -10573,14 +10573,6 @@ packages: engines: { node: '>=10.13.0' } hasBin: true - prettier@3.6.2: - resolution: - { - integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== - } - engines: { node: '>=14' } - hasBin: true - prettier@3.7.4: resolution: { @@ -14492,11 +14484,11 @@ snapshots: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-accessible-icon@1.1.8(@types/react-dom@19.2.3(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-accessible-icon@1.1.8(@types/react-dom@19.2.3(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-visually-hidden': 1.2.4(@types/react-dom@19.2.3(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.4(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.4(@types/react-dom@19.2.3(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 19.2.3(@types/react@18.3.28) @@ -14607,9 +14599,9 @@ snapshots: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.28)(react@19.2.0)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.28)(react@19.2.4)': dependencies: - react: 19.2.0 + react: 19.2.4 optionalDependencies: '@types/react': 18.3.28 @@ -14935,11 +14927,11 @@ snapshots: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.4(react@19.2.0) + '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 19.2.3(@types/react@18.3.28) @@ -15070,10 +15062,10 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-slot@1.2.4(@types/react@18.3.28)(react@19.2.0)': + '@radix-ui/react-slot@1.2.4(@types/react@18.3.28)(react@19.2.4)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.0) - react: 19.2.0 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.4) + react: 19.2.4 optionalDependencies: '@types/react': 18.3.28 @@ -15259,11 +15251,11 @@ snapshots: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-visually-hidden@1.2.4(@types/react-dom@19.2.3(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-visually-hidden@1.2.4(@types/react-dom@19.2.3(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.4(react@19.2.0) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 19.2.3(@types/react@18.3.28) @@ -19673,21 +19665,19 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.3): + prettier-plugin-organize-imports@4.3.0(prettier@3.8.1)(typescript@5.9.3): dependencies: - prettier: 3.6.2 + prettier: 3.8.1 typescript: 5.9.3 - prettier-plugin-tailwindcss@0.7.2(prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.3))(prettier@3.6.2): + prettier-plugin-tailwindcss@0.7.2(prettier-plugin-organize-imports@4.3.0(prettier@3.8.1)(typescript@5.9.3))(prettier@3.8.1): dependencies: - prettier: 3.6.2 + prettier: 3.8.1 optionalDependencies: - prettier-plugin-organize-imports: 4.3.0(prettier@3.6.2)(typescript@5.9.3) + prettier-plugin-organize-imports: 4.3.0(prettier@3.8.1)(typescript@5.9.3) prettier@2.8.8: {} - prettier@3.6.2: {} - prettier@3.7.4: {} prettier@3.8.1: {} @@ -19810,11 +19800,6 @@ snapshots: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - react-dom@19.2.4(react@19.2.0): - dependencies: - react: 19.2.0 - scheduler: 0.27.0 - react-dom@19.2.4(react@19.2.4): dependencies: react: 19.2.4 From ceaf178339b2dad2afda22c81630e817fb9180de Mon Sep 17 00:00:00 2001 From: Charline Mons <48532888+charlinemons@users.noreply.github.com> Date: Wed, 13 May 2026 12:05:10 -0400 Subject: [PATCH 2/2] chore: run changeset --- .changeset/every-vans-clean.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/every-vans-clean.md diff --git a/.changeset/every-vans-clean.md b/.changeset/every-vans-clean.md new file mode 100644 index 0000000..08e339e --- /dev/null +++ b/.changeset/every-vans-clean.md @@ -0,0 +1,6 @@ +--- +'@perimetre/tokens': minor +'@perimetre/ui': minor +--- + +Add microbird brand support to `FieldGooglePlacesAutocomplete`