Skip to content

Commit

Permalink
feat: automatic glint registration via importing /glint
Browse files Browse the repository at this point in the history
  • Loading branch information
NullVoxPopuli committed Jul 3, 2022
1 parent e8715f3 commit cfea170
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 16 deletions.
28 changes: 12 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,26 +159,22 @@ Usage:

### Glint

Having type checking with these state machines requires a wrapper function.
Having type checking with these state machines can be done automatically
after importing the `/glint` file in your `types/<app-name>/glint-registry.d.ts`.

```ts
// app/components/my-component.ts
import { createMachine } from 'xstate';
import { asComponent } from 'ember-statechart-component/glint';

export const machine = createMachine(/* ... */);

export default asComponent(machine);
```
or, if you want 0 runtime cost there is a more verbose, type-only option:
```ts
// app/components/my-component.ts
import { createMachine } from 'xstate';
import type { MachineComponent } from 'ember-statechart-component/glint';
import "@glint/environment-ember-loose";
import "@glint/environment-ember-loose/native-integration";
import "ember-page-title/glint";

export const machine = createMachine(/* ... */);
// This import extends the type of `StateMachine` to be glint-compatible
import 'ember-statechart-component/glint';

export default machine as unknown as MachineComponent<typeof machine>;
declare module "@glint/environment-ember-loose/registry" {
export default interface Registry {
// How to define globals from external addons
}
}
```

### API
Expand Down
37 changes: 37 additions & 0 deletions ember-statechart-component/src/glint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
import type { ComponentLike } from '@glint/template';
import type {
AnyStateMachine,
BaseActionObject,
ContextFrom,
EventFrom,
EventObject,
Interpreter,
MachineConfig,
NoInfer,
ResolveTypegenMeta,
ServiceMap,
StateFrom,
StateMachine,
StateSchema,
TypegenDisabled,
Typestate,
} from 'xstate';

type StateSchemaFrom<T> = T extends StateMachine<any, infer U, any> ? U : StateSchema;
Expand All @@ -28,6 +35,36 @@ export type MachineComponent<T extends AnyStateMachine = any> = ComponentLike<{
};
}>;

declare module 'xstate' {
// We need to
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface StateMachine<
TContext,
TStateSchema extends StateSchema,
TEvent extends EventObject,
TTypestate extends Typestate<TContext> = { value: any; context: TContext },
TAction extends BaseActionObject = BaseActionObject,
TServiceMap extends ServiceMap = ServiceMap,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
TResolvedTypesMeta = ResolveTypegenMeta<TypegenDisabled, NoInfer<TEvent>, TAction, TServiceMap>
> extends ComponentLike<{
Args: {
config?: MachineConfig<TContext, TStateSchema, TEvent>;
context?: TContext;
state?: Interpreter<TContext, TStateSchema, TEvent, TTypestate>['state'];
};
Blocks: {
default: [
Interpreter<TContext, TStateSchema, TEvent, TTypestate>['state'],
Interpreter<TContext, TStateSchema, TEvent, TTypestate>['send'],
Interpreter<TContext, TStateSchema, TEvent, TTypestate>['onTransition']
];
};
}> {
// Intentionally empty as we're changing StateMachine to extend from ComponentLike
}
}

export function asComponent<T extends AnyStateMachine = any>(machine: T): MachineComponent<T> {
return machine as unknown as MachineComponent<T>;
}

0 comments on commit cfea170

Please sign in to comment.