Skip to content

Commit 86d3256

Browse files
committed
fix(vue-actionbar): remove class collisions and stabilize parity hooks
1 parent 5cc7cb5 commit 86d3256

File tree

5 files changed

+44
-22
lines changed

5 files changed

+44
-22
lines changed

PARITY_REVIEW_CHECKLIST.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ Use this as a progression checklist for parity re-review. Mark each line when co
1414
- [x] Story: Accordion.stories.ts
1515
- [x] Story: Disclosure.stories.ts
1616
- Evidence: React/Vue story exports and metadata align; targeted story-id parity is zero for `accordion--*` and `disclosure--*`; style-source wiring matches React (`@adobe/spectrum-css-temp/components/accordion/vars.css` with Spectrum selector contract only, no helper-class collisions); fixed RTL indicator parity in `DisclosureTitle` (Vue now renders left-chevron glyph in RTL like React) and added regression coverage in `starters/vue/src/components.spec.ts`; validation rerun passed (`yarn typecheck:vue`, `yarn test:vue`, `yarn build:vue:storybook`).
17-
- [ ] 1.02 `@vue-spectrum/actionbar`
17+
- [x] 1.02 `@vue-spectrum/actionbar`
1818
- Components: ActionBar, ActionBarContainer
19-
- [ ] Story: ActionBar.stories.ts
19+
- [x] Story: ActionBar.stories.ts
20+
- Evidence: React/Vue story export surface and arg metadata align; targeted story-id parity is zero for `actionbar--*`; style-source parity uses shared React Spectrum selectors in `actionbar.css`; class-collision audit found `vs-action-bar*` overlap with `packages/vue-aria-components/src/styles.css`, so Vue Spectrum ActionBar helper classes were renamed to `vs-spectrum-action-bar*` and parity tests moved to stable `data-vs-action-bar*` hooks; validation rerun passed (`yarn typecheck:vue`, `yarn test:vue`, `yarn build:vue:storybook`).
2021
- [ ] 1.03 `@vue-spectrum/actiongroup`
2122
- Components: ActionGroup
2223
- [ ] Story: ActionGroup.stories.ts

packages/@vue-spectrum/actionbar/src/index.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,26 @@ import {ActionButton} from '@vue-spectrum/button';
33
import {ActionGroup} from '@vue-spectrum/actiongroup';
44
import {computed, defineComponent, h, type PropType} from 'vue';
55

6+
const ACTION_BAR_CLEAR_ICON_PATH = 'M11.697 10.283L7.414 6l4.283-4.283A1 1 0 1 0 10.283.303L6 4.586 1.717.303A1 1 0 1 0 .303 1.717L4.586 6 .303 10.283a1 1 0 1 0 1.414 1.414L6 7.414l4.283 4.283a1 1 0 1 0 1.414-1.414z';
7+
68
function normalizeActionKeyForComparison(value: string): string {
79
return value.trim().toLowerCase().replace(/\s+/g, '');
810
}
911

