ebig-library 0.0.1

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.
Files changed (128) hide show
  1. package/README.md +964 -0
  2. package/dist/component/audio/audio.d.ts +22 -0
  3. package/dist/component/audio/audio.d.ts.map +1 -0
  4. package/dist/component/button/button.d.ts +32 -0
  5. package/dist/component/button/button.d.ts.map +1 -0
  6. package/dist/component/calendar/calendar.d.ts +27 -0
  7. package/dist/component/calendar/calendar.d.ts.map +1 -0
  8. package/dist/component/carousel/carousel.d.ts +32 -0
  9. package/dist/component/carousel/carousel.d.ts.map +1 -0
  10. package/dist/component/checkbox/checkbox.d.ts +18 -0
  11. package/dist/component/checkbox/checkbox.d.ts.map +1 -0
  12. package/dist/component/ck-editor/ckeditor.d.ts +66 -0
  13. package/dist/component/ck-editor/ckeditor.d.ts.map +1 -0
  14. package/dist/component/color-picker/color-picker.d.ts +22 -0
  15. package/dist/component/color-picker/color-picker.d.ts.map +1 -0
  16. package/dist/component/component-form.d.ts +211 -0
  17. package/dist/component/component-form.d.ts.map +1 -0
  18. package/dist/component/component-status.d.ts +8 -0
  19. package/dist/component/component-status.d.ts.map +1 -0
  20. package/dist/component/date-time-picker/date-time-picker.d.ts +42 -0
  21. package/dist/component/date-time-picker/date-time-picker.d.ts.map +1 -0
  22. package/dist/component/dialog/dialog.d.ts +19 -0
  23. package/dist/component/dialog/dialog.d.ts.map +1 -0
  24. package/dist/component/dropdown/select-dropdown.d.ts +70 -0
  25. package/dist/component/dropdown/select-dropdown.d.ts.map +1 -0
  26. package/dist/component/ebig-editor/ebig-editor.d.ts +41 -0
  27. package/dist/component/ebig-editor/ebig-editor.d.ts.map +1 -0
  28. package/dist/component/empty-page.d.ts +13 -0
  29. package/dist/component/empty-page.d.ts.map +1 -0
  30. package/dist/component/icon/ebig-icon.d.ts +35 -0
  31. package/dist/component/icon/ebig-icon.d.ts.map +1 -0
  32. package/dist/component/icon-picker/icon-picker.d.ts +22 -0
  33. package/dist/component/icon-picker/icon-picker.d.ts.map +1 -0
  34. package/dist/component/icon-picker/iconLibrary.d.ts +12 -0
  35. package/dist/component/icon-picker/iconLibrary.d.ts.map +1 -0
  36. package/dist/component/iframe/iframe.d.ts +23 -0
  37. package/dist/component/iframe/iframe.d.ts.map +1 -0
  38. package/dist/component/import-file/import-file.d.ts +33 -0
  39. package/dist/component/import-file/import-file.d.ts.map +1 -0
  40. package/dist/component/import-file/upload.d.ts +46 -0
  41. package/dist/component/import-file/upload.d.ts.map +1 -0
  42. package/dist/component/infinite-scroll/infinite-scroll.d.ts +16 -0
  43. package/dist/component/infinite-scroll/infinite-scroll.d.ts.map +1 -0
  44. package/dist/component/input-otp/input-otp.d.ts +23 -0
  45. package/dist/component/input-otp/input-otp.d.ts.map +1 -0
  46. package/dist/component/number-picker/number-picker.d.ts +26 -0
  47. package/dist/component/number-picker/number-picker.d.ts.map +1 -0
  48. package/dist/component/pagination/pagination.d.ts +19 -0
  49. package/dist/component/pagination/pagination.d.ts.map +1 -0
  50. package/dist/component/popup/popup.d.ts +40 -0
  51. package/dist/component/popup/popup.d.ts.map +1 -0
  52. package/dist/component/progress-bar/progress-bar.d.ts +19 -0
  53. package/dist/component/progress-bar/progress-bar.d.ts.map +1 -0
  54. package/dist/component/progress-circle/progress-circle.d.ts +18 -0
  55. package/dist/component/progress-circle/progress-circle.d.ts.map +1 -0
  56. package/dist/component/radio-button/radio-button.d.ts +17 -0
  57. package/dist/component/radio-button/radio-button.d.ts.map +1 -0
  58. package/dist/component/rating/rating.d.ts +17 -0
  59. package/dist/component/rating/rating.d.ts.map +1 -0
  60. package/dist/component/slider/slider.d.ts +42 -0
  61. package/dist/component/slider/slider.d.ts.map +1 -0
  62. package/dist/component/switch/switch.d.ts +18 -0
  63. package/dist/component/switch/switch.d.ts.map +1 -0
  64. package/dist/component/tag/tag.d.ts +23 -0
  65. package/dist/component/tag/tag.d.ts.map +1 -0
  66. package/dist/component/text/text.d.ts +14 -0
  67. package/dist/component/text/text.d.ts.map +1 -0
  68. package/dist/component/text-area/text-area.d.ts +31 -0
  69. package/dist/component/text-area/text-area.d.ts.map +1 -0
  70. package/dist/component/text-field/text-field.d.ts +39 -0
  71. package/dist/component/text-field/text-field.d.ts.map +1 -0
  72. package/dist/component/toast-noti/toast-noti.d.ts +9 -0
  73. package/dist/component/toast-noti/toast-noti.d.ts.map +1 -0
  74. package/dist/component/video/video.d.ts +24 -0
  75. package/dist/component/video/video.d.ts.map +1 -0
  76. package/dist/controller/config.d.ts +58 -0
  77. package/dist/controller/config.d.ts.map +1 -0
  78. package/dist/controller/data.d.ts +124 -0
  79. package/dist/controller/data.d.ts.map +1 -0
  80. package/dist/controller/setting.d.ts +56 -0
  81. package/dist/controller/setting.d.ts.map +1 -0
  82. package/dist/controller/utils.d.ts +70 -0
  83. package/dist/controller/utils.d.ts.map +1 -0
  84. package/dist/index.cjs.js +290 -0
  85. package/dist/index.cjs.js.map +1 -0
  86. package/dist/index.d.ts +53 -0
  87. package/dist/index.d.ts.map +1 -0
  88. package/dist/index.es.js +110091 -0
  89. package/dist/index.es.js.map +1 -0
  90. package/dist/language/i18n.d.ts +4 -0
  91. package/dist/language/i18n.d.ts.map +1 -0
  92. package/dist/module/EbigProvider.d.ts +47 -0
  93. package/dist/module/EbigProvider.d.ts.map +1 -0
  94. package/dist/module/card/cardById.d.ts +133 -0
  95. package/dist/module/card/cardById.d.ts.map +1 -0
  96. package/dist/module/card/config.d.ts +5 -0
  97. package/dist/module/card/config.d.ts.map +1 -0
  98. package/dist/module/chart/chartById.d.ts +26 -0
  99. package/dist/module/chart/chartById.d.ts.map +1 -0
  100. package/dist/module/chart/chartByType.d.ts +48 -0
  101. package/dist/module/chart/chartByType.d.ts.map +1 -0
  102. package/dist/module/da.d.ts +147 -0
  103. package/dist/module/da.d.ts.map +1 -0
  104. package/dist/module/form/config.d.ts +19 -0
  105. package/dist/module/form/config.d.ts.map +1 -0
  106. package/dist/module/form/formById.d.ts +72 -0
  107. package/dist/module/form/formById.d.ts.map +1 -0
  108. package/dist/module/page/component-form.d.ts +235 -0
  109. package/dist/module/page/component-form.d.ts.map +1 -0
  110. package/dist/module/page/config.d.ts +15 -0
  111. package/dist/module/page/config.d.ts.map +1 -0
  112. package/dist/module/page/pageById.d.ts +227 -0
  113. package/dist/module/page/pageById.d.ts.map +1 -0
  114. package/dist/module/table/addEditElement.d.ts +40 -0
  115. package/dist/module/table/addEditElement.d.ts.map +1 -0
  116. package/dist/module/table/config.d.ts +42 -0
  117. package/dist/module/table/config.d.ts.map +1 -0
  118. package/dist/module/table/exportXlsx.d.ts +22 -0
  119. package/dist/module/table/exportXlsx.d.ts.map +1 -0
  120. package/dist/module/table/featureElement.d.ts +51 -0
  121. package/dist/module/table/featureElement.d.ts.map +1 -0
  122. package/dist/module/table/tableById.d.ts +187 -0
  123. package/dist/module/table/tableById.d.ts.map +1 -0
  124. package/dist/module/table/tableElement.d.ts +100 -0
  125. package/dist/module/table/tableElement.d.ts.map +1 -0
  126. package/dist/module/view/viewById.d.ts +58 -0
  127. package/dist/module/view/viewById.d.ts.map +1 -0
  128. package/package.json +81 -0
