openstack-uicore-foundation 5.0.6 → 5.0.8-beta.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/docs/plans/2026-04-09-showconfirmdialog-react16-compat.md +83 -0
- package/lib/components/index.js +1 -1
- package/lib/components/index.js.map +1 -1
- package/lib/components/mui/confirm-dialog-provider.js +2 -0
- package/lib/components/mui/confirm-dialog-provider.js.map +1 -0
- package/lib/components/mui/editable-table.js +1 -1
- package/lib/components/mui/editable-table.js.map +1 -1
- package/lib/components/mui/formik-inputs/additional-input-list.js +1 -1
- package/lib/components/mui/formik-inputs/additional-input-list.js.map +1 -1
- package/lib/components/mui/formik-inputs/additional-input.js +1 -1
- package/lib/components/mui/formik-inputs/additional-input.js.map +1 -1
- package/lib/components/mui/show-confirm-dialog.js +1 -1
- package/lib/components/mui/show-confirm-dialog.js.map +1 -1
- package/lib/components/mui/sortable-table.js +1 -1
- package/lib/components/mui/sortable-table.js.map +1 -1
- package/lib/components/mui/table.js +1 -1
- package/lib/components/mui/table.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# showConfirmDialog React 16 Compatibility Fix Plan
|
|
2
|
+
|
|
3
|
+
Created: 2026-04-09
|
|
4
|
+
Author: smarcet@gmail.com
|
|
5
|
+
Status: VERIFIED
|
|
6
|
+
Approved: Yes
|
|
7
|
+
Iterations: 0
|
|
8
|
+
Worktree: No
|
|
9
|
+
Type: Bugfix
|
|
10
|
+
|
|
11
|
+
## Summary
|
|
12
|
+
|
|
13
|
+
**Symptom:** `showConfirmDialog` causes "Module not found: Error: Can't resolve 'react-dom/client'" build error on React 16 projects, despite a `/* webpackIgnore: true */` dynamic import guard.
|
|
14
|
+
|
|
15
|
+
**Trigger:** Any consuming project on React 16 that bundles `openstack-uicore-foundation` hits the error during webpack build.
|
|
16
|
+
|
|
17
|
+
**Root Cause:** `src/components/mui/showConfirmDialog.js:27` — The `import(/* webpackIgnore: true */ "react-dom/client")` compiles into the UMD output as a bare `import("react-dom/client")` (the magic comment is stripped during this library's build). When a consuming project's webpack processes the compiled bundle, it encounters the bare dynamic import, tries to resolve `react-dom/client`, and fails because React 16 has no such module path.
|
|
18
|
+
|
|
19
|
+
## Investigation
|
|
20
|
+
|
|
21
|
+
- **Evolution:** Original code (cd39cf3) used only `ReactDOM.render()`. PR #214 (094c6b9) added `require("react-dom/client")` in try/catch for React 18+ support — caused the same build error. Commit 6c95b33 replaced `require()` with `import(/* webpackIgnore: true */ ...)` — the magic comment works for THIS library's webpack but is stripped from the compiled UMD output.
|
|
22
|
+
- **Confirmed in built output:** `lib/components/mui/show-confirm-dialog.js` contains literal `await import("react-dom/client")` with no webpack annotation — any consuming webpack resolves it at build time.
|
|
23
|
+
- **Key insight:** The `webpackIgnore` comment is a build-time directive that only affects the webpack instance that processes the source file. It does not survive into the output and cannot protect consuming projects.
|
|
24
|
+
- **Internal callers** (5 files: mui-table, mui-table-sortable, mui-table-editable, meta-field-values, additional-input-list) all use `showConfirmDialog` as a plain imperative function — `const isConfirmed = await showConfirmDialog({...})`.
|
|
25
|
+
|
|
26
|
+
## Fix Approach
|
|
27
|
+
|
|
28
|
+
**Chosen:** Bridge Pattern + Context Provider
|
|
29
|
+
|
|
30
|
+
**Why:** Completely eliminates all references to `react-dom/client` from the source and compiled output. The dialog renders inside the existing React tree (managed by whatever React version the app uses), so no version-specific rendering API is needed. Preserves the imperative `showConfirmDialog()` API unchanged.
|
|
31
|
+
|
|
32
|
+
**Alternatives considered:**
|
|
33
|
+
- *Configuration injection* (`configureConfirmDialog({ createRoot })`) — simpler but less ergonomic; consumer must handle version detection and import themselves.
|
|
34
|
+
- *Remove createRoot entirely* (pure `ReactDOM.render`) — works on 16/17/18 but breaks React 19 where `ReactDOM.render` was removed.
|
|
35
|
+
|
|
36
|
+
**How it works:**
|
|
37
|
+
1. A new `ConfirmDialogProvider` component manages dialog state (open/closed, options, resolve callback) and renders `ConfirmDialog` within the existing React tree.
|
|
38
|
+
2. On mount, the provider registers a "bridge" callback in a module-level variable inside `showConfirmDialog.js`.
|
|
39
|
+
3. When `showConfirmDialog()` is called, it delegates to the bridge if registered. If no provider is mounted, it falls back to `ReactDOM.render()` with a console warning (backward compat for React 16/17/18 consumers who haven't added the provider yet).
|
|
40
|
+
4. Zero references to `react-dom/client` remain in the codebase.
|
|
41
|
+
|
|
42
|
+
**Files:**
|
|
43
|
+
- `src/components/mui/showConfirmDialog.js` — Add bridge registration, fallback logic
|
|
44
|
+
- `src/components/mui/ConfirmDialogProvider.js` — NEW: Provider component
|
|
45
|
+
- `src/components/index.js` — Export the new provider
|
|
46
|
+
- `webpack.common.js` — Add entry point for the new provider
|
|
47
|
+
|
|
48
|
+
**Tests:**
|
|
49
|
+
- `src/components/mui/__tests__/show-confirm-dialog.test.js` — Update for bridge-based flow
|
|
50
|
+
- `src/components/mui/__tests__/confirm-dialog-provider.test.js` — NEW: Provider tests
|
|
51
|
+
|
|
52
|
+
**Defense-in-depth:** Not applicable — this is a build-time resolution error, not a data flow issue.
|
|
53
|
+
|
|
54
|
+
## Progress
|
|
55
|
+
|
|
56
|
+
- [x] Task 1: Implement bridge pattern + provider
|
|
57
|
+
- [x] Task 2: Verify
|
|
58
|
+
**Tasks:** 2 | **Done:** 2
|
|
59
|
+
|
|
60
|
+
## Tasks
|
|
61
|
+
|
|
62
|
+
### Task 1: Implement bridge pattern + provider
|
|
63
|
+
|
|
64
|
+
**Objective:** Replace the `react-dom/client` dynamic import with a bridge pattern. Create `ConfirmDialogProvider`, modify `showConfirmDialog` to use bridge with ReactDOM.render fallback, export the new provider.
|
|
65
|
+
|
|
66
|
+
**Files:**
|
|
67
|
+
- `src/components/mui/showConfirmDialog.js` — Remove `getCreateRoot()`, add bridge registration exports (`_registerBridge`, `_unregisterBridge`). When bridge is registered, delegate. When not, fall back to `ReactDOM.render()` with `console.warn` suggesting provider migration.
|
|
68
|
+
- `src/components/mui/ConfirmDialogProvider.js` — NEW: Functional component using `useState` + `useEffect`. On mount, registers bridge via `_registerBridge`. Bridge callback sets dialog state and returns a Promise. Renders `<ConfirmDialog>` when dialog state is active. On unmount, calls `_unregisterBridge`.
|
|
69
|
+
- `src/components/index.js` — Add export: `export { default as ConfirmDialogProvider } from './mui/ConfirmDialogProvider'`
|
|
70
|
+
- `webpack.common.js` — Add entry: `'components/mui/confirm-dialog-provider': './src/components/mui/ConfirmDialogProvider.js'`
|
|
71
|
+
|
|
72
|
+
**TDD:**
|
|
73
|
+
1. Write regression test: import `showConfirmDialog` without mocking `react-dom/client` — verify no reference to `react-dom/client` exists in the module
|
|
74
|
+
2. Write provider test: render `ConfirmDialogProvider`, call `showConfirmDialog`, verify dialog appears and resolves correctly
|
|
75
|
+
3. Write fallback test: call `showConfirmDialog` without provider mounted — verify `ReactDOM.render` is called with console warning
|
|
76
|
+
4. Verify all existing tests still pass (callers mock `showConfirmDialog` so they are unaffected)
|
|
77
|
+
|
|
78
|
+
**Verify:** `npx jest --no-cache`
|
|
79
|
+
|
|
80
|
+
### Task 2: Verify
|
|
81
|
+
|
|
82
|
+
**Objective:** Full test suite passes, no regressions across all components that use `showConfirmDialog`.
|
|
83
|
+
**Verify:** `npx jest --no-cache && grep -r "react-dom/client" src/ && echo "FAIL: react-dom/client still referenced" || echo "PASS: no react-dom/client references"`
|