Add price-only MapPin variant (no name)

Name is now optional. When omitted, renders a compact single-line
pill with just "From $X" using the bolder name styling. Useful for
denser map views or when provider identity isn't needed at pin level.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-06 20:55:36 +10:00
parent 9f16bc87c2
commit c457ee8b0d
2 changed files with 57 additions and 24 deletions

View File

@@ -74,6 +74,30 @@ export const NameOnlyUnverified: Story = {
},
};
/** Price-only pill — no name, verified */
export const PriceOnly: Story = {
args: {
price: 900,
verified: true,
},
};
/** Price-only pill — unverified */
export const PriceOnlyUnverified: Story = {
args: {
price: 1200,
},
};
/** Price-only pill — active */
export const PriceOnlyActive: Story = {
args: {
price: 900,
verified: true,
active: true,
},
};
/** Custom price label */
export const CustomPriceLabel: Story = {
args: {

View File

@@ -6,8 +6,8 @@ import type { SxProps, Theme } from '@mui/material/styles';
/** Props for the FA MapPin atom */
export interface MapPinProps {
/** Provider or venue name — always shown on the pin */
name: string;
/** Provider or venue name — omit for a price-only pill */
name?: string;
/** Starting package price in dollars — shown as "From $X" */
price?: number;
/** Custom price label (e.g. "POA") — overrides formatted price */
@@ -81,7 +81,8 @@ const colours = {
* Usage:
* ```tsx
* <MapPin name="H.Parsons" price={900} verified onClick={...} />
* <MapPin name="Smith & Sons" /> {/* No price, unverified *\/}
* <MapPin name="Smith & Sons" /> {/* Name only, unverified *\/}
* <MapPin price={900} verified /> {/* Price-only pill, no name *\/}
* <MapPin name="H.Parsons" price={900} verified active />
* ```
*/
@@ -105,7 +106,7 @@ export const MapPin = React.forwardRef<HTMLDivElement, MapPinProps>(
ref={ref}
role="button"
tabIndex={0}
aria-label={`${name}${hasPrice ? `, packages from $${price?.toLocaleString('en-AU') ?? priceLabel}` : ''}${verified ? ', verified' : ''}${active ? ' (selected)' : ''}`}
aria-label={`${name ?? (verified ? 'Verified' : 'Unverified') + ' provider'}${hasPrice ? `, packages from $${price?.toLocaleString('en-AU') ?? priceLabel}` : ''}${verified ? ', verified' : ''}${active ? ' (selected)' : ''}`}
onClick={onClick}
onKeyDown={handleKeyDown}
sx={[
@@ -150,6 +151,7 @@ export const MapPin = React.forwardRef<HTMLDivElement, MapPinProps>(
}}
>
{/* Name */}
{name && (
<Box
component="span"
sx={{
@@ -167,17 +169,24 @@ export const MapPin = React.forwardRef<HTMLDivElement, MapPinProps>(
>
{name}
</Box>
)}
{/* Price line */}
{hasPrice && (
<Box
component="span"
sx={{
fontSize: 11,
fontWeight: 600,
fontSize: !name ? 12 : 11,
fontWeight: !name ? 700 : 600,
fontFamily: (t: Theme) => t.typography.fontFamily,
lineHeight: 1.2,
color: active ? palette.activePrice : palette.price,
color: !name
? active
? palette.activeName
: palette.name
: active
? palette.activePrice
: palette.price,
whiteSpace: 'nowrap',
transition: 'color 150ms ease-in-out',
}}