Skip to content

Commit b588f3b

Browse files
committed
Fix labels on mobile
1 parent e9a8031 commit b588f3b

4 files changed

Lines changed: 89 additions & 115 deletions

File tree

packages/react/src/PricingOptions/PricingOptions.module.css

Lines changed: 35 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -62,85 +62,63 @@
6262
}
6363
}
6464

65-
.PricingOptions__labels {
66-
display: none;
65+
.PricingOptions__label-cell {
66+
grid-row: labels;
67+
justify-self: stretch;
6768
}
6869

69-
@media (min-width: 63.25rem) {
70-
.PricingOptions__labels {
71-
--brand-pricing-options-column-count: 1;
70+
.PricingOptions__label-cell--empty {
71+
display: none;
72+
}
7273

73-
display: grid;
74-
grid-column: 1 / -1;
75-
grid-row: labels;
76-
grid-template-columns: repeat(var(--brand-pricing-options-column-count), minmax(0, 1fr));
77-
column-gap: var(--brand-pricing-options-item-gap, 0);
78-
}
74+
.PricingOptions__label-cell--has-label {
75+
display: flex;
76+
align-items: center;
77+
margin-inline: calc(var(--brand-pricing-options-item-padding-inline, 0px) * -1);
78+
margin-block-end: var(--base-size-16);
79+
padding-inline: var(--brand-pricing-options-item-padding-inline, 0px);
80+
padding-block-end: var(--base-size-16);
81+
border-block-end: var(--brand-borderWidth-thin) solid var(--brand-color-border-subtle);
82+
}
7983

84+
@media (min-width: 63.25rem) {
8085
.PricingOptions__label-cell {
8186
position: relative;
8287
display: flex;
8388
align-items: center;
8489
min-height: var(--base-size-54);
90+
margin-block-end: 0;
8591
padding-block: var(--base-size-16);
92+
border-block-end: 0;
8693
background-color: var(--brand-PricingOptions-item-bgColor-solid);
94+
transform: translateY(calc(var(--brand-pricing-options-item-padding-block-start, 0px) * -1));
8795
}
8896

8997
/* Accent top border — uses ::after so it can overflow into the column gap */
9098
.PricingOptions__label-cell--has-label::after {
9199
content: '';
92100
position: absolute;
93101
inset-block-start: 0;
94-
inset-inline-start: calc(var(--brand-pricing-options-item-gap, 0px) / 2 * -1);
95-
inset-inline-end: calc(var(--brand-pricing-options-item-gap, 0px) / 2 * -1);
102+
inset-inline: 0;
96103
height: var(--brand-borderWidth-thin);
97104
background-color: var(--brand-color-text-emphasized);
98105
z-index: 1;
99106
}
100107

101-
/* First cell: don't overflow past container start (cards override below) */
102-
.PricingOptions__label-cell--has-label:first-child::after {
103-
inset-inline-start: 0;
104-
}
105-
106-
/* Last cell: don't overflow past container end (cards override below) */
107-
.PricingOptions__label-cell--has-label:last-child::after {
108-
inset-inline-end: 0;
109-
}
110-
111-
.PricingOptions--layout-default .PricingOptions__label-cell--has-label::after {
112-
inset-inline-start: 0;
113-
inset-inline-end: 0;
114-
}
115-
116108
/* ---- Default layout labels ---- */
117109

118-
/* Continuous bottom border across entire labels row — uses ::after to extend into container padding */
119-
.PricingOptions--layout-default .PricingOptions__labels {
120-
position: relative;
121-
}
122-
123-
.PricingOptions--layout-default .PricingOptions__labels::after {
124-
content: '';
125-
position: absolute;
126-
inset-block-end: 0;
127-
inset-inline-start: calc(var(--brand-pricing-options-container-padding-inline, 0px) * -1);
128-
inset-inline-end: calc(var(--brand-pricing-options-container-padding-inline, 0px) * -1);
129-
height: var(--brand-borderWidth-thin);
130-
background-color: var(--brand-color-border-subtle);
131-
}
132-
133110
.PricingOptions--layout-default .PricingOptions__label-cell {
134111
margin-inline: calc(var(--brand-pricing-options-item-gap) / 2 * -1);
135112
padding-inline: calc(var(--brand-pricing-options-item-gap) / 2);
113+
border-block-end: var(--brand-borderWidth-thin) solid var(--brand-color-border-subtle);
136114
}
137115

138-
.PricingOptions--layout-default .PricingOptions__label-cell:first-child {
116+
.PricingOptions--layout-default .PricingOptions__item:first-child .PricingOptions__label-cell {
139117
margin-inline-start: calc(var(--brand-pricing-options-container-padding-inline) * -1);
140118
padding-inline-start: var(--brand-pricing-options-container-padding-inline);
141119
}
142120

143-
.PricingOptions--layout-default .PricingOptions__label-cell:last-child {
121+
.PricingOptions--layout-default .PricingOptions__item:last-child .PricingOptions__label-cell {
144122
margin-inline-end: calc(var(--brand-pricing-options-container-padding-inline) * -1);
145123
padding-inline-end: var(--brand-pricing-options-container-padding-inline);
146124
}
@@ -151,28 +129,29 @@
151129
border-block-start-color: transparent;
152130
}
153131

154-
/* Vertical dividers between label cells, centered in the gap */
155-
.PricingOptions--layout-default .PricingOptions__label-cell + .PricingOptions__label-cell::before {
132+
/* Vertical dividers between label cells, centered in the column gap */
133+
.PricingOptions--layout-default .PricingOptions__item + .PricingOptions__item .PricingOptions__label-cell::before {
156134
content: '';
157135
position: absolute;
158136
inset-block: 0;
159-
width: var(--brand-borderWidth-thin);
160137
inset-inline-start: 0;
138+
width: var(--brand-borderWidth-thin);
161139
background-color: var(--brand-color-border-subtle);
162140
}
163141

164142
.PricingOptions--layout-default.PricingOptions--appearance-gradient
165-
.PricingOptions__label-cell
166-
+ .PricingOptions__label-cell::before {
143+
.PricingOptions__item
144+
+ .PricingOptions__item
145+
.PricingOptions__label-cell::before {
167146
mask-image: var(--brand-PricingOptions-borderMask);
168147
}
169148

170149
/* ---- Cards layout labels ---- */
171150

172151
.PricingOptions--layout-cards .PricingOptions__label-cell {
152+
margin-inline: calc(var(--brand-pricing-options-item-padding-inline) * -1);
173153
padding-inline: var(--base-size-28);
174154
border-inline: var(--brand-borderWidth-thin) solid var(--brand-color-border-subtle);
175-
/* border-block-end: var(--brand-borderWidth-thin) solid var(--brand-color-border-muted); */
176155
}
177156

178157
.PricingOptions--layout-cards .PricingOptions__label-cell--empty {
@@ -228,6 +207,7 @@
228207

229208
.PricingOptions--layout-default .PricingOptions__item {
230209
--brand-pricing-options-item-padding-inline: var(--base-size-24);
210+
--brand-pricing-options-item-padding-block-start: var(--base-size-20);
231211

232212
position: relative; /* Used for positioning the divider between items */
233213
padding-inline: var(--base-size-24);
@@ -272,6 +252,7 @@
272252
@media (min-width: 63.25rem) {
273253
.PricingOptions--layout-default .PricingOptions__item {
274254
--brand-pricing-options-item-padding-inline: 0;
255+
--brand-pricing-options-item-padding-block-start: var(--base-size-40);
275256

276257
padding-inline: 0;
277258
padding-block: var(--base-size-40);
@@ -311,6 +292,7 @@
311292

312293
.PricingOptions--layout-cards .PricingOptions__item {
313294
--brand-pricing-options-item-padding-inline: var(--base-size-32);
295+
--brand-pricing-options-item-padding-block-start: var(--base-size-32);
314296

315297
position: relative;
316298
padding-inline: var(--base-size-32);
@@ -368,12 +350,12 @@
368350

369351
@media (min-width: 63.25rem) {
370352
.PricingOptions__item {
371-
grid-row: header / footnote;
353+
grid-row: labels / footnote;
372354
grid-template-rows: subgrid;
373355
}
374356

375357
.PricingOptions__item--has-leading-component {
376-
grid-row: leadingComponent / footnote;
358+
grid-row: labels / footnote;
377359
}
378360
}
379361

@@ -640,10 +622,6 @@
640622
/* First item: don't overflow past container start */
641623
.PricingOptions--layout-default
642624
.PricingOptions__item:first-child
643-
:is(.PricingOptions__price, .PricingOptions__feature-list--has-divider)::before,
644-
.PricingOptions--layout-default
645-
.PricingOptions__labels
646-
+ .PricingOptions__item
647625
:is(.PricingOptions__price, .PricingOptions__feature-list--has-divider)::before {
648626
inset-inline-start: calc(var(--brand-pricing-options-container-padding-inline, 0px) * -1);
649627
}

packages/react/src/PricingOptions/PricingOptions.module.css.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ declare const styles: {
3535
readonly "PricingOptions__label-cell": string;
3636
readonly "PricingOptions__label-cell--empty": string;
3737
readonly "PricingOptions__label-cell--has-label": string;
38-
readonly "PricingOptions__labels": string;
3938
readonly "PricingOptions__leading-component": string;
4039
readonly "PricingOptions__menu-action": string;
4140
readonly "PricingOptions__price": string;

packages/react/src/PricingOptions/PricingOptions.test.tsx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react'
2-
import {render, cleanup} from '@testing-library/react'
2+
import {render, cleanup, within} from '@testing-library/react'
33

44
import '@testing-library/jest-dom'
55
import userEvent from '@testing-library/user-event'
@@ -164,34 +164,41 @@ describe('PricingOptions', () => {
164164
expect(getByText(mockFootnote)).toBeInTheDocument()
165165
})
166166

167-
it('renders header labels in a dedicated row above items', () => {
167+
it('renders labels inside their corresponding PricingOptions.Item', () => {
168168
const firstLabel = 'Most popular'
169169
const secondLabel = 'Best value'
170170

171-
const {getByTestId, getAllByTestId, getByText} = render(
171+
const {getAllByTestId} = render(
172172
<PricingOptions>
173173
<PricingOptions.Item>
174174
<PricingOptions.Label>{firstLabel}</PricingOptions.Label>
175175
<PricingOptions.Heading>First</PricingOptions.Heading>
176176
</PricingOptions.Item>
177177
<PricingOptions.Item>
178-
<PricingOptions.Label>{secondLabel}</PricingOptions.Label>
179178
<PricingOptions.Heading>Second</PricingOptions.Heading>
180179
</PricingOptions.Item>
180+
<PricingOptions.Item>
181+
<PricingOptions.Label>{secondLabel}</PricingOptions.Label>
182+
<PricingOptions.Heading>Third</PricingOptions.Heading>
183+
</PricingOptions.Item>
181184
</PricingOptions>,
182185
)
183186

184-
expect(getByTestId(PricingOptions.testIds.labelRow)).toBeInTheDocument()
185-
expect(getAllByTestId(PricingOptions.testIds.label)).toHaveLength(2)
186-
expect(getByText(firstLabel)).toBeInTheDocument()
187-
expect(getByText(secondLabel)).toBeInTheDocument()
187+
const items = getAllByTestId(PricingOptions.testIds.item)
188+
189+
expect(getAllByTestId(PricingOptions.testIds.label)).toHaveLength(3)
190+
expect(within(items[0]).getByText(firstLabel)).toBeInTheDocument()
191+
expect(within(items[1]).queryByText(firstLabel)).not.toBeInTheDocument()
192+
expect(within(items[1]).queryByText(secondLabel)).not.toBeInTheDocument()
193+
expect(within(items[2]).getByText(secondLabel)).toBeInTheDocument()
188194
})
189195

190196
it('renders PricingOptions.Item markup in the expected order', () => {
191197
mockUseWindowSize.mockReturnValue(mediumBreakpoint)
192198

193199
const {getByTestId} = render(
194200
<PricingOptions.Item data-testid={testId}>
201+
<PricingOptions.Label>{mockHeaderLabel}</PricingOptions.Label>
195202
<PricingOptions.Footnote>{mockFootnote}</PricingOptions.Footnote>
196203
<PricingOptions.Description>{mockDescription}</PricingOptions.Description>
197204
<PricingOptions.Heading>{mockHeading}</PricingOptions.Heading>
@@ -205,6 +212,7 @@ describe('PricingOptions', () => {
205212
const PricingOptionsItemEl = getByTestId(testId)
206213

207214
const expectedOrder = [
215+
'PricingOptions__label',
208216
'PricingOptions__heading',
209217
'PricingOptions__description',
210218
'PricingOptions__featureList',

0 commit comments

Comments
 (0)