@middag-io/react 0.6.0 → 0.7.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 +349 -0
- package/bin/codemods/README.md +18 -0
- package/bin/codemods/v0.7.0.mjs +21 -0
- package/bin/middag-react.js +91 -10
- package/dist-lib/{ConditionTreeBlock-BGPYAImJ.js → ConditionTreeBlock-B24FzcsP.js} +39 -36
- package/dist-lib/{FormBuilderBlock-b_-QQaKn.js → FormBuilderBlock-BFUwXZ4d.js} +773 -772
- package/dist-lib/{MarkdownContent-BgwUdgoN.js → MarkdownContent-C7osjiEF.js} +1322 -1320
- package/dist-lib/{SentenceBuilderBlock-ClWjm0dX.js → SentenceBuilderBlock-BuT-5hKD.js} +39 -38
- package/dist-lib/app/LazyBlock.d.ts.map +1 -1
- package/dist-lib/app/providers/error-reporter.d.ts +66 -0
- package/dist-lib/app/providers/error-reporter.d.ts.map +1 -0
- package/dist-lib/app/providers/i18n-defaults.d.ts +12 -0
- package/dist-lib/app/providers/i18n-defaults.d.ts.map +1 -0
- package/dist-lib/app/providers/i18n.d.ts.map +1 -1
- package/dist-lib/base/blocks/ActionGridBlock.d.ts.map +1 -1
- package/dist-lib/base/blocks/ActivityTimelineBlock.d.ts.map +1 -1
- package/dist-lib/base/blocks/ConditionTreeBlock.d.ts.map +1 -1
- package/dist-lib/base/blocks/DenseTableBlock.d.ts.map +1 -1
- package/dist-lib/base/blocks/DetailPanelBlock.d.ts.map +1 -1
- package/dist-lib/base/blocks/EmptyStateBlock.d.ts.map +1 -1
- package/dist-lib/base/blocks/FormBuilderBlock.d.ts.map +1 -1
- package/dist-lib/base/blocks/FormPanelBlock.d.ts.map +1 -1
- package/dist-lib/base/blocks/SentenceBuilderBlock.d.ts.map +1 -1
- package/dist-lib/base/form/fields/MultiSelectField.d.ts.map +1 -1
- package/dist-lib/base/partials/ActionBar/index.d.ts.map +1 -1
- package/dist-lib/base/partials/ConfirmationDialog/index.d.ts.map +1 -1
- package/dist-lib/base/partials/DataTable/index.d.ts +1 -1
- package/dist-lib/base/partials/DataTable/index.d.ts.map +1 -1
- package/dist-lib/base/partials/FilterBar/index.d.ts.map +1 -1
- package/dist-lib/base/partials/FormSection/index.d.ts.map +1 -1
- package/dist-lib/base/partials/LogViewer/LogViewerToolbar.d.ts.map +1 -1
- package/dist-lib/base/partials/MarkdownContent/index.d.ts.map +1 -1
- package/dist-lib/base/partials/TimelineList/index.d.ts.map +1 -1
- package/dist-lib/base/shell/AdminShell.d.ts.map +1 -1
- package/dist-lib/base/shell/ProductShell.d.ts.map +1 -1
- package/dist-lib/base/shell/partials/CommandPalette.d.ts.map +1 -1
- package/dist-lib/base/shell/partials/HelpPanel.d.ts.map +1 -1
- package/dist-lib/base/shell/partials/InlineInspector.d.ts.map +1 -1
- package/dist-lib/base/shell/partials/NavErrorBoundary.d.ts +3 -11
- package/dist-lib/base/shell/partials/NavErrorBoundary.d.ts.map +1 -1
- package/dist-lib/base/shell/partials/OverlayScreen.d.ts.map +1 -1
- package/dist-lib/base/shell/partials/PageActionButton.d.ts.map +1 -1
- package/dist-lib/base/shell/partials/PageHeader.d.ts.map +1 -1
- package/dist-lib/base/shell/partials/SidebarNav.d.ts.map +1 -1
- package/dist-lib/contracts/page-contract-schema.d.ts +2 -14
- package/dist-lib/contracts/page-contract-schema.d.ts.map +1 -1
- package/dist-lib/contracts/page-contract.d.ts +10 -2
- package/dist-lib/contracts/page-contract.d.ts.map +1 -1
- package/dist-lib/i18n-zhMby9Ml.js +128 -0
- package/dist-lib/index.d.ts +7 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/middag-react.css +1 -1
- package/dist-lib/middag-react.js +5176 -4790
- package/package.json +3 -2
- /package/dist-lib/{FlowEditorBlock-D3nx4re7.js → FlowEditorBlock-CHodeGBw.js} +0 -0
- /package/dist-lib/{dist-C3f2_wwS.js → dist-BDvVQ5m8.js} +0 -0
- /package/dist-lib/{index.min-BVLV21vp.js → index.min-Cno07_zY.js} +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# @middag-io/react
|
|
2
|
+
|
|
3
|
+
Shared React UI library for the MIDDAG ecosystem. Consumed by Moodle (`local_middag`) and WordPress host plugins via Inertia.js.
|
|
4
|
+
|
|
5
|
+
**[Live Demo](https://middag-react-mock.pages.dev)** | **[Documentation](https://ui-docs.middag.io)**
|
|
6
|
+
|
|
7
|
+
## Stack
|
|
8
|
+
|
|
9
|
+
- React 19, TypeScript, Tailwind CSS v4
|
|
10
|
+
- Inertia.js (peer dependency -- all hosts use Inertia)
|
|
11
|
+
- ReUI components (Radix-based)
|
|
12
|
+
- TanStack Table, @xyflow/react, @dnd-kit
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
### Quick start (recommended)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Community (no auth needed)
|
|
20
|
+
npx create-middag-ui
|
|
21
|
+
|
|
22
|
+
# PRO (source maps, mock SPA, full exports)
|
|
23
|
+
npx @middag-io/create-middag-ui
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The wizard detects your host platform (Moodle/WordPress), configures authentication, and scaffolds a `ui/` directory with a working mock build.
|
|
27
|
+
|
|
28
|
+
### Manual install
|
|
29
|
+
|
|
30
|
+
**npm public (no auth needed):**
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install @middag-io/react react react-dom @inertiajs/react @inertiajs/core
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**GitHub Packages (includes TypeScript source for IDE navigation):**
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Add to global ~/.npmrc
|
|
40
|
+
echo "@middag-io:registry=https://npm.pkg.github.com" >> ~/.npmrc
|
|
41
|
+
echo "//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN" >> ~/.npmrc
|
|
42
|
+
|
|
43
|
+
npm install @middag-io/react react react-dom @inertiajs/react @inertiajs/core
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Create a token at [github.com/settings/tokens](https://github.com/settings/tokens) with `read:packages` scope. See [Authentication](https://ui-docs.middag.io/authentication) for details.
|
|
47
|
+
|
|
48
|
+
> **GitHub Packages access requires:** membership in the [middag-io](https://github.com/middag-io) organization on GitHub. The token alone is not sufficient — you must have read access to the `middag-io/middag-react` repository.
|
|
49
|
+
|
|
50
|
+
### Community vs PRO
|
|
51
|
+
|
|
52
|
+
| Content | Community | PRO |
|
|
53
|
+
|---------|-----------|-----|
|
|
54
|
+
| ESM bundle (`dist-lib/`) | Yes | Yes |
|
|
55
|
+
| TypeScript declarations (`.d.ts`) | Yes | Yes |
|
|
56
|
+
| Declaration maps (`.d.ts.map`) | Yes | Yes |
|
|
57
|
+
| TypeScript source (`src/`) | No | Yes |
|
|
58
|
+
| Mock SPA extensible (`mock/`) | No | Yes |
|
|
59
|
+
| IDE "go to definition" into source | No | Yes |
|
|
60
|
+
| Authentication required | No | Yes |
|
|
61
|
+
|
|
62
|
+
Both editions deliver the same runtime code. Community is sufficient for building plugins. PRO additionally includes TypeScript source for IDE navigation and the extensible mock SPA.
|
|
63
|
+
|
|
64
|
+
## Usage
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { ContractPage, registerDefaults } from '@middag-io/react';
|
|
68
|
+
import type { PageContract } from '@middag-io/react';
|
|
69
|
+
|
|
70
|
+
// Register core shells, layouts, and all 17 blocks
|
|
71
|
+
registerDefaults();
|
|
72
|
+
|
|
73
|
+
// Render a contract-driven page
|
|
74
|
+
<ContractPage contract={myContract} />
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Selective registration (IIFE consumers)
|
|
78
|
+
|
|
79
|
+
WordPress and other IIFE consumers should import only the blocks they need to avoid bundling heavy dependencies (@xyflow/react, @dnd-kit) via `inlineDynamicImports`:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import {
|
|
83
|
+
ContractPage,
|
|
84
|
+
registerShell, registerLayout, registerBlock,
|
|
85
|
+
AdminShell, StackLayout, DashboardLayout,
|
|
86
|
+
DenseTableBlock, MetricCardBlock, EmptyStateBlock,
|
|
87
|
+
} from '@middag-io/react';
|
|
88
|
+
|
|
89
|
+
registerShell('admin', AdminShell);
|
|
90
|
+
registerLayout('stack', StackLayout);
|
|
91
|
+
registerLayout('dashboard', DashboardLayout);
|
|
92
|
+
registerBlock('dense_table', DenseTableBlock);
|
|
93
|
+
registerBlock('metric_card', MetricCardBlock);
|
|
94
|
+
registerBlock('empty_state', EmptyStateBlock);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Lazy block loading
|
|
98
|
+
|
|
99
|
+
Blocks can defer data loading until they mount (useful for tabbed pages):
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
// PHP sends block with empty data + lazyProp metadata:
|
|
103
|
+
{
|
|
104
|
+
type: 'dense_table',
|
|
105
|
+
key: 'invoices',
|
|
106
|
+
data: {},
|
|
107
|
+
meta: { lazyProp: 'invoices' }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// PHP also sends a top-level Inertia prop (initially null):
|
|
111
|
+
// 'invoices' => null
|
|
112
|
+
|
|
113
|
+
// When the block mounts, it auto-fetches via router.reload({ only: ['invoices'] })
|
|
114
|
+
// Radix Tabs unmounts inactive tabs, so lazy blocks only fetch when their tab activates
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### ReUI components
|
|
118
|
+
|
|
119
|
+
Consumers can import ReUI primitives for custom components:
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@middag-io/react/reui/tabs.tsx';
|
|
123
|
+
import { Button } from '@middag-io/react/reui/button.tsx';
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Custom blocks
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
import { registerBlock, type BlockProps } from '@middag-io/react';
|
|
130
|
+
|
|
131
|
+
function ChartBlock({ block }: BlockProps<{ labels: string[]; values: number[] }>) {
|
|
132
|
+
return <div>{/* your chart */}</div>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
registerBlock('chart', ChartBlock);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Contract validation
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import { validatePageContract } from '@middag-io/react';
|
|
142
|
+
|
|
143
|
+
const errors = validatePageContract(contractFromBackend);
|
|
144
|
+
if (errors) {
|
|
145
|
+
console.error('Invalid contract:', errors);
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Zod schemas are exported for consumers who want to extend validation or generate JSON Schema for PHP consumers.
|
|
150
|
+
|
|
151
|
+
### i18n with host-specific resolver
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import { I18nProvider } from '@middag-io/react';
|
|
155
|
+
|
|
156
|
+
// Moodle: inject Moodle string resolver
|
|
157
|
+
<I18nProvider asyncResolver={moodleGetStrings}>
|
|
158
|
+
<App />
|
|
159
|
+
</I18nProvider>
|
|
160
|
+
|
|
161
|
+
// WordPress: inject WP i18n resolver
|
|
162
|
+
<I18nProvider asyncResolver={wpGetStrings}>
|
|
163
|
+
<App />
|
|
164
|
+
</I18nProvider>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Architecture
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
src/
|
|
171
|
+
app/ # ContractPage, registries, providers, LazyBlock
|
|
172
|
+
base/ # Shells, layouts, blocks, hooks, theme, partials
|
|
173
|
+
components/
|
|
174
|
+
reui/ # ReUI primitives (Radix-based, source of truth)
|
|
175
|
+
examples/ # ReUI component examples (synced from registry)
|
|
176
|
+
contracts/ # TypeScript types (PageContract, BlockData, etc.)
|
|
177
|
+
lib/ # Generic utilities and hooks
|
|
178
|
+
assets/ # Fonts, lottie animations
|
|
179
|
+
index.ts # Barrel export
|
|
180
|
+
mock/ # Dev playground (standalone SPA, no server needed)
|
|
181
|
+
scripts/ # Tooling (sync, doctor)
|
|
182
|
+
.githooks/ # Git hooks (pre-commit, commit-msg, pre-push)
|
|
183
|
+
.changeset/ # Changesets config for automated versioning
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### What belongs here vs host plugins
|
|
187
|
+
|
|
188
|
+
| Here (@middag-io/react) | Host plugin (Moodle/WP) |
|
|
189
|
+
|-----------------------------|-------------------------------------|
|
|
190
|
+
| Shells, layouts, blocks | Extensions with host-specific pages |
|
|
191
|
+
| ContractPage renderer | Inertia server-side adapter |
|
|
192
|
+
| Theme system | License validation (server-side) |
|
|
193
|
+
| i18n provider (generic) | i18n resolver (host-specific) |
|
|
194
|
+
| Type contracts | API endpoints, DB queries |
|
|
195
|
+
| ReUI examples (reference) | Custom components |
|
|
196
|
+
| Mock build (dev playground) | AMD build (Moodle), ESM bundle (WP) |
|
|
197
|
+
|
|
198
|
+
### Extension model
|
|
199
|
+
|
|
200
|
+
Extensions implement `ExtensionPage` (extends `PageContract`) for licensed features. The build gate excludes unlicensed extensions at compile time. Host plugins handle server-side license checks and only send contracts for active extensions.
|
|
201
|
+
|
|
202
|
+
## Development
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Check environment
|
|
206
|
+
npm run doctor
|
|
207
|
+
|
|
208
|
+
# Mock build -- standalone SPA, no server needed
|
|
209
|
+
npm run dev:mock # http://localhost:5174
|
|
210
|
+
|
|
211
|
+
# Typecheck
|
|
212
|
+
npm run typecheck
|
|
213
|
+
|
|
214
|
+
# Lint
|
|
215
|
+
npm run lint:fix
|
|
216
|
+
|
|
217
|
+
# Build ESM lib
|
|
218
|
+
npm run build
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Host switching (mock only)
|
|
222
|
+
|
|
223
|
+
The mock build includes a host switcher (M/W button in sidebar footer) to preview the UI inside Moodle Boost header or WordPress admin chrome.
|
|
224
|
+
|
|
225
|
+
### ReUI component examples
|
|
226
|
+
|
|
227
|
+
Examples from the ReUI registry are synced to `src/components/examples/`. They serve as reference for component usage and are excluded from the published NPM package.
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Sync all examples from ReUI registry (auto-discovers new components)
|
|
231
|
+
npm run sync:examples
|
|
232
|
+
|
|
233
|
+
# Preview what would be synced
|
|
234
|
+
npm run sync:examples -- --dry-run
|
|
235
|
+
|
|
236
|
+
# Check if new examples are available (used by CI)
|
|
237
|
+
npm run sync:examples -- --check
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
A GitHub Action runs weekly (Mondays 8:00 UTC) to check for new examples and opens a PR automatically if updates are available.
|
|
241
|
+
|
|
242
|
+
## Git Hooks
|
|
243
|
+
|
|
244
|
+
Configured via `.githooks/` (activated by `npm run prepare`):
|
|
245
|
+
|
|
246
|
+
| Hook | Trigger | Protection |
|
|
247
|
+
|--------------|--------------|--------------------------------------|
|
|
248
|
+
| `pre-commit` | `git commit` | Typecheck + lint on staged files |
|
|
249
|
+
| `commit-msg` | `git commit` | Enforces Conventional Commits format |
|
|
250
|
+
| `pre-push` | `git push` | Full typecheck + lib build |
|
|
251
|
+
|
|
252
|
+
## Versioning
|
|
253
|
+
|
|
254
|
+
Uses [Changesets](https://github.com/changesets/changesets) for automated versioning and changelog with GitHub-linked entries.
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# After finishing a feature:
|
|
258
|
+
npx changeset # select patch/minor/major, write summary
|
|
259
|
+
git add . && git commit # include the .changeset/*.md file
|
|
260
|
+
|
|
261
|
+
# On merge to main:
|
|
262
|
+
# GitHub Action opens "Version Packages" PR
|
|
263
|
+
# Merge that PR to publish to GitHub Packages
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## CLI
|
|
267
|
+
|
|
268
|
+
The package includes a CLI for bootstrapping and maintaining the UI layer in consumer projects:
|
|
269
|
+
|
|
270
|
+
| Command | Description |
|
|
271
|
+
|-----------------------------------------|-------------------------------------------------------------------------------|
|
|
272
|
+
| `npx create-middag-ui` | Bootstrap `ui/` (Community) |
|
|
273
|
+
| `npx @middag-io/create-middag-ui` | Bootstrap `ui/` (PRO) |
|
|
274
|
+
| `npx @middag-io/react doctor` | Validate consumer project setup (deps, configs, peer deps) |
|
|
275
|
+
| `npx @middag-io/react dev` | Start mock dev server from consumer project |
|
|
276
|
+
| `npx @middag-io/react add-block <type>` | Scaffold a new block type with component + mock factory |
|
|
277
|
+
| `npx @middag-io/react upgrade` | Check for updates and run codemods |
|
|
278
|
+
|
|
279
|
+
## Scripts
|
|
280
|
+
|
|
281
|
+
| Command | Description |
|
|
282
|
+
|-------------------------|---------------------------------------|
|
|
283
|
+
| `npm run doctor` | Validate development environment |
|
|
284
|
+
| `npm run dev:mock` | Dev server with hot reload (mock SPA) |
|
|
285
|
+
| `npm run build` | Build ESM lib to `dist-lib/` |
|
|
286
|
+
| `npm run build:mock` | Build mock SPA to `dist-mock/` |
|
|
287
|
+
| `npm run typecheck` | TypeScript type check |
|
|
288
|
+
| `npm run lint` | ESLint check |
|
|
289
|
+
| `npm run lint:fix` | ESLint auto-fix |
|
|
290
|
+
| `npm run format` | Prettier format |
|
|
291
|
+
| `npm run format:check` | Prettier check |
|
|
292
|
+
| `npm run sync:examples` | Sync ReUI examples from registry |
|
|
293
|
+
| `npm run changeset` | Create a changeset for versioning |
|
|
294
|
+
| `npm run release` | Build + publish (used by CI) |
|
|
295
|
+
|
|
296
|
+
## Peer Dependencies
|
|
297
|
+
|
|
298
|
+
- `react` ^19.0.0
|
|
299
|
+
- `react-dom` ^19.0.0
|
|
300
|
+
- `@inertiajs/react` ^2.0.0
|
|
301
|
+
- `@inertiajs/core` ^2.0.0
|
|
302
|
+
|
|
303
|
+
## Mock Build Deployment (Cloudflare Pages)
|
|
304
|
+
|
|
305
|
+
The mock SPA is deployed automatically to Cloudflare Pages on every push to `main`.
|
|
306
|
+
|
|
307
|
+
**Live URL:** `https://middag-react-mock.pages.dev`
|
|
308
|
+
|
|
309
|
+
### First-time setup
|
|
310
|
+
|
|
311
|
+
1. Create the Cloudflare Pages project:
|
|
312
|
+
```bash
|
|
313
|
+
npx wrangler pages project create middag-react-mock --production-branch main
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
2. Add repository secrets in GitHub (`Settings > Secrets and variables > Actions`):
|
|
317
|
+
- `CLOUDFLARE_API_TOKEN` -- API token with "Cloudflare Pages: Edit" permission
|
|
318
|
+
- `CLOUDFLARE_ACCOUNT_ID` -- your Cloudflare account ID (found in dashboard URL or Workers & Pages overview)
|
|
319
|
+
|
|
320
|
+
3. Push to `main` -- the `deploy-mock.yml` workflow runs automatically.
|
|
321
|
+
|
|
322
|
+
### Manual deploy (local)
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
npm run build:mock
|
|
326
|
+
npx wrangler pages deploy dist-mock --project-name=middag-react-mock
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## CI/CD
|
|
330
|
+
|
|
331
|
+
| Workflow | Trigger | What it does |
|
|
332
|
+
|--------------------------------|-------------------------------------------|----------------------------------------------------------------------|
|
|
333
|
+
| `publish.yml` | Push to main | Typecheck + Changesets publish to GitHub Packages + npm public |
|
|
334
|
+
| `publish-create-middag-ui.yml` | Push to main (packages/create-middag-ui/) | Publish to npm (Community) + GitHub Packages (PRO) |
|
|
335
|
+
| `deploy-mock.yml` | Push to main / manual | Build mock + deploy to Cloudflare Pages |
|
|
336
|
+
| `sync-examples.yml` | Monday 8:00 UTC / manual | Sync ReUI examples, opens PR if updates |
|
|
337
|
+
|
|
338
|
+
### Required secrets
|
|
339
|
+
|
|
340
|
+
| Secret | Registry | Purpose |
|
|
341
|
+
|-------------------------|------------------|--------------------------------------------|
|
|
342
|
+
| `GITHUB_TOKEN` | GitHub Packages | Publish `@middag-io/react` (auto-provided) |
|
|
343
|
+
| `NPM_TOKEN` | npm (public) | Publish `@middag-io/react` + `create-middag-ui` |
|
|
344
|
+
| `CLOUDFLARE_API_TOKEN` | Cloudflare Pages | Deploy mock SPA |
|
|
345
|
+
| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare Pages | Account identifier |
|
|
346
|
+
|
|
347
|
+
## License
|
|
348
|
+
|
|
349
|
+
Private -- MIDDAG proprietary.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Codemods
|
|
2
|
+
|
|
3
|
+
Automatic migration scripts for breaking changes between versions.
|
|
4
|
+
|
|
5
|
+
Each codemod is a `.mjs` file named `v{VERSION}.mjs` (e.g., `v0.7.0.mjs`).
|
|
6
|
+
The upgrade command runs all codemods between the current and target version.
|
|
7
|
+
|
|
8
|
+
## Writing a codemod
|
|
9
|
+
|
|
10
|
+
Export a default function that receives the project root path:
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
export default async function migrate(projectRoot) {
|
|
14
|
+
// Read, transform, write files
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const description = "What this codemod does";
|
|
18
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.7.0 codemod: i18n defaults, error telemetry, mock exports, open contract types
|
|
3
|
+
*
|
|
4
|
+
* No breaking changes — inform user about new features.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* global console */
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
10
|
+
export default async function migrate(_projectRoot) {
|
|
11
|
+
console.log([
|
|
12
|
+
" No breaking changes in v0.7.0",
|
|
13
|
+
" New features available:",
|
|
14
|
+
" - LIB_UI_DEFAULTS: override lib UI strings via I18nProvider",
|
|
15
|
+
" - ErrorReporterProvider: plug Sentry/New Relic for error telemetry",
|
|
16
|
+
" - @middag-io/react/mock: extend the mock SPA (GitHub Packages only)",
|
|
17
|
+
" - Custom shell/layout types: register your own shells and layouts",
|
|
18
|
+
].join("\n"));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const description = "i18n defaults, error telemetry, mock exports, open contract types";
|
package/bin/middag-react.js
CHANGED
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
* For bootstrapping a new project, use: npx create-middag-ui
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
19
|
-
import { join } from "node:path";
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
19
|
+
import { join, dirname } from "node:path";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
20
21
|
import { execSync } from "node:child_process";
|
|
21
22
|
|
|
22
23
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
@@ -170,7 +171,55 @@ export function create${pascalName.replace("Block", "")}Block(
|
|
|
170
171
|
console.log(`\n Docs: https://docs.middag.io/guides/custom-blocks\n`);
|
|
171
172
|
}
|
|
172
173
|
|
|
173
|
-
|
|
174
|
+
/**
|
|
175
|
+
* Parse a semver string like "0.7.0" or "^0.6.0" into [major, minor, patch].
|
|
176
|
+
* Strips leading ^ ~ >= etc.
|
|
177
|
+
*/
|
|
178
|
+
function parseSemver(v) {
|
|
179
|
+
const m = String(v).match(/(\d+)\.(\d+)\.(\d+)/);
|
|
180
|
+
return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Compare two semver tuples: -1 (a < b), 0 (a == b), 1 (a > b).
|
|
185
|
+
*/
|
|
186
|
+
function compareSemver(a, b) {
|
|
187
|
+
for (let i = 0; i < 3; i++) {
|
|
188
|
+
if (a[i] < b[i]) return -1;
|
|
189
|
+
if (a[i] > b[i]) return 1;
|
|
190
|
+
}
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Discover codemod files in bin/codemods/ and return those whose version
|
|
196
|
+
* is > currentVer and <= targetVer, sorted ascending.
|
|
197
|
+
*/
|
|
198
|
+
function discoverCodemods(currentVer, targetVer) {
|
|
199
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
200
|
+
const __dirname = dirname(__filename);
|
|
201
|
+
const codemodsDir = join(__dirname, "codemods");
|
|
202
|
+
|
|
203
|
+
if (!existsSync(codemodsDir)) return [];
|
|
204
|
+
|
|
205
|
+
const files = readdirSync(codemodsDir).filter((f) => /^v[\d.]+\.mjs$/.test(f));
|
|
206
|
+
const candidates = [];
|
|
207
|
+
|
|
208
|
+
for (const file of files) {
|
|
209
|
+
const ver = parseSemver(file);
|
|
210
|
+
if (!ver) continue;
|
|
211
|
+
// Include codemods where: currentVer < codemodVer <= targetVer
|
|
212
|
+
if (compareSemver(ver, currentVer) > 0 && compareSemver(ver, targetVer) <= 0) {
|
|
213
|
+
candidates.push({ file, ver, path: join(codemodsDir, file) });
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Sort ascending by version
|
|
218
|
+
candidates.sort((a, b) => compareSemver(a.ver, b.ver));
|
|
219
|
+
return candidates;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async function cmdUpgrade(cwd) {
|
|
174
223
|
log("Checking for updates...\n");
|
|
175
224
|
const pkgPath = join(cwd, "package.json");
|
|
176
225
|
|
|
@@ -180,19 +229,51 @@ function cmdUpgrade(cwd) {
|
|
|
180
229
|
}
|
|
181
230
|
|
|
182
231
|
try {
|
|
183
|
-
const
|
|
232
|
+
const latest = execSync("npm view @middag-io/react version 2>/dev/null", { encoding: "utf8" }).trim();
|
|
184
233
|
const currentPkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
185
|
-
const
|
|
234
|
+
const currentRaw = currentPkg.dependencies?.["@middag-io/react"] || "unknown";
|
|
235
|
+
|
|
236
|
+
console.log(` Current: ${currentRaw}`);
|
|
237
|
+
console.log(` Latest: ${latest}`);
|
|
186
238
|
|
|
187
|
-
|
|
188
|
-
|
|
239
|
+
const currentVer = parseSemver(currentRaw);
|
|
240
|
+
const targetVer = parseSemver(latest);
|
|
189
241
|
|
|
190
|
-
if (
|
|
242
|
+
if (currentRaw.includes(latest)) {
|
|
191
243
|
success("Already up to date");
|
|
192
244
|
} else {
|
|
193
245
|
log("Updating...");
|
|
194
246
|
run("npm install @middag-io/react@latest", { cwd });
|
|
195
|
-
success(`Updated to ${
|
|
247
|
+
success(`Updated to ${latest}`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ── Codemods ────────────────────────────────────────────────────────
|
|
251
|
+
if (currentVer && targetVer && compareSemver(currentVer, targetVer) < 0) {
|
|
252
|
+
const codemods = discoverCodemods(currentVer, targetVer);
|
|
253
|
+
|
|
254
|
+
if (codemods.length > 0) {
|
|
255
|
+
console.log("");
|
|
256
|
+
log(`Running ${codemods.length} codemod(s)...\n`);
|
|
257
|
+
|
|
258
|
+
let applied = 0;
|
|
259
|
+
for (const cm of codemods) {
|
|
260
|
+
const mod = await import(cm.path);
|
|
261
|
+
const desc = mod.description || cm.file;
|
|
262
|
+
console.log(` \x1b[36m▸\x1b[0m ${cm.file}: ${desc}`);
|
|
263
|
+
try {
|
|
264
|
+
await mod.default(cwd);
|
|
265
|
+
applied++;
|
|
266
|
+
} catch (err) {
|
|
267
|
+
fail(`Codemod ${cm.file} failed: ${err.message}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
console.log("");
|
|
272
|
+
success(`${applied}/${codemods.length} codemod(s) applied`);
|
|
273
|
+
} else {
|
|
274
|
+
console.log("");
|
|
275
|
+
success("No codemods needed for this upgrade");
|
|
276
|
+
}
|
|
196
277
|
}
|
|
197
278
|
} catch {
|
|
198
279
|
warn("Could not check latest version (network or auth issue)");
|
|
@@ -222,7 +303,7 @@ switch (command) {
|
|
|
222
303
|
cmdAddBlock(cwd, args[0]);
|
|
223
304
|
break;
|
|
224
305
|
case "upgrade":
|
|
225
|
-
cmdUpgrade(cwd);
|
|
306
|
+
await cmdUpgrade(cwd);
|
|
226
307
|
break;
|
|
227
308
|
default:
|
|
228
309
|
console.log(`
|
|
@@ -1,83 +1,86 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as e } from "./i18n-zhMby9Ml.js";
|
|
2
|
+
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
2
3
|
//#region src/base/blocks/ConditionTreeBlock.tsx
|
|
3
|
-
function
|
|
4
|
-
return /* @__PURE__ */
|
|
5
|
-
className:
|
|
6
|
-
children:
|
|
4
|
+
function r({ logic: e }) {
|
|
5
|
+
return /* @__PURE__ */ t("span", {
|
|
6
|
+
className: e === "and" ? "text-primary inline-flex items-center rounded bg-[oklch(0.93_0.04_264)] px-2 py-0.5 text-xs font-bold uppercase" : "inline-flex items-center rounded bg-[oklch(0.95_0.04_75)] px-2 py-0.5 text-xs font-bold text-[oklch(0.55_0.16_75)] uppercase",
|
|
7
|
+
children: e
|
|
7
8
|
});
|
|
8
9
|
}
|
|
9
|
-
function
|
|
10
|
-
|
|
10
|
+
function i({ rule: r }) {
|
|
11
|
+
let { t: i } = e();
|
|
12
|
+
return /* @__PURE__ */ n("div", {
|
|
11
13
|
className: "bg-background flex items-center gap-2 rounded-md p-2",
|
|
12
14
|
children: [
|
|
13
|
-
/* @__PURE__ */
|
|
15
|
+
/* @__PURE__ */ t("span", {
|
|
14
16
|
className: "border-border bg-muted/50 inline-flex items-center rounded border px-2 py-1 text-sm font-medium",
|
|
15
|
-
children:
|
|
17
|
+
children: r.field
|
|
16
18
|
}),
|
|
17
|
-
/* @__PURE__ */
|
|
19
|
+
/* @__PURE__ */ t("span", {
|
|
18
20
|
className: "text-muted-foreground text-sm",
|
|
19
|
-
children:
|
|
21
|
+
children: r.operator
|
|
20
22
|
}),
|
|
21
|
-
/* @__PURE__ */
|
|
23
|
+
/* @__PURE__ */ t("span", {
|
|
22
24
|
className: "border-border bg-muted/50 inline-flex items-center rounded border px-2 py-1 text-sm font-medium",
|
|
23
|
-
children:
|
|
25
|
+
children: r.value
|
|
24
26
|
}),
|
|
25
|
-
/* @__PURE__ */
|
|
27
|
+
/* @__PURE__ */ t("button", {
|
|
26
28
|
type: "button",
|
|
27
29
|
className: "text-muted-foreground hover:text-destructive ml-auto flex h-6 w-6 items-center justify-center rounded text-sm transition-colors",
|
|
28
30
|
tabIndex: -1,
|
|
29
|
-
"aria-label": "
|
|
31
|
+
"aria-label": i("middag.ui.condition_tree.remove_rule"),
|
|
30
32
|
children: "×"
|
|
31
33
|
})
|
|
32
34
|
]
|
|
33
35
|
});
|
|
34
36
|
}
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
+
function a({ group: o, depth: s }) {
|
|
38
|
+
let { t: c } = e();
|
|
39
|
+
return /* @__PURE__ */ n("div", {
|
|
37
40
|
className: "bg-muted/30 space-y-2 rounded-lg border p-3",
|
|
38
|
-
style:
|
|
41
|
+
style: s > 0 ? { marginLeft: `${s * 16}px` } : void 0,
|
|
39
42
|
children: [
|
|
40
|
-
/* @__PURE__ */
|
|
43
|
+
/* @__PURE__ */ n("div", {
|
|
41
44
|
className: "flex items-center gap-2",
|
|
42
|
-
children: [/* @__PURE__ */
|
|
45
|
+
children: [/* @__PURE__ */ t(r, { logic: o.logic }), s > 0 && /* @__PURE__ */ t("button", {
|
|
43
46
|
type: "button",
|
|
44
47
|
className: "text-muted-foreground hover:text-destructive ml-auto flex h-6 w-6 items-center justify-center rounded text-sm transition-colors",
|
|
45
48
|
tabIndex: -1,
|
|
46
|
-
"aria-label": "
|
|
49
|
+
"aria-label": c("middag.ui.condition_tree.remove_group"),
|
|
47
50
|
children: "×"
|
|
48
51
|
})]
|
|
49
52
|
}),
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
group:
|
|
53
|
-
depth:
|
|
54
|
-
},
|
|
55
|
-
/* @__PURE__ */
|
|
53
|
+
o.rules.map((e) => /* @__PURE__ */ t(i, { rule: e }, e.id)),
|
|
54
|
+
o.groups.map((e) => /* @__PURE__ */ t(a, {
|
|
55
|
+
group: e,
|
|
56
|
+
depth: s + 1
|
|
57
|
+
}, e.id)),
|
|
58
|
+
/* @__PURE__ */ n("div", {
|
|
56
59
|
className: "flex items-center gap-2 pt-1",
|
|
57
|
-
children: [/* @__PURE__ */
|
|
60
|
+
children: [/* @__PURE__ */ t("button", {
|
|
58
61
|
type: "button",
|
|
59
62
|
className: "text-muted-foreground hover:border-primary hover:text-primary rounded-md border border-dashed px-3 py-1 text-xs transition-colors",
|
|
60
63
|
tabIndex: -1,
|
|
61
|
-
children: "
|
|
62
|
-
}), /* @__PURE__ */
|
|
64
|
+
children: c("middag.ui.condition_tree.add_rule")
|
|
65
|
+
}), /* @__PURE__ */ t("button", {
|
|
63
66
|
type: "button",
|
|
64
67
|
className: "text-muted-foreground hover:border-primary hover:text-primary rounded-md border border-dashed px-3 py-1 text-xs transition-colors",
|
|
65
68
|
tabIndex: -1,
|
|
66
|
-
children: "
|
|
69
|
+
children: c("middag.ui.condition_tree.add_group")
|
|
67
70
|
})]
|
|
68
71
|
})
|
|
69
72
|
]
|
|
70
73
|
});
|
|
71
74
|
}
|
|
72
|
-
function
|
|
73
|
-
let { data: n } =
|
|
74
|
-
return /* @__PURE__ */
|
|
75
|
+
function o({ block: e }) {
|
|
76
|
+
let { data: n } = e;
|
|
77
|
+
return /* @__PURE__ */ t("div", {
|
|
75
78
|
className: "space-y-3",
|
|
76
|
-
children: /* @__PURE__ */
|
|
79
|
+
children: /* @__PURE__ */ t(a, {
|
|
77
80
|
group: n.root,
|
|
78
81
|
depth: 0
|
|
79
82
|
})
|
|
80
83
|
});
|
|
81
84
|
}
|
|
82
85
|
//#endregion
|
|
83
|
-
export {
|
|
86
|
+
export { o as ConditionTreeBlock };
|