@ippon-ui/ui 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/agents/component-library-create-from-pattern-library.agent.md +37 -0
- package/.agents/agents/patten-library-create-component.agent.md +30 -0
- package/.agents/skills/component-library/SKILL.md +169 -0
- package/.agents/skills/pattern-library/SKILL.md +277 -0
- package/.github/workflows/build.yml +34 -0
- package/.gitlab-ci.yml +12 -0
- package/.prettierignore +6 -0
- package/AGENTS.md +50 -0
- package/LICENSE +202 -0
- package/ci/build.yml +15 -0
- package/ci/common.yml +42 -0
- package/ci/deploy.yml +20 -0
- package/icons/LICENCE +202 -0
- package/icons/index.ts +69 -0
- package/icons/package.json +25 -0
- package/icons/tsconfig.json +11 -0
- package/lefthook.yml +10 -0
- package/mise.toml +55 -0
- package/package.json +26 -0
- package/pnpm-workspace.yaml +9 -0
- package/prettier.config.mts +8 -0
- package/react/LICENCE +202 -0
- package/react/README.md +75 -0
- package/react/eslint.config.js +22 -0
- package/react/package.json +63 -0
- package/react/src/CAP.ts +14 -0
- package/react/src/Card.ts +2 -0
- package/react/src/DataSelectable.ts +7 -0
- package/react/src/Grid.ts +33 -0
- package/react/src/IpponBadge.tsx +62 -0
- package/react/src/IpponButton.tsx +93 -0
- package/react/src/IpponButtonCard.tsx +34 -0
- package/react/src/IpponCard.tsx +30 -0
- package/react/src/IpponContainer.tsx +15 -0
- package/react/src/IpponGrid.tsx +56 -0
- package/react/src/IpponHSpace.tsx +56 -0
- package/react/src/IpponIcon.tsx +15 -0
- package/react/src/IpponImportFile.tsx +128 -0
- package/react/src/IpponIon.tsx +45 -0
- package/react/src/IpponMeter.tsx +43 -0
- package/react/src/IpponProgress.tsx +45 -0
- package/react/src/IpponText.tsx +56 -0
- package/react/src/IpponTitle.tsx +45 -0
- package/react/src/IpponVSpace.tsx +43 -0
- package/react/src/Optional.ts +177 -0
- package/react/src/Tokens.ts +36 -0
- package/react/src/index.ts +16 -0
- package/react/test/File.fixture.ts +13 -0
- package/react/test/IpponBadge.spec.tsx +245 -0
- package/react/test/IpponButton.spec.tsx +666 -0
- package/react/test/IpponButtonCard.spec.tsx +162 -0
- package/react/test/IpponCard.spec.tsx +133 -0
- package/react/test/IpponContainer.spec.tsx +56 -0
- package/react/test/IpponGrid.spec.tsx +140 -0
- package/react/test/IpponHSpace.spec.tsx +107 -0
- package/react/test/IpponIcon.spec.tsx +37 -0
- package/react/test/IpponImportFile.spec.tsx +431 -0
- package/react/test/IpponIon.spec.tsx +52 -0
- package/react/test/IpponMeter.spec.tsx +59 -0
- package/react/test/IpponProgress.spec.tsx +68 -0
- package/react/test/IpponText.spec.tsx +149 -0
- package/react/test/IpponTitle.spec.tsx +242 -0
- package/react/test/IpponVSpace.spec.tsx +91 -0
- package/react/tsconfig.app.json +24 -0
- package/react/tsconfig.json +4 -0
- package/react/tsconfig.node.json +23 -0
- package/react/vite.config.ts +30 -0
- package/react/vitest.config.ts +21 -0
- package/styles/.editorconfig +12 -0
- package/styles/.stylelintrc.json +75 -0
- package/styles/LICENCE +202 -0
- package/styles/README.md +107 -0
- package/styles/logo.svg +26 -0
- package/styles/package.json +67 -0
- package/styles/src/atom/_atom.scss +9 -0
- package/styles/src/atom/atom.pug +34 -0
- package/styles/src/atom/badge/_badge.scss +108 -0
- package/styles/src/atom/badge/badge.code.pug +29 -0
- package/styles/src/atom/badge/badge.md +1 -0
- package/styles/src/atom/badge/badge.mixin.pug +24 -0
- package/styles/src/atom/badge/badge.render.pug +7 -0
- package/styles/src/atom/button/_button.scss +242 -0
- package/styles/src/atom/button/button.code.pug +38 -0
- package/styles/src/atom/button/button.md +31 -0
- package/styles/src/atom/button/button.mixin.pug +30 -0
- package/styles/src/atom/button/button.render.pug +13 -0
- package/styles/src/atom/icon/_icon.scss +8 -0
- package/styles/src/atom/icon/icon.code.pug +5 -0
- package/styles/src/atom/icon/icon.md +11 -0
- package/styles/src/atom/icon/icon.mixin.pug +8 -0
- package/styles/src/atom/icon/icon.render.pug +7 -0
- package/styles/src/atom/ion/ion.code.pug +8 -0
- package/styles/src/atom/ion/ion.md +11 -0
- package/styles/src/atom/ion/ion.mixin.pug +8 -0
- package/styles/src/atom/ion/ion.render.pug +7 -0
- package/styles/src/atom/meter/_meter.scss +23 -0
- package/styles/src/atom/meter/meter.code.pug +8 -0
- package/styles/src/atom/meter/meter.md +7 -0
- package/styles/src/atom/meter/meter.mixin.pug +12 -0
- package/styles/src/atom/meter/meter.render.pug +5 -0
- package/styles/src/atom/progress/_progress.scss +23 -0
- package/styles/src/atom/progress/progress.code.pug +8 -0
- package/styles/src/atom/progress/progress.md +7 -0
- package/styles/src/atom/progress/progress.mixin.pug +14 -0
- package/styles/src/atom/progress/progress.render.pug +5 -0
- package/styles/src/atom/tab/_tab.scss +48 -0
- package/styles/src/atom/tab/tab.code.pug +5 -0
- package/styles/src/atom/tab/tab.md +1 -0
- package/styles/src/atom/tab/tab.mixin.pug +14 -0
- package/styles/src/atom/tab/tab.render.pug +4 -0
- package/styles/src/atom/text/_text.scss +74 -0
- package/styles/src/atom/text/text.code.pug +19 -0
- package/styles/src/atom/text/text.md +5 -0
- package/styles/src/atom/text/text.mixin.pug +12 -0
- package/styles/src/atom/text/text.render.pug +7 -0
- package/styles/src/atom/title/_title.scss +68 -0
- package/styles/src/atom/title/title.code.pug +25 -0
- package/styles/src/atom/title/title.md +9 -0
- package/styles/src/atom/title/title.mixin.pug +12 -0
- package/styles/src/atom/title/title.render.pug +5 -0
- package/styles/src/atom/title-display/_title-display.scss +26 -0
- package/styles/src/atom/title-display/title-display.code.pug +9 -0
- package/styles/src/atom/title-display/title-display.md +5 -0
- package/styles/src/atom/title-display/title-display.mixin.pug +6 -0
- package/styles/src/atom/title-display/title-display.render.pug +4 -0
- package/styles/src/doc.scss +2 -0
- package/styles/src/favicon.ico +0 -0
- package/styles/src/function/_conversion.scss +9 -0
- package/styles/src/index.pug +59 -0
- package/styles/src/layout-documentation.pug +14 -0
- package/styles/src/layout.pug +17 -0
- package/styles/src/molecule/_molecule.scss +2 -0
- package/styles/src/molecule/import-file/_import-file.scss +38 -0
- package/styles/src/molecule/import-file/import-file.code.pug +4 -0
- package/styles/src/molecule/import-file/import-file.md +1 -0
- package/styles/src/molecule/import-file/import-file.mixin.pug +15 -0
- package/styles/src/molecule/import-file/import-file.render.pug +5 -0
- package/styles/src/molecule/molecule.pug +20 -0
- package/styles/src/molecule/tabs/_tabs.scss +4 -0
- package/styles/src/molecule/tabs/tabs.code.pug +9 -0
- package/styles/src/molecule/tabs/tabs.md +1 -0
- package/styles/src/molecule/tabs/tabs.mixin.pug +4 -0
- package/styles/src/molecule/tabs/tabs.render.pug +4 -0
- package/styles/src/molecule/toggle/_toggle.scss +68 -0
- package/styles/src/molecule/toggle/toggle.code.pug +26 -0
- package/styles/src/molecule/toggle/toggle.md +1 -0
- package/styles/src/molecule/toggle/toggle.mixin.pug +36 -0
- package/styles/src/molecule/toggle/toggle.render.pug +5 -0
- package/styles/src/organism/_abstract-card.scss +36 -0
- package/styles/src/organism/_docorganism.scss +1 -0
- package/styles/src/organism/_organism.scss +8 -0
- package/styles/src/organism/button-card/_button-card.scss +22 -0
- package/styles/src/organism/button-card/button-card.code.pug +31 -0
- package/styles/src/organism/button-card/button-card.md +28 -0
- package/styles/src/organism/button-card/button-card.mixin.pug +8 -0
- package/styles/src/organism/button-card/button-card.render.pug +7 -0
- package/styles/src/organism/card/_card.scss +6 -0
- package/styles/src/organism/card/card.code.pug +9 -0
- package/styles/src/organism/card/card.md +23 -0
- package/styles/src/organism/card/card.mixin.pug +7 -0
- package/styles/src/organism/card/card.render.pug +7 -0
- package/styles/src/organism/container/_container.scss +3 -0
- package/styles/src/organism/container/container.code.pug +13 -0
- package/styles/src/organism/container/container.md +5 -0
- package/styles/src/organism/container/container.mixin.pug +3 -0
- package/styles/src/organism/container/container.render.pug +4 -0
- package/styles/src/organism/grid/_docgrid.scss +11 -0
- package/styles/src/organism/grid/_grid.scss +84 -0
- package/styles/src/organism/grid/grid.code.pug +25 -0
- package/styles/src/organism/grid/grid.md +1 -0
- package/styles/src/organism/grid/grid.mixin.pug +7 -0
- package/styles/src/organism/grid/grid.render.pug +5 -0
- package/styles/src/organism/h-space/_h-space.scss +49 -0
- package/styles/src/organism/h-space/h-space.code.pug +56 -0
- package/styles/src/organism/h-space/h-space.md +22 -0
- package/styles/src/organism/h-space/h-space.mixin.pug +14 -0
- package/styles/src/organism/h-space/h-space.render.pug +5 -0
- package/styles/src/organism/header/_header.scss +8 -0
- package/styles/src/organism/header/header.code.pug +14 -0
- package/styles/src/organism/header/header.md +1 -0
- package/styles/src/organism/header/header.mixin.pug +7 -0
- package/styles/src/organism/header/header.render.pug +4 -0
- package/styles/src/organism/modal/_modal.scss +58 -0
- package/styles/src/organism/modal/modal.code.pug +68 -0
- package/styles/src/organism/modal/modal.md +1 -0
- package/styles/src/organism/modal/modal.mixin.pug +25 -0
- package/styles/src/organism/modal/modal.render.pug +4 -0
- package/styles/src/organism/organism.pug +30 -0
- package/styles/src/organism/v-space/_v-space.scss +45 -0
- package/styles/src/organism/v-space/v-space.code.pug +41 -0
- package/styles/src/organism/v-space/v-space.md +20 -0
- package/styles/src/organism/v-space/v-space.mixin.pug +7 -0
- package/styles/src/organism/v-space/v-space.render.pug +5 -0
- package/styles/src/quark/_breakpoint.scss +12 -0
- package/styles/src/quark/_font.scss +38 -0
- package/styles/src/quark/_gap.scss +34 -0
- package/styles/src/quark/_placeholder.scss +27 -0
- package/styles/src/quark/_shadow.scss +13 -0
- package/styles/src/quark/_typography.scss +146 -0
- package/styles/src/template/_template.scss +1 -0
- package/styles/src/template/layout/_layout.scss +20 -0
- package/styles/src/template/layout/layout.code.pug +11 -0
- package/styles/src/template/layout/layout.md +1 -0
- package/styles/src/template/layout/layout.mixin.pug +11 -0
- package/styles/src/template/layout/layout.render.pug +4 -0
- package/styles/src/template/template.pug +16 -0
- package/styles/src/tikui.scss +5 -0
- package/styles/src/token/_doctable.scss +14 -0
- package/styles/src/token/_doctoken.scss +1 -0
- package/styles/src/token/_size.scss +9 -0
- package/styles/src/token/_token.scss +5 -0
- package/styles/src/token/color/_color.scss +9 -0
- package/styles/src/token/color/color/_base.scss +65 -0
- package/styles/src/token/color/color/_brand.scss +13 -0
- package/styles/src/token/color/color/_error.scss +13 -0
- package/styles/src/token/color/color/_information-2.scss +13 -0
- package/styles/src/token/color/color/_information.scss +13 -0
- package/styles/src/token/color/color/_neutral.scss +20 -0
- package/styles/src/token/color/color/_semantic.scss +69 -0
- package/styles/src/token/color/color/_success.scss +13 -0
- package/styles/src/token/color/color/_warning.scss +13 -0
- package/styles/src/token/color/color.js +31 -0
- package/styles/src/token/color/color.mixin.pug +19 -0
- package/styles/src/token/color/color.pug +9 -0
- package/styles/src/token/color/color.render.pug +13 -0
- package/styles/src/token/radius/_radius.scss +8 -0
- package/styles/src/token/radius/radius.js +54 -0
- package/styles/src/token/radius/radius.mixin.pug +14 -0
- package/styles/src/token/radius/radius.pug +9 -0
- package/styles/src/token/radius/radius.render.pug +11 -0
- package/styles/src/token/shadow/_shadow.scss +22 -0
- package/styles/src/token/shadow/shadow.js +45 -0
- package/styles/src/token/shadow/shadow.mixin.pug +13 -0
- package/styles/src/token/shadow/shadow.pug +9 -0
- package/styles/src/token/shadow/shadow.render.pug +9 -0
- package/styles/src/token/token.js +38 -0
- package/styles/src/token/token.pug +25 -0
- package/styles/src/token/typography/_typography.scss +103 -0
- package/styles/src/token/typography/typography.js +32 -0
- package/styles/src/token/typography/typography.mixin.pug +17 -0
- package/styles/src/token/typography/typography.pug +9 -0
- package/styles/src/token/typography/typography.render.pug +19 -0
- package/styles/test/function/conversion.test.scss +20 -0
- package/styles/test/function/sass.spec.ts +6 -0
- package/styles/tikuiconfig.json +14 -0
- package/styles/tsconfig.json +10 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: component-library-create-from-pattern-library
|
|
3
|
+
description: Create a component in the Component Library based on a component from the Pattern Library
|
|
4
|
+
skills:
|
|
5
|
+
- component-library
|
|
6
|
+
- pattern-library
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Task
|
|
10
|
+
|
|
11
|
+
As input, you are given the component name to create in the Component Library (based on an existing Pattern Library component).
|
|
12
|
+
|
|
13
|
+
## Steps
|
|
14
|
+
|
|
15
|
+
1. Check if a component already exists in `react/src/` that covers this need by searching for existing `Ippon<ComponentName>` components
|
|
16
|
+
|
|
17
|
+
2. Read the Pattern Library component documentation from the node module `@ippon-ui/styles` located in `node_modules/@ippon-ui/styles/dist`:
|
|
18
|
+
- Locate `src/<level>/<component-name>/<component-name>.mixin.pug` (where `<level>` is atom, molecule, organism, or template)
|
|
19
|
+
- Understand the HTML structure, alternatives (CAP `-variant`), and parts (CAP `--part`)
|
|
20
|
+
- Read `<component-name>.md` for component details
|
|
21
|
+
|
|
22
|
+
3. Write unit tests in `react/test/Ippon<ComponentName>.spec.tsx`:
|
|
23
|
+
- Create tests for all expected props: variants, colors, sizes
|
|
24
|
+
- Include tests for children rendering and `dataSelector` binding
|
|
25
|
+
- Follow the test structure from Component Library "Unit Tests" section
|
|
26
|
+
- Run `cd app && pnpm test:unit` to verify tests are red before implementing
|
|
27
|
+
|
|
28
|
+
4. Implement the React component in `react/src/Ippon<ComponentName>.tsx`:
|
|
29
|
+
- Follow the structure and conventions from Component Library "Creating a Component" section
|
|
30
|
+
- Type props using `DataSelectable` or `DataSelectableWithChildren`
|
|
31
|
+
- Build CSS classes using `clsx` and helpers from `CAP.ts`
|
|
32
|
+
- Create sub-components for any parts (CAP `--part`)
|
|
33
|
+
- Run tests with `cd app && pnpm test:unit` until all tests pass
|
|
34
|
+
|
|
35
|
+
5. Export the component from `react/src/index.ts`:
|
|
36
|
+
- Add `export { IpponComponent } from './IpponComponent.tsx';`
|
|
37
|
+
- If applicable, also export any sub-components or parts
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pattern-library-create-component
|
|
3
|
+
description: Create a component on the Pattern Library
|
|
4
|
+
skills:
|
|
5
|
+
- pattern-library
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Task
|
|
9
|
+
|
|
10
|
+
As input, you are given the level and name of the component to create.
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
1. Review the instructions in `.github/instructions/pattern-library.instructions.md` to understand:
|
|
15
|
+
- The Atomic Design principles (atoms, molecules, organisms, templates)
|
|
16
|
+
- The Tikui component architecture
|
|
17
|
+
- The CAP (Component Alternative Part) naming convention
|
|
18
|
+
- Token and Quark concepts
|
|
19
|
+
|
|
20
|
+
2. Generate the component using the tikui command with the proper format:
|
|
21
|
+
|
|
22
|
+
```shell
|
|
23
|
+
mise styles-create-component <component> --path <path>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Where:
|
|
27
|
+
- `<component>` is the component name in `kebab-case`
|
|
28
|
+
- `<path>` where default is 'atom' to create inside `src/atom`
|
|
29
|
+
|
|
30
|
+
3. Ensure the generated component follows the CAP convention for alternatives and parts
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 'component-library'
|
|
3
|
+
description: 'Component Library with React components used by the application.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Component Library
|
|
7
|
+
|
|
8
|
+
Component Library is a part of react folder, you can find it in the `react/src` folder.
|
|
9
|
+
|
|
10
|
+
It's a bounded context dedicated to React Components.
|
|
11
|
+
|
|
12
|
+
## Concept
|
|
13
|
+
|
|
14
|
+
The Component Library concept is not especially linked to a technology. The idea is to represent the mechanical part of each component.
|
|
15
|
+
|
|
16
|
+
It therefore provides React components that will be consumed by another bounded context.
|
|
17
|
+
|
|
18
|
+
## Integration with Pattern Library
|
|
19
|
+
|
|
20
|
+
The Component Library consume the Pattern Library, it uses the provided documentation to know classes and structure to use for each component. The CSS is linked using a `link` tag in the `index.html` file of the React application.
|
|
21
|
+
|
|
22
|
+
When implementing a component in the Component Library:
|
|
23
|
+
|
|
24
|
+
1. Refer to the Pattern Library documentation for the correct CSS classes and structure
|
|
25
|
+
2. Follow the CAP (Component Alternative Part) naming convention for variants and parts
|
|
26
|
+
3. Use the semantic colors and tokens defined in the Pattern Library
|
|
27
|
+
4. Ensure visual consistency by adhering to the Atomic Design hierarchy (atoms, molecules, organisms)
|
|
28
|
+
|
|
29
|
+
## Creating a Component
|
|
30
|
+
|
|
31
|
+
### File Organization
|
|
32
|
+
|
|
33
|
+
Each component is defined by:
|
|
34
|
+
|
|
35
|
+
- **Component file**: `react/src/Ippon<ComponentName>.tsx` (PascalCase)
|
|
36
|
+
- **Test file**: `react/test/Ippon<ComponentName>.spec.tsx`
|
|
37
|
+
- **Export**: added to `react/src/index.ts`
|
|
38
|
+
|
|
39
|
+
### React Component Structure
|
|
40
|
+
|
|
41
|
+
A component file follows this structure:
|
|
42
|
+
|
|
43
|
+
```typescriptreact
|
|
44
|
+
import type { DataSelectableWithChildren } from './DataSelectable.ts';
|
|
45
|
+
import { clsx } from 'clsx';
|
|
46
|
+
import { optionalToAlternativeClass } from './CAP.ts';
|
|
47
|
+
|
|
48
|
+
type IpponComponentProps = DataSelectableWithChildren<{
|
|
49
|
+
variant?: 'primary' | 'secondary';
|
|
50
|
+
color?: IpponTokenTextColor;
|
|
51
|
+
}>;
|
|
52
|
+
|
|
53
|
+
export const IpponComponent = (props: IpponComponentProps) => (
|
|
54
|
+
<div
|
|
55
|
+
className={clsx(
|
|
56
|
+
'ippon-component',
|
|
57
|
+
optionalToAlternativeClass(props.variant),
|
|
58
|
+
optionalToAlternativeClass(props.color),
|
|
59
|
+
)}
|
|
60
|
+
data-selector={props.dataSelector}
|
|
61
|
+
>
|
|
62
|
+
{props.children}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Key Conventions
|
|
68
|
+
|
|
69
|
+
#### Props Typing
|
|
70
|
+
|
|
71
|
+
- Extend `DataSelectable<T>` for components without children
|
|
72
|
+
- Extend `DataSelectableWithChildren<T>` for components with children
|
|
73
|
+
- Always include `dataSelector?: string` (via `DataSelectable`)
|
|
74
|
+
- Use types from `Tokens.ts` for colors and sizes (e.g., `IpponTokenTextColor`, `IpponTokenSize`)
|
|
75
|
+
- Model alternatives (CAP `-variant`) as union types
|
|
76
|
+
- Model booleans like `border` or `placeholder` as optional props
|
|
77
|
+
|
|
78
|
+
#### CSS Class Building
|
|
79
|
+
|
|
80
|
+
- Use `clsx()` from the `clsx` library to conditionally build class names
|
|
81
|
+
- Import helpers from `CAP.ts`:
|
|
82
|
+
- `optionalToAlternativeClass(value)` → converts `'primary'` to `'-primary'`
|
|
83
|
+
- `optionalToPrefixedAlternativeClass(prefix)(value)` → converts `'l1'` with prefix `'shadow'` to `'-shadow-l1'`
|
|
84
|
+
- `toAlternativeClass(value)` → always converts to alternative class (non-optional)
|
|
85
|
+
|
|
86
|
+
#### Parts and Sub-components
|
|
87
|
+
|
|
88
|
+
If the Pattern Library component has parts (CSS classes like `ippon-component--part`):
|
|
89
|
+
|
|
90
|
+
- Create a dedicated sub-component `IpponComponentPart` for parts with significant props
|
|
91
|
+
- Export both the main component and the part(s) from the same file
|
|
92
|
+
- Use `clsx('ippon-component--part', ...)` for part class names
|
|
93
|
+
|
|
94
|
+
Example with slots:
|
|
95
|
+
|
|
96
|
+
```typescriptreact
|
|
97
|
+
export const IpponVSpaceSlot = (props: IpponVSpaceSlotProps) => (
|
|
98
|
+
<div
|
|
99
|
+
className={clsx('ippon-v-space--slot', optionalToAlternativeClass(props.align))}
|
|
100
|
+
data-selector={props.dataSelector}
|
|
101
|
+
>
|
|
102
|
+
{props.children}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### Exporting Components
|
|
108
|
+
|
|
109
|
+
Add each new component to `react/src/index.ts`:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
export { IpponComponent } from './IpponComponent.tsx';
|
|
113
|
+
export { IpponComponentPart } from './IpponComponent.tsx'; // if applicable
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Unit Tests
|
|
117
|
+
|
|
118
|
+
Tests are located in `react/test/` and use Vitest + Testing Library.
|
|
119
|
+
|
|
120
|
+
#### Running Tests
|
|
121
|
+
|
|
122
|
+
```shell
|
|
123
|
+
cd react
|
|
124
|
+
|
|
125
|
+
pnpm test:unit:ci
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### Test Structure
|
|
129
|
+
|
|
130
|
+
Each component test should:
|
|
131
|
+
|
|
132
|
+
1. Verify the component renders with the correct base class name
|
|
133
|
+
2. Test each prop variant (alternatives, colors, sizes)
|
|
134
|
+
3. Test children rendering
|
|
135
|
+
4. Test `dataSelector` binding
|
|
136
|
+
5. Test custom HTML tags if applicable (via `tag` prop)
|
|
137
|
+
|
|
138
|
+
Example test:
|
|
139
|
+
|
|
140
|
+
```typescriptreact
|
|
141
|
+
import { describe, it, expect, afterEach } from 'vitest';
|
|
142
|
+
import { render, screen, configure, cleanup } from '@testing-library/react';
|
|
143
|
+
import '@testing-library/jest-dom/vitest';
|
|
144
|
+
import { IpponComponent } from '../src';
|
|
145
|
+
|
|
146
|
+
configure({
|
|
147
|
+
testIdAttribute: 'data-selector',
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('IpponComponent', () => {
|
|
151
|
+
afterEach(cleanup);
|
|
152
|
+
|
|
153
|
+
it('should be like pattern library', () => {
|
|
154
|
+
render(<IpponComponent dataSelector="ippon-component">Content</IpponComponent>);
|
|
155
|
+
|
|
156
|
+
const component = screen.getByTestId('ippon-component');
|
|
157
|
+
|
|
158
|
+
expect(component).toHaveClass('ippon-component');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it.each(['primary', 'secondary'] as const)('should have variant %s', (variant) => {
|
|
162
|
+
render(<IpponComponent variant={variant} dataSelector="ippon-component" />);
|
|
163
|
+
|
|
164
|
+
const component = screen.getByTestId('ippon-component');
|
|
165
|
+
|
|
166
|
+
expect(component).toHaveClass(`-${variant}`);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
```
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 'pattern-library'
|
|
3
|
+
description: 'Pattern Libreary which allows representing graphical components. Provides CSS and uses HTML as a template language. This is where tokens, quarks, atoms, molecules, organisms, templates are defined.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Pattern Library
|
|
7
|
+
|
|
8
|
+
The Pattern Library allows representing graphical elements.
|
|
9
|
+
|
|
10
|
+
The Pattern Library concept is not especially linked to a technology. The idea is to represent the visual part of each component, the states but not the mechanical part.
|
|
11
|
+
|
|
12
|
+
In the project, the Pattern Library applies to the web.
|
|
13
|
+
|
|
14
|
+
It therefore provides:
|
|
15
|
+
|
|
16
|
+
- CSS that will be consumed by another application
|
|
17
|
+
- Documentation for each component with:
|
|
18
|
+
- A description of the component
|
|
19
|
+
- A rendering of the component
|
|
20
|
+
- The source code of the component (HTML and pug)
|
|
21
|
+
|
|
22
|
+
So it's possible to consume the Pattern Library in any web application, regardless of the technology used (React, Vue, Angular, etc…).
|
|
23
|
+
|
|
24
|
+
It is organized following Atomic Design.
|
|
25
|
+
|
|
26
|
+
[Tikui](https://tikui.org/) is used to generate the documentation of the Pattern Library.
|
|
27
|
+
|
|
28
|
+
## Component
|
|
29
|
+
|
|
30
|
+
A component in Tikui is defined according to the following architecture:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
<component>/
|
|
34
|
+
<component>.mixin.pug
|
|
35
|
+
<component>.code.pug
|
|
36
|
+
<component>.render.pug
|
|
37
|
+
_<component>.scss
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The command to generate a component is as follows:
|
|
41
|
+
|
|
42
|
+
```shell
|
|
43
|
+
mise styles-create-component <component> --path <path>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- `<component>` is the name of the component, in `kebab-case`
|
|
47
|
+
- `<path>` is the path to the folder where the component will be created, default is `atom` to create inside `src/atom`
|
|
48
|
+
- The prefix is `ippon` using `mise`
|
|
49
|
+
|
|
50
|
+
To generate the `Button` atom with the `ippon` prefix:
|
|
51
|
+
|
|
52
|
+
```shell
|
|
53
|
+
mise styles-create-component button --path atom
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- ippon is used as the prefix
|
|
57
|
+
- button is the name of the component
|
|
58
|
+
- src/atom is the path to the folder where the component (atom) will be created
|
|
59
|
+
|
|
60
|
+
## Atomic Design
|
|
61
|
+
|
|
62
|
+
Atomic Design is proposed by Brad Frost. The idea is to hierarchically compose graphical components into five levels:
|
|
63
|
+
|
|
64
|
+
- Atoms: indivisible elements such as a button, form field, or icon
|
|
65
|
+
- Molecules: groups of atoms to compose to form small components
|
|
66
|
+
- Organisms: groups of molecules to assemble to form more complex elements
|
|
67
|
+
- Templates: groups of organisms, molecules, or atoms to assemble to form pages
|
|
68
|
+
- Pages: instances of templates with real content (it is the applications consuming the Pattern Library that will create the pages)
|
|
69
|
+
|
|
70
|
+
In Tikui, these concepts are represented by folders:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
src/
|
|
74
|
+
atom/
|
|
75
|
+
atom.pug
|
|
76
|
+
_atom.scss
|
|
77
|
+
molecule/
|
|
78
|
+
molecules.pug
|
|
79
|
+
_molecule.scss
|
|
80
|
+
organism/
|
|
81
|
+
organism.pug
|
|
82
|
+
_organism.scss
|
|
83
|
+
template/
|
|
84
|
+
template.pug
|
|
85
|
+
_template.scss
|
|
86
|
+
index.pug
|
|
87
|
+
tikui.scss
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## CAP
|
|
91
|
+
|
|
92
|
+
A component follows CAP (Component Alternative Part):
|
|
93
|
+
|
|
94
|
+
- Component: the name of the component in `kebab-case`
|
|
95
|
+
- Alternative: an alternative of the component or a part that starts with a `-`, followed by the name of the alternative in `kebab-case`
|
|
96
|
+
- Part: a part of the component or an alternative that starts with `--`, followed by the name of the part in `kebab-case`
|
|
97
|
+
|
|
98
|
+
An example with a button:
|
|
99
|
+
|
|
100
|
+
In SCSS:
|
|
101
|
+
|
|
102
|
+
```scss
|
|
103
|
+
.ippon-button {
|
|
104
|
+
// button styles
|
|
105
|
+
|
|
106
|
+
&.-primary {
|
|
107
|
+
// primary alternative styles
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
&.-secondary {
|
|
111
|
+
// secondary alternative styles
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&--icon {
|
|
115
|
+
// icon part styles
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&--text {
|
|
119
|
+
// text part styles
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
In HTML:
|
|
125
|
+
|
|
126
|
+
```html
|
|
127
|
+
<button class="ippon-button -primary">
|
|
128
|
+
<span class="ippon-button--icon">Icon</span>
|
|
129
|
+
<span class="ippon-button--text">Text</span>
|
|
130
|
+
</button>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Tikui
|
|
134
|
+
|
|
135
|
+
To document with Tikui, simply include the component's Markdown file in the file where you want to document it.
|
|
136
|
+
|
|
137
|
+
You will use:
|
|
138
|
+
|
|
139
|
+
- `componentDoc` for atoms, molecules, and organisms
|
|
140
|
+
- A size can be specified for the component rendering with the `height` option (example: `height=300`)
|
|
141
|
+
- `templateDoc` for templates
|
|
142
|
+
- There is no size since the rendering area represents a button to go to the rendering
|
|
143
|
+
|
|
144
|
+
For a `Button` atom:
|
|
145
|
+
|
|
146
|
+
```pug
|
|
147
|
+
include:componentDoc(height=300) button/button.md
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
For a `Layout` template:
|
|
151
|
+
|
|
152
|
+
```pug
|
|
153
|
+
include:templateDoc layout/layout.md
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Token
|
|
157
|
+
|
|
158
|
+
A token is a style property. This can be a color, a font, a spacing, etc… It's a concept, so, even if it's possible to use variables to represent tokens, it's important to not confuse tokens and variables.
|
|
159
|
+
|
|
160
|
+
In the Patten Library, tokens are defined inside the `tokens` folder:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
src/
|
|
164
|
+
token/
|
|
165
|
+
_token.scss
|
|
166
|
+
token.pug
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Color
|
|
170
|
+
|
|
171
|
+
A color token can be directly the color with a quantity represented by a number from 0 to 999.
|
|
172
|
+
|
|
173
|
+
For the color `green`, it can be represented by the following tokens:
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
--ippon-color-green-100, --ippon-color-green-200, --ippon-color-green-300, --ippon-color-green-400, --ippon-color-green-500, --ippon-color-green-600, --ippon-color-green-700, --ippon-color-green-800, --ippon-color-green-900
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
But it stills a base color, the base color itself can't be used directly for a component, it must be used by a semantic color.
|
|
180
|
+
|
|
181
|
+
#### Semantic color
|
|
182
|
+
|
|
183
|
+
A semantic color is a color token that represents a meaning. For example, the `positive` semantic color use the `green` base color. The `semantic` color has also a quantity.
|
|
184
|
+
|
|
185
|
+
Here is an example for the `positive` semantic color:
|
|
186
|
+
|
|
187
|
+
```scss
|
|
188
|
+
:root {
|
|
189
|
+
--ippon-color-positive-100: var(--ippon-color-green-100);
|
|
190
|
+
--ippon-color-positive-200: var(--ippon-color-green-200);
|
|
191
|
+
--ippon-color-positive-300: var(--ippon-color-green-300);
|
|
192
|
+
--ippon-color-positive-400: var(--ippon-color-green-400);
|
|
193
|
+
--ippon-color-positive-500: var(--ippon-color-green-500);
|
|
194
|
+
--ippon-color-positive-600: var(--ippon-color-green-600);
|
|
195
|
+
--ippon-color-positive-700: var(--ippon-color-green-700);
|
|
196
|
+
--ippon-color-positive-800: var(--ippon-color-green-800);
|
|
197
|
+
--ippon-color-positive-900: var(--ippon-color-green-900);
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Another level of semantic color exists, more relative to the usage. There is the following semantic color groups:
|
|
202
|
+
|
|
203
|
+
- `surface`
|
|
204
|
+
- `text-icon`
|
|
205
|
+
- `border`
|
|
206
|
+
|
|
207
|
+
It's also possible to find alternatives like 'primary', 'secondary', 'tertiary', etc…
|
|
208
|
+
|
|
209
|
+
So it's possible to define a text or icon color `on` a surface color, for example `on-primary` or `on-secondary`.
|
|
210
|
+
|
|
211
|
+
Here is an example for the `success` semantic color:
|
|
212
|
+
|
|
213
|
+
```scss
|
|
214
|
+
:root {
|
|
215
|
+
--ippon-color-success-surface-primary: var(--ippon-color-positive-700);
|
|
216
|
+
--ippon-color-success-surface-primary-hover: var(--ippon-color-positive-800);
|
|
217
|
+
--ippon-color-success-surface-primary-active: var(--ippon-color-positive-900);
|
|
218
|
+
--ippon-color-success-surface-secondary: var(--ippon-color-positive-100);
|
|
219
|
+
--ippon-color-success-surface-secondary-hover: var(--ippon-color-positive-200);
|
|
220
|
+
--ippon-color-success-surface-secondary-active: var(--ippon-color-positive-300);
|
|
221
|
+
--ippon-color-success-text-icon-primary: var(--ippon-color-positive-600);
|
|
222
|
+
--ippon-color-success-text-icon-secondary: var(--ippon-color-positive-800);
|
|
223
|
+
--ippon-color-success-text-icon-on-primary: var(--ippon-color-neutral-0);
|
|
224
|
+
--ippon-color-success-text-icon-on-secondary: var(--ippon-color-positive-700);
|
|
225
|
+
--ippon-color-success-border: var(--ippon-color-positive-500);
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Quark
|
|
230
|
+
|
|
231
|
+
A quark is a portion of an atom, molecule, or organism that is not usable without being part of a component. Generally, we use SCSS `@mixin` to represent quarks but it's not mandatory, it's a concept. For example, for a `Text` and a `Title` atom, we can imagine a set quark to represent weight alternatives:
|
|
232
|
+
|
|
233
|
+
```scss
|
|
234
|
+
@mixin weights {
|
|
235
|
+
&.-light {
|
|
236
|
+
font-weight: 300;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
&.-regular {
|
|
240
|
+
font-weight: 400;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
&.-medium {
|
|
244
|
+
font-weight: 500;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
&.-bold {
|
|
248
|
+
font-weight: 700;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
So it's possible to use this `weights` quark for both `Text` and `Title` atoms:
|
|
254
|
+
|
|
255
|
+
**Text:**
|
|
256
|
+
|
|
257
|
+
```scss
|
|
258
|
+
.ippon-text {
|
|
259
|
+
@include weights;
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Title:**
|
|
264
|
+
|
|
265
|
+
```scss
|
|
266
|
+
.ippon-title {
|
|
267
|
+
@include weights;
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
In the Pattern Library, quarks are defined in the `quark` folder:
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
src/
|
|
275
|
+
quark/
|
|
276
|
+
_quark.scss
|
|
277
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: pnpm/action-setup@v4
|
|
18
|
+
- uses: actions/setup-node@v4
|
|
19
|
+
with:
|
|
20
|
+
node-version: 24.14.1
|
|
21
|
+
cache: pnpm
|
|
22
|
+
- run: pnpm -r install --frozen-lockfile
|
|
23
|
+
- run: pnpm format:ci
|
|
24
|
+
- run: pnpm lint:ci
|
|
25
|
+
- run: pnpm test:unit:ci
|
|
26
|
+
- run: pnpm build
|
|
27
|
+
- uses: actions/upload-artifact@v4
|
|
28
|
+
with:
|
|
29
|
+
name: build-artifacts
|
|
30
|
+
path: |
|
|
31
|
+
icons/dist
|
|
32
|
+
icons/types
|
|
33
|
+
styles/dist
|
|
34
|
+
retention-days: 1
|
package/.gitlab-ci.yml
ADDED
package/.prettierignore
ADDED
package/AGENTS.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Code must be in English.
|
|
2
|
+
|
|
3
|
+
## Monorepo Structure
|
|
4
|
+
|
|
5
|
+
The project is a monorepo composed of the following projects:
|
|
6
|
+
|
|
7
|
+
- **styles**: Contains a Pattern Library with visual components, organized following Atomic Design.
|
|
8
|
+
- **icons**: Allows generating an icon font from SVG files from Ionicons
|
|
9
|
+
|
|
10
|
+
## Commands
|
|
11
|
+
|
|
12
|
+
You should use `mise` to run commands linked to this project. If you need to add more operations or a new command, please edit the `mise.toml` file, so the command will be available.
|
|
13
|
+
|
|
14
|
+
Run from the **monorepo root** unless noted otherwise.
|
|
15
|
+
|
|
16
|
+
| Task | Command |
|
|
17
|
+
| ---------------------------- | ------------------- |
|
|
18
|
+
| Trust mise | `mise trust` |
|
|
19
|
+
| Install mise | `mise install` |
|
|
20
|
+
| Install dependencies | `mise setup` |
|
|
21
|
+
| Start all in dev mode | `mise dev` |
|
|
22
|
+
| Build all packages | `mise build` |
|
|
23
|
+
| Format (fix) | `mise format` |
|
|
24
|
+
| Format (check only) | `mise format-ci` |
|
|
25
|
+
| Lint (fix) | `mise lint` |
|
|
26
|
+
| Lint (check only) | `mise lint-ci` |
|
|
27
|
+
| Unit tests (not interactive) | `mise unit-test-ci` |
|
|
28
|
+
|
|
29
|
+
## Pattern Library (`styles`)
|
|
30
|
+
|
|
31
|
+
The Pattern Library uses [Tikui](https://tikui.org) and follows [Atomic Design](http://atomicdesign.bradfrost.com/table-of-contents/):
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
src/
|
|
35
|
+
quark/ # SCSS variables, mixins, fonts reused inside atoms/molecules/organisms (no rendered output)
|
|
36
|
+
token/ # Design tokens (colors, shadows, typography, sizes)
|
|
37
|
+
atom/ # Smallest components: badge, button, icon, ion, meter, text, title, tab
|
|
38
|
+
molecule/ # Composed atoms: import-file, tabs, toggle
|
|
39
|
+
organism/ # Layout-level components: card, container, h-space, v-space, grid, header, modal, button-card
|
|
40
|
+
template/ # Full page layouts
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
CSS class naming uses an alternative-prefix convention: base class + `-<modifier>` (e.g. `ippon-card -shadow-2 -border`).
|
|
44
|
+
|
|
45
|
+
To develop the Pattern Library: `mise styles-dev` (serves on port 4220).
|
|
46
|
+
|
|
47
|
+
To add a component: `mise styles-create-component <component> --path <path>` where:
|
|
48
|
+
|
|
49
|
+
- component: component name in `kebab-case` (e.g. `button-card`)
|
|
50
|
+
- path: default is 'atom' to create inside `src/atom` from the styles directory
|