Skip to content

Commit

Permalink
feat: childrenTag prop for SfListItem (#2888)
Browse files Browse the repository at this point in the history
* feat:childrenTag prop for SfListItem

* fix: cr fixes

* fix: lint fixes

* fix: cr fixes
  • Loading branch information
justyna-13 authored Jul 7, 2023
1 parent aab5262 commit d5df1cd
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 16 deletions.
6 changes: 6 additions & 0 deletions .changeset/dry-humans-wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@storefront-ui/react': minor
'@storefront-ui/vue': minor
---

New prop for defining tags for children in SfListItem component
14 changes: 8 additions & 6 deletions apps/docs/components/components/listitem.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,16 @@ ListItem component can be rendered as an `<li>` or `<a>` or any other tag by pro
| `disabled ` | `boolean` | `false` | |
| `selected` | `boolean` | `false` | |
<!-- vue -->
| `tag` | `string` | `'li'` | any tag name |
| `tag` | `string` | `'li'` | any tag name |
| `childrenTag` | `string` | `'span'` | any tag name |
<!-- end vue -->
<!-- react -->
| `as` | `ReactElement` | `'li'` | any tag name |
| `children` | `ReactNode` | | label content |
| `slotPrefix` | `ReactNode` | | right side content |
| `slotSuffix` | `ReactNode` | | left side content |
| `className` | `string` | | |
| `as` | `ReactElement` | `'li'` | any tag name |
| `children` | `ReactNode` | | label content |
| `childrenTag` | `ReactElement` | `'span'` | any tag name |
| `slotPrefix` | `ReactNode` | | right side content |
| `slotSuffix` | `ReactNode` | | left side content |
| `className` | `string` | | |
<!-- end react -->

<!-- vue -->
Expand Down
7 changes: 7 additions & 0 deletions apps/preview/next/pages/examples/SfListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ function Example() {
modelName: 'as',
description: 'Change a tag to any other tag',
},
{
type: 'text',
modelName: 'childrenTag',
description: 'Change a tag for children to any other tag',
},
{
type: 'text',
modelName: 'label',
Expand Down Expand Up @@ -99,6 +104,7 @@ function Example() {
],
{
as: 'li',
childrenTag: 'span',
label: 'Label',
size: SfListItemSize.base,
counter: 123,
Expand All @@ -124,6 +130,7 @@ function Example() {
slotSuffix={suffixSlotOptions.getValue(state.get.slotSuffix)?.({
size: state.get.size === 'sm' ? 'sm' : 'base',
})}
childrenTag={state.get.childrenTag}
onClick={() => state.set((currentState) => ({ ...currentState, selected: !currentState.selected }))}
>
<span className="break-words">
Expand Down
6 changes: 6 additions & 0 deletions apps/preview/nuxt/pages/examples/SfListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ const { controlsAttrs, state } = prepareControls(
modelName: 'tag',
description: 'Change a tag to any other tag',
},
{
type: 'text',
modelName: 'childrenTag',
description: 'Change a tag for children to any other tag',
},
{
type: 'text',
modelName: 'label',
Expand Down Expand Up @@ -105,6 +110,7 @@ const { controlsAttrs, state } = prepareControls(
],
{
tag: ref('li'),
childrenTag: ref('span'),
label: ref<string>('Label'),
size: ref<SfListItemSize>(SfListItemSize.base),
counter: ref(123),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const sizeClasses = {
};

const defaultListItemTag = 'li';
const defaultChildrenTag = 'span';

const SfListItem = polymorphicForwardRef<typeof defaultListItemTag, SfListItemProps>((props, ref) => {
const {
Expand All @@ -19,11 +20,13 @@ const SfListItem = polymorphicForwardRef<typeof defaultListItemTag, SfListItemPr
slotPrefix,
slotSuffix,
as,
childrenTag,
children,
...attributes
} = props;

const Tag = as || defaultListItemTag;
const ChildrenTag = childrenTag || defaultChildrenTag;

return (
<Tag
Expand All @@ -41,9 +44,13 @@ const SfListItem = polymorphicForwardRef<typeof defaultListItemTag, SfListItemPr
data-testid="list-item"
{...attributes}
>
{slotPrefix && <span className={disabled ? 'text-disabled-500' : 'text-neutral-500'}>{slotPrefix}</span>}
<span className="flex flex-col w-full min-w-0">{children}</span>
{slotSuffix && <span className={disabled ? 'text-disabled-500' : 'text-neutral-500'}>{slotSuffix}</span>}
{slotPrefix && (
<ChildrenTag className={disabled ? 'text-disabled-500' : 'text-neutral-500'}>{slotPrefix}</ChildrenTag>
)}
<ChildrenTag className="flex flex-col w-full min-w-0">{children}</ChildrenTag>
{slotSuffix && (
<ChildrenTag className={disabled ? 'text-disabled-500' : 'text-neutral-500'}>{slotSuffix}</ChildrenTag>
)}
</Tag>
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ReactNode, PropsWithChildren } from 'react';
import type { ReactNode, PropsWithChildren, ElementType } from 'react';
import type { PropsWithStyle } from '@storefront-ui/react';
import { SfListItemSize } from '@storefront-ui/shared';

Expand All @@ -10,4 +10,5 @@ export interface SfListItemProps extends PropsWithChildren, PropsWithStyle {
slotSuffix?: ReactNode;
slotPrefix?: ReactNode;
role?: string;
childrenTag?: ElementType;
}
16 changes: 10 additions & 6 deletions packages/sfui/frameworks/vue/components/SfListItem/SfListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ defineProps({
type: [String, Object] as PropType<string | ConcreteComponent>,
default: undefined,
},
childrenTag: {
type: String,
default: 'span',
},
});
</script>

Expand All @@ -41,14 +45,14 @@ defineProps({
:disabled="disabled"
data-testid="list-item"
>
<span v-if="$slots.prefix" :class="disabled ? 'text-disabled-500' : 'text-neutral-500'">
<component :is="childrenTag" v-if="$slots.prefix" :class="disabled ? 'text-disabled-500' : 'text-neutral-500'">
<slot name="prefix" />
</span>
<span class="flex flex-col w-full min-w-0">
</component>
<component :is="childrenTag" class="flex flex-col w-full min-w-0">
<slot />
</span>
<span v-if="$slots.suffix" :class="disabled ? 'text-disabled-500' : 'text-neutral-500'">
</component>
<component :is="childrenTag" v-if="$slots.suffix" :class="disabled ? 'text-disabled-500' : 'text-neutral-500'">
<slot name="suffix" />
</span>
</component>
</component>
</template>
8 changes: 8 additions & 0 deletions packages/tests/components/SfListItem/SfListItem.PageObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ export default class SfListItemObject extends BasePage {
return this;
}

childrenHaveTag(tagName: string) {
this.container.children().each((child) => {
const childTagName = child[0].tagName;
expect(childTagName).to.equal(tagName);
});
return this;
}

hasContent(content: string) {
this.container.contains(content);
return this;
Expand Down
13 changes: 13 additions & 0 deletions packages/tests/components/SfListItem/SfListItem.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ describe('SfListItem', () => {
let selected: boolean;
let slotPrefix: boolean;
let slotSuffix: boolean;
let childrenTag: string | React.ElementType;
let onChangeSpy: Cypress.Agent<sinon.SinonSpy>;

const page = () => new SfListItemBaseObject('list-item');
Expand All @@ -33,6 +34,7 @@ describe('SfListItem', () => {
disabled,
size,
selected,
childrenTag,
onClick: onChangeSpy,
},
slots: {
Expand All @@ -46,6 +48,7 @@ describe('SfListItem', () => {
disabled={disabled}
selected={selected}
size={size}
childrenTag={childrenTag}
slotPrefix={slotPrefix && <SfIconCheckCircleReact />}
slotSuffix={slotSuffix && <SfIconCircleReact />}
onClick={onChangeSpy}
Expand Down Expand Up @@ -122,6 +125,16 @@ describe('SfListItem', () => {
});
});

describe('when childrenTag is set to div', () => {
before(() => (childrenTag = 'div'));
after(() => (childrenTag = 'span'));
it(`should render child as div tag`, () => {
initializeComponent();

page().childrenHaveTag('DIV').makeSnapshot();
});
});

describe('when component is clicked', () => {
before(() => (onChangeSpy = cy.spy()));

Expand Down

0 comments on commit d5df1cd

Please sign in to comment.