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 */ /** Custom price label */
export const CustomPriceLabel: Story = { export const CustomPriceLabel: Story = {
args: { args: {

View File

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