@fluid-app/fluid-cli-widget 0.1.34 → 0.1.36

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.
@@ -1,280 +1,45 @@
1
- # AGENTS.md
2
-
3
- Guidance for AI coding tools working in this standalone Fluid widget project.
4
-
5
- This repository is a generated Fluid widget package. Treat these instructions as the source of truth for code generated here. Do not assume the parent Fluid monorepo is present.
6
-
7
- ## Project boundary
8
-
9
- - This project contains a widget package only. Do not scaffold droplets, portal apps, Next.js apps, Rails code, API servers, or monorepo packages here.
10
- - Use React, TypeScript, Vite, and the Fluid widget CLI scripts already in `package.json`.
11
- - Keep widget source under `src/widgets/` and package metadata in `manifest.ts`.
12
- - Keep the Remote DOM worker entry in `src/index.ts`; it should call `startWidgetPackage()` once.
13
- - Keep package ownership in `fluid.widget.config.ts`. For droplet-owned widgets, link or set the droplet with `pnpm run widget:link` or `fluid widget link`; do not hard-code a droplet into component source.
14
- - Runtime CSS belongs in `styles.css` or files imported by the worker build graph. Keep the guarded CSS import in `src/index.ts` so the builder emits a stylesheet without executing DOM-oriented CSS loading inside the worker.
15
-
16
- ## Manifest authoring
17
-
18
- Use `defineWidget()`, `defineWidgetPackage()`, and `startWidgetPackage()` from `@fluid-app/portal-sdk/widgets/worker`.
19
-
20
- ### `defineWidget()` checklist
21
-
22
- Each widget should define:
23
-
24
- - `name`: stable, URL-safe widget name. Use letters, numbers, underscore, hyphen, or tilde. Changing it changes the generated widget type.
25
- - `component`: React component that renders the widget.
26
- - `displayName`, `description`, `icon`, and `category`: palette metadata for the builder.
27
- - `defaultProps`: JSON-serializable default props. Do not use functions, Dates, undefined values, class instances, NaN, or Infinity.
28
- - `propertySchema`: JSON-serializable editable fields for the builder property panel.
29
- - `container`: usually `block` or `card`; use `inline` only for inline content and `fullscreen` only for true full-screen experiences.
30
- - `uses`: every typed portal function called by this widget. Pass the imported function values; never hand-author capability strings.
31
- - `resizable`: omit or set false for fixed widgets; otherwise use `true`, `horizontal`, `vertical`, `both`, or an object with horizontal/vertical booleans and optional min sizes.
32
-
33
- ## Typed portal functions
34
-
35
- Import worker-safe portal functions from
36
- `@fluid-app/portal-sdk/widgets/worker`, call them directly, and declare the
37
- same function values in `defineWidget({ uses: [...] })`:
38
-
39
- ```ts
40
- import {
41
- defineWidget,
42
- getUserAccount,
43
- navigateTo,
44
- } from "@fluid-app/portal-sdk/widgets/worker";
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
- For public third-party HTTP APIs, import the declarative `networkAccess`
71
- marker and include it in `uses`. The builder asks the portal author for
72
- consent before adding the widget:
73
-
74
- ```ts
75
- import {
76
- defineWidget,
77
- networkAccess,
78
- } from "@fluid-app/portal-sdk/widgets/worker";
79
-
80
- export const weatherWidget = defineWidget({
81
- name: "Weather",
82
- component: Weather,
83
- uses: [networkAccess],
84
- });
85
- ```
86
-
87
- The worker then uses standard `fetch` directly. Fluid does not add tokens,
88
- cookies, credentials, or headers. Direct requests to `fluid.app`, the current
89
- portal origin, loopback, and private-network addresses are blocked. Redirects
90
- are handled by native fetch and are not inspected, so network approval remains
91
- a package-trust decision. WebSocket, EventSource, WebTransport, and
92
- streaming-specific APIs are not part of this capability.
93
-
94
- `getUserAccount()` may include email, but deliberately excludes phone numbers,
95
- addresses, payment data, credentials, government or tax identifiers, dates of
96
- birth, raw metadata, and unknown future fields. Widgets cannot access the
97
- host's `tenantClient`; use a purpose-built portal function.
98
-
99
- Define a company-specific typed function with
100
- `definePortalFunction<Output, Input>({ capability, version, method })`, call it
101
- directly, and include it in `uses`. The portal owner implements the same
102
- function with `implementPortalFunction(function, handler)` under
103
- `remoteWidgets.functions`. Built-in functions cannot be overridden and
104
- duplicate custom implementations are rejected.
105
-
106
- Custom function inputs and outputs must contain JSON values only: null,
107
- booleans, finite numbers, strings, arrays, and objects composed from those
108
- values. Do not use `undefined`, functions, Dates, Maps, Sets, class instances,
109
- `NaN`, or `Infinity`; the runtime validates both requests and responses.
110
-
111
- ### `defineWidgetPackage()` checklist
112
-
113
- The generated package is droplet-owned:
114
-
115
- - `scope` is the namespace passed at project creation.
116
- - `packageType` must stay `droplet`.
117
- - `version` must be SemVer without build metadata, such as `1.2.3` or `1.2.3-beta.1`.
118
- - Do not author `workerEntryUrl`; dev and build inject the served worker artifact URL.
119
- - `widgets` must contain at least one `defineWidget()` result.
120
- - 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.
121
-
122
- ## Property schema reference
123
-
124
- A property schema describes the builder editing UI. Use this shape:
125
-
126
- ```ts
127
- propertySchema: {
128
- tabsConfig: [{ id: "content", label: "Content" }],
129
- dataSourceTargetProps: ["title", "items"],
130
- fields: [
131
- {
132
- key: "title",
133
- label: "Title",
134
- type: "text",
135
- defaultValue: "Featured items",
136
- tab: "content",
137
- group: "Copy",
138
- },
139
- ],
140
- }
141
- ```
142
-
143
- Base field keys:
144
-
145
- - `key`: prop key written into widget props. For visual-only fields such as section headers, use a unique non-prop key.
146
- - `label`: human-readable property label.
147
- - `type`: one of the supported field types below.
148
- - `description`: optional helper text.
149
- - `defaultValue`: optional JSON-serializable value matching the prop.
150
- - `tab`: optional tab id from `tabsConfig`.
151
- - `group`: optional group label inside a tab.
152
- - `advanced`: true for theme override controls; advanced fields render in the Custom styling group.
153
- - `requiresKeyValue`: conditionally show the field when another prop has a value. Arrays are AND logic.
154
-
155
- Supported field types:
156
-
157
- - `text`: single-line string. Optional `placeholder`, `maxLength`, `tokenSuggestions`.
158
- - `textarea`: multi-line string. Optional `placeholder`, `rows`, `maxLength`.
159
- - `number`: numeric input. Optional `min`, `max`, `step`.
160
- - `boolean`: toggle.
161
- - `select`: dropdown. Requires `options` with `label` and `value` entries.
162
- - `color`: basic color value.
163
- - `range`: slider. Requires `min` and `max`; optional `step`.
164
- - `dataSource`: data-source selector/configuration entry point.
165
- - `resource`: single shareable/resource selector. Optional `allowedTypes`.
166
- - `image`: media picker. Optional `accept` as `image`, `video`, or `any`.
167
- - `alignment`: alignment picker. Requires `options.verticalEnabled` and `options.horizontalEnabled`.
168
- - `slider`: numeric slider with optional `unit` suffix plus `min`, `max`, and `step`.
169
- - `colorPicker`: color picker with optional `swatches`.
170
- - `sectionHeader`: visual grouping header with optional `subtitle`.
171
- - `separator`: visual separator.
172
- - `buttonGroup`: segmented control. Requires `options`; each option has `value` plus optional `label`, `ariaLabel`, and icon.
173
- - `colorSelect`: semantic theme color selector. Optional `excludeColors`.
174
- - `sectionLayoutSelect`: visual layout selector.
175
- - `background`: combined resource/color background control.
176
- - `contentPosition`: 3-by-3 content position picker.
177
- - `textSizeSelect`: theme text size selector.
178
- - `cssUnit`: number plus unit. Optional `allowedUnits`, `defaultUnit`, and min/max/step maps per unit.
179
- - `fontPicker`: Google font picker with optional `placeholder`.
180
- - `stringArray`: editable list of strings with optional `placeholder`.
181
- - `borderRadius`: composite radius editor. Requires `keys.topLeft`, `keys.topRight`, `keys.bottomLeft`, and `keys.bottomRight` mapping to real prop keys.
182
- - `screenPicker`: portal screen picker. Optional `includeSystemItems`.
183
-
184
- Data-source-ready props:
185
-
186
- - Add bindable prop keys to `dataSourceTargetProps`.
187
- - Keep those prop types serializable and tolerant of missing, empty, or partially populated data.
188
- - For arrays, render empty states and validate each item before reading nested properties.
189
- - Keep manual defaults in `defaultProps`; data sources should override props without requiring component rewrites.
190
- - If selected data needs per-item settings, add `itemConfigSchema` with its own `fields` array.
191
-
192
- ## Component quality bar
193
-
194
- - Components must be deterministic, portable, and host-safe. Avoid direct assumptions about the embedding portal, route, global CSS reset, or parent DOM.
195
- - Props are untrusted. Provide defaults, guard array access, and handle nullish values.
196
- - Use stable keys for lists. Do not use array indexes when items have stable ids.
197
- - Avoid side effects during render. Use effects only for host-safe subscriptions and clean them up.
198
- - Do not fetch data directly unless the widget explicitly owns that integration. Prefer props and data-source-ready schemas.
199
- - Keep bundle weight small. Avoid large UI kits or date/chart libraries unless the widget truly needs them.
200
- - Do not store secrets, API tokens, or tenant-specific credentials in source, props, or defaultProps.
201
-
202
- ## Accessibility requirements
203
-
204
- - Use semantic HTML first: sections, headings, buttons, lists, forms, and labels.
205
- - Every interactive control must be keyboard reachable and have a visible focus state.
206
- - Icon-only buttons need `aria-label`.
207
- - Images need meaningful alt text, or empty alt text when decorative.
208
- - Preserve heading order inside the widget; do not choose headings based only on size.
209
- - Announce dynamic changes when necessary with appropriate ARIA live regions.
210
- - Meet contrast expectations by using theme foreground/background token pairs.
211
- - Respect reduced motion for animation-heavy widgets.
212
-
213
- ## Theme and styling guidance
214
-
215
- Fluid hosts provide semantic CSS variables. Prefer those over hard-coded colors:
216
-
217
- - Surfaces: `--background`, `--card`, `--popover`.
218
- - Text on surfaces: `--foreground`, `--card-foreground`, `--popover-foreground`.
219
- - Brand/action: `--primary`, `--primary-foreground`.
220
- - Supporting UI: `--secondary`, `--secondary-foreground`, `--muted`, `--muted-foreground`, `--accent`, `--accent-foreground`.
221
- - Status and chrome: `--destructive`, `--destructive-foreground`, `--border`, `--input`, `--ring`.
222
- - Charts: `--chart-1` through `--chart-5`.
223
- - Radius: `--radius`, `--radius-sm`, `--radius-md`, `--radius-lg`, `--radius-xl`.
224
- - 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`.
225
-
226
- 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.
227
-
228
- Light/dark behavior:
229
-
230
- - The portal switches theme values with `data-theme-mode="dark"` and may also honor system dark mode when configured.
231
- - Do not write separate hard-coded dark palettes unless absolutely necessary. Use semantic variables so the host theme controls both modes.
232
- - If you need mode-specific refinements, scope them to `[data-theme-mode="dark"]` and keep them token-based.
233
- - Avoid styling that only works on white backgrounds. Use semantic variables and verify against representative light, dark, and high-contrast host token values.
234
-
235
- Runtime CSS rules:
236
-
237
- **A stylesheet is the only way to style a widget. Inline styles do not work.**
238
-
239
- The host sanitizes every Remote DOM mutation before it reaches the shadow root. The
240
- `style` attribute is rejected and `<style>` elements are a banned tag, so:
241
-
242
- - `style={{ color: "red" }}` on any element is **silently dropped**. The element renders
243
- with no styling and no error — this is the single most common reason a widget "looks
244
- broken" or "came out unstyled".
245
- - An inline `<style>` block never renders.
246
- - Only CSS reachable from the widget build graph is published as a `cssUrls` artifact and
247
- adopted into the shadow root.
248
-
249
- So: put every rule in a stylesheet, give elements `className`s, and target those classes.
250
- Never reach for an inline style — it will not survive.
251
-
252
- - Put runtime selectors in `styles.css` or imported CSS modules.
253
- - Keep selectors prefixed with the widget name to avoid leaking styles into the host.
254
- - Do not rely on global body styles for runtime appearance.
255
- - 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.
256
- - 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.
257
-
258
- ## Validation workflow
259
-
260
- Before considering changes complete, run:
261
-
262
- ```bash
263
- pnpm typecheck
264
- pnpm validate
265
- pnpm build
266
- ```
267
-
268
- Use `pnpm dev` for local descriptor and worker endpoints, and `pnpm run widget:publish --dry-run` when checking publish readiness without uploading.
269
-
270
- Common failures and fixes:
271
-
272
- - Missing droplet UUID: run `pnpm run widget:link` or pass `--droplet` to validate/build/publish commands.
273
- - No source package found: ensure `fluid.widget.config.ts` exports `widgetPackage` or `widgetPackages` from `manifest.ts`.
274
- - Invalid package type: keep `packageType: "droplet"` in `defineWidgetPackage()`.
275
- - Invalid widget name or package key: use URL-safe names only.
276
- - Invalid version: use SemVer without build metadata.
277
- - Non-serializable metadata: remove functions, undefined values, Dates, NaN, Infinity, Maps, Sets, and class instances from `propertySchema` and `defaultProps`.
278
- - CSS URL mismatch: import runtime CSS into the bundle or remove manual `cssUrls` entries.
279
- - Build succeeds but styles are missing: confirm the CSS import is reachable from `src/index.ts` or the widget component.
280
- - 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.