Skip to content

Commit

Permalink
feat(card): implement component
Browse files Browse the repository at this point in the history
  • Loading branch information
Leotheluck authored and dpellier committed Jul 29, 2024
1 parent 0c690db commit ec30d5f
Show file tree
Hide file tree
Showing 25 changed files with 491 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/ods/react/tests/_app/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const componentNames = [
'checkbox',
'select',
'modal',
'card',
//--generator-anchor--
];

Expand Down
12 changes: 12 additions & 0 deletions packages/ods/react/tests/_app/src/components/ods-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react-dom/client';
import { OdsCard, OdsText } from 'ods-components-react';

const Card = () => {
return (
<OdsCard>
<OdsText preset='heading-6'>Hello, world!</OdsText>
</OdsCard>
);
};

export default Card;
23 changes: 23 additions & 0 deletions packages/ods/react/tests/e2e/ods-card.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Page } from 'puppeteer';
import { goToComponentPage, setupBrowser } from '../setup';

describe('ods-card react', () => {
const setup = setupBrowser();
let page: Page;

beforeAll(async () => {
page = setup().page;
});

beforeEach(async () => {
await goToComponentPage(page, 'ods-card');
});

it('render the component correctly', async () => {
const elem = await page.$('ods-card');
const boundingBox = await elem?.boundingBox();

expect(boundingBox?.height).toBeGreaterThan(0);
expect(boundingBox?.width).toBeGreaterThan(0);
});
});
5 changes: 5 additions & 0 deletions packages/ods/src/components/card/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Local Stencil command generates external ods component build at the root of the project
# Excluding them is a temporary solution to avoid pushing generated files
# But the issue may cause main build (ods-component package) to fails, as it detects multiples occurences
# of the same component and thus you have to delete all those generated dir manually
*/src/
19 changes: 19 additions & 0 deletions packages/ods/src/components/card/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@ovhcloud/ods-component-card",
"version": "17.1.0",
"private": true,
"description": "ODS Card component",
"main": "dist/index.cjs.js",
"collection": "dist/collection/collection-manifest.json",
"scripts": {
"clean": "rimraf .stencil coverage dist docs-api www",
"doc": "typedoc --pretty --plugin ../../../scripts/typedoc-plugin-decorator.js && node ../../../scripts/generate-typedoc-md.js",
"lint:scss": "stylelint 'src/components/**/*.scss'",
"lint:ts": "eslint '{src,tests}/**/*.{js,ts,tsx}'",
"start": "stencil build --dev --watch --serve",
"test:e2e": "stencil test --e2e --config stencil.config.ts",
"test:e2e:ci": "tsc --noEmit && stencil test --e2e --ci --runInBand --config stencil.config.ts",
"test:spec": "stencil test --spec --config stencil.config.ts --coverage",
"test:spec:ci": "tsc --noEmit && stencil test --config stencil.config.ts --spec --ci --coverage"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
:host(.ods-card) {
display: inline-block;
}

.ods-card {
&__wrapper {
border: 1px solid;
border-radius: 8px;

&--neutral {
border-color: var(--ods-color-neutral-200);
}

&--primary {
border-color: var(--ods-color-primary-200);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { FunctionalComponent } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { ODS_CARD_COLOR, type OdsCardColor } from '../../constants/card-color';

@Component({
shadow: true,
styleUrl: 'ods-card.scss',
tag: 'ods-card',
})
export class OdsCard {
@Prop({ reflect: true }) public color: OdsCardColor = ODS_CARD_COLOR.primary;

render(): FunctionalComponent {
return (
<Host class={ 'ods-card' }>
<div class={ `ods-card__wrapper ods-card__wrapper--${this.color}` } part={ 'card' }>
<slot></slot>
</div>
</Host>
);
}
}
14 changes: 14 additions & 0 deletions packages/ods/src/components/card/src/constants/card-color.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
enum ODS_CARD_COLOR {
neutral = 'neutral',
primary = 'primary',
}

type OdsCardColor = `${ODS_CARD_COLOR}`;

const ODS_CARD_COLORS = Object.freeze(Object.values(ODS_CARD_COLOR));

export {
ODS_CARD_COLOR,
ODS_CARD_COLORS,
type OdsCardColor,
};
9 changes: 9 additions & 0 deletions packages/ods/src/components/card/src/globals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Import here all the external ODS component that you need to run the current component
* when running dev server (yarn start) or e2e tests
*
* ex:
* import '../../text/src';
*/

import '../../text/src';
39 changes: 39 additions & 0 deletions packages/ods/src/components/card/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html dir='ltr' lang='en'>
<head>
<meta charset='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0' />
<title>Dev ods-card</title>

<script type='module' src='/build/ods-card.esm.js'></script>
<script nomodule src='/build/ods-card.js'></script>
<link rel="stylesheet" href="/build/ods-card.css">
</head>

<body>
<p>Default</p>
<ods-card>
<ods-text preset="label">Hello, world!</ods-text>
</ods-card>

<p>Primary</p>
<ods-card color="primary">
<ods-text preset="label">Hello, world!</ods-text>
</ods-card>

<p>Neutral</p>
<ods-card color="neutral">
<ods-text preset="label">Hello, world!</ods-text>
</ods-card>

<style>
* {
font-family: 'Source Sans Pro', sans-serif;
}

ods-card::part(card) {
padding: 24px;
}
</style>
</body>
</html>
2 changes: 2 additions & 0 deletions packages/ods/src/components/card/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { OdsCard } from './components/ods-card/ods-card';
export { ODS_CARD_COLOR, ODS_CARD_COLORS, type OdsCardColor } from './constants/card-color';
7 changes: 7 additions & 0 deletions packages/ods/src/components/card/stencil.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { getStencilConfig } from '../../config/stencil';

export const config = getStencilConfig({
args: process.argv.slice(2),
componentCorePackage: '@ovhcloud/ods-component-card',
namespace: 'ods-card',
});
56 changes: 56 additions & 0 deletions packages/ods/src/components/card/tests/rendering/ods-card.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { E2EElement, E2EPage } from '@stencil/core/testing';
import { newE2EPage } from '@stencil/core/testing';

describe('ods-card rendering', () => {
let el: E2EElement;
let page: E2EPage;

async function setup(content: string, customStyle?: string): Promise<void> {
page = await newE2EPage();

await page.setContent(content);
await page.evaluate(() => document.body.style.setProperty('margin', '0px'));

if (customStyle) {
await page.addStyleTag({ content: customStyle });
}

el = await page.find('ods-card');
}

it('should render the web component', async() => {
await setup('<ods-card></ods-card>');

expect(el.shadowRoot).not.toBeNull();
});

describe('color', () => {
it('should render with correct color primary', async() => {
await setup(`
<ods-card color="primary">
</ods-card>
`);

const hasClassPrimary = await page.evaluate(() => {
const wrapper = document.querySelector('ods-card')?.shadowRoot?.querySelector('.ods-card__wrapper');
return wrapper?.classList.contains('ods-card__wrapper--primary');
});

expect(hasClassPrimary).toBe(true);
});

it('should render with correct color neutral', async() => {
await setup(`
<ods-card color="neutral">
</ods-card>
`);

const hasClassNeutral = await page.evaluate(() => {
const wrapper = document.querySelector('ods-card')?.shadowRoot?.querySelector('.ods-card__wrapper');
return wrapper?.classList.contains('ods-card__wrapper--neutral');
});

expect(hasClassNeutral).toBe(true);
});
});
});
35 changes: 35 additions & 0 deletions packages/ods/src/components/card/tests/rendering/ods-card.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { SpecPage } from '@stencil/core/testing';
import { newSpecPage } from '@stencil/core/testing';
import { ODS_CARD_COLOR, OdsCard } from '../../src';

describe('ods-card rendering', () => {
let page: SpecPage;
let root: HTMLElement | undefined;

async function setup(html: string): Promise<void> {
page = await newSpecPage({
components: [OdsCard],
html,
});

root = page.root;
}

describe('attributes', () => {
describe('color', () => {
it('should be reflected', async() => {
const colorValue = ODS_CARD_COLOR.neutral;

await setup(`<ods-card color="${colorValue}"></ods-card>`);

expect(root?.getAttribute('color')).toBe(colorValue);
});

it('should be set to its default value', async() => {
await setup('<ods-card></ods-card>');

expect(root?.getAttribute('color')).toBe(ODS_CARD_COLOR.primary);
});
});
});
});
7 changes: 7 additions & 0 deletions packages/ods/src/components/card/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../../tsconfig.json",
"include": [
"src",
"tests"
]
}
10 changes: 10 additions & 0 deletions packages/ods/src/components/card/typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"entryPoints": ["src/index.ts"],
"excludeInternal": true,
"excludePrivate": true,
"excludeProtected": true,
"hideGenerator": true,
"json": "dist/docs-api/typedoc.json",
"out": "dist/docs-api/",
"tsconfig":"tsconfig.json"
}
3 changes: 2 additions & 1 deletion packages/ods/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ export * from './message/src';
export * from './radio/src';
export * from './checkbox/src';
export * from './select/src';
export * from './modal/src';
export * from './modal/src';
export * from './card/src';
1 change: 1 addition & 0 deletions packages/ods/vue/tests/_app/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const componentNames = [
'checkbox',
'select',
'modal',
'card',
//--generator-anchor--
];

Expand Down
18 changes: 18 additions & 0 deletions packages/ods/vue/tests/_app/src/components/ods-card.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<template>
<OdsCard>
<OdsText preset='heading-6'>Hello, world!</OdsText>
</OdsCard>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { OdsCard, OdsText } from '@ovhcloud/ods-components/vue';
export default defineComponent({
name: 'Card',
components: {
OdsCard,
OdsText
},
});
</script>
23 changes: 23 additions & 0 deletions packages/ods/vue/tests/e2e/ods-card.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Page } from 'puppeteer';
import { goToComponentPage, setupBrowser } from '../setup';

describe('ods-card vue', () => {
const setup = setupBrowser();
let page: Page;

beforeAll(async () => {
page = setup().page;
});

beforeEach(async () => {
await goToComponentPage(page, 'ods-card');
});

it('render the component correctly', async () => {
const elem = await page.$('ods-card');
const boundingBox = await elem?.boundingBox();

expect(boundingBox?.height).toBeGreaterThan(0);
expect(boundingBox?.width).toBeGreaterThan(0);
});
});
Loading

0 comments on commit ec30d5f

Please sign in to comment.