Skip to content

Commit b8c317f

Browse files
committed
Add in chnages for accessibility for rev share generator
1 parent 8ccc4c4 commit b8c317f

File tree

3 files changed

+183
-51
lines changed

3 files changed

+183
-51
lines changed

frontend/app/components/redesign/components/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ export { ImportTagModal } from './revshare/ImportTagModal'
3333
export { RevShareChart } from './revshare/RevShareChart'
3434
export { ShareInput } from './revshare/ShareInput'
3535
export { ShareInputHeader } from './revshare/ShareInput'
36+
export { ShareInputTable } from './revshare/ShareInput'
3637
export { RevShareInfo } from './revshare/RevShareInfo'

frontend/app/components/redesign/components/revshare/ShareInput.tsx

Lines changed: 137 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,72 @@ interface ShareInputProps {
2424
const GRID_COLS = 'md:grid-cols-[16rem_1fr_6rem_6rem_auto]'
2525
const GRID_GAP = 'md:gap-x-md'
2626

27+
export const ShareInputTable = ({
28+
children
29+
}: {
30+
children: React.ReactNode
31+
}) => {
32+
return (
33+
<div
34+
role="table"
35+
aria-labelledby="revshare-table-caption"
36+
className="contents"
37+
>
38+
<div id="revshare-table-caption" className="sr-only">
39+
Revenue sharing recipients configuration table
40+
</div>
41+
{children}
42+
</div>
43+
)
44+
}
45+
2746
export const ShareInputHeader = () => {
2847
return (
2948
<div
49+
role="row"
50+
aria-rowindex={1}
3051
className={cx(
3152
'hidden p-md leading-sm text-silver-600 rounded-sm bg-silver-50',
3253
'md:grid',
3354
GRID_COLS,
3455
GRID_GAP
3556
)}
3657
>
37-
<div>Name</div>
38-
<div>Wallet Address/Payment Pointer</div>
39-
<div>Weight</div>
40-
<div>Percentage</div>
41-
<div>Action</div>
58+
<div
59+
role="columnheader"
60+
id="col-recipient-name"
61+
aria-label="Recipient name, optional field"
62+
>
63+
Name
64+
</div>
65+
<div
66+
role="columnheader"
67+
id="col-payment-pointer"
68+
aria-label="Wallet address or payment pointer for recipient, required field"
69+
>
70+
Wallet Address/Payment Pointer
71+
</div>
72+
<div
73+
role="columnheader"
74+
id="col-weight"
75+
aria-label="Weight value for revenue distribution, required field"
76+
>
77+
Weight
78+
</div>
79+
<div
80+
role="columnheader"
81+
id="col-percentage"
82+
aria-label="Calculated percentage of total revenue based on weight"
83+
>
84+
Percentage
85+
</div>
86+
<div
87+
role="columnheader"
88+
id="col-action"
89+
aria-label="Action to remove recipient from table"
90+
>
91+
Action
92+
</div>
4293
</div>
4394
)
4495
}
@@ -61,8 +112,16 @@ export const ShareInput = React.memo(
61112
weightDisabled = false
62113
}: ShareInputProps) => {
63114
const hasError = !validatePointer(pointer)
115+
const nameInputId = `name-input-${index}`
116+
const pointerInputId = `pointer-input-${index}`
117+
const weightInputId = `weight-input-${index}`
118+
const percentInputId = `percent-input-${index}`
119+
64120
return (
65121
<div
122+
role="row"
123+
aria-rowindex={index + 2}
124+
aria-invalid={hasError}
66125
className={cx(
67126
'bg-white flex flex-col gap-md p-md rounded-lg border border-silver-200',
68127
'md:rounded-none md:border-none md:grid md:px-md md:py-0 md:items-center',
@@ -76,34 +135,74 @@ export const ShareInput = React.memo(
76135
<ToolsSecondaryButton
77136
onClick={onRemove}
78137
className="border-none py-sm px-xs shrink-0"
79-
aria-label={`Recipient ${index + 1}`}
138+
aria-label={`Remove recipient ${index + 1}`}
80139
>
81-
<SVGDeleteScript className="w-5 h-5" />
140+
<SVGDeleteScript className="w-5 h-5" aria-hidden="true" />
82141
</ToolsSecondaryButton>
83142
</div>
84-
<div>
143+
<div role="cell" aria-labelledby="col-recipient-name">
144+
<label htmlFor={nameInputId} className="sr-only">
145+
Name (optional)
146+
</label>
85147
<InputField
148+
id={nameInputId}
86149
placeholder="Fill in name (optional)"
87150
value={name}
88151
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
89152
onChangeName(e.target.value)
90153
}
154+
aria-describedby={`name-description-${index}`}
91155
/>
156+
<div id={`name-description-${index}`} className="sr-only">
157+
Optional display name for recipient {index + 1}
158+
</div>
92159
</div>
93-
<div className="relative">
160+
<div
161+
role="cell"
162+
className="relative"
163+
aria-labelledby="col-payment-pointer"
164+
>
165+
<label htmlFor={pointerInputId} className="sr-only">
166+
Wallet Address or Payment Pointer *
167+
</label>
94168
<InputField
169+
id={pointerInputId}
95170
placeholder={placeholder}
96171
value={pointer}
97172
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
98173
onChangePointer(e.target.value)
99174
}
175+
aria-invalid={hasError}
176+
aria-describedby={cx(
177+
`pointer-description-${index}`,
178+
hasError ? `pointer-error-${index}` : ''
179+
)}
180+
aria-required="true"
100181
/>
101-
<p className="absolute left-0 text-xs mt-2xs text-text-error">
102-
{hasError && 'Invalid payment pointer'}
103-
</p>
182+
<div id={`pointer-description-${index}`} className="sr-only">
183+
Wallet address or payment pointer for recipient {index + 1}
184+
</div>
185+
{hasError && (
186+
<div
187+
id={`pointer-error-${index}`}
188+
className="absolute left-0 text-xs mt-2xs text-text-error"
189+
role="alert"
190+
aria-live="polite"
191+
>
192+
Invalid payment pointer
193+
</div>
194+
)}
104195
</div>
105-
<div className={hasError ? 'mt-xs' : 'md:mt-0'}>
196+
<div
197+
role="cell"
198+
className={hasError ? 'mt-xs' : 'md:mt-0'}
199+
aria-labelledby="col-weight"
200+
>
201+
<label htmlFor={weightInputId} className="sr-only">
202+
Weight *
203+
</label>
106204
<InputField
205+
id={weightInputId}
107206
type="number"
108207
value={weight}
109208
min={0}
@@ -112,10 +211,22 @@ export const ShareInput = React.memo(
112211
onChangeWeight(Number(e.target.value))
113212
}
114213
disabled={weightDisabled}
214+
aria-disabled={weightDisabled}
215+
aria-describedby={`weight-description-${index}`}
216+
aria-required="true"
115217
/>
218+
<div id={`weight-description-${index}`} className="sr-only">
219+
Weight value for revenue distribution calculation for
220+
recipient&nbsp;
221+
{index + 1}
222+
</div>
116223
</div>
117-
<div>
224+
<div role="cell" aria-labelledby="col-percent">
225+
<label htmlFor={percentInputId} className="sr-only">
226+
Percentage
227+
</label>
118228
<InputField
229+
id={percentInputId}
119230
type="number"
120231
min={0}
121232
max={100}
@@ -125,15 +236,24 @@ export const ShareInput = React.memo(
125236
onChangePercent(Number(e.target.value) / 100)
126237
}
127238
disabled={percentDisabled}
239+
aria-disabled={percentDisabled}
240+
aria-describedby={`percent-description-${index}`}
128241
/>
242+
<div id={`percent-description-${index}`} className="sr-only">
243+
Calculated percentage of total revenue for recipient {index + 1}
244+
</div>
129245
</div>
130-
<div className="hidden md:block">
246+
<div
247+
role="cell"
248+
className="hidden md:block"
249+
aria-labelledby="col-action"
250+
>
131251
<ToolsSecondaryButton
132252
onClick={onRemove}
133253
className="border-none py-sm px-xs shrink-0"
134-
aria-label={`Remove recipient ${index + 1}`}
254+
aria-label={`Remove recipient ${index + 1} from revenue sharing table`}
135255
>
136-
<SVGDeleteScript className="w-5 h-5" />
256+
<SVGDeleteScript className="w-5 h-5" aria-hidden="true" />
137257
</ToolsSecondaryButton>
138258
</div>
139259
</div>

frontend/app/routes/prob-revshare.tsx

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
RevShareInfo,
1010
ShareInput,
1111
ShareInputHeader,
12+
ShareInputTable,
1213
ToolsPrimaryButton,
1314
ToolsSecondaryButton
1415
} from '@/components'
@@ -155,37 +156,43 @@ function Revshare() {
155156
</HeadingCore>
156157
<Card>
157158
<Heading5>Recipients</Heading5>
158-
<ShareInputHeader />
159-
{shares.map((share, i) => {
160-
return (
161-
<ShareInput
162-
key={i}
163-
index={i}
164-
name={share.name || ''}
165-
onChangeName={(name) => handleChangeName(i, name)}
166-
pointer={share.pointer}
167-
onChangePointer={(pointer) => handleChangePointer(i, pointer)}
168-
weight={share.weight || 0}
169-
onChangeWeight={(weight) => handleChangeWeight(i, weight)}
170-
weightDisabled={!share.pointer}
171-
percent={
172-
totalWeight > 0 ? (share.weight || 0) / totalWeight : 0
173-
}
174-
percentDisabled={!share.pointer || shares.length <= 1}
175-
onChangePercent={(percent) =>
176-
handleChangePercent(
177-
i,
178-
percent,
179-
share.weight || 1,
180-
totalWeight
181-
)
182-
}
183-
onRemove={() => handleRemove(i)}
184-
validatePointer={validatePointer}
185-
placeholder={getPlaceholderText(i)}
186-
/>
187-
)
188-
})}
159+
<ShareInputTable>
160+
<ShareInputHeader />
161+
<div role="rowgroup" className="contents">
162+
{shares.map((share, i) => {
163+
return (
164+
<ShareInput
165+
key={i}
166+
index={i}
167+
name={share.name || ''}
168+
onChangeName={(name) => handleChangeName(i, name)}
169+
pointer={share.pointer}
170+
onChangePointer={(pointer) =>
171+
handleChangePointer(i, pointer)
172+
}
173+
weight={share.weight || 0}
174+
onChangeWeight={(weight) => handleChangeWeight(i, weight)}
175+
weightDisabled={!share.pointer}
176+
percent={
177+
totalWeight > 0 ? (share.weight || 0) / totalWeight : 0
178+
}
179+
percentDisabled={!share.pointer || shares.length <= 1}
180+
onChangePercent={(percent) =>
181+
handleChangePercent(
182+
i,
183+
percent,
184+
share.weight || 1,
185+
totalWeight
186+
)
187+
}
188+
onRemove={() => handleRemove(i)}
189+
validatePointer={validatePointer}
190+
placeholder={getPlaceholderText(i)}
191+
/>
192+
)
193+
})}
194+
</div>
195+
</ShareInputTable>
189196
<hr className={!hasValidShares ? 'md:mt-2xs' : ''} />
190197
<div className="flex flex-col-reverse md:flex-col gap-md">
191198
{revSharePointers && hasValidShares && (
@@ -196,12 +203,16 @@ function Revshare() {
196203
/>
197204
<button
198205
onClick={handleCopyClick}
199-
aria-label={isCopied ? 'Copied' : 'Copy code to clipboard'}
206+
aria-label={
207+
isCopied
208+
? 'Monetization tag copied to clipboard'
209+
: 'Copy monetization tag to clipboard'
210+
}
200211
>
201212
{isCopied ? (
202-
<SVGCheckIcon className="h-6 w-6" />
213+
<SVGCheckIcon className="h-6 w-6" aria-hidden="true" />
203214
) : (
204-
<SVGCopyIcon className="h-6 w-6" />
215+
<SVGCopyIcon className="h-6 w-6" aria-hidden="true" />
205216
)}
206217
</button>
207218
</div>

0 commit comments

Comments
 (0)