12+
function renderActionBarClearIcon() {
13+
return h('svg', {
14+
class: ['spectrum-Icon', 'spectrum-UIIcon-CrossLarge'],
15+
focusable: 'false',
16+
'aria-hidden': 'true',
17+
role: 'img',
18+
viewBox: '0 0 12 12'
19+
}, [
20+
h('path', {
21+
d: ACTION_BAR_CLEAR_ICON_PATH
22+
})
23+
]);
24+
}
25+
1026
export const ActionBar = defineComponent({
1127
name: 'VueActionBar',
1228
inheritAttrs: false,
@@ -95,7 +111,8 @@ export const ActionBar = defineComponent({
95111
let actions = slots.default
96112
? slots.default()
97113
: h(ActionGroup, {
98-
class: ['react-spectrum-ActionBar-actionGroup', 'vs-action-bar__actions'],
114+
class: ['react-spectrum-ActionBar-actionGroup', 'vs-spectrum-action-bar__actions'],
115+
'data-vs-action-bar-actions': 'true',
99116
'aria-label': 'Actions',
100117
items: props.items,
101118
selectionMode: 'none',
@@ -114,11 +131,12 @@ export const ActionBar = defineComponent({
114131
...attrs,
115132
class: [
116133
actionBarClassName.value,
117-
'vs-action-bar',
134+
'vs-spectrum-action-bar',
118135
isEmphasized.value ? 'is-emphasized' : null,
119136
isOpen.value ? 'is-open' : null,
120137
attrs.class
121138
],
139+
'data-vs-action-bar': 'true',
122140
tabindex: 0,
123141
'data-vac': '',
124142
onKeydown: (event: KeyboardEvent) => {
@@ -128,20 +146,22 @@ export const ActionBar = defineComponent({
128146
}
129147
}
130148
}, [
131-
h('div', {class: ['react-spectrum-ActionBar-bar', 'vs-action-bar__bar']}, [
149+
h('div', {class: ['react-spectrum-ActionBar-bar', 'vs-spectrum-action-bar__bar']}, [
132150
actions,
133151
h(ActionButton, {
134-
class: 'vs-action-bar__clear',
152+
class: 'vs-spectrum-action-bar__clear',
135153
isQuiet: true,
136154
staticColor: isEmphasized.value ? 'white' : undefined,
137155
'aria-label': props.clearLabel,
156+
'data-vs-action-bar-clear': 'true',
138157
style: {
139158
gridArea: 'clear'
140159
},
141160
onClick: () => emit('clearSelection')
142-
}, () => '\u00d7'),
161+
}, () => renderActionBarClearIcon()),
143162
h('p', {
144-
class: ['react-spectrum-ActionBar-selectedCount', 'vs-action-bar__count']
163+
class: ['react-spectrum-ActionBar-selectedCount', 'vs-spectrum-action-bar__count'],
164+
'data-vs-action-bar-count': 'true'
145165
}, selectedLabel.value)
146166
])
147167
]);
@@ -155,7 +175,8 @@ export const ActionBarContainer = defineComponent({
155175
setup(_props, {attrs, slots}) {
156176
return () => h('div', {
157177
...attrs,
158-
class: ['ActionBarContainer', 'vs-action-bar-container', attrs.class],
178+
class: ['ActionBarContainer', 'vs-spectrum-action-bar-container', attrs.class],
179+
'data-vs-action-bar-container': 'true',
159180
'data-vac': ''
160181
}, slots.default ? slots.default() : []);
161182
}

starters/vue/src/components.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1513,7 +1513,7 @@ describe('Vue migration primitives', () => {
15131513
}
15141514
});
15151515

1516-
expect(wrapper.find('button.vs-action-bar__clear svg path').exists()).toBe(true);
1516+
expect(wrapper.find('button[data-vs-action-bar-clear="true"] svg path').exists()).toBe(true);
15171517

15181518
let actionButtons = wrapper.findAll('button[data-vs-action-group-item="true"]');
15191519
expect(actionButtons).toHaveLength(2);

starters/vue/src/composition.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17054,7 +17054,7 @@ describe('Vue migration composition components', () => {
1705417054
expect(wrapper.text()).toContain('2 selected');
1705517055

1705617056
await actionButtons[1].trigger('click');
17057-
await wrapper.get('button.vs-action-bar__clear').trigger('click');
17057+
await wrapper.get('button[data-vs-action-bar-clear="true"]').trigger('click');
1705817058
expect(wrapper.emitted('action')?.[0]).toEqual(['Archive']);
1705917059
expect(wrapper.emitted('clearSelection')).toHaveLength(1);
1706017060
});

starters/vue/src/storybook-parity.spec.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,22 +1570,22 @@ describe('Vue storybook helper parity', () => {
15701570
let wrapper = mount(story);
15711571
wrappers.push(wrapper);
15721572

1573-
expect(wrapper.find('.vs-action-bar').exists()).toBe(false);
1573+
expect(wrapper.find('[data-vs-action-bar="true"]').exists()).toBe(false);
15741574

15751575
let rowSelection = wrapper.findAll('tbody.vs-table__body input.vs-table__selection-checkbox');
15761576
await rowSelection[0].setValue(true);
15771577
await nextTick();
1578-
expect(wrapper.get('.vs-action-bar').exists()).toBe(true);
1579-
expect(wrapper.get('.vs-action-bar__count').text()).toContain('1 selected');
1580-
expect(wrapper.find('button.vs-action-bar__clear svg path').exists()).toBe(true);
1578+
expect(wrapper.get('[data-vs-action-bar="true"]').exists()).toBe(true);
1579+
expect(wrapper.get('[data-vs-action-bar-count="true"]').text()).toContain('1 selected');
1580+
expect(wrapper.find('button[data-vs-action-bar-clear="true"] svg path').exists()).toBe(true);
15811581

15821582
await rowSelection[1].setValue(true);
15831583
await nextTick();
1584-
expect(wrapper.get('.vs-action-bar__count').text()).toContain('2 selected');
1584+
expect(wrapper.get('[data-vs-action-bar-count="true"]').text()).toContain('2 selected');
15851585

1586-
await wrapper.get('button.vs-action-bar__clear').trigger('click');
1586+
await wrapper.get('button[data-vs-action-bar-clear="true"]').trigger('click');
15871587
await nextTick();
1588-
expect(wrapper.find('.vs-action-bar').exists()).toBe(false);
1588+
expect(wrapper.find('[data-vs-action-bar="true"]').exists()).toBe(false);
15891589
} finally {
15901590
for (let wrapper of wrappers) {
15911591
wrapper.unmount();
@@ -2867,19 +2867,19 @@ describe('Vue storybook helper parity', () => {
28672867
let actionBarStory = ListViewWithActionBarStory.render?.({}) as ReturnType<Exclude<typeof ListViewWithActionBarStory.render, undefined>>;
28682868
let actionBarWrapper = mount(actionBarStory);
28692869
wrappers.push(actionBarWrapper);
2870-
expect(actionBarWrapper.get('.vs-action-bar__count').text()).toContain('1 selected');
2870+
expect(actionBarWrapper.get('[data-vs-action-bar-count="true"]').text()).toContain('1 selected');
28712871

28722872
let actionBarListView = actionBarWrapper.getComponent({name: 'VueListView'});
28732873
let actionBarSelectionHandler = (actionBarListView.vm.$.vnode.props as {'onUpdate:modelValue'?: (value: unknown) => void} | undefined)?.['onUpdate:modelValue'];
28742874
expect(actionBarSelectionHandler).toBeTypeOf('function');
28752875
actionBarSelectionHandler?.(new Set(['a', 'b']));
28762876
await nextTick();
2877-
expect(actionBarWrapper.get('.vs-action-bar__count').text()).toContain('2 selected');
2877+
expect(actionBarWrapper.get('[data-vs-action-bar-count="true"]').text()).toContain('2 selected');
28782878

2879-
await actionBarWrapper.get('button.vs-action-bar__clear').trigger('click');
2879+
await actionBarWrapper.get('button[data-vs-action-bar-clear="true"]').trigger('click');
28802880
await nextTick();
28812881
expect(actionBarWrapper.findAll('button.vs-listbox__item.is-selected')).toHaveLength(0);
2882-
expect(actionBarWrapper.find('.vs-action-bar').exists()).toBe(false);
2882+
expect(actionBarWrapper.find('[data-vs-action-bar="true"]').exists()).toBe(false);
28832883
} finally {
28842884
for (let wrapper of wrappers) {
28852885
wrapper.unmount();

0 commit comments

Comments
 (0)