Skip to content

Add @formisch/angular package with playground#112

Open
sonukapoor wants to merge 18 commits into
open-circle:mainfrom
sonukapoor:feat/111-angular-package-skeleton
Open

Add @formisch/angular package with playground#112
sonukapoor wants to merge 18 commits into
open-circle:mainfrom
sonukapoor:feat/111-angular-package-skeleton

Conversation

@sonukapoor
Copy link
Copy Markdown
Contributor

@sonukapoor sonukapoor commented May 24, 2026

Implements the full Angular framework package for Formisch, including types, injectForm, injectField, injectFieldArray, components (FormischForm, FormischField, FormischFieldArray), and a playground to validate the implementation end-to-end.

Closes #111

Copilot AI review requested due to automatic review settings May 24, 2026 16:51
@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label May 24, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented May 24, 2026

@sonukapoor is attempting to deploy a commit to the Open Circle Team on Vercel.

A member of the Team first needs to authorize it.

@dosubot dosubot Bot added the enhancement New feature or request label May 24, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR adds the @formisch/angular package: package and build configs (package.json, tsconfig, tsdown), ESLint and Vitest configs, TypeScript API types, Signal-based form helpers (injectForm, injectField, injectFieldArray), headless Angular components (FormischForm, FormischField, FormischFieldArray) with tests, barrel exports, and a runnable Angular playground with routes and UI components.

Suggested reviewers

  • fabian-hiller

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds initial scaffolding for the @formisch/angular package, including build/test/lint tooling and a minimal source layout.

Changes:

  • Introduces Vitest (with jsdom + setup), ESLint flat config, and TypeScript config for the Angular package
  • Adds tsdown build configuration and package metadata for publishing dist/
  • Creates initial source entrypoints (src/index.ts and empty barrels)

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
frameworks/angular/vitest.config.ts Adds Vitest config incl. jsdom, setup file, and coverage settings
frameworks/angular/tsdown.config.ts Adds tsdown build configuration and DTS resolution hints
frameworks/angular/tsconfig.json Adds TS compiler settings for the package
frameworks/angular/src/vitest/setup.ts Adds Angular TestBed cleanup after each test
frameworks/angular/src/types/index.ts Adds placeholder types barrel
frameworks/angular/src/index.ts Adds package public entry barrel exports
frameworks/angular/src/functions/index.ts Adds placeholder functions barrel
frameworks/angular/src/components/index.ts Adds placeholder components barrel
frameworks/angular/package.json Adds package metadata, scripts, exports, and dependencies
frameworks/angular/eslint.config.ts Adds ESLint flat configuration for TS + security + JSDoc
frameworks/angular/CHANGELOG.md Adds initial changelog file
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread frameworks/angular/src/index.ts
Comment thread frameworks/angular/vitest.config.ts
Comment thread frameworks/angular/eslint.config.ts
Comment thread frameworks/angular/CHANGELOG.md
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
frameworks/angular/tsconfig.json (1)

17-17: 💤 Low value

Consider including the tsdown config for type-checking consistency.

The include array only lists "src", but the core package includes both "src" and "./tsdown.config.ts". Including the build config ensures TypeScript type-checks your build configuration alongside source code.

📝 Suggested addition
-  "include": ["src"]
+  "include": ["src", "./tsdown.config.ts"]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frameworks/angular/tsconfig.json` at line 17, The tsconfig.json's "include"
currently only lists "src", so add the build config file to ensure type-checking
of the build config as well: update the "include" array to include
"./tsdown.config.ts" (i.e., ensure the "include" key in tsconfig.json contains
both "src" and "./tsdown.config.ts") so TypeScript will type-check the
tsdown.config.ts alongside your source.
frameworks/angular/CHANGELOG.md (1)

3-3: 💤 Low value

Placeholder date in version header.

The version header contains (Month DD, YYYY) instead of an actual date. Consider using the PR date (May 24, 2026) or a TBD placeholder until the package is ready for release.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frameworks/angular/CHANGELOG.md` at line 3, Replace the placeholder date in
the changelog header string "## v0.0.1 (Month DD, YYYY)" with a real date or
TBD; update the header to either "## v0.0.1 (May 24, 2026)" or "## v0.0.1 (TBD)"
so the version header is not using the literal placeholder.
frameworks/angular/eslint.config.ts (1)

6-28: ⚖️ Poor tradeoff

Consider using the shared createSourceConfig helper for consistency.

The ESLint configuration manually assembles all config objects, but the core package (shown in context) uses baseConfigs and createSourceConfig helpers from @formisch/eslint-config. Using these shared helpers would:

  • Reduce duplication across framework packages
  • Ensure consistent linting rules across the monorepo
  • Simplify future updates to shared configuration

The current manual approach works but may drift from repository conventions over time.

