agroptima-design-system 0.1.3 → 0.2.0
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/.github/workflows/publish-package-to-npmjs.yml +21 -0
- package/package.json +1 -1
- package/src/atoms/CardsTableList.scss +26 -0
- package/src/atoms/CardsTableList.tsx +66 -37
- package/src/atoms/CardsTableListHeader.tsx +32 -0
- package/src/atoms/CardsTableListRow.tsx +15 -0
- package/src/stories/CardsTableList.stories.ts +70 -8
- package/src/stories/Changelog.stories.mdx +8 -0
- package/src/stories/Icons.stories.mdx +5 -0
- package/src/stories/ProgrammersStartingGuide.stories.mdx +33 -1
- package/src/stories/Welcome.stories.mdx +4 -0
- package/src/stories/Workflow.stories.mdx +8 -0
- package/src/utils/sort.ts +31 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Publish Package to npmjs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
# Setup .npmrc file to publish to npm
|
|
14
|
+
- uses: actions/setup-node@v4
|
|
15
|
+
with:
|
|
16
|
+
node-version: '20.x'
|
|
17
|
+
registry-url: 'https://registry.npmjs.org'
|
|
18
|
+
- run: npm ci
|
|
19
|
+
- run: npm publish
|
|
20
|
+
env:
|
|
21
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/package.json
CHANGED
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
white-space: nowrap;
|
|
30
30
|
text-align: left;
|
|
31
31
|
|
|
32
|
+
&.sortable {
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
.icon {
|
|
33
37
|
width: config.$icon-size-3x;
|
|
34
38
|
height: config.$icon-size-3x;
|
|
@@ -59,6 +63,28 @@
|
|
|
59
63
|
fill: color_alias.$neutral-white;
|
|
60
64
|
}
|
|
61
65
|
}
|
|
66
|
+
|
|
67
|
+
&.ascending {
|
|
68
|
+
> svg {
|
|
69
|
+
.sorter_svg__up {
|
|
70
|
+
fill: color_alias.$primary-color-1000;
|
|
71
|
+
}
|
|
72
|
+
.sorter_svg__down {
|
|
73
|
+
fill: color_alias.$neutral-white;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&.descending {
|
|
79
|
+
> svg {
|
|
80
|
+
.sorter_svg__up {
|
|
81
|
+
fill: color_alias.$neutral-white;
|
|
82
|
+
}
|
|
83
|
+
.sorter_svg__down {
|
|
84
|
+
fill: color_alias.$primary-color-1000;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
62
88
|
}
|
|
63
89
|
}
|
|
64
90
|
|
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
import './CardsTableList.scss'
|
|
2
|
-
import {
|
|
2
|
+
import React, { useState } from 'react'
|
|
3
|
+
import { sortBy } from '../utils/sort'
|
|
4
|
+
import { IconType } from './Icon'
|
|
5
|
+
import { CardsTableListHeader } from './CardsTableListHeader'
|
|
6
|
+
import { CardsTableListRow } from './CardsTableListRow'
|
|
3
7
|
|
|
4
8
|
export type Variant = 'primary'
|
|
5
|
-
|
|
6
|
-
export type
|
|
9
|
+
|
|
10
|
+
export type Header = {
|
|
11
|
+
label: string
|
|
12
|
+
icon?: IconType
|
|
13
|
+
columnId: string
|
|
14
|
+
isSortable?: boolean
|
|
15
|
+
}
|
|
16
|
+
export type Column = {
|
|
7
17
|
[key: string]: string
|
|
8
18
|
}
|
|
9
|
-
export type Row = { id: string; isDisabled
|
|
19
|
+
export type Row = { id: string; isDisabled?: boolean; columns: Column }
|
|
20
|
+
|
|
21
|
+
export enum Order {
|
|
22
|
+
Ascending = 'ascending',
|
|
23
|
+
Descending = 'descending',
|
|
24
|
+
None = 'none',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type SortState = { columnId: string; order: Order }
|
|
10
28
|
|
|
11
29
|
export interface CardsTableListProps
|
|
12
30
|
extends React.ComponentPropsWithoutRef<'table'> {
|
|
@@ -21,48 +39,59 @@ export function CardsTableList({
|
|
|
21
39
|
summary,
|
|
22
40
|
variant = 'primary',
|
|
23
41
|
}: CardsTableListProps): React.JSX.Element {
|
|
42
|
+
const [sortState, setSortState] = useState<SortState | null>(() => {
|
|
43
|
+
return headers[0]?.isSortable
|
|
44
|
+
? { columnId: headers[0].columnId, order: Order.Ascending }
|
|
45
|
+
: null
|
|
46
|
+
})
|
|
47
|
+
|
|
24
48
|
const cssClasses = ['cards-table-list', variant].join(' ')
|
|
25
49
|
|
|
50
|
+
function checkColumnOrder(columnId: string) {
|
|
51
|
+
if (sortState?.columnId === columnId) {
|
|
52
|
+
return sortState.order
|
|
53
|
+
}
|
|
54
|
+
return Order.None
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function applySort(columnId: string) {
|
|
58
|
+
if (!headers.find((header) => header.columnId === columnId)?.isSortable) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
setSortState({
|
|
63
|
+
columnId,
|
|
64
|
+
order:
|
|
65
|
+
checkColumnOrder(columnId) === Order.Ascending
|
|
66
|
+
? Order.Descending
|
|
67
|
+
: Order.Ascending,
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
const sortedRows = sortState?.columnId
|
|
71
|
+
? sortBy({
|
|
72
|
+
rows,
|
|
73
|
+
prop: sortState?.columnId,
|
|
74
|
+
order: sortState?.order,
|
|
75
|
+
})
|
|
76
|
+
: rows
|
|
26
77
|
return (
|
|
27
78
|
<table summary={summary} role="table" className={cssClasses}>
|
|
28
79
|
<thead role="rowgroup">
|
|
29
80
|
<tr role="row">
|
|
30
|
-
{headers.map((header) =>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
>
|
|
39
|
-
<div className="container">
|
|
40
|
-
<div className="title-container">
|
|
41
|
-
<span>{header.label}</span>
|
|
42
|
-
{icon && <Icon name={icon} />}
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
</th>
|
|
46
|
-
)
|
|
47
|
-
})}
|
|
81
|
+
{headers.map((header) => (
|
|
82
|
+
<CardsTableListHeader
|
|
83
|
+
key={header.columnId}
|
|
84
|
+
header={header}
|
|
85
|
+
order={checkColumnOrder(header.columnId)}
|
|
86
|
+
onClick={() => applySort(header.columnId)}
|
|
87
|
+
/>
|
|
88
|
+
))}
|
|
48
89
|
</tr>
|
|
49
90
|
</thead>
|
|
50
91
|
<tbody role="rowgroup">
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<tr role="row" className={`row ${disabledClass}`} key={row.id}>
|
|
56
|
-
{Object.getOwnPropertyNames(data).map((property) => {
|
|
57
|
-
return (
|
|
58
|
-
<td role="cell" key={row.id + property} className="cell">
|
|
59
|
-
{data[property]}
|
|
60
|
-
</td>
|
|
61
|
-
)
|
|
62
|
-
})}
|
|
63
|
-
</tr>
|
|
64
|
-
)
|
|
65
|
-
})}
|
|
92
|
+
{sortedRows.map((row: Row) => (
|
|
93
|
+
<CardsTableListRow key={row.id} {...row} />
|
|
94
|
+
))}
|
|
66
95
|
</tbody>
|
|
67
96
|
</table>
|
|
68
97
|
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Icon } from './Icon'
|
|
2
|
+
import { Header, Order } from './CardsTableList'
|
|
3
|
+
|
|
4
|
+
export interface CardsTableListHeaderProps {
|
|
5
|
+
header: Header
|
|
6
|
+
order: Order
|
|
7
|
+
onClick: () => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function CardsTableListHeader({
|
|
11
|
+
header,
|
|
12
|
+
order,
|
|
13
|
+
onClick,
|
|
14
|
+
}: CardsTableListHeaderProps) {
|
|
15
|
+
return (
|
|
16
|
+
<th
|
|
17
|
+
scope="col"
|
|
18
|
+
role="columnheader"
|
|
19
|
+
className={`header ${header.isSortable ? 'sortable' : ''}`}
|
|
20
|
+
aria-sort={order}
|
|
21
|
+
onClick={onClick}
|
|
22
|
+
>
|
|
23
|
+
<div className="container">
|
|
24
|
+
<div className="title-container">
|
|
25
|
+
<span>{header.label}</span>
|
|
26
|
+
{header.icon && <Icon name={header.icon} />}
|
|
27
|
+
</div>
|
|
28
|
+
{header.isSortable && <Icon name="Sorter" className={order} />}
|
|
29
|
+
</div>
|
|
30
|
+
</th>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Row } from './CardsTableList'
|
|
2
|
+
|
|
3
|
+
export function CardsTableListRow({ isDisabled, columns, id }: Row) {
|
|
4
|
+
const disabledClass = isDisabled ? 'disabled' : ''
|
|
5
|
+
const cells = Object.entries(columns)
|
|
6
|
+
return (
|
|
7
|
+
<tr role="row" className={`row ${disabledClass}`}>
|
|
8
|
+
{cells.map(([columnId, value]) => (
|
|
9
|
+
<td role="cell" key={`${id}${columnId}`} className="cell">
|
|
10
|
+
{value}
|
|
11
|
+
</td>
|
|
12
|
+
))}
|
|
13
|
+
</tr>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
@@ -14,7 +14,8 @@ const meta = {
|
|
|
14
14
|
'Summary of the table purpose and structure for assistive technologies',
|
|
15
15
|
},
|
|
16
16
|
headers: {
|
|
17
|
-
description:
|
|
17
|
+
description:
|
|
18
|
+
'Array of values to be displayed on the headers. columnId value must match with rows columns ids.',
|
|
18
19
|
},
|
|
19
20
|
rows: {
|
|
20
21
|
description: 'Array of values to be displayed as the data',
|
|
@@ -32,7 +33,64 @@ const figmaPrimaryDesign = {
|
|
|
32
33
|
export default meta
|
|
33
34
|
type Story = StoryObj<typeof meta>
|
|
34
35
|
|
|
35
|
-
export const
|
|
36
|
+
export const WithSorting: Story = {
|
|
37
|
+
args: {
|
|
38
|
+
variant: 'primary',
|
|
39
|
+
summary: 'Videogames companies contact information',
|
|
40
|
+
headers: [
|
|
41
|
+
{
|
|
42
|
+
label: 'Game title',
|
|
43
|
+
icon: 'Info',
|
|
44
|
+
columnId: 'name',
|
|
45
|
+
isSortable: true,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
label: 'Company address',
|
|
49
|
+
icon: 'Info',
|
|
50
|
+
columnId: 'address',
|
|
51
|
+
isSortable: false,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
label: 'Customer service email',
|
|
55
|
+
columnId: 'email',
|
|
56
|
+
icon: 'Info',
|
|
57
|
+
isSortable: true,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
rows: [
|
|
61
|
+
{
|
|
62
|
+
id: '1',
|
|
63
|
+
columns: {
|
|
64
|
+
name: 'Metal Gear Solid 5: The Phantom Pain',
|
|
65
|
+
address:
|
|
66
|
+
'Konami Digital Entertainment Co., Ltd. 1-11-1, Ginza, Chuo-ku, Tokyo, 104-0061 Japan',
|
|
67
|
+
email: 'konami@fakemail.com',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: '2',
|
|
72
|
+
columns: {
|
|
73
|
+
name: 'The Witcher 3',
|
|
74
|
+
address: 'CD PROJEKT S.A. ul. Jagiellońska 74 03-301 Warszawa Poland',
|
|
75
|
+
email: 'cdprojekt@fakemail.com',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: '3',
|
|
80
|
+
isDisabled: true,
|
|
81
|
+
columns: {
|
|
82
|
+
name: 'Tekken 8',
|
|
83
|
+
address:
|
|
84
|
+
'Bandai Namco Studios Inc. ; Address: 2-37-25 Eitai, Koto-ku, Tokyo 135-0034, Japan',
|
|
85
|
+
email: 'namco@fakemail.com',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
parameters: figmaPrimaryDesign,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const NoSorting: Story = {
|
|
36
94
|
args: {
|
|
37
95
|
variant: 'primary',
|
|
38
96
|
summary: 'Videogames companies contact information',
|
|
@@ -40,18 +98,23 @@ export const Primary: Story = {
|
|
|
40
98
|
{
|
|
41
99
|
label: 'Game title',
|
|
42
100
|
icon: 'Info',
|
|
101
|
+
columnId: 'name',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
label: 'Company address',
|
|
105
|
+
icon: 'Info',
|
|
106
|
+
columnId: 'address',
|
|
43
107
|
},
|
|
44
|
-
{ label: 'Company address' },
|
|
45
108
|
{
|
|
46
109
|
label: 'Customer service email',
|
|
110
|
+
columnId: 'email',
|
|
47
111
|
icon: 'Info',
|
|
48
112
|
},
|
|
49
113
|
],
|
|
50
114
|
rows: [
|
|
51
115
|
{
|
|
52
116
|
id: '1',
|
|
53
|
-
|
|
54
|
-
data: {
|
|
117
|
+
columns: {
|
|
55
118
|
name: 'Metal Gear Solid 5: The Phantom Pain',
|
|
56
119
|
address:
|
|
57
120
|
'Konami Digital Entertainment Co., Ltd. 1-11-1, Ginza, Chuo-ku, Tokyo, 104-0061 Japan',
|
|
@@ -60,8 +123,7 @@ export const Primary: Story = {
|
|
|
60
123
|
},
|
|
61
124
|
{
|
|
62
125
|
id: '2',
|
|
63
|
-
|
|
64
|
-
data: {
|
|
126
|
+
columns: {
|
|
65
127
|
name: 'The Witcher 3',
|
|
66
128
|
address: 'CD PROJEKT S.A. ul. Jagiellońska 74 03-301 Warszawa Poland',
|
|
67
129
|
email: 'cdprojekt@fakemail.com',
|
|
@@ -70,7 +132,7 @@ export const Primary: Story = {
|
|
|
70
132
|
{
|
|
71
133
|
id: '3',
|
|
72
134
|
isDisabled: true,
|
|
73
|
-
|
|
135
|
+
columns: {
|
|
74
136
|
name: 'Tekken 8',
|
|
75
137
|
address:
|
|
76
138
|
'Bandai Namco Studios Inc. ; Address: 2-37-25 Eitai, Koto-ku, Tokyo 135-0034, Japan',
|
|
@@ -3,6 +3,14 @@ import { Meta } from "@storybook/addon-docs";
|
|
|
3
3
|
<Meta title="Changelog" />
|
|
4
4
|
# Changelog
|
|
5
5
|
|
|
6
|
+
## 0.2.0
|
|
7
|
+
|
|
8
|
+
- Sorting has been added to the CardsTableList component.
|
|
9
|
+
|
|
10
|
+
BREAKING CHANGES
|
|
11
|
+
- `columnId` prop is required from this version.
|
|
12
|
+
- rows `data` prop has been renamed to `columns`.
|
|
13
|
+
|
|
6
14
|
## 0.1.3
|
|
7
15
|
|
|
8
16
|
Update left padding on the cells from CardsTableList component
|
|
@@ -5,6 +5,11 @@ import * as Icons from '../icons'
|
|
|
5
5
|
|
|
6
6
|
# Icons
|
|
7
7
|
|
|
8
|
+
📁 You can find the source icons on this [link]( https://drive.google.com/drive/folders/16L5iR5KnDP9kfeCF-mDU0C0LiJZi0cwi).
|
|
9
|
+
|
|
10
|
+
ℹ️ If you need to edit the svgo default options, check this [link](https://stackoverflow.com/a/70360615).
|
|
11
|
+
|
|
12
|
+
|
|
8
13
|
<IconGallery>
|
|
9
14
|
{
|
|
10
15
|
Object.values(Icons).map((Icon) => {
|
|
@@ -3,4 +3,36 @@ import { Meta } from "@storybook/addon-docs";
|
|
|
3
3
|
<Meta title="Programmers start guide" />
|
|
4
4
|
# Getting started guide for programmers
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
## Indigo Project
|
|
7
|
+
|
|
8
|
+
### Install agroptima-design-system dependency
|
|
9
|
+
|
|
10
|
+
On the frontend project's package.json, you can see the `agroptima-design-system` dependency.
|
|
11
|
+
|
|
12
|
+
After installing all the project dependencies, run `npm i agroptima-design-system@latest` to have the latest version
|
|
13
|
+
of the design sytem package.
|
|
14
|
+
|
|
15
|
+
### Import & use design system components
|
|
16
|
+
|
|
17
|
+
Import the desired component:
|
|
18
|
+
|
|
19
|
+
`import { Input } from 'agroptima-design-system/src/atoms/Button'`
|
|
20
|
+
|
|
21
|
+
Use the desired component:
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
<Button
|
|
25
|
+
type="submit"
|
|
26
|
+
label="Login"
|
|
27
|
+
loading={isSubmitting}
|
|
28
|
+
variant="primary"
|
|
29
|
+
/>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Sioux Project
|
|
34
|
+
|
|
35
|
+
We have been focused on creating prioritized components, learning how Storybook works and behaves, making the Design System independent
|
|
36
|
+
from the Indigo project and checking the consumption of components from a single project.
|
|
37
|
+
|
|
38
|
+
Once we reach the needed checkpoint, we'll continue the integration of the Design System with Sioux project.
|
|
@@ -31,3 +31,7 @@ If you have any questions, proposals, needs or issues, don't hesitate to contact
|
|
|
31
31
|
|
|
32
32
|
## How to report issues
|
|
33
33
|
|
|
34
|
+
You can report an issue on the [Issues section](https://github.com/agroptima/design-system/issues) of the design system repo.
|
|
35
|
+
|
|
36
|
+
Contact with the responsibles of the project to make them aware of the reported issue.
|
|
37
|
+
|
|
@@ -3,6 +3,14 @@ import { Meta } from "@storybook/addon-docs";
|
|
|
3
3
|
<Meta title="Component creation workflow" />
|
|
4
4
|
# Component creation workflow
|
|
5
5
|
|
|
6
|
+
## Style properties conditioned by variants
|
|
7
|
+
|
|
8
|
+
The following properties are the ones which will change depending on the variant provided:
|
|
9
|
+
|
|
10
|
+
- Font family
|
|
11
|
+
- Border radius
|
|
12
|
+
- Colours: Except Error and Success variants colours which are common for all themes
|
|
13
|
+
|
|
6
14
|
## How does the Design Team work
|
|
7
15
|
|
|
8
16
|
🌈 <b>The Figma design system is the only source of truth and the collaboration, teamwork and regard among
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Order, Row } from '../atoms/CardsTableList'
|
|
2
|
+
|
|
3
|
+
interface Parse {
|
|
4
|
+
(x: string): string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface Sort {
|
|
8
|
+
rows: Row[]
|
|
9
|
+
prop: string
|
|
10
|
+
order: string
|
|
11
|
+
parse?: Parse
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function sortBy({
|
|
15
|
+
rows,
|
|
16
|
+
prop,
|
|
17
|
+
order = Order.Ascending,
|
|
18
|
+
parse = (x) => x,
|
|
19
|
+
}: Sort) {
|
|
20
|
+
const sortOrder = order === Order.Descending ? -1 : 1
|
|
21
|
+
return rows.sort((a: Row, b: Row) => {
|
|
22
|
+
let result = 0
|
|
23
|
+
if (parse(a.columns[prop]) < parse(b.columns[prop])) {
|
|
24
|
+
result = -1
|
|
25
|
+
}
|
|
26
|
+
if (parse(a.columns[prop]) > parse(b.columns[prop])) {
|
|
27
|
+
result = 1
|
|
28
|
+
}
|
|
29
|
+
return result * sortOrder
|
|
30
|
+
})
|
|
31
|
+
}
|