@openg2p/registry-widgets 0.2.0 → 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.
- package/README.md +110 -12
- package/dist/components/SectionRenderer.d.ts.map +1 -1
- package/dist/hooks/useWidgetTheme.d.ts +19 -0
- package/dist/hooks/useWidgetTheme.d.ts.map +1 -0
- package/dist/index.esm.js +53 -13
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +53 -13
- package/dist/index.js.map +1 -1
- package/dist/theme/index.d.ts +101 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/widgets/HeaderSectionWidget.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,9 +16,14 @@ The Registry UI Widget Library is a layered, extensible system that enables you
|
|
|
16
16
|
- ✅ **Data Sources** (static, API, schema reference)
|
|
17
17
|
- ✅ **Formatting** (dates, currency, phone numbers, numbers)
|
|
18
18
|
- ✅ **Widget Registry** system for extensible plugin architecture
|
|
19
|
-
- ✅ **
|
|
19
|
+
- ✅ **20 Pre-built Widgets** ready to use (including HeaderSection)
|
|
20
20
|
- ✅ **Internationalization** support via i18next
|
|
21
21
|
- ✅ **Tailwind CSS** ready (unstyled base, you provide styles)
|
|
22
|
+
- ✅ **Multi-mode Section Rendering** (RegistryView, CRView, IntakeForm)
|
|
23
|
+
- ✅ **Geo Hierarchy Cascading Dropdowns** for location-based fields
|
|
24
|
+
- ✅ **Section Builder** with visual and JSON editor for UI schemas
|
|
25
|
+
- ✅ **Form Handle API** for host-driven validation and submission
|
|
26
|
+
- ✅ **Dirty Tracking** with unsaved changes detection per section
|
|
22
27
|
|
|
23
28
|
## Installation
|
|
24
29
|
|
|
@@ -77,7 +82,7 @@ The library follows a layered architecture that separates concerns and enables e
|
|
|
77
82
|
↓
|
|
78
83
|
┌─────────────────────────────────────────┐
|
|
79
84
|
│ Widget Components Layer │
|
|
80
|
-
│ (
|
|
85
|
+
│ (20 Pre-built Widgets) │
|
|
81
86
|
└─────────────────────────────────────────┘
|
|
82
87
|
↓
|
|
83
88
|
┌─────────────────────────────────────────┐
|
|
@@ -102,7 +107,7 @@ The library follows a layered architecture that separates concerns and enables e
|
|
|
102
107
|
|
|
103
108
|
**Widget Registry Layer** - A plugin system that maintains a catalog of available widgets. When a widget is requested by name, the registry looks it up and returns the corresponding React component. This enables dynamic widget loading and easy extensibility - new widgets can be registered without modifying core library code.
|
|
104
109
|
|
|
105
|
-
**Widget Components Layer** - The actual React components that render UI elements (text inputs, selects, tables, etc.). These are the
|
|
110
|
+
**Widget Components Layer** - The actual React components that render UI elements (text inputs, selects, tables, etc.). These are the 20 pre-built widgets that come with the library. Each widget is a React component that receives configuration and renders the appropriate UI. Custom widgets can be added by registering them in the registry.
|
|
106
111
|
|
|
107
112
|
**Core Hooks Layer** - React hooks that provide all the business logic for widgets. The `useBaseWidget` hook handles state management, validation, conditional logic, data source loading, and formatting. The `useWidgetTranslation` hook provides internationalization support. Widget components use these hooks to get values, errors, visibility states, and change handlers without directly interacting with Redux or utilities.
|
|
108
113
|
|
|
@@ -224,25 +229,92 @@ Support for multiple validation strategies:
|
|
|
224
229
|
|
|
225
230
|
## Available Widgets
|
|
226
231
|
|
|
227
|
-
The library includes
|
|
232
|
+
The library includes 20 pre-built widgets:
|
|
228
233
|
|
|
229
234
|
- **Input Widgets**: TextInput, TextArea, NumberInput, CurrencyInput, DateInput, DateTimeInput, PhoneInput, FileInput
|
|
230
235
|
- **Selection Widgets**: Select, Radio, Checkbox, Boolean
|
|
231
236
|
- **Layout Widgets**: Array, IterableAccordion
|
|
232
237
|
- **Display Widgets**: Display, Profile
|
|
233
238
|
- **Table Widgets**: Table, SimpleTable
|
|
239
|
+
- **Section Widgets**: HeaderSection
|
|
234
240
|
|
|
235
|
-
|
|
241
|
+
### HeaderSection Widget
|
|
242
|
+
|
|
243
|
+
A full-width header card designed for registry record views. Displays a profile image, record name, functional ID, status badge, and audit metadata (created by / approved by) in a responsive two-column layout. Supports editable status and status-reason fields with data source-driven dropdowns, customisable label overrides via i18n, and configurable status-colour mapping.
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"widget": "header-section",
|
|
248
|
+
"widget-type": "group",
|
|
249
|
+
"widget-id": "registry-header",
|
|
250
|
+
"widget-data-path": {
|
|
251
|
+
"image": "record_image_storage_id",
|
|
252
|
+
"name": "record_name",
|
|
253
|
+
"functionalId": "functional_record_id",
|
|
254
|
+
"status": "record_status"
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Section Modes
|
|
260
|
+
|
|
261
|
+
`SectionsContainer` supports three display modes via the `mode` prop:
|
|
262
|
+
|
|
263
|
+
### RegistryView (default)
|
|
264
|
+
|
|
265
|
+
Standard registry display. Sections render in a CSS Grid layout with an inline **Edit Details** button. Only one section can be in edit mode at a time; editing a section opens it as a portal-based overlay with save/cancel controls.
|
|
266
|
+
|
|
267
|
+
### CRView (Change Request View)
|
|
268
|
+
|
|
269
|
+
Read-only comparison view for change requests. Sections display **Created by** / **Approved by** metadata and support `changeRequestType` labels (`"new"` / `"old"`) for side-by-side comparison.
|
|
270
|
+
|
|
271
|
+
### IntakeForm
|
|
272
|
+
|
|
273
|
+
Accordion-based registration form. Sections expand and collapse, with **Prev** / **Next** navigation buttons. Supports `isDraft` mode (editable vs read-only), per-section validation on save, and status badges (**Saved** / **Modified and not saved**).
|
|
274
|
+
|
|
275
|
+
## Form Handle API
|
|
276
|
+
|
|
277
|
+
`SectionsContainer` exposes a `SectionsFormHandle` via the `onFormReady` callback, enabling host applications to drive form submission externally:
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
<SectionsContainer
|
|
281
|
+
sections={sections}
|
|
282
|
+
mode="IntakeForm"
|
|
283
|
+
onFormReady={(handle) => {
|
|
284
|
+
// handle.validate() – validate all sections, returns boolean
|
|
285
|
+
// handle.getFormData() – raw store data (no validation)
|
|
286
|
+
// handle.validateAndGetData() – validate then return SectionChanges[]
|
|
287
|
+
// handle.getStructuredData() – get records and files without validation
|
|
288
|
+
}}
|
|
289
|
+
/>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Geo Hierarchy Cascading Dropdowns
|
|
293
|
+
|
|
294
|
+
The `useGeoWidgetCascade` hook and `geoHierarchyBuilder` utility provide cascading dropdown functionality for geographic location fields (e.g. Country > State > City). Changes in a parent level automatically reload and reset child dropdowns via the widget event bus.
|
|
295
|
+
|
|
296
|
+
## Section Builder
|
|
297
|
+
|
|
298
|
+
A visual UI schema editor shipped as `SectionBuilder`, with sub-components:
|
|
299
|
+
|
|
300
|
+
- **JSONEditorPanel** — Live JSON editor (powered by `json-edit-react`) for direct schema manipulation
|
|
301
|
+
- **VisualBuilderPanel** — Drag-and-drop visual layout editor
|
|
302
|
+
- **SectionTree** — Tree view of the section/panel/widget hierarchy
|
|
303
|
+
- **PropertyEditor** — Contextual property panel for the selected node
|
|
236
304
|
|
|
237
305
|
## Examples
|
|
238
306
|
|
|
239
307
|
See the `examples/` directory for comprehensive examples demonstrating:
|
|
240
308
|
|
|
241
|
-
- Basic widget usage
|
|
242
|
-
- Layout widgets
|
|
243
|
-
- Schema internationalization
|
|
244
|
-
- Comparison views
|
|
245
|
-
-
|
|
309
|
+
- Basic widget usage (`usage-example.tsx`)
|
|
310
|
+
- Layout widgets (`LayoutWidgets.tsx`)
|
|
311
|
+
- Schema internationalization (`schema-i18n-example.tsx`)
|
|
312
|
+
- Comparison views (`comparison-view-example.tsx`)
|
|
313
|
+
- Section rendering modes (`section-renderer-example.tsx`)
|
|
314
|
+
- Intake form flow (`intake-form-example.tsx`)
|
|
315
|
+
- Header section widget (`header-section-example.tsx`)
|
|
316
|
+
- Section builder (`section-builder-example.tsx`)
|
|
317
|
+
- JSON editor standalone (`jsoneditor-standalone-example.tsx`)
|
|
246
318
|
|
|
247
319
|
## API Reference
|
|
248
320
|
|
|
@@ -280,10 +352,36 @@ Registry for managing widget components.
|
|
|
280
352
|
|
|
281
353
|
### Components
|
|
282
354
|
|
|
283
|
-
- `SectionsContainer` - Container for rendering sections
|
|
284
|
-
- `SectionRenderer` - Renders individual sections
|
|
355
|
+
- `SectionsContainer` - Container for rendering sections with mode support (RegistryView, CRView, IntakeForm)
|
|
356
|
+
- `SectionRenderer` - Renders individual sections with edit mode, dirty tracking, and accordion support
|
|
285
357
|
- `PanelRenderer` - Renders panels within sections
|
|
286
358
|
- `FilePreviewModal` - Modal for file preview
|
|
359
|
+
- `SectionBuilder` - Visual UI schema editor
|
|
360
|
+
- `JSONEditorPanel` - JSON editor for UI schemas
|
|
361
|
+
- `VisualBuilderPanel` - Visual layout builder
|
|
362
|
+
- `SectionTree` - Tree view of section hierarchy
|
|
363
|
+
- `PropertyEditor` - Property editor for selected nodes
|
|
364
|
+
|
|
365
|
+
### Hooks
|
|
366
|
+
|
|
367
|
+
- `useBaseWidget` - Core hook for widget state, validation, conditional logic, and formatting
|
|
368
|
+
- `useWidgetTranslation` - i18n hook for widget labels and messages
|
|
369
|
+
- `useWidgetEventBus` - Pub/sub event bus for inter-widget communication
|
|
370
|
+
- `useWidgetCascade` - Cascading dropdown behaviour between linked widgets
|
|
371
|
+
- `useGeoWidgetCascade` - Geo hierarchy cascading for location-based dropdowns
|
|
372
|
+
|
|
373
|
+
### Utilities
|
|
374
|
+
|
|
375
|
+
- `pathUtils` - Dot-notation path read/write for nested data structures
|
|
376
|
+
- `validation` - Built-in, regex, and Zod validation
|
|
377
|
+
- `formatting` - Date, currency, phone, number, and text formatting
|
|
378
|
+
- `conditions` - Conditional show/hide and enable/disable evaluation
|
|
379
|
+
- `dataSource` - Static, API, and schema reference data loading
|
|
380
|
+
- `geoHierarchy` - Geo hierarchy builder for location cascades
|
|
381
|
+
- `sectionValidate` - Section-level validation across all widgets
|
|
382
|
+
- `buildSectionChanges` - Build change payloads from section data
|
|
383
|
+
- `schemaNamespace` - Namespace section configs for multi-instance rendering
|
|
384
|
+
- `schemaTranslation` - Translate UI schemas, widget configs, and panel configs
|
|
287
385
|
|
|
288
386
|
## Contributing
|
|
289
387
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SectionRenderer.d.ts","sourceRoot":"","sources":["../../src/components/SectionRenderer.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAyC,MAAM,UAAU,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAM9D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMlD,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,aAAa,CAAC;IACvB,wBAAwB,CAAC,EAAE,oBAAoB,CAAC,0BAA0B,CAAC,CAAC;IAC5E,UAAU,CAAC,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAC;IAChD,aAAa,CAAC,EAAE,oBAAoB,CAAC,eAAe,CAAC,CAAC;IACtD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAClC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAGjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,2GAA2G;IAC3G,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAErE,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,oGAAoG;IACpG,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,uGAAuG;IACvG,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,4FAA4F;IAC5F,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,wGAAwG;IACxG,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,0HAA0H;IAC1H,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjE,iGAAiG;IACjG,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAGD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAAI,wZAwB7B,oBAAoB,
|
|
1
|
+
{"version":3,"file":"SectionRenderer.d.ts","sourceRoot":"","sources":["../../src/components/SectionRenderer.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAyC,MAAM,UAAU,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAM9D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMlD,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,aAAa,CAAC;IACvB,wBAAwB,CAAC,EAAE,oBAAoB,CAAC,0BAA0B,CAAC,CAAC;IAC5E,UAAU,CAAC,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAC;IAChD,aAAa,CAAC,EAAE,oBAAoB,CAAC,eAAe,CAAC,CAAC;IACtD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAClC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAGjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,2GAA2G;IAC3G,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAErE,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,oGAAoG;IACpG,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,uGAAuG;IACvG,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,4FAA4F;IAC5F,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,wGAAwG;IACxG,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,0HAA0H;IAC1H,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjE,iGAAiG;IACjG,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAGD;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAAI,wZAwB7B,oBAAoB,4CAq6CtB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { resolveTheme } from '../theme';
|
|
2
|
+
export type ResolvedTheme = ReturnType<typeof resolveTheme>;
|
|
3
|
+
export declare const ThemeContext: import("react").Context<Required<{
|
|
4
|
+
colors: Required<import("../theme").WidgetThemeColors>;
|
|
5
|
+
section: Required<import("../theme").WidgetThemeSection>;
|
|
6
|
+
panel: Required<import("../theme").WidgetThemePanel>;
|
|
7
|
+
button: Required<import("../theme").WidgetThemeButton>;
|
|
8
|
+
widget: Required<import("../theme").WidgetThemeWidget>;
|
|
9
|
+
}>>;
|
|
10
|
+
/**
|
|
11
|
+
* Access the resolved widget theme from any component inside `<WidgetProvider>`.
|
|
12
|
+
*
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const theme = useWidgetTheme();
|
|
15
|
+
* // theme.colors.primary, theme.section.dividerColor, etc.
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function useWidgetTheme(): ResolvedTheme;
|
|
19
|
+
//# sourceMappingURL=useWidgetTheme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWidgetTheme.d.ts","sourceRoot":"","sources":["../../src/hooks/useWidgetTheme.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,YAAY,EAAE,MAAM,UAAU,CAAC;AAEtD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AAE5D,eAAO,MAAM,YAAY;;;;;;GAA6C,CAAC;AAEvE;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,aAAa,CAE9C"}
|
package/dist/index.esm.js
CHANGED
|
@@ -4200,6 +4200,15 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
|
|
|
4200
4200
|
text-overflow: ellipsis !important;
|
|
4201
4201
|
white-space: nowrap !important;
|
|
4202
4202
|
}
|
|
4203
|
+
/* Readonly: prevent flex row from overflowing panel */
|
|
4204
|
+
.${sectionClassId} .TextDisplayWidget {
|
|
4205
|
+
min-width: 0 !important;
|
|
4206
|
+
overflow: hidden !important;
|
|
4207
|
+
}
|
|
4208
|
+
.${sectionClassId} .TextDisplayWidget > .flex-1 {
|
|
4209
|
+
min-width: 0 !important;
|
|
4210
|
+
overflow: hidden !important;
|
|
4211
|
+
}
|
|
4203
4212
|
/* Readonly value text truncation */
|
|
4204
4213
|
.${sectionClassId} .TextDisplayWidget > .flex-1 > .text-gray-900 {
|
|
4205
4214
|
overflow: hidden;
|
|
@@ -4530,11 +4539,11 @@ const SectionRenderer = ({ section, dataSourceRequestHandler: propDataSourceRequ
|
|
|
4530
4539
|
fontSize: '14px',
|
|
4531
4540
|
color: '#000000',
|
|
4532
4541
|
fontWeight: 'normal',
|
|
4533
|
-
}, children: crViewData.approvedDate }))] })] })] })), mode === 'RegistryView' && !hideEditButton && (jsxRuntimeExports.jsx("hr", { className: "border-gray-300 w-full", style: { height: '1px', marginTop: !isEditMode ? '
|
|
4542
|
+
}, children: crViewData.approvedDate }))] })] })] })), mode === 'RegistryView' && !hideEditButton && (jsxRuntimeExports.jsx("hr", { className: "border-gray-300 w-full", style: { height: '1px', marginTop: !isEditMode ? '10px' : 0, marginBottom: '14px' } })), mode === 'RegistryView' && !isEditMode && !hideEditButton && (jsxRuntimeExports.jsx("div", { className: "flex justify-center items-center", style: { marginBottom: '20px' }, children: jsxRuntimeExports.jsxs("button", { onClick: handleEdit, className: "font-normal inline-flex items-center gap-2 bg-transparent border-0 p-0 cursor-pointer hover:opacity-80", style: {
|
|
4534
4543
|
fontFamily: 'Roboto, sans-serif',
|
|
4535
4544
|
fontSize: '16px',
|
|
4536
4545
|
color: 'rgba(0, 0, 0, 0.50)'
|
|
4537
|
-
}, children: [
|
|
4546
|
+
}, children: [translate('common.editDetails') || 'Edit Details', jsxRuntimeExports.jsx("img", { src: img$8, alt: "right-arrow", className: "w-3.5 h-3.5 brightness-0 opacity-50" })] }) }))] })] })) })] }));
|
|
4538
4547
|
};
|
|
4539
4548
|
|
|
4540
4549
|
/**
|
|
@@ -8935,6 +8944,17 @@ const DEFAULT_STATUS_COLORS = {
|
|
|
8935
8944
|
inactive: '#D97706',
|
|
8936
8945
|
archived: '#6B7280',
|
|
8937
8946
|
};
|
|
8947
|
+
const DEFAULT_LABELS = {
|
|
8948
|
+
functionalId: 'Functional Record ID',
|
|
8949
|
+
status: 'Record Status',
|
|
8950
|
+
statusReason: 'Status Reason',
|
|
8951
|
+
select: 'Select',
|
|
8952
|
+
enterReason: 'Enter Reason',
|
|
8953
|
+
createdBy: 'Created by',
|
|
8954
|
+
createdAt: 'Created at',
|
|
8955
|
+
lastApprovedBy: 'Last Approved by',
|
|
8956
|
+
lastApprovedAt: 'Last Approved at',
|
|
8957
|
+
};
|
|
8938
8958
|
// ── Hook: load data-source options for a single field ────────────
|
|
8939
8959
|
// Options are loaded in both view and edit modes because view mode
|
|
8940
8960
|
// needs them to resolve display labels (e.g. "active" → "Active").
|
|
@@ -8998,6 +9018,21 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
8998
9018
|
const values = useSelector((state) => state.widget.values);
|
|
8999
9019
|
const isReadonly = widgetConfig['widget-readonly'] !== false;
|
|
9000
9020
|
const dataPath = widgetConfig['widget-data-path'];
|
|
9021
|
+
// ── Resolve labels ──────────────────────────────────────────────
|
|
9022
|
+
// Priority: widget-labels override → translateConfig(English default) → English default
|
|
9023
|
+
// The host's locale JSON files should use the English text as keys,
|
|
9024
|
+
// e.g. { "Functional Record ID": "ID fonctionnel" }
|
|
9025
|
+
const configLabels = widgetConfig['widget-labels'];
|
|
9026
|
+
const getLabel = useCallback((key) => {
|
|
9027
|
+
const englishDefault = DEFAULT_LABELS[key] || key;
|
|
9028
|
+
if (configLabels?.[key]) {
|
|
9029
|
+
const translated = translateConfig(configLabels[key]);
|
|
9030
|
+
if (translated && translated !== configLabels[key])
|
|
9031
|
+
return translated;
|
|
9032
|
+
}
|
|
9033
|
+
const translated = translateConfig(englishDefault);
|
|
9034
|
+
return translated || englishDefault;
|
|
9035
|
+
}, [configLabels, translateConfig]);
|
|
9001
9036
|
// ── Per-field config map ──────────────────────────────────────
|
|
9002
9037
|
const fieldConfigMap = useMemo(() => {
|
|
9003
9038
|
return widgetConfig['widget-field-config'] || {};
|
|
@@ -9045,7 +9080,7 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9045
9080
|
const lastApprovedAt = findValue('lastApprovedAt') || '';
|
|
9046
9081
|
// ── Format options ────────────────────────────────────────────
|
|
9047
9082
|
const format = (widgetConfig['widget-data-format'] || {});
|
|
9048
|
-
const imageSize = format.imageSize ||
|
|
9083
|
+
const imageSize = format.imageSize || 120;
|
|
9049
9084
|
const nameColor = format.nameColor || '#ED7C22';
|
|
9050
9085
|
const statusColors = {
|
|
9051
9086
|
...DEFAULT_STATUS_COLORS,
|
|
@@ -9095,7 +9130,7 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9095
9130
|
flex-direction: row;
|
|
9096
9131
|
align-items: flex-start;
|
|
9097
9132
|
gap: 1rem;
|
|
9098
|
-
flex: 1 1
|
|
9133
|
+
flex: 1 1 50%;
|
|
9099
9134
|
min-width: 0;
|
|
9100
9135
|
}
|
|
9101
9136
|
|
|
@@ -9103,7 +9138,7 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9103
9138
|
display: flex;
|
|
9104
9139
|
flex-direction: column;
|
|
9105
9140
|
gap: 0.5rem;
|
|
9106
|
-
flex:
|
|
9141
|
+
flex: 1 1 40%;
|
|
9107
9142
|
min-width: 220px;
|
|
9108
9143
|
}
|
|
9109
9144
|
|
|
@@ -9157,19 +9192,19 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9157
9192
|
display: flex;
|
|
9158
9193
|
align-items: flex-start;
|
|
9159
9194
|
gap: 0.5rem;
|
|
9160
|
-
font-size:
|
|
9195
|
+
font-size: 1rem;
|
|
9161
9196
|
line-height: 1.6;
|
|
9162
9197
|
}
|
|
9163
9198
|
|
|
9164
9199
|
.${cls} .hdr-field-label {
|
|
9165
|
-
color:
|
|
9166
|
-
font-weight:
|
|
9200
|
+
color: rgba(0, 0, 0, 0.5);
|
|
9201
|
+
font-weight: 400;
|
|
9167
9202
|
white-space: nowrap;
|
|
9168
9203
|
}
|
|
9169
9204
|
|
|
9170
9205
|
.${cls} .hdr-field-value {
|
|
9171
9206
|
color: #111827;
|
|
9172
|
-
font-weight:
|
|
9207
|
+
font-weight: 500;
|
|
9173
9208
|
}
|
|
9174
9209
|
|
|
9175
9210
|
.${cls} .hdr-status-badge {
|
|
@@ -9185,18 +9220,18 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9185
9220
|
display: flex;
|
|
9186
9221
|
align-items: baseline;
|
|
9187
9222
|
gap: 0.35rem;
|
|
9188
|
-
font-size:
|
|
9223
|
+
font-size: 1rem;
|
|
9189
9224
|
line-height: 1.6;
|
|
9190
9225
|
}
|
|
9191
9226
|
|
|
9192
9227
|
.${cls} .hdr-meta-label {
|
|
9193
|
-
color:
|
|
9228
|
+
color: rgba(0, 0, 0, 0.5);
|
|
9194
9229
|
font-weight: 400;
|
|
9195
9230
|
}
|
|
9196
9231
|
|
|
9197
9232
|
.${cls} .hdr-meta-value {
|
|
9198
9233
|
color: #111827;
|
|
9199
|
-
font-weight:
|
|
9234
|
+
font-weight: 500;
|
|
9200
9235
|
}
|
|
9201
9236
|
|
|
9202
9237
|
.${cls} .hdr-select {
|
|
@@ -9247,7 +9282,7 @@ const HeaderSectionWidget = ({ config }) => {
|
|
|
9247
9282
|
.parentElement?.querySelector('.hdr-avatar-placeholder');
|
|
9248
9283
|
if (placeholder)
|
|
9249
9284
|
placeholder.style.display = 'flex';
|
|
9250
|
-
} })) : null, jsxRuntimeExports.jsx("div", { className: "hdr-avatar-placeholder", style: { display: imageUrl ? 'none' : 'flex' }, children: jsxRuntimeExports.jsx("img", { src: img$f, alt: "Profile Placeholder" }) })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-info", children: [displayName && jsxRuntimeExports.jsx("div", { className: "hdr-name", children: displayName }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx(Dot, { color: "#9CA3AF" }), jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", children: [
|
|
9285
|
+
} })) : null, jsxRuntimeExports.jsx("div", { className: "hdr-avatar-placeholder", style: { display: imageUrl ? 'none' : 'flex' }, children: jsxRuntimeExports.jsx("img", { src: img$f, alt: "Profile Placeholder" }) })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-info", children: [displayName && jsxRuntimeExports.jsx("div", { className: "hdr-name", children: displayName }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx(Dot, { color: "#9CA3AF" }), jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", children: [getLabel('functionalId'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: functionalId || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx(Dot, { color: isReadonly ? statusColor : '#F59E0B' }), jsxRuntimeExports.jsx("span", { className: "hdr-field-label", children: getLabel('status') }), isReadonly ? (statusLabel ? (jsxRuntimeExports.jsx("span", { className: "hdr-status-badge", style: { backgroundColor: statusColor }, children: statusLabel })) : (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: "-" }))) : (jsxRuntimeExports.jsxs("select", { className: "hdr-select", value: statusValue, onChange: (e) => updateFieldValue('status', e.target.value), children: [jsxRuntimeExports.jsx("option", { value: "", children: getLabel('select') }), statusOptions.map((opt) => (jsxRuntimeExports.jsx("option", { value: opt.value, children: opt.label }, opt.value)))] }))] }), jsxRuntimeExports.jsxs("div", { className: "hdr-field-row", children: [jsxRuntimeExports.jsx(Dot, { color: isReadonly ? '#9CA3AF' : '#F59E0B' }), jsxRuntimeExports.jsxs("span", { className: "hdr-field-label", children: [getLabel('statusReason'), " :"] }), isReadonly ? (jsxRuntimeExports.jsx("span", { className: "hdr-field-value", children: statusReason || '-' })) : (jsxRuntimeExports.jsx("input", { type: "text", className: "hdr-input", value: statusReason, placeholder: getLabel('enterReason'), onChange: (e) => updateFieldValue('statusReason', e.target.value) }))] })] })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-right", children: [jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('createdBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: createdBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('createdAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: createdAt || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('lastApprovedBy'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: lastApprovedBy || '-' })] }), jsxRuntimeExports.jsxs("div", { className: "hdr-meta-row", children: [jsxRuntimeExports.jsxs("span", { className: "hdr-meta-label", children: [getLabel('lastApprovedAt'), " :"] }), jsxRuntimeExports.jsx("span", { className: "hdr-meta-value", children: lastApprovedAt || '-' })] })] })] })] }));
|
|
9251
9286
|
};
|
|
9252
9287
|
|
|
9253
9288
|
/**
|
|
@@ -9345,8 +9380,13 @@ var enTranslations = {
|
|
|
9345
9380
|
"common.uploadFile": "Upload File",
|
|
9346
9381
|
"common.maxFileSize": "Maximum file size: {{size}} MB",
|
|
9347
9382
|
"common.edit": "Edit",
|
|
9383
|
+
"common.editDetails": "Edit Details",
|
|
9348
9384
|
"common.save": "Save",
|
|
9349
9385
|
"common.cancel": "Cancel",
|
|
9386
|
+
"common.previous": "Prev",
|
|
9387
|
+
"common.next": "Next",
|
|
9388
|
+
"common.sectionSaved": "Saved",
|
|
9389
|
+
"common.sectionModified": "Modified and not saved",
|
|
9350
9390
|
"common.supportedDocuments": "Supported Documents",
|
|
9351
9391
|
"table.addRecord": "Add New Record",
|
|
9352
9392
|
"table.confirm": "Confirm Action",
|