@gemx-dev/clarity-visualize 0.8.47 → 0.8.49
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/build/clarity.visualize.js +1067 -767
- package/build/clarity.visualize.min.js +1 -1
- package/build/clarity.visualize.module.js +1067 -767
- package/package.json +2 -2
- package/src/custom/README.md +60 -0
- package/src/custom/dialog.ts +129 -0
- package/src/custom/index.ts +6 -0
- package/src/layout.ts +26 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gemx-dev/clarity-visualize",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.49",
|
|
4
4
|
"description": "Clarity visualize",
|
|
5
5
|
"author": "Microsoft Corp.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"unpkg": "build/clarity.visualize.min.js",
|
|
10
10
|
"types": "types/index.d.ts",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@gemx-dev/clarity-decode": "^0.8.
|
|
12
|
+
"@gemx-dev/clarity-decode": "^0.8.49"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@rollup/plugin-commonjs": "^24.0.0",
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Custom Clarity Visualize Modules
|
|
2
|
+
|
|
3
|
+
This directory contains custom rendering modules that extend the base Clarity visualization for GemX.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
All custom modules follow the functional module pattern:
|
|
8
|
+
- Pure functions for testability
|
|
9
|
+
- No side effects in utility functions
|
|
10
|
+
- Clear separation of concerns
|
|
11
|
+
- Type-safe interfaces
|
|
12
|
+
|
|
13
|
+
## Modules
|
|
14
|
+
|
|
15
|
+
### Dialog Module (`dialog.ts`)
|
|
16
|
+
|
|
17
|
+
Renders HTML `<dialog>` elements with proper top-layer and backdrop support.
|
|
18
|
+
|
|
19
|
+
**Functions:**
|
|
20
|
+
|
|
21
|
+
- `getDialogRenderOptions(attributes, dialogElement)` - Extracts rendering options from attributes
|
|
22
|
+
- `showDialog(dialogElement, isModal, onError)` - Shows dialog with proper modal/non-modal handling
|
|
23
|
+
- `closeDialog(dialogElement)` - Safely closes a dialog
|
|
24
|
+
- `renderDialog(dialogElement, options, onError)` - Main entry point for dialog rendering
|
|
25
|
+
- `cleanDialogAttributes(attributes)` - Removes internal tracking attributes
|
|
26
|
+
|
|
27
|
+
**Usage:**
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import * as dialogCustom from "./custom/dialog";
|
|
31
|
+
|
|
32
|
+
const renderOptions = dialogCustom.getDialogRenderOptions(node.attributes, dialogElement);
|
|
33
|
+
node.attributes = dialogCustom.cleanDialogAttributes(node.attributes);
|
|
34
|
+
|
|
35
|
+
dialogCustom.renderDialog(
|
|
36
|
+
dialogElement,
|
|
37
|
+
renderOptions,
|
|
38
|
+
this.state.options.logerror
|
|
39
|
+
);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Features:**
|
|
43
|
+
|
|
44
|
+
- Automatic detection of modal vs non-modal dialogs
|
|
45
|
+
- Proper top-layer rendering via `showModal()`
|
|
46
|
+
- Backdrop support for modal dialogs
|
|
47
|
+
- Handles dialogs already open from HTML attributes
|
|
48
|
+
- Error handling and logging
|
|
49
|
+
|
|
50
|
+
## Adding New Custom Modules
|
|
51
|
+
|
|
52
|
+
1. Create a new file in this directory (e.g., `my-feature.ts`)
|
|
53
|
+
2. Follow the functional module pattern
|
|
54
|
+
3. Export functions with clear type signatures
|
|
55
|
+
4. Add exports to `index.ts`
|
|
56
|
+
5. Document the module in this README
|
|
57
|
+
|
|
58
|
+
## Testing
|
|
59
|
+
|
|
60
|
+
Custom modules should be unit tested separately from the main Clarity codebase.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom module for rendering HTML Dialog elements
|
|
3
|
+
* Handles proper visualization of modal dialogs in the top-layer
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface DialogRenderOptions {
|
|
7
|
+
isModal: boolean;
|
|
8
|
+
shouldBeOpen: boolean;
|
|
9
|
+
isExistingDialog: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Extracts dialog rendering options from node attributes
|
|
14
|
+
*
|
|
15
|
+
* @param attributes - Node attributes containing dialog state
|
|
16
|
+
* @param dialogElement - The dialog element being rendered
|
|
17
|
+
* @returns Dialog render options
|
|
18
|
+
*/
|
|
19
|
+
export function getDialogRenderOptions(
|
|
20
|
+
attributes: { [key: string]: string },
|
|
21
|
+
dialogElement: HTMLDialogElement | null
|
|
22
|
+
): DialogRenderOptions {
|
|
23
|
+
return {
|
|
24
|
+
isModal: attributes["data-clarity-modal"] === "true",
|
|
25
|
+
shouldBeOpen: attributes["open"] !== undefined,
|
|
26
|
+
isExistingDialog: !!dialogElement
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Shows a dialog element with proper modal/non-modal handling
|
|
32
|
+
* Modal dialogs are shown via showModal() to render in top-layer with backdrop
|
|
33
|
+
* Non-modal dialogs are shown via show() method
|
|
34
|
+
*
|
|
35
|
+
* @param dialogElement - The dialog element to show
|
|
36
|
+
* @param isModal - Whether this is a modal dialog
|
|
37
|
+
* @param onError - Optional error callback
|
|
38
|
+
*/
|
|
39
|
+
export function showDialog(
|
|
40
|
+
dialogElement: HTMLDialogElement,
|
|
41
|
+
isModal: boolean,
|
|
42
|
+
onError?: (error: Error) => void
|
|
43
|
+
): void {
|
|
44
|
+
try {
|
|
45
|
+
if (!dialogElement.isConnected) {
|
|
46
|
+
console.warn('⚠️ Dialog not connected to DOM, skipping show');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// IMPORTANT: If dialog is already open (from HTML attribute),
|
|
51
|
+
// we need to close and reopen to ensure showModal() is called
|
|
52
|
+
// and dialog enters top-layer properly
|
|
53
|
+
if (dialogElement.open) {
|
|
54
|
+
dialogElement.close();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (isModal) {
|
|
58
|
+
dialogElement.showModal();
|
|
59
|
+
} else {
|
|
60
|
+
dialogElement.show();
|
|
61
|
+
}
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.error('❌ Error showing dialog:', e);
|
|
64
|
+
if (onError) {
|
|
65
|
+
onError(e as Error);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Closes a dialog element safely
|
|
72
|
+
*
|
|
73
|
+
* @param dialogElement - The dialog element to close
|
|
74
|
+
*/
|
|
75
|
+
export function closeDialog(dialogElement: HTMLDialogElement): void {
|
|
76
|
+
try {
|
|
77
|
+
if (dialogElement.open) {
|
|
78
|
+
dialogElement.close();
|
|
79
|
+
}
|
|
80
|
+
} catch (e) {
|
|
81
|
+
console.warn('⚠️ Error closing dialog:', e);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Handles dialog rendering based on its state
|
|
87
|
+
* This is the main entry point for dialog rendering logic
|
|
88
|
+
*
|
|
89
|
+
* @param dialogElement - The dialog element to render
|
|
90
|
+
* @param options - Dialog render options
|
|
91
|
+
* @param onError - Optional error callback
|
|
92
|
+
*/
|
|
93
|
+
export function renderDialog(
|
|
94
|
+
dialogElement: HTMLDialogElement,
|
|
95
|
+
options: DialogRenderOptions,
|
|
96
|
+
onError?: (error: Error) => void
|
|
97
|
+
): void {
|
|
98
|
+
const { isModal, shouldBeOpen, isExistingDialog } = options;
|
|
99
|
+
|
|
100
|
+
if (shouldBeOpen) {
|
|
101
|
+
const doShow = () => showDialog(dialogElement, isModal, onError);
|
|
102
|
+
|
|
103
|
+
if (isExistingDialog) {
|
|
104
|
+
// Dialog already exists, call immediately
|
|
105
|
+
doShow();
|
|
106
|
+
} else {
|
|
107
|
+
// New dialog, wait for DOM insertion
|
|
108
|
+
setTimeout(doShow, 0);
|
|
109
|
+
}
|
|
110
|
+
} else if (dialogElement.open) {
|
|
111
|
+
// Dialog should be closed
|
|
112
|
+
closeDialog(dialogElement);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Removes custom tracking attributes before rendering
|
|
118
|
+
* These attributes are only for internal use
|
|
119
|
+
*
|
|
120
|
+
* @param attributes - Attributes object to clean
|
|
121
|
+
* @returns Cleaned attributes
|
|
122
|
+
*/
|
|
123
|
+
export function cleanDialogAttributes(
|
|
124
|
+
attributes: { [key: string]: string }
|
|
125
|
+
): { [key: string]: string } {
|
|
126
|
+
const cleaned = { ...attributes };
|
|
127
|
+
delete cleaned["data-clarity-modal"];
|
|
128
|
+
return cleaned;
|
|
129
|
+
}
|
package/src/layout.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { StyleSheetOperation } from "@gemx-dev/clarity-js/types/layout";
|
|
|
5
5
|
import { AnimationOperation } from "@gemx-dev/clarity-js/types/layout";
|
|
6
6
|
import { Constant as LayoutConstants } from "@gemx-dev/clarity-js/types/layout";
|
|
7
7
|
import sharedStyle from "./styles/shared.css";
|
|
8
|
+
import * as dialogCustom from "./custom/dialog";
|
|
8
9
|
|
|
9
10
|
/* BEGIN blobUnavailableSvgs */
|
|
10
11
|
import blobUnavailableSvgEnglish from "./styles/blobUnavailable/english.svg";
|
|
@@ -459,6 +460,31 @@ export class LayoutHelper {
|
|
|
459
460
|
this.insertDefaultElement(node, parent, pivot, doc, insert);
|
|
460
461
|
break;
|
|
461
462
|
}
|
|
463
|
+
case "DIALOG":
|
|
464
|
+
{
|
|
465
|
+
// Use custom module for dialog rendering
|
|
466
|
+
let dialogElement = this.element(node.id) as HTMLDialogElement;
|
|
467
|
+
dialogElement = dialogElement ? dialogElement : this.createElement(doc, node.tag) as HTMLDialogElement;
|
|
468
|
+
if (!node.attributes) { node.attributes = {}; }
|
|
469
|
+
|
|
470
|
+
// Extract render options before cleaning attributes
|
|
471
|
+
const renderOptions = dialogCustom.getDialogRenderOptions(node.attributes, dialogElement);
|
|
472
|
+
|
|
473
|
+
// Clean custom tracking attributes
|
|
474
|
+
node.attributes = dialogCustom.cleanDialogAttributes(node.attributes);
|
|
475
|
+
|
|
476
|
+
// Set attributes and insert into DOM
|
|
477
|
+
this.setAttributes(dialogElement, node);
|
|
478
|
+
insert(node, parent, dialogElement, pivot);
|
|
479
|
+
|
|
480
|
+
// Render dialog with proper modal/non-modal handling
|
|
481
|
+
dialogCustom.renderDialog(
|
|
482
|
+
dialogElement,
|
|
483
|
+
renderOptions,
|
|
484
|
+
this.state.options.logerror
|
|
485
|
+
);
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
462
488
|
default:
|
|
463
489
|
this.insertDefaultElement(node, parent, pivot, doc, insert);
|
|
464
490
|
break;
|