package/README.md ADDED
@@ -0,0 +1,964 @@
1
+ # ebig-library
2
+
3
+ A modern, lightweight React + TypeScript UI component library by **eBig** — 35+ ready-to-use components, a responsive layout system, design-token theming, built-in i18n (en/vi), and optional eBig backend integration for dynamic form/table/page rendering.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/ebig-library)](https://www.npmjs.com/package/ebig-library)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
+
8
+ ---
9
+
10
+ ## Table of Contents
11
+
12
+ - [Installation](#installation)
13
+ - [Setup: EbigProvider](#setup-ebigprovider)
14
+ - [Global Context](#global-context)
15
+ - [Layout System](#layout-system)
16
+ - [Skin / CSS](#skin--css)
17
+ - [Components](#components)
18
+ - [Button & SimpleButton](#button--simplebutton)
19
+ - [Ebigicon](#ebigicon)
20
+ - [TextField](#textfield)
21
+ - [TextArea](#textarea)
22
+ - [SelectDropdown](#selectdropdown)
23
+ - [Checkbox](#checkbox)
24
+ - [Switch](#switch)
25
+ - [RadioButton](#radiobutton)
26
+ - [DateTimePicker](#datetimepicker)
27
+ - [NumberPicker](#numberpicker)
28
+ - [Slider](#slider)
29
+ - [Rating](#rating)
30
+ - [InputOtp](#inputotp)
31
+ - [ColorPicker](#colorpicker)
32
+ - [Tag](#tag)
33
+ - [Pagination](#pagination)
34
+ - [InfiniteScroll](#infinitescroll)
35
+ - [Dialog](#dialog)
36
+ - [Popup](#popup)
37
+ - [ToastMessage](#toastmessage)
38
+ - [ProgressBar](#progressbar)
39
+ - [ProgressCircle](#progresscircle)
40
+ - [Calendar](#calendar)
41
+ - [Carousel](#carousel)
42
+ - [VideoPlayer / AudioPlayer / IframePlayer](#videoplayer--audioplayer--iframeplayer)
43
+ - [ImportFile / UploadFiles](#importfile--uploadfiles)
44
+ - [CustomCkEditor5](#customckeditor5)
45
+ - [EbigEditor](#ebigeditor)
46
+ - [IconPicker](#iconpicker)
47
+ - [EmptyPage](#emptypage)
48
+ - [Text](#text)
49
+ - [ComponentStatus](#componentstatus)
50
+ - [Form Components (react-hook-form)](#form-components-react-hook-form)
51
+ - [Utility Class (Util)](#utility-class-util)
52
+ - [Controllers](#controllers)
53
+ - [DataController](#datacontroller)
54
+ - [SettingDataController](#settingdatacontroller)
55
+ - [AccountController](#accountcontroller)
56
+ - [EbigController](#ebigcontroller)
57
+ - [TableController](#tablecontroller)
58
+ - [IntegrationController](#integrationcontroller)
59
+ - [BaseDA](#baseda)
60
+ - [Backend-Driven Modules](#backend-driven-modules)
61
+ - [Design Tokens & Theming](#design-tokens--theming)
62
+ - [Responsive Grid Classes](#responsive-grid-classes)
63
+
64
+ ---
65
+
66
+ ## Installation
67
+
68
+ ```bash
69
+ npm install ebig-library
70
+ ```
71
+
72
+ Import the CSS skin files (required for layout and typography utilities):
73
+
74
+ ```html
75
+ <!-- In your index.html or root CSS -->
76
+ <link rel="stylesheet" href="https://cdn.ebig.co/ebig-library/src/skin/root.min.css" />
77
+ <link rel="stylesheet" href="https://cdn.ebig.co/ebig-library/src/skin/layout.min.css" />
78
+ <link rel="stylesheet" href="https://cdn.ebig.co/ebig-library/src/skin/typography.min.css" />
79
+ <link rel="stylesheet" href="https://cdn.ebig.co/ebig-library/src/skin/toast-noti.min.css" />
80
+ ```
81
+
82
+ > These are loaded automatically if you use `EbigProvider` with `loadResources={true}` (default).
83
+
84
+ ---
85
+
86
+ ## Setup: EbigProvider
87
+
88
+ Wrap your app's root with `EbigProvider`. It sets up routing (`BrowserRouter` internally), toast notifications, dialogs, token refresh, and optional design token + i18n loading from the eBig backend.
89
+
90
+ ```tsx
91
+ // main.tsx
92
+ import ReactDOM from 'react-dom/client'
93
+ import EbigProvider, { Route } from 'ebig-library'
94
+
95
+ ReactDOM.createRoot(document.getElementById('root')!).render(
96
+ <EbigProvider
97
+ pid="your-project-id"
98
+ url="https://your-ebig-api.com/"
99
+ fileUrl="https://your-file-server.com/"
100
+ imgUrlId="https://your-cdn.com/"
101
+ theme="light" // "light" | "dark"
102
+ loadResources={true} // false → skip backend token/i18n loading
103
+ >
104
+ <Route path="/" element={<HomePage />} />
105
+ <Route path="/about" element={<AboutPage />} />
106
+ </EbigProvider>
107
+ )
108
+ ```
109
+
110
+ > **Important:** `EbigProvider` wraps `BrowserRouter` internally. Do **not** add another `BrowserRouter` in your app.
111
+
112
+ ### Props
113
+
114
+ | Prop | Type | Required | Description |
115
+ |---|---|---|---|
116
+ | `pid` | `string` | ✅ | eBig project ID (32-char) |
117
+ | `url` | `string` | ✅ | eBig API base URL |
118
+ | `fileUrl` | `string` | ✅ | File server URL |
119
+ | `imgUrlId` | `string` | ✅ | CDN/image URL prefix |
120
+ | `theme` | `"light" \| "dark"` | — | Default `"light"` |
121
+ | `loadResources` | `boolean` | — | Default `true`. Set to `false` to skip backend loading |
122
+ | `onInvalidToken` | `() => void` | — | Called on 401 — override to redirect to login |
123
+ | `children` | `ReactNode` | — | `<Route>` elements |
124
+
125
+ ---
126
+
127
+ ## Global Context
128
+
129
+ ```tsx
130
+ import { useEbigContext } from 'ebig-library'
131
+
132
+ function MyComponent() {
133
+ const {
134
+ theme, // "light" | "dark"
135
+ setTheme,
136
+ userData, // current user object (set by you)
137
+ setUserData,
138
+ globalData, // any global state bag
139
+ setGlobalData,
140
+ i18n, // i18next instance
141
+ } = useEbigContext()
142
+
143
+ return (
144
+ <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
145
+ Toggle theme
146
+ </button>
147
+ )
148
+ }
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Layout System
154
+
155
+ Use `row` and `col` CSS classes for flex layouts. Add `remain` to let a child fill remaining space.
156
+
157
+ ```tsx
158
+ // Horizontal (flex-direction: row, align-items: center)
159
+ <div className="row" style={{ gap: 12 }}>
160
+ <span>Left</span>
161
+ <span className="remain">Stretches to fill space</span>
162
+ <span>Right</span>
163
+ </div>
164
+
165
+ // Vertical (flex-direction: column)
166
+ <div className="col" style={{ gap: 8 }}>
167
+ <span>Top</span>
168
+ <span>Bottom</span>
169
+ </div>
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Skin / CSS
175
+
176
+ | Resource | URL |
177
+ |---|---|
178
+ | Design tokens (CSS variables) | `https://cdn.ebig.co/ebig-library/src/skin/root.min.css` |
179
+ | Layout utilities (`row`, `col`, grids) | `https://cdn.ebig.co/ebig-library/src/skin/layout.min.css` |
180
+ | Typography (`heading-1`…`heading-8`, `body-1`…`body-3`) | `https://cdn.ebig.co/ebig-library/src/skin/typography.min.css` |
181
+ | Toast styles | `https://cdn.ebig.co/ebig-library/src/skin/toast-noti.min.css` |
182
+
183
+ ---
184
+
185
+ ## Components
186
+
187
+ ### Button & SimpleButton
188
+
189
+ ```tsx
190
+ import { Button, SimpleButton, Ebigicon } from 'ebig-library'
191
+
192
+ // Basic
193
+ <Button label="Click me" onClick={() => alert('clicked!')} />
194
+
195
+ // Size + color variant
196
+ <Button label="Save" className="size40 button-primary" onClick={handleSave} />
197
+
198
+ // With prefix icon
199
+ <Button
200
+ label="Upload"
201
+ prefix={<Ebigicon src="outline/arrows/cloud-upload" size={16} />}
202
+ className="size40 button-neutral"
203
+ onClick={handleUpload}
204
+ />
205
+
206
+ // As a link
207
+ <Button label="Docs" linkTo="https://ebig.co" target="_blank" className="size40 button-grey" />
208
+
209
+ // With tooltip
210
+ <Button label="Info" tooltip={{ message: 'More details', position: 'top' }} />
211
+
212
+ // Submit — also triggers on Enter key
213
+ <Button label="Submit" type="submit" className="size40 button-primary" onClick={handleSubmit} />
214
+
215
+ // SimpleButton — auto-disables itself during async onClick to prevent double-clicks
216
+ <SimpleButton label="Save" className="size40 button-primary" onClick={async () => { await save() }} />
217
+ ```
218
+
219
+ **Size classes:** `size24` · `size32` *(default)* · `size40` · `size48` · `size56` · `size64`
220
+
221
+ **Color classes:** `button-primary` · `button-grey` · `button-neutral` · `button-black` · `button-white` · `button-infor` · `button-warning` · `button-error` · `button-success` · `button-infor-main` · `button-warning-main` · `button-error-main` · `button-success-main`
222
+
223
+ ---
224
+
225
+ ### Ebigicon
226
+
227
+ SVG icon component. Icons are fetched from `https://cdn.ebig.co/icon-library/` and cached in the browser via the Cache API after first load.
228
+
229
+ ```tsx
230
+ import { Ebigicon } from 'ebig-library'
231
+
232
+ <Ebigicon src="outline/user/user" size={24} />
233
+ <Ebigicon src="fill/actions/trash" size={20} color="#E14337" onClick={handleDelete} className="icon-button" />
234
+
235
+ // With tooltip
236
+ <Ebigicon src="outline/essential/info-circle" size={20} tooltip={{ message: 'Help', position: 'bottom' }} />
237
+
238
+ // From a custom link
239
+ <Ebigicon link="https://your-cdn.com/custom-icon.svg" size={24} />
240
+ ```
241
+
242
+ **Style classes:** `icon-button` (adds hover/active styles) · `icon-button light` · `border` · `dashed`
243
+
244
+ **Size classes:** `size24` · `size32` · `size40` · `size48` · `size56` · `size64`
245
+
246
+ ---
247
+
248
+ ### TextField
249
+
250
+ ```tsx
251
+ import { TextField, Ebigicon } from 'ebig-library'
252
+
253
+ <TextField placeholder="Enter name" onChange={(e) => setName(e.target.value)} />
254
+
255
+ // With prefix icon and helper text (shown in red below)
256
+ <TextField
257
+ prefix={<Ebigicon src="outline/user/user" size={16} />}
258
+ placeholder="Email"
259
+ type="email"
260
+ helperText="Invalid email"
261
+ className="size40 body-3"
262
+ />
263
+
264
+ // With react-hook-form
265
+ const { register } = useForm()
266
+ <TextField placeholder="Username" register={register('username', { required: true })} />
267
+ ```
268
+
269
+ **Size classes:** `size24` · `size32` · `size40` *(default)* · `size48`
270
+
271
+ ---
272
+
273
+ ### TextArea
274
+
275
+ ```tsx
276
+ import { TextArea } from 'ebig-library'
277
+
278
+ <TextArea placeholder="Write something..." onChange={(e) => setText(e.target.value)} />
279
+ ```
280
+
281
+ ---
282
+
283
+ ### SelectDropdown
284
+
285
+ Single-value dropdown. Supports static options, async lazy-loading, hierarchical (parent/child) options, and `react-hook-form`.
286
+
287
+ ```tsx
288
+ import { SelectDropdown } from 'ebig-library'
289
+
290
+ const options = [
291
+ { id: '1', name: 'Option A' },
292
+ { id: '2', name: 'Option B' },
293
+ { id: '3', name: 'Option C', disabled: true },
294
+ ]
295
+
296
+ // Static
297
+ <SelectDropdown
298
+ value={selected}
299
+ options={options}
300
+ placeholder="Choose one"
301
+ onChange={(item) => setSelected(item?.id)}
302
+ />
303
+
304
+ // Async (loads on open / search)
305
+ <SelectDropdown
306
+ options={[]}
307
+ getOptions={async ({ length, search }) => {
308
+ const res = await fetchItems({ page: Math.floor(length / 10) + 1, search })
309
+ return { data: res.items, totalCount: res.total }
310
+ }}
311
+ onChange={(item) => setSelected(item?.id)}
312
+ />
313
+ ```
314
+
315
+ ---
316
+
317
+ ### Checkbox
318
+
319
+ ```tsx
320
+ import { Checkbox } from 'ebig-library'
321
+
322
+ <Checkbox value={isChecked} onChange={(val) => setIsChecked(val)} />
323
+ <Checkbox value={null} /> {/* null = indeterminate */}
324
+ ```
325
+
326
+ ---
327
+
328
+ ### Switch
329
+
330
+ ```tsx
331
+ import { Switch } from 'ebig-library'
332
+
333
+ <Switch value={isOn} onChange={(val) => setIsOn(val)} />
334
+ <Switch value={isOn} size="2.4rem" onBackground="#287CF0" onChange={setIsOn} />
335
+ ```
336
+
337
+ ---
338
+
339
+ ### RadioButton
340
+
341
+ ```tsx
342
+ import { RadioButton } from 'ebig-library'
343
+
344
+ <RadioButton value={selected === 'a'} onChange={() => setSelected('a')} label="Option A" />
345
+ <RadioButton value={selected === 'b'} onChange={() => setSelected('b')} label="Option B" />
346
+ ```
347
+
348
+ ---
349
+
350
+ ### DateTimePicker
351
+
352
+ ```tsx
353
+ import { DateTimePicker } from 'ebig-library'
354
+
355
+ <DateTimePicker value={date} onChange={(val) => setDate(val)} placeholder="Pick a date" />
356
+ ```
357
+
358
+ ---
359
+
360
+ ### NumberPicker
361
+
362
+ ```tsx
363
+ import { NumberPicker } from 'ebig-library'
364
+
365
+ <NumberPicker value={count} onChange={(val) => setCount(val)} min={0} max={100} />
366
+ ```
367
+
368
+ ---
369
+
370
+ ### Slider
371
+
372
+ ```tsx
373
+ import { Slider } from 'ebig-library'
374
+
375
+ <Slider value={volume} min={0} max={100} onChange={(val) => setVolume(val)} />
376
+ ```
377
+
378
+ ---
379
+
380
+ ### Rating
381
+
382
+ ```tsx
383
+ import { Rating } from 'ebig-library'
384
+
385
+ <Rating value={3} onChange={(val) => setRating(val)} />
386
+ ```
387
+
388
+ ---
389
+
390
+ ### InputOtp
391
+
392
+ ```tsx
393
+ import { InputOtp } from 'ebig-library'
394
+
395
+ <InputOtp length={6} onComplete={(code) => verifyOtp(code)} />
396
+ ```
397
+
398
+ ---
399
+
400
+ ### ColorPicker
401
+
402
+ ```tsx
403
+ import { ColorPicker } from 'ebig-library'
404
+
405
+ <ColorPicker value={color} onChange={(hex) => setColor(hex)} />
406
+ ```
407
+
408
+ ---
409
+
410
+ ### Tag
411
+
412
+ ```tsx
413
+ import { Tag } from 'ebig-library'
414
+
415
+ <Tag label="Active" color="#287CF0" />
416
+ <Tag label="Error" color="#E14337" onRemove={() => handleRemove()} />
417
+ ```
418
+
419
+ ---
420
+
421
+ ### Pagination
422
+
423
+ ```tsx
424
+ import { Pagination } from 'ebig-library'
425
+
426
+ <Pagination
427
+ pageIndex={page}
428
+ totalCount={total}
429
+ pageSize={10}
430
+ onChange={(newPage) => setPage(newPage)}
431
+ />
432
+ ```
433
+
434
+ ---
435
+
436
+ ### InfiniteScroll
437
+
438
+ ```tsx
439
+ import { InfiniteScroll } from 'ebig-library'
440
+
441
+ <InfiniteScroll
442
+ data={items}
443
+ render={(item) => <div key={item.id}>{item.name}</div>}
444
+ totalCount={total}
445
+ onLoadMore={() => loadNextPage()}
446
+ />
447
+ ```
448
+
449
+ ---
450
+
451
+ ### Dialog
452
+
453
+ ```tsx
454
+ import { showDialog, DialogAlignment } from 'ebig-library'
455
+
456
+ showDialog({
457
+ title: 'Confirm delete',
458
+ content: 'Are you sure?',
459
+ alignment: DialogAlignment.center,
460
+ onConfirm: () => handleDelete(),
461
+ })
462
+ ```
463
+
464
+ ---
465
+
466
+ ### Popup
467
+
468
+ ```tsx
469
+ import { Popup, showPopup, closePopup } from 'ebig-library'
470
+ import { useRef } from 'react'
471
+
472
+ const ref = useRef()
473
+
474
+ <button onClick={(ev) => showPopup({ ref, id: 'my-popup', clickTarget: ev.currentTarget, content: () => <div>Content</div> })}>
475
+ Open popup
476
+ </button>
477
+ <Popup ref={ref} />
478
+ ```
479
+
480
+ ---
481
+
482
+ ### ToastMessage
483
+
484
+ ```tsx
485
+ import { ToastMessage } from 'ebig-library'
486
+
487
+ ToastMessage.success('Saved successfully')
488
+ ToastMessage.errors('Something went wrong')
489
+ ToastMessage.warning('Check your input')
490
+ ```
491
+
492
+ ---
493
+
494
+ ### ProgressBar
495
+
496
+ ```tsx
497
+ import { ProgressBar } from 'ebig-library'
498
+
499
+ <ProgressBar percent={75} label="Uploading..." />
500
+ ```
501
+
502
+ ---
503
+
504
+ ### ProgressCircle
505
+
506
+ ```tsx
507
+ import { ProgressCircle } from 'ebig-library'
508
+
509
+ <ProgressCircle percent={60} size={80} />
510
+ ```
511
+
512
+ ---
513
+
514
+ ### Calendar
515
+
516
+ ```tsx
517
+ import { Calendar } from 'ebig-library'
518
+
519
+ <Calendar value={date} onChange={(val) => setDate(val)} />
520
+ ```
521
+
522
+ ---
523
+
524
+ ### Carousel
525
+
526
+ ```tsx
527
+ import { Carousel } from 'ebig-library'
528
+
529
+ <Carousel>
530
+ <img src="/slide1.jpg" alt="Slide 1" />
531
+ <img src="/slide2.jpg" alt="Slide 2" />
532
+ </Carousel>
533
+ ```
534
+
535
+ ---
536
+
537
+ ### VideoPlayer / AudioPlayer / IframePlayer
538
+
539
+ ```tsx
540
+ import { VideoPlayer, AudioPlayer, IframePlayer } from 'ebig-library'
541
+
542
+ <VideoPlayer src="https://example.com/video.mp4" />
543
+ <AudioPlayer src="https://example.com/audio.mp3" />
544
+ <IframePlayer src="https://www.youtube.com/embed/xxxxx" />
545
+ ```
546
+
547
+ ---
548
+
549
+ ### ImportFile / UploadFiles
550
+
551
+ ```tsx
552
+ import { ImportFile, UploadFiles } from 'ebig-library'
553
+
554
+ // File input with preview
555
+ <ImportFile
556
+ value={files}
557
+ onChange={(fileList) => setFiles(fileList)}
558
+ maxSize={5 * 1024 * 1024} // 5 MB
559
+ accept={['.png', '.jpg', '.pdf']}
560
+ />
561
+
562
+ // Full upload flow with progress and CDN upload
563
+ <UploadFiles
564
+ value={uploadedFiles}
565
+ onChange={(files) => setUploadedFiles(files)}
566
+ />
567
+ ```
568
+
569
+ ---
570
+
571
+ ### CustomCkEditor5
572
+
573
+ Rich-text editor powered by CKEditor 5. Requires `ckeditor5` and `@ckeditor/ckeditor5-react` to be installed by the consumer.
574
+
575
+ ```tsx
576
+ import { CustomCkEditor5, CkEditorUploadAdapter } from 'ebig-library'
577
+
578
+ <CustomCkEditor5
579
+ value={html}
580
+ onChange={(val) => setHtml(val)}
581
+ uploadAdapter={CkEditorUploadAdapter}
582
+ />
583
+ ```
584
+
585
+ ---
586
+
587
+ ### EbigEditor
588
+
589
+ Lightweight rich-text editor (no CKEditor dependency). Supports emoji, bold, italic, underline, hyperlinks, and `@mention`-style suggestion hooks.
590
+
591
+ ```tsx
592
+ import { EbigEditor } from 'ebig-library'
593
+
594
+ <EbigEditor
595
+ placeholder="Write a comment..."
596
+ onChange={(value, el) => setContent(value)}
597
+ onBlur={(value, el) => handleBlur(value)}
598
+ />
599
+
600
+ // Custom toolbar subset
601
+ <EbigEditor
602
+ customToolbar={['bold', 'italic', 'emoji']}
603
+ onChange={(val) => setContent(val)}
604
+ />
605
+
606
+ // Mention suggestions
607
+ <EbigEditor
608
+ onSuggest={[{
609
+ triggerPattern: '@',
610
+ render: (offset, match, select) => (
611
+ <MentionList offset={offset} query={match} onSelect={select} />
612
+ )
613
+ }]}
614
+ onChange={(val) => setContent(val)}
615
+ />
616
+ ```
617
+
618
+ ---
619
+
620
+ ### IconPicker
621
+
622
+ ```tsx
623
+ import { IconPicker } from 'ebig-library'
624
+
625
+ <IconPicker value={iconName} onChange={(name) => setIconName(name)} />
626
+ ```
627
+
628
+ ---
629
+
630
+ ### EmptyPage
631
+
632
+ ```tsx
633
+ import { EmptyPage } from 'ebig-library'
634
+
635
+ <EmptyPage
636
+ title="No data found"
637
+ subtitle="Try adjusting your filters"
638
+ button={<Button label="Reset" onClick={reset} />}
639
+ />
640
+ ```
641
+
642
+ ---
643
+
644
+ ### Text
645
+
646
+ Typography component that renders semantic HTML elements with typography class helpers.
647
+
648
+ ```tsx
649
+ import { Text } from 'ebig-library'
650
+
651
+ <Text className="heading-3">Page title</Text>
652
+ <Text className="body-2" maxLine={2}>Truncated body text that wraps at two lines...</Text>
653
+ ```
654
+
655
+ ---
656
+
657
+ ### ComponentStatus
658
+
659
+ ```tsx
660
+ import { ComponentStatus, getStatusIcon } from 'ebig-library'
661
+
662
+ <ComponentStatus status="success" label="Completed" />
663
+ const icon = getStatusIcon('warning')
664
+ ```
665
+
666
+ ---
667
+
668
+ ## Form Components (react-hook-form)
669
+
670
+ Pre-built form field wrappers integrating `react-hook-form`. All accept `methods` (from `useForm()`), `name`, `label`, `required`, `disabled`, `placeholder`, and `className`.
671
+
672
+ ```tsx
673
+ import { useForm } from 'react-hook-form'
674
+ import {
675
+ TextFieldForm,
676
+ TextAreaForm,
677
+ Select1Form,
678
+ SelectMultipleForm,
679
+ CheckboxForm,
680
+ SwitchForm,
681
+ DateTimePickerForm,
682
+ NumberPickerForm, // NumberPicker
683
+ RateForm, // Rating
684
+ ColorPickerForm,
685
+ GroupCheckboxForm,
686
+ GroupRadioButtonForm,
687
+ RangeForm, // Slider
688
+ CKEditorForm,
689
+ EbigEditorForm,
690
+ InputPasswordForm,
691
+ IconPickerForm,
692
+ UploadMultipleFileTypeForm,
693
+ } from 'ebig-library'
694
+
695
+ const methods = useForm()
696
+
697
+ <form onSubmit={methods.handleSubmit(onSubmit)}>
698
+ <TextFieldForm methods={methods} name="username" label="Username" required />
699
+ <TextFieldForm methods={methods} name="price" label="Price" type="money" />
700
+ <Select1Form
701
+ methods={methods}
702
+ name="category"
703
+ label="Category"
704
+ options={[{ id: '1', name: 'Tech' }, { id: '2', name: 'Finance' }]}
705
+ />
706
+ <DateTimePickerForm methods={methods} name="dueDate" label="Due date" />
707
+ <EbigEditorForm methods={methods} name="description" label="Description" />
708
+ <Button label="Submit" type="submit" className="size40 button-primary" />
709
+ </form>
710
+ ```
711
+
712
+ ---
713
+
714
+ ## Utility Class (Util)
715
+
716
+ ```tsx
717
+ import { Util } from 'ebig-library'
718
+
719
+ // Date & Time
720
+ Util.dateTime_stringToDecimal('2026-04-08T10:00:00Z') // → Unix seconds
721
+ Util.stringToDate('08/04/2026', 'dd/mm/yyyy') // → Date
722
+ Util.calculateAge('01/01/2000') // → number
723
+
724
+ // Number & Currency
725
+ Util.formatCurrency(1500000, 'VND') // → "1,500,000.00 ₫"
726
+ Util.formatCurrency(99.9, 'USD') // → "$99.90"
727
+ Util.convertCurrency(100, 'USD', 'VND') // → 2450000
728
+
729
+ // Color
730
+ Util.hexToRgb('#287CF0') // → { r: 40, g: 124, b: 240 }
731
+ Util.rgbToHex(40, 124, 240) // → "#287cf0"
732
+
733
+ // String
734
+ Util.toSlug('Hello World!') // → "hello-world"
735
+ Util.randomGID() // → 32-char random hex ID
736
+
737
+ // Cookie
738
+ Util.getCookie('accessToken')
739
+ Util.setCookie('accessToken', token)
740
+ Util.clearCookie()
741
+
742
+ // File
743
+ Util.formatFileSize(1048576) // → "1 MB"
744
+ Util.stringToFile('content', 'file.txt')
745
+
746
+ // Auth
747
+ Util.encodeBase64('string')
748
+ Util.decodeBase64('encoded')
749
+ ```
750
+
751
+ ---
752
+
753
+ ## Controllers
754
+
755
+ All controllers require `ConfigData.url` and `ConfigData.pid` to be set (done automatically by `EbigProvider`).
756
+
757
+ ### DataController
758
+
759
+ Generic CRUD for any project data module.
760
+
761
+ ```tsx
762
+ import { DataController } from 'ebig-library'
763
+
764
+ const ctrl = new DataController('Product')
765
+
766
+ // Fetch list (RediSearch query syntax)
767
+ const res = await ctrl.getListSimple({ page: 1, size: 20, query: '@Category:{Electronics}' })
768
+
769
+ // Get by ID
770
+ const item = await ctrl.getById('abc123')
771
+
772
+ // Add
773
+ await ctrl.add([{ Name: 'Product A', Price: 100 }])
774
+
775
+ // Edit
776
+ await ctrl.edit([{ Id: 'abc123', Price: 120 }])
777
+
778
+ // Delete
779
+ await ctrl.delete(['abc123', 'def456'])
780
+
781
+ // Aggregate / group
782
+ await ctrl.aggregateList({ filter: '@Price:[100 200]', sortby: [{ prop: 'Price', direction: 'ASC' }] })
783
+ ```
784
+
785
+ ### SettingDataController
786
+
787
+ For system-level setting entities (`report`, `chart`, `form`, `card`, `view`).
788
+
789
+ ```tsx
790
+ import { SettingDataController } from 'ebig-library'
791
+
792
+ const ctrl = new SettingDataController('form')
793
+ await ctrl.getListSimple({ page: 1, size: 10 })
794
+ await ctrl.action('add', { data: [{ Name: 'My Form' }] })
795
+ await ctrl.getByIds(['id1', 'id2'])
796
+ ```
797
+
798
+ ### AccountController
799
+
800
+ Login, get user info, and password utilities.
801
+
802
+ ```tsx
803
+ import { AccountController } from 'ebig-library'
804
+
805
+ const acc = new AccountController('Customer') // or 'User'
806
+
807
+ // Login with account/password
808
+ const res = await acc.login({ type: 'account', username: 'admin', password: 'pass' })
809
+
810
+ // Login with Google OAuth token
811
+ await acc.login({ type: 'google', token: googleToken })
812
+
813
+ // Get current user info
814
+ const info = await acc.getInfor()
815
+
816
+ // Hash a password
817
+ const hashed = await acc.hashPassword('mypassword')
818
+ ```
819
+
820
+ ### EbigController
821
+
822
+ Project-level queries (fetches eBig project metadata). **Do not change the internal API paths.**
823
+
824
+ ```tsx
825
+ import { EbigController } from 'ebig-library'
826
+
827
+ const ctrl = new EbigController('Project')
828
+ const project = await ctrl.getById('your-project-id')
829
+ const results = await ctrl.getListSimple({ query: '@Domain:{ebig.co}', size: 1 })
830
+ ```
831
+
832
+ ### TableController
833
+
834
+ CRUD for schema-level settings (`table`, `column`, `rel`, `menu`, `page`, `layout`, `designtoken`, `workflow`, `process`, `step`).
835
+
836
+ ```tsx
837
+ import { TableController } from 'ebig-library'
838
+
839
+ const ctrl = new TableController('table')
840
+ const tables = await ctrl.getAll()
841
+ await ctrl.add([{ Name: 'Orders' }])
842
+ await ctrl.edit([{ Id: 'xxx', Name: 'OrdersV2' }])
843
+ await ctrl.delete(['xxx'])
844
+ ```
845
+
846
+ ### IntegrationController
847
+
848
+ ```tsx
849
+ import { IntegrationController } from 'ebig-library'
850
+
851
+ const integration = new IntegrationController()
852
+ await integration.sendEmail({
853
+ templateId: 'welcome-email',
854
+ templateParams: { to: 'user@example.com', name: 'Alice' }
855
+ })
856
+ ```
857
+
858
+ ### BaseDA
859
+
860
+ Low-level HTTP helpers used by all controllers. Use directly only when you need calls outside the standard controller pattern.
861
+
862
+ ```tsx
863
+ import { BaseDA, ConfigData } from 'ebig-library'
864
+
865
+ // GET (auto-injects auth headers for ConfigData.url requests)
866
+ const data = await BaseDA.get(`${ConfigData.url}data/custom-endpoint`, {
867
+ headers: { pid: ConfigData.pid }
868
+ })
869
+
870
+ // POST
871
+ await BaseDA.post(`${ConfigData.url}data/action?action=add`, {
872
+ headers: { pid: ConfigData.pid, module: 'Product' },
873
+ body: { data: [{ Name: 'Item' }] }
874
+ })
875
+
876
+ // Upload files (auto-batches: max 12 files / 200 MB per batch)
877
+ const uploaded = await BaseDA.uploadFiles(fileList)
878
+ // uploaded → [{ Id, Url, Name, ... }]
879
+ ```
880
+
881
+ ---
882
+
883
+ ## Backend-Driven Modules
884
+
885
+ Render entire UI sections driven by eBig backend configuration. Requires a valid `pid`/`url` in `EbigProvider`.
886
+
887
+ ```tsx
888
+ import { PageById, PageByUrl, FormById, CardById, ViewById, ChartById, ChartByType } from 'ebig-library'
889
+
890
+ // Render a full page by its backend ID
891
+ <PageById id="page-id" />
892
+
893
+ // Render a page by URL path (matches current URL)
894
+ <PageByUrl url="location.pathname" />
895
+
896
+ // Render a form by ID
897
+ <FormById id="form-id" onSuccess={(data) => console.log(data)} />
898
+
899
+ // Render a card layout by ID
900
+ <CardById id="card-id" />
901
+
902
+ // Render a data view by ID
903
+ <ViewById id="view-id" />
904
+
905
+ // Chart by backend config ID
906
+ <ChartById id="chart-id" />
907
+
908
+ // Chart by type with your own data
909
+ <ChartByType type="bar" data={chartData} />
910
+ ```
911
+
912
+ ---
913
+
914
+ ## Design Tokens & Theming
915
+
916
+ Design tokens are loaded from the eBig backend at runtime and injected as CSS custom properties into `<head>`. Toggle dark mode via `setTheme`:
917
+
918
+ ```tsx
919
+ const { theme, setTheme } = useEbigContext()
920
+ setTheme('dark') // adds class="dark" to <html>
921
+ ```
922
+
923
+ Tokens follow the pattern:
924
+
925
+ ```css
926
+ /* Light mode */
927
+ --primary-main-color: #287CF0;
928
+ --neutral-text-title-color: #18181B;
929
+
930
+ /* Dark mode (html.dark) */
931
+ --primary-main-color: #4A90E2;
932
+ --neutral-text-title-color: #EAEAEC;
933
+ ```
934
+
935
+ ---
936
+
937
+ ## Responsive Grid Classes
938
+
939
+ The layout system uses a **24-column grid**. Add these classes to children inside a `row`.
940
+
941
+ | Class | Columns | Notes |
942
+ |---|---|---|
943
+ | `col1` – `col24` | 1/24 – 24/24 | Always applied |
944
+ | `remain` | fills rest | `flex: 1` |
945
+ | `col1-min` – `col24-min` | at **< 576px** | phones |
946
+ | `col1-sm` – `col24-sm` | at **≥ 576px** | small devices |
947
+ | `col1-md` – `col24-md` | at **≥ 768px** | tablets |
948
+ | `col1-lg` – `col24-lg` | at **≥ 992px** | laptops |
949
+ | `col1-xl` – `col24-xl` | at **≥ 1200px** | desktops |
950
+ | `col1-xxl` – `col24-xxl` | at **> 1200px** | wide screens |
951
+
952
+ ```tsx
953
+ // 2-column on desktop, stacks on mobile
954
+ <div className="row" style={{ gap: 16 }}>
955
+ <div className="col24 col12-lg" style={{ "--gutter": "16px" }}>Left panel</div>
956
+ <div className="col24 col12-lg" style={{ "--gutter": "16px" }}>Right panel</div>
957
+ </div>
958
+ ```
959
+
960
+ ---
961
+
962
+ ## License
963
+
964
+ MIT © [eBig / FDITECH](https://github.com/FDITECH)