Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/agents/local-cicd-testing-subagent.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,4 @@ Status: PASS | FAIL | BLOCKED
- Limit file-changing retries to formatting and lint autofix only when the workflow output clearly points to those issues.
- Treat release testing as dry-run validation only.
- Treat deploy testing as limited by the documented local environment setup and GitHub-visible ref requirements.
- **NEVER run `npm ci` locally.** It wipes and reinstalls `node_modules`, which breaks locked native binaries (e.g. `esbuild.exe`, `@tailwindcss/oxide`) on Windows when VS Code or dev servers hold file locks, leaving the workspace in a partially corrupted state. If dependency installation is needed, use `npm install` instead.
18 changes: 14 additions & 4 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,27 +130,36 @@ When proposing code, **adhere to all of the following**:
- Mirror existing naming, file layout, import style, and error handling patterns.
- Keep public API shapes and function signatures stable unless a bug requires change.

3. **No New Files by Default**
3. **Always Emit Code That Passes `npx nx format:check`**

- `npx nx format` uses Prettier under the hood. The project config is `.prettierrc`: `singleQuote: true`, all other options are Prettier defaults.
- Apply correct indentation, trailing commas, bracket spacing, and line length so that running `npx nx format:check` produces zero diffs.

- When the user asks for a format check, always run `npx nx format:check` first; if it fails, run `npx nx format --base="remotes/origin/main"`, then rerun `npx nx format:check` and report the final status.
- This applies to every file type handled in this repo: `.ts`, `.tsx`, `.js`, `.jsx`, `.json`, `.md`, `.css`.
- Do **not** rely on a post-write format step — emit correctly formatted code the first time.

4. **No New Files by Default**

- Do not create new modules unless duplication or complexity becomes worse without them.
- Never create standalone markdown documentation files (e.g., PR tickets, feature docs, summaries).
- Embed all information directly into code comments or verbally respond to user.
- **Exception:** Internal tickets can be created in `.github/INTERNAL-TICKETS/` for feature planning (gitignored, local only).

4. **Zero Surprises**
5. **Zero Surprises**

- Avoid side effects, global state changes, or cross-cutting refactors.
- Keep behavior backward-compatible unless the task explicitly requests otherwise.

5. **Only Change When Explicitly Told**
6. **Only Change When Explicitly Told**

- Do NOT make changes unless explicitly asked, given clear permission, or strongly hinted.
- Do NOT assume what should be changed or refactored.
- Ask for clarification if instructions are ambiguous.
- Respect the current state of the code unless directed otherwise.
- Do NOT "improve" or refactor code without being told to do so.

6. **Edit Method: Direct Patches Only**
7. **Edit Method: Direct Patches Only**

