@farzadbagheri/fb-components 0.1.3 → 0.1.4

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
@@ -2,16 +2,27 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@farzadbagheri/fb-components.svg)](https://www.npmjs.com/package/@farzadbagheri/fb-components)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@farzadbagheri/fb-components.svg)](https://www.npmjs.com/package/@farzadbagheri/fb-components)
5
+ [![CI](https://github.com/BAGHERIFarzad/fb-components/actions/workflows/ci.yml/badge.svg)](https://github.com/BAGHERIFarzad/fb-components/actions/workflows/ci.yml)
5
6
  [![license](https://img.shields.io/npm/l/@farzadbagheri/fb-components.svg)](./LICENSE)
6
7
  [![React](https://img.shields.io/badge/React-18%20%7C%2019-61DAFB?logo=react)](https://react.dev/)
7
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-ready-3178C6?logo=typescript)](https://www.typescriptlang.org/)
9
+ [![Node](https://img.shields.io/badge/Node-%3E%3D18-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
8
10
 
9
- **Production-minded React components for motion, AI interfaces, data visualization, and modern product experiences.**
11
+ **Production-minded React components for motion, AI interfaces, modern landing pages, data visualization, and polished product experiences.**
10
12
 
11
13
  FB Components is a modern React component library built for polished product interfaces. It includes reusable components with TypeScript declarations, ESM/CommonJS builds, category-based entry points, and category-specific CSS so you can import only what you need.
12
14
 
15
+ ## Documentation
16
+
17
+ - [Component API Reference](./COMPONENTS.md)
18
+ - [Usage Examples](./EXAMPLES.md)
19
+ - [Development Guide](./DEVELOPMENT.md)
20
+ - [Contributing](./CONTRIBUTING.md)
21
+ - [Release Guide](./RELEASING.md)
22
+ - [Security Policy](./SECURITY.md)
23
+
13
24
  - **npm:** `@farzadbagheri/fb-components`
14
- - **Current release:** `0.1.0`
25
+ - **Current release:** `0.1.3`
15
26
  - **Website:** https://farzadbagheri.fr/en/components
16
27
  - **GitHub:** https://github.com/BAGHERIFarzad/fb-components
17
28
  - **License:** MIT
@@ -29,7 +40,8 @@ FB Components is a modern React component library built for polished product int
29
40
  - Category-specific CSS exports
30
41
  - Root convenience import
31
42
  - Modern UI, motion, AI, data, hero, landing, and background components
32
- - Simple installation and CSS setup
43
+ - Accessibility-conscious APIs
44
+ - Automated release validation
33
45
 
34
46
  ---
35
47
 
@@ -85,9 +97,25 @@ The root JavaScript entry remains tree-shaking friendly, while `styles.css` incl
85
97
 
86
98
  ---
87
99
 
88
- ## Components
100
+ ## Component catalog
101
+
102
+ FB Components currently includes **22 free public components** across nine categories.
89
103
 
90
- ### Backgrounds
104
+ | Category | Components |
105
+ |---|---|
106
+ | Backgrounds | PredictiveArc, SignalParticles, DotMatrix, GradientMesh, AuroraGrid, NoiseField |
107
+ | Buttons | MagneticButton, GlowButton, GlassButton |
108
+ | Text | RevealText, BlurReveal |
109
+ | UI | SpotlightCard, GlassCard |
110
+ | Motion | GlowCursor, MagneticCursor |
111
+ | AI | AiPromptBox, StreamingResponse |
112
+ | Heroes | SaasLaunchHero |
113
+ | Landing | StartupLanding |
114
+ | Data | AnimatedCounter, RadialProgress, MetricGrid |
115
+
116
+ ---
117
+
118
+ ## Backgrounds
91
119
 
92
120
  ```tsx
93
121
  import {
@@ -96,7 +124,7 @@ import {
96
124
  DotMatrix,
97
125
  GradientMesh,
98
126
  AuroraGrid,
99
- NoiseField
127
+ NoiseField,
100
128
  } from "@farzadbagheri/fb-components/backgrounds";
101
129
 
102
130
  import "@farzadbagheri/fb-components/backgrounds.css";
@@ -111,13 +139,26 @@ Available components:
111
139
  - `AuroraGrid`
112
140
  - `NoiseField`
113
141
 
114
- ### Buttons
142
+ Example:
143
+
144
+ ```tsx
145
+ <PredictiveArc
146
+ color="#9b7cff"
147
+ size={70}
148
+ thickness={3}
149
+ glow={16}
150
+ />
151
+ ```
152
+
153
+ ---
154
+
155
+ ## Buttons
115
156
 
116
157
  ```tsx
117
158
  import {
118
159
  MagneticButton,
119
160
  GlowButton,
120
- GlassButton
161
+ GlassButton,
121
162
  } from "@farzadbagheri/fb-components/buttons";
122
163
 
123
164
  import "@farzadbagheri/fb-components/buttons.css";
@@ -129,12 +170,26 @@ Available components:
129
170
  - `GlowButton`
130
171
  - `GlassButton`
131
172
 
132
- ### Text Animation
173
+ Example:
174
+
175
+ ```tsx
176
+ <GlassButton
177
+ tint="#9b7cff"
178
+ opacity={0.12}
179
+ blur={18}
180
+ >
181
+ Explore
182
+ </GlassButton>
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Text animation
133
188
 
134
189
  ```tsx
135
190
  import {
136
191
  RevealText,
137
- BlurReveal
192
+ BlurReveal,
138
193
  } from "@farzadbagheri/fb-components/text";
139
194
 
140
195
  import "@farzadbagheri/fb-components/text.css";
@@ -145,12 +200,22 @@ Available components:
145
200
  - `RevealText`
146
201
  - `BlurReveal`
147
202
 
148
- ### UI
203
+ Example:
204
+
205
+ ```tsx
206
+ <RevealText>
207
+ Build better interfaces.
208
+ </RevealText>
209
+ ```
210
+
211
+ ---
212
+
213
+ ## UI
149
214
 
150
215
  ```tsx
151
216
  import {
152
217
  SpotlightCard,
153
- GlassCard
218
+ GlassCard,
154
219
  } from "@farzadbagheri/fb-components/ui";
155
220
 
156
221
  import "@farzadbagheri/fb-components/ui.css";
@@ -161,12 +226,23 @@ Available components:
161
226
  - `SpotlightCard`
162
227
  - `GlassCard`
163
228
 
164
- ### Motion
229
+ Example:
230
+
231
+ ```tsx
232
+ <SpotlightCard>
233
+ <h3>AI Platform</h3>
234
+ <p>Build modern AI experiences.</p>
235
+ </SpotlightCard>
236
+ ```
237
+
238
+ ---
239
+
240
+ ## Motion
165
241
 
166
242
  ```tsx
167
243
  import {
168
244
  GlowCursor,
169
- MagneticCursor
245
+ MagneticCursor,
170
246
  } from "@farzadbagheri/fb-components/motion";
171
247
 
172
248
  import "@farzadbagheri/fb-components/motion.css";
@@ -177,12 +253,27 @@ Available components:
177
253
  - `GlowCursor`
178
254
  - `MagneticCursor`
179
255
 
180
- ### AI
256
+ Example:
257
+
258
+ ```tsx
259
+ <MagneticCursor>
260
+ <button
261
+ type="button"
262
+ data-magnetic-target
263
+ >
264
+ Explore
265
+ </button>
266
+ </MagneticCursor>
267
+ ```
268
+
269
+ ---
270
+
271
+ ## AI
181
272
 
182
273
  ```tsx
183
274
  import {
184
275
  AiPromptBox,
185
- StreamingResponse
276
+ StreamingResponse,
186
277
  } from "@farzadbagheri/fb-components/ai";
187
278
 
188
279
  import "@farzadbagheri/fb-components/ai.css";
@@ -193,7 +284,21 @@ Available components:
193
284
  - `AiPromptBox`
194
285
  - `StreamingResponse`
195
286
 
196
- ### Heroes
287
+ Example:
288
+
289
+ ```tsx
290
+ <AiPromptBox
291
+ modelLabel="FB AI · Fast"
292
+ placeholder="Describe your task"
293
+ onSubmit={(value) => {
294
+ console.log(value);
295
+ }}
296
+ />
297
+ ```
298
+
299
+ ---
300
+
301
+ ## Heroes
197
302
 
198
303
  ```tsx
199
304
  import { SaasLaunchHero } from "@farzadbagheri/fb-components/heroes";
@@ -204,7 +309,20 @@ Available component:
204
309
 
205
310
  - `SaasLaunchHero`
206
311
 
207
- ### Landing Pages
312
+ Example:
313
+
314
+ ```tsx
315
+ <SaasLaunchHero
316
+ eyebrow="BUILT FOR MODERN TEAMS"
317
+ title={"Ship faster.\nScale smarter."}
318
+ primaryLabel="Start free"
319
+ secondaryLabel="See demo"
320
+ />
321
+ ```
322
+
323
+ ---
324
+
325
+ ## Landing
208
326
 
209
327
  ```tsx
210
328
  import { StartupLanding } from "@farzadbagheri/fb-components/landing";
@@ -215,13 +333,25 @@ Available component:
215
333
 
216
334
  - `StartupLanding`
217
335
 
218
- ### Data
336
+ Example:
337
+
338
+ ```tsx
339
+ <StartupLanding
340
+ accent="#7d63ff"
341
+ showMetrics
342
+ showFeatures
343
+ />
344
+ ```
345
+
346
+ ---
347
+
348
+ ## Data
219
349
 
220
350
  ```tsx
221
351
  import {
222
352
  AnimatedCounter,
223
353
  RadialProgress,
224
- MetricGrid
354
+ MetricGrid,
225
355
  } from "@farzadbagheri/fb-components/data";
226
356
 
227
357
  import "@farzadbagheri/fb-components/data.css";
@@ -233,6 +363,25 @@ Available components:
233
363
  - `RadialProgress`
234
364
  - `MetricGrid`
235
365
 
366
+ Examples:
367
+
368
+ ```tsx
369
+ <AnimatedCounter
370
+ value={128}
371
+ suffix="K"
372
+ label="ACTIVE USERS"
373
+ delta="+18.4%"
374
+ />
375
+
376
+ <RadialProgress
377
+ value={72}
378
+ label="COMPLETE"
379
+ ariaLabel="Profile completion"
380
+ />
381
+
382
+ <MetricGrid />
383
+ ```
384
+
236
385
  ---
237
386
 
238
387
  ## All root exports
@@ -262,7 +411,7 @@ import {
262
411
  SignalParticles,
263
412
  SpotlightCard,
264
413
  StartupLanding,
265
- StreamingResponse
414
+ StreamingResponse,
266
415
  } from "@farzadbagheri/fb-components";
267
416
  ```
268
417
 
@@ -318,12 +467,36 @@ import { RadialProgress } from "@farzadbagheri/fb-components/data";
318
467
  import "@farzadbagheri/fb-components/data.css";
319
468
 
320
469
  export function ProgressExample() {
321
- return <RadialProgress value={72} />;
470
+ return (
471
+ <RadialProgress
472
+ value={72}
473
+ ariaLabel="Profile completion"
474
+ />
475
+ );
322
476
  }
323
477
  ```
324
478
 
325
479
  ---
326
480
 
481
+ ## React compatibility
482
+
483
+ Supported versions:
484
+
485
+ ```text
486
+ React 18
487
+ React 19
488
+ ```
489
+
490
+ Peer dependency range:
491
+
492
+ ```text
493
+ >=18 <20
494
+ ```
495
+
496
+ FB Components uses standard React APIs and can be integrated into Vite, React Router applications, Next.js client components, and other standard React build systems.
497
+
498
+ ---
499
+
327
500
  ## ESM and CommonJS
328
501
 
329
502
  ### ESM
@@ -357,26 +530,66 @@ The root JavaScript entry can still be tree-shaken by modern bundlers, while the
357
530
 
358
531
  ---
359
532
 
360
- ## Example: AI interface
533
+ ## Accessibility
361
534
 
362
- ```tsx
363
- import {
364
- AiPromptBox,
365
- StreamingResponse
366
- } from "@farzadbagheri/fb-components/ai";
535
+ Accessibility is treated as part of the public component API.
367
536
 
368
- import "@farzadbagheri/fb-components/ai.css";
537
+ Examples include:
369
538
 
370
- export function AiExample() {
371
- return (
372
- <div>
373
- <AiPromptBox />
374
- <StreamingResponse />
375
- </div>
376
- );
377
- }
539
+ - semantic native buttons
540
+ - explicit button types
541
+ - progressbar ARIA semantics
542
+ - descriptive labels where required
543
+ - decorative elements hidden from assistive technology
544
+ - keyboard-compatible native controls
545
+ - accessibility-focused automated tests
546
+
547
+ Applications should still test complete pages in their own accessibility context.
548
+
549
+ ---
550
+
551
+ ## Testing and quality
552
+
553
+ The public component library is covered by automated tests across:
554
+
555
+ - rendering
556
+ - component props
557
+ - interactions
558
+ - keyboard behavior
559
+ - visual configuration
560
+ - accessibility
561
+ - public exports
562
+ - animation behavior
563
+ - lifecycle cleanup
564
+ - edge cases
565
+ - fresh package installation
566
+
567
+ The project also validates:
568
+
569
+ ```text
570
+ TypeScript
571
+ Tests
572
+ Build
573
+ Package size
574
+ Fresh consumer installation
378
575
  ```
379
576
 
577
+ before release.
578
+
579
+ ---
580
+
581
+ ## Package size guard
582
+
583
+ Current release guard limits:
584
+
585
+ ```text
586
+ Packed package: <= 100 kB
587
+ Unpacked package: <= 600 kB
588
+ Files: <= 150
589
+ ```
590
+
591
+ This helps prevent accidental package growth.
592
+
380
593
  ---
381
594
 
382
595
  ## Documentation and live previews
@@ -433,6 +646,8 @@ Issues, bug reports, ideas, and feedback are welcome:
433
646
 
434
647
  https://github.com/BAGHERIFarzad/fb-components/issues
435
648
 
649
+ See `CONTRIBUTING.md` before submitting larger changes.
650
+
436
651
  When reporting a problem, please include:
437
652
 
438
653
  - component name
@@ -445,9 +660,65 @@ When reporting a problem, please include:
445
660
 
446
661
  ---
447
662
 
663
+ ## Development
664
+
665
+ Install dependencies:
666
+
667
+ ```bash
668
+ npm install
669
+ ```
670
+
671
+ Run tests:
672
+
673
+ ```bash
674
+ npm run test
675
+ ```
676
+
677
+ Run coverage:
678
+
679
+ ```bash
680
+ npm run test:coverage
681
+ ```
682
+
683
+ Run type checking:
684
+
685
+ ```bash
686
+ npm run typecheck
687
+ ```
688
+
689
+ Build the package:
690
+
691
+ ```bash
692
+ npm run build
693
+ ```
694
+
695
+ Run complete release validation:
696
+
697
+ ```bash
698
+ npm run release:check
699
+ ```
700
+
701
+ ---
702
+
448
703
  ## Security
449
704
 
450
- Please do not publish secrets, credentials, tokens, or private application data in public issues.
705
+ Please do not publish secrets, credentials, tokens, API keys, or private application data in public issues.
706
+
707
+ See `SECURITY.md` for security reporting guidance.
708
+
709
+ ---
710
+
711
+ ## Developer Documentation
712
+
713
+ For deeper technical documentation:
714
+
715
+ - [Component API Reference](./COMPONENTS.md)
716
+ - [Usage Examples](./EXAMPLES.md)
717
+ - [Development Guide](./DEVELOPMENT.md)
718
+ - [Contributing Guide](./CONTRIBUTING.md)
719
+ - [Release Guide](./RELEASING.md)
720
+ - [Branch Protection](./BRANCH-PROTECTION.md)
721
+ - [Security Policy](./SECURITY.md)
451
722
 
452
723
  ---
453
724
 
@@ -101,6 +101,7 @@ function RadialProgress({
101
101
  trackColor = "#24242c",
102
102
  animated = true,
103
103
  label = "COMPLETE",
104
+ ariaLabel = "Progress",
104
105
  className = "",
105
106
  style,
106
107
  ...props
@@ -127,15 +128,18 @@ function RadialProgress({
127
128
  ["--fb-radial-color"]: color
128
129
  },
129
130
  role: "progressbar",
131
+ "aria-label": ariaLabel,
130
132
  "aria-valuemin": 0,
131
133
  "aria-valuemax": 100,
132
134
  "aria-valuenow": clamped,
135
+ "aria-valuetext": `${Math.round(clamped)}%`,
133
136
  children: [
134
137
  /* @__PURE__ */ jsxRuntime.jsxs(
135
138
  "svg",
136
139
  {
137
140
  viewBox: "0 0 100 100",
138
141
  "aria-hidden": "true",
142
+ focusable: "false",
139
143
  children: [
140
144
  /* @__PURE__ */ jsxRuntime.jsx(
141
145
  "circle",
@@ -168,9 +172,7 @@ function RadialProgress({
168
172
  ),
169
173
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fb-radial-progress__content", children: [
170
174
  /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
171
- Math.round(
172
- clamped
173
- ),
175
+ Math.round(clamped),
174
176
  /* @__PURE__ */ jsxRuntime.jsx("small", { children: "%" })
175
177
  ] }),
176
178
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: label })
@@ -256,5 +258,5 @@ function MetricGrid({
256
258
  exports.AnimatedCounter = AnimatedCounter;
257
259
  exports.MetricGrid = MetricGrid;
258
260
  exports.RadialProgress = RadialProgress;
259
- //# sourceMappingURL=chunk-SQPNHJ6D.cjs.map
260
- //# sourceMappingURL=chunk-SQPNHJ6D.cjs.map
261
+ //# sourceMappingURL=chunk-7PUXKRNW.cjs.map
262
+ //# sourceMappingURL=chunk-7PUXKRNW.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/data/AnimatedCounter.tsx","../src/data/RadialProgress.tsx","../src/data/MetricGrid.tsx"],"names":["useState","useRef","useEffect","jsxs","jsx"],"mappings":"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","file":"chunk-7PUXKRNW.cjs","sourcesContent":["import {\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport type {\n HTMLAttributes,\n} from \"react\";\n\nimport \"./AnimatedCounter.css\";\n\nexport interface AnimatedCounterProps\n extends HTMLAttributes<HTMLDivElement> {\n value?: number;\n duration?: number;\n\n color?: string;\n accent?: string;\n\n fontSize?: number;\n\n prefix?: string;\n suffix?: string;\n\n label?: string;\n delta?: string;\n\n decimals?: number;\n\n className?: string;\n}\n\nexport function AnimatedCounter({\n value = 128,\n duration = 1.5,\n\n color = \"#ffffff\",\n accent = \"#9b7cff\",\n\n fontSize = 72,\n\n prefix = \"\",\n suffix = \"K\",\n\n label =\n \"ACTIVE USERS\",\n\n delta =\n \"+18.4%\",\n\n decimals = 0,\n\n className = \"\",\n style,\n\n ...props\n}: AnimatedCounterProps) {\n const [\n displayed,\n setDisplayed,\n ] =\n useState(0);\n\n const frameRef =\n useRef<number | null>(\n null\n );\n\n useEffect(() => {\n const start =\n performance.now();\n\n const total =\n Math.max(\n duration,\n 0.01\n ) *\n 1000;\n\n function animate(\n now: number\n ) {\n const progress =\n Math.min(\n (\n now -\n start\n ) /\n total,\n 1\n );\n\n const eased =\n 1 -\n Math.pow(\n 1 -\n progress,\n 3\n );\n\n setDisplayed(\n value *\n eased\n );\n\n if (\n progress <\n 1\n ) {\n frameRef.current =\n requestAnimationFrame(\n animate\n );\n }\n }\n\n frameRef.current =\n requestAnimationFrame(\n animate\n );\n\n return () => {\n if (\n frameRef.current !==\n null\n ) {\n cancelAnimationFrame(\n frameRef.current\n );\n }\n };\n }, [\n value,\n duration,\n ]);\n\n return (\n <div\n {...props}\n className={`fb-animated-counter ${className}`}\n style={{\n ...style,\n\n color,\n\n [\"--fb-counter-accent\" as string]:\n accent,\n\n [\"--fb-counter-size\" as string]:\n `${fontSize}px`,\n }}\n >\n <span className=\"fb-animated-counter__label\">\n {label}\n </span>\n\n <strong>\n {prefix}\n\n {displayed.toLocaleString(\n undefined,\n {\n minimumFractionDigits:\n decimals,\n\n maximumFractionDigits:\n decimals,\n }\n )}\n\n {suffix}\n </strong>\n\n {delta && (\n <small>\n {delta}\n </small>\n )}\n </div>\n );\n}","import type {\n HTMLAttributes,\n} from \"react\";\n\nimport \"./RadialProgress.css\";\n\nexport interface RadialProgressProps\n extends HTMLAttributes<HTMLDivElement> {\n value?: number;\n\n size?: number;\n strokeWidth?: number;\n\n color?: string;\n trackColor?: string;\n\n animated?: boolean;\n\n label?: string;\n\n ariaLabel?: string;\n\n className?: string;\n}\n\nexport function RadialProgress({\n value = 72,\n\n size = 180,\n strokeWidth = 10,\n\n color = \"#9b7cff\",\n trackColor = \"#24242c\",\n\n animated = true,\n\n label = \"COMPLETE\",\n\n ariaLabel = \"Progress\",\n\n className = \"\",\n style,\n\n ...props\n}: RadialProgressProps) {\n const clamped =\n Math.min(\n 100,\n Math.max(\n 0,\n value\n )\n );\n\n const radius =\n 50 -\n strokeWidth /\n 2;\n\n const circumference =\n 2 *\n Math.PI *\n radius;\n\n const offset =\n circumference *\n (\n 1 -\n clamped /\n 100\n );\n\n return (\n <div\n {...props}\n className={`fb-radial-progress ${className}`}\n style={{\n ...style,\n\n width:\n size,\n\n height:\n size,\n\n [\"--fb-radial-color\" as string]:\n color,\n }}\n role=\"progressbar\"\n aria-label={ariaLabel}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={clamped}\n aria-valuetext={`${Math.round(clamped)}%`}\n >\n <svg\n viewBox=\"0 0 100 100\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle\n cx=\"50\"\n cy=\"50\"\n r={radius}\n fill=\"none\"\n stroke={trackColor}\n strokeWidth={strokeWidth}\n />\n\n <circle\n cx=\"50\"\n cy=\"50\"\n r={radius}\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n strokeDashoffset={offset}\n className={\n animated\n ? \"fb-radial-progress__value fb-radial-progress__value--animated\"\n : \"fb-radial-progress__value\"\n }\n />\n </svg>\n\n <div className=\"fb-radial-progress__content\">\n <strong>\n {Math.round(clamped)}\n <small>\n %\n </small>\n </strong>\n\n <span>\n {label}\n </span>\n </div>\n </div>\n );\n}","import type {\n HTMLAttributes,\n} from \"react\";\n\nimport \"./MetricGrid.css\";\n\nexport interface MetricItem {\n label: string;\n value: string;\n delta?: string;\n positive?: boolean;\n}\n\nexport interface MetricGridProps\n extends HTMLAttributes<HTMLDivElement> {\n accent?: string;\n background?: string;\n\n columns?: number;\n radius?: number;\n\n items?: MetricItem[];\n\n className?: string;\n}\n\nconst defaultItems:\n MetricItem[] = [\n {\n label:\n \"Revenue\",\n\n value:\n \"$84.2K\",\n\n delta:\n \"+12.6%\",\n\n positive:\n true,\n },\n\n {\n label:\n \"Users\",\n\n value:\n \"18.4K\",\n\n delta:\n \"+8.1%\",\n\n positive:\n true,\n },\n\n {\n label:\n \"Conversion\",\n\n value:\n \"7.8%\",\n\n delta:\n \"+2.4%\",\n\n positive:\n true,\n },\n\n {\n label:\n \"Latency\",\n\n value:\n \"94ms\",\n\n delta:\n \"-11%\",\n\n positive:\n true,\n },\n ];\n\nexport function MetricGrid({\n accent = \"#9b7cff\",\n background = \"#111116\",\n\n columns = 3,\n radius = 18,\n\n items =\n defaultItems,\n\n className = \"\",\n style,\n\n ...props\n}: MetricGridProps) {\n return (\n <div\n {...props}\n className={`fb-metric-grid ${className}`}\n style={{\n ...style,\n\n gridTemplateColumns:\n `repeat(${Math.max(\n 1,\n columns\n )}, minmax(0, 1fr))`,\n\n [\"--fb-metric-accent\" as string]:\n accent,\n\n [\"--fb-metric-background\" as string]:\n background,\n\n [\"--fb-metric-radius\" as string]:\n `${radius}px`,\n }}\n >\n {items.map(\n (\n item\n ) => (\n <article\n key={\n item.label\n }\n >\n <span>\n {\n item.label\n }\n </span>\n\n <strong>\n {\n item.value\n }\n </strong>\n\n {item.delta && (\n <small\n className={\n item.positive ===\n false\n ? \"is-negative\"\n : \"\"\n }\n >\n {\n item.delta\n }\n </small>\n )}\n </article>\n )\n )}\n </div>\n );\n}"]}
@@ -99,6 +99,7 @@ function RadialProgress({
99
99
  trackColor = "#24242c",
100
100
  animated = true,
101
101
  label = "COMPLETE",
102
+ ariaLabel = "Progress",
102
103
  className = "",
103
104
  style,
104
105
  ...props
@@ -125,15 +126,18 @@ function RadialProgress({
125
126
  ["--fb-radial-color"]: color
126
127
  },
127
128
  role: "progressbar",
129
+ "aria-label": ariaLabel,
128
130
  "aria-valuemin": 0,
129
131
  "aria-valuemax": 100,
130
132
  "aria-valuenow": clamped,
133
+ "aria-valuetext": `${Math.round(clamped)}%`,
131
134
  children: [
132
135
  /* @__PURE__ */ jsxs(
133
136
  "svg",
134
137
  {
135
138
  viewBox: "0 0 100 100",
136
139
  "aria-hidden": "true",
140
+ focusable: "false",
137
141
  children: [
138
142
  /* @__PURE__ */ jsx(
139
143
  "circle",
@@ -166,9 +170,7 @@ function RadialProgress({
166
170
  ),
167
171
  /* @__PURE__ */ jsxs("div", { className: "fb-radial-progress__content", children: [
168
172
  /* @__PURE__ */ jsxs("strong", { children: [
169
- Math.round(
170
- clamped
171
- ),
173
+ Math.round(clamped),
172
174
  /* @__PURE__ */ jsx("small", { children: "%" })
173
175
  ] }),
174
176
  /* @__PURE__ */ jsx("span", { children: label })
@@ -252,5 +254,5 @@ function MetricGrid({
252
254
  }
253
255
 
254
256
  export { AnimatedCounter, MetricGrid, RadialProgress };
255
- //# sourceMappingURL=chunk-O2FP27HX.js.map
256
- //# sourceMappingURL=chunk-O2FP27HX.js.map
257
+ //# sourceMappingURL=chunk-P77GGWU6.js.map
258
+ //# sourceMappingURL=chunk-P77GGWU6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/data/AnimatedCounter.tsx","../src/data/RadialProgress.tsx","../src/data/MetricGrid.tsx"],"names":["jsxs","jsx"],"mappings":"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","file":"chunk-P77GGWU6.js","sourcesContent":["import {\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport type {\n HTMLAttributes,\n} from \"react\";\n\nimport \"./AnimatedCounter.css\";\n\nexport interface AnimatedCounterProps\n extends HTMLAttributes<HTMLDivElement> {\n value?: number;\n duration?: number;\n\n color?: string;\n accent?: string;\n\n fontSize?: number;\n\n prefix?: string;\n suffix?: string;\n\n label?: string;\n delta?: string;\n\n decimals?: number;\n\n className?: string;\n}\n\nexport function AnimatedCounter({\n value = 128,\n duration = 1.5,\n\n color = \"#ffffff\",\n accent = \"#9b7cff\",\n\n fontSize = 72,\n\n prefix = \"\",\n suffix = \"K\",\n\n label =\n \"ACTIVE USERS\",\n\n delta =\n \"+18.4%\",\n\n decimals = 0,\n\n className = \"\",\n style,\n\n ...props\n}: AnimatedCounterProps) {\n const [\n displayed,\n setDisplayed,\n ] =\n useState(0);\n\n const frameRef =\n useRef<number | null>(\n null\n );\n\n useEffect(() => {\n const start =\n performance.now();\n\n const total =\n Math.max(\n duration,\n 0.01\n ) *\n 1000;\n\n function animate(\n now: number\n ) {\n const progress =\n Math.min(\n (\n now -\n start\n ) /\n total,\n 1\n );\n\n const eased =\n 1 -\n Math.pow(\n 1 -\n progress,\n 3\n );\n\n setDisplayed(\n value *\n eased\n );\n\n if (\n progress <\n 1\n ) {\n frameRef.current =\n requestAnimationFrame(\n animate\n );\n }\n }\n\n frameRef.current =\n requestAnimationFrame(\n animate\n );\n\n return () => {\n if (\n frameRef.current !==\n null\n ) {\n cancelAnimationFrame(\n frameRef.current\n );\n }\n };\n }, [\n value,\n duration,\n ]);\n\n return (\n <div\n {...props}\n className={`fb-animated-counter ${className}`}\n style={{\n ...style,\n\n color,\n\n [\"--fb-counter-accent\" as string]:\n accent,\n\n [\"--fb-counter-size\" as string]:\n `${fontSize}px`,\n }}\n >\n <span className=\"fb-animated-counter__label\">\n {label}\n </span>\n\n <strong>\n {prefix}\n\n {displayed.toLocaleString(\n undefined,\n {\n minimumFractionDigits:\n decimals,\n\n maximumFractionDigits:\n decimals,\n }\n )}\n\n {suffix}\n </strong>\n\n {delta && (\n <small>\n {delta}\n </small>\n )}\n </div>\n );\n}","import type {\n HTMLAttributes,\n} from \"react\";\n\nimport \"./RadialProgress.css\";\n\nexport interface RadialProgressProps\n extends HTMLAttributes<HTMLDivElement> {\n value?: number;\n\n size?: number;\n strokeWidth?: number;\n\n color?: string;\n trackColor?: string;\n\n animated?: boolean;\n\n label?: string;\n\n ariaLabel?: string;\n\n className?: string;\n}\n\nexport function RadialProgress({\n value = 72,\n\n size = 180,\n strokeWidth = 10,\n\n color = \"#9b7cff\",\n trackColor = \"#24242c\",\n\n animated = true,\n\n label = \"COMPLETE\",\n\n ariaLabel = \"Progress\",\n\n className = \"\",\n style,\n\n ...props\n}: RadialProgressProps) {\n const clamped =\n Math.min(\n 100,\n Math.max(\n 0,\n value\n )\n );\n\n const radius =\n 50 -\n strokeWidth /\n 2;\n\n const circumference =\n 2 *\n Math.PI *\n radius;\n\n const offset =\n circumference *\n (\n 1 -\n clamped /\n 100\n );\n\n return (\n <div\n {...props}\n className={`fb-radial-progress ${className}`}\n style={{\n ...style,\n\n width:\n size,\n\n height:\n size,\n\n [\"--fb-radial-color\" as string]:\n color,\n }}\n role=\"progressbar\"\n aria-label={ariaLabel}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={clamped}\n aria-valuetext={`${Math.round(clamped)}%`}\n >\n <svg\n viewBox=\"0 0 100 100\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle\n cx=\"50\"\n cy=\"50\"\n r={radius}\n fill=\"none\"\n stroke={trackColor}\n strokeWidth={strokeWidth}\n />\n\n <circle\n cx=\"50\"\n cy=\"50\"\n r={radius}\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n strokeDashoffset={offset}\n className={\n animated\n ? \"fb-radial-progress__value fb-radial-progress__value--animated\"\n : \"fb-radial-progress__value\"\n }\n />\n </svg>\n\n <div className=\"fb-radial-progress__content\">\n <strong>\n {Math.round(clamped)}\n <small>\n %\n </small>\n </strong>\n\n <span>\n {label}\n </span>\n </div>\n </div>\n );\n}","import type {\n HTMLAttributes,\n} from \"react\";\n\nimport \"./MetricGrid.css\";\n\nexport interface MetricItem {\n label: string;\n value: string;\n delta?: string;\n positive?: boolean;\n}\n\nexport interface MetricGridProps\n extends HTMLAttributes<HTMLDivElement> {\n accent?: string;\n background?: string;\n\n columns?: number;\n radius?: number;\n\n items?: MetricItem[];\n\n className?: string;\n}\n\nconst defaultItems:\n MetricItem[] = [\n {\n label:\n \"Revenue\",\n\n value:\n \"$84.2K\",\n\n delta:\n \"+12.6%\",\n\n positive:\n true,\n },\n\n {\n label:\n \"Users\",\n\n value:\n \"18.4K\",\n\n delta:\n \"+8.1%\",\n\n positive:\n true,\n },\n\n {\n label:\n \"Conversion\",\n\n value:\n \"7.8%\",\n\n delta:\n \"+2.4%\",\n\n positive:\n true,\n },\n\n {\n label:\n \"Latency\",\n\n value:\n \"94ms\",\n\n delta:\n \"-11%\",\n\n positive:\n true,\n },\n ];\n\nexport function MetricGrid({\n accent = \"#9b7cff\",\n background = \"#111116\",\n\n columns = 3,\n radius = 18,\n\n items =\n defaultItems,\n\n className = \"\",\n style,\n\n ...props\n}: MetricGridProps) {\n return (\n <div\n {...props}\n className={`fb-metric-grid ${className}`}\n style={{\n ...style,\n\n gridTemplateColumns:\n `repeat(${Math.max(\n 1,\n columns\n )}, minmax(0, 1fr))`,\n\n [\"--fb-metric-accent\" as string]:\n accent,\n\n [\"--fb-metric-background\" as string]:\n background,\n\n [\"--fb-metric-radius\" as string]:\n `${radius}px`,\n }}\n >\n {items.map(\n (\n item\n ) => (\n <article\n key={\n item.label\n }\n >\n <span>\n {\n item.label\n }\n </span>\n\n <strong>\n {\n item.value\n }\n </strong>\n\n {item.delta && (\n <small\n className={\n item.positive ===\n false\n ? \"is-negative\"\n : \"\"\n }\n >\n {\n item.delta\n }\n </small>\n )}\n </article>\n )\n )}\n </div>\n );\n}"]}
package/dist/data.cjs CHANGED
@@ -1,20 +1,20 @@
1
1
  'use strict';
2
2
 
3
- var chunkSQPNHJ6D_cjs = require('./chunk-SQPNHJ6D.cjs');
3
+ var chunk7PUXKRNW_cjs = require('./chunk-7PUXKRNW.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "AnimatedCounter", {
8
8
  enumerable: true,
9
- get: function () { return chunkSQPNHJ6D_cjs.AnimatedCounter; }
9
+ get: function () { return chunk7PUXKRNW_cjs.AnimatedCounter; }
10
10
  });
11
11
  Object.defineProperty(exports, "MetricGrid", {
12
12
  enumerable: true,
13
- get: function () { return chunkSQPNHJ6D_cjs.MetricGrid; }
13
+ get: function () { return chunk7PUXKRNW_cjs.MetricGrid; }
14
14
  });
15
15
  Object.defineProperty(exports, "RadialProgress", {
16
16
  enumerable: true,
17
- get: function () { return chunkSQPNHJ6D_cjs.RadialProgress; }
17
+ get: function () { return chunk7PUXKRNW_cjs.RadialProgress; }
18
18
  });
19
19
  //# sourceMappingURL=data.cjs.map
20
20
  //# sourceMappingURL=data.cjs.map