jcicl 1.0.71 → 1.0.74
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 +334 -50
- package/Table/Table.js +6381 -6414
- package/assets/style.css +1 -1
- package/assets/tailwind.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,106 +1,390 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Johnson County Component Library (jcicl)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A React component library for Johnson County, Iowa web applications. Built with TypeScript, Vite, MUI, and Emotion. Includes reusable components, form state management, data loading patterns, and page templates.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Quick Start (for consumers)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### Runtime Environment
|
|
8
|
+
|
|
9
|
+
1. Download and install [NVM for Windows](https://github.com/coreybutler/nvm-windows?tab=readme-ov-file)
|
|
8
10
|
2. `nvm install 22.11.0`
|
|
9
11
|
3. `nvm use 22`
|
|
10
12
|
|
|
11
|
-
###
|
|
13
|
+
### Install
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
```bash
|
|
16
|
+
npm install jcicl@latest
|
|
17
|
+
```
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
import Button, { ButtonProps } from 'jcicl/Button';
|
|
17
|
-
import Nav, { NavProps } from 'jcicl/Nav';
|
|
19
|
+
### Usage
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
```tsx
|
|
22
|
+
import Button from 'jcicl/Button';
|
|
23
|
+
import DataPage from 'jcicl/DataPage';
|
|
24
|
+
import { BaseApiClient } from 'jcicl/api';
|
|
25
|
+
import { createFormContext } from 'jcicl/FormContext';
|
|
20
26
|
```
|
|
21
27
|
|
|
22
|
-
###
|
|
28
|
+
### Required CSS & Fonts
|
|
23
29
|
|
|
24
|
-
In your project entry point (
|
|
30
|
+
In your project entry point (`main.tsx`), add:
|
|
25
31
|
|
|
26
|
-
```
|
|
32
|
+
```tsx
|
|
27
33
|
import '@fontsource/roboto/300.css';
|
|
28
34
|
import '@fontsource/roboto/400.css';
|
|
29
35
|
import '@fontsource/roboto/500.css';
|
|
30
36
|
import '@fontsource/roboto/700.css';
|
|
31
37
|
import '@fontsource/material-icons';
|
|
38
|
+
import 'jcicl/assets/tailwind.css';
|
|
32
39
|
import 'overlayscrollbars/overlayscrollbars.css';
|
|
33
40
|
```
|
|
34
41
|
|
|
35
|
-
|
|
42
|
+
---
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
## Key Features
|
|
45
|
+
|
|
46
|
+
### BaseApiClient (`jcicl/api`)
|
|
47
|
+
|
|
48
|
+
Reusable API client base class with timeout, JSON parsing, and standardized error handling. Extend it in your app and add endpoint methods.
|
|
42
49
|
|
|
43
|
-
|
|
50
|
+
[View documentation](src/utils/api.ts)
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
### DataPage (`jcicl/DataPage`)
|
|
46
53
|
|
|
47
|
-
|
|
54
|
+
Generic component that manages async data fetching with loading, error, empty, and happy-path states. Includes `setData` for optimistic CRUD, `withWarnings` for partial success, and `guards` for data-dependent routing.
|
|
55
|
+
|
|
56
|
+
- [Overview (mid-level)](src/components/templates/DataPage/DATA_PAGE_OVERVIEW.md)
|
|
57
|
+
- [Beginner guide](src/components/templates/DataPage/DATA_PAGE_BEGINNER_OVERVIEW.md)
|
|
58
|
+
|
|
59
|
+
### FormContext (`jcicl/FormContext`)
|
|
60
|
+
|
|
61
|
+
Factory function that creates typed React Context + Provider pairs for form state management. Handles text, checkbox, dropdown, phone, zip, and multi-select inputs automatically.
|
|
62
|
+
|
|
63
|
+
- [Overview (mid-level)](src/context/FormContext/FORM_CONTEXT_OVERVIEW.md)
|
|
64
|
+
- [Beginner guide](src/context/FormContext/FORM_CONTEXT_BEGINNER_OVERVIEW.md)
|
|
65
|
+
- [Comparison with react-hook-form](src/context/FormContext/AI_PATTERN_ANALYSIS.md)
|
|
66
|
+
|
|
67
|
+
---
|
|
48
68
|
|
|
49
69
|
## Development
|
|
50
70
|
|
|
51
71
|
### Getting started
|
|
52
72
|
|
|
53
|
-
[
|
|
73
|
+
1. [Ensure your React development environment is set up](https://devops.jc.net/JCIT/Business%20Solutions%20Delivery/_wiki/wikis/Business-Solutions-Delivery.wiki?wikiVersion=GBwikiMaster&pagePath=%2FSetting%20Up%20React&pageId=219)
|
|
74
|
+
2. `npm install` from the root project directory
|
|
75
|
+
3. `npm start` or `npm run storybook` to launch Storybook
|
|
76
|
+
|
|
77
|
+
### Storybook
|
|
54
78
|
|
|
55
|
-
|
|
79
|
+
We use [Storybook](https://storybook.js.org/docs/get-started/frameworks/react-vite?renderer=react) for component documentation and visual testing.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npm run storybook # Start Storybook dev server
|
|
83
|
+
npm start # Same as above
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Component directory structure
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
src/components/
|
|
90
|
+
base/ # Foundational building blocks (Button, Input, Flex, etc.)
|
|
91
|
+
composite/ # Reusable patterns built from base components (Table, Toast, WithLoading, etc.)
|
|
92
|
+
supercomposite/ # Higher complexity composites (FieldGroup, FormFields, etc.)
|
|
93
|
+
templates/ # Full-page layouts (DefaultTemplate, AppContainer, DataPage)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Each component folder contains:
|
|
97
|
+
|
|
98
|
+
- `[Component].tsx` — the component implementation
|
|
99
|
+
- `[Component].stories.tsx` — Storybook documentation
|
|
100
|
+
- `index.ts` — barrel export
|
|
56
101
|
|
|
57
102
|
### Dependencies
|
|
58
103
|
|
|
59
|
-
|
|
104
|
+
- [Material UI](https://mui.com/material-ui/getting-started/) — base UI components (legacy, being phased out)
|
|
105
|
+
- [Emotion](https://emotion.sh/docs/styled) — CSS-in-JS styling (legacy, being phased out)
|
|
106
|
+
- [Tailwind CSS v4](https://tailwindcss.com/) — utility-first CSS (new standard)
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Styling Migration: MUI/Emotion to Tailwind
|
|
111
|
+
|
|
112
|
+
### Current state
|
|
113
|
+
|
|
114
|
+
The library is actively migrating from **Material UI + Emotion** to **Tailwind CSS + fully custom components**. During the transition, both approaches coexist:
|
|
60
115
|
|
|
61
|
-
|
|
116
|
+
- **Legacy components** use MUI base components (`MuiButton`, `MuiDrawer`, etc.) with Emotion `styled()` for visual customization
|
|
117
|
+
- **New and migrated components** use Tailwind utility classes directly in JSX, with CSS custom properties for runtime-dynamic values
|
|
62
118
|
|
|
63
|
-
|
|
119
|
+
### Why Tailwind
|
|
64
120
|
|
|
65
|
-
|
|
121
|
+
**Broader ecosystem adoption.** Tailwind is the most widely used CSS framework in the React ecosystem. New developers joining the team are more likely to already know it than Emotion's CSS-in-JS API. This reduces onboarding time.
|
|
66
122
|
|
|
67
|
-
|
|
123
|
+
**Colocated styles.** Tailwind classes live directly on the JSX element they style. There's no need to scroll between a styled component definition and its usage, or to name every wrapper (`const StyledContainer = styled('div')(...)`). You read the element and its styles together:
|
|
68
124
|
|
|
69
|
-
|
|
125
|
+
```tsx
|
|
126
|
+
// Emotion — style is defined elsewhere, applied by component name
|
|
127
|
+
const CardHeader = styled('div')(({ color }) => ({
|
|
128
|
+
padding: '12px 16px',
|
|
129
|
+
backgroundColor: color,
|
|
130
|
+
borderRadius: '8px',
|
|
131
|
+
fontWeight: 600,
|
|
132
|
+
}));
|
|
133
|
+
<CardHeader color={themeColor}>Title</CardHeader>
|
|
70
134
|
|
|
71
|
-
|
|
135
|
+
// Tailwind — style is on the element
|
|
136
|
+
<div className="p-3 px-4 rounded-lg font-semibold" style={{ backgroundColor: themeColor }}>
|
|
137
|
+
Title
|
|
138
|
+
</div>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**No runtime CSS generation.** Emotion generates CSS at runtime (in the browser), which adds JavaScript execution time on every render. Tailwind generates all CSS at build time — the browser just applies static classes. This improves performance, especially on low-powered devices.
|
|
142
|
+
|
|
143
|
+
**Smaller bundle when tree-shaken.** Emotion ships ~11KB of runtime JavaScript. Tailwind ships zero runtime JS — only the CSS classes you actually use, determined at build time.
|
|
144
|
+
|
|
145
|
+
**Better DevTools experience.** Tailwind classes are visible in the browser's element inspector as real class names. Emotion generates hashed class names (`css-1a2b3c`) that are meaningless in DevTools without the React DevTools extension.
|
|
146
|
+
|
|
147
|
+
**Design token consistency.** Tailwind's theme system (`--spacing`, `--color-*`, etc.) enforces consistent spacing, colors, and typography across components. Emotion relies on manually importing and using a theme object, which is easy to forget or override inconsistently.
|
|
148
|
+
|
|
149
|
+
### Class objects pattern
|
|
150
|
+
|
|
151
|
+
For components with multiple variants or states, define Tailwind class strings as **named constants** at module level. This keeps JSX clean and makes the style definitions reusable, testable, and easy to scan. See the Button component for the canonical example:
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
// Define class strings as named constants — one per variant
|
|
155
|
+
const button1Classes =
|
|
156
|
+
'!bg-[#009200] !h-10 !border-2 !border-transparent !text-white transition-all duration-[313ms] ease-in !rounded-[32px] !font-normal !py-3 !px-8 !text-base shadow-[0px_0px_2px_1px_rgba(100,100,100,0.63)] hover:!bg-[#005c00]';
|
|
157
|
+
|
|
158
|
+
const button2Classes =
|
|
159
|
+
'!bg-[#fab62d] !h-10 !border-2 !border-transparent !text-[#131313] transition-all duration-[313ms] ease-in !rounded-[32px] !font-normal !py-3 !px-8 !text-base shadow-[0px_0px_2px_1px_rgba(100,100,100,0.63)] hover:!bg-[#e0a022]';
|
|
160
|
+
|
|
161
|
+
const customButtonClasses =
|
|
162
|
+
'!h-10 !border-2 !border-transparent transition-all duration-[313ms] ease-in !rounded-[32px] !font-normal !py-3 !px-8 !text-base ...';
|
|
163
|
+
|
|
164
|
+
// Use in JSX — clean, one className per element
|
|
165
|
+
if (variant === 1) return <ButtonBase className={button1Classes} {...props}>{children}</ButtonBase>;
|
|
166
|
+
if (variant === 2) return <ButtonBase className={button2Classes} {...props}>{children}</ButtonBase>;
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Why this pattern:**
|
|
170
|
+
- **Readable** — each variant's full visual definition is in one place, not scattered across JSX
|
|
171
|
+
- **Scannable** — you can compare two variants by looking at two adjacent constants
|
|
172
|
+
- **Composable** — use `clsx()` to merge base classes with conditional classes:
|
|
173
|
+
```tsx
|
|
174
|
+
className={clsx(baseClasses, active ? activeClasses : inactiveClasses)}
|
|
175
|
+
```
|
|
176
|
+
- **Static** — Tailwind's build can scan these constants for class names (unlike template literals with dynamic interpolation)
|
|
72
177
|
|
|
73
|
-
|
|
178
|
+
### Migration rules for contributors
|
|
74
179
|
|
|
75
|
-
|
|
180
|
+
**All new code must use Tailwind.** No new Emotion `styled()` components, no new `css` template literals.
|
|
76
181
|
|
|
77
|
-
|
|
182
|
+
**Updating an existing Emotion component? Rewrite it in Tailwind first.** If you need to modify a component that currently uses Emotion, migrate the entire component to Tailwind before making your changes. This ensures we're always moving forward — every PR that touches a legacy component leaves it fully migrated.
|
|
183
|
+
|
|
184
|
+
The only exception is a **critical production bugfix** where the risk of a full rewrite outweighs the migration benefit. In that case, fix the bug in Emotion, file a follow-up ticket for the Tailwind migration, and note it in the PR description.
|
|
185
|
+
|
|
186
|
+
### Tailwind patterns
|
|
187
|
+
|
|
188
|
+
**Static styles** — use class string constants (see class objects pattern above):
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
const cardClasses = 'rounded-lg p-4 bg-white shadow-md';
|
|
192
|
+
<div className={cardClasses}>...</div>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Runtime-dynamic values** (props that change per-instance) — use CSS custom properties with a wrapper `div`:
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
<div
|
|
199
|
+
style={{
|
|
200
|
+
'--card-bg': backgroundColor,
|
|
201
|
+
'--card-text': textColor,
|
|
202
|
+
display: 'contents',
|
|
203
|
+
} as React.CSSProperties}
|
|
204
|
+
>
|
|
205
|
+
<div className="rounded-lg p-4 !bg-[var(--card-bg)] !text-[var(--card-text)]">
|
|
206
|
+
{children}
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The `display: contents` wrapper is invisible to layout but provides a CSS scope for the custom properties. This avoids Emotion entirely for dynamic values.
|
|
212
|
+
|
|
213
|
+
**Conditional classes** — use `clsx`:
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
import clsx from 'clsx';
|
|
217
|
+
|
|
218
|
+
<button className={clsx(
|
|
219
|
+
baseClasses,
|
|
220
|
+
active ? '!bg-black !text-white' : '!bg-white !text-black',
|
|
221
|
+
)}>
|
|
222
|
+
```
|
|
78
223
|
|
|
79
|
-
|
|
224
|
+
**MUI overrides** — use `!important` prefix (`!bg-*`, `!text-*`) when Tailwind classes need to override MUI's built-in styles during the transition period. Once a component is fully off MUI, the `!` prefixes can be removed.
|
|
80
225
|
|
|
81
|
-
|
|
226
|
+
### Tailwind CSS output
|
|
82
227
|
|
|
83
|
-
|
|
228
|
+
Tailwind CSS is generated at build time via the `@tailwindcss/cli` postbuild step. The output lives at `dist/assets/tailwind.css`. Consuming apps import it in their entry point:
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
import 'jcicl/assets/tailwind.css';
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Only `tailwindcss/theme` and `tailwindcss/utilities` are included — **not** Tailwind's Preflight base reset, which would conflict with existing app styles.
|
|
235
|
+
|
|
236
|
+
### Extending library component styles in consuming apps
|
|
237
|
+
|
|
238
|
+
With Tailwind, consuming apps can extend or override a library component's styles directly via `className` — no custom `style` prop, no wrapper `div`, no Emotion override needed:
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
// Consuming app — add margin and custom width to a library Button
|
|
242
|
+
<Button className="mt-4 w-full" variant={1}>
|
|
243
|
+
Full Width Submit
|
|
244
|
+
</Button>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
This works because Tailwind classes are just CSS classes. The consuming app's Tailwind build scans its own source files, generates the utilities, and they merge naturally with the library's classes. The consumer has full control without the library needing to expose a `style` or `className` forwarding prop for every visual property.
|
|
248
|
+
|
|
249
|
+
**Why this replaces the `style` prop pattern:**
|
|
250
|
+
|
|
251
|
+
The common pattern across our apps has been passing inline `style={{}}` objects to customize component appearance:
|
|
252
|
+
|
|
253
|
+
```tsx
|
|
254
|
+
// Old pattern — inline styles scattered across consuming apps
|
|
255
|
+
<FormContainer style={{ paddingTop: '25px', paddingBottom: '25px' }}>
|
|
256
|
+
<Button style={{ width: '447px', alignSelf: 'center' }}>
|
|
257
|
+
<Flex styles={{ margin: '20px', fontWeight: 500 }}>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
This approach has problems:
|
|
261
|
+
|
|
262
|
+
- **Not reusable** — inline styles can't be shared or composed. If three pages need the same padding, each repeats the same object.
|
|
263
|
+
- **Not responsive** — inline styles don't support media queries, hover states, or focus states. You can't write `style={{ '@media (max-width: 768px)': { padding: '10px' } }}`.
|
|
264
|
+
- **Highest specificity** — inline styles override everything, making it impossible for the component to provide sensible defaults that consumers can opt out of.
|
|
265
|
+
- **No design tokens** — inline styles use raw pixel values (`'25px'`) instead of a shared spacing scale. Nothing enforces consistency across pages.
|
|
266
|
+
- **Not scannable by Tailwind** — inline styles exist at runtime. They add no value to Tailwind's build-time optimization.
|
|
267
|
+
|
|
268
|
+
With Tailwind, all of these are solved:
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
// New pattern — Tailwind classes, composable, responsive, consistent
|
|
272
|
+
<FormContainer className="pt-6 pb-6">
|
|
273
|
+
<Button className="w-[447px] self-center" variant={1}>
|
|
274
|
+
<Flex className="m-5 font-medium">
|
|
275
|
+
|
|
276
|
+
// Responsive? Just add a breakpoint prefix:
|
|
277
|
+
<FormContainer className="pt-4 pb-4 md:pt-6 md:pb-6">
|
|
278
|
+
|
|
279
|
+
// Hover/focus? Just add the state prefix:
|
|
280
|
+
<Button className="w-full hover:w-auto">
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**For component authors:** ensure your components forward `className` to the root element so consumers can extend styles. Most components already do this via `...muiProps` or `...rest` spread. As we migrate off MUI, make `className` an explicit prop.
|
|
284
|
+
|
|
285
|
+
**The goal:** eliminate all `style={{}}` props from consuming apps. Every visual customization should be expressible as a Tailwind class. If it can't be (truly dynamic runtime values like theme colors), use the CSS custom property pattern documented above.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Accessibility (a11y)
|
|
290
|
+
|
|
291
|
+
All components should follow [WCAG 2.1 Level AA](https://www.w3.org/WAI/WCAG21/quickref/?levels=aaa) guidelines. Here's a brief overview of the key principles:
|
|
292
|
+
|
|
293
|
+
### The four principles (POUR)
|
|
294
|
+
|
|
295
|
+
- **Perceivable** — information must be presentable in ways all users can perceive (alt text on images, sufficient color contrast, visible focus indicators)
|
|
296
|
+
- **Operable** — UI must be navigable by keyboard, screen reader, and assistive devices (all interactive elements focusable, no keyboard traps, adequate time limits)
|
|
297
|
+
- **Understandable** — content and operation must be understandable (clear labels, predictable navigation, helpful error messages)
|
|
298
|
+
- **Robust** — content must work with current and future assistive technologies (semantic HTML, proper ARIA attributes, valid markup)
|
|
299
|
+
|
|
300
|
+
### Practical checklist for component development
|
|
301
|
+
|
|
302
|
+
- **Color contrast** — text must have at least 4.5:1 contrast ratio against its background (3:1 for large text). Use [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/) to verify.
|
|
303
|
+
- **Keyboard navigation** — every interactive element must be reachable and operable via keyboard (Tab, Enter, Escape, arrow keys). Test by unplugging your mouse.
|
|
304
|
+
- **Focus indicators** — focused elements must have a visible outline. Never use `outline: none` without providing an alternative focus style.
|
|
305
|
+
- **Semantic HTML** — use `<button>` for buttons (not `<div onClick>`), `<table>` for tabular data, `<nav>` for navigation, `<h1>`-`<h6>` in order.
|
|
306
|
+
- **ARIA labels** — add `aria-label` or `aria-labelledby` to interactive elements that don't have visible text labels (icon buttons, inputs without visible labels).
|
|
307
|
+
- **Screen reader testing** — test with [NVDA](https://www.nvaccess.org/) (free, Windows) or the browser's built-in accessibility inspector.
|
|
308
|
+
- **Form inputs** — every input must have an associated `<label>`. Our `LabeledInput`, `LabeledDropdown`, and `LabeledCheckbox` components handle this automatically.
|
|
309
|
+
- **Error messages** — form errors should be announced to screen readers via `aria-live="polite"` or `role="alert"`.
|
|
310
|
+
|
|
311
|
+
### Resources
|
|
312
|
+
|
|
313
|
+
- [WCAG 2.1 Quick Reference](https://www.w3.org/WAI/WCAG21/quickref/)
|
|
314
|
+
- [WebAIM — Web Accessibility in Mind](https://webaim.org/)
|
|
315
|
+
- [MDN Accessibility Guide](https://developer.mozilla.org/en-US/docs/Web/Accessibility)
|
|
316
|
+
- [A11y Project Checklist](https://www.a11yproject.com/checklist/)
|
|
317
|
+
- [Inclusive Components (book/blog)](https://inclusive-components.design/)
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Building & Testing Locally
|
|
322
|
+
|
|
323
|
+
### Build the library
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
npm run build
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
This runs TypeScript compilation, Vite build, Tailwind CSS generation, and packages everything into `dist/`.
|
|
330
|
+
|
|
331
|
+
### Test locally in a consuming app (without publishing)
|
|
332
|
+
|
|
333
|
+
Instead of publishing to npm, you can install the built `dist/` folder directly into a consuming app:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
# 1. Build the library
|
|
337
|
+
cd /path/to/your/local/JCComponentLibrary
|
|
338
|
+
npm run build
|
|
339
|
+
|
|
340
|
+
# 2. Install from local dist in your consuming app
|
|
341
|
+
cd /path/to/your/consumingApplication # or any consuming app
|
|
342
|
+
npm install /path/to/your/local/JCComponentLibrary/dist
|
|
343
|
+
|
|
344
|
+
# 3. Verify it works
|
|
345
|
+
npm run dev
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
This creates a symlink-like install in `node_modules/jcicl` pointing to the local `dist/` folder. Changes take effect immediately after rebuilding the library — no version bump or publish needed.
|
|
349
|
+
|
|
350
|
+
**To revert to the published version:**
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
npm install jcicl@latest
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Build + publish (when ready to release)
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
npm run bp # Patch version bump (0.0.x), build, and publish
|
|
360
|
+
npm run bpMinor # Minor version bump (0.x.0)
|
|
361
|
+
npm run bpMajor # Major version bump (x.0.0)
|
|
362
|
+
```
|
|
84
363
|
|
|
85
|
-
|
|
86
|
-
2. Export any newly created components in the relevant index files: `(base/(super)composite/templates)/[NewComponent]/index.ts` and `components/index.ts`.
|
|
87
|
-
3. Export any newly created types for the component from `(base/(super)composite/templates)/[NewComponent]/index.ts`
|
|
88
|
-
4. Publish the library and update relevant project dependencies
|
|
364
|
+
The library also auto-publishes on merges to master via the CI pipeline.
|
|
89
365
|
|
|
90
|
-
|
|
366
|
+
---
|
|
91
367
|
|
|
92
|
-
|
|
368
|
+
## Adding a New Component
|
|
93
369
|
|
|
94
|
-
|
|
370
|
+
1. Create the component folder: `src/components/base/MyComponent/`
|
|
371
|
+
2. Create the component: `MyComponent.tsx`
|
|
372
|
+
3. Create stories: `MyComponent.stories.tsx`
|
|
373
|
+
4. Create barrel export: `index.ts` — `export { default, type MyComponentProps } from './MyComponent';`
|
|
374
|
+
5. Add to the main barrel: `src/components/index.ts` — `export { default as MyComponent } from './base/MyComponent';`
|
|
375
|
+
6. Build and test locally (see above)
|
|
376
|
+
7. Publish when ready
|
|
95
377
|
|
|
96
|
-
|
|
378
|
+
---
|
|
97
379
|
|
|
98
|
-
|
|
380
|
+
## Deploying Storybook
|
|
99
381
|
|
|
100
|
-
|
|
382
|
+
Build Storybook with `npm run build-storybook`, then copy all files from `storybook-static/` to the hosting location.
|
|
101
383
|
|
|
102
|
-
|
|
384
|
+
---
|
|
103
385
|
|
|
104
|
-
|
|
386
|
+
## Useful Links
|
|
105
387
|
|
|
106
|
-
|
|
388
|
+
- [Component Library Repository](https://devops.jc.net/JCIT/Business%20Solutions%20Delivery/_git/JCComponentLibrary)
|
|
389
|
+
- [Setting Up React (internal wiki)](https://devops.jc.net/JCIT/Business%20Solutions%20Delivery/_wiki/wikis/Business-Solutions-Delivery.wiki?wikiVersion=GBwikiMaster&pagePath=%2FSetting%20Up%20React&pageId=219)
|
|
390
|
+
- [npm CLI documentation](https://docs.npmjs.com/cli/v9/commands)
|