formica-ui-lib 1.0.149 → 1.0.151
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/README.md +267 -7
- package/dist/componentProps/atoms/layout/ContentContainerProps.d.ts +8 -0
- package/dist/componentProps/atoms/layout/ContentGridProps.d.ts +12 -0
- package/dist/componentProps/atoms/layout/FlowRowProps.d.ts +12 -0
- package/dist/componentProps/molecules/selectors/filterbar/DropdownFilterProps.d.ts +5 -0
- package/dist/componentProps/molecules/selectors/filterbar/FilterBarButtonProps.d.ts +5 -0
- package/dist/componentProps/molecules/selectors/filterbar/FilterBarProps.d.ts +6 -0
- package/dist/componentProps/molecules/selectors/filterbar/SearchFilterProps.d.ts +5 -0
- package/dist/componentProps/organisms/imagegrid/ImageGridProps.d.ts +5 -0
- package/dist/componentProps/scene/category/CategorySceneProps.d.ts +8 -2
- package/dist/componentProps/scene/gallery/GallerySceneProps.d.ts +4 -2
- package/dist/index.cjs +8 -8
- package/dist/index.d.ts +14 -0
- package/dist/index.js +1071 -992
- package/dist/stories/atoms/layout/ContentContainer/ContentContainer.d.ts +4 -0
- package/dist/stories/atoms/layout/ContentGrid/ContentGrid.d.ts +4 -0
- package/dist/stories/atoms/layout/FlowRow/FlowRow.d.ts +4 -0
- package/dist/stories/molecules/selectors/filterbar/DropdownFilter.d.ts +4 -0
- package/dist/stories/molecules/selectors/filterbar/FilterBar.d.ts +4 -0
- package/dist/stories/molecules/selectors/filterbar/FilterBarButton.d.ts +4 -0
- package/dist/stories/molecules/selectors/filterbar/SearchFilter.d.ts +4 -0
- package/package.json +1 -1
- package/dist/componentProps/molecules/selectors/sortandfilterbar/SortAndFilterBarProps.d.ts +0 -8
- package/dist/componentProps/molecules/selectors/tripledropdownbar/TripleDropdownBarProps.d.ts +0 -4
- package/dist/stories/molecules/selectors/sortandfilterbar/SortAndFilterBar.d.ts +0 -4
- package/dist/stories/molecules/selectors/tripledropdownbar/TripleDropdownBar.d.ts +0 -4
- /package/dist/stories/molecules/selectors/{sortandfilterbar/SortAndFilterBar.test.d.ts → filterbar/FilterBar.test.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,17 +1,263 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Formica UI
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
This repository contains Formica's Storybook-based UI component library.
|
|
4
|
+
|
|
5
|
+
The goal of this repo is to keep UI pieces:
|
|
6
|
+
|
|
7
|
+
- reusable
|
|
8
|
+
- easy to compose
|
|
9
|
+
- easy to wire into a BFF or app layer
|
|
10
|
+
- free from business logic
|
|
11
|
+
|
|
12
|
+
If you are new to the codebase, read this file first. If you need the stricter engineering rules, read [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
13
|
+
|
|
14
|
+
## What Lives Here
|
|
15
|
+
|
|
16
|
+
This project is mainly for:
|
|
17
|
+
|
|
18
|
+
- atoms, molecules, organisms, templates, and scenes
|
|
19
|
+
- Storybook stories for those components
|
|
20
|
+
- shared prop contracts and callback payload types
|
|
21
|
+
|
|
22
|
+
This project is not where UI components should:
|
|
23
|
+
|
|
24
|
+
- fetch data
|
|
25
|
+
- handle routing
|
|
26
|
+
- talk directly to APIs
|
|
27
|
+
- make business decisions
|
|
28
|
+
|
|
29
|
+
## Folder Basics
|
|
30
|
+
|
|
31
|
+
- `src/stories/...`
|
|
32
|
+
UI components and Storybook-facing implementations
|
|
33
|
+
- `src/componentProps/...`
|
|
34
|
+
prop contracts and shared exported types
|
|
35
|
+
- `mocks/...`
|
|
36
|
+
mock data used by stories and scene simulations
|
|
37
|
+
|
|
38
|
+
## Working Rule Of Thumb
|
|
39
|
+
|
|
40
|
+
Think of most UI components as display components.
|
|
41
|
+
|
|
42
|
+
Their job is to:
|
|
43
|
+
|
|
44
|
+
- render data
|
|
45
|
+
- accept callback props
|
|
46
|
+
- emit typed payloads upward
|
|
47
|
+
- keep only small visual state when needed
|
|
48
|
+
|
|
49
|
+
Their job is not to:
|
|
50
|
+
|
|
51
|
+
- decide where the app navigates
|
|
52
|
+
- call APIs
|
|
53
|
+
- manage app-wide state
|
|
54
|
+
- invent behavior on their own
|
|
55
|
+
|
|
56
|
+
## Coding Standards In Plain English
|
|
57
|
+
|
|
58
|
+
### 1. Put props and types in their own files
|
|
59
|
+
|
|
60
|
+
If a component needs props, create a dedicated prop file for it under `src/componentProps/...`.
|
|
61
|
+
|
|
62
|
+
Do not define the full prop contract inline inside the component unless it is truly private and temporary.
|
|
63
|
+
|
|
64
|
+
Good:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
export type ImageGridProps = {
|
|
68
|
+
images: GridImage[];
|
|
69
|
+
onImageClick?: (payload: ImageGridClickPayload) => void;
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2. Keep UI components dumb
|
|
74
|
+
|
|
75
|
+
A UI component should mostly just render what it is given.
|
|
76
|
+
|
|
77
|
+
Good:
|
|
78
|
+
|
|
79
|
+
- render text, images, layout, and controls
|
|
80
|
+
- call `onClick`, `onChange`, `onSelect`, etc.
|
|
81
|
+
|
|
82
|
+
Bad:
|
|
83
|
+
|
|
84
|
+
- calling `fetch`
|
|
85
|
+
- importing routing logic
|
|
86
|
+
- mutating app-wide data
|
|
87
|
+
- logging app behavior from deep inside a presentational component unless it is only a temporary local debug step
|
|
88
|
+
|
|
89
|
+
### 3. Pass behavior down, emit events up
|
|
90
|
+
|
|
91
|
+
The app layer, BFF simulation layer, or scene story should own behavior.
|
|
92
|
+
|
|
93
|
+
The deeper UI component should only emit a typed callback.
|
|
94
|
+
|
|
95
|
+
Example flow:
|
|
96
|
+
|
|
97
|
+
1. story or scene owns the state
|
|
98
|
+
2. scene passes callback props down
|
|
99
|
+
3. item component calls the callback
|
|
100
|
+
4. typed payload comes back up
|
|
101
|
+
|
|
102
|
+
### 4. Use explicit callback names
|
|
103
|
+
|
|
104
|
+
Prefer clear names over generic handlers.
|
|
105
|
+
|
|
106
|
+
Good:
|
|
107
|
+
|
|
108
|
+
- `onCartClick`
|
|
109
|
+
- `onLoginClick`
|
|
110
|
+
- `onPromoClick`
|
|
111
|
+
- `onImageClick`
|
|
112
|
+
- `onCountrySelect`
|
|
113
|
+
|
|
114
|
+
Less preferred:
|
|
115
|
+
|
|
116
|
+
- `onAction`
|
|
117
|
+
- `onEvent`
|
|
118
|
+
- `handleThing`
|
|
119
|
+
|
|
120
|
+
### 5. Do not use `any`
|
|
121
|
+
|
|
122
|
+
If a callback sends data upward, define a real payload type and export it.
|
|
123
|
+
|
|
124
|
+
Good:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
export type ImageGridClickPayload = {
|
|
128
|
+
image: GridImage;
|
|
129
|
+
index: number;
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Storybook Standards
|
|
134
|
+
|
|
135
|
+
### Stories should use `.stories.js`
|
|
136
|
+
|
|
137
|
+
Use `.stories.js` files for Storybook stories in this repo.
|
|
138
|
+
|
|
139
|
+
### Stories should use args
|
|
140
|
+
|
|
141
|
+
Prefer `args`-based stories and simple templates.
|
|
142
|
+
|
|
143
|
+
Avoid complex JSX-heavy story files unless there is a real need.
|
|
144
|
+
|
|
145
|
+
### Stories must match the final prop contract
|
|
146
|
+
|
|
147
|
+
If the component props change, update the story right away.
|
|
148
|
+
|
|
149
|
+
Do not leave stale story args, controls, or fake props around.
|
|
150
|
+
|
|
151
|
+
## Scene Stories
|
|
152
|
+
|
|
153
|
+
Scene stories are special.
|
|
154
|
+
|
|
155
|
+
They should act like a lightweight simulation of how the UI will behave when wired into a BFF or application layer.
|
|
156
|
+
|
|
157
|
+
That means scene stories should often own:
|
|
158
|
+
|
|
159
|
+
- selected values
|
|
160
|
+
- visible/hidden state
|
|
161
|
+
- click handlers
|
|
162
|
+
- change handlers
|
|
163
|
+
- log output for interaction testing
|
|
164
|
+
|
|
165
|
+
In other words: if a child component needs a callback to feel real, the scene story should usually provide it.
|
|
166
|
+
|
|
167
|
+
## Generic Layout Containers
|
|
168
|
+
|
|
169
|
+
We now have a few reusable layout primitives:
|
|
170
|
+
|
|
171
|
+
- `ContentContainer`
|
|
172
|
+
- `ContentGrid`
|
|
173
|
+
- `FlowRow`
|
|
174
|
+
|
|
175
|
+
Use them when several components share the same layout pattern.
|
|
176
|
+
|
|
177
|
+
Examples:
|
|
178
|
+
|
|
179
|
+
- centered max-width wrappers
|
|
180
|
+
- responsive content grids
|
|
181
|
+
- rows of controls or logos with shared spacing
|
|
182
|
+
|
|
183
|
+
Do not force everything into one generic container.
|
|
184
|
+
|
|
185
|
+
A generic container is worth using when the shared part is structural:
|
|
186
|
+
|
|
187
|
+
- width
|
|
188
|
+
- spacing
|
|
189
|
+
- columns
|
|
190
|
+
- wrapping
|
|
191
|
+
- alignment
|
|
192
|
+
|
|
193
|
+
It is not the right tool when the component needs domain-specific rules.
|
|
194
|
+
|
|
195
|
+
### Good use of a generic container
|
|
196
|
+
|
|
197
|
+
- `ImageGrid` using `ContentGrid`
|
|
198
|
+
- `DecorGrid` using `ContentGrid`
|
|
199
|
+
|
|
200
|
+
### Bad use of a generic container
|
|
201
|
+
|
|
202
|
+
- a grid deciding what happens when a card is clicked
|
|
203
|
+
- a layout wrapper deciding navigation or selection logic
|
|
204
|
+
|
|
205
|
+
## When To Use `ClickableCard`
|
|
206
|
+
|
|
207
|
+
Use `ClickableCard` when a whole card or large visual surface acts as one click target.
|
|
208
|
+
|
|
209
|
+
Examples:
|
|
210
|
+
|
|
211
|
+
- an image tile that opens detail
|
|
212
|
+
- a swatch card where clicking the image opens the decor
|
|
213
|
+
|
|
214
|
+
Do not use `ClickableCard` when only a normal CTA inside the card is interactive.
|
|
215
|
+
|
|
216
|
+
Examples:
|
|
217
|
+
|
|
218
|
+
- a card with a single "Learn More" button
|
|
219
|
+
- a card with a standard text link
|
|
220
|
+
|
|
221
|
+
### Important rule
|
|
222
|
+
|
|
223
|
+
The component that owns the clickable surface should own `ClickableCard`.
|
|
224
|
+
|
|
225
|
+
Good:
|
|
226
|
+
|
|
227
|
+
- `SwatchCard` uses `ClickableCard`
|
|
228
|
+
- `ImageGrid` uses `ClickableCard` per image tile
|
|
229
|
+
|
|
230
|
+
Bad:
|
|
231
|
+
|
|
232
|
+
- `DecorGrid` wrapping every child in `ClickableCard`
|
|
233
|
+
- `ContentGrid` trying to handle clicks
|
|
234
|
+
|
|
235
|
+
## Atomic Design Guidance
|
|
236
|
+
|
|
237
|
+
Try to keep responsibility at the right layer:
|
|
238
|
+
|
|
239
|
+
- atoms
|
|
240
|
+
simple UI pieces and layout primitives
|
|
241
|
+
- molecules
|
|
242
|
+
small composed patterns like `ClickableCard`
|
|
243
|
+
- organisms
|
|
244
|
+
richer composed sections like grids, navs, banners, panels
|
|
245
|
+
- scenes
|
|
246
|
+
higher-level composition and interaction simulation
|
|
247
|
+
|
|
248
|
+
If a primitive starts learning too much about a domain concept, it is probably in the wrong layer.
|
|
4
249
|
|
|
5
250
|
## Branching / Git Workflow
|
|
6
251
|
|
|
7
|
-
|
|
252
|
+
Direct commits to `main` are not allowed.
|
|
8
253
|
|
|
9
|
-
|
|
254
|
+
Create feature branches from `dev`.
|
|
10
255
|
|
|
11
|
-
|
|
12
|
-
2. Create a new feature branch named `feature/YourFeature`
|
|
256
|
+
### Create a feature branch from `dev`
|
|
13
257
|
|
|
14
|
-
|
|
258
|
+
1. Checkout `dev`
|
|
259
|
+
2. Pull the latest changes
|
|
260
|
+
3. Create a feature branch named `feature/YourFeature`
|
|
15
261
|
|
|
16
262
|
```bash
|
|
17
263
|
git fetch
|
|
@@ -19,3 +265,17 @@ git checkout dev
|
|
|
19
265
|
git pull
|
|
20
266
|
git checkout -b feature/YourFeature
|
|
21
267
|
```
|
|
268
|
+
|
|
269
|
+
## Final Advice For Junior Devs
|
|
270
|
+
|
|
271
|
+
If you are unsure where code should live, ask these questions:
|
|
272
|
+
|
|
273
|
+
1. Is this layout or behavior?
|
|
274
|
+
2. Does this component need to know app logic, or just render?
|
|
275
|
+
3. Is this click target owned by the item, or by the container?
|
|
276
|
+
4. Is this type reusable enough to belong in `componentProps`?
|
|
277
|
+
5. Would this be easier to understand if the story owned the state instead?
|
|
278
|
+
|
|
279
|
+
If you stay strict about those five questions, your changes will usually fit the codebase well.
|
|
280
|
+
|
|
281
|
+
For the stricter rule set, examples, and review checklist, see [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type ContentContainerMaxWidth = "sm" | "md" | "lg" | "xl" | "2xl" | "4xl" | "6xl";
|
|
3
|
+
export type ContentContainerProps = {
|
|
4
|
+
children?: React.ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
innerClassName?: string;
|
|
7
|
+
maxWidth?: ContentContainerMaxWidth;
|
|
8
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { ContentContainerMaxWidth } from "./ContentContainerProps";
|
|
3
|
+
export type ContentGridColumns = 1 | 2 | 3 | 4;
|
|
4
|
+
export type ContentGridGap = "sm" | "md" | "lg" | "xl";
|
|
5
|
+
export type ContentGridProps = {
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
gridClassName?: string;
|
|
9
|
+
maxWidth?: ContentContainerMaxWidth;
|
|
10
|
+
columns?: ContentGridColumns;
|
|
11
|
+
gap?: ContentGridGap;
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type FlowRowGap = "sm" | "md" | "lg" | "xl";
|
|
3
|
+
export type FlowRowAlign = "start" | "center" | "end" | "stretch";
|
|
4
|
+
export type FlowRowJustify = "start" | "center" | "end" | "between" | "around" | "evenly";
|
|
5
|
+
export type FlowRowProps = {
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
gap?: FlowRowGap;
|
|
9
|
+
align?: FlowRowAlign;
|
|
10
|
+
justify?: FlowRowJustify;
|
|
11
|
+
wrap?: boolean;
|
|
12
|
+
};
|
|
@@ -4,6 +4,11 @@ export type GridImage = Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src" |
|
|
|
4
4
|
alt: string;
|
|
5
5
|
quality: number;
|
|
6
6
|
};
|
|
7
|
+
export type ImageGridClickPayload = {
|
|
8
|
+
image: GridImage;
|
|
9
|
+
index: number;
|
|
10
|
+
};
|
|
7
11
|
export interface ImageGridProps {
|
|
8
12
|
images: GridImage[];
|
|
13
|
+
onImageClick?: (payload: ImageGridClickPayload) => void;
|
|
9
14
|
}
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import type { StandardCopyHeroProps } from "../../organisms/banner/standardcopyhero/StandardCopyHeroProps";
|
|
2
2
|
import type { MultiButtonBarProps } from "../../molecules/selectors/multibuttonbar/MultiButtonBarProps";
|
|
3
|
-
import type {
|
|
3
|
+
import type { FilterBarProps } from "../../molecules/selectors/filterbar/FilterBarProps";
|
|
4
|
+
import type { FilterBarButtonProps } from "../../molecules/selectors/filterbar/FilterBarButtonProps";
|
|
5
|
+
import type { DropdownFilterProps } from "../../molecules/selectors/filterbar/DropdownFilterProps";
|
|
6
|
+
import type { SearchFilterProps } from "../../molecules/selectors/filterbar/SearchFilterProps";
|
|
4
7
|
import type { DecorGridProps } from "../../organisms/decorgrid/DecorGridProps";
|
|
5
8
|
import type { VerticalCheckboxListCollectionProps } from "../../organisms/verticalcheckboxlistcollection/VerticalCheckboxListCollectionProps";
|
|
6
9
|
export type CategorySceneProps = {
|
|
7
10
|
standardCopyHeroProps: StandardCopyHeroProps;
|
|
8
11
|
multiButtonBarProps: MultiButtonBarProps;
|
|
9
|
-
|
|
12
|
+
filterBarProps: FilterBarProps;
|
|
13
|
+
filterToggleButtonProps: FilterBarButtonProps;
|
|
14
|
+
sortDropdownFilterProps: DropdownFilterProps;
|
|
15
|
+
searchFilterProps: SearchFilterProps;
|
|
10
16
|
verticalCheckboxListCollectionProps?: VerticalCheckboxListCollectionProps;
|
|
11
17
|
decorGridProps: DecorGridProps;
|
|
12
18
|
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { StandardCopyHeroProps } from "../../organisms/banner/standardcopyhero/StandardCopyHeroProps";
|
|
2
2
|
import type { MultiButtonBarProps } from "../../molecules/selectors/multibuttonbar/MultiButtonBarProps";
|
|
3
|
-
import type {
|
|
3
|
+
import type { FilterBarProps } from "../../molecules/selectors/filterbar/FilterBarProps";
|
|
4
|
+
import type { DropdownFilterProps } from "../../molecules/selectors/filterbar/DropdownFilterProps";
|
|
4
5
|
import type { ImageGridProps } from "../../organisms/imagegrid/ImageGridProps";
|
|
5
6
|
export type GallerySceneProps = {
|
|
6
7
|
standardCopyHeroProps: StandardCopyHeroProps;
|
|
7
8
|
multiButtonBarProps: MultiButtonBarProps;
|
|
8
|
-
|
|
9
|
+
filterBarProps: FilterBarProps;
|
|
10
|
+
dropdownFilterPropsList: DropdownFilterProps[];
|
|
9
11
|
imageGridProps: ImageGridProps;
|
|
10
12
|
};
|