@blockle/blocks-react 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -0
- package/dist/components/display/Icon/IconMask.d.ts.map +1 -1
- package/dist/components/display/Icon/IconMask.js +1 -0
- package/dist/components/feedback/Alert/Alert.d.ts +6 -0
- package/dist/components/feedback/Alert/Alert.d.ts.map +1 -1
- package/dist/components/feedback/Alert/Alert.js +2 -0
- package/dist/components/feedback/Toast/Toast.css.d.ts +10 -1
- package/dist/components/feedback/Toast/Toast.css.d.ts.map +1 -1
- package/dist/components/feedback/Toast/Toast.css.js +37 -10
- package/dist/components/feedback/Toast/ToastContext.d.ts.map +1 -1
- package/dist/components/feedback/Toast/ToastContext.js +1 -0
- package/dist/components/feedback/Toast/ToastProvider.d.ts +9 -1
- package/dist/components/feedback/Toast/ToastProvider.d.ts.map +1 -1
- package/dist/components/feedback/Toast/ToastProvider.js +47 -24
- package/dist/components/feedback/Toast/useToast.d.ts.map +1 -1
- package/dist/components/feedback/Toast/useToast.js +1 -0
- package/dist/components/form/Checkbox/Checkbox.d.ts +0 -1
- package/dist/components/form/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/form/Checkbox/Checkbox.js +0 -2
- package/dist/components/form/Checkbox/checkbox.css.d.ts.map +1 -1
- package/dist/components/form/Checkbox/checkbox.css.js +1 -0
- package/dist/components/form/NumericInput/NumericInput.d.ts.map +1 -1
- package/dist/components/form/NumericInput/NumericInput.js +1 -0
- package/dist/components/form/Radio/Radio.d.ts +0 -1
- package/dist/components/form/Radio/Radio.d.ts.map +1 -1
- package/dist/components/form/Radio/Radio.js +1 -11
- package/dist/components/form/Radio/radio.css.d.ts.map +1 -1
- package/dist/components/form/Radio/radio.css.js +1 -0
- package/dist/components/form/Select/Select.d.ts +2 -1
- package/dist/components/form/Select/Select.d.ts.map +1 -1
- package/dist/components/form/Select/Select.js +2 -1
- package/dist/components/form/Slider/usePointerProgress.d.ts.map +1 -1
- package/dist/components/form/Slider/usePointerProgress.js +1 -0
- package/dist/components/form/Switch/Switch.d.ts +5 -1
- package/dist/components/form/Switch/Switch.d.ts.map +1 -1
- package/dist/components/form/Switch/Switch.js +19 -29
- package/dist/components/form/Switch/switch.css.d.ts.map +1 -1
- package/dist/components/form/Switch/switch.css.js +1 -0
- package/dist/components/form/TextInput/TextInput.d.ts +0 -1
- package/dist/components/form/TextInput/TextInput.d.ts.map +1 -1
- package/dist/components/form/TextInput/TextInput.js +0 -2
- package/dist/components/overlay/Dialog/Dialog.d.ts +4 -1
- package/dist/components/overlay/Dialog/Dialog.d.ts.map +1 -1
- package/dist/components/overlay/Dialog/Dialog.js +19 -46
- package/dist/components/overlay/Drawer/Drawer.d.ts +9 -2
- package/dist/components/overlay/Drawer/Drawer.d.ts.map +1 -1
- package/dist/components/overlay/Drawer/Drawer.js +26 -44
- package/dist/components/overlay/Drawer/drawer.css.d.ts.map +1 -1
- package/dist/components/overlay/Drawer/drawer.css.js +4 -8
- package/dist/components/overlay/Popover/Popover.d.ts +15 -3
- package/dist/components/overlay/Popover/Popover.d.ts.map +1 -1
- package/dist/components/overlay/Popover/Popover.js +35 -11
- package/dist/components/overlay/Popover/popover-utils.d.ts +38 -1
- package/dist/components/overlay/Popover/popover-utils.d.ts.map +1 -1
- package/dist/components/overlay/Popover/popover-utils.js +92 -41
- package/dist/components/overlay/Tooltip/Tooltip.d.ts +8 -0
- package/dist/components/overlay/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/components/overlay/Tooltip/Tooltip.js +3 -2
- package/dist/components/overlay/requestCloseReason.d.ts +6 -0
- package/dist/components/overlay/requestCloseReason.d.ts.map +1 -0
- package/dist/components/overlay/useModalOverlay.d.ts +35 -0
- package/dist/components/overlay/useModalOverlay.d.ts.map +1 -0
- package/dist/components/overlay/useModalOverlay.js +85 -0
- package/dist/components/providers/BlocksProvider/context.d.ts.map +1 -1
- package/dist/components/providers/BlocksProvider/context.js +1 -0
- package/dist/components/typography/Heading/Heading.d.ts.map +1 -1
- package/dist/components/typography/Heading/Heading.js +1 -0
- package/dist/components/typography/Text/Text.d.ts.map +1 -1
- package/dist/components/typography/Text/Text.js +1 -0
- package/dist/hooks/useClickOutside/useClickOutside.d.ts.map +1 -1
- package/dist/hooks/useClickOutside/useClickOutside.js +28 -7
- package/dist/hooks/useComponentStyles/useComponentStyleDefaultProps.d.ts.map +1 -1
- package/dist/hooks/useComponentStyles/useComponentStyleDefaultProps.js +1 -0
- package/dist/hooks/useModalDialog/useModalDialog.d.ts +13 -0
- package/dist/hooks/useModalDialog/useModalDialog.d.ts.map +1 -0
- package/dist/hooks/useModalDialog/useModalDialog.js +39 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/testUtils/browser/pointer.d.ts +18 -0
- package/dist/testUtils/browser/pointer.d.ts.map +1 -0
- package/package.json +2 -2
- package/dist/components/overlay/Dialog/dialogHelper.d.ts +0 -7
- package/dist/components/overlay/Dialog/dialogHelper.d.ts.map +0 -1
- package/dist/components/overlay/Dialog/dialogHelper.js +0 -21
package/README.md
CHANGED
|
@@ -1 +1,139 @@
|
|
|
1
1
|
# @blockle/blocks-react
|
|
2
|
+
|
|
3
|
+
## Testing
|
|
4
|
+
|
|
5
|
+
`Dialog` and `Drawer` open with `HTMLDialogElement.showModal()` and close with `close()`. jsdom does not implement these, so in a jsdom test an open `Dialog` stays a closed `<dialog>`, and Testing Library cannot find it, or anything in it, by role.
|
|
6
|
+
|
|
7
|
+
Add this polyfill to your Vitest or Jest setup file. It only defines the methods jsdom is missing:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const DialogPrototype = HTMLDialogElement.prototype;
|
|
11
|
+
|
|
12
|
+
if (!DialogPrototype.showModal) {
|
|
13
|
+
DialogPrototype.showModal = function showModal() {
|
|
14
|
+
this.setAttribute('open', '');
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!DialogPrototype.show) {
|
|
19
|
+
DialogPrototype.show = function show() {
|
|
20
|
+
this.setAttribute('open', '');
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!DialogPrototype.close) {
|
|
25
|
+
DialogPrototype.close = function close() {
|
|
26
|
+
if (!this.hasAttribute('open')) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.removeAttribute('open');
|
|
31
|
+
this.dispatchEvent(new Event('close'));
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
With it, an open dialog can be found with `getByRole('dialog')`:
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
render(
|
|
40
|
+
<Dialog open onRequestClose={() => {}} aria-label="Settings">
|
|
41
|
+
<button type="button">Save</button>
|
|
42
|
+
</Dialog>,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
screen.getByRole('dialog', { name: 'Settings' });
|
|
46
|
+
screen.getByRole('button', { name: 'Save' });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Under the polyfill the dialog is open but not modal: it is not in the top layer, and nothing outside it is made inert, so content behind it can still be queried and clicked. Test modal behaviour, focus trapping and clicks outside in a real browser, for example with Vitest Browser Mode or Playwright.
|
|
50
|
+
|
|
51
|
+
### Popover
|
|
52
|
+
|
|
53
|
+
`Popover` opens with `showPopover()` and closes with `hidePopover()`. jsdom does not implement the Popover API, and its default stylesheet hides every `[popover]` element that is not open, so Testing Library treats an open popover's content as hidden and `getByRole` finds nothing in it.
|
|
54
|
+
|
|
55
|
+
Add this polyfill to your test setup. It only defines the methods jsdom is missing, and marks an open popover with a `data-popover-open` attribute that a test stylesheet shows:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const PopoverPrototype = HTMLElement.prototype;
|
|
59
|
+
|
|
60
|
+
if (!PopoverPrototype.showPopover) {
|
|
61
|
+
PopoverPrototype.showPopover = function showPopover() {
|
|
62
|
+
this.setAttribute('data-popover-open', '');
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!PopoverPrototype.hidePopover) {
|
|
67
|
+
PopoverPrototype.hidePopover = function hidePopover() {
|
|
68
|
+
this.removeAttribute('data-popover-open');
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!PopoverPrototype.togglePopover) {
|
|
73
|
+
PopoverPrototype.togglePopover = function togglePopover(force?: boolean) {
|
|
74
|
+
return this.toggleAttribute('data-popover-open', force);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const popoverStyle = document.createElement('style');
|
|
79
|
+
popoverStyle.textContent = '[popover][data-popover-open] { display: block; }';
|
|
80
|
+
document.head.append(popoverStyle);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
With it, an open popover's content can be found by role:
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
render(
|
|
87
|
+
<Popover open anchorElement={anchorRef} onRequestClose={() => {}}>
|
|
88
|
+
<button type="button">Inside</button>
|
|
89
|
+
</Popover>,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
screen.getByRole('button', { name: 'Inside' });
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Other libraries may check for `showPopover` and behave differently once it exists; dnd-kit, for example, drags differently. If a global polyfill breaks such tests, apply it only inside the `describe` that opens a popover, and remove what it added afterwards:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { afterAll, beforeAll, describe } from 'vitest';
|
|
99
|
+
|
|
100
|
+
describe('with a popover open', () => {
|
|
101
|
+
const polyfills: Record<string, (this: HTMLElement, force?: boolean) => unknown> = {
|
|
102
|
+
showPopover() {
|
|
103
|
+
this.setAttribute('data-popover-open', '');
|
|
104
|
+
},
|
|
105
|
+
hidePopover() {
|
|
106
|
+
this.removeAttribute('data-popover-open');
|
|
107
|
+
},
|
|
108
|
+
togglePopover(force?: boolean) {
|
|
109
|
+
return this.toggleAttribute('data-popover-open', force);
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
const added: string[] = [];
|
|
113
|
+
const popoverStyle = document.createElement('style');
|
|
114
|
+
|
|
115
|
+
beforeAll(() => {
|
|
116
|
+
for (const [method, polyfill] of Object.entries(polyfills)) {
|
|
117
|
+
if (!(method in HTMLElement.prototype)) {
|
|
118
|
+
Reflect.set(HTMLElement.prototype, method, polyfill);
|
|
119
|
+
added.push(method);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
popoverStyle.textContent = '[popover][data-popover-open] { display: block; }';
|
|
124
|
+
document.head.append(popoverStyle);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
afterAll(() => {
|
|
128
|
+
for (const method of added) {
|
|
129
|
+
Reflect.deleteProperty(HTMLElement.prototype, method);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
popoverStyle.remove();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Tests that open a popover
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Where the Popover API is missing and no polyfill is applied, `Popover` warns when it opens or closes instead of throwing. Its content then stays hidden under jsdom's default styles. Test positioning, the top layer and clicks outside in a real browser.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconMask.d.ts","sourceRoot":"","sources":["../../../../src/components/display/Icon/IconMask.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"IconMask.d.ts","sourceRoot":"","sources":["../../../../src/components/display/Icon/IconMask.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,KAAK,EAEV,KAAK,eAAe,EAGpB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,KAAK,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AAEzC,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC3B,IAAI,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IACrC,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,WAAW,GACb,IAAI,CAAC,gBAAgB,CAAC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC,CAAC;AAExE,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA8B5C,CAAC"}
|
|
@@ -4,6 +4,12 @@ export type AlertProps = {
|
|
|
4
4
|
children?: React.ReactNode;
|
|
5
5
|
intent?: AlertTheme['variants']['intent'];
|
|
6
6
|
onRequestClose?: () => void;
|
|
7
|
+
/**
|
|
8
|
+
* Accessible name of the close button, rendered when `onRequestClose` is set.
|
|
9
|
+
* Pass your own wording to translate it.
|
|
10
|
+
* @default 'Close'
|
|
11
|
+
*/
|
|
12
|
+
closeLabel?: string;
|
|
7
13
|
} & HTMLElementProps<HTMLDivElement>;
|
|
8
14
|
export declare const Alert: React.FC<AlertProps>;
|
|
9
15
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Alert.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Alert/Alert.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAO9B,KAAK,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;AAE3C,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC1C,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"Alert.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Alert/Alert.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAO9B,KAAK,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;AAE3C,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC1C,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;AAErC,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA0DtC,CAAC"}
|
|
@@ -9,6 +9,7 @@ const Alert = ({
|
|
|
9
9
|
intent = "info",
|
|
10
10
|
children,
|
|
11
11
|
onRequestClose,
|
|
12
|
+
closeLabel = "Close",
|
|
12
13
|
className,
|
|
13
14
|
...restProps
|
|
14
15
|
}) => {
|
|
@@ -33,6 +34,7 @@ const Alert = ({
|
|
|
33
34
|
variant: "ghost",
|
|
34
35
|
size: "small",
|
|
35
36
|
className: closeButton,
|
|
37
|
+
"aria-label": closeLabel,
|
|
36
38
|
onClick: () => onRequestClose?.(),
|
|
37
39
|
children: /* @__PURE__ */ jsxs(
|
|
38
40
|
"svg",
|
|
@@ -1,2 +1,11 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const stack: string;
|
|
2
|
+
export declare const toast: string;
|
|
3
|
+
export declare const placement: {
|
|
4
|
+
top: string;
|
|
5
|
+
'top-start': string;
|
|
6
|
+
'top-end': string;
|
|
7
|
+
bottom: string;
|
|
8
|
+
'bottom-start': string;
|
|
9
|
+
'bottom-end': string;
|
|
10
|
+
};
|
|
2
11
|
//# sourceMappingURL=Toast.css.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toast.css.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Toast/Toast.css.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Toast.css.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Toast/Toast.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,KAAK,QAYhB,CAAC;AAEH,eAAO,MAAM,KAAK,QAOhB,CAAC;AAmBH,eAAO,MAAM,SAAS;;;;;;;CAOrB,CAAC"}
|
|
@@ -1,22 +1,49 @@
|
|
|
1
1
|
import { setFileScope, endFileScope } from "@vanilla-extract/css/fileScope";
|
|
2
2
|
import { layers } from "@blockle/blocks-core";
|
|
3
|
-
import { style
|
|
3
|
+
import { style } from "@vanilla-extract/css";
|
|
4
4
|
setFileScope("src/components/feedback/Toast/Toast.css.ts", "@blockle/blocks-react");
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const stack = style({
|
|
6
|
+
"@layer": {
|
|
7
|
+
[layers.molecule]: {
|
|
8
|
+
position: "fixed",
|
|
9
|
+
display: "flex",
|
|
10
|
+
flexDirection: "column",
|
|
11
|
+
width: "100%",
|
|
12
|
+
boxSizing: "border-box",
|
|
13
|
+
// Let clicks through the stack's empty space, but not through a toast
|
|
14
|
+
pointerEvents: "none"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
8
17
|
});
|
|
9
|
-
const
|
|
18
|
+
const toast = style({
|
|
10
19
|
"@layer": {
|
|
11
20
|
[layers.molecule]: {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
animationTimingFunction: "ease-out",
|
|
15
|
-
height: "fit-content"
|
|
21
|
+
height: "fit-content",
|
|
22
|
+
pointerEvents: "auto"
|
|
16
23
|
}
|
|
17
24
|
}
|
|
18
25
|
});
|
|
26
|
+
const top = {
|
|
27
|
+
insetBlockStart: 0,
|
|
28
|
+
// Newest toast nearest the top edge
|
|
29
|
+
flexDirection: "column-reverse"
|
|
30
|
+
};
|
|
31
|
+
const bottom = { insetBlockEnd: 0 };
|
|
32
|
+
const center = { insetInline: 0, marginInline: "auto" };
|
|
33
|
+
const start = { insetInlineStart: 0 };
|
|
34
|
+
const end = { insetInlineEnd: 0 };
|
|
35
|
+
const placementStyle = (...rules) => style({ "@layer": { [layers.molecule]: Object.assign({}, ...rules) } });
|
|
36
|
+
const placement = {
|
|
37
|
+
top: placementStyle(top, center),
|
|
38
|
+
"top-start": placementStyle(top, start),
|
|
39
|
+
"top-end": placementStyle(top, end),
|
|
40
|
+
bottom: placementStyle(bottom, center),
|
|
41
|
+
"bottom-start": placementStyle(bottom, start),
|
|
42
|
+
"bottom-end": placementStyle(bottom, end)
|
|
43
|
+
};
|
|
19
44
|
endFileScope();
|
|
20
45
|
export {
|
|
21
|
-
|
|
46
|
+
placement,
|
|
47
|
+
stack,
|
|
48
|
+
toast
|
|
22
49
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToastContext.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Toast/ToastContext.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ToastContext.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Toast/ToastContext.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B,CAAC;AAEF,eAAO,MAAM,YAAY,kDAA+C,CAAC"}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
import { ToastPlacement } from '@blockle/blocks-core';
|
|
2
|
+
export type { ToastPlacement };
|
|
3
|
+
type ToastPosition = 'bottom-left' | 'bottom-center' | 'bottom-right' | 'top-left' | 'top-center' | 'top-right';
|
|
1
4
|
export type ToastProviderProps = {
|
|
2
5
|
children?: React.ReactNode;
|
|
3
|
-
|
|
6
|
+
/** Where the toasts sit on the screen. Defaults to `bottom` */
|
|
7
|
+
placement?: ToastPlacement;
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated Use `placement`, which wins when both are passed
|
|
10
|
+
*/
|
|
11
|
+
position?: ToastPosition;
|
|
4
12
|
};
|
|
5
13
|
export declare const ToastProvider: React.FC<ToastProviderProps>;
|
|
6
14
|
//# sourceMappingURL=ToastProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToastProvider.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Toast/ToastProvider.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ToastProvider.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Toast/ToastProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA4BvE,YAAY,EAAE,cAAc,EAAE,CAAC;AAE/B,KAAK,aAAa,GACd,aAAa,GACb,eAAe,GACf,cAAc,GACd,UAAU,GACV,YAAY,GACZ,WAAW,CAAC;AAWhB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,+DAA+D;IAC/D,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;OAEG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAoGtD,CAAC"}
|
|
@@ -1,41 +1,64 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { classnames } from "@blockle/blocks-core";
|
|
3
4
|
import { useState, useRef, useCallback, useMemo } from "react";
|
|
4
5
|
import { flushSync } from "react-dom";
|
|
5
|
-
import {
|
|
6
|
-
import { Stack } from "../../layout/Stack/Stack.js";
|
|
6
|
+
import { useComponentStyles } from "../../../hooks/useComponentStyles/useComponentStyles.js";
|
|
7
7
|
import { Alert } from "../Alert/Alert.js";
|
|
8
|
-
import {
|
|
8
|
+
import { toast, stack, placement } from "./Toast.css.js";
|
|
9
9
|
import { ToastContext } from "./ToastContext.js";
|
|
10
10
|
function makeTransition(transition) {
|
|
11
11
|
if (document.startViewTransition) {
|
|
12
|
-
document.startViewTransition(() => {
|
|
12
|
+
const viewTransition = document.startViewTransition(() => {
|
|
13
13
|
flushSync(() => {
|
|
14
14
|
transition();
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
|
+
viewTransition.ready.catch(() => {
|
|
18
|
+
});
|
|
17
19
|
} else {
|
|
18
20
|
transition();
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
|
-
const
|
|
23
|
+
const placementByPosition = {
|
|
24
|
+
"bottom-left": "bottom-start",
|
|
25
|
+
"bottom-center": "bottom",
|
|
26
|
+
"bottom-right": "bottom-end",
|
|
27
|
+
"top-left": "top-start",
|
|
28
|
+
"top-center": "top",
|
|
29
|
+
"top-right": "top-end"
|
|
30
|
+
};
|
|
31
|
+
const ToastProvider = ({
|
|
32
|
+
children,
|
|
33
|
+
placement: placementProp,
|
|
34
|
+
position
|
|
35
|
+
}) => {
|
|
36
|
+
const placement$1 = placementProp ?? (position ? placementByPosition[position] : "bottom");
|
|
37
|
+
const rootClassName = useComponentStyles("toast", {
|
|
38
|
+
root: true,
|
|
39
|
+
variants: { placement: placement$1 }
|
|
40
|
+
});
|
|
41
|
+
const toastClassName = useComponentStyles("toast", {
|
|
42
|
+
toast: true,
|
|
43
|
+
variants: { placement: placement$1 }
|
|
44
|
+
});
|
|
22
45
|
const [toasts, setToasts] = useState([]);
|
|
23
46
|
const toastsRef = useRef(toasts);
|
|
24
47
|
toastsRef.current = toasts;
|
|
25
48
|
const removeToast = useCallback((id) => {
|
|
26
49
|
makeTransition(() => {
|
|
27
|
-
setToasts((prev) => prev.filter((
|
|
50
|
+
setToasts((prev) => prev.filter((toast2) => toast2.id !== id));
|
|
28
51
|
});
|
|
29
52
|
}, []);
|
|
30
|
-
const addToast = useCallback((
|
|
53
|
+
const addToast = useCallback((toast2) => {
|
|
31
54
|
const toasts2 = toastsRef.current;
|
|
32
|
-
const match = toasts2.findIndex(({ id }) => id ===
|
|
55
|
+
const match = toasts2.findIndex(({ id }) => id === toast2.id) !== -1;
|
|
33
56
|
function updateState(prev) {
|
|
34
|
-
const match2 = prev.findIndex(({ id }) => id ===
|
|
57
|
+
const match2 = prev.findIndex(({ id }) => id === toast2.id) !== -1;
|
|
35
58
|
if (match2) {
|
|
36
|
-
return prev.map((item) => item.id ===
|
|
59
|
+
return prev.map((item) => item.id === toast2.id ? toast2 : item);
|
|
37
60
|
}
|
|
38
|
-
return [...prev,
|
|
61
|
+
return [...prev, toast2];
|
|
39
62
|
}
|
|
40
63
|
if (match) {
|
|
41
64
|
setToasts(updateState);
|
|
@@ -44,13 +67,13 @@ const ToastProvider = ({ children }) => {
|
|
|
44
67
|
makeTransition(() => {
|
|
45
68
|
setToasts(updateState);
|
|
46
69
|
});
|
|
47
|
-
if (
|
|
48
|
-
const toastId =
|
|
70
|
+
if (toast2.duration) {
|
|
71
|
+
const toastId = toast2.id;
|
|
49
72
|
setTimeout(() => {
|
|
50
73
|
makeTransition(() => {
|
|
51
|
-
setToasts((prev) => prev.filter((
|
|
74
|
+
setToasts((prev) => prev.filter((toast22) => toast22.id !== toastId));
|
|
52
75
|
});
|
|
53
|
-
},
|
|
76
|
+
}, toast2.duration);
|
|
54
77
|
}
|
|
55
78
|
}, []);
|
|
56
79
|
const contextValue = useMemo(
|
|
@@ -63,18 +86,18 @@ const ToastProvider = ({ children }) => {
|
|
|
63
86
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
64
87
|
/* @__PURE__ */ jsx(ToastContext.Provider, { value: contextValue, children }),
|
|
65
88
|
/* @__PURE__ */ jsx(
|
|
66
|
-
|
|
89
|
+
"div",
|
|
67
90
|
{
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
children:
|
|
91
|
+
className: classnames(
|
|
92
|
+
stack,
|
|
93
|
+
placement[placement$1],
|
|
94
|
+
rootClassName
|
|
95
|
+
),
|
|
96
|
+
children: toasts.map(({ id, children: children2, intent }) => /* @__PURE__ */ jsx(
|
|
74
97
|
Alert,
|
|
75
98
|
{
|
|
76
99
|
intent,
|
|
77
|
-
className:
|
|
100
|
+
className: classnames(toast, toastClassName),
|
|
78
101
|
style: {
|
|
79
102
|
viewTransitionName: `toast-${id}`
|
|
80
103
|
},
|
|
@@ -84,7 +107,7 @@ const ToastProvider = ({ children }) => {
|
|
|
84
107
|
children: children2
|
|
85
108
|
},
|
|
86
109
|
id
|
|
87
|
-
))
|
|
110
|
+
))
|
|
88
111
|
}
|
|
89
112
|
)
|
|
90
113
|
] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useToast.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Toast/useToast.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useToast.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/Toast/useToast.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,KAAK,EAAgB,MAAM,mBAAmB,CAAC;AAE7D,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG;IAC3C,EAAE,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,QAAQ;uBAQT,UAAU;sBAYb,MAAM;CAad,CAAC"}
|
|
@@ -2,7 +2,6 @@ import { HTMLElementProps } from '@blockle/blocks-core';
|
|
|
2
2
|
import { default as React } from 'react';
|
|
3
3
|
export type CheckboxProps = {
|
|
4
4
|
children?: React.ReactNode;
|
|
5
|
-
name: string;
|
|
6
5
|
required?: boolean;
|
|
7
6
|
} & HTMLElementProps<HTMLInputElement>;
|
|
8
7
|
export declare const Checkbox: React.FC<CheckboxProps>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Checkbox/Checkbox.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAO/B,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"Checkbox.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Checkbox/Checkbox.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAO/B,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;AAEvC,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA+C5C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkbox.css.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Checkbox/checkbox.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"checkbox.css.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Checkbox/checkbox.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS,QASpB,CAAC;AAEH,eAAO,MAAM,KAAK,QAShB,CAAC;AAEH,eAAO,MAAM,IAAI,QAEf,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NumericInput.d.ts","sourceRoot":"","sources":["../../../../src/components/form/NumericInput/NumericInput.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"NumericInput.d.ts","sourceRoot":"","sources":["../../../../src/components/form/NumericInput/NumericInput.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAG3E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,cAAc,CAAC;AAEnB,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA2CpD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Radio.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Radio/Radio.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAOzE,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"Radio.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Radio/Radio.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAOzE,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;AAEvC,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA8BtC,CAAC"}
|
|
@@ -6,7 +6,6 @@ import { useComponentStyles } from "../../../hooks/useComponentStyles/useCompone
|
|
|
6
6
|
import { Label } from "../Label/Label.js";
|
|
7
7
|
import { input, icon, container } from "./radio.css.js";
|
|
8
8
|
const Radio = ({
|
|
9
|
-
name,
|
|
10
9
|
children,
|
|
11
10
|
className,
|
|
12
11
|
...restProps
|
|
@@ -21,16 +20,7 @@ const Radio = ({
|
|
|
21
20
|
{
|
|
22
21
|
className: classnames(container, containerClassName, className),
|
|
23
22
|
children: [
|
|
24
|
-
/* @__PURE__ */ jsx(
|
|
25
|
-
"input",
|
|
26
|
-
{
|
|
27
|
-
type: "radio",
|
|
28
|
-
name,
|
|
29
|
-
id,
|
|
30
|
-
className: input,
|
|
31
|
-
...restProps
|
|
32
|
-
}
|
|
33
|
-
),
|
|
23
|
+
/* @__PURE__ */ jsx("input", { type: "radio", id, className: input, ...restProps }),
|
|
34
24
|
/* @__PURE__ */ jsx("div", { className: classnames(icon, iconClassName) })
|
|
35
25
|
]
|
|
36
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radio.css.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Radio/radio.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"radio.css.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Radio/radio.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS,QASpB,CAAC;AAEH,eAAO,MAAM,KAAK,QAShB,CAAC;AAEH,eAAO,MAAM,IAAI,QAEf,CAAC"}
|
|
@@ -4,8 +4,9 @@ type SelectTheme = ComponentThemes['select'];
|
|
|
4
4
|
export type SelectProps = {
|
|
5
5
|
children: React.ReactNode;
|
|
6
6
|
placeholder?: string;
|
|
7
|
+
size?: SelectTheme['variants']['size'];
|
|
7
8
|
variant?: SelectTheme['variants']['variant'];
|
|
8
|
-
} & HTMLElementProps<HTMLSelectElement>;
|
|
9
|
+
} & Omit<HTMLElementProps<HTMLSelectElement>, 'size'>;
|
|
9
10
|
export declare const Select: React.FC<SelectProps>;
|
|
10
11
|
export {};
|
|
11
12
|
//# sourceMappingURL=Select.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Select/Select.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,KAAK,WAAW,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC;CAC9C,GAAG,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Select/Select.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,KAAK,WAAW,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;AAE7C,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC;CAC9C,GAAG,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;AAEtD,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAiCxC,CAAC"}
|
|
@@ -8,13 +8,14 @@ const Select = ({
|
|
|
8
8
|
children,
|
|
9
9
|
placeholder,
|
|
10
10
|
className,
|
|
11
|
+
size,
|
|
11
12
|
variant,
|
|
12
13
|
...restProps
|
|
13
14
|
}) => {
|
|
14
15
|
const wrapperClassName = useComponentStyles("select", { root: true }, false);
|
|
15
16
|
const selectClassName = useComponentStyles("select", {
|
|
16
17
|
select: true,
|
|
17
|
-
variants: { variant }
|
|
18
|
+
variants: { variant, size }
|
|
18
19
|
});
|
|
19
20
|
const iconClassName = useComponentStyles("select", { icon: true }, false);
|
|
20
21
|
return /* @__PURE__ */ jsxs(Box, { className: classnames(wrapper, wrapperClassName), children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePointerProgress.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Slider/usePointerProgress.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"usePointerProgress.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Slider/usePointerProgress.ts"],"names":[],"mappings":"AAIA,KAAK,sBAAsB,CAAC,CAAC,SAAS,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI;IAC3E,SAAS,EAAE,CAAC,CAAC;IACb,WAAW,EAAE,YAAY,GAAG,UAAU,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF,wBAAgB,WAAW,CACzB,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,OAAO,GACZ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAQxB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,CAAC,SAAS,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAC7C,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,IAAI,CA6CvE"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { HTMLElementProps } from '@blockle/blocks-core';
|
|
2
2
|
export type SwitchProps = {
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The native change handler of the underlying input.
|
|
5
|
+
* Read the new value from `event.target.checked`.
|
|
6
|
+
*/
|
|
7
|
+
onChange?: React.ChangeEventHandler<HTMLInputElement>;
|
|
4
8
|
} & Omit<HTMLElementProps<HTMLInputElement>, 'onChange'>;
|
|
5
9
|
export declare const Switch: React.FC<SwitchProps>;
|
|
6
10
|
//# sourceMappingURL=Switch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Switch/Switch.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../../../src/components/form/Switch/Switch.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAM9B,MAAM,MAAM,WAAW,GAAG;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;CACvD,GAAG,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,EAAE,UAAU,CAAC,CAAC;AAEzD,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAyDxC,CAAC"}
|