@fluid-app/fluid-cli-widget 0.1.33 → 0.1.35
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/authoring/commands.md +195 -0
- package/dist/{index-JKSTx5pZ.d.mts → index-DW3icMxz.d.mts} +7 -1
- package/dist/index-DW3icMxz.d.mts.map +1 -0
- package/dist/index.d.mts +3 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{src-_wfDoBLp.mjs → src-CzqGGQnf.mjs} +12 -2
- package/dist/src-CzqGGQnf.mjs.map +1 -0
- package/dist/vite/plugin.d.mts +1 -1
- package/dist/vite/plugin.mjs +1 -1
- package/package.json +4 -3
- package/templates/default/AGENTS.md +45 -256
- package/templates/default/README.md.template +110 -316
- package/templates/default/manifest.ts.template +16 -0
- package/templates/default/styles.css +20 -27
- package/dist/index-JKSTx5pZ.d.mts.map +0 -1
- package/dist/src-_wfDoBLp.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluid-app/fluid-cli-widget",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
4
4
|
"description": "Fluid CLI plugin for standalone widget package workflows",
|
|
5
5
|
"files": [
|
|
6
|
+
"authoring",
|
|
6
7
|
"dist",
|
|
7
8
|
"templates"
|
|
8
9
|
],
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
"prompts": "^2.4.2",
|
|
34
35
|
"tsx": "^4.21.0",
|
|
35
36
|
"vite": "^6.4.1",
|
|
36
|
-
"@fluid-app/fluid-cli": "0.1.
|
|
37
|
+
"@fluid-app/fluid-cli": "0.1.17"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"@types/node": "24.10.12",
|
|
@@ -42,8 +43,8 @@
|
|
|
42
43
|
"tsdown": "^0.21.0",
|
|
43
44
|
"typescript": "^5",
|
|
44
45
|
"vitest": "^4.0.18",
|
|
45
|
-
"@fluid-app/fluidos-api-client": "0.1.0",
|
|
46
46
|
"@fluid-app/fluid-cli-widget-tooling": "0.1.0",
|
|
47
|
+
"@fluid-app/fluidos-api-client": "0.1.0",
|
|
47
48
|
"@fluid-app/typescript-config": "0.0.0"
|
|
48
49
|
},
|
|
49
50
|
"engines": {
|
|
@@ -1,256 +1,45 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
async function openProfile(): Promise<void> {
|
|
47
|
-
const account = await getUserAccount();
|
|
48
|
-
await navigateTo(account.slug);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export const profileButtonWidget = defineWidget({
|
|
52
|
-
name: "ProfileButton",
|
|
53
|
-
component: ProfileButton,
|
|
54
|
-
uses: [getUserAccount, navigateTo],
|
|
55
|
-
});
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Available built-ins are `getUserAccount`, `getStore`, `getPortalApp`,
|
|
59
|
-
`getPortalProfile`, `getNavigationState`, `buildPortalHref`, `navigateTo`,
|
|
60
|
-
`getFullscreenState`, `requestFullscreen`, and `exitFullscreen`. Getters return
|
|
61
|
-
resolved data instead of query snapshots. Navigation accepts a slug string,
|
|
62
|
-
`{ slug }`, or `{ href }`.
|
|
63
|
-
|
|
64
|
-
`uses` is required for every called function. `defineWidget()` converts it to
|
|
65
|
-
the existing descriptor declarations, and both the worker and host enforce the
|
|
66
|
-
declaration. A `PortalFunctionError` with code `NOT_DECLARED` means the called
|
|
67
|
-
function must be added to the widget's `uses` array. Do not write a raw
|
|
68
|
-
`capabilities` array.
|
|
69
|
-
|
|
70
|
-
`getUserAccount()` may include email, but deliberately excludes phone numbers,
|
|
71
|
-
addresses, payment data, credentials, government or tax identifiers, dates of
|
|
72
|
-
birth, raw metadata, and unknown future fields. Widgets cannot access the
|
|
73
|
-
host's `tenantClient`; use a purpose-built portal function.
|
|
74
|
-
|
|
75
|
-
Define a company-specific typed function with
|
|
76
|
-
`definePortalFunction<Output, Input>({ capability, version, method })`, call it
|
|
77
|
-
directly, and include it in `uses`. The portal owner implements the same
|
|
78
|
-
function with `implementPortalFunction(function, handler)` under
|
|
79
|
-
`remoteWidgets.functions`. Built-in functions cannot be overridden and
|
|
80
|
-
duplicate custom implementations are rejected.
|
|
81
|
-
|
|
82
|
-
Custom function inputs and outputs must contain JSON values only: null,
|
|
83
|
-
booleans, finite numbers, strings, arrays, and objects composed from those
|
|
84
|
-
values. Do not use `undefined`, functions, Dates, Maps, Sets, class instances,
|
|
85
|
-
`NaN`, or `Infinity`; the runtime validates both requests and responses.
|
|
86
|
-
|
|
87
|
-
### `defineWidgetPackage()` checklist
|
|
88
|
-
|
|
89
|
-
The generated package is droplet-owned:
|
|
90
|
-
|
|
91
|
-
- `scope` is the namespace passed at project creation.
|
|
92
|
-
- `packageType` must stay `droplet`.
|
|
93
|
-
- `version` must be SemVer without build metadata, such as `1.2.3` or `1.2.3-beta.1`.
|
|
94
|
-
- Do not author `workerEntryUrl`; dev and build inject the served worker artifact URL.
|
|
95
|
-
- `widgets` must contain at least one `defineWidget()` result.
|
|
96
|
-
- Do not manually set `packageStableId` for the default droplet template. The CLI injects the linked droplet as the stable package key during validation, build, and publish.
|
|
97
|
-
|
|
98
|
-
## Property schema reference
|
|
99
|
-
|
|
100
|
-
A property schema describes the builder editing UI. Use this shape:
|
|
101
|
-
|
|
102
|
-
```ts
|
|
103
|
-
propertySchema: {
|
|
104
|
-
tabsConfig: [{ id: "content", label: "Content" }],
|
|
105
|
-
dataSourceTargetProps: ["title", "items"],
|
|
106
|
-
fields: [
|
|
107
|
-
{
|
|
108
|
-
key: "title",
|
|
109
|
-
label: "Title",
|
|
110
|
-
type: "text",
|
|
111
|
-
defaultValue: "Featured items",
|
|
112
|
-
tab: "content",
|
|
113
|
-
group: "Copy",
|
|
114
|
-
},
|
|
115
|
-
],
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
Base field keys:
|
|
120
|
-
|
|
121
|
-
- `key`: prop key written into widget props. For visual-only fields such as section headers, use a unique non-prop key.
|
|
122
|
-
- `label`: human-readable property label.
|
|
123
|
-
- `type`: one of the supported field types below.
|
|
124
|
-
- `description`: optional helper text.
|
|
125
|
-
- `defaultValue`: optional JSON-serializable value matching the prop.
|
|
126
|
-
- `tab`: optional tab id from `tabsConfig`.
|
|
127
|
-
- `group`: optional group label inside a tab.
|
|
128
|
-
- `advanced`: true for theme override controls; advanced fields render in the Custom styling group.
|
|
129
|
-
- `requiresKeyValue`: conditionally show the field when another prop has a value. Arrays are AND logic.
|
|
130
|
-
|
|
131
|
-
Supported field types:
|
|
132
|
-
|
|
133
|
-
- `text`: single-line string. Optional `placeholder`, `maxLength`, `tokenSuggestions`.
|
|
134
|
-
- `textarea`: multi-line string. Optional `placeholder`, `rows`, `maxLength`.
|
|
135
|
-
- `number`: numeric input. Optional `min`, `max`, `step`.
|
|
136
|
-
- `boolean`: toggle.
|
|
137
|
-
- `select`: dropdown. Requires `options` with `label` and `value` entries.
|
|
138
|
-
- `color`: basic color value.
|
|
139
|
-
- `range`: slider. Requires `min` and `max`; optional `step`.
|
|
140
|
-
- `dataSource`: data-source selector/configuration entry point.
|
|
141
|
-
- `resource`: single shareable/resource selector. Optional `allowedTypes`.
|
|
142
|
-
- `image`: media picker. Optional `accept` as `image`, `video`, or `any`.
|
|
143
|
-
- `alignment`: alignment picker. Requires `options.verticalEnabled` and `options.horizontalEnabled`.
|
|
144
|
-
- `slider`: numeric slider with optional `unit` suffix plus `min`, `max`, and `step`.
|
|
145
|
-
- `colorPicker`: color picker with optional `swatches`.
|
|
146
|
-
- `sectionHeader`: visual grouping header with optional `subtitle`.
|
|
147
|
-
- `separator`: visual separator.
|
|
148
|
-
- `buttonGroup`: segmented control. Requires `options`; each option has `value` plus optional `label`, `ariaLabel`, and icon.
|
|
149
|
-
- `colorSelect`: semantic theme color selector. Optional `excludeColors`.
|
|
150
|
-
- `sectionLayoutSelect`: visual layout selector.
|
|
151
|
-
- `background`: combined resource/color background control.
|
|
152
|
-
- `contentPosition`: 3-by-3 content position picker.
|
|
153
|
-
- `textSizeSelect`: theme text size selector.
|
|
154
|
-
- `cssUnit`: number plus unit. Optional `allowedUnits`, `defaultUnit`, and min/max/step maps per unit.
|
|
155
|
-
- `fontPicker`: Google font picker with optional `placeholder`.
|
|
156
|
-
- `stringArray`: editable list of strings with optional `placeholder`.
|
|
157
|
-
- `borderRadius`: composite radius editor. Requires `keys.topLeft`, `keys.topRight`, `keys.bottomLeft`, and `keys.bottomRight` mapping to real prop keys.
|
|
158
|
-
- `screenPicker`: portal screen picker. Optional `includeSystemItems`.
|
|
159
|
-
|
|
160
|
-
Data-source-ready props:
|
|
161
|
-
|
|
162
|
-
- Add bindable prop keys to `dataSourceTargetProps`.
|
|
163
|
-
- Keep those prop types serializable and tolerant of missing, empty, or partially populated data.
|
|
164
|
-
- For arrays, render empty states and validate each item before reading nested properties.
|
|
165
|
-
- Keep manual defaults in `defaultProps`; data sources should override props without requiring component rewrites.
|
|
166
|
-
- If selected data needs per-item settings, add `itemConfigSchema` with its own `fields` array.
|
|
167
|
-
|
|
168
|
-
## Component quality bar
|
|
169
|
-
|
|
170
|
-
- Components must be deterministic, portable, and host-safe. Avoid direct assumptions about the embedding portal, route, global CSS reset, or parent DOM.
|
|
171
|
-
- Props are untrusted. Provide defaults, guard array access, and handle nullish values.
|
|
172
|
-
- Use stable keys for lists. Do not use array indexes when items have stable ids.
|
|
173
|
-
- Avoid side effects during render. Use effects only for host-safe subscriptions and clean them up.
|
|
174
|
-
- Do not fetch data directly unless the widget explicitly owns that integration. Prefer props and data-source-ready schemas.
|
|
175
|
-
- Keep bundle weight small. Avoid large UI kits or date/chart libraries unless the widget truly needs them.
|
|
176
|
-
- Do not store secrets, API tokens, or tenant-specific credentials in source, props, or defaultProps.
|
|
177
|
-
|
|
178
|
-
## Accessibility requirements
|
|
179
|
-
|
|
180
|
-
- Use semantic HTML first: sections, headings, buttons, lists, forms, and labels.
|
|
181
|
-
- Every interactive control must be keyboard reachable and have a visible focus state.
|
|
182
|
-
- Icon-only buttons need `aria-label`.
|
|
183
|
-
- Images need meaningful alt text, or empty alt text when decorative.
|
|
184
|
-
- Preserve heading order inside the widget; do not choose headings based only on size.
|
|
185
|
-
- Announce dynamic changes when necessary with appropriate ARIA live regions.
|
|
186
|
-
- Meet contrast expectations by using theme foreground/background token pairs.
|
|
187
|
-
- Respect reduced motion for animation-heavy widgets.
|
|
188
|
-
|
|
189
|
-
## Theme and styling guidance
|
|
190
|
-
|
|
191
|
-
Fluid hosts provide semantic CSS variables. Prefer those over hard-coded colors:
|
|
192
|
-
|
|
193
|
-
- Surfaces: `--background`, `--card`, `--popover`.
|
|
194
|
-
- Text on surfaces: `--foreground`, `--card-foreground`, `--popover-foreground`.
|
|
195
|
-
- Brand/action: `--primary`, `--primary-foreground`.
|
|
196
|
-
- Supporting UI: `--secondary`, `--secondary-foreground`, `--muted`, `--muted-foreground`, `--accent`, `--accent-foreground`.
|
|
197
|
-
- Status and chrome: `--destructive`, `--destructive-foreground`, `--border`, `--input`, `--ring`.
|
|
198
|
-
- Charts: `--chart-1` through `--chart-5`.
|
|
199
|
-
- Radius: `--radius`, `--radius-sm`, `--radius-md`, `--radius-lg`, `--radius-xl`.
|
|
200
|
-
- Theme engine aliases may also provide `--font-header`, `--font-body`, `--font-size-extra-small`, `--font-size-small`, `--font-size-regular`, `--font-size-large`, `--font-size-extra-large`, and `--font-size-giant`.
|
|
201
|
-
|
|
202
|
-
Tailwind equivalents, when Tailwind is available in a host, are the semantic utilities: `bg-background`, `text-foreground`, `bg-card`, `text-card-foreground`, `bg-primary`, `text-primary-foreground`, `border-border`, `ring-ring`, `rounded-lg`, and text sizes such as `text-sm` or `text-xl`. In this standalone template, plain CSS is the safest runtime default.
|
|
203
|
-
|
|
204
|
-
Light/dark behavior:
|
|
205
|
-
|
|
206
|
-
- The portal switches theme values with `data-theme-mode="dark"` and may also honor system dark mode when configured.
|
|
207
|
-
- Do not write separate hard-coded dark palettes unless absolutely necessary. Use semantic variables so the host theme controls both modes.
|
|
208
|
-
- If you need mode-specific refinements, scope them to `[data-theme-mode="dark"]` and keep them token-based.
|
|
209
|
-
- Avoid styling that only works on white backgrounds. Use semantic variables and verify against representative light, dark, and high-contrast host token values.
|
|
210
|
-
|
|
211
|
-
Runtime CSS rules:
|
|
212
|
-
|
|
213
|
-
**A stylesheet is the only way to style a widget. Inline styles do not work.**
|
|
214
|
-
|
|
215
|
-
The host sanitizes every Remote DOM mutation before it reaches the shadow root. The
|
|
216
|
-
`style` attribute is rejected and `<style>` elements are a banned tag, so:
|
|
217
|
-
|
|
218
|
-
- `style={{ color: "red" }}` on any element is **silently dropped**. The element renders
|
|
219
|
-
with no styling and no error — this is the single most common reason a widget "looks
|
|
220
|
-
broken" or "came out unstyled".
|
|
221
|
-
- An inline `<style>` block never renders.
|
|
222
|
-
- Only CSS reachable from the widget build graph is published as a `cssUrls` artifact and
|
|
223
|
-
adopted into the shadow root.
|
|
224
|
-
|
|
225
|
-
So: put every rule in a stylesheet, give elements `className`s, and target those classes.
|
|
226
|
-
Never reach for an inline style — it will not survive.
|
|
227
|
-
|
|
228
|
-
- Put runtime selectors in `styles.css` or imported CSS modules.
|
|
229
|
-
- Keep selectors prefixed with the widget name to avoid leaking styles into the host.
|
|
230
|
-
- Do not rely on global body styles for runtime appearance.
|
|
231
|
-
- Ensure CSS is reachable from the guarded import in `src/index.ts` or another module included in the widget build, otherwise CSS artifacts may not be published.
|
|
232
|
-
- Test through a portal or builder host using the generated Remote DOM endpoints. Do not add a direct React host preview for third-party widgets.
|
|
233
|
-
|
|
234
|
-
## Validation workflow
|
|
235
|
-
|
|
236
|
-
Before considering changes complete, run:
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
pnpm typecheck
|
|
240
|
-
pnpm validate
|
|
241
|
-
pnpm build
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
Use `pnpm dev` for local descriptor and worker endpoints, and `pnpm run widget:publish --dry-run` when checking publish readiness without uploading.
|
|
245
|
-
|
|
246
|
-
Common failures and fixes:
|
|
247
|
-
|
|
248
|
-
- Missing droplet UUID: run `pnpm run widget:link` or pass `--droplet` to validate/build/publish commands.
|
|
249
|
-
- No source package found: ensure `fluid.widget.config.ts` exports `widgetPackage` or `widgetPackages` from `manifest.ts`.
|
|
250
|
-
- Invalid package type: keep `packageType: "droplet"` in `defineWidgetPackage()`.
|
|
251
|
-
- Invalid widget name or package key: use URL-safe names only.
|
|
252
|
-
- Invalid version: use SemVer without build metadata.
|
|
253
|
-
- Non-serializable metadata: remove functions, undefined values, Dates, NaN, Infinity, Maps, Sets, and class instances from `propertySchema` and `defaultProps`.
|
|
254
|
-
- CSS URL mismatch: import runtime CSS into the bundle or remove manual `cssUrls` entries.
|
|
255
|
-
- Build succeeds but styles are missing: confirm the CSS import is reachable from `src/index.ts` or the widget component.
|
|
256
|
-
- Local development works but the published widget fails: check that browser-only APIs are guarded and no local-only URLs or environment variables are required at runtime.
|
|
1
|
+
# Fluid widget project guidance
|
|
2
|
+
|
|
3
|
+
Use `.agents/skills/fluid-widget-authoring/SKILL.md` for every widget change.
|
|
4
|
+
Read the linked reference for the task before editing source or metadata.
|
|
5
|
+
|
|
6
|
+
## Sources of truth
|
|
7
|
+
|
|
8
|
+
- `manifest.ts` owns package scope, package key, package version, and widget
|
|
9
|
+
registrations. Each `defineWidget()` call owns its widget metadata, defaults,
|
|
10
|
+
property schema, portal functions, and capabilities.
|
|
11
|
+
- `fluid.widget.config.ts` owns the linked Droplet ID and exports the package
|
|
12
|
+
resolved from `manifest.ts`. It does not own package metadata.
|
|
13
|
+
- `src/` owns worker-safe widget components. The root `styles.css` owns package
|
|
14
|
+
CSS and is imported once by `src/index.ts`.
|
|
15
|
+
- The installed SDK declarations and
|
|
16
|
+
`node_modules/@fluid-app/portal-sdk/authoring/widget-api/` own exact API and
|
|
17
|
+
property-field contracts.
|
|
18
|
+
- `node_modules/@fluid-app/fluid-cli-widget/authoring/commands.md` owns exact
|
|
19
|
+
command syntax and options.
|
|
20
|
+
- `.fluid/` contains generated build and publication artifacts. Never edit it.
|
|
21
|
+
|
|
22
|
+
## Authoring rules
|
|
23
|
+
|
|
24
|
+
- Preserve existing work. Inspect `git status` before commands that can change
|
|
25
|
+
files.
|
|
26
|
+
- Keep package and widget identifiers stable after publication. Published
|
|
27
|
+
versions are immutable; increase `version` for each release.
|
|
28
|
+
- Treat all props and portal-function results as partial or malformed JSON.
|
|
29
|
+
Render an empty or error state instead of throwing during render.
|
|
30
|
+
- Declare every portal function and capability used by a widget in `uses`.
|
|
31
|
+
- Use semantic theme tokens. Use the `colorSelect` property field for colors.
|
|
32
|
+
The legacy `color` field is deprecated. Do not add custom colors, fonts,
|
|
33
|
+
radii, spacing, or styling controls when the theme engine already represents
|
|
34
|
+
the design decision.
|
|
35
|
+
- Keep secrets, credentials, private endpoints, and tenant tokens out of worker
|
|
36
|
+
code. Use a host portal function or server application for privileged work.
|
|
37
|
+
- `publish`, `push`, and version changes affect remote state. Do not run them
|
|
38
|
+
unless the task authorizes that remote change. A dry run does not publish.
|
|
39
|
+
|
|
40
|
+
## Required verification
|
|
41
|
+
|
|
42
|
+
Run typecheck, validation, and build for a package change. Inspect the generated
|
|
43
|
+
manifest and the widget in a portal or builder host. Before publication, also
|
|
44
|
+
run the dry-run publish path and inspect the source diff. A successful build
|
|
45
|
+
does not authorize publication.
|