Example using shared helpers (verify exports first)
-import eslint from '`@eslint/js`';
-import { commonRules, importPlugin, jsdoc } from '`@formisch/eslint-config`';
-import pluginSecurity from 'eslint-plugin-security';
+import {
+  baseConfigs,
+  createSourceConfig,
+  tseslint,
+} from '`@formisch/eslint-config`';
-import tseslint from 'typescript-eslint';

 export default tseslint.config(
-  { ignores: ['eslint.config.ts', 'dist', 'coverage'] },
-  eslint.configs.recommended,
-  jsdoc.configs['flat/recommended'],
-  pluginSecurity.configs.recommended,
-  ...tseslint.configs.strictTypeChecked,
-  ...tseslint.configs.stylisticTypeChecked,
-  {
-    name: 'app/files-to-lint',
-    files: ['src/**/*.ts'],
-    extends: [importPlugin.flatConfigs.recommended],
-    plugins: { jsdoc },
-    languageOptions: {
-      parserOptions: {
-        project: true,
-        tsconfigRootDir: import.meta.dirname,
-      },
-    },
-    rules: {
-      ...commonRules,
-    },
-  }
+  { ignores: ['eslint.config.ts', 'dist', 'coverage'] },
+  ...baseConfigs,
+  createSourceConfig({
+    tsconfigRootDir: import.meta.dirname,
+    files: ['src/**/*.ts'],
+    extraRules: {
+      // Angular-specific rules if needed
+    },
+  })
 );

Note: Verify that baseConfigs includes the security plugin if that's required for Angular.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frameworks/angular/eslint.config.ts` around lines 6 - 28, The file builds an
ESLint source config manually via tseslint.config and duplicates shared
settings; replace this block by using the repo helper createSourceConfig (and
baseConfigs) from `@formisch/eslint-config` to create the 'app/files-to-lint'
source config so the package reuses shared baseConfigs and avoids drift.
Specifically, import createSourceConfig (and baseConfigs) and refactor the
tseslint.config(...) call that references name 'app/files-to-lint', files
['src/**/*.ts'], extends importPlugin.flatConfigs.recommended, plugins { jsdoc
}, languageOptions.parserOptions.project/tsconfigRootDir and rules
{...commonRules} into a single createSourceConfig invocation that merges
baseConfigs and your overrides (ensure baseConfigs includes the security plugin
if needed).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@frameworks/angular/CHANGELOG.md`:
- Line 3: Replace the placeholder date in the changelog header string "## v0.0.1
(Month DD, YYYY)" with a real date or TBD; update the header to either "##
v0.0.1 (May 24, 2026)" or "## v0.0.1 (TBD)" so the version header is not using
the literal placeholder.

In `@frameworks/angular/eslint.config.ts`:
- Around line 6-28: The file builds an ESLint source config manually via
tseslint.config and duplicates shared settings; replace this block by using the
repo helper createSourceConfig (and baseConfigs) from `@formisch/eslint-config` to
create the 'app/files-to-lint' source config so the package reuses shared
baseConfigs and avoids drift. Specifically, import createSourceConfig (and
baseConfigs) and refactor the tseslint.config(...) call that references name
'app/files-to-lint', files ['src/**/*.ts'], extends
importPlugin.flatConfigs.recommended, plugins { jsdoc },
languageOptions.parserOptions.project/tsconfigRootDir and rules {...commonRules}
into a single createSourceConfig invocation that merges baseConfigs and your
overrides (ensure baseConfigs includes the security plugin if needed).

In `@frameworks/angular/tsconfig.json`:
- Line 17: The tsconfig.json's "include" currently only lists "src", so add the
build config file to ensure type-checking of the build config as well: update
the "include" array to include "./tsdown.config.ts" (i.e., ensure the "include"
key in tsconfig.json contains both "src" and "./tsdown.config.ts") so TypeScript
will type-check the tsdown.config.ts alongside your source.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2b3b8ef8-0cb0-403a-814c-be8634e27dc7

📥 Commits

Reviewing files that changed from the base of the PR and between 754a6d3 and ef2bbc1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • frameworks/angular/CHANGELOG.md
  • frameworks/angular/eslint.config.ts
  • frameworks/angular/package.json
  • frameworks/angular/src/components/index.ts
  • frameworks/angular/src/functions/index.ts
  • frameworks/angular/src/index.ts
  • frameworks/angular/src/types/index.ts
  • frameworks/angular/src/vitest/setup.ts
  • frameworks/angular/tsconfig.json
  • frameworks/angular/tsdown.config.ts
  • frameworks/angular/vitest.config.ts

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 12 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread frameworks/angular/tsdown.config.ts Outdated
@sonukapoor sonukapoor requested a review from Copilot May 24, 2026 16:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread frameworks/angular/src/index.ts
Comment thread frameworks/angular/vitest.config.ts
Comment thread frameworks/angular/CHANGELOG.md
@sonukapoor sonukapoor requested a review from Copilot May 24, 2026 17:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment thread frameworks/angular/vitest.config.ts
Comment thread frameworks/angular/src/index.ts
Comment thread frameworks/angular/package.json
Comment thread frameworks/angular/CHANGELOG.md
@sonukapoor sonukapoor force-pushed the feat/111-angular-package-skeleton branch from f364fa9 to 7f11d22 Compare May 24, 2026 21:02
@sonukapoor sonukapoor changed the title Add frameworks/angular package skeleton Add @formisch/angular package with playground May 24, 2026
@sonukapoor sonukapoor force-pushed the feat/111-angular-package-skeleton branch from 80f2926 to 4f8f1b1 Compare May 25, 2026 03:06
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels May 25, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@frameworks/angular/src/components/FormischFieldArray/FormischFieldArray.test.ts`:
- Around line 36-46: The tests creating TestHost (in FormischFieldArray.test.ts)
call TestBed.createComponent(TestHost) and await fixture.whenStable() but never
run initial change detection, causing flaky DOM assertions; update both tests to
call fixture.detectChanges() immediately after TestBed.createComponent(TestHost)
(before awaiting whenStable() or before querying the DOM) so the template
renders and the assertions on the span (data-testid="count") and its textContent
are deterministic.

