commons-shared-web-ui 0.0.53 → 0.0.55
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/documentation/smart-form.md +236 -3
- package/documentation/time-picker.md +274 -0
- package/ng-package.json +3 -1
- package/package.json +1 -1
- package/src/lib/modules/form-components/form-components.module.ts +2 -1
- package/src/lib/modules/form-field-configuration/services/config-schema-tree.service.ts +13 -2
- package/src/lib/modules/side-nav/components/side-nav/side-nav.component.scss +1 -1
- package/src/lib/modules/smart-form/components/form-field/form-field.component.html +145 -11
- package/src/lib/modules/smart-form/components/form-field/form-field.component.scss +98 -0
- package/src/lib/modules/smart-form/components/form-field/form-field.component.ts +225 -1
- package/src/lib/modules/smart-form/components/form-section/form-section.component.scss +2 -2
- package/src/lib/modules/smart-form/components/smart-form/smart-form.component.scss +2 -2
- package/src/lib/modules/smart-form/models/form-schema.model.ts +44 -0
- package/src/lib/modules/smart-form/smart-form.module.ts +3 -1
- package/src/lib/modules/time-picker/components/time-picker/time-picker.component.html +37 -0
- package/src/lib/modules/time-picker/components/time-picker/time-picker.component.scss +102 -0
- package/src/lib/modules/time-picker/components/time-picker/time-picker.component.ts +178 -0
- package/src/lib/modules/time-picker/components/time-wheel-panel/time-wheel-panel.component.html +78 -0
- package/src/lib/modules/time-picker/components/time-wheel-panel/time-wheel-panel.component.scss +226 -0
- package/src/lib/modules/time-picker/components/time-wheel-panel/time-wheel-panel.component.ts +595 -0
- package/src/lib/modules/time-picker/models/time-picker.models.ts +49 -0
- package/src/lib/modules/time-picker/time-picker.module.ts +23 -0
- package/src/lib/modules/time-picker/time-picker.theme.scss +87 -0
- package/src/lib/shared-ui.module.ts +5 -0
- package/src/lib/styles/global.scss +10 -0
- package/src/public-api.ts +6 -0
|
@@ -396,6 +396,10 @@ The End Date picker automatically sets its minimum to whatever value `startDate`
|
|
|
396
396
|
| `maxTime` | string | Explicit maximum time in 24-hour `"HH:mm"` format (e.g. `"18:00"`). |
|
|
397
397
|
| `inputReadonly` | boolean | When true, the input is readonly. |
|
|
398
398
|
| `minTimeField` | string | Name of a sibling TIME field whose value is used as the dynamic minimum. When it changes, this field's minimum updates and any now-invalid value (earlier than the new minimum) is cleared. Mirrors `dateConfig.minTimeField`. |
|
|
399
|
+
| `variant` | string | Rendering variant: `'default'` (native picker input, default) or `'wheel'` (custom drum-roll slide picker). |
|
|
400
|
+
| `mode` | string | Hour display mode for `'wheel'` variant: `'12'` (12-hour, AM/PM column, default) or `'24'` (24-hour, no AM/PM). |
|
|
401
|
+
| `minuteStep` | number | Minute column increment step for `'wheel'` variant. Omit (or `1`) for every minute `00–59`; a value greater than `0` adds the break (e.g. `5`, `10`, `15`, `30`). |
|
|
402
|
+
| `placeholder` | string | Overridden placeholder text for the `'wheel'` variant trigger field. |
|
|
399
403
|
|
|
400
404
|
**Start / End time pair** — the end time cannot be earlier than the start time (same pattern as `dateConfig.minDateField`):
|
|
401
405
|
|
|
@@ -419,6 +423,154 @@ The End Date picker automatically sets its minimum to whatever value `startDate`
|
|
|
419
423
|
}
|
|
420
424
|
```
|
|
421
425
|
|
|
426
|
+
**Custom Wheel Time Picker Example** — using the custom drum-roll picker with 12-hour mode and 15-minute increments:
|
|
427
|
+
|
|
428
|
+
```json
|
|
429
|
+
{
|
|
430
|
+
"name": "preferredSlot",
|
|
431
|
+
"label": "Preferred Meeting Slot",
|
|
432
|
+
"type": "TIME",
|
|
433
|
+
"subType": "SINGLE",
|
|
434
|
+
"required": true,
|
|
435
|
+
"timeConfig": {
|
|
436
|
+
"variant": "wheel",
|
|
437
|
+
"mode": "12",
|
|
438
|
+
"minuteStep": 15,
|
|
439
|
+
"minTime": "09:00",
|
|
440
|
+
"maxTime": "17:00",
|
|
441
|
+
"placeholder": "Choose a 15-minute slot"
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
> **Note:** `minuteStep` omitted (or `0`/`1`) shows every minute `00–59`; any value greater than `0` adds the step break (e.g. `15` → `00, 15, 30, 45`). The wheel opens as a compact, centered modal.
|
|
447
|
+
|
|
448
|
+
**Styling & Variants (SCSS)**:
|
|
449
|
+
By default, the time picker uses the black/grey theme (Image 2 style). To use a blue accent variant instead, include the theme mixin with overrides inside your global stylesheet or MFE container styles:
|
|
450
|
+
|
|
451
|
+
```scss
|
|
452
|
+
@use 'commons-shared-web-ui/lib/modules/time-picker/time-picker.theme' as tp;
|
|
453
|
+
|
|
454
|
+
// Default variant (Black/Grey Color Scheme)
|
|
455
|
+
:root {
|
|
456
|
+
@include tp.time-picker-theme();
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Blue Accent Variant
|
|
460
|
+
:root {
|
|
461
|
+
@include tp.time-picker-theme((
|
|
462
|
+
accent: #4D89EB,
|
|
463
|
+
accent-light: rgba(77, 137, 235, 0.08),
|
|
464
|
+
accent-border: rgba(77, 137, 235, 0.15),
|
|
465
|
+
btn-confirm-bg: #4D89EB,
|
|
466
|
+
btn-confirm-hover: #3b74d1,
|
|
467
|
+
btn-cancel-bg: transparent,
|
|
468
|
+
btn-cancel-border: #e5e7eb,
|
|
469
|
+
btn-cancel-hover: #e5e7eb
|
|
470
|
+
));
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
**Time Picker i18n labels** — the `'wheel'` variant reads these keys from the form-level `[labels]` map (all optional; each falls back to English):
|
|
475
|
+
|
|
476
|
+
| Label key | Applies to | Default |
|
|
477
|
+
| --- | --- | --- |
|
|
478
|
+
| `TIME_PICKER.SELECT_TIME` | Popup title | `Select Time` |
|
|
479
|
+
| `TIME_PICKER.HOUR` | Hour column header | `Hour` |
|
|
480
|
+
| `TIME_PICKER.MINUTE` | Minute column header | `Minute` |
|
|
481
|
+
| `TIME_PICKER.PERIOD` | AM/PM column header | `AM/PM` |
|
|
482
|
+
| `TIME_PICKER.AM` / `TIME_PICKER.PM` | Period values | `AM` / `PM` |
|
|
483
|
+
| `COMMON.ACTIONS.CONFIRM` | Confirm button | `Confirm` |
|
|
484
|
+
| `COMMON.ACTIONS.CANCEL` | Cancel button | `Cancel` |
|
|
485
|
+
|
|
486
|
+
#### Complete Example (TIME wheel field in a Smart Form)
|
|
487
|
+
|
|
488
|
+
A full form schema with a start/end wheel time-picker pair, plus the parent-component wiring and picker i18n labels.
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
import { Component } from '@angular/core';
|
|
492
|
+
|
|
493
|
+
@Component({
|
|
494
|
+
selector: 'app-booking-form',
|
|
495
|
+
template: `
|
|
496
|
+
<lib-smart-form
|
|
497
|
+
[formJson]="formJson"
|
|
498
|
+
[labels]="labels"
|
|
499
|
+
(submit)="onSubmit($event)">
|
|
500
|
+
</lib-smart-form>
|
|
501
|
+
`
|
|
502
|
+
})
|
|
503
|
+
export class BookingFormComponent {
|
|
504
|
+
formJson = JSON.stringify({
|
|
505
|
+
entityType: 'BOOKING',
|
|
506
|
+
label: 'FORM.BOOKING_TITLE',
|
|
507
|
+
formType: 'SECTION',
|
|
508
|
+
sectionConfig: {
|
|
509
|
+
children: [
|
|
510
|
+
{
|
|
511
|
+
type: 'ROW',
|
|
512
|
+
subType: 'HORIZONTAL',
|
|
513
|
+
children: [
|
|
514
|
+
{
|
|
515
|
+
name: 'startTime',
|
|
516
|
+
label: 'FIELD.START_TIME',
|
|
517
|
+
type: 'TIME',
|
|
518
|
+
subType: 'SINGLE',
|
|
519
|
+
required: true,
|
|
520
|
+
colSpan: 6,
|
|
521
|
+
timeConfig: {
|
|
522
|
+
variant: 'wheel',
|
|
523
|
+
mode: '12',
|
|
524
|
+
minuteStep: 15,
|
|
525
|
+
minTime: '09:00',
|
|
526
|
+
maxTime: '18:00'
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
name: 'endTime',
|
|
531
|
+
label: 'FIELD.END_TIME',
|
|
532
|
+
type: 'TIME',
|
|
533
|
+
subType: 'SINGLE',
|
|
534
|
+
required: true,
|
|
535
|
+
colSpan: 6,
|
|
536
|
+
timeConfig: {
|
|
537
|
+
variant: 'wheel',
|
|
538
|
+
mode: '12',
|
|
539
|
+
minuteStep: 15,
|
|
540
|
+
minTimeField: 'startTime' // end cannot precede start
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
]
|
|
544
|
+
}
|
|
545
|
+
]
|
|
546
|
+
},
|
|
547
|
+
submitConfig: {
|
|
548
|
+
apiUrl: 'https://api.example.com/bookings',
|
|
549
|
+
method: 'POST',
|
|
550
|
+
successMessage: 'Booking created!'
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
labels = {
|
|
555
|
+
'FORM.BOOKING_TITLE': 'New Booking',
|
|
556
|
+
'FIELD.START_TIME': 'Start Time',
|
|
557
|
+
'FIELD.END_TIME': 'End Time',
|
|
558
|
+
// Time picker popup i18n
|
|
559
|
+
'TIME_PICKER.SELECT_TIME': 'Pick a time',
|
|
560
|
+
'TIME_PICKER.HOUR': 'Hour',
|
|
561
|
+
'TIME_PICKER.MINUTE': 'Min',
|
|
562
|
+
'TIME_PICKER.PERIOD': 'AM/PM',
|
|
563
|
+
'COMMON.ACTIONS.CONFIRM': 'Confirm',
|
|
564
|
+
'COMMON.ACTIONS.CANCEL': 'Cancel'
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
onSubmit(payload: any): void {
|
|
568
|
+
// { startTime: "09:15 AM", endTime: "10:00 AM" }
|
|
569
|
+
console.log('Booking:', payload);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
422
574
|
### 5. Autocomplete (AUTOCOMPLETE)
|
|
423
575
|
|
|
424
576
|
A searchable input backed by Angular Material's `mat-autocomplete`. As the user types, the option list is filtered by label or code. The form control stores the **code** value, while the input shows the human-readable **label**.
|
|
@@ -989,6 +1141,87 @@ Provides a WYSIWYG rich text editor using Quill.
|
|
|
989
1141
|
|
|
990
1142
|
Supported tokens: `bold`, `italic`, `underline`, `strike`, `blockquote`, `code`, `font`, `size`, `color`, `background`, `align`, `header1`, `header2`, `orderedList`, `bulletList`, `subscript`, `superscript`, `indentMinus`, `indentPlus`, `link`, `image`, `video`, `clean`.
|
|
991
1143
|
|
|
1144
|
+
### 14. Link List (LINK_LIST)
|
|
1145
|
+
|
|
1146
|
+
Allows users to manage a list of URLs dynamically. Provides a text input box with a trailing plus icon to add links, displaying them as a list above or below the input field.
|
|
1147
|
+
|
|
1148
|
+
**Configuration Properties (`linkListConfig`):**
|
|
1149
|
+
|
|
1150
|
+
| Property | Type | Description |
|
|
1151
|
+
|---|---|---|
|
|
1152
|
+
| `listPosition` | `'top' \| 'bottom'` | Renders the link list above or below the input field (default: `'bottom'`). |
|
|
1153
|
+
| `editable` | `boolean` | Allows inline editing of existing links in the list (default: `true`). |
|
|
1154
|
+
| `deleteable` | `boolean` | Shows a delete action button on list items (default: `true`). |
|
|
1155
|
+
| `valueFormat` | `'string' \| 'array' \| 'object'` | Format in which data is stored in the form control: `'string'` (separated by `separator`), `'array'` (array of strings), or `'object'` (array of objects) (default: `'string'`). |
|
|
1156
|
+
| `separator` | `string` | Character used to separate links when `valueFormat` is `'string'` (default: `','`). |
|
|
1157
|
+
| `urlKey` | `string` | The object key used to store/load the link URL when `valueFormat` is `'object'` (default: `'linkUrl'`). |
|
|
1158
|
+
| `idField` | `string` | The object key representing the link identifier when resolving API placeholders (default: `'id'`). |
|
|
1159
|
+
| `deleteApiUrl` | `string` | Optional API endpoint to execute an HTTP DELETE call upon removing a saved item (e.g. `/api/v1/links/:id`). |
|
|
1160
|
+
| `editApiUrl` | `string` | Optional API endpoint to execute an HTTP PUT call upon editing a saved item (e.g. `/api/v1/links/:id`). |
|
|
1161
|
+
| `pattern` | `string` | Regular expression pattern for validating each link (default URL validator regex: `^https?://([a-zA-Z0-9\-]+\.)+[a-zA-Z]{2,}(/\S*)?$`). |
|
|
1162
|
+
| `patternMessage` | `string` | Custom error message displayed if pattern validation fails. |
|
|
1163
|
+
| `colSpan` | `number` | Grid column span (1-12) for each list item in the 12-column grid. E.g., `6` for two columns side-by-side (default: `12`). |
|
|
1164
|
+
|
|
1165
|
+
**Example Config (Storing as an Array of Objects):**
|
|
1166
|
+
|
|
1167
|
+
```json
|
|
1168
|
+
{
|
|
1169
|
+
"name": "externalLinks",
|
|
1170
|
+
"label": "External Links",
|
|
1171
|
+
"type": "LINK_LIST",
|
|
1172
|
+
"placeholder": "Enter link...",
|
|
1173
|
+
"colSpan": 12,
|
|
1174
|
+
"linkListConfig": {
|
|
1175
|
+
"listPosition": "bottom",
|
|
1176
|
+
"editable": true,
|
|
1177
|
+
"deleteable": true,
|
|
1178
|
+
"valueFormat": "object",
|
|
1179
|
+
"urlKey": "linkUrl"
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
```
|
|
1183
|
+
|
|
1184
|
+
**Example Config (Storing as a Comma-Separated String):**
|
|
1185
|
+
|
|
1186
|
+
```json
|
|
1187
|
+
{
|
|
1188
|
+
"name": "externalLinks",
|
|
1189
|
+
"label": "External Links",
|
|
1190
|
+
"type": "LINK_LIST",
|
|
1191
|
+
"placeholder": "Enter link...",
|
|
1192
|
+
"colSpan": 12,
|
|
1193
|
+
"linkListConfig": {
|
|
1194
|
+
"listPosition": "top",
|
|
1195
|
+
"editable": true,
|
|
1196
|
+
"deleteable": true,
|
|
1197
|
+
"valueFormat": "string",
|
|
1198
|
+
"separator": ","
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
```
|
|
1202
|
+
|
|
1203
|
+
**Example Config (Two-Column Layout with Regex Validation):**
|
|
1204
|
+
|
|
1205
|
+
```json
|
|
1206
|
+
{
|
|
1207
|
+
"name": "externalLinks",
|
|
1208
|
+
"label": "External Links",
|
|
1209
|
+
"type": "LINK_LIST",
|
|
1210
|
+
"placeholder": "Enter link...",
|
|
1211
|
+
"colSpan": 12,
|
|
1212
|
+
"linkListConfig": {
|
|
1213
|
+
"listPosition": "bottom",
|
|
1214
|
+
"editable": true,
|
|
1215
|
+
"deleteable": true,
|
|
1216
|
+
"valueFormat": "object",
|
|
1217
|
+
"urlKey": "linkUrl",
|
|
1218
|
+
"colSpan": 6,
|
|
1219
|
+
"pattern": "^https?://([a-zA-Z0-9\\-]+\\.)+com(/\\S*)?$",
|
|
1220
|
+
"patternMessage": "Only .com domain links are allowed"
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
```
|
|
1224
|
+
|
|
992
1225
|
---
|
|
993
1226
|
|
|
994
1227
|
## Layout System
|
|
@@ -2104,6 +2337,7 @@ All variables are prefixed `--cc-sf-`. They are generated by the mixin and casca
|
|
|
2104
2337
|
|
|
2105
2338
|
### Contact Form
|
|
2106
2339
|
|
|
2340
|
+
```json
|
|
2107
2341
|
{
|
|
2108
2342
|
"entityType": "CONTACT",
|
|
2109
2343
|
"label": "Contact Us",
|
|
@@ -2147,8 +2381,7 @@ All variables are prefixed `--cc-sf-`. They are generated by the mixin and casca
|
|
|
2147
2381
|
]
|
|
2148
2382
|
}
|
|
2149
2383
|
}
|
|
2150
|
-
|
|
2151
|
-
````
|
|
2384
|
+
```
|
|
2152
2385
|
|
|
2153
2386
|
### User Registration with Password Validation
|
|
2154
2387
|
|
|
@@ -2203,7 +2436,7 @@ All variables are prefixed `--cc-sf-`. They are generated by the mixin and casca
|
|
|
2203
2436
|
]
|
|
2204
2437
|
}
|
|
2205
2438
|
}
|
|
2206
|
-
|
|
2439
|
+
```
|
|
2207
2440
|
|
|
2208
2441
|
### Section Stepper with `showOnLastStepOnly`
|
|
2209
2442
|
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# Time Picker Component (`lib-time-picker`)
|
|
2
|
+
|
|
3
|
+
A highly customizable, slot-machine / drum-roll style wheel picker component that supports 12-hour or 24-hour modes, custom minute steps, disabled time range limits (`minTime` and `maxTime`), full touch interaction, and accessibility attributes.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Importing the Module
|
|
8
|
+
|
|
9
|
+
To use the time picker in your Angular application (or within a Micro Frontend Remote MFE), import `TimePickerModule` into your Angular module:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { NgModule } from '@angular/core';
|
|
13
|
+
import { CommonModule } from '@angular/common';
|
|
14
|
+
import { TimePickerModule } from 'commons-shared-web-ui';
|
|
15
|
+
|
|
16
|
+
@NgModule({
|
|
17
|
+
imports: [
|
|
18
|
+
CommonModule,
|
|
19
|
+
TimePickerModule
|
|
20
|
+
]
|
|
21
|
+
})
|
|
22
|
+
export class MyFeatureModule {}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. Basic Component Usage
|
|
28
|
+
|
|
29
|
+
### Template-Driven Form / Two-Way Binding (`ngModel`)
|
|
30
|
+
```html
|
|
31
|
+
<lib-time-picker
|
|
32
|
+
[(ngModel)]="selectedTime"
|
|
33
|
+
[label]="'Meeting Time'"
|
|
34
|
+
[placeholder]="'Choose a time'"
|
|
35
|
+
[required]="true"
|
|
36
|
+
[mode]="'12'"
|
|
37
|
+
[minuteStep]="15">
|
|
38
|
+
</lib-time-picker>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Reactive Forms (`formControlName`)
|
|
42
|
+
```html
|
|
43
|
+
<form [formGroup]="form">
|
|
44
|
+
<lib-time-picker
|
|
45
|
+
[formControlName]="'startTime'"
|
|
46
|
+
[label]="'Start Time'"
|
|
47
|
+
[mode]="'24'"
|
|
48
|
+
[minTime]="'08:00'"
|
|
49
|
+
[maxTime]="'18:00'">
|
|
50
|
+
</lib-time-picker>
|
|
51
|
+
</form>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Complete Example (Reactive Form + Events)
|
|
55
|
+
|
|
56
|
+
A full working component wiring up two pickers with a time range, a minute step, and the `(timeChange)` output.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { Component } from '@angular/core';
|
|
60
|
+
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
|
61
|
+
|
|
62
|
+
@Component({
|
|
63
|
+
selector: 'app-schedule-form',
|
|
64
|
+
templateUrl: './schedule-form.component.html'
|
|
65
|
+
})
|
|
66
|
+
export class ScheduleFormComponent {
|
|
67
|
+
form: FormGroup = this.fb.group({
|
|
68
|
+
startTime: ['09:00 AM', Validators.required],
|
|
69
|
+
endTime: ['05:00 PM', Validators.required]
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
constructor(private fb: FormBuilder) {}
|
|
73
|
+
|
|
74
|
+
onStartChange(value: string): void {
|
|
75
|
+
// Emitted on Confirm — "hh:mm AM|PM" (12h) or "HH:mm" (24h)
|
|
76
|
+
console.log('Start time selected:', value);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
submit(): void {
|
|
80
|
+
if (this.form.valid) {
|
|
81
|
+
console.log('Schedule:', this.form.value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<form [formGroup]="form" (ngSubmit)="submit()">
|
|
89
|
+
<lib-time-picker
|
|
90
|
+
formControlName="startTime"
|
|
91
|
+
[label]="'Start Time'"
|
|
92
|
+
[placeholder]="'Select start'"
|
|
93
|
+
[required]="true"
|
|
94
|
+
[mode]="'12'"
|
|
95
|
+
[minuteStep]="15"
|
|
96
|
+
[errorMessage]="form.get('startTime')?.touched && form.get('startTime')?.invalid ? 'Start time is required' : ''"
|
|
97
|
+
(timeChange)="onStartChange($event)">
|
|
98
|
+
</lib-time-picker>
|
|
99
|
+
|
|
100
|
+
<lib-time-picker
|
|
101
|
+
formControlName="endTime"
|
|
102
|
+
[label]="'End Time'"
|
|
103
|
+
[mode]="'12'"
|
|
104
|
+
[minuteStep]="15"
|
|
105
|
+
[minTime]="'09:00'"
|
|
106
|
+
[maxTime]="'21:00'">
|
|
107
|
+
</lib-time-picker>
|
|
108
|
+
|
|
109
|
+
<button type="submit" [disabled]="form.invalid">Save</button>
|
|
110
|
+
</form>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Complete Example (Single `config` object)
|
|
114
|
+
|
|
115
|
+
Every input can also be supplied through one `TimePickerConfig` object — handy when the config comes from JSON/i18n.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { Component } from '@angular/core';
|
|
119
|
+
import { TimePickerConfig } from 'commons-shared-web-ui';
|
|
120
|
+
|
|
121
|
+
@Component({
|
|
122
|
+
selector: 'app-reminder',
|
|
123
|
+
template: `
|
|
124
|
+
<lib-time-picker
|
|
125
|
+
[(ngModel)]="reminderTime"
|
|
126
|
+
[config]="pickerConfig"
|
|
127
|
+
(timeChange)="reminderTime = $event">
|
|
128
|
+
</lib-time-picker>
|
|
129
|
+
`
|
|
130
|
+
})
|
|
131
|
+
export class ReminderComponent {
|
|
132
|
+
reminderTime = '';
|
|
133
|
+
|
|
134
|
+
pickerConfig: TimePickerConfig = {
|
|
135
|
+
label: 'Daily Reminder',
|
|
136
|
+
placeholder: 'Pick a time',
|
|
137
|
+
mode: '24',
|
|
138
|
+
minuteStep: 5, // 0/1 = every minute; > 0 adds the break
|
|
139
|
+
required: true,
|
|
140
|
+
minTime: '06:00',
|
|
141
|
+
maxTime: '23:30'
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 3. Configuration Properties
|
|
149
|
+
|
|
150
|
+
### Inputs
|
|
151
|
+
| Input | Type | Default | Description |
|
|
152
|
+
| --- | --- | --- | --- |
|
|
153
|
+
| `config` | `TimePickerConfig` | `undefined` | Unified configuration object that mirrors individual inputs. |
|
|
154
|
+
| `labels` | `TimePickerLabels` | `undefined` | i18n label map keys. |
|
|
155
|
+
| `label` | `string` | `""` | The label text displayed above the trigger input. |
|
|
156
|
+
| `placeholder` | `string` | `""` | Placeholder text shown inside the input when no time is selected. |
|
|
157
|
+
| `mode` | `'12' \| '24'` | `'12'` | Hour display format. `'12'` shows a AM/PM column, while `'24'` runs from 00-23. |
|
|
158
|
+
| `minuteStep` | `number` | `0` | Increment for the minutes column. `0` (or `1`) shows every minute `00–59` with no break; a value greater than `0` adds the step break (e.g. `15` → `00, 15, 30, 45`). |
|
|
159
|
+
| `disabled` | `boolean` | `false` | Disables the trigger field, blocking popup opening. |
|
|
160
|
+
| `required` | `boolean` | `false` | Appends a red asterisk to the field label. |
|
|
161
|
+
| `errorMessage` | `string` | `""` | Validation error message text. |
|
|
162
|
+
| `minTime` | `string` | `undefined` | Minimum allowed limit in 24hr `"HH:mm"` string format (e.g., `"09:30"`). |
|
|
163
|
+
| `maxTime` | `string` | `undefined` | Maximum allowed limit in 24hr `"HH:mm"` string format (e.g., `"17:00"`). |
|
|
164
|
+
|
|
165
|
+
### `TimePickerLabels` Properties
|
|
166
|
+
When passing the `[labels]` input, you can provide any of the following fields (all optional, falling back to English defaults):
|
|
167
|
+
|
|
168
|
+
| Property | Type | Default | Description |
|
|
169
|
+
| --- | --- | --- | --- |
|
|
170
|
+
| `selectTimeTitle` | `string` | `'Select Time'` | The subtle header title printed at the top of the dialog. |
|
|
171
|
+
| `hourLabel` | `string` | `'Hour'` | Header label shown above the hour column. |
|
|
172
|
+
| `minuteLabel` | `string` | `'Minute'` | Header label shown above the minute column. |
|
|
173
|
+
| `periodLabel` | `string` | `'AM/PM'` | Header label shown above the AM/PM column (12h mode only). |
|
|
174
|
+
| `confirmLabel` | `string` | `'Confirm'` | Confirm button text. |
|
|
175
|
+
| `cancelLabel` | `string` | `'Cancel'` | Cancel button text. |
|
|
176
|
+
|
|
177
|
+
### Outputs
|
|
178
|
+
| Output | Type | Description |
|
|
179
|
+
| --- | --- | --- |
|
|
180
|
+
| `timeChange` | `EventEmitter<string>` | Emitted when a time is confirmed and closed. Emits `"hh:mm AM\|PM"` for `'12'` mode, or `"HH:mm"` for `'24'` mode. |
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 4. Styling & Customization in MFEs
|
|
185
|
+
|
|
186
|
+
The time-picker has two main styling options: the **Default (Black/Grey)** scheme (matching Image 2) and the **Blue Accent** scheme. These are easily set via the theme mixin or global CSS variables.
|
|
187
|
+
|
|
188
|
+
### Variant Options (SCSS)
|
|
189
|
+
|
|
190
|
+
#### Option 1: Default (Black/Grey Theme — Image 2)
|
|
191
|
+
The default theme features black text active indicators, borderless wheels, a light-grey center highlight bar, a black Confirm button, and a light-grey Cancel button.
|
|
192
|
+
|
|
193
|
+
```scss
|
|
194
|
+
@use 'commons-shared-web-ui/lib/modules/time-picker/time-picker.theme' as tp;
|
|
195
|
+
|
|
196
|
+
:root {
|
|
197
|
+
@include tp.time-picker-theme();
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### Option 2: Blue Accent Variant
|
|
202
|
+
The blue accent theme uses the same layout and headers, but changes highlights, preview text, active wheel items, and buttons to use the blue accent color.
|
|
203
|
+
|
|
204
|
+
```scss
|
|
205
|
+
@use 'commons-shared-web-ui/lib/modules/time-picker/time-picker.theme' as tp;
|
|
206
|
+
|
|
207
|
+
:root {
|
|
208
|
+
@include tp.time-picker-theme((
|
|
209
|
+
accent: #4D89EB,
|
|
210
|
+
accent-light: rgba(77, 137, 235, 0.08),
|
|
211
|
+
accent-border: rgba(77, 137, 235, 0.15),
|
|
212
|
+
btn-confirm-bg: #4D89EB,
|
|
213
|
+
btn-confirm-hover: #3b74d1,
|
|
214
|
+
btn-cancel-bg: transparent,
|
|
215
|
+
btn-cancel-border: #e5e7eb,
|
|
216
|
+
btn-cancel-hover: #e5e7eb
|
|
217
|
+
));
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
You can style the trigger inputs and picker wheels using two different methods: using Scss Mixins or CSS Custom Properties.
|
|
222
|
+
|
|
223
|
+
### Method A: Including Theme Mixin inside MFE Component SCSS
|
|
224
|
+
|
|
225
|
+
To scope the theme changes inside a specific feature component or the main MFE root stylesheet, use the `@use` rule to import the SCSS file and `@include` the mixin:
|
|
226
|
+
|
|
227
|
+
```scss
|
|
228
|
+
// remote-mfe/src/app/feature/feature.component.scss
|
|
229
|
+
|
|
230
|
+
@use 'commons-shared-web-ui/lib/modules/time-picker/time-picker.theme' as tp;
|
|
231
|
+
|
|
232
|
+
// Apply default theme to component scope
|
|
233
|
+
:host {
|
|
234
|
+
@include tp.time-picker-theme();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// OR customize theme properties:
|
|
238
|
+
.custom-theme-picker {
|
|
239
|
+
@include tp.time-picker-theme((
|
|
240
|
+
accent: #C21E25, // Crimson Red brand color
|
|
241
|
+
accent-light: rgba(194, 30, 37, 0.08),
|
|
242
|
+
accent-border: rgba(194, 30, 37, 0.15),
|
|
243
|
+
btn-confirm-bg: #C21E25,
|
|
244
|
+
btn-confirm-hover: #a1141a,
|
|
245
|
+
border-radius: 8px
|
|
246
|
+
));
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Method B: Overriding CSS Custom Properties directly
|
|
251
|
+
|
|
252
|
+
If you prefer not to include mixins, you can set the CSS variables directly in your MFE stylesheet:
|
|
253
|
+
|
|
254
|
+
```css
|
|
255
|
+
/* remote-mfe/src/styles.scss */
|
|
256
|
+
:root {
|
|
257
|
+
--cc-timepicker-accent: #C21E25;
|
|
258
|
+
--cc-timepicker-accent-light: rgba(194, 30, 37, 0.08);
|
|
259
|
+
--cc-timepicker-accent-border: rgba(194, 30, 37, 0.15);
|
|
260
|
+
--cc-timepicker-btn-confirm-bg: #C21E25;
|
|
261
|
+
--cc-timepicker-btn-confirm-hover: #a1141a;
|
|
262
|
+
--cc-timepicker-border-radius: 8px;
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## 5. Constraint Engine Enforcement
|
|
269
|
+
|
|
270
|
+
When `minTime` and/or `maxTime` is specified:
|
|
271
|
+
1. Slices of time that violate the boundaries are **automatically greyed out** (`opacity: 0.25`) and have pointer events disabled.
|
|
272
|
+
2. Clicking on a disabled item will not trigger selection.
|
|
273
|
+
3. Flicking or scrolling past a disabled value snaps to the **closest valid item** automatically.
|
|
274
|
+
4. Changing the AM/PM column to a period where the current hour is disabled triggers an automatic visual snap transition to a valid hour.
|
package/ng-package.json
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
"src/lib/modules/side-nav/side-nav.theme.scss",
|
|
24
24
|
"src/lib/modules/form-builder/form-builder.theme.scss",
|
|
25
25
|
"src/lib/modules/filter-table-selector/filter-table-selector.theme.scss",
|
|
26
|
-
"src/lib/modules/snackbar/snackbar.theme.scss"
|
|
26
|
+
"src/lib/modules/snackbar/snackbar.theme.scss",
|
|
27
|
+
"src/lib/modules/button-dropdown/button-dropdown.theme.scss",
|
|
28
|
+
"src/lib/modules/time-picker/time-picker.theme.scss"
|
|
27
29
|
]
|
|
28
30
|
}
|
package/package.json
CHANGED
|
@@ -83,13 +83,24 @@ export class ConfigSchemaTreeService {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
// A section is locked (toggle replaced by a lock, can never be hidden) when its
|
|
87
|
+
// own field is locked OR any descendant field/subsection is locked — hiding the
|
|
88
|
+
// section would otherwise hide a field that must always stay visible. Subsection
|
|
89
|
+
// locks are already transitive, so checking direct children is enough.
|
|
90
|
+
const hasLockedDescendant =
|
|
91
|
+
fields.some(f => f.lockVisibility) || subsections.some(s => s.lockVisibility);
|
|
92
|
+
const lockVisibility = field.lockVisibility === true || hasLockedDescendant;
|
|
93
|
+
|
|
94
|
+
// Locked sections are always visible; otherwise honour the schema's flags.
|
|
95
|
+
const visible = lockVisibility
|
|
96
|
+
? true
|
|
97
|
+
: (field.isEnabled ?? field.visible ?? true) && field.disabled !== true;
|
|
87
98
|
return {
|
|
88
99
|
label: field.sectionConfig?.label || field.label || field.name || 'Section',
|
|
89
100
|
fieldConfig: field,
|
|
90
101
|
sectionConfig: field.sectionConfig ?? null,
|
|
91
102
|
visible,
|
|
92
|
-
lockVisibility
|
|
103
|
+
lockVisibility,
|
|
93
104
|
expanded: true,
|
|
94
105
|
fields,
|
|
95
106
|
subsections,
|