Skip to content

Commit d3e09d2

Browse files
Merge pull request #503 from NullVoxPopuli/fix-matches
Fix .matches alias method
2 parents f3ce949 + 668ecfe commit d3e09d2

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

ember-statechart-component/src/-private/statechart-manager.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@ const STOP = Symbol.for('__ESM__STOP__');
1313
const START = Symbol.for('__ESM__START__');
1414
const HANDLE_UPDATE = Symbol.for('__ESM__HANDLE_UPDATE__');
1515

16+
/**
17+
* https://stately.ai/docs/migration#the-statetostrings-method-has-been-removed
18+
*/
19+
function getStateValueStrings(stateValue) {
20+
if (typeof stateValue === 'string') {
21+
return [stateValue];
22+
}
23+
24+
const valueKeys = Object.keys(stateValue);
25+
26+
return valueKeys.concat(
27+
...valueKeys.map((key) => getStateValueStrings(stateValue[key]).map((s) => key + '.' + s))
28+
);
29+
}
30+
1631
class ReactiveActor {
1732
/**
1833
* @private
@@ -39,10 +54,11 @@ class ReactiveActor {
3954
/**
4055
* @type {import('xstate').Snapshot['matches']}
4156
*/
42-
matches = (...args) => this.actor.matches(...args);
57+
matches = (...args) => this.snapshot.matches(...args);
4358

4459
/**
45-
* The dot-separated name of the current state
60+
* The dot-separated name of the current state.
61+
* If multiple states are active, those well be comma-separated
4662
*/
4763
get statePath() {
4864
let x = this.value;
@@ -54,8 +70,7 @@ class ReactiveActor {
5470
if (typeof x === 'object') {
5571
if (!x) return '';
5672

57-
if ('toStrings' in x) return x.toStrings();
58-
if ('toString' in x) return x.toString();
73+
return getStateValueStrings(x).join(',');
5974
}
6075

6176
return `${x}`;

ember-statechart-component/src/public-types.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,12 @@ interface Signature<
160160
*/
161161
send: typeof send;
162162

163+
/**
164+
* Alias for snapshot.matches,
165+
* returns true of the passed state path is active.
166+
*/
167+
matches: (statePath: string) => boolean;
168+
163169
/**
164170
* The Machine's Snapshot
165171
*/

test-app/tests/integration/usage-test.gts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,40 @@ module('Usage', function (hooks) {
143143
assert.dom().containsText('The active state');
144144
});
145145

146+
test(`it can use the wrapped matches function`, async function (assert) {
147+
const Toggle = createMachine({
148+
initial: 'inactive',
149+
states: {
150+
inactive: { on: { TOGGLE: 'active' } },
151+
active: { on: { TOGGLE: 'inactive' } },
152+
},
153+
});
154+
155+
await render(
156+
<template>
157+
<Toggle as |toggler|>
158+
{{#if (call toggler toggler.matches "inactive")}}
159+
The inactive state
160+
{{else if (call toggler toggler.matches "active")}}
161+
The active state
162+
{{else}}
163+
Unknown state
164+
{{/if}}
165+
166+
<button type="button" {{on "click" (fn toggler.send "TOGGLE")}}>
167+
Toggle
168+
</button>
169+
</Toggle>
170+
</template>
171+
);
172+
173+
assert.dom().containsText('The inactive state');
174+
175+
await click('button');
176+
177+
assert.dom().containsText('The active state');
178+
});
179+
146180
test('multiple invocations have their own state', async function (assert) {
147181
const Toggle = createMachine({
148182
initial: 'inactive',

0 commit comments

Comments
 (0)