secure-ui-components 0.1.0-beta.1 โ 0.1.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.
- package/README.md +434 -155
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,41 +1,42 @@
|
|
|
1
1
|
# secure-ui-components
|
|
2
2
|
|
|
3
|
-
Security-first
|
|
3
|
+
Security-first Web Component library with zero dependencies.
|
|
4
4
|
|
|
5
5
|
**[Live Demo](https://barryprender.github.io/Secure-UI/)** โ Try all components in your browser.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Features
|
|
8
8
|
|
|
9
|
-
- **8 Secure Components
|
|
10
|
-
- **4-Tier Security System
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **SSR Friendly
|
|
15
|
-
- **
|
|
9
|
+
- **8 Secure Components** โ Input, Textarea, Select, Form, File Upload, DateTime, Table, Submit Button
|
|
10
|
+
- **4-Tier Security System** โ `public`, `authenticated`, `sensitive`, `critical`
|
|
11
|
+
- **Zero Dependencies** โ Pure TypeScript, no runtime dependencies
|
|
12
|
+
- **Progressive Enhancement** โ All components render meaningful markup and work without JavaScript
|
|
13
|
+
- **CSP-Safe** โ Styles loaded via `<link>` from `'self'`; no `unsafe-inline` required
|
|
14
|
+
- **SSR Friendly** โ Adopts server-rendered markup on upgrade; no document access in constructors
|
|
15
|
+
- **Fully Customisable** โ CSS Design Tokens + `::part()` API
|
|
16
|
+
- **Comprehensive Testing** โ 689 tests, 80%+ branch coverage
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
18
21
|
|
|
19
22
|
```bash
|
|
20
23
|
npm install secure-ui-components
|
|
21
24
|
```
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
---
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
## Quick Start
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
### Bundler (Vite, Webpack, Rollup)
|
|
28
31
|
|
|
29
32
|
```js
|
|
30
33
|
import 'secure-ui-components/secure-input';
|
|
31
34
|
import 'secure-ui-components/secure-form';
|
|
32
35
|
```
|
|
33
36
|
|
|
34
|
-
Then use them in your HTML:
|
|
35
|
-
|
|
36
37
|
```html
|
|
37
38
|
<secure-input
|
|
38
|
-
label="Email
|
|
39
|
+
label="Email"
|
|
39
40
|
name="email"
|
|
40
41
|
type="email"
|
|
41
42
|
required
|
|
@@ -43,7 +44,7 @@ Then use them in your HTML:
|
|
|
43
44
|
></secure-input>
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
### CDN / Vanilla HTML
|
|
47
|
+
### CDN / Vanilla HTML
|
|
47
48
|
|
|
48
49
|
```html
|
|
49
50
|
<!DOCTYPE html>
|
|
@@ -52,13 +53,7 @@ Then use them in your HTML:
|
|
|
52
53
|
<link rel="stylesheet" href="https://unpkg.com/secure-ui-components/dist/styles/tokens.css">
|
|
53
54
|
</head>
|
|
54
55
|
<body>
|
|
55
|
-
<secure-input
|
|
56
|
-
label="Email Address"
|
|
57
|
-
name="email"
|
|
58
|
-
type="email"
|
|
59
|
-
required
|
|
60
|
-
security-tier="authenticated"
|
|
61
|
-
></secure-input>
|
|
56
|
+
<secure-input label="Email" name="email" type="email" required></secure-input>
|
|
62
57
|
|
|
63
58
|
<script type="module">
|
|
64
59
|
import 'https://unpkg.com/secure-ui-components/dist/index.js';
|
|
@@ -67,10 +62,76 @@ Then use them in your HTML:
|
|
|
67
62
|
</html>
|
|
68
63
|
```
|
|
69
64
|
|
|
70
|
-
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Security Tiers
|
|
71
68
|
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
All components accept a `security-tier` attribute. The default is `critical`.
|
|
70
|
+
|
|
71
|
+
| Tier | Level | Masking | Autocomplete | Rate Limit | Audit |
|
|
72
|
+
|------|-------|---------|--------------|------------|-------|
|
|
73
|
+
| `public` | 1 | off | on | off | minimal |
|
|
74
|
+
| `authenticated` | 2 | off | on | off | changes + submission |
|
|
75
|
+
| `sensitive` | 3 | partial (last 4 chars) | off | 10/min | full |
|
|
76
|
+
| `critical` | 4 | full | off | 5/min | full |
|
|
77
|
+
|
|
78
|
+
```html
|
|
79
|
+
<secure-input security-tier="public" label="Username" name="username"></secure-input>
|
|
80
|
+
<secure-input security-tier="sensitive" label="Card Number" name="card"></secure-input>
|
|
81
|
+
<secure-input security-tier="critical" type="password" label="Password" name="password"></secure-input>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The `security-tier` attribute is **immutable after connection** โ changes after `connectedCallback` are silently ignored (fail-secure).
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Components
|
|
89
|
+
|
|
90
|
+
### `<secure-input>`
|
|
91
|
+
|
|
92
|
+
Text input with XSS prevention, masking, password strength validation, and rate limiting.
|
|
93
|
+
|
|
94
|
+
**Attributes**
|
|
95
|
+
|
|
96
|
+
| Attribute | Type | Description |
|
|
97
|
+
|-----------|------|-------------|
|
|
98
|
+
| `label` | string | Visible field label |
|
|
99
|
+
| `name` | string | Form field name |
|
|
100
|
+
| `type` | string | Input type โ `text`, `password`, `email`, `tel`, `number`, `url`, `search` |
|
|
101
|
+
| `placeholder` | string | Placeholder text |
|
|
102
|
+
| `required` | boolean | Mark as required |
|
|
103
|
+
| `disabled` | boolean | Disable the field |
|
|
104
|
+
| `readonly` | boolean | Make read-only |
|
|
105
|
+
| `pattern` | string | Regex validation pattern |
|
|
106
|
+
| `minlength` | number | Minimum character length |
|
|
107
|
+
| `maxlength` | number | Maximum character length |
|
|
108
|
+
| `autocomplete` | string | Autocomplete hint (overridden to `off` for sensitive/critical) |
|
|
109
|
+
| `value` | string | Initial value |
|
|
110
|
+
| `security-tier` | string | `public` \| `authenticated` \| `sensitive` \| `critical` |
|
|
111
|
+
|
|
112
|
+
**Properties & Methods**
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
const el = document.querySelector('secure-input');
|
|
116
|
+
|
|
117
|
+
el.value // get current value (unmasked)
|
|
118
|
+
el.value = 'foo' // set value programmatically
|
|
119
|
+
el.valid // boolean โ passes all validation rules
|
|
120
|
+
el.name // field name string
|
|
121
|
+
el.getAuditLog() // array of audit log entries
|
|
122
|
+
el.clearAuditLog()
|
|
123
|
+
el.focus()
|
|
124
|
+
el.blur()
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Events**
|
|
128
|
+
|
|
129
|
+
| Event | Detail |
|
|
130
|
+
|-------|--------|
|
|
131
|
+
| `secure-input` | `{ name, value, masked, tier }` |
|
|
132
|
+
| `secure-audit` | `{ event, tier, timestamp, โฆ }` |
|
|
133
|
+
|
|
134
|
+
**Example**
|
|
74
135
|
|
|
75
136
|
```html
|
|
76
137
|
<secure-input
|
|
@@ -82,48 +143,171 @@ Text input with security features and validation.
|
|
|
82
143
|
></secure-input>
|
|
83
144
|
```
|
|
84
145
|
|
|
85
|
-
|
|
86
|
-
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### `<secure-textarea>`
|
|
149
|
+
|
|
150
|
+
Multi-line input with real-time character counter and rate limiting.
|
|
151
|
+
|
|
152
|
+
**Attributes:** `label`, `name`, `placeholder`, `required`, `disabled`, `readonly`, `minlength`, `maxlength`, `rows`, `cols`, `wrap`, `value`, `security-tier`
|
|
153
|
+
|
|
154
|
+
**Properties & Methods:** `value`, `name`, `valid`, `getAuditLog()`, `clearAuditLog()`, `focus()`, `blur()`
|
|
155
|
+
|
|
156
|
+
**Events:** `secure-textarea` โ `{ name, value, tier }`
|
|
87
157
|
|
|
88
158
|
```html
|
|
89
159
|
<secure-textarea
|
|
90
160
|
label="Description"
|
|
91
161
|
name="description"
|
|
92
|
-
rows="5"
|
|
93
162
|
maxlength="500"
|
|
163
|
+
rows="5"
|
|
94
164
|
></secure-textarea>
|
|
95
165
|
```
|
|
96
166
|
|
|
97
|
-
|
|
98
|
-
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### `<secure-select>`
|
|
170
|
+
|
|
171
|
+
Dropdown with option whitelist validation โ prevents value injection.
|
|
172
|
+
|
|
173
|
+
**Attributes:** `label`, `name`, `required`, `disabled`, `multiple`, `size`, `value`, `security-tier`
|
|
174
|
+
|
|
175
|
+
**Properties & Methods**
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
el.value // current value (comma-separated for multiple)
|
|
179
|
+
el.selectedOptions // string[] of selected values
|
|
180
|
+
el.valid
|
|
181
|
+
el.name
|
|
182
|
+
el.addOption(value, text, selected?)
|
|
183
|
+
el.removeOption(value)
|
|
184
|
+
el.clearOptions()
|
|
185
|
+
el.getAuditLog()
|
|
186
|
+
el.focus()
|
|
187
|
+
el.blur()
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Events:** `secure-select` โ `{ name, value, tier }`
|
|
99
191
|
|
|
100
192
|
```html
|
|
101
|
-
<secure-select
|
|
102
|
-
|
|
103
|
-
name="country"
|
|
104
|
-
required
|
|
105
|
-
>
|
|
193
|
+
<secure-select label="Country" name="country" required>
|
|
194
|
+
<option value="">Select a country</option>
|
|
106
195
|
<option value="us">United States</option>
|
|
107
196
|
<option value="uk">United Kingdom</option>
|
|
108
197
|
</secure-select>
|
|
109
198
|
```
|
|
110
199
|
|
|
111
|
-
|
|
112
|
-
|
|
200
|
+
Light DOM `<option>` children are transferred to the shadow DOM automatically. Only values added via `<option>` or `addOption()` are accepted โ attempts to set an arbitrary value are rejected.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### `<secure-form>`
|
|
205
|
+
|
|
206
|
+
Form container with CSRF protection, field validation, and optional fetch-enhanced submission.
|
|
207
|
+
|
|
208
|
+
> `<secure-form>` uses **light DOM** (no Shadow DOM) for native form submission compatibility.
|
|
209
|
+
|
|
210
|
+
**Attributes**
|
|
211
|
+
|
|
212
|
+
| Attribute | Description |
|
|
213
|
+
|-----------|-------------|
|
|
214
|
+
| `action` | Form submission URL |
|
|
215
|
+
| `method` | HTTP method (default `POST`) |
|
|
216
|
+
| `enctype` | Encoding type |
|
|
217
|
+
| `csrf-token` | CSRF token value injected as a hidden field |
|
|
218
|
+
| `csrf-field-name` | Hidden field name (default `csrf_token`) |
|
|
219
|
+
| `csrf-header-name` | Also send CSRF token in this request header |
|
|
220
|
+
| `novalidate` | Disable browser constraint validation |
|
|
221
|
+
| `enhance` | Enable fetch-based JSON submission instead of native |
|
|
222
|
+
| `security-tier` | Security tier |
|
|
223
|
+
|
|
224
|
+
**Properties & Methods**
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
el.valid // true if all secure child fields pass validation
|
|
228
|
+
el.securityTier
|
|
229
|
+
el.getData() // { fieldName: value, โฆ } including CSRF token
|
|
230
|
+
el.reset()
|
|
231
|
+
el.submit() // programmatic submit (triggers validation)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Events**
|
|
235
|
+
|
|
236
|
+
| Event | Detail |
|
|
237
|
+
|-------|--------|
|
|
238
|
+
| `secure-form-submit` | `{ formData, formElement, preventDefault() }` โ cancelable |
|
|
239
|
+
| `secure-form-success` | `{ formData, response }` โ only fired when `enhance` is set |
|
|
240
|
+
|
|
241
|
+
**Submission modes**
|
|
242
|
+
|
|
243
|
+
- **Without `enhance`** โ native browser form submission. Values from shadow DOM inputs are synced to hidden `<input type="hidden">` fields automatically.
|
|
244
|
+
- **With `enhance`** โ intercepts submit, validates all fields, sends JSON via `fetch`. Dispatches `secure-form-submit` (cancelable) then `secure-form-success` on success.
|
|
245
|
+
|
|
246
|
+
**Example**
|
|
113
247
|
|
|
114
248
|
```html
|
|
115
|
-
<secure-form
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
security-tier="sensitive"
|
|
120
|
-
>
|
|
121
|
-
<!-- Your form fields here -->
|
|
249
|
+
<secure-form action="/api/register" method="POST" csrf-token="abc123" enhance>
|
|
250
|
+
<secure-input label="Email" name="email" type="email" required></secure-input>
|
|
251
|
+
<secure-input label="Password" name="password" type="password" required security-tier="critical"></secure-input>
|
|
252
|
+
<secure-submit-button label="Register"></secure-submit-button>
|
|
122
253
|
</secure-form>
|
|
123
254
|
```
|
|
124
255
|
|
|
125
|
-
|
|
126
|
-
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### `<secure-file-upload>`
|
|
259
|
+
|
|
260
|
+
Drag-and-drop file upload with content validation and optional malware scan hook.
|
|
261
|
+
|
|
262
|
+
**Attributes**
|
|
263
|
+
|
|
264
|
+
| Attribute | Description |
|
|
265
|
+
|-----------|-------------|
|
|
266
|
+
| `label` | Visible label |
|
|
267
|
+
| `name` | Field name |
|
|
268
|
+
| `accept` | Accepted MIME types / extensions (e.g. `image/*,.pdf`) |
|
|
269
|
+
| `max-size` | Max file size in bytes |
|
|
270
|
+
| `multiple` | Allow multiple files |
|
|
271
|
+
| `required` | Mark as required |
|
|
272
|
+
| `capture` | Camera capture hint |
|
|
273
|
+
| `security-tier` | Security tier |
|
|
274
|
+
|
|
275
|
+
**Size limits by tier (when `max-size` is not set)**
|
|
276
|
+
|
|
277
|
+
| Tier | Limit |
|
|
278
|
+
|------|-------|
|
|
279
|
+
| `public` | 20 MB |
|
|
280
|
+
| `authenticated` | 10 MB |
|
|
281
|
+
| `sensitive` | 5 MB |
|
|
282
|
+
| `critical` | 2 MB |
|
|
283
|
+
|
|
284
|
+
**Properties & Methods**
|
|
285
|
+
|
|
286
|
+
```js
|
|
287
|
+
el.files // FileList | null
|
|
288
|
+
el.valid
|
|
289
|
+
el.name
|
|
290
|
+
el.hasScanHook // boolean
|
|
291
|
+
el.scanning // boolean โ true while scan hook is running
|
|
292
|
+
el.clear()
|
|
293
|
+
el.setScanHook(async (file) => { return { valid: true } })
|
|
294
|
+
el.getAuditLog()
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**Scan hook**
|
|
298
|
+
|
|
299
|
+
```js
|
|
300
|
+
upload.setScanHook(async (file) => {
|
|
301
|
+
const result = await myApi.scanFile(file);
|
|
302
|
+
return { valid: result.clean, reason: result.threat };
|
|
303
|
+
});
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Events:** `secure-file-upload` โ `{ name, files: File[], tier }`
|
|
307
|
+
|
|
308
|
+
**Content validation (critical tier):** Magic number verification for JPEG, PNG, and PDF files.
|
|
309
|
+
|
|
310
|
+
**Filename validation:** Blocks path traversal (e.g. `../`), null bytes, and dangerous config file names.
|
|
127
311
|
|
|
128
312
|
```html
|
|
129
313
|
<secure-file-upload
|
|
@@ -131,62 +315,203 @@ File upload with drag-drop and validation.
|
|
|
131
315
|
name="document"
|
|
132
316
|
accept="image/*,.pdf"
|
|
133
317
|
max-size="5242880"
|
|
318
|
+
security-tier="sensitive"
|
|
134
319
|
></secure-file-upload>
|
|
135
320
|
```
|
|
136
321
|
|
|
137
|
-
|
|
138
|
-
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
### `<secure-datetime>`
|
|
325
|
+
|
|
326
|
+
Date and time picker with format validation, range enforcement, and timezone display.
|
|
327
|
+
|
|
328
|
+
**Attributes**
|
|
329
|
+
|
|
330
|
+
| Attribute | Description |
|
|
331
|
+
|-----------|-------------|
|
|
332
|
+
| `label` | Visible label |
|
|
333
|
+
| `name` | Field name |
|
|
334
|
+
| `type` | `date` \| `time` \| `datetime-local` \| `month` \| `week` (default `date`) |
|
|
335
|
+
| `min` | Minimum date/time (ISO format) |
|
|
336
|
+
| `max` | Maximum date/time (ISO format) |
|
|
337
|
+
| `step` | Step value |
|
|
338
|
+
| `value` | Initial value (ISO format) |
|
|
339
|
+
| `required` | Mark as required |
|
|
340
|
+
| `disabled` | Disable the field |
|
|
341
|
+
| `readonly` | Make read-only |
|
|
342
|
+
| `show-timezone` | Display UTC offset alongside the input |
|
|
343
|
+
| `security-tier` | Security tier |
|
|
344
|
+
|
|
345
|
+
**Properties & Methods**
|
|
346
|
+
|
|
347
|
+
```js
|
|
348
|
+
el.value // ISO string
|
|
349
|
+
el.value = '2025-06-15' // set value
|
|
350
|
+
el.valid
|
|
351
|
+
el.name
|
|
352
|
+
el.getValueAsDate() // Date | null
|
|
353
|
+
el.setValueFromDate(date) // accepts Date object, sets formatted value
|
|
354
|
+
el.getAuditLog()
|
|
355
|
+
el.focus()
|
|
356
|
+
el.blur()
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
**Events:** `secure-datetime` โ `{ name, value, type, tier }`
|
|
360
|
+
|
|
361
|
+
**CRITICAL tier:** Year must be between 1900 and 2100.
|
|
139
362
|
|
|
140
363
|
```html
|
|
141
364
|
<secure-datetime
|
|
142
|
-
label="
|
|
143
|
-
name="
|
|
144
|
-
type="
|
|
145
|
-
min="
|
|
146
|
-
max="
|
|
365
|
+
label="Appointment"
|
|
366
|
+
name="appointment"
|
|
367
|
+
type="datetime-local"
|
|
368
|
+
min="2025-01-01T00:00"
|
|
369
|
+
max="2030-12-31T23:59"
|
|
370
|
+
required
|
|
147
371
|
></secure-datetime>
|
|
148
372
|
```
|
|
149
373
|
|
|
150
|
-
|
|
151
|
-
Accessible submit button with loading state and security integration.
|
|
374
|
+
---
|
|
152
375
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
376
|
+
### `<secure-table>`
|
|
377
|
+
|
|
378
|
+
Data table with sorting, filtering, pagination, and column-level data masking.
|
|
156
379
|
|
|
157
|
-
|
|
158
|
-
Data table with sorting, filtering, and pagination.
|
|
380
|
+
**Properties**
|
|
159
381
|
|
|
160
|
-
```
|
|
161
|
-
const table = document.querySelector('secure-table');
|
|
382
|
+
```js
|
|
162
383
|
table.data = [
|
|
163
|
-
{ id: 1, name: '
|
|
164
|
-
{ id: 2, name: 'Jane', email: 'jane@example.com' }
|
|
384
|
+
{ id: 1, name: 'Alice', ssn: '123-45-6789' },
|
|
165
385
|
];
|
|
166
386
|
table.columns = [
|
|
167
|
-
{ key: 'id',
|
|
387
|
+
{ key: 'id', label: 'ID', sortable: true },
|
|
168
388
|
{ key: 'name', label: 'Name', sortable: true, filterable: true },
|
|
169
|
-
{ key: '
|
|
389
|
+
{ key: 'ssn', label: 'SSN', tier: 'critical' }, // masked
|
|
170
390
|
];
|
|
171
391
|
```
|
|
172
392
|
|
|
173
|
-
|
|
393
|
+
**Column definition**
|
|
394
|
+
|
|
395
|
+
| Property | Type | Description |
|
|
396
|
+
|----------|------|-------------|
|
|
397
|
+
| `key` | string | Data object key |
|
|
398
|
+
| `label` | string | Column header text |
|
|
399
|
+
| `sortable` | boolean | Enable click-to-sort |
|
|
400
|
+
| `filterable` | boolean | Include in global search |
|
|
401
|
+
| `tier` | string | Mask values at this tier level |
|
|
402
|
+
| `width` | string | CSS column width |
|
|
403
|
+
| `render` | `(value, row, key) => string` | Custom cell renderer |
|
|
404
|
+
|
|
405
|
+
**Column masking**
|
|
174
406
|
|
|
175
|
-
|
|
407
|
+
| Column `tier` | Behaviour |
|
|
408
|
+
|---------------|-----------|
|
|
409
|
+
| `sensitive` | Last 4 characters visible, rest masked (`โขโขโขโข4567`) |
|
|
410
|
+
| `critical` | Fully masked (`โขโขโขโขโขโขโขโข`) |
|
|
411
|
+
|
|
412
|
+
**Events:** `table-action` โ `{ action, โฆdata-attributes }` โ fired when an element with `[data-action]` inside a cell is clicked.
|
|
413
|
+
|
|
414
|
+
**Progressive enhancement:** Place a `<table slot="table">` with `data-key` attributes on `<th>` elements inside `<secure-table>` โ the component reads columns and data from the server-rendered markup.
|
|
415
|
+
|
|
416
|
+
```js
|
|
417
|
+
table.columns = [
|
|
418
|
+
{
|
|
419
|
+
key: 'status',
|
|
420
|
+
label: 'Status',
|
|
421
|
+
render: (value) => `<span class="badge">${value}</span>`
|
|
422
|
+
}
|
|
423
|
+
];
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
### `<secure-submit-button>`
|
|
429
|
+
|
|
430
|
+
Accessible submit button with loading state and automatic form-validity gating.
|
|
431
|
+
|
|
432
|
+
**Attributes:** `label`, `loading-label`, `disabled`, `security-tier`
|
|
433
|
+
|
|
434
|
+
**Properties**
|
|
435
|
+
|
|
436
|
+
```js
|
|
437
|
+
el.disabled
|
|
438
|
+
el.label
|
|
439
|
+
el.getAuditLog()
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Behaviour**
|
|
443
|
+
|
|
444
|
+
- For `authenticated`, `sensitive`, and `critical` tiers: button remains disabled until all required `<secure-input>`, `<secure-textarea>`, `<secure-select>`, and `<secure-datetime>` siblings report `valid = true`.
|
|
445
|
+
- Shows a spinner and `loading-label` during form submission.
|
|
446
|
+
- Rate-limited at `sensitive` / `critical` tiers.
|
|
447
|
+
|
|
448
|
+
```html
|
|
449
|
+
<secure-submit-button label="Submit" loading-label="Submittingโฆ"></secure-submit-button>
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Common Attributes
|
|
455
|
+
|
|
456
|
+
All components support:
|
|
457
|
+
|
|
458
|
+
| Attribute | Type | Description |
|
|
459
|
+
|-----------|------|-------------|
|
|
460
|
+
| `label` | string | Visible field label |
|
|
461
|
+
| `name` | string | Form field name |
|
|
462
|
+
| `required` | boolean | Mark field as required |
|
|
463
|
+
| `disabled` | boolean | Disable the field |
|
|
464
|
+
| `readonly` | boolean | Make the field read-only |
|
|
465
|
+
| `security-tier` | string | `public` \| `authenticated` \| `sensitive` \| `critical` (default: `critical`) |
|
|
466
|
+
|
|
467
|
+
## Common Properties & Methods
|
|
468
|
+
|
|
469
|
+
```js
|
|
470
|
+
el.value // get/set current value
|
|
471
|
+
el.valid // boolean โ passes all validation rules
|
|
472
|
+
el.name // field name string
|
|
473
|
+
el.securityTier // current security tier
|
|
474
|
+
el.getAuditLog() // AuditLogEntry[]
|
|
475
|
+
el.clearAuditLog()
|
|
476
|
+
el.focus()
|
|
477
|
+
el.blur()
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## Common Events
|
|
481
|
+
|
|
482
|
+
| Event | Fired by | Detail |
|
|
483
|
+
|-------|----------|--------|
|
|
484
|
+
| `secure-input` | `<secure-input>` | `{ name, value, masked, tier }` |
|
|
485
|
+
| `secure-textarea` | `<secure-textarea>` | `{ name, value, tier }` |
|
|
486
|
+
| `secure-select` | `<secure-select>` | `{ name, value, tier }` |
|
|
487
|
+
| `secure-datetime` | `<secure-datetime>` | `{ name, value, type, tier }` |
|
|
488
|
+
| `secure-file-upload` | `<secure-file-upload>` | `{ name, files, tier }` |
|
|
489
|
+
| `secure-form-submit` | `<secure-form>` | `{ formData, formElement, preventDefault() }` |
|
|
490
|
+
| `secure-form-success` | `<secure-form>` | `{ formData, response }` |
|
|
491
|
+
| `secure-audit` | all components | `{ event, tier, timestamp, โฆ }` |
|
|
492
|
+
| `table-action` | `<secure-table>` | `{ action, row }` |
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Customisation
|
|
497
|
+
|
|
498
|
+
### CSS Design Tokens
|
|
499
|
+
|
|
500
|
+
Override tokens at `:root` to theme all components globally:
|
|
176
501
|
|
|
177
502
|
```css
|
|
178
503
|
:root {
|
|
179
|
-
|
|
180
|
-
--secure-ui-color-primary: #your-brand-color;
|
|
504
|
+
--secure-ui-color-primary: #6366f1;
|
|
181
505
|
--secure-ui-input-border-radius: 8px;
|
|
182
|
-
--secure-ui-font-family-base: '
|
|
506
|
+
--secure-ui-font-family-base: 'Inter', sans-serif;
|
|
183
507
|
}
|
|
184
508
|
```
|
|
185
509
|
|
|
186
|
-
###
|
|
510
|
+
### CSS Parts API
|
|
511
|
+
|
|
512
|
+
Style internal elements directly:
|
|
187
513
|
|
|
188
514
|
```css
|
|
189
|
-
/* Style internal elements */
|
|
190
515
|
secure-input::part(label) {
|
|
191
516
|
font-weight: 700;
|
|
192
517
|
text-transform: uppercase;
|
|
@@ -202,109 +527,63 @@ secure-input::part(error) {
|
|
|
202
527
|
}
|
|
203
528
|
```
|
|
204
529
|
|
|
205
|
-
|
|
530
|
+
**Available parts on all components:** `container`, `label`, `wrapper`, `input` / `textarea` / `select`, `error`, `security-badge`
|
|
206
531
|
|
|
207
|
-
|
|
532
|
+
See the [Customization Guide](https://github.com/Barryprender/Secure-UI/blob/main/secure-ui-components/docs/customization.md) for a full token reference.
|
|
208
533
|
|
|
209
|
-
|
|
210
|
-
<!-- PUBLIC: Basic validation -->
|
|
211
|
-
<secure-input security-tier="public"></secure-input>
|
|
534
|
+
---
|
|
212
535
|
|
|
213
|
-
|
|
214
|
-
<secure-input security-tier="authenticated"></secure-input>
|
|
536
|
+
## Per-Component Imports
|
|
215
537
|
|
|
216
|
-
|
|
217
|
-
<secure-input security-tier="sensitive"></secure-input>
|
|
538
|
+
Import only what you need:
|
|
218
539
|
|
|
219
|
-
|
|
220
|
-
|
|
540
|
+
```js
|
|
541
|
+
import 'secure-ui-components/secure-input';
|
|
542
|
+
import 'secure-ui-components/secure-textarea';
|
|
543
|
+
import 'secure-ui-components/secure-select';
|
|
544
|
+
import 'secure-ui-components/secure-form';
|
|
545
|
+
import 'secure-ui-components/secure-file-upload';
|
|
546
|
+
import 'secure-ui-components/secure-datetime';
|
|
547
|
+
import 'secure-ui-components/secure-table';
|
|
221
548
|
```
|
|
222
549
|
|
|
223
|
-
|
|
550
|
+
Or import everything at once:
|
|
224
551
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
```bash
|
|
228
|
-
# Run all tests
|
|
229
|
-
npm test
|
|
230
|
-
|
|
231
|
-
# Run tests in watch mode
|
|
232
|
-
npm run test:watch
|
|
233
|
-
|
|
234
|
-
# Run tests with coverage report
|
|
235
|
-
npm run test:coverage
|
|
552
|
+
```js
|
|
553
|
+
import 'secure-ui-components';
|
|
236
554
|
```
|
|
237
555
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
- [Customization Guide](https://github.com/Barryprender/Secure-UI/blob/main/secure-ui-components/docs/customization.md) - Complete styling guide
|
|
241
|
-
- [Architecture](https://github.com/Barryprender/Secure-UI/blob/main/secure-ui-components/docs/ARCHITECTURE.md) - Technical architecture details
|
|
242
|
-
|
|
243
|
-
## ๐ API Reference
|
|
244
|
-
|
|
245
|
-
### Common Attributes
|
|
246
|
-
|
|
247
|
-
All components support:
|
|
248
|
-
|
|
249
|
-
| Attribute | Type | Description |
|
|
250
|
-
|-----------|------|-------------|
|
|
251
|
-
| `label` | `string` | Visible field label |
|
|
252
|
-
| `name` | `string` | Form field name |
|
|
253
|
-
| `required` | `boolean` | Mark field as required |
|
|
254
|
-
| `disabled` | `boolean` | Disable the field |
|
|
255
|
-
| `readonly` | `boolean` | Make the field read-only |
|
|
256
|
-
| `security-tier` | `string` | Security level: `public`, `authenticated`, `sensitive`, `critical` (default: `critical`) |
|
|
257
|
-
|
|
258
|
-
### Common Properties / Methods
|
|
556
|
+
---
|
|
259
557
|
|
|
260
|
-
|
|
261
|
-
const el = document.querySelector('secure-input');
|
|
558
|
+
## Testing
|
|
262
559
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
el.getAuditLog() // returns array of security audit log entries
|
|
560
|
+
```bash
|
|
561
|
+
npm test # run all tests
|
|
562
|
+
npm run test:watch # watch mode
|
|
563
|
+
npm run test:coverage # coverage report
|
|
268
564
|
```
|
|
269
565
|
|
|
270
|
-
|
|
566
|
+
---
|
|
271
567
|
|
|
272
|
-
|
|
273
|
-
el.files // FileList | null
|
|
274
|
-
el.clear() // clear selected files
|
|
275
|
-
el.hasScanHook // boolean
|
|
276
|
-
el.scanning // boolean โ true while scan hook is running
|
|
277
|
-
el.setScanHook(async (file) => { return { valid: true } })
|
|
278
|
-
```
|
|
568
|
+
## Documentation
|
|
279
569
|
|
|
280
|
-
|
|
570
|
+
- [Customization Guide](https://github.com/Barryprender/Secure-UI/blob/main/secure-ui-components/docs/customization.md)
|
|
571
|
+
- [Architecture](https://github.com/Barryprender/Secure-UI/blob/main/secure-ui-components/docs/ARCHITECTURE.md)
|
|
572
|
+
- [Live Demo](https://barryprender.github.io/Secure-UI/)
|
|
281
573
|
|
|
282
|
-
|
|
283
|
-
|-------|----------|--------|
|
|
284
|
-
| `secure-input` | `secure-input` | `{ name, value, masked, tier }` |
|
|
285
|
-
| `secure-textarea` | `secure-textarea` | `{ name, value, tier }` |
|
|
286
|
-
| `secure-select` | `secure-select` | `{ name, value, tier }` |
|
|
287
|
-
| `secure-datetime` | `secure-datetime` | `{ name, value, type, tier }` |
|
|
288
|
-
| `secure-file-upload` | `secure-file-upload` | `{ name, files, tier }` |
|
|
289
|
-
| `secure-form-submit` | `secure-form` | `{ formData, formElement, preventDefault }` |
|
|
290
|
-
| `secure-form-success` | `secure-form` | `{ formData, response }` |
|
|
291
|
-
| `secure-audit` | all components | `{ event, tier, timestamp, โฆ }` |
|
|
292
|
-
| `table-action` | `secure-table` | `{ action, row }` |
|
|
574
|
+
---
|
|
293
575
|
|
|
294
|
-
##
|
|
576
|
+
## Contributing
|
|
295
577
|
|
|
296
|
-
Contributions are welcome
|
|
578
|
+
Contributions are welcome. Please see the main repository for guidelines.
|
|
297
579
|
|
|
298
|
-
##
|
|
580
|
+
## License
|
|
299
581
|
|
|
300
|
-
MIT
|
|
582
|
+
MIT โ see LICENSE file for details.
|
|
301
583
|
|
|
302
|
-
##
|
|
584
|
+
## Links
|
|
303
585
|
|
|
304
586
|
- [GitHub Repository](https://github.com/Barryprender/Secure-UI)
|
|
587
|
+
- [npm Package](https://www.npmjs.com/package/secure-ui-components)
|
|
305
588
|
- [Live Demo](https://barryprender.github.io/Secure-UI/)
|
|
306
|
-
|
|
307
|
-
## ๐ Support
|
|
308
|
-
|
|
309
589
|
- [Issue Tracker](https://github.com/Barryprender/Secure-UI/issues)
|
|
310
|
-
- [Discussions](https://github.com/Barryprender/Secure-UI/discussions)
|
package/dist/package.json
CHANGED