Skip to content

Commit 75acad4

Browse files
committed
✨ Add Grid component
1 parent aac5d1e commit 75acad4

File tree

12 files changed

+323
-4
lines changed

12 files changed

+323
-4
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ import { Accordion } from 'webcoreui/react'
239239
- [DataTable](https://github.com/Frontendland/webcoreui/tree/main/src/components/DataTable)
240240
- [Flex](https://github.com/Frontendland/webcoreui/tree/main/src/components/Flex)
241241
- [Footer](https://github.com/Frontendland/webcoreui/tree/main/src/components/Footer)
242+
- [Grid](https://github.com/Frontendland/webcoreui/tree/main/src/components/Grid)
242243
- [Group](https://github.com/Frontendland/webcoreui/tree/main/src/components/Group)
243244
- [Icon](https://github.com/Frontendland/webcoreui/tree/main/src/components/Icon)
244245
- [Input](https://github.com/Frontendland/webcoreui/tree/main/src/components/Input)

scripts/utilityTypes.js

+71
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,73 @@
11
export const utilityTypes = `
2+
export type Gap = 'none'
3+
| 'xxs'
4+
| 'xs'
5+
| 'sm'
6+
| 'md'
7+
| 'default'
8+
| 'lg'
9+
| 'xl'
10+
| 'xl2'
11+
| 'xl3'
12+
| 'xl4'
13+
| 'xl5'
14+
| ''
15+
16+
export type VerticalAlignment = 'center'
17+
| 'start'
18+
| 'end'
19+
| 'baseline'
20+
| 'stretch'
21+
| ''
22+
23+
export type HorizontalAlignment = 'center'
24+
| 'start'
25+
| 'end'
26+
| 'between'
27+
| 'around'
28+
| 'evenly'
29+
| 'stretch'
30+
| ''
31+
32+
export type Direction = 'row'
33+
| 'column'
34+
| 'row-reverse'
35+
| 'column-reverse'
36+
| ''
37+
38+
export type Wrap = 'wrap'
39+
| 'nowrap'
40+
| 'wrap-reverse'
41+
| ''
42+
43+
export type Column = (2 | 3) | {
44+
default?: 2 | 3
45+
xs?: 2 | 3 | 4
46+
sm?: 2 | 3 | 4
47+
md?: 2 | 3 | 4 | 5 | 6
48+
lg?: 2 | 3 | 4 | 5 | 6 | 7 | 8
49+
} | null
50+
51+
export type Responsive<T> = T | {
52+
default?: T
53+
xs?: T
54+
sm?: T
55+
md?: T
56+
lg?: T
57+
}
58+
59+
export type Alignment = {
60+
horizontal?: HorizontalAlignment
61+
vertical?: VerticalAlignment
62+
}
63+
64+
export type getLayoutClassesConfig = {
65+
gap?: Responsive<Gap>
66+
alignment?: Responsive<Alignment>
67+
direction?: Responsive<Direction>
68+
wrap?: Responsive<Wrap>
69+
}
70+
271
export type ModalCallback = {
372
trigger: Element | null
473
modal: HTMLElement
@@ -81,6 +150,8 @@ declare module 'webcoreui' {
81150
remove: () => void
82151
}
83152
153+
export const getLayoutClasses: (config: getLayoutClassesConfig) => string
154+
84155
export const clamp: (num: number, min: number, max: number) => number
85156
export const lerp: (start: number, end: number, value: number) => number
86157
export const invlerp: (start: number, end: number, value: number) => number

src/components/Flex/flex.ts

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type FlexProps = {
1313
direction?: Responsive<Direction>
1414
wrap?: Responsive<Wrap>
1515
className?: string
16+
[key: string]: any
1617
}
1718

1819
export type ReactFlexProps = {

src/components/Grid/Grid.astro

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
import type { GridProps } from './grid'
3+
4+
import { classNames } from '../../utils/classNames'
5+
import { getLayoutClasses } from '../../utils/getLayoutClasses'
6+
7+
interface Props extends GridProps {}
8+
9+
const {
10+
element = 'div',
11+
gap,
12+
column,
13+
className,
14+
...rest
15+
} = Astro.props
16+
17+
const Component = element
18+
19+
const classes = classNames([
20+
'grid',
21+
getLayoutClasses({ gap, column }),
22+
className
23+
])
24+
25+
const props = {
26+
class: classes
27+
}
28+
---
29+
30+
<Component {...props} {...rest}>
31+
<slot />
32+
</Component>

src/components/Grid/Grid.svelte

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script lang="ts">
2+
import type { GridProps } from './grid'
3+
4+
import { classNames } from '../../utils/classNames'
5+
import { getLayoutClasses } from '../../utils/getLayoutClasses'
6+
7+
export let element: GridProps['className'] = 'div'
8+
export let gap: GridProps['gap'] = ''
9+
export let column: GridProps['column'] = null
10+
export let className: GridProps['className'] = ''
11+
12+
const classes = classNames([
13+
'grid',
14+
getLayoutClasses({ gap, column }),
15+
className
16+
])
17+
18+
const props = {
19+
class: classes
20+
}
21+
</script>
22+
23+
<svelte:element this={element} {...props} {...$$restProps}>
24+
<slot />
25+
</svelte:element>

src/components/Grid/Grid.tsx

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react'
2+
import type { ReactGridProps } from './grid'
3+
4+
import { classNames } from '../../utils/classNames'
5+
import { getLayoutClasses } from '../../utils/getLayoutClasses'
6+
7+
const Grid = ({
8+
Element = 'div',
9+
gap,
10+
column,
11+
className,
12+
children,
13+
...rest
14+
}: ReactGridProps) => {
15+
const classes = classNames([
16+
'grid',
17+
getLayoutClasses({ gap, column }),
18+
className
19+
])
20+
21+
return (
22+
<Element className={classes} {...rest}>
23+
{children}
24+
</Element>
25+
)
26+
}
27+
28+
export default Grid

src/components/Grid/grid.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type {
2+
Column,
3+
Gap,
4+
Responsive
5+
} from '../../utils/getLayoutClasses'
6+
7+
export type GridProps = {
8+
element?: string
9+
gap?: Responsive<Gap>
10+
column?: Responsive<Column>
11+
className?: string
12+
[key: string]: any
13+
}
14+
15+
export type ReactGridProps = {
16+
Element?: keyof JSX.IntrinsicElements
17+
children: React.ReactNode
18+
} & Omit<GridProps, 'element'>

src/pages/components/flex.astro

+7
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ const gap = {
2727

2828
<Layout>
2929
<h1>Flex</h1>
30+
31+
<p>
32+
To use this component, <code>includeUtilities</code> must not be disabled in your <code>setup</code> mixin.
33+
You can also use the <a href="/css/utilities">utility classes</a> without this component to build flexible layouts.
34+
To build grid layouts, see the <code><a href="/components/grid">Grid</a></code> component.
35+
</p>
36+
3037
<div class="grid md-2 lg-3">
3138
<ComponentWrapper type="Astro">
3239
<AstroFlex gap={gap}>

src/pages/components/grid.astro

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
import Box from '@static/Box.astro'
3+
import ComponentWrapper from '@static/ComponentWrapper.astro'
4+
import Layout from '@static/Layout.astro'
5+
6+
import AstroGrid from '@components/Grid/Grid.astro'
7+
import SvelteGrid from '@components/Grid/Grid.svelte'
8+
import ReactGrid from '@components/Grid/Grid.tsx'
9+
10+
import { getSections } from '@helpers'
11+
12+
import type { Gap, Responsive } from '@utils/getLayoutClasses'
13+
14+
const sections = getSections({
15+
title: 'grids',
16+
components: [AstroGrid, SvelteGrid, ReactGrid]
17+
})
18+
19+
const gap = {
20+
default: 'xxs',
21+
xs: 'xs',
22+
sm: 'sm',
23+
md: 'md',
24+
lg: 'default'
25+
} as Responsive<Gap>
26+
---
27+
28+
<Layout>
29+
<h1>Grid</h1>
30+
31+
<p>
32+
To use this component, <code>includeUtilities</code> must not be disabled in your <code>setup</code> mixin.
33+
You can also use the <a href="/css/utilities">utility classes</a> without this component to build grid layouts.
34+
To build flexible layouts, see the <code><a href="/components/flex">Flex</a></code> component.
35+
</p>
36+
37+
<div class="grid md-2 lg-3">
38+
<ComponentWrapper type="Astro">
39+
<AstroGrid gap={gap}>
40+
<Box>1</Box>
41+
<Box>2</Box>
42+
<Box>3</Box>
43+
</AstroGrid>
44+
</ComponentWrapper>
45+
46+
<ComponentWrapper type="Svelte">
47+
<SvelteGrid gap={gap}>
48+
<Box>1</Box>
49+
<Box>2</Box>
50+
<Box>3</Box>
51+
</SvelteGrid>
52+
</ComponentWrapper>
53+
54+
<ComponentWrapper type="React">
55+
<ReactGrid gap={gap}>
56+
<Box>1</Box>
57+
<Box>2</Box>
58+
<Box>3</Box>
59+
</ReactGrid>
60+
</ComponentWrapper>
61+
</div>
62+
63+
{sections.map(section => (
64+
<h1>{section.title}</h1>
65+
<Fragment>
66+
{section.subTitle && <h2 set:html={section.subTitle} />}
67+
</Fragment>
68+
<div class="grid md-2 lg-3">
69+
<ComponentWrapper title="Default">
70+
<section.component>
71+
<Box>1</Box>
72+
<Box>2</Box>
73+
<Box>3</Box>
74+
</section.component>
75+
</ComponentWrapper>
76+
77+
<ComponentWrapper title="Custom gap">
78+
<section.component gap="xs">
79+
<Box>1</Box>
80+
<Box>2</Box>
81+
<Box>3</Box>
82+
</section.component>
83+
</ComponentWrapper>
84+
85+
<ComponentWrapper title="Number of columns (Set to 3)">
86+
<section.component column={3}>
87+
<Box>1</Box>
88+
<Box>2</Box>
89+
<Box>3</Box>
90+
</section.component>
91+
</ComponentWrapper>
92+
93+
<ComponentWrapper title="Media-query columns">
94+
<section.component column={{
95+
xs: 2,
96+
sm: 3,
97+
md: 4
98+
}}>
99+
<Box>1</Box>
100+
<Box>2</Box>
101+
<Box>3</Box>
102+
<Box>4</Box>
103+
</section.component>
104+
</ComponentWrapper>
105+
</div>
106+
))}
107+
</Layout>

src/pages/css/utilities.astro

+5
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ const wraps = [
5858
<Layout docs="/docs/layout">
5959
<h1>CSS Utility Classes</h1>
6060

61+
<p>The classes below are only available if <code>includeUtilities</code> is not disabled in your <code>setup</code> mixin.</p>
62+
6163
<h3>Container</h3>
6264
<Card>
6365
<div class="container">
@@ -139,6 +141,9 @@ const wraps = [
139141
</div>
140142

141143
<h3>Grid</h3>
144+
145+
<p>You can also use the <code><a href="/components/grid">Grid</a></code> component to build grid layouts.</p>
146+
142147
{Object.keys(breakpoints).map(key => (
143148
<Fragment>
144149
{Array.from({ length: breakpoints[key] - 1 }, (_, i) => i + 2).map(i => (

src/pages/index.astro

+7
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import Copy from '@components/Copy/Copy.astro'
1919
import DataTable from '@components/DataTable/DataTable.astro'
2020
import Flex from '@components/Flex/Flex.astro'
2121
import Footer from '@components/Footer/Footer.astro'
22+
import Grid from '@components/Grid/Grid.astro'
2223
import Group from '@components/Group/Group.astro'
2324
import Icon from '@components/Icon/Icon.astro'
2425
import Input from '@components/Input/Input.astro'
@@ -173,6 +174,12 @@ import {
173174
<CardWrapper title="Footer" href="/components/footer">
174175
<Footer columns={[{ title: 'WEBCORE', items: [] }]} />
175176
</CardWrapper>
177+
<CardWrapper title="Grid" href="/components/grid">
178+
<Grid column={2} gap="xs">
179+
<Box>1</Box>
180+
<Box>2</Box>
181+
</Grid>
182+
</CardWrapper>
176183
<CardWrapper title="Group" href="/components/group">
177184
<Group withSeparator={true}>
178185
<Button theme="secondary">Profile</Button>

0 commit comments

Comments
 (0)