Skip to content

Commit 5d73dda

Browse files
committed
fix: Fixed valueRef in bindable and normalizeProps
1 parent 891101f commit 5d73dda

12 files changed

Lines changed: 936 additions & 1046 deletions

File tree

package.json

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,31 @@
1111
},
1212
"private": true,
1313
"dependencies": {
14-
"@angular/animations": "^19.2.1",
15-
"@angular/cdk": "^19.2.2",
16-
"@angular/common": "^19.2.1",
17-
"@angular/compiler": "^19.2.1",
18-
"@angular/core": "^19.2.1",
19-
"@angular/forms": "^19.2.1",
20-
"@angular/platform-browser": "^19.2.1",
21-
"@angular/platform-browser-dynamic": "^19.2.1",
22-
"@angular/router": "^19.2.1",
23-
"@zag-js/accordion": "^1.3.3",
24-
"@zag-js/collapsible": "^1.3.3",
25-
"@zag-js/core": "^1.3.3",
26-
"@zag-js/menu": "^1.3.3",
27-
"@zag-js/tooltip": "^1.3.3",
28-
"@zag-js/types": "^1.3.3",
29-
"@zag-js/utils": "^1.3.3",
14+
"@angular/animations": "^19.2.2",
15+
"@angular/cdk": "^19.2.3",
16+
"@angular/common": "^19.2.2",
17+
"@angular/compiler": "^19.2.2",
18+
"@angular/core": "^19.2.2",
19+
"@angular/forms": "^19.2.2",
20+
"@angular/platform-browser": "^19.2.2",
21+
"@angular/platform-browser-dynamic": "^19.2.2",
22+
"@angular/router": "^19.2.2",
23+
"@zag-js/accordion": "^1.4.0",
24+
"@zag-js/collapsible": "^1.4.0",
25+
"@zag-js/core": "^1.4.0",
26+
"@zag-js/menu": "^1.4.0",
27+
"@zag-js/toast": "^1.4.0",
28+
"@zag-js/tooltip": "^1.4.0",
29+
"@zag-js/types": "^1.4.0",
30+
"@zag-js/utils": "^1.4.0",
3031
"rxjs": "~7.8.2",
3132
"tslib": "^2.8.1",
3233
"zone.js": "~0.15.0"
3334
},
3435
"devDependencies": {
35-
"@angular-devkit/build-angular": "^19.2.1",
36-
"@angular/cli": "^19.2.1",
37-
"@angular/compiler-cli": "^19.2.1",
36+
"@angular-devkit/build-angular": "^19.2.3",
37+
"@angular/cli": "^19.2.3",
38+
"@angular/compiler-cli": "^19.2.2",
3839
"@types/jasmine": "~5.1.7",
3940
"angular-eslint": "^19.2.1",
4041
"eslint": "^9.22.0",

pnpm-lock.yaml

Lines changed: 728 additions & 989 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

projects/zag-angular/src/lib/bindable.ts

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { computed, effect, isSignal, signal } from '@angular/core';
1+
import { computed, signal } from '@angular/core';
22
import { type Bindable, type BindableParams } from '@zag-js/core';
33
import { isFunction } from '@zag-js/utils';
44

@@ -10,27 +10,17 @@ export function bindable<T>(props: () => BindableParams<T>): Bindable<T> {
1010
const value = signal(initial as T);
1111
const controlled = computed(() => props().value !== undefined);
1212

13-
const valueRef = { current: value() };
14-
const prevValue: { current: T | undefined; } = { current: undefined };
15-
16-
effect(() => {
17-
const v = controlled() ? props().value : value();
18-
19-
prevValue.current = v;
20-
valueRef.current = v as T;
21-
});
13+
const valueRef = computed(() => controlled() ? props().value! : value());
2214

2315
return {
2416
initial,
2517
ref: valueRef,
2618
get(): T {
27-
const v = (controlled() ? props().value : value);
28-
29-
return isSignal(v) ? v() : v as T;
19+
return valueRef();
3020
},
3121
set(v: T | ((prev: T) => T)) {
32-
const prev = prevValue.current;
33-
const next = isFunction(v) ? v(valueRef.current) : v;
22+
const prev = valueRef();
23+
const next = isFunction(v) ? v(prev) : v;
3424

3525
if (props().debug) {
3626
console.log(`[bindable > ${ props().debug }] setValue`, { next, prev });

projects/zag-angular/src/lib/machine.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ export function useMachine<T extends MachineSchema>(
266266
});
267267

268268
// TODO: Add EventType
269-
const _send = (event: any) => {
269+
const send = (event: any) => {
270270
previousEventRef = eventRef;
271271
eventRef = event;
272272

@@ -303,17 +303,6 @@ export function useMachine<T extends MachineSchema>(
303303
}
304304
};
305305

306-
const send = (event: any) => {
307-
// TODO: Remove this when issue with menu have been resolved
308-
if (!['MENU_POINTERENTER', 'POINTER_MOVED_AWAY_FROM_SUBMENU'].includes(event.type)) {
309-
_send(event);
310-
311-
return;
312-
}
313-
314-
setTimeout(() => _send(event));
315-
};
316-
317306
machine.watch?.(getParams());
318307

319308
return {

projects/zag-angular/src/lib/normalize-props.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createNormalizer, PropTypes } from '@zag-js/types';
2-
import { isNumber, isObject, isString } from '@zag-js/utils';
2+
import { isObject, isString } from '@zag-js/utils';
33

44
const propMap: Record<string, string> = {
55
onFocus: 'onfocusin',
@@ -27,15 +27,15 @@ const preserveKeys = [
2727
'strokeMiterlimit'
2828
];
2929

30-
export type StyleObject = Record<string, string>;
30+
export type StyleObject = Record<string, string | number>;
3131

3232
export type Dict = Record<string, boolean | number | string | EventListener | StyleObject | undefined>;
3333

3434
export const normalizeProps = createNormalizer<PropTypes<Dict>>(props => {
3535
const normalized: Dict = {};
3636

3737
for (const [key, value] of Object.entries(props)) {
38-
if (key === 'style' && isString(value)) {
38+
if (key === 'style') {
3939
if (isString(value)) {
4040
normalized['style'] = serializeStyle(value);
4141
} else if (isObject(value)) {
@@ -77,11 +77,11 @@ function hyphenateStyle(style: Record<string, string | number>): StyleObject {
7777
const res: StyleObject = {};
7878

7979
for (const [property, value] of Object.entries(style)) {
80-
if (isString(value)) {
81-
res[hyphenateStyleName(property)] = value;
82-
} else if (isNumber(value)) {
83-
res[hyphenateStyleName(property)] = `${ value }px`;
80+
if (value === null || value === undefined) {
81+
continue;
8482
}
83+
84+
res[hyphenateStyleName(property)] = value;
8585
}
8686

8787
return res;
@@ -102,7 +102,7 @@ function hyphenateStyleName(name: string) {
102102

103103
const hName = name.replace(uppercasePattern, toHyphenLower);
104104

105-
return cache.set(name, msPattern.test(hName) ? "-" + hName : hName).get(name)!;
105+
return cache.set(name, msPattern.test(hName) ? '-' + hName : hName).get(name)!;
106106
}
107107

108108
function toHyphenLower(match: string) {

projects/zag-angular/src/lib/zag-it.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ export class ZagIt implements OnDestroy {
171171
const el = elementRef.nativeElement;
172172

173173
for (const name of Object.keys(style)) {
174-
renderer.removeStyle(el, name);
174+
renderer.removeStyle(el, name, RendererStyleFlags2.DashCase);
175175
}
176176
}
177177

src/app/app.component.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Component } from '@angular/core';
2+
import { createId } from 'zag-angular';
23
import { AccordionComponent, AccordionContentComponent, AccordionHeaderComponent, AccordionItemComponent } from './accordion';
34
import { CollapsibleComponent, CollapsibleContentComponent, CollapsibleTriggerComponent } from './collapsible';
45
import { MenuComponent } from './menu/menu.compponent';
6+
import { toaster, ToasterComponent } from './toast';
57
import { TooltipComponent } from './tooltip/tooltip.component';
68

79
@Component({
@@ -15,7 +17,8 @@ import { TooltipComponent } from './tooltip/tooltip.component';
1517
AccordionHeaderComponent,
1618
AccordionItemComponent,
1719
AccordionContentComponent,
18-
MenuComponent
20+
MenuComponent,
21+
ToasterComponent
1922
],
2023
template: `
2124
<div class='container'>
@@ -71,6 +74,12 @@ import { TooltipComponent } from './tooltip/tooltip.component';
7174
<div class="container">
7275
<button (click)="showAccordion = !showAccordion">Toggle Accordion</button>
7376
</div>
77+
78+
<div class=container>
79+
<button (click)="showToast()">Show Toast</button>
80+
</div>
81+
82+
<app-toaster/>
7483
`,
7584
styles: `
7685
.container {
@@ -82,4 +91,13 @@ export class AppComponent {
8291

8392
public showAccordion = false;
8493

94+
public showToast() {
95+
toaster.create({
96+
id: createId(),
97+
title: 'Data submitted!',
98+
description: 'The description of the toast.',
99+
type: 'info'
100+
});
101+
}
102+
85103
}

src/app/menu/menu.compponent.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ export class MenuComponent {
132132
shareMenuOutlet = new DomPortalOutlet(document.body);
133133

134134
constructor() {
135-
menu.machine.debug = true;
136135
// Level 1 - File Menu
137136
const fileMenuService = useMachine(
138137
menu.machine,

src/app/toast/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './toast.store';
2+
export * from './toaster.component';
3+

src/app/toast/toast.component.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { Component, computed, inject, Injector, input, runInInjectionContext, Signal } from '@angular/core';
2+
import * as toast from '@zag-js/toast';
3+
import { normalizeProps, useMachine, ZagIt } from 'zag-angular';
4+
5+
@Component({
6+
selector: 'app-toast',
7+
standalone: true,
8+
imports: [ZagIt],
9+
template: `
10+
<span [zagIt]="api().getGhostBeforeProps()"></span>
11+
<h3 [zagIt]="api().getTitleProps()">
12+
{{ api().title }}
13+
</h3>
14+
<p [zagIt]="api().getDescriptionProps()">
15+
{{ api().description }}
16+
</p>
17+
<button (click)="api().dismiss()">Close</button>
18+
<span [zagIt]="api().getGhostAfterProps()"></span>
19+
`,
20+
styles: `
21+
:host {
22+
box-sizing: border-box;
23+
width: 400px;
24+
border-radius: .375rem;
25+
border: 1px solid #ededed;
26+
padding: 1.5rem;
27+
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, .12);
28+
overflow-wrap: anywhere;
29+
translate: var(--x) var(--y);
30+
scale: var(--scale);
31+
z-index: var(--z-index);
32+
height: var(--height);
33+
opacity: var(--opacity);
34+
will-change: translate, opacity, scale;
35+
transition: translate 400ms, scale 400ms, opacity 400ms;
36+
transition-timing-function: cubic-bezier(0.21, 1.02, 0.73, 1);
37+
}
38+
39+
:host[data-type=info] {
40+
background: #fff;
41+
color: black;
42+
}
43+
44+
:host[data-state=closed] {
45+
transition: translate 400ms, scale 400ms, opacity 200ms;
46+
transition-timing-function: cubic-bezier(0.06, 0.71, 0.55, 1);
47+
}
48+
49+
[data-scope="toast"][data-part="close-trigger"] {
50+
display: flex;
51+
position: absolute;
52+
top: 0.75rem;
53+
right: 0.75rem;
54+
}
55+
`,
56+
hostDirectives: [ZagIt]
57+
})
58+
export class ToastComponent {
59+
60+
public readonly toast = input.required<toast.Options>();
61+
62+
public readonly parent = input.required<toast.GroupService>();
63+
64+
public readonly index = input.required<number>();
65+
66+
protected readonly api!: Signal<toast.Api>;
67+
68+
private readonly zagIt = inject(ZagIt);
69+
70+
private injector = inject(Injector);
71+
72+
public ngOnInit() {
73+
runInInjectionContext(
74+
this.injector,
75+
() => {
76+
const service = useMachine(
77+
toast.machine,
78+
computed(() => ({
79+
...this.toast(),
80+
parent: this.parent(),
81+
index: this.index()
82+
}))
83+
);
84+
85+
// @ts-expect-error Initialization
86+
this.api = computed(() => toast.connect(service, normalizeProps));
87+
88+
this.zagIt.next = computed(() => this.api().getRootProps());
89+
}
90+
);
91+
}
92+
93+
}

0 commit comments

Comments
 (0)