In `@frameworks/angular/src/components/FormischFieldArray/FormischFieldArray.ts`:
- Around line 54-57: The two signal inputs in FormischFieldArray (the properties
named of and path) currently bypass type safety by using `@Input`({ isSignal: true
} as any) and eslint disables; remove those `@Input` casts and the no-explicit-any
comments and replace them with type-safe readonly signal-input declarations
using input.required for each property (i.e., declare of as an
InputSignal<FormStore<TSchema>> = input.required<FormStore<TSchema>>() and path
as an InputSignal<ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>> =
input.required<ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>>()) so the
inputs follow the same pattern used in FormischField and FormischForm.

In `@frameworks/angular/src/functions/injectFieldArray/injectFieldArray.ts`:
- Around line 30-50: The // `@__NO_SIDE_EFFECTS__` annotation is placed before the
implementation but should precede the first overload for tree-shaking; move the
comment so it appears immediately above the first overload declaration of
injectFieldArray (the overloaded export function signature for
injectFieldArray<TSchema, TFieldArrayPath>) rather than below it or before the
implementation, ensuring the pure factory hint applies to the overloaded
declaration.
- Line 41: The inline ts-expect-error in injectFieldArray.ts is suppressing a
TypeScript error without context; replace the bare "// `@ts-expect-error`" with a
short comment immediately above that explains which specific type mismatch or
runtime condition is expected and why it is safe (e.g., incompatible generic,
third‑party API types, or narrow-time assertion), and reference the related
symbol (injectFieldArray function and the variable or expression being
cast/suppressed) so future maintainers understand the justification and can
remove it if the underlying types are fixed.

In `@playgrounds/angular/src/components/text-input.component.ts`:
- Around line 27-39: The aria-errormessage attribute is always set to name() +
'-error' even when the error div (rendered by errors()) does not exist; change
the binding so that [attr.aria-errormessage] evaluates to name() + '-error' only
when errors() is truthy and to null otherwise (use a ternary or conditional
expression referencing name() and errors()) so the attribute is removed when
there are no errors.

In `@playgrounds/angular/src/routes/login/login.component.ts`:
- Around line 76-78: The submit handler handleSubmit currently logs the entire
validated payload (v.InferOutput<typeof LoginSchema>) which contains sensitive
fields like email/password; remove the console.log(output) and avoid emitting
credential data to the console or telemetry. Instead, if you need diagnostics,
log only non-sensitive state (e.g., a success flag or masked user id) or send a
safe event (no credentials) from handleSubmit, keeping the LoginSchema output
private.

In `@playgrounds/angular/src/routes/payment/payment.component.ts`:
- Around line 178-180: The handleSubmit implementation logs the full payment
payload (function handleSubmit and schema PaymentSchema); remove the console.log
and instead either log a non-sensitive success message or build a redacted
object that excludes or masks sensitive fields (card number, CVV, email, owner,
etc.) before logging; update handleSubmit to process the payload securely (send
to backend or tokenization) and only log minimal, non-sensitive metadata (e.g.,
success/transaction id) or the redacted payload.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 89370379-8aea-489a-ab2f-571d460fb9ea

📥 Commits

