react-component-by-vite 2.0.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 ADDED
@@ -0,0 +1,759 @@
1
+ # First React Component Test
2
+
3
+ Panduan lengkap membuat library React dari nol hingga publish ke npm.
4
+
5
+ ## 📋 Daftar Isi
6
+
7
+ - [Pendahuluan](#pendahuluan)
8
+ - [Prasyarat](#prasyarat)
9
+ - [1. Setup Proyek Awal](#1-setup-proyek-awal)
10
+ - [2. Membuat Struktur Folder](#2-membuat-struktur-folder)
11
+ - [3. Konfigurasi Vite](#3-konfigurasi-vite)
12
+ - [4. Membuat Komponen React](#4-membuat-komponen-react)
13
+ - [5. Setup Storybook](#5-setup-storybook)
14
+ - [6. Build Library](#6-build-library)
15
+ - [7. Testing (Opsional)](#7-testing-opsional)
16
+ - [8. Publish ke NPM](#8-publish-ke-npm)
17
+ - [Troubleshooting](#troubleshooting)
18
+
19
+ ---
20
+
21
+ ## 📖 Pendahuluan
22
+
23
+ Library ini adalah template untuk membuat **React Component Library** yang dapat dipublikasikan di npm. Library ini dirancang untuk:
24
+
25
+ - ✅ Mendukung CommonJS (UMD) dan ES Modules
26
+ - ✅ Menggunakan Storybook untuk dokumentasi komponen
27
+ - ✅ Optimasi bundle dengan Vite
28
+ - ✅ Support React 18+ dan React 19+
29
+ - ✅ TypeScript & JavaScript support
30
+ - ✅ Testing dengan Vitest
31
+
32
+ ---
33
+
34
+ ## 🔧 Prasyarat
35
+
36
+ Sebelum memulai, pastikan Anda sudah menginstall:
37
+
38
+ - **Node.js** (v18+): [Download di nodejs.org](https://nodejs.org/)
39
+ - **npm** (v9+) atau **yarn** (v3+)
40
+ - **Git**: Untuk version control
41
+ - **npm account**: Untuk publish ke npm ([https://www.npmjs.com/](https://www.npmjs.com/))
42
+
43
+ Verifikasi instalasi:
44
+ ```bash
45
+ node --version
46
+ npm --version
47
+ git --version
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 1. Setup Proyek Awal
53
+
54
+ ### 1.1 Buat Folder Proyek
55
+
56
+ ```bash
57
+ mkdir first-react-component-test
58
+ cd first-react-component-test
59
+ ```
60
+
61
+ ### 1.2 Inisialisasi Git
62
+
63
+ ```bash
64
+ git init
65
+ git config user.name "Nama Anda"
66
+ git config user.email "email@example.com"
67
+ ```
68
+
69
+ ### 1.3 Inisialisasi npm
70
+
71
+ ```bash
72
+ npm init -y
73
+ ```
74
+
75
+ Ini akan membuat `package.json` dengan konfigurasi default.
76
+
77
+ ### 1.4 Update package.json
78
+
79
+ Edit `package.json` dan sesuaikan dengan informasi library Anda:
80
+
81
+ ```json
82
+ {
83
+ "name": "first-react-component-test",
84
+ "version": "1.0.0",
85
+ "description": "Komponen React kustom pertamaku",
86
+ "type": "module",
87
+ "main": "./dist/index.umd.js",
88
+ "module": "./dist/index.es.js",
89
+ "exports": {
90
+ ".": {
91
+ "import": "./dist/index.es.js",
92
+ "require": "./dist/index.umd.js"
93
+ }
94
+ },
95
+ "files": [
96
+ "dist"
97
+ ],
98
+ "scripts": {
99
+ "dev": "vite",
100
+ "build": "vite build",
101
+ "storybook": "storybook dev -p 6006",
102
+ "build-storybook": "storybook build"
103
+ },
104
+ "peerDependencies": {
105
+ "react": "^18.0.0 || ^19.0.0",
106
+ "react-dom": "^18.0.0 || ^19.0.0"
107
+ },
108
+ "keywords": [
109
+ "react",
110
+ "component"
111
+ ],
112
+ "author": "Nama Anda",
113
+ "license": "MIT",
114
+ "repository": {
115
+ "type": "git",
116
+ "url": "https://github.com/username/first-react-component-test"
117
+ },
118
+ "bugs": {
119
+ "url": "https://github.com/username/first-react-component-test/issues"
120
+ },
121
+ "homepage": "https://github.com/username/first-react-component-test#readme"
122
+ }
123
+ ```
124
+
125
+ **Penjelasan field penting:**
126
+ - `name`: Nama package di npm (harus unik)
127
+ - `main`: Entry point untuk CommonJS
128
+ - `module`: Entry point untuk ES Modules
129
+ - `exports`: Mendefinisikan multiple entry points
130
+ - `files`: File yang akan dipublikasikan ke npm
131
+ - `peerDependencies`: Dependency yang harus diinstall oleh user
132
+
133
+ ---
134
+
135
+ ## 2. Membuat Struktur Folder
136
+
137
+ Buat struktur folder proyek:
138
+
139
+ ```bash
140
+ mkdir -p src/stories
141
+ touch src/index.js
142
+ touch .gitignore
143
+ touch .npmrc
144
+ ```
145
+
146
+ Struktur folder akhir:
147
+
148
+ ```
149
+ first-react-component-test/
150
+ ├── node_modules/
151
+ ├── src/
152
+ │ ├── components/
153
+ │ │ ├── ChatTrigger.tsx
154
+ │ │ ├── ChatWindow.tsx
155
+ │ │ └── MyComponent.jsx
156
+ │ ├── stories/
157
+ │ │ ├── ChatTrigger.stories.jsx
158
+ │ │ ├── ChatWindow.stories.jsx
159
+ │ │ └── MyComponent.stories.jsx
160
+ │ └── index.js
161
+ ├── dist/ (generated saat build)
162
+ ├── .gitignore
163
+ ├── .npmrc
164
+ ├── vite.config.js
165
+ ├── package.json
166
+ └── README.md
167
+ ```
168
+
169
+ ### 2.1 Buat .gitignore
170
+
171
+ ```bash
172
+ cat > .gitignore << 'EOF'
173
+ # Dependencies
174
+ node_modules/
175
+ package-lock.json
176
+ yarn.lock
177
+ pnpm-lock.yaml
178
+
179
+ # Build output
180
+ dist/
181
+ build/
182
+
183
+ # Logs
184
+ npm-debug.log*
185
+ yarn-debug.log*
186
+ yarn-error.log*
187
+
188
+ # IDE
189
+ .vscode/
190
+ .idea/
191
+ *.swp
192
+ *.swo
193
+ .DS_Store
194
+
195
+ # Storybook
196
+ storybook-static/
197
+
198
+ # Environment variables
199
+ .env
200
+ .env.local
201
+ EOF
202
+ ```
203
+
204
+ ### 2.2 Buat .npmrc
205
+
206
+ File ini mengonfigurasi npm publishing:
207
+
208
+ ```bash
209
+ cat > .npmrc << 'EOF'
210
+ # Publish public packages
211
+ access=public
212
+
213
+ # Optional: set registry (gunakan jika menggunakan private registry)
214
+ # registry=https://registry.npmjs.org/
215
+ EOF
216
+ ```
217
+
218
+ ---
219
+
220
+ ## 3. Konfigurasi Vite
221
+
222
+ ### 3.1 Install Dependencies
223
+
224
+ ```bash
225
+ npm install --save-dev vite @vitejs/plugin-react
226
+ npm install --save-dev @storybook/react-vite storybook
227
+ ```
228
+
229
+ ### 3.2 Buat vite.config.js
230
+
231
+ ```javascript
232
+ /// <reference types="vitest/config" />
233
+ import { defineConfig } from 'vite';
234
+ import react from '@vitejs/plugin-react';
235
+ import { resolve } from 'path';
236
+
237
+ export default defineConfig({
238
+ plugins: [react()],
239
+ build: {
240
+ lib: {
241
+ // Entry point ke index.js di folder src
242
+ entry: resolve(__dirname, 'src/index.js'),
243
+ name: 'FirstReactComponentTest',
244
+ // Format output: ES module dan UMD
245
+ formats: ['es', 'umd'],
246
+ fileName: (format) => `index.${format}.js`,
247
+ },
248
+ rollupOptions: {
249
+ // Jangan masukkan react ke dalam bundle
250
+ external: ['react', 'react-dom', 'react/jsx-runtime'],
251
+ output: {
252
+ // Konfigurasi global variables untuk UMD
253
+ globals: {
254
+ react: 'React',
255
+ 'react-dom': 'ReactDOM',
256
+ 'react/jsx-runtime': 'jsxRuntime'
257
+ }
258
+ }
259
+ }
260
+ }
261
+ });
262
+ ```
263
+
264
+ ---
265
+
266
+ ## 4. Membuat Komponen React
267
+
268
+ ### 4.1 Buat File Komponen
269
+
270
+ Contoh `src/components/MyComponent.jsx`:
271
+
272
+ ```jsx
273
+ import React from 'react';
274
+ import PropTypes from 'prop-types';
275
+
276
+ export const MyComponent = ({ title, description, onClick }) => {
277
+ return (
278
+ <div style={{
279
+ padding: '20px',
280
+ border: '1px solid #ccc',
281
+ borderRadius: '8px',
282
+ backgroundColor: '#f9f9f9'
283
+ }}>
284
+ <h2>{title}</h2>
285
+ <p>{description}</p>
286
+ <button onClick={onClick}>Click Me</button>
287
+ </div>
288
+ );
289
+ };
290
+
291
+ MyComponent.propTypes = {
292
+ title: PropTypes.string.isRequired,
293
+ description: PropTypes.string,
294
+ onClick: PropTypes.func
295
+ };
296
+
297
+ MyComponent.defaultProps = {
298
+ description: 'Deskripsi komponen',
299
+ onClick: () => console.log('Button clicked')
300
+ };
301
+ ```
302
+
303
+ ### 4.2 Buat File TypeScript (Opsional)
304
+
305
+ Contoh `src/components/ChatTrigger.tsx`:
306
+
307
+ ```typescript
308
+ import React, { FC, ReactNode } from 'react';
309
+
310
+ interface ChatTriggerProps {
311
+ children?: ReactNode;
312
+ onOpen?: () => void;
313
+ variant?: 'primary' | 'secondary';
314
+ }
315
+
316
+ export const ChatTrigger: FC<ChatTriggerProps> = ({
317
+ children = 'Open Chat',
318
+ onOpen,
319
+ variant = 'primary'
320
+ }) => {
321
+ return (
322
+ <button
323
+ onClick={onOpen}
324
+ style={{
325
+ padding: '10px 20px',
326
+ backgroundColor: variant === 'primary' ? '#007bff' : '#6c757d',
327
+ color: '#fff',
328
+ border: 'none',
329
+ borderRadius: '4px',
330
+ cursor: 'pointer'
331
+ }}
332
+ >
333
+ {children}
334
+ </button>
335
+ );
336
+ };
337
+ ```
338
+
339
+ ### 4.3 Buat File Index (Entry Point)
340
+
341
+ `src/index.js`:
342
+
343
+ ```javascript
344
+ // Export semua komponen
345
+ export { MyComponent } from './components/MyComponent.jsx';
346
+ export { ChatTrigger } from './components/ChatTrigger.tsx';
347
+ export { ChatWindow } from './components/ChatWindow.tsx';
348
+
349
+ // Atau dengan named exports
350
+ // export * from './components/MyComponent.jsx';
351
+ // export * from './components/ChatTrigger.tsx';
352
+ // export * from './components/ChatWindow.tsx';
353
+ ```
354
+
355
+ ---
356
+
357
+ ## 5. Setup Storybook
358
+
359
+ Storybook membantu Anda mendokumentasikan dan menguji komponen secara visual.
360
+
361
+ ### 5.1 Install Storybook
362
+
363
+ ```bash
364
+ npx storybook@latest init --type react
365
+ ```
366
+
367
+ Atau manual:
368
+
369
+ ```bash
370
+ npm install --save-dev storybook @storybook/react @storybook/react-vite
371
+ ```
372
+
373
+ ### 5.2 Buat .storybook/main.js
374
+
375
+ ```javascript
376
+ export default {
377
+ stories: ['../src/**/*.stories.{js,jsx,ts,tsx}'],
378
+ addons: [
379
+ '@storybook/addon-links',
380
+ '@storybook/addon-essentials',
381
+ '@storybook/addon-onboarding'
382
+ ],
383
+ framework: '@storybook/react-vite',
384
+ core: {
385
+ builder: '@storybook/builder-vite'
386
+ }
387
+ };
388
+ ```
389
+
390
+ ### 5.3 Buat File Story
391
+
392
+ `src/components/MyComponent.stories.jsx`:
393
+
394
+ ```jsx
395
+ import { MyComponent } from './MyComponent';
396
+
397
+ export default {
398
+ title: 'Components/MyComponent',
399
+ component: MyComponent,
400
+ tags: ['autodocs'],
401
+ };
402
+
403
+ export const Primary = {
404
+ args: {
405
+ title: 'Hello Component',
406
+ description: 'Ini adalah contoh komponen'
407
+ }
408
+ };
409
+
410
+ export const Secondary = {
411
+ args: {
412
+ title: 'Secondary Variant',
413
+ description: 'Variant kedua dari komponen',
414
+ onClick: () => alert('Tombol diklik!')
415
+ }
416
+ };
417
+ ```
418
+
419
+ ### 5.4 Jalankan Storybook
420
+
421
+ ```bash
422
+ npm run storybook
423
+ ```
424
+
425
+ Storybook akan berjalan di `http://localhost:6006`
426
+
427
+ ---
428
+
429
+ ## 6. Build Library
430
+
431
+ ### 6.1 Build untuk NPM
432
+
433
+ ```bash
434
+ npm run build
435
+ ```
436
+
437
+ Ini akan menghasilkan folder `dist/` dengan:
438
+ - `dist/index.es.js` - ES Module format
439
+ - `dist/index.umd.js` - UMD format (untuk browser dan Node.js)
440
+
441
+ ### 6.2 Verifikasi Build
442
+
443
+ ```bash
444
+ ls -la dist/
445
+ ```
446
+
447
+ Seharusnya Anda melihat dua file yang dihasilkan.
448
+
449
+ ### 6.3 Test Build Lokal (Opsional)
450
+
451
+ Untuk test apakah package bisa diinstall:
452
+
453
+ ```bash
454
+ # Di folder proyek lain
455
+ npm install /path/to/first-react-component-test
456
+ ```
457
+
458
+ ---
459
+
460
+ ## 7. Testing (Opsional)
461
+
462
+ ### 7.1 Install Vitest
463
+
464
+ ```bash
465
+ npm install --save-dev vitest @testing-library/react @testing-library/jest-dom
466
+ ```
467
+
468
+ ### 7.2 Setup vitest.config.js
469
+
470
+ ```javascript
471
+ import { defineConfig } from 'vitest/config';
472
+ import react from '@vitejs/plugin-react';
473
+
474
+ export default defineConfig({
475
+ plugins: [react()],
476
+ test: {
477
+ globals: true,
478
+ environment: 'jsdom',
479
+ setupFiles: './src/test/setup.js'
480
+ }
481
+ });
482
+ ```
483
+
484
+ ### 7.3 Buat Test File
485
+
486
+ `src/components/MyComponent.test.jsx`:
487
+
488
+ ```jsx
489
+ import { describe, it, expect } from 'vitest';
490
+ import { render, screen } from '@testing-library/react';
491
+ import { MyComponent } from './MyComponent';
492
+
493
+ describe('MyComponent', () => {
494
+ it('renders with title', () => {
495
+ render(<MyComponent title="Test Title" />);
496
+ expect(screen.getByText('Test Title')).toBeInTheDocument();
497
+ });
498
+
499
+ it('displays description', () => {
500
+ render(<MyComponent title="Test" description="Test Description" />);
501
+ expect(screen.getByText('Test Description')).toBeInTheDocument();
502
+ });
503
+ });
504
+ ```
505
+
506
+ ### 7.4 Update package.json
507
+
508
+ ```json
509
+ {
510
+ "scripts": {
511
+ "test": "vitest",
512
+ "test:ui": "vitest --ui"
513
+ }
514
+ }
515
+ ```
516
+
517
+ ### 7.5 Jalankan Test
518
+
519
+ ```bash
520
+ npm run test
521
+ npm run test:ui
522
+ ```
523
+
524
+ ---
525
+
526
+ ## 8. Publish ke NPM
527
+
528
+ ### 8.1 Persiapan Pre-Publish
529
+
530
+ ```bash
531
+ # 1. Pastikan build sudah terbuat
532
+ npm run build
533
+
534
+ # 2. Verifikasi package.json
535
+ cat package.json | grep -E '"name"|"version"|"main"|"module"'
536
+
537
+ # 3. Commit semua perubahan
538
+ git add .
539
+ git commit -m "Initial commit"
540
+
541
+ # 4. Create tag version
542
+ git tag v1.0.0
543
+ ```
544
+
545
+ ### 8.2 Login ke NPM
546
+
547
+ ```bash
548
+ npm login
549
+ ```
550
+
551
+ Masukkan:
552
+ - Username npm Anda
553
+ - Password
554
+ - Email
555
+ - OTP (One-Time Password) jika enabled
556
+
557
+ **Verifikasi login:**
558
+ ```bash
559
+ npm whoami
560
+ ```
561
+
562
+ ### 8.3 Test Publish (Opsional)
563
+
564
+ Sebelum publish ke npm public, Anda bisa test dengan npm dry-run:
565
+
566
+ ```bash
567
+ npm publish --dry-run
568
+ ```
569
+
570
+ Ini akan menampilkan file apa saja yang akan dipublikasikan tanpa benar-benar publish.
571
+
572
+ ### 8.4 Publish ke NPM
573
+
574
+ ```bash
575
+ npm publish
576
+ ```
577
+
578
+ **Output yang diharapkan:**
579
+ ```
580
+ npm notice
581
+ npm notice 📦 first-react-component-test@1.0.0
582
+ npm notice === Tarball Contents ===
583
+ npm notice 258B dist/index.es.js
584
+ npm notice 312B dist/index.umd.js
585
+ npm notice 456B package.json
586
+ npm notice === Tarball Details ===
587
+ npm notice name: first-react-component-test
588
+ npm notice version: 1.0.0
589
+ npm notice ...
590
+ ```
591
+
592
+ ### 8.5 Verifikasi Publish
593
+
594
+ ```bash
595
+ # Cek di npm registry
596
+ npm view first-react-component-test
597
+
598
+ # Atau kunjungi: https://www.npmjs.com/package/first-react-component-test
599
+ ```
600
+
601
+ ---
602
+
603
+ ## 9. Update dan Re-publish
604
+
605
+ ### 9.1 Semantic Versioning
606
+
607
+ Gunakan format `MAJOR.MINOR.PATCH`:
608
+
609
+ ```
610
+ 1.2.3
611
+ │ │ └─ PATCH (bug fixes)
612
+ │ └─── MINOR (new features, backward compatible)
613
+ └───── MAJOR (breaking changes)
614
+ ```
615
+
616
+ ### 9.2 Update Version
617
+
618
+ ```bash
619
+ # Patch version (1.0.0 → 1.0.1)
620
+ npm version patch
621
+
622
+ # Minor version (1.0.0 → 1.1.0)
623
+ npm version minor
624
+
625
+ # Major version (1.0.0 → 2.0.0)
626
+ npm version major
627
+ ```
628
+
629
+ Ini akan:
630
+ - Update `package.json`
631
+ - Create git tag otomatis
632
+ - Commit changes
633
+
634
+ ### 9.3 Re-publish
635
+
636
+ ```bash
637
+ npm publish
638
+ ```
639
+
640
+ ---
641
+
642
+ ## 🚀 Cara Menggunakan Library
643
+
644
+ Setelah publish, user bisa install library Anda:
645
+
646
+ ```bash
647
+ npm install first-react-component-test
648
+ ```
649
+
650
+ ### Import dan Gunakan
651
+
652
+ **Di React App:**
653
+
654
+ ```jsx
655
+ import React from 'react';
656
+ import { MyComponent, ChatTrigger } from 'first-react-component-test';
657
+
658
+ function App() {
659
+ return (
660
+ <div>
661
+ <MyComponent title="Hello" description="Welcome" />
662
+ <ChatTrigger onOpen={() => console.log('opened')} />
663
+ </div>
664
+ );
665
+ }
666
+
667
+ export default App;
668
+ ```
669
+
670
+ ---
671
+
672
+ ## 🐛 Troubleshooting
673
+
674
+ ### Masalah: "Cannot find module 'react'"
675
+
676
+ **Penyebab:** React tidak diinstall di project yang menggunakan library.
677
+
678
+ **Solusi:**
679
+ ```bash
680
+ npm install react react-dom
681
+ ```
682
+
683
+ ### Masalah: "Module is not defined"
684
+
685
+ **Penyebab:** Konfigurasi Vite tidak benar.
686
+
687
+ **Solusi:** Pastikan `vite.config.js` memiliki:
688
+ ```javascript
689
+ plugins: [react()],
690
+ ```
691
+
692
+ ### Masalah: Build tidak menghasilkan file di dist
693
+
694
+ **Penyebab:** Entry point tidak benar atau index.js kosong.
695
+
696
+ **Solusi:** Verifikasi `src/index.js` export komponen dengan benar:
697
+ ```javascript
698
+ export { MyComponent } from './components/MyComponent.jsx';
699
+ ```
700
+
701
+ ### Masalah: Publish gagal "Package name already exists"
702
+
703
+ **Penyebab:** Nama package sudah terdaftar di npm.
704
+
705
+ **Solusi:** Gunakan nama unik dengan scope:
706
+ ```json
707
+ {
708
+ "name": "@username/first-react-component-test"
709
+ }
710
+ ```
711
+
712
+ ### Masalah: Storybook tidak bisa jalankan komponen
713
+
714
+ **Penyebab:** Dependencies TypeScript tidak terinstall.
715
+
716
+ **Solusi:**
717
+ ```bash
718
+ npm install --save-dev typescript
719
+ npm install --save-dev @types/react @types/react-dom
720
+ ```
721
+
722
+ ---
723
+
724
+ ## 📚 Resources Tambahan
725
+
726
+ - [Vite Documentation](https://vitejs.dev/)
727
+ - [Storybook Documentation](https://storybook.js.org/)
728
+ - [NPM Publishing Guide](https://docs.npmjs.com/packages-and-modules/contributing-packages-to-the-registry)
729
+ - [React Documentation](https://react.dev/)
730
+ - [Semantic Versioning](https://semver.org/)
731
+
732
+ ---
733
+
734
+ ## 📝 Checklist Pre-Publish
735
+
736
+ Sebelum publish, pastikan:
737
+
738
+ - [ ] `package.json` sudah dikonfigurasi dengan benar
739
+ - [ ] `name` unik dan belum terdaftar di npm
740
+ - [ ] `version` sudah diupdate sesuai semantic versioning
741
+ - [ ] `main` dan `module` menunjuk ke file yang benar
742
+ - [ ] `files` include folder `dist`
743
+ - [ ] Build berhasil tanpa error: `npm run build`
744
+ - [ ] Semua file dikompilasi di folder `dist`
745
+ - [ ] Git sudah diinit dan commit pertama sudah dibuat
746
+ - [ ] `.npmrc` sudah dibuat
747
+ - [ ] Sudah login ke npm: `npm whoami`
748
+ - [ ] Storybook running dengan baik
749
+ - [ ] README.md lengkap dengan dokumentasi
750
+
751
+ ---
752
+
753
+ ## 📄 License
754
+
755
+ MIT License - Gratis untuk digunakan secara komersial dan pribadi.
756
+
757
+ ---
758
+
759
+ **Happy Publishing! 🎉**
@@ -0,0 +1,168 @@
1
+ import { useEffect as e, useRef as t, useState as n } from "react";
2
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
3
+ //#region src/MyComponent.jsx
4
+ var a = ({ text: e = "Halo dari NPM!", color: t = "blue" }) => /* @__PURE__ */ r("button", {
5
+ style: {
6
+ padding: "10px 20px",
7
+ backgroundColor: t,
8
+ color: "#fff",
9
+ border: "none",
10
+ borderRadius: "5px",
11
+ cursor: "pointer"
12
+ },
13
+ children: e
14
+ }), o = ({ open: a }) => {
15
+ let [o, s] = n(!1), [c, l] = n([{
16
+ id: 0,
17
+ role: "bot",
18
+ text: "Halo! Saya bisa dibuka pakai tombol maupun langsung lewat props!"
19
+ }]), [u, d] = n(""), [f, p] = n(!1), m = t(null), h = a !== void 0, g = h ? a === "true" || a === !0 : o;
20
+ e(() => {
21
+ if (!h) {
22
+ let e = () => s((e) => !e);
23
+ return window.addEventListener("TOGGLE_CHAT_BOT", e), () => window.removeEventListener("TOGGLE_CHAT_BOT", e);
24
+ }
25
+ }, [h]);
26
+ let _ = async () => {
27
+ let e = u.trim();
28
+ if (!(!e || f)) {
29
+ p(!0), l((t) => [...t, {
30
+ id: Date.now(),
31
+ role: "user",
32
+ text: e
33
+ }]), d("");
34
+ try {
35
+ let t = `Pesan diterima (id: ${(await (await fetch("https://jsonplaceholder.typicode.com/posts", {
36
+ method: "POST",
37
+ headers: { "Content-Type": "application/json" },
38
+ body: JSON.stringify({
39
+ title: "chat-message",
40
+ body: e,
41
+ userId: 1
42
+ })
43
+ })).json())?.id ?? "-"}). Isi: ${e}`;
44
+ l((e) => [...e, {
45
+ id: Date.now() + 1,
46
+ role: "bot",
47
+ text: t
48
+ }]);
49
+ } catch (e) {
50
+ console.error("Gagal mengirim ke API:", e), l((e) => [...e, {
51
+ id: Date.now() + 2,
52
+ role: "bot",
53
+ text: "Maaf, gagal mengirim pesan. Coba lagi."
54
+ }]);
55
+ } finally {
56
+ p(!1);
57
+ }
58
+ }
59
+ };
60
+ return e(() => {
61
+ m.current?.scrollTo({
62
+ top: m.current.scrollHeight,
63
+ behavior: "smooth"
64
+ });
65
+ }, [c.length]), g ? /* @__PURE__ */ i("div", {
66
+ style: {
67
+ position: "fixed",
68
+ bottom: "100px",
69
+ right: "30px",
70
+ width: "350px",
71
+ height: "450px",
72
+ background: "white",
73
+ borderRadius: "10px",
74
+ boxShadow: "0 5px 20px rgba(0,0,0,0.2)",
75
+ display: "flex",
76
+ flexDirection: "column",
77
+ zIndex: 9999,
78
+ fontFamily: "sans-serif"
79
+ },
80
+ children: [
81
+ /* @__PURE__ */ r("div", {
82
+ style: {
83
+ background: "#007bff",
84
+ color: "white",
85
+ padding: "15px",
86
+ borderRadius: "10px 10px 0 0"
87
+ },
88
+ children: /* @__PURE__ */ r("strong", { children: "AI Chat Bot" })
89
+ }),
90
+ /* @__PURE__ */ r("div", {
91
+ ref: m,
92
+ style: {
93
+ flex: 1,
94
+ padding: "15px",
95
+ overflowY: "auto",
96
+ display: "flex",
97
+ flexDirection: "column",
98
+ gap: "8px"
99
+ },
100
+ children: c.map((e) => /* @__PURE__ */ r("div", {
101
+ style: {
102
+ maxWidth: "80%",
103
+ alignSelf: e.role === "user" ? "flex-end" : "flex-start",
104
+ background: e.role === "user" ? "#e6f0ff" : "#f1f1f1",
105
+ padding: "8px 10px",
106
+ borderRadius: "8px",
107
+ wordBreak: "break-word"
108
+ },
109
+ children: e.text
110
+ }, e.id))
111
+ }),
112
+ /* @__PURE__ */ i("div", {
113
+ style: {
114
+ padding: "10px",
115
+ borderTop: "1px solid #eee",
116
+ display: "flex",
117
+ gap: "8px"
118
+ },
119
+ children: [/* @__PURE__ */ r("input", {
120
+ type: "text",
121
+ value: u,
122
+ onChange: (e) => d(e.target.value),
123
+ onKeyDown: (e) => {
124
+ e.key === "Enter" && !e.shiftKey && (e.preventDefault(), _());
125
+ },
126
+ placeholder: "Ketik pesan...",
127
+ style: {
128
+ flex: 1,
129
+ padding: "10px",
130
+ border: "1px solid #ccc",
131
+ borderRadius: "6px",
132
+ outline: "none"
133
+ },
134
+ disabled: f
135
+ }), /* @__PURE__ */ r("button", {
136
+ onClick: _,
137
+ disabled: f || !u.trim(),
138
+ style: {
139
+ background: "#007bff",
140
+ color: "white",
141
+ border: "none",
142
+ padding: "10px 14px",
143
+ borderRadius: "6px",
144
+ cursor: f || !u.trim() ? "not-allowed" : "pointer"
145
+ },
146
+ children: f ? "Mengirim..." : "Kirim"
147
+ })]
148
+ })
149
+ ]
150
+ }) : null;
151
+ }, s = ({ text: e = "💬 Chat" }) => /* @__PURE__ */ r("button", {
152
+ onClick: () => {
153
+ let e = new CustomEvent("TOGGLE_CHAT_BOT");
154
+ window.dispatchEvent(e);
155
+ },
156
+ style: {
157
+ padding: "12px 24px",
158
+ background: "#007bff",
159
+ color: "white",
160
+ border: "none",
161
+ borderRadius: "50px",
162
+ cursor: "pointer",
163
+ boxShadow: "0 4px 10px rgba(0,0,0,0.15)"
164
+ },
165
+ children: e
166
+ });
167
+ //#endregion
168
+ export { s as ChatTrigger, o as ChatWindow, a as MyComponent };
@@ -0,0 +1 @@
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.FirstReactComponentTest={},e.React,e.jsxRuntime))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=Object.create,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty,l=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var s=o(t),l=0,u=s.length,d;l<u;l++)d=s[l],!c.call(e,d)&&d!==n&&i(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=a(t,d))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:r(s(e)),l(t||!e||!e.__esModule?i(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1),e.ChatTrigger=({text:e=`💬 Chat`})=>(0,n.jsx)(`button`,{onClick:()=>{let e=new CustomEvent(`TOGGLE_CHAT_BOT`);window.dispatchEvent(e)},style:{padding:`12px 24px`,background:`#007bff`,color:`white`,border:`none`,borderRadius:`50px`,cursor:`pointer`,boxShadow:`0 4px 10px rgba(0,0,0,0.15)`},children:e}),e.ChatWindow=({open:e})=>{let[r,i]=(0,t.useState)(!1),[a,o]=(0,t.useState)([{id:0,role:`bot`,text:`Halo! Saya bisa dibuka pakai tombol maupun langsung lewat props!`}]),[s,c]=(0,t.useState)(``),[l,u]=(0,t.useState)(!1),d=(0,t.useRef)(null),f=e!==void 0,p=f?e===`true`||e===!0:r;(0,t.useEffect)(()=>{if(!f){let e=()=>i(e=>!e);return window.addEventListener(`TOGGLE_CHAT_BOT`,e),()=>window.removeEventListener(`TOGGLE_CHAT_BOT`,e)}},[f]);let m=async()=>{let e=s.trim();if(!(!e||l)){u(!0),o(t=>[...t,{id:Date.now(),role:`user`,text:e}]),c(``);try{let t=`Pesan diterima (id: ${(await(await fetch(`https://jsonplaceholder.typicode.com/posts`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({title:`chat-message`,body:e,userId:1})})).json())?.id??`-`}). Isi: ${e}`;o(e=>[...e,{id:Date.now()+1,role:`bot`,text:t}])}catch(e){console.error(`Gagal mengirim ke API:`,e),o(e=>[...e,{id:Date.now()+2,role:`bot`,text:`Maaf, gagal mengirim pesan. Coba lagi.`}])}finally{u(!1)}}};return(0,t.useEffect)(()=>{d.current?.scrollTo({top:d.current.scrollHeight,behavior:`smooth`})},[a.length]),p?(0,n.jsxs)(`div`,{style:{position:`fixed`,bottom:`100px`,right:`30px`,width:`350px`,height:`450px`,background:`white`,borderRadius:`10px`,boxShadow:`0 5px 20px rgba(0,0,0,0.2)`,display:`flex`,flexDirection:`column`,zIndex:9999,fontFamily:`sans-serif`},children:[(0,n.jsx)(`div`,{style:{background:`#007bff`,color:`white`,padding:`15px`,borderRadius:`10px 10px 0 0`},children:(0,n.jsx)(`strong`,{children:`AI Chat Bot`})}),(0,n.jsx)(`div`,{ref:d,style:{flex:1,padding:`15px`,overflowY:`auto`,display:`flex`,flexDirection:`column`,gap:`8px`},children:a.map(e=>(0,n.jsx)(`div`,{style:{maxWidth:`80%`,alignSelf:e.role===`user`?`flex-end`:`flex-start`,background:e.role===`user`?`#e6f0ff`:`#f1f1f1`,padding:`8px 10px`,borderRadius:`8px`,wordBreak:`break-word`},children:e.text},e.id))}),(0,n.jsxs)(`div`,{style:{padding:`10px`,borderTop:`1px solid #eee`,display:`flex`,gap:`8px`},children:[(0,n.jsx)(`input`,{type:`text`,value:s,onChange:e=>c(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),m())},placeholder:`Ketik pesan...`,style:{flex:1,padding:`10px`,border:`1px solid #ccc`,borderRadius:`6px`,outline:`none`},disabled:l}),(0,n.jsx)(`button`,{onClick:m,disabled:l||!s.trim(),style:{background:`#007bff`,color:`white`,border:`none`,padding:`10px 14px`,borderRadius:`6px`,cursor:l||!s.trim()?`not-allowed`:`pointer`},children:l?`Mengirim...`:`Kirim`})]})]}):null},e.MyComponent=({text:e=`Halo dari NPM!`,color:t=`blue`})=>(0,n.jsx)(`button`,{style:{padding:`10px 20px`,backgroundColor:t,color:`#fff`,border:`none`,borderRadius:`5px`,cursor:`pointer`},children:e})});
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "react-component-by-vite",
3
+ "version": "2.0.0",
4
+ "description": "Komponen React kustom pertamaku",
5
+ "type": "module",
6
+ "main": "./dist/index.umd.js",
7
+ "module": "./dist/index.es.js",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.es.js",
11
+ "require": "./dist/index.umd.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "vite build",
19
+ "storybook": "storybook dev -p 6006",
20
+ "build-storybook": "storybook build"
21
+ },
22
+ "peerDependencies": {
23
+ "react": "^18.0.0 || ^19.0.0",
24
+ "react-dom": "^18.0.0 || ^19.0.0"
25
+ },
26
+ "keywords": [
27
+ "react",
28
+ "component"
29
+ ],
30
+ "author": "Nama Anda",
31
+ "license": "MIT",
32
+ "devDependencies": {
33
+ "@chromatic-com/storybook": "^5.2.1",
34
+ "@storybook/addon-a11y": "^10.4.1",
35
+ "@storybook/addon-docs": "^10.4.1",
36
+ "@storybook/addon-mcp": "^0.6.0",
37
+ "@storybook/addon-vitest": "^10.4.1",
38
+ "@storybook/react-vite": "^10.4.1",
39
+ "@vitejs/plugin-react": "^6.0.2",
40
+ "@vitest/browser-playwright": "^4.1.8",
41
+ "@vitest/coverage-v8": "^4.1.8",
42
+ "playwright": "^1.60.0",
43
+ "prop-types": "^15.8.1",
44
+ "storybook": "^10.4.1",
45
+ "vitest": "^4.1.8"
46
+ }
47
+ }