@synertech/ui 0.39.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/LICENSE ADDED
@@ -0,0 +1,37 @@
1
+ Synertech UI License
2
+
3
+ Copyright (c) 2026 Kevin Tremblay. All rights reserved.
4
+
5
+ Permission is granted, free of charge, to any person or organisation obtaining a
6
+ copy of this software and its associated files (the "Software") to install and
7
+ use the Software, and to distribute it as an incorporated part of an
8
+ application, subject to the conditions below.
9
+
10
+ 1. Use. The Software may be installed and used free of charge as a dependency of
11
+ any application, commercial or not, and may be bundled into that application's
12
+ build output.
13
+
14
+ 2. No redistribution. The Software may not be redistributed, republished,
15
+ sublicensed, rented or sold on its own, in source or compiled form, whether
16
+ modified or not. Publishing it, in whole or in substantial part, to any
17
+ package registry or public repository is not permitted.
18
+
19
+ 3. No derivative works. The Software may not be modified, adapted, translated,
20
+ decompiled or reverse engineered in order to create a competing or derivative
21
+ component library. Inspecting and debugging the Software as needed to operate
22
+ an application that depends on it is permitted.
23
+
24
+ 4. Notices. This notice must be preserved in every copy of the Software.
25
+
26
+ 5. Termination. This licence terminates automatically if these conditions are
27
+ breached.
28
+
29
+ The name "Synertech", the Synertech logo and any other Synertech trademarks are
30
+ not covered by this licence.
31
+
32
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
34
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE
35
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
36
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
37
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,343 @@
1
+ # @synertech/ui
2
+
3
+ A TypeScript/React UI component library using Tailwind CSS classes. Published on the public npm registry.
4
+
5
+ 📖 **[View Storybook](https://ui.synertechweb.com/)** — Interactive component documentation
6
+
7
+ ## Installation
8
+
9
+ ### 1. Install the package
10
+
11
+ ```bash
12
+ pnpm add @synertech/ui
13
+ ```
14
+
15
+ No registry configuration, no token: the package is published on the public npm registry.
16
+
17
+ ### 2. Import the styles
18
+
19
+ Import the compiled CSS in your app's entry point (e.g., `layout.tsx`, `_app.tsx`, or `main.tsx`):
20
+
21
+ ```tsx
22
+ import "@synertech/ui/styles.css";
23
+ ```
24
+
25
+ That's it! Components are now fully styled and ready to use. 🎉
26
+
27
+ <details>
28
+ <summary><strong>Advanced: Using your own Tailwind configuration (optional)</strong></summary>
29
+
30
+ If you want to customize the library's Tailwind classes or optimize bundle size, you can skip the CSS import and configure Tailwind to scan the library:
31
+
32
+ ```js
33
+ // tailwind.config.js
34
+ module.exports = {
35
+ content: [
36
+ "./src/**/*.{js,ts,jsx,tsx}",
37
+ "./node_modules/@synertech/ui/dist/**/*.{js,mjs}"
38
+ ],
39
+ safelist: [
40
+ "w-4", "h-4", "w-5", "h-5", "w-6", "h-6",
41
+ "bg-blue-600", "bg-green-600", "bg-purple-600", "bg-orange-600",
42
+ ],
43
+ }
44
+ ```
45
+
46
+ </details>
47
+
48
+ ### 3. Optional: Markdown editing
49
+
50
+ `<HelpButton markdown editable>` uses [MDXEditor](https://mdxeditor.dev/), which is an
51
+ **optional** peer dependency — it pulls in a large dependency tree, so it is not
52
+ installed with the library. Every other component works without it.
53
+
54
+ ```bash
55
+ pnpm add @mdxeditor/editor
56
+ ```
57
+
58
+ ```tsx
59
+ import "@mdxeditor/editor/style.css";
60
+ ```
61
+
62
+ Without the package, the edit mode renders an explanatory message instead of the editor.
63
+
64
+
65
+ ## Usage
66
+
67
+ ### Button
68
+
69
+ ```tsx
70
+ import { Button } from "@synertech/ui";
71
+
72
+ <Button variant="primary" onClick={() => console.log("clicked")}>
73
+ Click me
74
+ </Button>
75
+
76
+ <Button variant="outline" disabled>
77
+ Disabled
78
+ </Button>
79
+ ```
80
+
81
+ ### Input
82
+
83
+ ```tsx
84
+ import { Input } from "@synertech/ui";
85
+
86
+ <Input
87
+ label="Email"
88
+ type="email"
89
+ name="email"
90
+ value={email}
91
+ onChange={(e) => setEmail(e.target.value)}
92
+ />
93
+
94
+ <Input label="Name" inline />
95
+ ```
96
+
97
+ ### Layout (Header & Footer)
98
+
99
+ ```tsx
100
+ import { Header, Footer } from "@synertech/ui";
101
+
102
+ <Header
103
+ logo={<span className="font-bold">MyApp</span>}
104
+ navItems={[
105
+ { label: "Home", href: "/" },
106
+ { label: "About", href: "/about" },
107
+ ]}
108
+ />
109
+
110
+ <Footer copyright="© 2026 MyApp" />
111
+ ```
112
+
113
+ ### Modal
114
+
115
+ ```tsx
116
+ import { Modal } from "@synertech/ui";
117
+
118
+ <Modal
119
+ isOpen={isOpen}
120
+ onClose={() => setIsOpen(false)}
121
+ title="Confirm Action"
122
+ buttonLabel="Confirm"
123
+ onButtonClick={handleConfirm}
124
+ >
125
+ <p>Are you sure you want to proceed?</p>
126
+ </Modal>
127
+ ```
128
+
129
+ `Modal`, `Drawer` and the mobile `Sidebar` are real modal dialogs: `role="dialog"` + `aria-modal`,
130
+ accessible name from the title, focus moved in on open and returned to the
131
+ trigger on close, Tab/Shift+Tab contained, Escape to close, inert background and
132
+ nested dialog support. The same behaviour is available for custom dialogs
133
+ through the exported `useDialogA11y` hook.
134
+
135
+ ### Translating built-in labels
136
+
137
+ ```tsx
138
+ import { UILabelsProvider, frenchUILabels } from "@synertech/ui";
139
+
140
+ <UILabelsProvider labels={frenchUILabels}>
141
+ <App />
142
+ </UILabelsProvider>;
143
+
144
+ // or per instance
145
+ <Modal closeLabel="Fermer la fenêtre" ... />
146
+ <Drawer closeLabel="Fermer le panneau" ... />
147
+ <Sidebar closeLabel="Fermer le menu" ... />
148
+ ```
149
+
150
+ ### Table
151
+
152
+ ```tsx
153
+ import {
154
+ Table,
155
+ TableHeader,
156
+ TableHeaderCell,
157
+ TableBody,
158
+ TableRow,
159
+ TableCell,
160
+ } from "@synertech/ui";
161
+
162
+ <Table>
163
+ <TableHeader>
164
+ <TableHeaderCell>Name</TableHeaderCell>
165
+ <TableHeaderCell>Email</TableHeaderCell>
166
+ </TableHeader>
167
+ <TableBody>
168
+ <TableRow onClick={() => console.log("row clicked")}>
169
+ <TableCell>John Doe</TableCell>
170
+ <TableCell>john@example.com</TableCell>
171
+ </TableRow>
172
+ </TableBody>
173
+ </Table>
174
+ ```
175
+
176
+ ## Available Components
177
+
178
+ | Category | Components |
179
+ | -------- | ------------------------------------------------------------------------------- |
180
+ | Button | `Button` |
181
+ | Form | `Input` |
182
+ | Layout | `Header`, `Footer` |
183
+ | Modal | `Modal` |
184
+ | Table | `Table`, `TableHeader`, `TableHeaderCell`, `TableBody`, `TableRow`, `TableCell` |
185
+
186
+ ## Contributing
187
+
188
+ ### Adding a new component
189
+
190
+ 1. Create the component in the appropriate category: `src/components/<category>/<Component>.tsx`
191
+ 2. Add `"use client"` directive if using React hooks
192
+ 3. Export the component and its props type
193
+ 4. Add export in `src/components/<category>/index.ts`
194
+ 5. Verify: `pnpm typecheck && pnpm build`
195
+ 6. Create a changeset: `pnpm changeset` (see [Releasing](#releasing))
196
+ 7. Commit and push to `main`
197
+
198
+ ### Guidelines
199
+
200
+ - **No MUI** – HTML + Tailwind only
201
+ - **No compiled CSS** – Tailwind classes are applied, not compiled
202
+ - **React as peer dependency** – Don't bundle React
203
+ - **Next.js compatible** – Proper ESM/CJS exports
204
+ - **Use `"use client"`** – Only for components using hooks
205
+ - **Accept `className`** – All components should allow style overrides
206
+ - **Export types** – Each component exports its props type
207
+
208
+ ## Development
209
+
210
+ ```bash
211
+ pnpm build # Build to dist/
212
+ pnpm dev # Build in watch mode
213
+ pnpm typecheck # TypeScript check
214
+ pnpm lint # ESLint check
215
+ pnpm lint:fix # ESLint auto-fix
216
+ pnpm format # Prettier format
217
+ pnpm format:check # Prettier check
218
+ pnpm storybook # Run Storybook locally (port 6006)
219
+ pnpm build-storybook # Build static Storybook
220
+ ```
221
+
222
+ ## Storybook
223
+
224
+ Interactive component documentation is available via Storybook.
225
+
226
+ ### Run locally
227
+
228
+ ```bash
229
+ pnpm storybook
230
+ ```
231
+
232
+ Then open [http://localhost:6006](http://localhost:6006).
233
+
234
+ ### Hosted version
235
+
236
+ Storybook is automatically deployed to GitLab Pages on every push to `main`:
237
+
238
+ 👉 **https://ui.synertechweb.com/**
239
+
240
+ ## Releasing
241
+
242
+ This project uses [Changesets](https://github.com/changesets/changesets) for version management and changelog generation.
243
+
244
+ ### Workflow
245
+
246
+ 1. **Create a changeset** after making changes:
247
+ ```bash
248
+ pnpm changeset
249
+ ```
250
+ This will prompt you to select the version bump type (patch/minor/major) and write a summary.
251
+
252
+ 2. **Commit the changeset file** (`.changeset/*.md`) along with your changes.
253
+
254
+ 3. **When ready to release**, apply the version bump:
255
+ ```bash
256
+ pnpm version-packages
257
+ ```
258
+ This consumes all changesets, bumps `package.json` version, and updates `CHANGELOG.md`.
259
+
260
+ 4. **Commit and push** to `main`:
261
+ ```bash
262
+ git add -A && git commit -m "chore: release vX.Y.Z" && git push
263
+ ```
264
+
265
+ 5. **CI publishes automatically** to the public npm registry.
266
+
267
+ > **Note**: npm versions are immutable. Once published, a version cannot be overwritten. Changesets prevents accidental duplicate publishes.
268
+
269
+ ## Conventions
270
+
271
+ ### `"use client"` directive
272
+
273
+ Only add `"use client"` to components that use React hooks (`useState`, `useEffect`, etc.). Currently:
274
+ - ✅ `Header` – uses `useState` for mobile menu
275
+ - ✅ `Modal` / `Drawer` / `Sidebar` – use `useId` / `forwardRef` and `useDialogA11y`
276
+ - ✅ `UILabelsProvider` – uses React context
277
+ - ❌ All other components – no hooks, no directive needed
278
+
279
+ ### `className` prop
280
+
281
+ All components accept a `className` prop for style customization. Classes are merged using the internal `cn()` utility.
282
+
283
+ ### Styles CSS
284
+
285
+ The library ships with pre-compiled CSS. Simply import it once:
286
+
287
+ ```tsx
288
+ import "@synertech/ui/styles.css";
289
+ ```
290
+
291
+ For advanced customization, see the [installation section](#2-import-the-styles).
292
+
293
+
294
+ ## Table Suite
295
+
296
+ The Table components are designed to be composed together for flexibility:
297
+
298
+ ```
299
+ Table
300
+ ├── TableHeader
301
+ │ └── TableHeaderCell (multiple)
302
+ └── TableBody
303
+ └── TableRow (multiple)
304
+ └── TableCell (multiple)
305
+ ```
306
+
307
+ ### Component Props
308
+
309
+ | Component | Key Props | HTML Element |
310
+ | ----------------- | ----------------------------------- | ------------ |
311
+ | `Table` | `className` | `<table>` |
312
+ | `TableHeader` | `className` | `<thead>` |
313
+ | `TableHeaderCell` | `sortable`, `onClick`, `className` | `<th>` |
314
+ | `TableBody` | `className` | `<tbody>` |
315
+ | `TableRow` | `clickable`, `onClick`, `className` | `<tr>` |
316
+ | `TableCell` | `className` | `<td>` |
317
+
318
+ ### Example with sortable headers
319
+
320
+ ```tsx
321
+ <Table>
322
+ <TableHeader>
323
+ <TableHeaderCell sortable onClick={() => sort("name")}>
324
+ Name ↕
325
+ </TableHeaderCell>
326
+ <TableHeaderCell>Email</TableHeaderCell>
327
+ </TableHeader>
328
+ <TableBody>
329
+ {users.map((user) => (
330
+ <TableRow key={user.id} onClick={() => selectUser(user)}>
331
+ <TableCell>{user.name}</TableCell>
332
+ <TableCell>{user.email}</TableCell>
333
+ </TableRow>
334
+ ))}
335
+ </TableBody>
336
+ </Table>
337
+ ```
338
+
339
+ ## License
340
+
341
+ Free to install and use in your applications, including commercial ones.
342
+ Redistribution and derivative component libraries are not permitted.
343
+ See [LICENSE](LICENSE).
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { cpSync, existsSync, mkdirSync, readFileSync } from "node:fs";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const packageRoot = resolve(__dirname, "..");
9
+ const skillSource = join(packageRoot, ".claude", "skills", "use-synertech-ui");
10
+ const projectRoot = process.cwd();
11
+ const skillDest = join(projectRoot, ".claude", "skills", "use-synertech-ui");
12
+
13
+ // Read package version
14
+ let version = "unknown";
15
+ try {
16
+ const pkg = JSON.parse(
17
+ readFileSync(join(packageRoot, "package.json"), "utf-8")
18
+ );
19
+ version = pkg.version;
20
+ } catch {
21
+ // ignore
22
+ }
23
+
24
+ // Verify source exists
25
+ if (!existsSync(skillSource)) {
26
+ console.error(
27
+ "Error: Claude skill source not found in @synertech/ui package."
28
+ );
29
+ console.error("Expected at:", skillSource);
30
+ process.exit(1);
31
+ }
32
+
33
+ // Check if already installed and up to date
34
+ if (existsSync(skillDest)) {
35
+ const args = process.argv.slice(2);
36
+ if (!args.includes("--force")) {
37
+ console.log("Claude skill 'use-synertech-ui' is already installed.");
38
+ console.log("Use --force to overwrite with the latest version.");
39
+ process.exit(0);
40
+ }
41
+ console.log("Overwriting existing skill...");
42
+ }
43
+
44
+ // Create destination directory and copy
45
+ mkdirSync(dirname(skillDest), { recursive: true });
46
+ cpSync(skillSource, skillDest, { recursive: true });
47
+
48
+ console.log("");
49
+ console.log(` @synertech/ui v${version} — Claude skill installed`);
50
+ console.log("");
51
+ console.log(` Copied to: .claude/skills/use-synertech-ui/`);
52
+ console.log("");
53
+ console.log(" Usage in Claude Code:");
54
+ console.log(" /use-synertech-ui Button");
55
+ console.log(" /use-synertech-ui Select");
56
+ console.log(' /use-synertech-ui comment faire un formulaire');
57
+ console.log(" /use-synertech-ui setup");
58
+ console.log("");
59
+ console.log(" Tip: Add .claude/skills/use-synertech-ui/ to .gitignore");
60
+ console.log(" if you don't want to commit it to your repo.");
61
+ console.log("");