@process.co/ui 0.0.9 → 0.0.10
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 -284
- package/css/ui.css +0 -7
- package/dist/components/fields/index.cjs +130 -0
- package/dist/components/fields/index.cjs.map +1 -1
- package/dist/components/fields/index.d.cts +1 -1
- package/dist/components/fields/index.d.ts +1 -1
- package/dist/components/fields/index.js +126 -1
- package/dist/components/fields/index.js.map +1 -1
- package/dist/{index-nu_JyZnb.d.cts → index-DGN9LJqq.d.cts} +149 -2
- package/dist/{index-nu_JyZnb.d.ts → index-DGN9LJqq.d.ts} +149 -2
- package/dist/index.cjs +140 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +140 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @process.co/ui
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Installation](#installation)
|
|
8
|
-
- [Usage](#usage)
|
|
9
|
-
- [Components](#components)
|
|
10
|
-
- [Basic Components](#basic-components)
|
|
11
|
-
- [Form Components](#form-components)
|
|
12
|
-
- [Layout Components](#layout-components)
|
|
13
|
-
- [Feedback Components](#feedback-components)
|
|
14
|
-
- [Navigation Components](#navigation-components)
|
|
15
|
-
- [Blocks](#blocks)
|
|
16
|
-
- [Providers](#providers)
|
|
17
|
-
- [Storybook](#storybook)
|
|
3
|
+
A React UI component library for Process.co applications with built-in collaborative editing, type inference, and expression support.
|
|
18
4
|
|
|
19
5
|
## Installation
|
|
20
6
|
|
|
@@ -22,393 +8,472 @@ This package contains a collection of reusable UI components for the proc-app pr
|
|
|
22
8
|
npm install @process.co/ui
|
|
23
9
|
```
|
|
24
10
|
|
|
25
|
-
Or with pnpm:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
pnpm add @process.co/ui
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Usage
|
|
32
|
-
|
|
33
|
-
### Importing Components
|
|
34
|
-
|
|
35
|
-
```tsx
|
|
36
|
-
import { Button, Card, Alert } from '@process.co/ui';
|
|
37
|
-
import { UIProvider } from '@process.co/ui';
|
|
38
|
-
```
|
|
39
|
-
|
|
40
11
|
### Importing Styles
|
|
41
12
|
|
|
42
|
-
The library includes pre-built CSS that must be imported in your application:
|
|
43
|
-
|
|
44
13
|
```tsx
|
|
45
|
-
// In your main app file or layout
|
|
46
14
|
import '@process.co/ui/styles';
|
|
47
15
|
```
|
|
48
16
|
|
|
49
|
-
|
|
17
|
+
---
|
|
50
18
|
|
|
51
|
-
|
|
52
|
-
@import '@process.co/ui/styles';
|
|
53
|
-
```
|
|
19
|
+
## Field Components
|
|
54
20
|
|
|
55
|
-
|
|
21
|
+
The `Input` and `Select` components are collaborative-aware form controls designed for building custom UIs that integrate with Process.co's flow editor.
|
|
22
|
+
|
|
23
|
+
### Quick Start
|
|
56
24
|
|
|
57
25
|
```tsx
|
|
58
|
-
import {
|
|
59
|
-
import { UIProvider } from '@process.co/ui';
|
|
26
|
+
import { Input, Select, useNodeProperty } from '@process.co/ui/fields';
|
|
60
27
|
import '@process.co/ui/styles';
|
|
61
28
|
|
|
62
|
-
|
|
63
|
-
|
|
29
|
+
function MyCustomControl({ fieldName }) {
|
|
30
|
+
const [value, setValue] = useNodeProperty(fieldName);
|
|
31
|
+
|
|
64
32
|
return (
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
33
|
+
<Input
|
|
34
|
+
fieldName="expression"
|
|
35
|
+
label="Expression"
|
|
36
|
+
expectedType="string"
|
|
37
|
+
value={value}
|
|
38
|
+
onChange={setValue}
|
|
39
|
+
/>
|
|
68
40
|
);
|
|
69
41
|
}
|
|
70
42
|
```
|
|
71
43
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
### Basic Components
|
|
44
|
+
---
|
|
75
45
|
|
|
76
|
-
|
|
77
|
-
A customizable button component with multiple variants and sizes.
|
|
46
|
+
## Input Component
|
|
78
47
|
|
|
79
|
-
|
|
80
|
-
import { Button } from '@repo/ui';
|
|
48
|
+
A text input with expression support, type inference, and real-time collaboration.
|
|
81
49
|
|
|
82
|
-
|
|
83
|
-
Click me
|
|
84
|
-
</Button>
|
|
85
|
-
```
|
|
50
|
+
### Props
|
|
86
51
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
52
|
+
| Prop | Type | Description |
|
|
53
|
+
|------|------|-------------|
|
|
54
|
+
| `fieldName` | `string` | Unique identifier for collaborative sync |
|
|
55
|
+
| `label` | `string` | Display label |
|
|
56
|
+
| `value` | `any` | Current value |
|
|
57
|
+
| `onChange` | `(value: any) => void` | Change handler |
|
|
58
|
+
| `expectedType` | `string` | Expected type for validation (see Type Inference) |
|
|
59
|
+
| `placeholder` | `string` | Placeholder text |
|
|
93
60
|
|
|
94
|
-
|
|
95
|
-
A clickable card component that links to external resources.
|
|
61
|
+
### Example
|
|
96
62
|
|
|
97
63
|
```tsx
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
</Card>
|
|
64
|
+
<Input
|
|
65
|
+
fieldName="userEmail"
|
|
66
|
+
label="Email Address"
|
|
67
|
+
expectedType="string"
|
|
68
|
+
value={email}
|
|
69
|
+
onChange={setEmail}
|
|
70
|
+
placeholder="user@example.com"
|
|
71
|
+
/>
|
|
107
72
|
```
|
|
108
73
|
|
|
109
|
-
|
|
110
|
-
- `title`: string (required)
|
|
111
|
-
- `href`: string (required)
|
|
112
|
-
- `className`: string (optional)
|
|
113
|
-
- `children`: React.ReactNode
|
|
74
|
+
---
|
|
114
75
|
|
|
115
|
-
|
|
116
|
-
A simple inline code component for displaying code snippets.
|
|
76
|
+
## Select Component
|
|
117
77
|
|
|
118
|
-
|
|
119
|
-
import { Code } from '@repo/ui';
|
|
78
|
+
A dropdown select with expression support and type-aware options.
|
|
120
79
|
|
|
121
|
-
|
|
122
|
-
```
|
|
80
|
+
### Props
|
|
123
81
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
82
|
+
| Prop | Type | Description |
|
|
83
|
+
|------|------|-------------|
|
|
84
|
+
| `fieldName` | `string` | Unique identifier for collaborative sync |
|
|
85
|
+
| `label` | `string` | Display label |
|
|
86
|
+
| `value` | `any` | Current selected value |
|
|
87
|
+
| `onChange` | `(value: any) => void` | Change handler |
|
|
88
|
+
| `options` | `SelectOption[]` | Available options |
|
|
89
|
+
| `expectedType` | `string` | Expected type for validation |
|
|
127
90
|
|
|
128
|
-
|
|
129
|
-
A header component with navigation and branding.
|
|
91
|
+
### SelectOption Type
|
|
130
92
|
|
|
131
93
|
```tsx
|
|
132
|
-
|
|
94
|
+
type SelectOption = {
|
|
95
|
+
value: string;
|
|
96
|
+
label: string;
|
|
97
|
+
node?: ReactNode; // Custom render
|
|
98
|
+
};
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Example
|
|
133
102
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
103
|
+
```tsx
|
|
104
|
+
<Select
|
|
105
|
+
fieldName="operator"
|
|
106
|
+
label="Operation"
|
|
107
|
+
value={operator}
|
|
108
|
+
onChange={setOperator}
|
|
109
|
+
options={[
|
|
110
|
+
{ value: 'equals', label: 'Equals' },
|
|
111
|
+
{ value: 'contains', label: 'Contains' },
|
|
112
|
+
{ value: 'startsWith', label: 'Starts With' },
|
|
113
|
+
]}
|
|
138
114
|
/>
|
|
139
115
|
```
|
|
140
116
|
|
|
141
|
-
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Type Inference System
|
|
120
|
+
|
|
121
|
+
The `$infer<...>` syntax enables automatic type inference and propagation between fields.
|
|
122
|
+
|
|
123
|
+
### How It Works
|
|
124
|
+
|
|
125
|
+
When a field uses `$infer` or `$infer<allowedTypes>` as its `expectedType`:
|
|
126
|
+
|
|
127
|
+
1. The field **infers** the type of the user's input
|
|
128
|
+
2. The field **publishes** that inferred type under its `fieldName`
|
|
129
|
+
3. Other fields can **subscribe** to that type using `$infer<[fieldName]>`
|
|
130
|
+
|
|
131
|
+
### Publishing Types (Automatic)
|
|
142
132
|
|
|
143
|
-
|
|
144
|
-
A text input component with built-in validation and error handling.
|
|
133
|
+
Any field with `$infer` syntax automatically publishes its inferred type:
|
|
145
134
|
|
|
146
135
|
```tsx
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
name="email"
|
|
152
|
-
type="email"
|
|
153
|
-
placeholder="Enter your email"
|
|
154
|
-
error={errors.email}
|
|
155
|
-
onChange={handleChange}
|
|
136
|
+
// This field publishes its inferred type as "switchExpression"
|
|
137
|
+
<Input
|
|
138
|
+
fieldName="switchExpression"
|
|
139
|
+
expectedType="$infer<string | number | boolean>"
|
|
156
140
|
/>
|
|
157
141
|
```
|
|
158
142
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
- `placeholder`: string
|
|
164
|
-
- `error`: string
|
|
165
|
-
- `required`: boolean
|
|
166
|
-
- Standard input HTML attributes
|
|
143
|
+
The field will:
|
|
144
|
+
1. Accept string, number, or boolean values
|
|
145
|
+
2. Infer the actual type from user input (e.g., if user types `"hello"`, infers `string`)
|
|
146
|
+
3. **Publish** the inferred type so other fields can access it via `fieldName`
|
|
167
147
|
|
|
168
|
-
|
|
169
|
-
A password input with strength meter visualization.
|
|
148
|
+
You can also use just `$infer` without constraints:
|
|
170
149
|
|
|
171
150
|
```tsx
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
onChange={setPassword}
|
|
177
|
-
requirements={{
|
|
178
|
-
minLength: 8,
|
|
179
|
-
requireUppercase: true,
|
|
180
|
-
requireNumbers: true,
|
|
181
|
-
requireSpecialChars: true
|
|
182
|
-
}}
|
|
151
|
+
// Publishes inferred type with no restrictions on allowed types
|
|
152
|
+
<Input
|
|
153
|
+
fieldName="myExpression"
|
|
154
|
+
expectedType="$infer"
|
|
183
155
|
/>
|
|
184
156
|
```
|
|
185
157
|
|
|
186
|
-
|
|
187
|
-
- `password`: string
|
|
188
|
-
- `onChange`: (value: string) => void
|
|
189
|
-
- `requirements`: PasswordRequirements object
|
|
190
|
-
|
|
191
|
-
### Layout Components
|
|
192
|
-
|
|
193
|
-
#### NotFound (404)
|
|
194
|
-
A pre-styled 404 error page layout.
|
|
158
|
+
Or with a single known type:
|
|
195
159
|
|
|
196
160
|
```tsx
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
161
|
+
// Publishes "string" as the inferred type for this field
|
|
162
|
+
<Input
|
|
163
|
+
fieldName="stringField"
|
|
164
|
+
expectedType="$infer<string>"
|
|
165
|
+
/>
|
|
200
166
|
```
|
|
201
167
|
|
|
202
|
-
|
|
168
|
+
### Subscribing to Types
|
|
203
169
|
|
|
204
|
-
|
|
205
|
-
A collapsible sidebar navigation component.
|
|
170
|
+
A field can **subscribe** to another field's published type:
|
|
206
171
|
|
|
207
172
|
```tsx
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
collapsed={isCollapsed}
|
|
213
|
-
onToggle={handleToggle}
|
|
173
|
+
// This field receives its expected type from "switchExpression"
|
|
174
|
+
<Input
|
|
175
|
+
fieldName="caseValue"
|
|
176
|
+
expectedType="$infer<[switchExpression]>"
|
|
214
177
|
/>
|
|
215
178
|
```
|
|
216
179
|
|
|
217
|
-
|
|
180
|
+
This field will:
|
|
181
|
+
1. Look up the inferred type published by `switchExpression`
|
|
182
|
+
2. Use that type for validation and autocomplete
|
|
183
|
+
3. Update automatically when the source field's type changes
|
|
218
184
|
|
|
219
|
-
|
|
220
|
-
A dismissible alert component for displaying messages.
|
|
185
|
+
### Multi-Field Subscription
|
|
221
186
|
|
|
222
|
-
|
|
223
|
-
import { Alert } from '@repo/ui';
|
|
187
|
+
Subscribe to multiple fields - types are intersected:
|
|
224
188
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
189
|
+
```tsx
|
|
190
|
+
<Input
|
|
191
|
+
fieldName="value"
|
|
192
|
+
expectedType='$infer<["statementField", "operatorField"]>'
|
|
229
193
|
/>
|
|
230
194
|
```
|
|
231
195
|
|
|
232
|
-
|
|
233
|
-
- `type`: 'success' | 'error' | 'warning' | 'info'
|
|
234
|
-
- `message`: string
|
|
235
|
-
- `onClose`: () => void (optional)
|
|
196
|
+
The expected type is computed by intersecting types from both fields.
|
|
236
197
|
|
|
237
|
-
|
|
238
|
-
An animated loading indicator.
|
|
198
|
+
### Example Flow
|
|
239
199
|
|
|
240
200
|
```tsx
|
|
241
|
-
|
|
201
|
+
// 1. Statement field publishes its inferred type
|
|
202
|
+
<Input
|
|
203
|
+
fieldName="statement"
|
|
204
|
+
expectedType="$infer<string | number | boolean>"
|
|
205
|
+
// User enters: this.user.age
|
|
206
|
+
// Infers and publishes: "number"
|
|
207
|
+
/>
|
|
242
208
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
209
|
+
// 2. Operator dropdown reads the published type to filter options
|
|
210
|
+
const ctx = useInferredTypes();
|
|
211
|
+
const statementType = ctx?.getInferredType('statement'); // "number"
|
|
212
|
+
const operators = statementType === 'number'
|
|
213
|
+
? ['=', '!=', '<', '>', '<=', '>=']
|
|
214
|
+
: ['=', '!='];
|
|
215
|
+
|
|
216
|
+
// 3. Value field subscribes to the statement's type
|
|
217
|
+
<Input
|
|
218
|
+
fieldName="value"
|
|
219
|
+
expectedType="$infer<[statement]>"
|
|
220
|
+
// Expects: "number" (from statement field)
|
|
247
221
|
/>
|
|
248
222
|
```
|
|
249
223
|
|
|
250
|
-
|
|
251
|
-
A full-screen loading component with animation, wrapped in React Query provider.
|
|
224
|
+
---
|
|
252
225
|
|
|
253
|
-
|
|
254
|
-
import { SuspenseLoader } from '@repo/ui';
|
|
226
|
+
## useInferredTypes Hook
|
|
255
227
|
|
|
256
|
-
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
#### FullScreenLoader
|
|
260
|
-
A centered full-screen loading overlay.
|
|
228
|
+
Access inferred types programmatically for building type-aware UIs:
|
|
261
229
|
|
|
262
230
|
```tsx
|
|
263
|
-
import {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
231
|
+
import { useInferredTypes } from '@process.co/ui/fields';
|
|
232
|
+
|
|
233
|
+
function OperatorSelect() {
|
|
234
|
+
const ctx = useInferredTypes();
|
|
235
|
+
|
|
236
|
+
// Read the published type from another field
|
|
237
|
+
const expressionType = ctx?.getInferredType('switchExpression') || 'any';
|
|
238
|
+
|
|
239
|
+
// Manually publish a type (e.g., for operator narrowing)
|
|
240
|
+
ctx?.setInferredType('operatorNarrow', 'string');
|
|
241
|
+
|
|
242
|
+
// Filter operators based on type
|
|
243
|
+
const operators = expressionType === 'number'
|
|
244
|
+
? ['=', '!=', '<', '>', '<=', '>=']
|
|
245
|
+
: expressionType === 'string'
|
|
246
|
+
? ['=', '!=', 'contains', 'startsWith', 'endsWith']
|
|
247
|
+
: ['=', '!='];
|
|
248
|
+
|
|
249
|
+
return (
|
|
250
|
+
<Select options={operators.map(op => ({ value: op, label: op }))} />
|
|
251
|
+
);
|
|
252
|
+
}
|
|
269
253
|
```
|
|
270
254
|
|
|
271
|
-
|
|
272
|
-
A simple tooltip component for hover information.
|
|
255
|
+
### Context Methods
|
|
273
256
|
|
|
274
|
-
|
|
275
|
-
|
|
257
|
+
| Method | Description |
|
|
258
|
+
|--------|-------------|
|
|
259
|
+
| `getInferredType(fieldName)` | Get the published type for a field |
|
|
260
|
+
| `setInferredType(fieldName, type)` | Manually publish a type for a field |
|
|
261
|
+
| `inferredTypes` | Record of all fieldName → type mappings |
|
|
276
262
|
|
|
277
|
-
|
|
278
|
-
<Button>Hover me</Button>
|
|
279
|
-
</Tooltip>
|
|
280
|
-
```
|
|
263
|
+
---
|
|
281
264
|
|
|
282
|
-
|
|
265
|
+
## useNodeProperty Hook
|
|
283
266
|
|
|
284
|
-
|
|
285
|
-
A portal component for setting navigation breadcrumbs and content.
|
|
267
|
+
Subscribe to and update node properties with automatic collaboration sync:
|
|
286
268
|
|
|
287
269
|
```tsx
|
|
288
|
-
import
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
>
|
|
298
|
-
|
|
299
|
-
</
|
|
270
|
+
import { useNodeProperty } from '@process.co/ui/fields';
|
|
271
|
+
|
|
272
|
+
function MyControl({ fieldName }) {
|
|
273
|
+
const [value, setValue] = useNodeProperty<MyValueType>(fieldName);
|
|
274
|
+
|
|
275
|
+
// value: Current property value (undefined if not set)
|
|
276
|
+
// setValue: Update function with automatic sync
|
|
277
|
+
|
|
278
|
+
return (
|
|
279
|
+
<button onClick={() => setValue({ ...value, enabled: true })}>
|
|
280
|
+
Enable
|
|
281
|
+
</button>
|
|
282
|
+
);
|
|
283
|
+
}
|
|
300
284
|
```
|
|
301
285
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
- `keys`: unknown[] (for memoization)
|
|
306
|
-
- `children`: React.ReactNode (navigation content)
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Building Custom Controls
|
|
307
289
|
|
|
308
|
-
|
|
290
|
+
Custom controls integrate with Process.co's collaborative editing system through the `useNodeProperty` hook.
|
|
309
291
|
|
|
310
|
-
|
|
311
|
-
A component displaying a tree of navigation links.
|
|
292
|
+
### Basic Pattern
|
|
312
293
|
|
|
313
294
|
```tsx
|
|
314
|
-
import {
|
|
295
|
+
import { useNodeProperty, useInferredTypes } from '@process.co/ui/fields';
|
|
315
296
|
|
|
316
|
-
|
|
297
|
+
interface MyControlProps {
|
|
298
|
+
fieldName: string;
|
|
299
|
+
readonly?: boolean;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export default function MyControl({ fieldName, readonly = false }: MyControlProps) {
|
|
303
|
+
// Subscribe to the property value
|
|
304
|
+
const [value, setValue] = useNodeProperty<MyValueType>(fieldName);
|
|
305
|
+
|
|
306
|
+
// Access type inference context (optional)
|
|
307
|
+
const ctx = useInferredTypes();
|
|
308
|
+
|
|
309
|
+
// Derive state from value
|
|
310
|
+
const items = value?.items ?? [];
|
|
311
|
+
|
|
312
|
+
// Update handler
|
|
313
|
+
const addItem = () => {
|
|
314
|
+
setValue({
|
|
315
|
+
...value,
|
|
316
|
+
items: [...items, { id: generateId(), name: '' }]
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
return (
|
|
321
|
+
<div>
|
|
322
|
+
{items.map(item => (
|
|
323
|
+
<ItemRow key={item.id} item={item} />
|
|
324
|
+
))}
|
|
325
|
+
{!readonly && <button onClick={addItem}>Add Item</button>}
|
|
326
|
+
</div>
|
|
327
|
+
);
|
|
328
|
+
}
|
|
317
329
|
```
|
|
318
330
|
|
|
319
|
-
|
|
320
|
-
A copyright notice component with customizable text.
|
|
331
|
+
### With Type Inference
|
|
321
332
|
|
|
322
333
|
```tsx
|
|
323
|
-
import {
|
|
324
|
-
|
|
325
|
-
|
|
334
|
+
import {
|
|
335
|
+
useNodeProperty,
|
|
336
|
+
useInferredTypes,
|
|
337
|
+
Input,
|
|
338
|
+
Select,
|
|
339
|
+
} from '@process.co/ui/fields';
|
|
340
|
+
|
|
341
|
+
export default function ConditionalEditor({ fieldName }) {
|
|
342
|
+
const [value, setValue] = useNodeProperty(fieldName);
|
|
343
|
+
const ctx = useInferredTypes();
|
|
344
|
+
|
|
345
|
+
// Get inferred type from statement field (it publishes automatically)
|
|
346
|
+
const statementType = ctx?.getInferredType(`${fieldName}_statement`) || 'any';
|
|
347
|
+
|
|
348
|
+
// Filter operators based on statement type
|
|
349
|
+
const operators = getOperatorsForType(statementType);
|
|
350
|
+
|
|
351
|
+
return (
|
|
352
|
+
<div>
|
|
353
|
+
{/* This field PUBLISHES its inferred type as "${fieldName}_statement" */}
|
|
354
|
+
<Input
|
|
355
|
+
fieldName={`${fieldName}_statement`}
|
|
356
|
+
label="Statement"
|
|
357
|
+
expectedType="$infer<string | number | boolean>"
|
|
358
|
+
value={value?.statement}
|
|
359
|
+
onChange={(v) => setValue({ ...value, statement: v })}
|
|
360
|
+
/>
|
|
361
|
+
|
|
362
|
+
<Select
|
|
363
|
+
fieldName={`${fieldName}_operator`}
|
|
364
|
+
label="Operator"
|
|
365
|
+
options={operators}
|
|
366
|
+
value={value?.operator}
|
|
367
|
+
onChange={(v) => setValue({ ...value, operator: v })}
|
|
368
|
+
/>
|
|
369
|
+
|
|
370
|
+
{/* This field SUBSCRIBES to the statement field's type */}
|
|
371
|
+
<Input
|
|
372
|
+
fieldName={`${fieldName}_value`}
|
|
373
|
+
label="Value"
|
|
374
|
+
expectedType={`$infer<[${fieldName}_statement]>`}
|
|
375
|
+
value={value?.value}
|
|
376
|
+
onChange={(v) => setValue({ ...value, value: v })}
|
|
377
|
+
/>
|
|
378
|
+
</div>
|
|
379
|
+
);
|
|
380
|
+
}
|
|
326
381
|
```
|
|
327
382
|
|
|
328
|
-
|
|
383
|
+
---
|
|
329
384
|
|
|
330
|
-
|
|
331
|
-
A component for social authentication providers.
|
|
332
|
-
|
|
333
|
-
```tsx
|
|
334
|
-
import { SocialLogin } from '@repo/ui';
|
|
335
|
-
|
|
336
|
-
<SocialLogin
|
|
337
|
-
providers={['google', 'github', 'microsoft']}
|
|
338
|
-
onLogin={handleSocialLogin}
|
|
339
|
-
/>
|
|
340
|
-
```
|
|
385
|
+
## Operator Utilities
|
|
341
386
|
|
|
342
|
-
|
|
387
|
+
Shared utilities for building query builders with type-aware operators.
|
|
343
388
|
|
|
344
|
-
|
|
345
|
-
The main provider component that wraps your application and provides context for translations, settings, and state management.
|
|
389
|
+
### Types
|
|
346
390
|
|
|
347
391
|
```tsx
|
|
348
|
-
import {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
392
|
+
import {
|
|
393
|
+
BaseOperatorType,
|
|
394
|
+
OperatorDef,
|
|
395
|
+
ParsedTypes,
|
|
396
|
+
} from '@process.co/ui/fields';
|
|
397
|
+
|
|
398
|
+
// BaseOperatorType includes: 'exists', 'not_exists', 'string_equals',
|
|
399
|
+
// 'string_contains', 'number_gt', 'boolean_equals', etc.
|
|
400
|
+
|
|
401
|
+
// OperatorDef<T> is generic - extend with custom operators
|
|
402
|
+
type MyOperator = 'expression' | 'custom_check';
|
|
403
|
+
const operators: OperatorDef<MyOperator>[] = [...];
|
|
357
404
|
```
|
|
358
405
|
|
|
359
|
-
|
|
360
|
-
- `useSettings`: Hook to access UI settings
|
|
361
|
-
- `useTranslation`: Hook for translations
|
|
362
|
-
- `KeyValueStore`: Type definition for storage
|
|
363
|
-
- `StorageType`: Enum for storage types
|
|
364
|
-
|
|
365
|
-
## Utility Functions
|
|
366
|
-
|
|
367
|
-
The package also exports utility functions from `lib/utils`:
|
|
406
|
+
### Functions
|
|
368
407
|
|
|
369
408
|
```tsx
|
|
370
|
-
import {
|
|
409
|
+
import {
|
|
410
|
+
parseInferredTypes,
|
|
411
|
+
computeExtendedType,
|
|
412
|
+
filterOperatorsByType,
|
|
413
|
+
getStringConstants,
|
|
414
|
+
getNumberConstants,
|
|
415
|
+
} from '@process.co/ui/fields';
|
|
416
|
+
|
|
417
|
+
// Parse type string into components
|
|
418
|
+
const parsed = parseInferredTypes('"adam" | "beth" | number');
|
|
419
|
+
// { baseTypes: ['string', 'number'], stringConstants: ['adam', 'beth'], ... }
|
|
420
|
+
|
|
421
|
+
// Filter operators by compatible type
|
|
422
|
+
const ops = filterOperatorsByType(OPERATORS, '"adam" | "beth"');
|
|
423
|
+
// Returns operators with types: ['any'] or ['string']
|
|
424
|
+
|
|
425
|
+
// Compute extended type for operators with extendsWithBase
|
|
426
|
+
const expectedType = computeExtendedType('"adam" | "beth"', operatorDef);
|
|
427
|
+
// If extendsWithBase: true, returns '"adam" | "beth" | string'
|
|
371
428
|
```
|
|
372
429
|
|
|
373
|
-
|
|
430
|
+
### Extended Type Narrowing
|
|
374
431
|
|
|
375
|
-
|
|
432
|
+
Some operators support `extendsWithBase` for flexible type matching:
|
|
376
433
|
|
|
377
|
-
```
|
|
378
|
-
|
|
434
|
+
```tsx
|
|
435
|
+
const OPERATORS: OperatorDef[] = [
|
|
436
|
+
// Exact match - only accepts the literal values
|
|
437
|
+
{ value: 'string_equals', narrowsTo: 'string', extendsWithBase: false },
|
|
438
|
+
|
|
439
|
+
// Extended match - accepts literals OR any string
|
|
440
|
+
{ value: 'string_starts_with', narrowsTo: 'string', extendsWithBase: true },
|
|
441
|
+
];
|
|
379
442
|
```
|
|
380
443
|
|
|
381
|
-
|
|
444
|
+
**Example:** If statement infers `"adam" | "beth"`:
|
|
445
|
+
- `string_equals` expects: `"adam" | "beth"` (must match exactly)
|
|
446
|
+
- `string_starts_with` expects: `"adam" | "beth" | string` (can provide partial match like `"a"`)
|
|
382
447
|
|
|
383
|
-
|
|
448
|
+
---
|
|
384
449
|
|
|
385
|
-
|
|
386
|
-
2. Export it from `src/index.tsx`
|
|
387
|
-
3. Create a Storybook story in `src/stories/components/`
|
|
388
|
-
4. Update this documentation
|
|
450
|
+
## Collaboration Features
|
|
389
451
|
|
|
390
|
-
|
|
452
|
+
All field components support real-time collaboration when used within the Process.co flow editor:
|
|
391
453
|
|
|
392
|
-
-
|
|
393
|
-
-
|
|
394
|
-
-
|
|
395
|
-
- Add JSDoc comments for props
|
|
396
|
-
- Create comprehensive Storybook stories
|
|
397
|
-
- Ensure accessibility compliance
|
|
398
|
-
- Use Tailwind CSS with the `ui:` prefix for styling
|
|
454
|
+
- **Cursor sharing**: See where other users are editing
|
|
455
|
+
- **Conflict resolution**: Automatic handling of concurrent edits via Yjs
|
|
456
|
+
- **Presence indicators**: Visual indication of active editors
|
|
399
457
|
|
|
400
|
-
|
|
458
|
+
These features work automatically when components are rendered within a `NodePropertyProvider` context.
|
|
401
459
|
|
|
402
|
-
|
|
460
|
+
---
|
|
403
461
|
|
|
404
|
-
|
|
405
|
-
pnpm test
|
|
406
|
-
```
|
|
462
|
+
## UI Components
|
|
407
463
|
|
|
408
|
-
|
|
464
|
+
The library also includes standard UI components:
|
|
409
465
|
|
|
410
|
-
|
|
466
|
+
```tsx
|
|
467
|
+
import {
|
|
468
|
+
Button,
|
|
469
|
+
Card,
|
|
470
|
+
Alert,
|
|
471
|
+
DropdownMenu,
|
|
472
|
+
DropdownMenuTrigger,
|
|
473
|
+
DropdownMenuContent,
|
|
474
|
+
DropdownMenuItem,
|
|
475
|
+
ConfirmationDropdownMenuItem,
|
|
476
|
+
} from '@process.co/ui';
|
|
477
|
+
```
|
|
411
478
|
|
|
412
|
-
|
|
413
|
-
pnpm build
|
|
414
|
-
```
|
|
479
|
+
See the [Storybook documentation](https://main--674d30e40a127b13419e46ba.chromatic.com) for full component reference.
|