react-bootstrap-plugins 1.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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +426 -0
  3. package/dist/DatePicker.cjs +2 -0
  4. package/dist/DatePicker.cjs.map +1 -0
  5. package/dist/DatePicker.d.ts +45 -0
  6. package/dist/DatePicker.js +2 -0
  7. package/dist/DatePicker.js.map +1 -0
  8. package/dist/Label.cjs +2 -0
  9. package/dist/Label.cjs.map +1 -0
  10. package/dist/Label.d.ts +16 -0
  11. package/dist/Label.js +2 -0
  12. package/dist/Label.js.map +1 -0
  13. package/dist/SearchSelect.cjs +2 -0
  14. package/dist/SearchSelect.cjs.map +1 -0
  15. package/dist/SearchSelect.d.ts +28 -0
  16. package/dist/SearchSelect.js +2 -0
  17. package/dist/SearchSelect.js.map +1 -0
  18. package/dist/chunk-46AJ2Q5H.js +2 -0
  19. package/dist/chunk-46AJ2Q5H.js.map +1 -0
  20. package/dist/chunk-4ISYCPRB.cjs +2 -0
  21. package/dist/chunk-4ISYCPRB.cjs.map +1 -0
  22. package/dist/chunk-CZV7QBHA.cjs +2 -0
  23. package/dist/chunk-CZV7QBHA.cjs.map +1 -0
  24. package/dist/chunk-DIUGH74M.js +2 -0
  25. package/dist/chunk-DIUGH74M.js.map +1 -0
  26. package/dist/chunk-F3KMQZXU.js +2 -0
  27. package/dist/chunk-F3KMQZXU.js.map +1 -0
  28. package/dist/chunk-HBS6VOGV.cjs +2 -0
  29. package/dist/chunk-HBS6VOGV.cjs.map +1 -0
  30. package/dist/chunk-NOGRIWSU.js +2 -0
  31. package/dist/chunk-NOGRIWSU.js.map +1 -0
  32. package/dist/chunk-QQNPKA7A.cjs +2 -0
  33. package/dist/chunk-QQNPKA7A.cjs.map +1 -0
  34. package/dist/css/css/datepicker-bootstrap.css +299 -0
  35. package/dist/index.cjs +2 -0
  36. package/dist/index.cjs.map +1 -0
  37. package/dist/index.d.ts +10 -0
  38. package/dist/index.js +2 -0
  39. package/dist/index.js.map +1 -0
  40. package/package.json +125 -0
  41. package/src/components/DatePicker.d.ts +45 -0
  42. package/src/components/DatePicker.jsx +690 -0
  43. package/src/components/Label.d.ts +16 -0
  44. package/src/components/Label.jsx +21 -0
  45. package/src/components/SearchSelect.d.ts +28 -0
  46. package/src/components/SearchSelect.jsx +152 -0
  47. package/src/css/datepicker-bootstrap.css +299 -0
  48. package/src/index.js +15 -0
  49. package/src/lib/cn.js +35 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tumwesigye Robert
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,426 @@
1
+ # react-bootstrap-plugins
2
+
3
+ > Production-grade Bootstrap 5 UI components for React 18+. Zero runtime dependencies. Tree-shakeable.
4
+
5
+ [![license](https://img.shields.io/npm/l/react-bootstrap-plugins)](./LICENSE)
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ - 🎯 **Zero runtime dependencies** — only React and React DOM as peer dependencies
12
+ - 🌳 **Tree-shakeable** — import only what you need; unused components are stripped at build time
13
+ - 🎨 **Bootstrap 5 native** — uses CSS custom properties (`--bs-*`), respects dark mode via `[data-bs-theme="dark"]`
14
+ - 📦 **ESM + CJS dual format** — works with any bundler (Vite, webpack, Turbopack, Rollup)
15
+ - 🔒 **TypeScript ready** — full `.d.ts` declarations included
16
+ - ♿ **Accessible** — ARIA attributes, keyboard navigation, screen-reader friendly
17
+ - 📱 **Responsive** — mobile-optimized layouts for all components
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install react-bootstrap-plugins
23
+ # or
24
+ pnpm add react-bootstrap-plugins
25
+ # or
26
+ yarn add react-bootstrap-plugins
27
+ ```
28
+
29
+ ### Peer Dependencies
30
+
31
+ Make sure you have React 18+ and Bootstrap 5 CSS loaded:
32
+
33
+ ```bash
34
+ npm install react react-dom bootstrap
35
+ ```
36
+
37
+ ```js
38
+ // In your app entry point
39
+ import 'bootstrap/dist/css/bootstrap.min.css'
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Components
45
+
46
+ ### DatePicker
47
+
48
+ A fully-featured date, time, and datetime picker with Bootstrap styling. Popover is rendered via React Portal — no z-index stacking issues with modals or sidebars.
49
+
50
+ #### Import
51
+
52
+ ```js
53
+ // Tree-shakeable single import (recommended)
54
+ import { DatePicker } from 'react-bootstrap-plugins/DatePicker'
55
+
56
+ // Or barrel import
57
+ import { DatePicker } from 'react-bootstrap-plugins'
58
+
59
+ // Required CSS (import once, anywhere in your app)
60
+ import 'react-bootstrap-plugins/css/datepicker.css'
61
+ ```
62
+
63
+ #### Basic Usage
64
+
65
+ ```jsx
66
+ import { useState } from 'react'
67
+ import { DatePicker } from 'react-bootstrap-plugins'
68
+ import 'react-bootstrap-plugins/css/datepicker.css'
69
+
70
+ function MyForm() {
71
+ const [date, setDate] = useState(null)
72
+
73
+ return (
74
+ <DatePicker
75
+ value={date}
76
+ onChange={(e) => setDate(e.target.value)}
77
+ placeholderText="Pick a date"
78
+ />
79
+ )
80
+ }
81
+ ```
82
+
83
+ #### Props
84
+
85
+ | Prop | Type | Default | Description |
86
+ |---|---|---|---|
87
+ | `mode` | `'date'` \| `'time'` \| `'datetime'` | `'date'` | Picker mode |
88
+ | `value` | `Date` \| `string` \| `null` | — | Currently selected value |
89
+ | `selected` | `Date` \| `null` | — | Alias for `value` |
90
+ | `onChange` | `(e) => void` | — | Synthetic event; `e.target.value` is formatted string |
91
+ | `dateFormat` | `string` | — | Custom format. Tokens: `yyyy`, `MM`, `dd`, `hh`, `mm`, `aa` |
92
+ | `placeholderText` | `string` | Auto | Placeholder when empty |
93
+ | `size` | `'sm'` \| `'lg'` | — | Bootstrap input size variant |
94
+ | `isClearable` | `boolean` | `false` | Show clear button |
95
+ | `disabled` | `boolean` | `false` | Disable the input |
96
+ | `minDate` | `Date` | — | Earliest selectable date |
97
+ | `maxDate` | `Date` | — | Latest selectable date |
98
+ | `timeIntervals` | `number` | `5` | Minute step in time picker |
99
+ | `timezone` | `string` | `'Kampala'` | Timezone label |
100
+ | `className` | `string` | — | Additional CSS classes on the input |
101
+ | `id` | `string` | — | Input element ID |
102
+ | `name` | `string` | — | Input name attribute |
103
+
104
+ #### Examples
105
+
106
+ **Date mode (default):**
107
+ ```jsx
108
+ <DatePicker
109
+ name="dob"
110
+ value={birthDate}
111
+ onChange={(e) => setBirthDate(e.target.value)}
112
+ maxDate={new Date()}
113
+ isClearable
114
+ />
115
+ // e.target.value → "2026-06-29"
116
+ ```
117
+
118
+ **Time mode:**
119
+ ```jsx
120
+ <DatePicker
121
+ mode="time"
122
+ value={startTime}
123
+ onChange={(e) => setStartTime(e.target.value)}
124
+ timeIntervals={15}
125
+ />
126
+ // e.target.value → "02:30 PM"
127
+ ```
128
+
129
+ **Datetime mode:**
130
+ ```jsx
131
+ <DatePicker
132
+ mode="datetime"
133
+ value={appointmentDateTime}
134
+ onChange={(e) => setAppointmentDateTime(e.target.value)}
135
+ dateFormat="dd/MM/yyyy hh:mm aa"
136
+ />
137
+ // e.target.value → "29/06/2026 02:30 PM"
138
+ ```
139
+
140
+ **With Bootstrap form layout:**
141
+ ```jsx
142
+ <div className="mb-3">
143
+ <label htmlFor="eventDate" className="form-label">Event Date</label>
144
+ <DatePicker
145
+ id="eventDate"
146
+ name="eventDate"
147
+ value={eventDate}
148
+ onChange={(e) => setEventDate(e.target.value)}
149
+ minDate={new Date()}
150
+ className="form-control-lg"
151
+ />
152
+ </div>
153
+ ```
154
+
155
+ ---
156
+
157
+ ### SearchSelect
158
+
159
+ A filterable, searchable select dropdown. Supports both primitive arrays and object arrays with configurable label/value keys.
160
+
161
+ #### Import
162
+
163
+ ```js
164
+ import SearchSelect from 'react-bootstrap-plugins/SearchSelect'
165
+ // or
166
+ import { SearchSelect } from 'react-bootstrap-plugins'
167
+ ```
168
+
169
+ #### Basic Usage
170
+
171
+ **Primitive array (strings/numbers):**
172
+ ```jsx
173
+ import { useState } from 'react'
174
+ import { SearchSelect } from 'react-bootstrap-plugins'
175
+
176
+ function FruitPicker() {
177
+ const [fruit, setFruit] = useState('')
178
+
179
+ return (
180
+ <SearchSelect
181
+ options={['Apple', 'Banana', 'Orange', 'Mango', 'Pineapple']}
182
+ placeholder="Choose a fruit..."
183
+ value={fruit}
184
+ onChange={(val) => setFruit(val)}
185
+ />
186
+ )
187
+ }
188
+ ```
189
+
190
+ **Object array with label/value mapping:**
191
+ ```jsx
192
+ function UserPicker() {
193
+ const [userId, setUserId] = useState(null)
194
+
195
+ const users = [
196
+ { id: 101, fullName: 'Alice Johnson', email: 'alice@example.com' },
197
+ { id: 102, fullName: 'Bob Smith', email: 'bob@example.com' },
198
+ { id: 103, fullName: 'Charlie Brown', email: 'charlie@example.com' },
199
+ ]
200
+
201
+ return (
202
+ <SearchSelect
203
+ options={users}
204
+ labelKey="fullName"
205
+ valueKey="id"
206
+ placeholder="Select a user..."
207
+ value={userId}
208
+ onChange={(id) => setUserId(id)}
209
+ />
210
+ )
211
+ }
212
+ ```
213
+
214
+ #### Props
215
+
216
+ | Prop | Type | Default | Description |
217
+ |---|---|---|---|
218
+ | `options` | `Array<string\|number\|boolean\|object>` | `[]` | Selectable options |
219
+ | `labelKey` | `string` | `'label'` | Key for display text (object options only) |
220
+ | `valueKey` | `string` | `'value'` | Key for the value (object options only) |
221
+ | `placeholder` | `string` | `'Select...'` | Placeholder text |
222
+ | `value` | `any` | `null` | Currently selected value |
223
+ | `onChange` | `(value: any) => void` | — | Called with selected value |
224
+ | `id` | `string` | `'filterable-select'` | Input element ID |
225
+ | `disabled` | `boolean` | `false` | Disable the input |
226
+ | `className` | `string` | — | Additional CSS classes on wrapper |
227
+
228
+ #### Inside Bootstrap Input Groups
229
+
230
+ ```jsx
231
+ <div className="input-group mb-3">
232
+ <span className="input-group-text">Subject</span>
233
+ <SearchSelect
234
+ options={subjects}
235
+ labelKey="name"
236
+ valueKey="id"
237
+ placeholder="Search subject..."
238
+ value={subjectId}
239
+ onChange={setSubjectId}
240
+ />
241
+ </div>
242
+ ```
243
+
244
+ ---
245
+
246
+ ### Label
247
+
248
+ A simple form label with a Bootstrap-styled required field indicator.
249
+
250
+ #### Import
251
+
252
+ ```js
253
+ import { Label } from 'react-bootstrap-plugins/Label'
254
+ // or
255
+ import { Label } from 'react-bootstrap-plugins'
256
+ ```
257
+
258
+ #### Basic Usage
259
+
260
+ ```jsx
261
+ import { Label } from 'react-bootstrap-plugins'
262
+
263
+ <Label hf="studentName" label="Student Name" />
264
+ // Renders: <label for="studentName">Student Name <b class="text-danger">*</b></label>
265
+ ```
266
+
267
+ #### Props
268
+
269
+ | Prop | Type | Default | Description |
270
+ |---|---|---|---|
271
+ | `hf` | `string` | `'default'` | `htmlFor` attribute — matches input `id` |
272
+ | `label` | `string` | `'Title'` | Label text |
273
+ | `required` | `boolean` | `true` | Show red asterisk |
274
+ | `className` | `string` | — | Additional CSS classes |
275
+
276
+ #### Examples
277
+
278
+ **With required indicator:**
279
+ ```jsx
280
+ <Label hf="email" label="Email Address" required />
281
+ ```
282
+
283
+ **Optional field (no asterisk):**
284
+ ```jsx
285
+ <Label hf="middleName" label="Middle Name" required={false} />
286
+ ```
287
+
288
+ **With Bootstrap grid:**
289
+ ```jsx
290
+ <div className="mb-3 row">
291
+ <div className="col-sm-3">
292
+ <Label hf="phone" label="Phone Number" className="col-form-label" />
293
+ </div>
294
+ <div className="col-sm-9">
295
+ <input id="phone" type="tel" className="form-control" />
296
+ </div>
297
+ </div>
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Import Patterns
303
+
304
+ All patterns are tree-shakeable. Your bundler will only include the code you actually import.
305
+
306
+ ```js
307
+ // Single component — smallest bundle
308
+ import { DatePicker } from 'react-bootstrap-plugins/DatePicker'
309
+
310
+ // Multiple named — tree-shaken
311
+ import { DatePicker, Label } from 'react-bootstrap-plugins'
312
+
313
+ // All components
314
+ import { DatePicker, SearchSelect, Label } from 'react-bootstrap-plugins'
315
+
316
+ // CSS (required for DatePicker)
317
+ import 'react-bootstrap-plugins/css/datepicker.css'
318
+ ```
319
+
320
+ ---
321
+
322
+ ## Dark Mode
323
+
324
+ All components respect Bootstrap 5's dark mode. Set `data-bs-theme="dark"` on any parent element:
325
+
326
+ ```html
327
+ <html data-bs-theme="dark">
328
+ <!-- DatePicker popover, dropdown, and all styling adapt automatically -->
329
+ </html>
330
+ ```
331
+
332
+ Or toggle dynamically:
333
+
334
+ ```jsx
335
+ function App() {
336
+ const [theme, setTheme] = useState('light')
337
+
338
+ return (
339
+ <div data-bs-theme={theme}>
340
+ <DatePicker value={date} onChange={handleDate} />
341
+ </div>
342
+ )
343
+ }
344
+ ```
345
+
346
+ ---
347
+
348
+ ## Bundle Size
349
+
350
+ | Import | Approx. Size (min+gzip) |
351
+ |---|---|
352
+ | `DatePicker` (with CSS) | ~5.5 KB |
353
+ | `SearchSelect` | ~1.2 KB |
354
+ | `Label` | ~0.3 KB |
355
+ | All three (barrel) | ~6.5 KB |
356
+
357
+ Measured with ESM, tree-shaken, minified, gzipped. Your actual size depends on your bundler configuration.
358
+
359
+ ---
360
+
361
+ ## Browser Support
362
+
363
+ - Chrome 90+
364
+ - Firefox 90+
365
+ - Safari 15+
366
+ - Edge 90+
367
+
368
+ Requires `ResizeObserver` (all modern browsers), CSS Grid, and CSS Custom Properties.
369
+
370
+ ---
371
+
372
+ ## Security
373
+
374
+ - All user content rendered as React text nodes — no raw HTML injection surfaces
375
+ - No dynamic code evaluation or runtime code generation
376
+ - DatePicker input is `readOnly` — displayed value is always the formatted date, never raw user input
377
+ - Synthetic events use safe, explicit value construction
378
+ - Popover content is isolated from the input DOM tree via React Portal
379
+
380
+ Report security issues to: security@allios.app
381
+
382
+ ---
383
+
384
+ ## Development
385
+
386
+ ```bash
387
+ # Clone and install
388
+ git clone https://github.com/allios/react-bootstrap-plugins.git
389
+ cd react-bootstrap-plugins
390
+ pnpm install
391
+
392
+ # Build
393
+ pnpm run build
394
+
395
+ # Watch mode (rebuild on changes)
396
+ pnpm run dev
397
+ ```
398
+
399
+ ### Project Structure
400
+
401
+ ```
402
+ src/
403
+ ├── index.js Barrel export
404
+ ├── lib/cn.js Internal classname utility
405
+ ├── components/
406
+ │ ├── DatePicker.jsx Date/time/datetime picker
407
+ │ ├── SearchSelect.jsx Searchable select dropdown
408
+ │ ├── Label.jsx Form label
409
+ │ └── *.d.ts TypeScript declarations
410
+ └── css/
411
+ └── datepicker-bootstrap.css
412
+ ```
413
+
414
+ ---
415
+
416
+ ## License
417
+
418
+ MIT © [Tumwesigye Robert](https://allios.app)
419
+
420
+ ---
421
+
422
+ ## Related
423
+
424
+ - [Bootstrap 5](https://getbootstrap.com/) — CSS framework this package integrates with
425
+ - [React](https://react.dev/) — UI library
426
+ - [AlliOs](https://allios.app) — Multi-tenant SaaS ecosystem this package originated from
@@ -0,0 +1,2 @@
1
+ 'use strict';var chunk4ISYCPRB_cjs=require('./chunk-4ISYCPRB.cjs');require('./chunk-QQNPKA7A.cjs');Object.defineProperty(exports,"DatePicker",{enumerable:true,get:function(){return chunk4ISYCPRB_cjs.a}});//# sourceMappingURL=DatePicker.cjs.map
2
+ //# sourceMappingURL=DatePicker.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"DatePicker.cjs"}
@@ -0,0 +1,45 @@
1
+ import * as React from 'react'
2
+
3
+ export interface DatePickerProps {
4
+ /** Picker mode (default 'date') */
5
+ mode?: 'date' | 'time' | 'datetime'
6
+ /** Currently selected Date (alias for `value`) */
7
+ selected?: Date | null
8
+ /** Currently selected Date */
9
+ value?: Date | string | number | null
10
+ /**
11
+ * Synthetic event handler — `e.target.value` is a pre-formatted string:
12
+ * - date → `"YYYY-MM-DD"`
13
+ * - time → `"hh:mm AA"`
14
+ * - datetime → `"YYYY-MM-DD hh:mm AA"`
15
+ */
16
+ onChange?: (e: { target: { value: string | null; name: string; type: string } }) => void
17
+ /** Display format — tokens: yyyy, MM, dd, hh, mm, aa */
18
+ dateFormat?: string
19
+ /** Placeholder text when empty */
20
+ placeholderText?: string
21
+ /** Bootstrap size variant */
22
+ size?: 'sm' | 'lg'
23
+ /** Show a clear button on the input */
24
+ isClearable?: boolean
25
+ /** Disable the input */
26
+ disabled?: boolean
27
+ /** Earliest selectable date */
28
+ minDate?: Date
29
+ /** Latest selectable date */
30
+ maxDate?: Date
31
+ /** Minute step in the time list (default 5) */
32
+ timeIntervals?: number
33
+ /** Timezone identifier for display (default 'Kampala') */
34
+ timezone?: string
35
+ /** Additional CSS classes on the input */
36
+ className?: string
37
+ /** Input element ID */
38
+ id?: string
39
+ /** Input name attribute */
40
+ name?: string
41
+ }
42
+
43
+ export const DatePicker: React.ForwardRefExoticComponent<
44
+ DatePickerProps & React.RefAttributes<HTMLInputElement>
45
+ >
@@ -0,0 +1,2 @@
1
+ export{a as DatePicker}from'./chunk-DIUGH74M.js';import'./chunk-46AJ2Q5H.js';//# sourceMappingURL=DatePicker.js.map
2
+ //# sourceMappingURL=DatePicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"DatePicker.js"}
package/dist/Label.cjs ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict';var chunkCZV7QBHA_cjs=require('./chunk-CZV7QBHA.cjs');Object.defineProperty(exports,"Label",{enumerable:true,get:function(){return chunkCZV7QBHA_cjs.a}});//# sourceMappingURL=Label.cjs.map
2
+ //# sourceMappingURL=Label.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"Label.cjs"}
@@ -0,0 +1,16 @@
1
+ import * as React from 'react'
2
+
3
+ export interface LabelProps {
4
+ /** Additional CSS classes */
5
+ className?: string
6
+ /** htmlFor attribute — associates label with input ID (default 'default') */
7
+ hf?: string
8
+ /** Whether to show the required asterisk (default true) */
9
+ required?: boolean
10
+ /** Label text content (default 'Title') */
11
+ label?: string
12
+ }
13
+
14
+ export const Label: React.ForwardRefExoticComponent<
15
+ LabelProps & React.RefAttributes<HTMLLabelElement>
16
+ >
package/dist/Label.js ADDED
@@ -0,0 +1,2 @@
1
+ export{a as Label}from'./chunk-F3KMQZXU.js';//# sourceMappingURL=Label.js.map
2
+ //# sourceMappingURL=Label.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"Label.js"}
@@ -0,0 +1,2 @@
1
+ 'use strict';var chunkHBS6VOGV_cjs=require('./chunk-HBS6VOGV.cjs');require('./chunk-QQNPKA7A.cjs');module.exports=chunkHBS6VOGV_cjs.a;//# sourceMappingURL=SearchSelect.cjs.map
2
+ //# sourceMappingURL=SearchSelect.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"SearchSelect.cjs"}
@@ -0,0 +1,28 @@
1
+ import * as React from 'react'
2
+
3
+ export interface SearchSelectProps<T = any> {
4
+ /** Additional CSS classes on the wrapper */
5
+ className?: string
6
+ /** Selectable options — primitives (string/number/boolean) or objects */
7
+ options?: T[] | Array<string | number | boolean>
8
+ /** Key for display text when options are objects (default 'label') */
9
+ labelKey?: string
10
+ /** Key for the value when options are objects (default 'value') */
11
+ valueKey?: string
12
+ /** Placeholder text (default 'Select...') */
13
+ placeholder?: string
14
+ /** Currently selected value */
15
+ value?: any
16
+ /** Called with the selected value when user picks */
17
+ onChange?: (value: any) => void
18
+ /** Input element ID */
19
+ id?: string
20
+ /** Disable the input */
21
+ disabled?: boolean
22
+ }
23
+
24
+ declare const SearchSelect: React.ForwardRefExoticComponent<
25
+ SearchSelectProps & React.RefAttributes<HTMLDivElement>
26
+ >
27
+
28
+ export default SearchSelect
@@ -0,0 +1,2 @@
1
+ export{a as default}from'./chunk-NOGRIWSU.js';import'./chunk-46AJ2Q5H.js';//# sourceMappingURL=SearchSelect.js.map
2
+ //# sourceMappingURL=SearchSelect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"SearchSelect.js"}
@@ -0,0 +1,2 @@
1
+ function f(...t){let s=[];for(let e of t)if(e){if(typeof e=="string")s.push(e);else if(Array.isArray(e)){let o=f(...e);o&&s.push(o);}else if(typeof e=="object")for(let[o,n]of Object.entries(e))n&&s.push(o);}return s.join(" ")}export{f as a};//# sourceMappingURL=chunk-46AJ2Q5H.js.map
2
+ //# sourceMappingURL=chunk-46AJ2Q5H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/cn.js"],"names":["cn","args","classes","arg","nested","key","value"],"mappings":"AAeO,SAASA,CAAAA,CAAAA,GAAMC,CAAAA,CAAM,CAC1B,IAAMC,CAAAA,CAAU,EAAC,CAEjB,IAAA,IAAWC,CAAAA,IAAOF,CAAAA,CAChB,GAAKE,CAAAA,CAAAA,CAEL,GAAI,OAAOA,CAAAA,EAAQ,QAAA,CACjBD,CAAAA,CAAQ,IAAA,CAAKC,CAAG,CAAA,CAAA,KAAA,GACP,KAAA,CAAM,OAAA,CAAQA,CAAG,CAAA,CAAG,CAC7B,IAAMC,CAAAA,CAASJ,CAAAA,CAAG,GAAGG,CAAG,CAAA,CACpBC,CAAAA,EAAQF,CAAAA,CAAQ,IAAA,CAAKE,CAAM,EACjC,CAAA,KAAA,GAAW,OAAOD,CAAAA,EAAQ,QAAA,CACxB,IAAA,GAAW,CAACE,CAAAA,CAAKC,CAAK,CAAA,GAAK,MAAA,CAAO,OAAA,CAAQH,CAAG,CAAA,CACvCG,CAAAA,EAAOJ,CAAAA,CAAQ,IAAA,CAAKG,CAAG,EAAA,CAKjC,OAAOH,CAAAA,CAAQ,IAAA,CAAK,GAAG,CACzB","file":"chunk-46AJ2Q5H.js","sourcesContent":["/**\n * Utility for conditionally joining CSS class names together.\n * Filters out falsy values and joins with space.\n *\n * @param {...any} args - Class name strings, objects, or arrays\n * @returns {string} Joined class string\n *\n * @example\n * cn('btn', isActive && 'btn-primary', 'px-3')\n * // => 'btn btn-primary px-3'\n *\n * @example\n * cn('base-class', { 'active': isActive, 'disabled': isDisabled })\n * // => 'base-class active' (when isActive=true, isDisabled=false)\n */\nexport function cn(...args) {\n const classes = []\n\n for (const arg of args) {\n if (!arg) continue\n\n if (typeof arg === 'string') {\n classes.push(arg)\n } else if (Array.isArray(arg)) {\n const nested = cn(...arg)\n if (nested) classes.push(nested)\n } else if (typeof arg === 'object') {\n for (const [key, value] of Object.entries(arg)) {\n if (value) classes.push(key)\n }\n }\n }\n\n return classes.join(' ')\n}\n"]}
@@ -0,0 +1,2 @@
1
+ 'use strict';var chunkQQNPKA7A_cjs=require('./chunk-QQNPKA7A.cjs'),i=require('react'),reactDom=require('react-dom'),jsxRuntime=require('react/jsx-runtime');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var i__namespace=/*#__PURE__*/_interopNamespace(i);var Ye=["Su","Mo","Tu","We","Th","Fr","Sa"],Ce=["January","February","March","April","May","June","July","August","September","October","November","December"],Ee=Array.from({length:60},(n,t)=>t),g=12,V=(n,t)=>new Date(n,t+1,0).getDate(),ne=(n,t)=>n&&t&&n.getFullYear()===t.getFullYear()&&n.getMonth()===t.getMonth()&&n.getDate()===t.getDate(),Ae=(n,t,r)=>!(t&&n<new Date(t.getFullYear(),t.getMonth(),t.getDate())||r&&n>new Date(r.getFullYear(),r.getMonth(),r.getDate())),Ie=(n,t)=>{let r=new Date(n,t,1).getDay(),m=V(n,t),p=[],b=V(n,t-1);for(let d=r-1;d>=0;d--){let D=b-d;p.push({day:D,date:new Date(n,t-1,D),isOutside:true});}for(let d=1;d<=m;d++)p.push({day:d,date:new Date(n,t,d),isOutside:false});let y=42-p.length;for(let d=1;d<=y;d++)p.push({day:d,date:new Date(n,t+1,d),isOutside:true});return p},L=(n,t,r)=>{if(!n||isNaN(n.getTime()))return "";let m=n.getFullYear(),p=String(n.getMonth()+1).padStart(2,"0"),b=String(n.getDate()).padStart(2,"0"),y=n.getHours(),d=String(n.getMinutes()).padStart(2,"0"),D=y>=12?"PM":"AM";y=y%12||12;let k=String(y).padStart(2,"0");if(r)return r.replace("yyyy",m).replace("MM",p).replace("dd",b).replace("hh",k).replace("mm",d).replace("aa",D);switch(t){case "time":return `${k}:${d} ${D}`;case "datetime":return `${m}-${p}-${b} ${k}:${d} ${D}`;default:return `${m}-${p}-${b}`}},O=(n,t,r="date")=>({target:{value:n,name:t,type:r},preventDefault:()=>{},stopPropagation:()=>{},nativeEvent:null}),Te={date:300,time:300,datetime:400,year:250},Fe=n=>{if(!n)return document.documentElement;let t=n.parentElement;for(;t;){let r=window.getComputedStyle(t),m=r.overflowY||r.overflow;if(m==="auto"||m==="scroll")return t;t=t.parentElement;}return document.documentElement},Oe=(n,t)=>{if(!n)return {};let r=n.getBoundingClientRect(),m=t||300,p=window.innerHeight-r.bottom,b=r.top,y=p<m&&b>p,d=Math.max(r.width,window.innerWidth<576?220:260);return {position:"fixed",top:y?Math.max(4,r.top-m-4):r.bottom+4,left:Math.max(4,Math.min(r.left,window.innerWidth-d-4)),minWidth:d,maxWidth:window.innerWidth-8,zIndex:1070}},$e=i__namespace.forwardRef(({className:n,mode:t="date",selected:r,value:m,onChange:p,dateFormat:b,placeholderText:y,size:d,isClearable:D=false,disabled:k=false,minDate:q,maxDate:z,timeIntervals:We=5,timezone:_e="Kampala",id:se,name:N,...re},$)=>{let ie=e=>{if(!e)return null;if(e instanceof Date)return isNaN(e.getTime())?null:e;if(typeof e=="string"||typeof e=="number"){let a=new Date(e);if(!isNaN(a.getTime()))return a;if(typeof e=="string"){let l=e.match(/^(\d{1,2}):(\d{2})\s*(AM|PM)$/i);if(l){let c=parseInt(l[1],10),h=parseInt(l[2],10),_=l[3].toUpperCase();c===12&&_==="AM"&&(c=0),c!==12&&_==="PM"&&(c+=12);let X=new Date;return new Date(X.getFullYear(),X.getMonth(),X.getDate(),c,h,0,0)}let u=e.match(/^(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{2})\s*(AM|PM)$/i);if(u){let c=parseInt(u[4],10),h=parseInt(u[5],10),_=u[6].toUpperCase();return c===12&&_==="AM"&&(c=0),c!==12&&_==="PM"&&(c+=12),new Date(parseInt(u[1]),parseInt(u[2])-1,parseInt(u[3]),c,h,0,0)}}return null}return null},o=i__namespace.useMemo(()=>ie(r??m),[r instanceof Date?r.getTime():r,m instanceof Date?m.getTime():m]),Z=t==="date"||t==="datetime",S=t==="time"||t==="datetime",[R,I]=i__namespace.useState(false),[P,K]=i__namespace.useState(()=>o?o.getFullYear():new Date().getFullYear()),[v,J]=i__namespace.useState(()=>o?o.getMonth():new Date().getMonth()),[w,x]=i__namespace.useState(o),[Y,ee]=i__namespace.useState(()=>o&&o.getHours()%12||12),[C,te]=i__namespace.useState(()=>o?o.getMinutes():0),[E,ae]=i__namespace.useState(()=>o&&o.getHours()>=12?"PM":"AM"),[U,T]=i__namespace.useState(false),[j,B]=i__namespace.useState(()=>Math.floor((o?o.getFullYear():new Date().getFullYear())/g)*g),[oe,ce]=i__namespace.useState({}),F=i__namespace.useRef(null),H=i__namespace.useRef(null),G=i__namespace.useRef(null);i__namespace.useEffect(()=>{let e=document.createElement("div");return e.className="datepicker-portal-root",document.body.appendChild(e),G.current=e,()=>{e.parentNode&&document.body.removeChild(e),G.current=null;}},[]),i__namespace.useEffect(()=>{o&&!isNaN(o.getTime())?(x(o),K(o.getFullYear()),J(o.getMonth()),ee(o.getHours()%12||12),te(o.getMinutes()),ae(o.getHours()>=12?"PM":"AM"),B(Math.floor(o.getFullYear()/g)*g)):x(null);},[o]),i__namespace.useEffect(()=>{if(!R)return;let e=()=>H.current?H.current.getBoundingClientRect().height:Te[U?"year":t]||300,a=Fe(F.current),l=()=>{requestAnimationFrame(()=>{ce(Oe(F.current,e()));});};return l(),a.addEventListener("scroll",l,{passive:true}),window.addEventListener("resize",l),()=>{a.removeEventListener("scroll",l),window.removeEventListener("resize",l);}},[R,t,U]),i__namespace.useEffect(()=>{if(!R)return;let e=a=>{H.current&&!H.current.contains(a.target)&&F.current&&!F.current.contains(a.target)&&(I(false),T(false));};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[R]);let A=(e,a,l,u)=>{let c=new Date(e),h=a%12;return u==="PM"&&(h+=12),h===12&&u==="AM"&&(h=0),c.setHours(h,l,0,0),c},W=e=>{if(!e||isNaN(e.getTime()))return;let a=L(e,t,b);p?.(O(a,N,t));},le=e=>{if(!e){p?.(O(null,N,t)),I(false),T(false);return}W(e),t==="date"&&(I(false),T(false));},de=e=>{if(x(e),t==="date")le(e);else if(t==="datetime"){let a=A(e,Y,C,E);W(a);}},ue=Ie(P,v),pe=()=>{let e=P,a=v;v===0?(e=P-1,a=11):a=v-1,K(e),J(a);let l=w||new Date,u=V(e,a),c=new Date(e,a,Math.min(l.getDate(),u));x(c),W(S?A(c,Y,C,E):c);},me=()=>{let e=P,a=v;v===11?(e=P+1,a=0):a=v+1,K(e),J(a);let l=w||new Date,u=V(e,a),c=new Date(e,a,Math.min(l.getDate(),u));x(c),W(S?A(c,Y,C,E):c);},fe=new Date,be=q?new Date(q.getFullYear(),q.getMonth(),q.getDate()):null,ge=z?new Date(z.getFullYear(),z.getMonth(),z.getDate()):null,ye=e=>{if(ee(e),S){let a=A(w||new Date,e,C,E);p?.(O(L(a,t,b),N,t));}},ve=e=>{if(te(e),S){let a=A(w||new Date,Y,e,E);p?.(O(L(a,t,b),N,t));}},we=e=>{if(ae(e),S){let a=A(w||new Date,Y,C,e);p?.(O(L(a,t,b),N,t));}},he=()=>{B(Math.floor(P/g)*g),T(true);},Me=e=>{K(e),T(false);let a=w||new Date,l=V(e,v),u=new Date(e,v,Math.min(a.getDate(),l));x(u),W(S?A(u,Y,C,E):u);},Q=Math.floor(j/g)*g,De=Array.from({length:g},(e,a)=>Q+a),ke=e=>{e.stopPropagation(),x(null),p?.(O(null,N));},Ne=e=>{e.key==="Escape"&&(I(false),T(false),F.current?.blur()),(e.key==="ArrowDown"||e.key==="Enter"||e.key===" ")&&(e.preventDefault(),I(true));},Se=i__namespace.useCallback(e=>{F.current=e,typeof $=="function"?$(e):$&&($.current=e);},[$]),Re=y??(t==="time"?"Select time":t==="datetime"?"Select date & time":"Select date"),Pe=jsxRuntime.jsxs("div",{ref:H,className:chunkQQNPKA7A_cjs.a("datepicker-popover card border shadow-sm",t==="datetime"&&"datepicker-popover--wide"),style:oe,children:[U&&Z&&jsxRuntime.jsxs("div",{className:"datepicker-year-picker p-3",children:[jsxRuntime.jsxs("div",{className:"d-flex align-items-center justify-content-between mb-2",children:[jsxRuntime.jsx("button",{type:"button",className:"btn btn-sm btn-outline-secondary border-0 px-1",onClick:()=>B(j-g),"aria-label":"Previous years",children:"\u2039"}),jsxRuntime.jsxs("span",{className:"fw-semibold small",children:[Q," \u2013 ",Q+g-1]}),jsxRuntime.jsx("button",{type:"button",className:"btn btn-sm btn-outline-secondary border-0 px-1",onClick:()=>B(j+g),"aria-label":"Next years",children:"\u203A"})]}),jsxRuntime.jsx("div",{className:"datepicker-year-grid",children:De.map(e=>{let a=e===new Date().getFullYear(),l=w&&e===w.getFullYear();return jsxRuntime.jsx("button",{type:"button",className:chunkQQNPKA7A_cjs.a("datepicker-year-cell btn btn-sm",l&&"btn-primary",!l&&a&&"btn-outline-primary",!l&&!a&&"btn-light border"),onClick:()=>Me(e),children:e},e)})})]}),!U&&jsxRuntime.jsx(jsxRuntime.Fragment,{children:jsxRuntime.jsxs("div",{className:chunkQQNPKA7A_cjs.a("d-flex",t==="datetime"?"flex-row":"flex-column"),children:[Z&&jsxRuntime.jsxs("div",{className:"datepicker-calendar p-2",children:[jsxRuntime.jsxs("div",{className:"d-flex align-items-center justify-content-between mb-2",children:[jsxRuntime.jsx("button",{type:"button",className:"btn btn-sm btn-outline-secondary border-0 px-1",onClick:pe,"aria-label":"Previous month",children:"\u2039"}),jsxRuntime.jsxs("div",{className:"d-flex align-items-center gap-1",children:[jsxRuntime.jsx("span",{className:"fw-semibold small",children:Ce[v]}),jsxRuntime.jsx("button",{type:"button",className:"btn btn-sm btn-link text-decoration-none text-primary fw-semibold small p-0",onClick:he,"aria-label":"Choose year",children:P})]}),jsxRuntime.jsx("button",{type:"button",className:"btn btn-sm btn-outline-secondary border-0 px-1",onClick:me,"aria-label":"Next month",children:"\u203A"})]}),jsxRuntime.jsx("div",{className:"datepicker-days-header",children:Ye.map(e=>jsxRuntime.jsx("div",{className:"datepicker-day-label",children:e},e))}),jsxRuntime.jsx("div",{className:"datepicker-days-grid",children:ue.map((e,a)=>{let l=ne(e.date,fe),u=w&&ne(e.date,w),c=Ae(e.date,be,ge),h=e.isOutside||!c;return jsxRuntime.jsx("button",{type:"button",disabled:h,className:chunkQQNPKA7A_cjs.a("datepicker-day",l&&"datepicker-day--today",u&&"datepicker-day--selected",e.isOutside&&"datepicker-day--outside",!c&&"datepicker-day--disabled"),onClick:()=>de(e.date),tabIndex:e.isOutside?-1:0,children:e.day},a)})})]}),t==="datetime"&&jsxRuntime.jsx("div",{className:"vr mx-1 my-2"}),S&&jsxRuntime.jsxs("div",{className:"datepicker-time p-2 d-flex flex-column",style:{minWidth:180},children:[t==="datetime"&&jsxRuntime.jsx("div",{className:"small fw-semibold text-muted text-center mb-1",children:"Time"}),jsxRuntime.jsxs("div",{className:"d-flex justify-content-center gap-2",children:[jsxRuntime.jsxs("div",{className:"datepicker-time-col",children:[jsxRuntime.jsx("div",{className:"datepicker-time-col-label",children:"Hour"}),jsxRuntime.jsx("div",{className:"datepicker-time-col-scroll",children:Array.from({length:12},(e,a)=>a+1).map(e=>jsxRuntime.jsx("button",{type:"button",className:chunkQQNPKA7A_cjs.a("datepicker-time-item",e===Y&&"active"),onClick:()=>ye(e),children:String(e).padStart(2,"0")},e))})]}),jsxRuntime.jsx("span",{className:"datepicker-time-separator",children:":"}),jsxRuntime.jsxs("div",{className:"datepicker-time-col",children:[jsxRuntime.jsx("div",{className:"datepicker-time-col-label",children:"Min"}),jsxRuntime.jsx("div",{className:"datepicker-time-col-scroll",children:Ee.map(e=>jsxRuntime.jsx("button",{type:"button",className:chunkQQNPKA7A_cjs.a("datepicker-time-item",e===C&&"active"),onClick:()=>ve(e),children:String(e).padStart(2,"0")},e))})]}),jsxRuntime.jsxs("div",{className:"datepicker-time-col",children:[jsxRuntime.jsx("div",{className:"datepicker-time-col-label",children:"\xA0"}),jsxRuntime.jsx("div",{className:"d-flex flex-column gap-1 mt-1",children:["AM","PM"].map(e=>jsxRuntime.jsx("button",{type:"button",className:chunkQQNPKA7A_cjs.a("datepicker-time-item","datepicker-time-item--ampm",E===e&&"active"),onClick:()=>we(e),children:e},e))})]})]})]})]})})]});return jsxRuntime.jsxs("div",{className:"position-relative d-inline-block w-100",style:{minWidth:0},children:[jsxRuntime.jsxs("div",{className:"position-relative",children:[jsxRuntime.jsx("input",{ref:Se,id:se,name:N,type:"text",readOnly:true,disabled:k,className:chunkQQNPKA7A_cjs.a("form-control",d==="sm"&&"form-control-sm",d==="lg"&&"form-control-lg","pe-5",n),placeholder:Re,value:L(o,t,b),onClick:()=>!k&&I(!R),onKeyDown:Ne,"aria-haspopup":"dialog","aria-expanded":R,autoComplete:"off",...re}),D&&o&&!k&&jsxRuntime.jsx("button",{type:"button",className:"btn btn-sm btn-link position-absolute top-50 end-0 translate-middle-y pe-2 text-secondary",style:{zIndex:2},onClick:ke,tabIndex:-1,"aria-label":"Clear",children:"\xD7"})]}),R&&!k&&G.current&&reactDom.createPortal(Pe,G.current)]})});$e.displayName="DatePicker";exports.a=$e;//# sourceMappingURL=chunk-4ISYCPRB.cjs.map
2
+ //# sourceMappingURL=chunk-4ISYCPRB.cjs.map