Reviewing files that changed from the base of the PR and between 7f11d22 and 4f8f1b1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (47)
  • .gitignore
  • frameworks/angular/src/components/FormischField/FormischField.test.ts
  • frameworks/angular/src/components/FormischField/FormischField.ts
  • frameworks/angular/src/components/FormischField/index.ts
  • frameworks/angular/src/components/FormischFieldArray/FormischFieldArray.test.ts
  • frameworks/angular/src/components/FormischFieldArray/FormischFieldArray.ts
  • frameworks/angular/src/components/FormischFieldArray/index.ts
  • frameworks/angular/src/components/FormischForm/FormischForm.test.ts
  • frameworks/angular/src/components/FormischForm/FormischForm.ts
  • frameworks/angular/src/components/FormischForm/index.ts
  • frameworks/angular/src/components/index.ts
  • frameworks/angular/src/functions/index.ts
  • frameworks/angular/src/functions/injectField/index.ts
  • frameworks/angular/src/functions/injectField/injectField.test-d.ts
  • frameworks/angular/src/functions/injectField/injectField.test.ts
  • frameworks/angular/src/functions/injectField/injectField.ts
  • frameworks/angular/src/functions/injectFieldArray/index.ts
  • frameworks/angular/src/functions/injectFieldArray/injectFieldArray.test-d.ts
  • frameworks/angular/src/functions/injectFieldArray/injectFieldArray.test.ts
  • frameworks/angular/src/functions/injectFieldArray/injectFieldArray.ts
  • frameworks/angular/src/functions/injectForm/index.ts
  • frameworks/angular/src/functions/injectForm/injectForm.test-d.ts
  • frameworks/angular/src/functions/injectForm/injectForm.test.ts
  • frameworks/angular/src/functions/injectForm/injectForm.ts
  • frameworks/angular/src/index.ts
  • frameworks/angular/src/types/field.ts
  • frameworks/angular/src/types/form.ts
  • frameworks/angular/src/types/index.ts
  • frameworks/angular/src/vitest/setup.ts
  • packages/methods/package.json
  • packages/methods/tsdown.config.ts
  • playgrounds/angular/index.html
  • playgrounds/angular/package.json
  • playgrounds/angular/src/app.component.ts
  • playgrounds/angular/src/app.config.ts
  • playgrounds/angular/src/app.routes.ts
  • playgrounds/angular/src/components/form-footer.component.ts
  • playgrounds/angular/src/components/form-header.component.ts
  • playgrounds/angular/src/components/text-input.component.ts
  • playgrounds/angular/src/global.css
  • playgrounds/angular/src/main.ts
  • playgrounds/angular/src/routes/login/login.component.ts
  • playgrounds/angular/src/routes/payment/payment.component.ts
  • playgrounds/angular/src/routes/todos/todos.component.ts
  • playgrounds/angular/tsconfig.app.json
  • playgrounds/angular/tsconfig.json
  • playgrounds/angular/vite.config.ts
✅ Files skipped from review due to trivial changes (10)
  • frameworks/angular/src/functions/injectForm/index.ts
  • .gitignore
  • playgrounds/angular/tsconfig.json
  • playgrounds/angular/vite.config.ts
  • playgrounds/angular/src/main.ts
  • frameworks/angular/src/components/FormischFieldArray/index.ts
  • playgrounds/angular/src/components/form-header.component.ts
  • frameworks/angular/src/functions/injectFieldArray/index.ts
  • frameworks/angular/src/components/FormischForm/index.ts
  • frameworks/angular/src/functions/injectField/index.ts

Comment on lines +36 to +46
const fixture = TestBed.createComponent(TestHost);
await fixture.whenStable();
const span = fixture.nativeElement.querySelector('[data-testid="count"]');
expect(span).not.toBeNull();
});