- Make file changes using direct file patch/edit tools (for example, `apply_patch` / editor patch tools).
- Do NOT edit files by running shell/terminal write commands (for example PowerShell replacement scripts, `sed`, or inline command-based rewrites).
Expand Down Expand Up @@ -414,6 +423,7 @@ function getTotal(items) {
- Add new dependencies/config.
- Create new architectural layers.
- Use `any` — use `unknown` and narrow.
- Run `npm ci` locally — it wipes and reinstalls `node_modules`, which breaks locked native binaries (e.g. `esbuild.exe`) on Windows when VS Code or dev servers hold file locks. Use `npm install` to repair dependencies in place.

---

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-title-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:

cat <<'EOF'
PR title must follow conventional commits format:
feat(scope): description
feat(scope): descriptionP
enhance(scope): description
fix(scope): description
perf(scope): description
Expand Down
4 changes: 2 additions & 2 deletions apps/demo/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "demo",
"name": "app-demo",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"targets": {
"build": {
Expand All @@ -17,7 +17,7 @@
],
"executor": "nx:run-commands",
"options": {
"command": "npx nx run demo:serve"
"command": "npx nx run app-demo:serve"
}
},
"serve": {
Expand Down
6 changes: 3 additions & 3 deletions apps/demo/src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ const demoUrl = isDev ? 'http://localhost:3001/' : '/demo/';

export function Navbar({ children }: { children?: ReactNode }) {
return (
<nav className="demo-navbar h-14 px-6 flex items-center gap-5 bg-white border-b border-slate-200 sticky top-0 z-50">
<nav className="demo-navbar min-h-14 px-4 sm:px-6 py-2 sm:py-0 flex flex-wrap items-center gap-x-5 gap-y-2 bg-white border-b border-slate-200 sticky top-0 z-50">
<a
href={landingUrl}
className="inline-flex items-center gap-2 text-slate-700 hover:text-blue-600 text-base font-bold no-underline transition-colors shrink-0"
>
eSheet
</a>
<div className="demo-navbar-links flex items-center gap-4 ml-2">
<div className="demo-navbar-links flex items-center gap-4 ml-0 sm:ml-2">
<a
href={docsUrl}
className="text-sm text-slate-600 hover:text-blue-600 no-underline transition-colors"
Expand All @@ -29,7 +29,7 @@ export function Navbar({ children }: { children?: ReactNode }) {
</a>
</div>
{children && (
<div className="demo-navbar-actions flex flex-1 items-center gap-3">
<div className="demo-navbar-actions order-last basis-full w-full flex flex-wrap items-center gap-2 min-w-0 sm:order-none sm:basis-auto sm:w-auto sm:flex-1">
{children}
</div>
)}
Expand Down
6 changes: 3 additions & 3 deletions apps/demo/src/views/RendererView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function RendererView() {
onChange={(e) => {
if (e.target.value) handleLoadSchema(e.target.value);
}}
className="px-3 py-1.5 text-sm border border-slate-300 rounded-lg bg-white"
className="px-3 py-1.5 text-sm border border-slate-300 rounded-lg bg-white whitespace-nowrap"
>
<option value="" disabled>
Load example…
Expand All @@ -69,7 +69,7 @@ export function RendererView() {
))}
</select>

<label className="inline-flex items-center gap-2 px-3 py-1.5 text-sm border border-slate-300 rounded-lg bg-white cursor-pointer hover:bg-slate-50">
<label className="inline-flex items-center justify-center sm:justify-start gap-2 px-3 py-1.5 text-sm border border-slate-300 rounded-lg bg-white cursor-pointer hover:bg-slate-50 whitespace-nowrap">
Import JSON
<input
type="file"
Expand All @@ -82,7 +82,7 @@ export function RendererView() {
{formData && (
<button
onClick={handleGetResponses}
className="ml-auto px-4 py-1.5 text-sm font-medium bg-emerald-500 hover:bg-emerald-600 text-white rounded-lg transition-colors"
className="px-4 py-1.5 text-sm font-medium bg-emerald-500 hover:bg-emerald-600 text-white rounded-lg transition-colors whitespace-nowrap"
>
Get Responses
</button>
Expand Down
71 changes: 34 additions & 37 deletions apps/docs/docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,31 @@ Quick reference of all public exports from each eSheet package.

### Types

| Export | Kind | Description |
| ---------------------------- | ---------- | ------------------------------------------------------------------------------------- |
| `FormDefinition` | Interface | Top-level form structure |
| `FieldDefinition` | Interface | Single field structure |
| `FieldResponse` | Interface | Response values for a field |
| `FormResponse` | Type alias | `Record<string, FieldResponse>` |
| `SelectedOption` | Interface | `{ id, value }` for selected options |
| `FieldType` | Type | Union of 19 field type strings |
| `TextInputType` | Type | Union of 9 text input variants |
| `FieldOption` | Interface | Option in a choice field |
| `MatrixRow` / `MatrixColumn` | Interface | Matrix dimensions |
| `ConditionalRule` | Interface | Conditional rule structure |
| `Condition` | Interface | Single condition |
| `ConditionOperator` | Type | Union of 10 operators |
| `ConditionalEffect` | Type | `'visible' \| 'enable' \| 'required'` |
| `LogicMode` | Type | `'AND' \| 'OR'` |
| `FieldCategory` | Type | Field grouping category |
| `AnswerType` | Type | How a field stores its answer |
| `FieldTypeMeta` | Interface | Field type metadata |
| `FieldTypeRegistry` | Type | Registry map |
| `FieldComponentProps` | Interface | Props contract for field components |
| `HydratedResponseItem` | Interface | `{ id, text, answer }` — one per answerable field, returned by `hydrateResponse` |
| `FieldNode` | Interface | Node in normalized definition tree |
| `NormalizedDefinition` | Interface | Flat normalized representation of a form |
| `SheetDndDropDetail` | Interface | Custom event detail for `sheetdrop` events: `{ sourceId, targetId, edge, operation }` |
| `AddFieldOptions` | Interface | Options for `FormStore.addField()` |
| Export | Kind | Description |
| ---------------------------- | ---------- | -------------------------------------------------------------------------------- |
| `FormDefinition` | Interface | Top-level form structure |
| `FieldDefinition` | Interface | Single field structure |
| `FieldResponse` | Interface | Response values for a field |
| `FormResponse` | Type alias | `Record<string, FieldResponse>` |
| `SelectedOption` | Interface | `{ id, value }` for selected options |
| `FieldType` | Type | Union of 19 field type strings |
| `TextInputType` | Type | Union of 9 text input variants |
| `FieldOption` | Interface | Option in a choice field |
| `MatrixRow` / `MatrixColumn` | Interface | Matrix dimensions |
| `ConditionalRule` | Interface | Conditional rule structure |
| `Condition` | Interface | Single condition |
| `ConditionOperator` | Type | Union of 10 operators |
| `ConditionalEffect` | Type | `'visible' \| 'enable' \| 'required'` |
| `LogicMode` | Type | `'AND' \| 'OR'` |
| `FieldCategory` | Type | Field grouping category |
| `AnswerType` | Type | How a field stores its answer |
| `FieldTypeMeta` | Interface | Field type metadata |
| `FieldTypeRegistry` | Type | Registry map |
| `FieldComponentProps` | Interface | Props contract for field components |
| `HydratedResponseItem` | Interface | `{ id, text, answer }` — one per answerable field, returned by `hydrateResponse` |
| `FieldNode` | Interface | Node in normalized definition tree |
| `NormalizedDefinition` | Interface | Flat normalized representation of a form |
| `AddFieldOptions` | Interface | Options for `FormStore.addField()` |

### Constants

Expand Down Expand Up @@ -79,17 +78,15 @@ Quick reference of all public exports from each eSheet package.

### Utilities

| Export | Description |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `normalizeDefinition(def)` | Convert tree → flat normalized state |
| `hydrateDefinition(normalized)` | Convert flat → nested tree |
| `hydrateResponse(normalized, responses)` | Walk normalized definition and return `HydratedResponseItem[]` for export/submission |
| `generateFieldId(fieldType)` | Generate a unique field ID |
| `generateOptionId()` | Generate a unique option ID |
| `generateRowId()` | Generate a unique matrix row ID |
| `generateColumnId()` | Generate a unique matrix column ID |
| `applySheetDnd(handle)` | Attach pointer-event drag-and-drop to a drag handle element |
| `getReorderDestinationIndex(source, target, edge, items)` | Calculate the destination index after a reorder drop |
| Export | Description |
| ---------------------------------------- | ------------------------------------------------------------------------------------ |
| `normalizeDefinition(def)` | Convert tree → flat normalized state |
| `hydrateDefinition(normalized)` | Convert flat → nested tree |
| `hydrateResponse(normalized, responses)` | Walk normalized definition and return `HydratedResponseItem[]` for export/submission |
| `generateFieldId(fieldType)` | Generate a unique field ID |
| `generateOptionId()` | Generate a unique option ID |
| `generateRowId()` | Generate a unique matrix row ID |
| `generateColumnId()` | Generate a unique matrix column ID |

### Registry

Expand Down
4 changes: 2 additions & 2 deletions apps/docs/project.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "docs",
"name": "app-docs",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"targets": {
"dev": {
"executor": "nx:run-commands",
"options": {
"command": "npx nx run docs:serve"
"command": "npx nx run app-docs:serve"
}
},
"serve": {
Expand Down
50 changes: 39 additions & 11 deletions nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,47 +78,75 @@
"types": {
"feat": {
"semverBump": "minor",
"changelog": { "title": "🚀 Features", "hidden": false }
"changelog": {
"title": "🚀 Features",
"hidden": false
}
},
"enhance": {
"semverBump": "patch",
"changelog": { "title": "✨ Enhancements", "hidden": false }
"changelog": {
"title": "✨ Enhancements",
"hidden": false
}
},
"fix": {
"semverBump": "patch",
"changelog": { "title": "🐛 Bug Fixes", "hidden": false }
"changelog": {
"title": "🐛 Bug Fixes",
"hidden": false
}
},
"perf": {
"semverBump": "patch",
"changelog": { "title": "⚡ Performance", "hidden": false }
"changelog": {
"title": "⚡ Performance",
"hidden": false
}
},
"refactor": {
"semverBump": "none",
"changelog": { "title": "♻️ Refactoring", "hidden": false }
"changelog": {
"title": "♻️ Refactoring",
"hidden": false
}
},
"docs": {
"semverBump": "none",
"changelog": { "title": "📚 Documentation", "hidden": false }
"changelog": {
"title": "📚 Documentation",
"hidden": false
}
},
"test": {
"semverBump": "none",
"changelog": { "hidden": true }
"changelog": {
"hidden": true
}
},
"chore": {
"semverBump": "none",
"changelog": { "hidden": true }
"changelog": {
"hidden": true
}
},
"ci": {
"semverBump": "none",
"changelog": { "hidden": true }
"changelog": {
"hidden": true
}
},
"build": {
"semverBump": "none",
"changelog": { "hidden": true }
"changelog": {
"hidden": true
}
},
"repo": {
"semverBump": "none",
"changelog": { "hidden": true }
"changelog": {
"hidden": true
}
}
}
},
Expand Down
Loading
Loading