@carbonbits/sixr 1.0.4 → 1.1.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/README.md CHANGED
@@ -1,7 +1,152 @@
1
- ## Sixr
1
+ # Sixr
2
2
 
3
- Component library for carbonbits.
3
+ E-commerce geared React component library for [carbonbits](https://carbonbits.co.ke/sixr).
4
4
 
5
- Contributing Guide
6
- ---
7
- Local machine shuld support nodejs
5
+ Ships ESM + CJS builds with type declarations, and a prebuilt stylesheet. Components
6
+ are React Server Component safe, so they work in the Next.js App Router without a
7
+ `"use client"` boundary.
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ pnpm add @carbonbits/sixr
13
+ ```
14
+
15
+ `react` and `react-dom` are peer dependencies (`^19.0.0`).
16
+
17
+ ## Usage
18
+
19
+ ```tsx
20
+ // app/layout.tsx
21
+ import "@carbonbits/sixr/styles.css";
22
+ ```
23
+
24
+ Each component has its own subpath. Import from there:
25
+
26
+ ```tsx
27
+ // app/cart/page.tsx
28
+ import { Cart, type CartProduct } from "@carbonbits/sixr/cart";
29
+
30
+ const products: CartProduct[] = [
31
+ { name: "Stovetop kettle", price: 1500 },
32
+ { name: "Enamel mug", price: 500 },
33
+ ];
34
+
35
+ export default function Page() {
36
+ return <Cart products={products} currency="KES" locale="en-KE" />;
37
+ }
38
+ ```
39
+
40
+ The root barrel (`@carbonbits/sixr`) re-exports everything and works too, but the
41
+ subpath is the one to reach for.
42
+
43
+ `dist/styles.css` is compiled by Tailwind 4 and contains only the utilities the
44
+ library itself uses, so it is safe to load alongside a consumer's own Tailwind build.
45
+
46
+ ## Contributing
47
+
48
+ Requires Node.js >= 20.19 and pnpm (see the `packageManager` field; `corepack enable`
49
+ picks up the right version).
50
+
51
+ ```sh
52
+ pnpm install
53
+ pnpm storybook # component workbench on :6006
54
+ pnpm test # vitest
55
+ pnpm run lint # biome: lint + format check
56
+ pnpm run lint:fix # biome: apply safe fixes
57
+ pnpm run typecheck
58
+ pnpm run build # dist/ — JS, .d.ts and styles.css
59
+ pnpm run build-storybook
60
+ ```
61
+
62
+ Linting and formatting are both [Biome](https://biomejs.dev/) (`biome.json`); there
63
+ is no ESLint or Prettier. It runs strict: every rule group is on at `error`, `style`
64
+ and `performance` use the full `all` preset, and `--error-on-warnings` means a
65
+ warning fails CI too. The handful of disabled rules each carry a reason in
66
+ `biome.json`, and stories, tests and config files get narrow overrides where a tool
67
+ mandates something the rules forbid (Storybook's `export default meta`, for one).
68
+
69
+ `biome check` also fails on unformatted files, so run `pnpm run lint:fix` before
70
+ pushing. Most editors have a Biome extension that formats on save.
71
+
72
+ ### Adding a component
73
+
74
+ Add it under `src/components/`, then wire it up in three places:
75
+
76
+ 1. an entry in `tsup.config.ts`, so it gets its own bundle
77
+ 2. a matching subpath in the package.json `exports` map
78
+ 3. a re-export from `src/index.ts`, for the barrel
79
+
80
+ Give it a `*.stories.tsx` file too, so Chromatic picks it up.
81
+
82
+ Client components (anything on Radix, or using hooks) need a `"use client"` banner
83
+ on their tsup entry — a directive in the source file does not survive bundling. Not
84
+ wired up yet; there are no client components in the library so far.
85
+
86
+ ## Releasing
87
+
88
+ Releases are automated by [semantic-release](https://semantic-release.gitbook.io/)
89
+ on every push to `master`, driven by
90
+ [conventional commits](https://www.conventionalcommits.org/):
91
+
92
+ | Commit prefix | Release |
93
+ | -------------------------------- | ------- |
94
+ | `fix:` | patch |
95
+ | `feat:` | minor |
96
+ | `feat!:` / `BREAKING CHANGE:` | major |
97
+ | `chore:`, `ci:`, `docs:`, `test:`| none |
98
+
99
+ The pipeline works out the version, writes `CHANGELOG.md`, builds `dist/`, commits
100
+ the bump back to `master`, tags it, and opens a GitHub release.
101
+
102
+ ### Staged publishing
103
+
104
+ npm is moving publishing behind a human approval step, so CI does **not** push the
105
+ package live. It runs `npm stage publish`, which uploads the tarball and parks it.
106
+ A maintainer then approves it with 2FA:
107
+
108
+ ```sh
109
+ npm stage list @carbonbits/sixr
110
+ npm stage view <stage-id> # inspect before approving
111
+ npm stage approve <stage-id> # prompts for 2FA, goes live
112
+ npm stage reject <stage-id> # discard instead
113
+ ```
114
+
115
+ Until approval the version does not appear in `npm view @carbonbits/sixr versions`,
116
+ even though the GitHub release and tag already exist. Staging needs npm >= 11.15.0
117
+ and Node >= 22.14, which CI pins.
118
+
119
+ ### Required secrets
120
+
121
+ | Secret | Used by |
122
+ | -------------------------- | ---------------------------------------------------- |
123
+ | `NPM_STAGING_TOKEN` | `npm stage publish` — a *Read and write (stage only)* granular token |
124
+ | `GH_APP_ID` | the release GitHub App |
125
+ | `GH_APP_PRIVATE_KEY` | that App's private key, **base64-encoded** |
126
+ | `CHROMATIC_PROJECT_TOKEN` | Chromatic publish |
127
+
128
+ Granular tokens lose the ability to publish new versions directly in January 2027,
129
+ which is why the release token is stage-only.
130
+
131
+ `master` carries a ruleset that blocks direct writes, so the release commit and tag
132
+ cannot be pushed with the default `GITHUB_TOKEN`. The workflow mints a short-lived
133
+ installation token from a GitHub App instead, and **that App must be listed in the
134
+ ruleset's bypass list** or the push still fails. The App needs `contents: write` and
135
+ `pull_requests: write` on this repo, nothing more.
136
+
137
+ That installation token is handed to semantic-release as `GITHUB_TOKEN`, and this
138
+ is not interchangeable with `GH_TOKEN`. semantic-release builds its push URL as
139
+ `https://<GH_TOKEN>@github.com/...`, but as
140
+ `https://x-access-token:<GITHUB_TOKEN>@github.com/...` when it detects Actions.
141
+ An App installation token is only accepted in the second form — via `GH_TOKEN` it
142
+ fails on `git ls-remote` with `Invalid username or token`.
143
+
144
+ There is deliberately no `GH_TOKEN` secret. `@semantic-release/github` resolves
145
+ `GH_TOKEN || GITHUB_TOKEN`, so a leftover expired PAT in `GH_TOKEN` silently
146
+ shadows any working token and fails with `EINVALIDGHTOKEN`. If that secret still
147
+ exists in repo settings, delete it.
148
+
149
+ ## Visual review
150
+
151
+ Every push and pull request publishes Storybook to
152
+ [Chromatic](https://www.chromatic.com/) for visual regression review.
package/dist/cart.cjs ADDED
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+
5
+ // src/components/cart/index.tsx
6
+ function formatPrice(value, currency, locale) {
7
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
8
+ value
9
+ );
10
+ }
11
+ function Cart({
12
+ products = [],
13
+ currency = "KES",
14
+ locale = "en-KE"
15
+ }) {
16
+ const total = products.reduce((sum, product) => sum + product.price, 0);
17
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cart flex w-full max-w-md flex-col gap-4 rounded-lg border border-gray-200 bg-white p-4", children: [
18
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-gray-900", children: "Cart" }),
19
+ products.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Your cart is empty." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
20
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col divide-y divide-gray-100", children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsxs(
21
+ "li",
22
+ {
23
+ className: "flex items-baseline justify-between gap-4 py-2",
24
+ children: [
25
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-800", children: product.name }),
26
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm tabular-nums text-gray-600", children: formatPrice(product.price, currency, locale) })
27
+ ]
28
+ },
29
+ product.id ?? product.name
30
+ )) }),
31
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between gap-4 border-t border-gray-200 pt-2", children: [
32
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-900", children: "Total" }),
33
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold tabular-nums text-gray-900", children: formatPrice(total, currency, locale) })
34
+ ] })
35
+ ] })
36
+ ] });
37
+ }
38
+
39
+ exports.Cart = Cart;
40
+ //# sourceMappingURL=cart.cjs.map
41
+ //# sourceMappingURL=cart.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/cart/index.tsx"],"names":["jsxs","jsx","Fragment"],"mappings":";;;;;AAkBA,SAAS,WAAA,CAAY,KAAA,EAAe,QAAA,EAAkB,MAAA,EAAgB;AACpE,EAAA,OAAO,IAAI,KAAK,YAAA,CAAa,MAAA,EAAQ,EAAE,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU,CAAA,CAAE,MAAA;AAAA,IACpE;AAAA,GACF;AACF;AAEO,SAAS,IAAA,CAAK;AAAA,EACnB,WAAW,EAAC;AAAA,EACZ,QAAA,GAAW,KAAA;AAAA,EACX,MAAA,GAAS;AACX,CAAA,EAAc;AACZ,EAAA,MAAM,KAAA,GAAQ,SAAS,MAAA,CAAO,CAAC,KAAK,OAAA,KAAY,GAAA,GAAM,OAAA,CAAQ,KAAA,EAAO,CAAC,CAAA;AAEtE,EAAA,uBACEA,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yFAAA,EACb,QAAA,EAAA;AAAA,oBAAAC,cAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,qCAAA,EAAsC,QAAA,EAAA,MAAA,EAAI,CAAA;AAAA,IAEvD,QAAA,CAAS,WAAW,CAAA,mBACnBA,cAAA,CAAC,OAAE,SAAA,EAAU,uBAAA,EAAwB,QAAA,EAAA,qBAAA,EAAmB,CAAA,mBAExDD,eAAA,CAAAE,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAAD,cAAA,CAAC,QAAG,SAAA,EAAU,wCAAA,EACX,QAAA,EAAA,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,qBACbD,eAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAU,gDAAA;AAAA,UAEV,QAAA,EAAA;AAAA,4BAAAC,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uBAAA,EAAyB,QAAA,EAAA,OAAA,CAAQ,IAAA,EAAK,CAAA;AAAA,4BACtDA,cAAA,CAAC,UAAK,SAAA,EAAU,oCAAA,EACb,sBAAY,OAAA,CAAQ,KAAA,EAAO,QAAA,EAAU,MAAM,CAAA,EAC9C;AAAA;AAAA,SAAA;AAAA,QANK,OAAA,CAAQ,MAAM,OAAA,CAAQ;AAAA,OAQ9B,CAAA,EACH,CAAA;AAAA,sBAEAD,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yEAAA,EACb,QAAA,EAAA;AAAA,wBAAAC,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EAAoC,QAAA,EAAA,OAAA,EAAK,CAAA;AAAA,wBACzDA,cAAA,CAAC,UAAK,SAAA,EAAU,kDAAA,EACb,sBAAY,KAAA,EAAO,QAAA,EAAU,MAAM,CAAA,EACtC;AAAA,OAAA,EACF;AAAA,KAAA,EACF;AAAA,GAAA,EAEJ,CAAA;AAEJ","file":"cart.cjs","sourcesContent":["export type CartProduct = {\n /**\n * Stable identity for this line, used as the React key. Falls back to `name`,\n * so pass an `id` whenever a cart can hold two lines with the same name.\n */\n id?: string;\n name: string;\n price: number;\n};\n\nexport type CartProps = {\n products?: CartProduct[];\n /** ISO 4217 code used to format prices. */\n currency?: string;\n /** BCP 47 locale used to format prices. */\n locale?: string;\n};\n\nfunction formatPrice(value: number, currency: string, locale: string) {\n return new Intl.NumberFormat(locale, { style: \"currency\", currency }).format(\n value,\n );\n}\n\nexport function Cart({\n products = [],\n currency = \"KES\",\n locale = \"en-KE\",\n}: CartProps) {\n const total = products.reduce((sum, product) => sum + product.price, 0);\n\n return (\n <div className=\"cart flex w-full max-w-md flex-col gap-4 rounded-lg border border-gray-200 bg-white p-4\">\n <h1 className=\"text-xl font-semibold text-gray-900\">Cart</h1>\n\n {products.length === 0 ? (\n <p className=\"text-sm text-gray-500\">Your cart is empty.</p>\n ) : (\n <>\n <ul className=\"flex flex-col divide-y divide-gray-100\">\n {products.map((product) => (\n <li\n key={product.id ?? product.name}\n className=\"flex items-baseline justify-between gap-4 py-2\"\n >\n <span className=\"text-sm text-gray-800\">{product.name}</span>\n <span className=\"text-sm tabular-nums text-gray-600\">\n {formatPrice(product.price, currency, locale)}\n </span>\n </li>\n ))}\n </ul>\n\n <div className=\"flex items-baseline justify-between gap-4 border-t border-gray-200 pt-2\">\n <span className=\"text-sm font-medium text-gray-900\">Total</span>\n <span className=\"text-sm font-semibold tabular-nums text-gray-900\">\n {formatPrice(total, currency, locale)}\n </span>\n </div>\n </>\n )}\n </div>\n );\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import * as react from 'react';
2
+
3
+ type CartProduct = {
4
+ /**
5
+ * Stable identity for this line, used as the React key. Falls back to `name`,
6
+ * so pass an `id` whenever a cart can hold two lines with the same name.
7
+ */
8
+ id?: string;
9
+ name: string;
10
+ price: number;
11
+ };
12
+ type CartProps = {
13
+ products?: CartProduct[];
14
+ /** ISO 4217 code used to format prices. */
15
+ currency?: string;
16
+ /** BCP 47 locale used to format prices. */
17
+ locale?: string;
18
+ };
19
+ declare function Cart({ products, currency, locale, }: CartProps): react.JSX.Element;
20
+
21
+ export { Cart, type CartProduct, type CartProps };
package/dist/cart.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import * as react from 'react';
2
+
3
+ type CartProduct = {
4
+ /**
5
+ * Stable identity for this line, used as the React key. Falls back to `name`,
6
+ * so pass an `id` whenever a cart can hold two lines with the same name.
7
+ */
8
+ id?: string;
9
+ name: string;
10
+ price: number;
11
+ };
12
+ type CartProps = {
13
+ products?: CartProduct[];
14
+ /** ISO 4217 code used to format prices. */
15
+ currency?: string;
16
+ /** BCP 47 locale used to format prices. */
17
+ locale?: string;
18
+ };
19
+ declare function Cart({ products, currency, locale, }: CartProps): react.JSX.Element;
20
+
21
+ export { Cart, type CartProduct, type CartProps };
package/dist/cart.js ADDED
@@ -0,0 +1,3 @@
1
+ export { Cart } from './chunk-BHSOSXTU.js';
2
+ //# sourceMappingURL=cart.js.map
3
+ //# sourceMappingURL=cart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"cart.js"}
@@ -0,0 +1,39 @@
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+
3
+ // src/components/cart/index.tsx
4
+ function formatPrice(value, currency, locale) {
5
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
6
+ value
7
+ );
8
+ }
9
+ function Cart({
10
+ products = [],
11
+ currency = "KES",
12
+ locale = "en-KE"
13
+ }) {
14
+ const total = products.reduce((sum, product) => sum + product.price, 0);
15
+ return /* @__PURE__ */ jsxs("div", { className: "cart flex w-full max-w-md flex-col gap-4 rounded-lg border border-gray-200 bg-white p-4", children: [
16
+ /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-gray-900", children: "Cart" }),
17
+ products.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: "Your cart is empty." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
18
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-col divide-y divide-gray-100", children: products.map((product) => /* @__PURE__ */ jsxs(
19
+ "li",
20
+ {
21
+ className: "flex items-baseline justify-between gap-4 py-2",
22
+ children: [
23
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-800", children: product.name }),
24
+ /* @__PURE__ */ jsx("span", { className: "text-sm tabular-nums text-gray-600", children: formatPrice(product.price, currency, locale) })
25
+ ]
26
+ },
27
+ product.id ?? product.name
28
+ )) }),
29
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-4 border-t border-gray-200 pt-2", children: [
30
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-900", children: "Total" }),
31
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold tabular-nums text-gray-900", children: formatPrice(total, currency, locale) })
32
+ ] })
33
+ ] })
34
+ ] });
35
+ }
36
+
37
+ export { Cart };
38
+ //# sourceMappingURL=chunk-BHSOSXTU.js.map
39
+ //# sourceMappingURL=chunk-BHSOSXTU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/cart/index.tsx"],"names":[],"mappings":";;;AAkBA,SAAS,WAAA,CAAY,KAAA,EAAe,QAAA,EAAkB,MAAA,EAAgB;AACpE,EAAA,OAAO,IAAI,KAAK,YAAA,CAAa,MAAA,EAAQ,EAAE,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU,CAAA,CAAE,MAAA;AAAA,IACpE;AAAA,GACF;AACF;AAEO,SAAS,IAAA,CAAK;AAAA,EACnB,WAAW,EAAC;AAAA,EACZ,QAAA,GAAW,KAAA;AAAA,EACX,MAAA,GAAS;AACX,CAAA,EAAc;AACZ,EAAA,MAAM,KAAA,GAAQ,SAAS,MAAA,CAAO,CAAC,KAAK,OAAA,KAAY,GAAA,GAAM,OAAA,CAAQ,KAAA,EAAO,CAAC,CAAA;AAEtE,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yFAAA,EACb,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,qCAAA,EAAsC,QAAA,EAAA,MAAA,EAAI,CAAA;AAAA,IAEvD,QAAA,CAAS,WAAW,CAAA,mBACnB,GAAA,CAAC,OAAE,SAAA,EAAU,uBAAA,EAAwB,QAAA,EAAA,qBAAA,EAAmB,CAAA,mBAExD,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,QAAG,SAAA,EAAU,wCAAA,EACX,QAAA,EAAA,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,qBACb,IAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAU,gDAAA;AAAA,UAEV,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uBAAA,EAAyB,QAAA,EAAA,OAAA,CAAQ,IAAA,EAAK,CAAA;AAAA,4BACtD,GAAA,CAAC,UAAK,SAAA,EAAU,oCAAA,EACb,sBAAY,OAAA,CAAQ,KAAA,EAAO,QAAA,EAAU,MAAM,CAAA,EAC9C;AAAA;AAAA,SAAA;AAAA,QANK,OAAA,CAAQ,MAAM,OAAA,CAAQ;AAAA,OAQ9B,CAAA,EACH,CAAA;AAAA,sBAEA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yEAAA,EACb,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EAAoC,QAAA,EAAA,OAAA,EAAK,CAAA;AAAA,wBACzD,GAAA,CAAC,UAAK,SAAA,EAAU,kDAAA,EACb,sBAAY,KAAA,EAAO,QAAA,EAAU,MAAM,CAAA,EACtC;AAAA,OAAA,EACF;AAAA,KAAA,EACF;AAAA,GAAA,EAEJ,CAAA;AAEJ","file":"chunk-BHSOSXTU.js","sourcesContent":["export type CartProduct = {\n /**\n * Stable identity for this line, used as the React key. Falls back to `name`,\n * so pass an `id` whenever a cart can hold two lines with the same name.\n */\n id?: string;\n name: string;\n price: number;\n};\n\nexport type CartProps = {\n products?: CartProduct[];\n /** ISO 4217 code used to format prices. */\n currency?: string;\n /** BCP 47 locale used to format prices. */\n locale?: string;\n};\n\nfunction formatPrice(value: number, currency: string, locale: string) {\n return new Intl.NumberFormat(locale, { style: \"currency\", currency }).format(\n value,\n );\n}\n\nexport function Cart({\n products = [],\n currency = \"KES\",\n locale = \"en-KE\",\n}: CartProps) {\n const total = products.reduce((sum, product) => sum + product.price, 0);\n\n return (\n <div className=\"cart flex w-full max-w-md flex-col gap-4 rounded-lg border border-gray-200 bg-white p-4\">\n <h1 className=\"text-xl font-semibold text-gray-900\">Cart</h1>\n\n {products.length === 0 ? (\n <p className=\"text-sm text-gray-500\">Your cart is empty.</p>\n ) : (\n <>\n <ul className=\"flex flex-col divide-y divide-gray-100\">\n {products.map((product) => (\n <li\n key={product.id ?? product.name}\n className=\"flex items-baseline justify-between gap-4 py-2\"\n >\n <span className=\"text-sm text-gray-800\">{product.name}</span>\n <span className=\"text-sm tabular-nums text-gray-600\">\n {formatPrice(product.price, currency, locale)}\n </span>\n </li>\n ))}\n </ul>\n\n <div className=\"flex items-baseline justify-between gap-4 border-t border-gray-200 pt-2\">\n <span className=\"text-sm font-medium text-gray-900\">Total</span>\n <span className=\"text-sm font-semibold tabular-nums text-gray-900\">\n {formatPrice(total, currency, locale)}\n </span>\n </div>\n </>\n )}\n </div>\n );\n}\n"]}
package/dist/index.cjs ADDED
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+
5
+ // src/components/cart/index.tsx
6
+ function formatPrice(value, currency, locale) {
7
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
8
+ value
9
+ );
10
+ }
11
+ function Cart({
12
+ products = [],
13
+ currency = "KES",
14
+ locale = "en-KE"
15
+ }) {
16
+ const total = products.reduce((sum, product) => sum + product.price, 0);
17
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "cart flex w-full max-w-md flex-col gap-4 rounded-lg border border-gray-200 bg-white p-4", children: [
18
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-gray-900", children: "Cart" }),
19
+ products.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "Your cart is empty." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
20
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col divide-y divide-gray-100", children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsxs(
21
+ "li",
22
+ {
23
+ className: "flex items-baseline justify-between gap-4 py-2",
24
+ children: [
25
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-800", children: product.name }),
26
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm tabular-nums text-gray-600", children: formatPrice(product.price, currency, locale) })
27
+ ]
28
+ },
29
+ product.id ?? product.name
30
+ )) }),
31
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline justify-between gap-4 border-t border-gray-200 pt-2", children: [
32
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-900", children: "Total" }),
33
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold tabular-nums text-gray-900", children: formatPrice(total, currency, locale) })
34
+ ] })
35
+ ] })
36
+ ] });
37
+ }
38
+
39
+ exports.Cart = Cart;
40
+ //# sourceMappingURL=index.cjs.map
41
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/cart/index.tsx"],"names":["jsxs","jsx","Fragment"],"mappings":";;;;;AAkBA,SAAS,WAAA,CAAY,KAAA,EAAe,QAAA,EAAkB,MAAA,EAAgB;AACpE,EAAA,OAAO,IAAI,KAAK,YAAA,CAAa,MAAA,EAAQ,EAAE,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU,CAAA,CAAE,MAAA;AAAA,IACpE;AAAA,GACF;AACF;AAEO,SAAS,IAAA,CAAK;AAAA,EACnB,WAAW,EAAC;AAAA,EACZ,QAAA,GAAW,KAAA;AAAA,EACX,MAAA,GAAS;AACX,CAAA,EAAc;AACZ,EAAA,MAAM,KAAA,GAAQ,SAAS,MAAA,CAAO,CAAC,KAAK,OAAA,KAAY,GAAA,GAAM,OAAA,CAAQ,KAAA,EAAO,CAAC,CAAA;AAEtE,EAAA,uBACEA,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yFAAA,EACb,QAAA,EAAA;AAAA,oBAAAC,cAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,qCAAA,EAAsC,QAAA,EAAA,MAAA,EAAI,CAAA;AAAA,IAEvD,QAAA,CAAS,WAAW,CAAA,mBACnBA,cAAA,CAAC,OAAE,SAAA,EAAU,uBAAA,EAAwB,QAAA,EAAA,qBAAA,EAAmB,CAAA,mBAExDD,eAAA,CAAAE,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAAD,cAAA,CAAC,QAAG,SAAA,EAAU,wCAAA,EACX,QAAA,EAAA,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,qBACbD,eAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAU,gDAAA;AAAA,UAEV,QAAA,EAAA;AAAA,4BAAAC,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uBAAA,EAAyB,QAAA,EAAA,OAAA,CAAQ,IAAA,EAAK,CAAA;AAAA,4BACtDA,cAAA,CAAC,UAAK,SAAA,EAAU,oCAAA,EACb,sBAAY,OAAA,CAAQ,KAAA,EAAO,QAAA,EAAU,MAAM,CAAA,EAC9C;AAAA;AAAA,SAAA;AAAA,QANK,OAAA,CAAQ,MAAM,OAAA,CAAQ;AAAA,OAQ9B,CAAA,EACH,CAAA;AAAA,sBAEAD,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yEAAA,EACb,QAAA,EAAA;AAAA,wBAAAC,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EAAoC,QAAA,EAAA,OAAA,EAAK,CAAA;AAAA,wBACzDA,cAAA,CAAC,UAAK,SAAA,EAAU,kDAAA,EACb,sBAAY,KAAA,EAAO,QAAA,EAAU,MAAM,CAAA,EACtC;AAAA,OAAA,EACF;AAAA,KAAA,EACF;AAAA,GAAA,EAEJ,CAAA;AAEJ","file":"index.cjs","sourcesContent":["export type CartProduct = {\n /**\n * Stable identity for this line, used as the React key. Falls back to `name`,\n * so pass an `id` whenever a cart can hold two lines with the same name.\n */\n id?: string;\n name: string;\n price: number;\n};\n\nexport type CartProps = {\n products?: CartProduct[];\n /** ISO 4217 code used to format prices. */\n currency?: string;\n /** BCP 47 locale used to format prices. */\n locale?: string;\n};\n\nfunction formatPrice(value: number, currency: string, locale: string) {\n return new Intl.NumberFormat(locale, { style: \"currency\", currency }).format(\n value,\n );\n}\n\nexport function Cart({\n products = [],\n currency = \"KES\",\n locale = \"en-KE\",\n}: CartProps) {\n const total = products.reduce((sum, product) => sum + product.price, 0);\n\n return (\n <div className=\"cart flex w-full max-w-md flex-col gap-4 rounded-lg border border-gray-200 bg-white p-4\">\n <h1 className=\"text-xl font-semibold text-gray-900\">Cart</h1>\n\n {products.length === 0 ? (\n <p className=\"text-sm text-gray-500\">Your cart is empty.</p>\n ) : (\n <>\n <ul className=\"flex flex-col divide-y divide-gray-100\">\n {products.map((product) => (\n <li\n key={product.id ?? product.name}\n className=\"flex items-baseline justify-between gap-4 py-2\"\n >\n <span className=\"text-sm text-gray-800\">{product.name}</span>\n <span className=\"text-sm tabular-nums text-gray-600\">\n {formatPrice(product.price, currency, locale)}\n </span>\n </li>\n ))}\n </ul>\n\n <div className=\"flex items-baseline justify-between gap-4 border-t border-gray-200 pt-2\">\n <span className=\"text-sm font-medium text-gray-900\">Total</span>\n <span className=\"text-sm font-semibold tabular-nums text-gray-900\">\n {formatPrice(total, currency, locale)}\n </span>\n </div>\n </>\n )}\n </div>\n );\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export { Cart, CartProduct, CartProps } from './cart.cjs';
2
+ import 'react';
@@ -0,0 +1,2 @@
1
+ export { Cart, CartProduct, CartProps } from './cart.js';
2
+ import 'react';
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { Cart } from './chunk-BHSOSXTU.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-white:#fff;--spacing:.25rem;--container-md:28rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.contents{display:contents}.flex{display:flex}.w-full{width:100%}.max-w-md{max-width:var(--container-md)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.items-baseline{align-items:baseline}.justify-between{justify-content:space-between}.gap-4{gap:calc(var(--spacing) * 4)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-100>:not(:last-child)){border-color:var(--color-gray-100)}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-gray-200{border-color:var(--color-gray-200)}.bg-white{background-color:var(--color-white)}.p-4{padding:calc(var(--spacing) * 4)}.py-2{padding-block:calc(var(--spacing) * 2)}.pt-2{padding-top:calc(var(--spacing) * 2)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
package/package.json CHANGED
@@ -1,82 +1,106 @@
1
1
  {
2
2
  "name": "@carbonbits/sixr",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "description": "e-commerce geared component library",
5
5
  "homepage": "https://carbonbits.co.ke/sixr",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/carbonbits/sixr.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/carbonbits/sixr/issues"
12
+ },
6
13
  "license": "MIT",
14
+ "type": "module",
15
+ "sideEffects": [
16
+ "**/*.css"
17
+ ],
7
18
  "files": [
8
- "dist/**"
19
+ "dist"
9
20
  ],
10
- "main": "dist/index.js",
21
+ "main": "./dist/index.cjs",
22
+ "module": "./dist/index.js",
23
+ "types": "./dist/index.d.ts",
24
+ "exports": {
25
+ ".": {
26
+ "import": {
27
+ "types": "./dist/index.d.ts",
28
+ "default": "./dist/index.js"
29
+ },
30
+ "require": {
31
+ "types": "./dist/index.d.cts",
32
+ "default": "./dist/index.cjs"
33
+ }
34
+ },
35
+ "./cart": {
36
+ "import": {
37
+ "types": "./dist/cart.d.ts",
38
+ "default": "./dist/cart.js"
39
+ },
40
+ "require": {
41
+ "types": "./dist/cart.d.cts",
42
+ "default": "./dist/cart.cjs"
43
+ }
44
+ },
45
+ "./styles.css": "./dist/styles.css",
46
+ "./package.json": "./package.json"
47
+ },
11
48
  "publishConfig": {
12
49
  "access": "public"
13
50
  },
14
- "dependencies": {
15
- "@testing-library/jest-dom": "^5.14.1",
16
- "@testing-library/react": "^13.0.0",
17
- "@testing-library/user-event": "^13.2.1",
18
- "@types/jest": "^27.0.1",
19
- "@types/node": "^16.7.13",
20
- "@types/react": "^18.0.0",
21
- "@types/react-dom": "^18.0.0",
22
- "react": "^18.2.0",
23
- "react-dom": "^18.2.0",
24
- "react-scripts": "5.0.1",
25
- "typescript": "^4.4.2",
26
- "web-vitals": "^2.1.0"
51
+ "engines": {
52
+ "node": ">=20.19.0"
27
53
  },
54
+ "packageManager": "pnpm@12.4.2",
28
55
  "scripts": {
29
- "start": "react-scripts start",
30
- "build": "react-scripts build",
31
- "test": "react-scripts test",
32
- "eject": "react-scripts eject",
56
+ "build": "pnpm run build:js && pnpm run build:css",
57
+ "build:js": "tsup",
58
+ "build:css": "tailwindcss -i ./src/styles/index.css -o ./dist/styles.css --minify",
59
+ "typecheck": "tsc --noEmit",
60
+ "lint": "biome check --error-on-warnings",
61
+ "lint:fix": "biome check --write --error-on-warnings",
62
+ "format": "biome format --write",
63
+ "test": "vitest run",
64
+ "test:watch": "vitest",
33
65
  "storybook": "storybook dev -p 6006",
34
- "build-storybook": "storybook build"
35
- },
36
- "eslintConfig": {
37
- "extends": [
38
- "react-app",
39
- "react-app/jest"
40
- ],
41
- "overrides": [
42
- {
43
- "files": [
44
- "**/*.stories.*"
45
- ],
46
- "rules": {
47
- "import/no-anonymous-default-export": "off"
48
- }
49
- }
50
- ]
66
+ "build-storybook": "storybook build",
67
+ "chromatic": "chromatic --exit-zero-on-changes"
51
68
  },
52
- "browserslist": {
53
- "production": [
54
- ">0.2%",
55
- "not dead",
56
- "not op_mini all"
57
- ],
58
- "development": [
59
- "last 1 chrome version",
60
- "last 1 firefox version",
61
- "last 1 safari version"
62
- ]
69
+ "peerDependencies": {
70
+ "react": "^19.0.0",
71
+ "react-dom": "^19.0.0"
63
72
  },
64
73
  "devDependencies": {
65
- "@semantic-release/git": "^10.0.1",
66
- "@storybook/addon-essentials": "^7.0.5",
67
- "@storybook/addon-interactions": "^7.0.5",
68
- "@storybook/addon-links": "^7.0.5",
69
- "@storybook/blocks": "^7.0.5",
70
- "@storybook/preset-create-react-app": "^7.0.5",
71
- "@storybook/react": "^7.0.5",
72
- "@storybook/react-webpack5": "^7.0.5",
73
- "@storybook/testing-library": "^0.0.14-next.2",
74
- "babel-plugin-named-exports-order": "^0.0.2",
75
- "chromatic": "^6.17.4",
76
- "prop-types": "^15.8.1",
77
- "semantic-release": "^21.0.1",
78
- "storybook": "^7.0.5",
79
- "webpack": "^5.79.0"
80
- },
81
- "readme": "ERROR: No README data found!"
74
+ "@biomejs/biome": "^2.5.14",
75
+ "@semantic-release/changelog": "^7.0.0",
76
+ "@semantic-release/exec": "^7.1.0",
77
+ "@semantic-release/git": "^11.0.1",
78
+ "@semantic-release/github": "^12.0.9",
79
+ "@semantic-release/npm": "^13.1.5",
80
+ "@storybook/addon-a11y": "^10.6.0",
81
+ "@storybook/addon-docs": "^10.6.0",
82
+ "@storybook/addon-links": "^10.6.0",
83
+ "@storybook/react-vite": "^10.6.0",
84
+ "@tailwindcss/cli": "^4.3.3",
85
+ "@tailwindcss/vite": "^4.3.3",
86
+ "@testing-library/dom": "^10.4.1",
87
+ "@testing-library/jest-dom": "^7.0.1",
88
+ "@testing-library/react": "^16.3.3",
89
+ "@testing-library/user-event": "^14.6.7",
90
+ "@types/react": "^19.3.0",
91
+ "@types/react-dom": "^19.3.0",
92
+ "@vitejs/plugin-react": "^6.1.1",
93
+ "chromatic": "^18.9.0",
94
+ "conventional-changelog-conventionalcommits": "^9.1.0",
95
+ "jsdom": "^30.1.0",
96
+ "react": "^19.3.0",
97
+ "react-dom": "^19.3.0",
98
+ "semantic-release": "^25.0.9",
99
+ "storybook": "^10.6.0",
100
+ "tailwindcss": "^4.3.3",
101
+ "tsup": "^8.5.1",
102
+ "typescript": "^6.0.3",
103
+ "vite": "^8.3.0",
104
+ "vitest": "^5.0.1"
105
+ }
82
106
  }