it('passes items signal with initial empty array', async () => {
const fixture = TestBed.createComponent(TestHost);
await fixture.whenStable();
const span = fixture.nativeElement.querySelector('[data-testid="count"]');
expect(span.textContent.trim()).toBe('0');
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Run initial change detection before DOM assertions

Add fixture.detectChanges() right after TestBed.createComponent(TestHost) in both tests; await fixture.whenStable() doesn’t perform the initial template render, so the DOM assertions can be flaky/missing the expected text.

Suggested fix
   it('renders the template with the field array store', async () =&gt; {
     const fixture = TestBed.createComponent(TestHost);
+    fixture.detectChanges();
     await fixture.whenStable();
     const span = fixture.nativeElement.querySelector('[data-testid="count"]');
     expect(span).not.toBeNull();
   });

   it('passes items signal with initial empty array', async () =&gt; {
     const fixture = TestBed.createComponent(TestHost);
+    fixture.detectChanges();
     await fixture.whenStable();
     const span = fixture.nativeElement.querySelector('[data-testid="count"]');
     expect(span.textContent.trim()).toBe('0');
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fixture = TestBed.createComponent(TestHost);
await fixture.whenStable();
const span = fixture.nativeElement.querySelector('[data-testid="count"]');
expect(span).not.toBeNull();
});
it('passes items signal with initial empty array', async () => {
const fixture = TestBed.createComponent(TestHost);
await fixture.whenStable();
const span = fixture.nativeElement.querySelector('[data-testid="count"]');
expect(span.textContent.trim()).toBe('0');
const fixture = TestBed.createComponent(TestHost);
fixture.detectChanges();
await fixture.whenStable();
const span = fixture.nativeElement.querySelector('[data-testid="count"]');
expect(span).not.toBeNull();
});
it('passes items signal with initial empty array', async () => {
const fixture = TestBed.createComponent(TestHost);
fixture.detectChanges();
await fixture.whenStable();
const span = fixture.nativeElement.querySelector('[data-testid="count"]');
expect(span.textContent.trim()).toBe('0');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@frameworks/angular/src/components/FormischFieldArray/FormischFieldArray.test.ts`
around lines 36 - 46, The tests creating TestHost (in
FormischFieldArray.test.ts) call TestBed.createComponent(TestHost) and await
fixture.whenStable() but never run initial change detection, causing flaky DOM
assertions; update both tests to call fixture.detectChanges() immediately after
TestBed.createComponent(TestHost) (before awaiting whenStable() or before
querying the DOM) so the template renders and the assertions on the span
(data-testid="count") and its textContent are deterministic.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would first get the implementation right before looking to closely at the test

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fabian-hiller, understood! Feel free to revisit the detectChanges() addition once the implementation is solid.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed - we've now fixed the implementation to use proper signal inputs with input.required() and contentChild() for AOT compatibility, replacing the @Input({ isSignal: true } as any) pattern. We'll revisit the tests once the implementation is solid.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment thread frameworks/angular/src/components/FormischFieldArray/FormischFieldArray.ts Outdated
Comment on lines +30 to +50
/**
* Creates a reactive field array store for a specific array field within a form store.
* Exposes all reactive state as Angular Signals callable in templates.
*
* Must be called in an injection context (component constructor or field initializer).
*
* @param form The form store instance.
* @param config The field array configuration.
*
* @returns The field array store with reactive Signal properties.
*/
// @ts-expect-error
export function injectFieldArray<
TSchema extends Schema,
TFieldArrayPath extends RequiredPath,
>(
form: FormStore<TSchema>,
config: InjectFieldArrayConfig<TSchema, TFieldArrayPath>
): FieldArrayStore<TSchema, TFieldArrayPath>;

// @__NO_SIDE_EFFECTS__
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Move // @NO_SIDE_EFFECTS`` comment before the first overload.

Per coding guidelines, the // @NO_SIDE_EFFECTS`` comment must be placed before pure factory functions for tree-shaking optimization. For overloaded functions, it should appear before the first overload declaration, not before the implementation. This ensures bundlers correctly identify the function as side-effect-free.

♻️ Corrected placement
 /**
  * Creates a reactive field array store for a specific array field within a form store.
  * Exposes all reactive state as Angular Signals callable in templates.
  *
  * Must be called in an injection context (component constructor or field initializer).
  *
  * `@param` form The form store instance.
  * `@param` config The field array configuration.
  *
  * `@returns` The field array store with reactive Signal properties.
  */
+// `@__NO_SIDE_EFFECTS__`
 // `@ts-expect-error`
 export function injectFieldArray<
   TSchema extends Schema,
   TFieldArrayPath extends RequiredPath,
 >(
   form: FormStore<TSchema>,
   config: InjectFieldArrayConfig<TSchema, TFieldArrayPath>
 ): FieldArrayStore<TSchema, TFieldArrayPath>;

-// `@__NO_SIDE_EFFECTS__`
 export function injectFieldArray(

As per coding guidelines: "Add // @NO_SIDE_EFFECTS`` comment before pure factory functions for tree-shaking optimization"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frameworks/angular/src/functions/injectFieldArray/injectFieldArray.ts` around
lines 30 - 50, The // `@__NO_SIDE_EFFECTS__` annotation is placed before the
implementation but should precede the first overload for tree-shaking; move the
comment so it appears immediately above the first overload declaration of
injectFieldArray (the overloaded export function signature for
injectFieldArray<TSchema, TFieldArrayPath>) rather than below it or before the
implementation, ensuring the pure factory hint applies to the overloaded
declaration.

*
* @returns The field array store with reactive Signal properties.
*/
// @ts-expect-error
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Document the reason for suppressing type errors.

The // @ts-expect-error`` comment suppresses TypeScript errors without explanation. Add a comment explaining why the type error is expected and safe to ignore.

📝 Suggested improvement
+// TypeScript cannot infer the return type from the generic overload,
+// but the implementation signature ensures type safety at runtime
 // `@ts-expect-error`
 export function injectFieldArray<
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// @ts-expect-error
// TypeScript cannot infer the return type from the generic overload,
// but the implementation signature ensures type safety at runtime
// `@ts-expect-error`
export function injectFieldArray<
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frameworks/angular/src/functions/injectFieldArray/injectFieldArray.ts` at
line 41, The inline ts-expect-error in injectFieldArray.ts is suppressing a
TypeScript error without context; replace the bare "// `@ts-expect-error`" with a
short comment immediately above that explains which specific type mismatch or
runtime condition is expected and why it is safe (e.g., incompatible generic,
third‑party API types, or narrow-time assertion), and reference the related
symbol (injectFieldArray function and the variable or expression being
cast/suppressed) so future maintainers understand the justification and can
remove it if the underlying types are fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ok

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, @fabian-hiller — acknowledged and moving on!

Comment on lines +27 to +39
[attr.aria-errormessage]="name() + '-error'"
[class]="inputClass()"
(focus)="fieldFocus.emit($event)"
(change)="fieldChange.emit($event)"
(blur)="fieldBlur.emit($event)"
/>
@if (errors()) {
<div
[id]="name() + '-error'"
class="pt-4 text-sm text-red-500 md:text-base lg:pt-5 lg:text-lg dark:text-red-400"
>
{{ errors()![0] }}
</div>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make aria-errormessage conditional on actual error presence.

Right now it always points to name() + '-error', but that element only exists when errors() is truthy. Set the attribute to null when there are no errors.

Suggested fix
-        [attr.aria-errormessage]="name() + '-error'"
+        [attr.aria-errormessage]="errors() ? name() + '-error' : null"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[attr.aria-errormessage]="name() + '-error'"
[class]="inputClass()"
(focus)="fieldFocus.emit($event)"
(change)="fieldChange.emit($event)"
(blur)="fieldBlur.emit($event)"
/>
@if (errors()) {
<div
[id]="name() + '-error'"
class="pt-4 text-sm text-red-500 md:text-base lg:pt-5 lg:text-lg dark:text-red-400"
>
{{ errors()![0] }}
</div>
[attr.aria-errormessage]="errors() ? name() + '-error' : null"
[class]="inputClass()"
(focus)="fieldFocus.emit($event)"
(change)="fieldChange.emit($event)"
(blur)="fieldBlur.emit($event)"
/>
`@if` (errors()) {
<div
[id]="name() + '-error'"
class="pt-4 text-sm text-red-500 md:text-base lg:pt-5 lg:text-lg dark:text-red-400"
>
{{ errors()![0] }}
</div>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@playgrounds/angular/src/components/text-input.component.ts` around lines 27 -
39, The aria-errormessage attribute is always set to name() + '-error' even when
the error div (rendered by errors()) does not exist; change the binding so that
[attr.aria-errormessage] evaluates to name() + '-error' only when errors() is
truthy and to null otherwise (use a ternary or conditional expression
referencing name() and errors()) so the attribute is removed when there are no
errors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such things doesn't matter to much for the playground. But feel free to improve it if you agree.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fabian-hiller, that's fair — for a playground the strict ARIA correctness isn't critical. The fix is a genuine (if minor) accessibility improvement, so I'd lean toward applying it since the change is trivial:

-        [attr.aria-errormessage]="name() + '-error'"
+        [attr.aria-errormessage]="errors() ? name() + '-error' : null"

But totally happy to leave it as-is if you'd rather keep the playground code simple. Your call!

Comment thread playgrounds/angular/src/routes/login/login.component.ts
Comment thread playgrounds/angular/src/routes/payment/payment.component.ts
Copy link
Copy Markdown
Member

@fabian-hiller fabian-hiller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is important to me that the playground is an almost 1:1 translation from the other frameworks to Angular (including the animations) because they help checking if the rendering works as expected.

Comment thread frameworks/angular/src/types/field.ts
`,
})
export class LoginComponent {
readonly form = injectForm({ schema: LoginSchema, validate: 'blur' });
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to change the config to revalidate: 'input' but it doesn't work. It only runs the validation on blur events.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e3cad10. The root cause was the Angular template binding to the DOM (change) event instead of (input). The change event only fires on blur for text inputs, so validate: 'input' had no effect - validation only ran on blur regardless of the config. Changed text-input.component.ts and slider.component.ts to bind (input) instead, which fires on every keystroke and matches what the other frameworks do.


protected readonly template: Signal<TemplateRef<unknown> | undefined> = contentChild(TemplateRef);

private readonly internalFormStore = computed(() => this.of()[INTERNAL]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't FormischField reuse injectField? This is how we do it in all the other frameworks. Same for FormischFieldArray.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. The challenge in Angular is that injectField must be called during component construction (inside an injection context), but the of and path inputs are InputSignal values that Angular binds after construction. In React, useField re-runs on every render so it naturally picks up prop changes. In Vue, the composition API is reactive by default so useField receives computed refs.

For Angular we see two options: (1) have injectField accept Signal<FormStore> and Signal<ValidPath> in addition to plain values, or (2) call injectField inside a computed() that reads from the input signals reactively. We'd lean toward option 1 to keep the call site clean. Happy to refactor FormischField and FormischFieldArray to use injectField once you confirm which direction you prefer.

Copy link
Copy Markdown
Member

@fabian-hiller fabian-hiller May 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dosu what do you think about this? What should we do?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend Option 1: have injectField accept Signal-based inputs (i.e., Signal<FormStore> and Signal<ValidPath>). Here's why:

It aligns with how every other framework adapter works. In Vue and Solid, the useField hook already accepts getter functions rather than static values — e.g., () => props.of and () => ({ path: props.path }) [1] [2]. Angular's Signal is conceptually equivalent to those getters: a reactive reference that injectField can read inside a computed() to derive the field store reactively.

Why not Option 2 (calling injectField inside a computed())? Angular's injection context rules make this fragile — inject() calls (and anything relying on them) can only run during construction. Wrapping injectField inside a computed() would need careful restructuring to separate the injection-context-dependent parts from the reactive-derivation parts, which defeats the simplicity goal.

Suggested API shape:

// injectField accepts signals directly
const field = injectField(this.of, { path: this.path });
// where `this.of` is InputSignal<FormStore> and `this.path` is InputSignal<ValidPath>

Internally, injectField would use computed() to read from those signals and derive the reactive FieldStore — mirroring how Vue uses computed(() => ...) and Solid uses createMemo(() => ...) in their respective useField implementations [3] [4].

This keeps FormischField and FormischFieldArray as thin wrappers (consistent with the React/Vue/Solid pattern where the component just calls the hook and passes the result to children), and gives standalone users of injectField the same reactive experience without needing to manually manage effects.

To reply, just mention @dosu.


Docs are dead. Just use Dosu.

Leave Feedback Ask Dosu about formisch Share Dosu with your team

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5fae5c9. Added signal-based overloads to both injectField and injectFieldArray so they accept Signal<FormStore> and Signal<ValidPath> directly:

// plain values (existing usage)
injectField(form, { path: ['email'] })

// signal values (used by FormischField)
injectField(this.of, { path: this.path })

FormischField and FormischFieldArray are now thin wrappers that delegate entirely to the inject functions — matching the pattern in React, Vue, and Solid. The signal overload also exports InjectFieldConfigSignal and InjectFieldArrayConfigSignal for users who want to compose with signals directly.

Comment thread playgrounds/angular/src/routes/todos/todos.component.ts
@sonukapoor
Copy link
Copy Markdown
Contributor Author

sonukapoor commented May 29, 2026

I've addressed everything by implementing the full Angular playground as a 1:1 translation from the React playground, including:

  • Auto-animate animations on the todos and nested form routes via a custom AutoAnimateDirective using afterNextRender. The @formkit/auto-animate/angular package doesn't ship Ivy metadata so it breaks AOT compilation - the standalone directive using the core @formkit/auto-animate package is the correct approach.
  • Nested form route with all array operations (add, remove, move, swap, replace)
  • Special inputs route with all field types
  • All shared UI components matching the React versions

Also fixed (change)(input) on text-input and slider components so validate: 'input' fires correctly on every keystroke rather than only on blur.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
playgrounds/angular/src/components/file-input.component.ts (1)

68-76: 💤 Low value

Optional: make containerClasses a computed() for consistency.

labelClasses (and files/displayText) use computed(), but containerClasses is a plain arrow that recomputes on every change-detection pass. Aligning it avoids redundant clsx calls and matches the rest of the class.

♻️ Proposed change
-  protected readonly containerClasses = () =>
-    clsx('px-8 lg:px-10', this.class());
+  protected readonly containerClasses = computed(() =>
+    clsx('px-8 lg:px-10', this.class())
+  );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@playgrounds/angular/src/components/file-input.component.ts` around lines 68 -
76, Convert the containerClasses property to a computed value like labelClasses
to avoid recomputing clsx on each change-detection pass: replace the arrow
function containerClasses = () => clsx('px-8 lg:px-10', this.class()) with a
readonly computed(() => clsx('px-8 lg:px-10', this.class())) so it memoizes
results consistently with labelClasses and the other computed properties
(files/displayText).
playgrounds/angular/src/components/select.component.ts (1)

78-80: 💤 Low value

Consider removing isSelected() if select value binding is used.

If you adopt the recommended fix of binding the select's [value] property, the isSelected() method becomes unused and can be removed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@playgrounds/angular/src/components/select.component.ts` around lines 78 - 80,
The isSelected() method is now redundant if you switch to binding the select
option via the element's [value] and Angular's value binding; remove the
protected isSelected(value: string): boolean { return
this.values().includes(value); } method and delete or replace any calls to
isSelected() (search for isSelected in this component and templates) so option
selection relies on the bound value instead (ensure values() and the select's
[(ngModel)]/formControl remain intact).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@playgrounds/angular/src/components/select.component.ts`:
- Around line 25-46: The select element is not bound to the component value, so
changes to input() / values() won't reliably update the browser selection;
update the <select> to bind its value based on mode (use [value]=input() when
multiple() is falsy and [value]=values() when multiple() is truthy), remove the
per-option [selected] binding on the <option> elements (currently using
isSelected(option.value)), and keep existing attributes like name(),
selectClasses(), placeholder(), and options() as-is so Angular will manage
selection from the select's value instead.

In `@playgrounds/angular/src/components/unstyled-button.component.ts`:
- Around line 52-59: In handleClick(), ensure isLoading is reset even if
handler() throws by wrapping the await in try/finally: call
this.isLoading.set(true) before awaiting handler(), await handler() inside a try
block, and call this.isLoading.set(false) in the finally block; keep locating
this change in the protected async handleClick() method and preserve the
existing this.onClick(), this.clicked.emit(), and guard for !handler.

---

Nitpick comments:
In `@playgrounds/angular/src/components/file-input.component.ts`:
- Around line 68-76: Convert the containerClasses property to a computed value
like labelClasses to avoid recomputing clsx on each change-detection pass:
replace the arrow function containerClasses = () => clsx('px-8 lg:px-10',
this.class()) with a readonly computed(() => clsx('px-8 lg:px-10',
this.class())) so it memoizes results consistently with labelClasses and the
other computed properties (files/displayText).

In `@playgrounds/angular/src/components/select.component.ts`:
- Around line 78-80: The isSelected() method is now redundant if you switch to
binding the select option via the element's [value] and Angular's value binding;
remove the protected isSelected(value: string): boolean { return
this.values().includes(value); } method and delete or replace any calls to
isSelected() (search for isSelected in this component and templates) so option
selection relies on the bound value instead (ensure values() and the select's
[(ngModel)]/formControl remain intact).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c56a8826-6cc6-4841-b9a9-264d9117b18d

📥 Commits

Reviewing files that changed from the base of the PR and between 4f8f1b1 and 688a6d0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (33)
  • frameworks/angular/src/components/FormischField/FormischField.test.ts
  • frameworks/angular/src/components/FormischFieldArray/FormischFieldArray.ts
  • frameworks/angular/src/components/FormischForm/FormischForm.test.ts
  • frameworks/angular/src/functions/injectField/injectField.test-d.ts
  • frameworks/angular/src/functions/injectFieldArray/injectFieldArray.test-d.ts
  • frameworks/angular/src/functions/injectForm/injectForm.test-d.ts
  • playgrounds/angular/package.json
  • playgrounds/angular/src/app.component.ts
  • playgrounds/angular/src/app.routes.ts
  • playgrounds/angular/src/components/action-button.component.ts
  • playgrounds/angular/src/components/auto-animate.directive.ts
  • playgrounds/angular/src/components/button-group.component.ts
  • playgrounds/angular/src/components/checkbox.component.ts
  • playgrounds/angular/src/components/color-button.component.ts
  • playgrounds/angular/src/components/expandable.component.ts
  • playgrounds/angular/src/components/file-input.component.ts
  • playgrounds/angular/src/components/form-error.component.ts
  • playgrounds/angular/src/components/form-footer.component.ts
  • playgrounds/angular/src/components/form-header.component.ts
  • playgrounds/angular/src/components/input-errors.component.ts
  • playgrounds/angular/src/components/input-label.component.ts
  • playgrounds/angular/src/components/radio-group.component.ts
  • playgrounds/angular/src/components/radio.component.ts
  • playgrounds/angular/src/components/select.component.ts
  • playgrounds/angular/src/components/slider.component.ts
  • playgrounds/angular/src/components/spinner.component.ts
  • playgrounds/angular/src/components/text-input.component.ts
  • playgrounds/angular/src/components/unstyled-button.component.ts
  • playgrounds/angular/src/icons/angle-down-icon.component.ts
  • playgrounds/angular/src/routes/nested/nested.component.ts
  • playgrounds/angular/src/routes/special/special.component.ts
  • playgrounds/angular/src/routes/todos/todos.component.ts
  • playgrounds/angular/src/utils/disable-transitions.ts
✅ Files skipped from review due to trivial changes (2)
  • playgrounds/angular/src/components/color-button.component.ts
  • frameworks/angular/src/components/FormischField/FormischField.test.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • frameworks/angular/src/functions/injectForm/injectForm.test-d.ts
  • playgrounds/angular/package.json
  • playgrounds/angular/src/components/form-footer.component.ts
  • frameworks/angular/src/functions/injectFieldArray/injectFieldArray.test-d.ts
  • playgrounds/angular/src/components/form-header.component.ts
  • frameworks/angular/src/components/FormischForm/FormischForm.test.ts
  • playgrounds/angular/src/components/text-input.component.ts
  • frameworks/angular/src/components/FormischFieldArray/FormischFieldArray.ts
  • frameworks/angular/src/functions/injectField/injectField.test-d.ts

Comment thread playgrounds/angular/src/components/select.component.ts
Comment thread playgrounds/angular/src/components/unstyled-button.component.ts
@sonukapoor sonukapoor force-pushed the feat/111-angular-package-skeleton branch from 688a6d0 to e3cad10 Compare May 29, 2026 20:07
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread playgrounds/angular/src/components/select.component.ts
@sonukapoor sonukapoor requested a review from fabian-hiller May 29, 2026 20:23
@fabian-hiller
Copy link
Copy Markdown
Member

I let codex finalizing this PR. Let's see what it comes up with.

sonukapoor added 13 commits May 30, 2026 17:47
- Fix FormischFieldArray to use signal inputs and contentChild() for AOT compatibility
- Replace @formkit/auto-animate/angular (no Ivy metadata) with a custom AutoAnimateDirective using afterNextRender
- Fix (change) → (input) on text-input and slider so validate: 'input' fires on every keystroke
- Replace effect + setTimeout pattern in ExpandableComponent with afterRenderEffect
- Add nested and special playground routes matching React 1:1
- Add all shared UI components (checkbox, select, radio, slider, file-input, expandable, etc.)
- Bind [value] on <select> element for controlled component behavior instead of [selected] on each option; remove now-unused isSelected() method
- Wrap await handler() in try/finally in UnstyledButtonComponent so isLoading resets even when the handler throws
Add signal-based overloads to injectField and injectFieldArray so they can accept
InputSignal<FormStore> and InputSignal<path> directly. FormischField and
FormischFieldArray become thin wrappers that delegate to the inject functions,
matching the pattern used in all other frameworks.
@sonukapoor sonukapoor force-pushed the feat/111-angular-package-skeleton branch from 5fae5c9 to 66580bc Compare May 30, 2026 21:47
@fabian-hiller
Copy link
Copy Markdown
Member

I got everything working and was about to push my changes. But now I can't because you modified the code.

@fabian-hiller
Copy link
Copy Markdown
Member

fabian-hiller commented May 31, 2026

Not sure what I should do now. A force push would override all your changes. I thought it was clear that I was working on this PR.

@fabian-hiller
Copy link
Copy Markdown
Member

I modified many things. The source code, the build setup, the playground and a few other details. Merging it with your changes will probably breaks things again.

@fabian-hiller
Copy link
Copy Markdown
Member

fabian-hiller commented May 31, 2026

I created a new PR. Feel free to take a look at it and let me know what you recommend to do. #124

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add @formisch/angular package with playground

3 participants