Contribution
A comprehensive guide on contributing to EletroDS, including project structure, development workflow, and best practices.
Mercado Eletrônico and EletroDS grow even more with your initiative to contribute . Your contributions, whether through bug reports, pull requests, or feedback, are essential to continuously improve this library.
Project Structure
EletroDS is organized as a monorepo using pnpm workspaces and Turborepo for efficient package management. Here's an overview of the key directories and files:
// Main entry point for @mercadoeletronico/eds-next
// Exports all components, composables, and utilities
export * from "./components";
Package Overview
| Package | Description | Path |
|---|---|---|
| @mercadoeletronico/eds-ui | Nuxt UI wrapper layer | packages/ui/ |
| @mercadoeletronico/eds-tokens | Design tokens (colors, spacing, etc.) | packages/tokens/ |
| @mercadoeletronico/eslint-config | Shared ESLint configuration | packages/eslint-config/ |
| @mercadoeletronico/ts-config | Shared TypeScript configuration | packages/ts-config/ |
Key Directories
icon: i-lucide-package title: packages/core/src/components/ color: primary
All Vue components organized by name. Each component has its own folder with theme configuration.
icon: i-lucide-palette title: packages/tokens/src/ color: secondary
Design tokens including colors, spacing, typography, shadows, and theme definitions.
icon: i-lucide-test-tube title: packages/playwright/tests/ color: success
E2E tests using Playwright for comprehensive component testing.
icon: i-lucide-book-open title: docs/content/ color: info
Documentation written in Markdown with Nuxt Content for interactive examples.
Getting Started
Jira Board
We use Jira to manage our development tasks and track progress. All available tasks can be found on our Jira board.
Taking a Task
Browse the Jira board to find an available task
Look for tasks that are unassigned and match your skills.
Communicate with the EDS team PO before assuming the task
This ensures proper coordination and avoids duplicate work.
Assign the task to yourself
Move the task to "In Development" status.
Add a comment using the validation template
Use the template provided below to document your progress.
Validation Template
When you take a task, add the following template as a comment in the Jira task:
✨ For validation
**Component Developed:** [Component Name]
**Link:** [Link to component documentation or example]
**Description:** [Brief description of what was implemented]
**Screenshots/Video:**
[Attach screenshots or video demonstrating the component - required for visual validation]
**Testing:**
- [ ] Cypress tests written and passing
- [ ] Component tested in different scenarios
- [ ] Cross-browser testing completed (if applicable)
**Documentation:**
- [ ] Documentation created/updated following Documentation Guide
- [ ] Examples provided
- [ ] Props, events, and slots documented
Local Development
To begin local development, follow these steps:
Clone the repository
git clone <repository-url>
cd eds-next
Install dependencies
# Using yarn
pnpm i
Start development
To work on the documentation and run the development server for testing components, run:
pnpm docs:dev
This command will start both the documentation server and the development environment for testing components.
IDE Setup
We recommend using VSCode alongside the ESLint extension. You can enable auto-fix and formatting when saving your code:
{
"editor.codeActionsOnSave": {
"source.fixAll": false,
"source.fixAll.eslint": true
}
}
Linting
You can use the lint command to check for linting errors:
pnpm lint # check for linting errors
Testing
Before submitting a MR, ensure that you run the tests:
# Run unit tests
pnpm test
# Run test coverage
pnpm coverage
Writing Unit Tests with Vitest
All components should have corresponding unit tests using Vitest + Vue Test Utils. The test files must be colocated alongside the component source, following the naming convention [ComponentName].test.ts.
Location: packages/ui/app/components/commons/
Test Structure
Each test file should follow this structure:
- Imports: Import
describe,itandexpectfromvitest, along withmountfrom@vue/test-utils. - Mock Components: When needed, create mock components to isolate the behavior being tested.
- Describe blocks: Group tests logically using nested
describeblocks — the first level for the component and the second for specific features. - Assertions: Use Vitest matchers (
toBeDefined,toBe,toContain, etc.).
Example: Test File
import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import { MyComponent } from "./MyComponent";
// 1. Create mocks when needed to isolate the test
const MockChild = {
name: "MockChild",
props: {
title: String,
count: Number,
},
template: '<div class="mock-child">{{ title }} - {{ count }}</div>',
};
describe("MyComponent", () => {
// 2. Test that the component is created correctly
it("should create the component correctly", () => {
const wrapper = mount(MyComponent);
expect(wrapper).toBeDefined();
});
// 3. Test rendering with props
it("should render with props correctly", () => {
const wrapper = mount(MyComponent, {
props: {
title: "Test",
count: 42,
},
});
expect(wrapper.find(".my-component").text()).toBe("Test - 42");
});
// 4. Test that props are passed correctly to internal components
it("should pass props to internal components", () => {
const wrapper = mount(MyComponent, {
props: {
title: "Test Component",
count: 100,
},
});
const child = wrapper.findComponent(MockChild);
expect(child.props("title")).toBe("Test Component");
expect(child.props("count")).toBe(100);
});
// 5. Test slot behavior
it("should work with slots", () => {
const wrapper = mount(MyComponent, {
slots: {
default: "Slot content",
},
});
expect(wrapper.text()).toContain("Slot content");
});
// 6. Test attributes and CSS classes
it("should apply attributes and CSS classes", () => {
const wrapper = mount(MyComponent, {
props: {
customClass: "test-class",
},
});
expect(wrapper.find(".my-component").classes()).toContain("test-class");
});
});
Best Practices
- Colocation: Test files should live alongside the component source (e.g.,
MyComponent.tsandMyComponent.test.tsin the same directory). - Isolation: Use mock components to isolate the behavior being tested, avoiding external dependencies.
- Coverage: Maintain coverage above 80%. Reports are generated in
target/packages/ui/coverage/. - Automatic cleanup: The
vitest.setup.tsfile already runscleanup()from@testing-library/vueafter each test, so manual cleanup is not needed. - Environment: Tests run in a
jsdomenvironment, simulating the browser DOM.
Documentation
Documentation Standard
Our component documentation follows the same structure and conventions used by Nuxt UI, providing a consistent and familiar experience for developers. Each component page is a markdown file located in docs/content/2.components/ and uses Nuxt Content with custom components like ::code-preview for interactive examples.
Creating Component Documentation
When creating or updating component documentation:
Create the markdown file
Add your documentation file in docs/content/2.components/ following the naming convention {order}.{component-name}.md (e.g., 2.button.md).
Add the frontmatter
Every component page must start with a YAML frontmatter block:
---
title: ComponentName
description: A brief description of the component and its purpose.
navigation:
icon: i-lucide-icon-name
---
Follow the required section structure
The documentation must include the sections described below in order.
Documentation Structure
Component documentation must follow this structure, in order:
| Section | Description |
|---|---|
| Introduction | A brief description of the component right after the frontmatter. |
| Usage | Basic usage with the default slot or main prop. Shows how to get started with the component. |
| Prop sections | One ## Section per major prop (e.g., Color, Variant, Size, Icon, etc.), each with a ::code-preview block showing a live preview and the corresponding code. |
| API | Technical reference with tables, divided into Props, Slots, and Emits (see API Section Format below). |
| Examples | Advanced or composite usage patterns (e.g., Button Group, Form Submit). |
Using ::code-preview
All visual examples must use the ::code-preview component, which renders a live preview alongside the source code. The structure is:
::code-preview
:me-component-name{prop="value" label="Example"}
#code
\```vue
<template>
<MeComponentName prop="value">Example</MeComponentName>
</template>
\```
::
For examples with multiple items, wrap them in a ::div:
::code-preview
::div{class="flex flex-wrap gap-2"}
:me-component-name{variant="solid" label="Solid"}
:me-component-name{variant="outline" label="Outline"}
::
#code
\```vue
<template>
<div class="flex flex-wrap gap-2">
<MeComponentName variant="solid">Solid</MeComponentName>
<MeComponentName variant="outline">Outline</MeComponentName>
</div>
</template>
\```
::
API Section Format
The API section must contain up to three subsections with tables, following the same column order as Nuxt UI:
Props
| Prop | Default | Type |
|---|---|---|
label | - | string Text content for the component. |
color | 'primary' | 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'error' | 'neutral' Component color. |
disabled | false | boolean Whether the component is disabled. |
Slots
| Slot | Type |
|---|---|
default | { label: string } |
leading | {} |
trailing | {} |
Emits
| Event | Type |
|---|---|
click | [payload: MouseEvent] |
update:modelValue | [value: string] |
Validation Criteria
Before submitting your work for validation, ensure you meet all the following criteria:
Component Development
icon: i-lucide-check-circle title: Fully Functional color: success
Component is fully functional and works as expected.
icon: i-lucide-palette title: Design Guidelines color: info
Component follows the design system guidelines.
icon: i-lucide-smartphone title: Responsive & Accessible color: primary
Component is responsive and accessible to all users.
icon: i-lucide-shield-check title: Edge Cases color: warning
Component handles edge cases and error states properly.
Testing Checklist
- Cypress tests are written and passing
- Component is tested in different scenarios
- Tests cover main functionality and edge cases
- Cross-browser testing completed (if applicable)
Documentation Checklist
- Documentation created/updated following the Documentation Guide
- Examples provided and working
- Props, events, and slots are fully documented
- Documentation is clear and easy to understand
Code Quality Checklist
- Code follows project conventions
- ESLint passes without errors
- No console errors or warnings
- Code is properly commented where necessary
Submitting Changes
Commit Conventions
We use Jira commit format for commit messages. All commits must include the Jira task code and time tracking.
Commit Format:
MW-XXXXX #time Xd - commit message
Where:
MW-XXXXXis the Jira task code#time Xdis the time spent (e.g.,2dfor 2 days,4hfor 4 hours)commit messageis a brief description of the changes
Examples:
MW-67130 #time 2d - add new Button component variant
MW-67131 #time 4h - resolve modal closing issue
MW-67132 #time 1d - update Button component documentation
MW-67133 #time 1h - update dependencies
Branch Naming Conventions
Branches must follow the naming pattern based on the type of change:
| Branch Type | Pattern | Description | Create From |
|---|---|---|---|
| Feature | feature/MW-XXXXX | New features or enhancements | develop |
| Fix | fix/MW-XXXXX | Bug fixes | develop |
| Hotfix | hotfix/MW-XXXXX | Urgent production fixes | master |
| Hotfeature | hotfeature/MW-XXXXX | Urgent feature implementations | master |
Making a Merge Request
Update Jira Task
Before creating a MR, update the Jira task with the validation template comment.
Create Branch
Create a branch following the naming conventions:
- For
featureandfixbranches: create fromdevelop(e.g.,feature/MW-67130,fix/MW-67131) - For
hotfeatureandhotfixbranches: create frommaster(e.g.,hotfeature/MW-67133,hotfix/MW-67132)
Make Changes
Implement your changes following the guidelines above.
Test
Ensure all tests pass and linting is clean.
Document
Update documentation if needed.
Commit
Use Jira commit format (e.g., MW-67130 #time 2d - commit message).
Push and Create MR
Push your branch and create a Merge Request. Link the MR to the Jira task.
MR Requirements
Squash and Merge when merging.- Follow along the instructions provided when creating a MR
- Ensure your MR's title includes the Jira task code and follows the commit format (e.g.,
MW-67130 #time 2d - description) - Ensure
lintandtestswork before submitting the MR - Avoid making unrelated changes
- Include screenshots or videos if the changes are visual
We'll review it promptly. If assigned to a maintainer, they'll review it carefully.