@cratis/scene.react 4.0.0 → 4.1.1

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.
Files changed (79) hide show
  1. package/dist/cjs/SceneElementView.js +1 -0
  2. package/dist/cjs/SceneElementView.js.map +1 -1
  3. package/dist/cjs/index.js +8 -0
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/interactions/ConfirmHost.js +71 -0
  6. package/dist/cjs/interactions/ConfirmHost.js.map +1 -0
  7. package/dist/cjs/interactions/InteractionScope.js +10 -1
  8. package/dist/cjs/interactions/InteractionScope.js.map +1 -1
  9. package/dist/cjs/interactions/NotificationHost.js +73 -0
  10. package/dist/cjs/interactions/NotificationHost.js.map +1 -0
  11. package/dist/cjs/interactions/UnresolvedActionHost.js +53 -0
  12. package/dist/cjs/interactions/UnresolvedActionHost.js.map +1 -0
  13. package/dist/cjs/interactions/useInteractionHosts.js +109 -0
  14. package/dist/cjs/interactions/useInteractionHosts.js.map +1 -0
  15. package/dist/cjs/renderer/InteractiveComponent.js +1 -0
  16. package/dist/cjs/renderer/InteractiveComponent.js.map +1 -1
  17. package/dist/esm/SceneElementView.js +1 -0
  18. package/dist/esm/SceneElementView.js.map +1 -1
  19. package/dist/esm/for_useInteractionHosts/when_a_document_asks_the_user_something.d.ts +2 -0
  20. package/dist/esm/for_useInteractionHosts/when_a_document_asks_the_user_something.d.ts.map +1 -0
  21. package/dist/esm/for_useInteractionHosts/when_a_document_asks_the_user_something.js +73 -0
  22. package/dist/esm/for_useInteractionHosts/when_a_document_asks_the_user_something.js.map +1 -0
  23. package/dist/esm/for_useInteractionHosts/when_the_host_cannot_do_what_was_asked.d.ts +2 -0
  24. package/dist/esm/for_useInteractionHosts/when_the_host_cannot_do_what_was_asked.d.ts.map +1 -0
  25. package/dist/esm/for_useInteractionHosts/when_the_host_cannot_do_what_was_asked.js +43 -0
  26. package/dist/esm/for_useInteractionHosts/when_the_host_cannot_do_what_was_asked.js.map +1 -0
  27. package/dist/esm/index.js +4 -0
  28. package/dist/esm/index.js.map +1 -1
  29. package/dist/esm/interactions/ConfirmHost.d.ts +8 -0
  30. package/dist/esm/interactions/ConfirmHost.d.ts.map +1 -0
  31. package/dist/esm/interactions/ConfirmHost.js +69 -0
  32. package/dist/esm/interactions/ConfirmHost.js.map +1 -0
  33. package/dist/esm/interactions/ConfirmRequest.d.ts +5 -0
  34. package/dist/esm/interactions/ConfirmRequest.d.ts.map +1 -0
  35. package/dist/esm/interactions/ConfirmRequest.js +2 -0
  36. package/dist/esm/interactions/ConfirmRequest.js.map +1 -0
  37. package/dist/esm/interactions/InteractionScope.d.ts +2 -1
  38. package/dist/esm/interactions/InteractionScope.d.ts.map +1 -1
  39. package/dist/esm/interactions/InteractionScope.js +10 -1
  40. package/dist/esm/interactions/InteractionScope.js.map +1 -1
  41. package/dist/esm/interactions/NotificationHost.d.ts +7 -0
  42. package/dist/esm/interactions/NotificationHost.d.ts.map +1 -0
  43. package/dist/esm/interactions/NotificationHost.js +71 -0
  44. package/dist/esm/interactions/NotificationHost.js.map +1 -0
  45. package/dist/esm/interactions/SceneNotification.d.ts +7 -0
  46. package/dist/esm/interactions/SceneNotification.d.ts.map +1 -0
  47. package/dist/esm/interactions/SceneNotification.js +2 -0
  48. package/dist/esm/interactions/SceneNotification.js.map +1 -0
  49. package/dist/esm/interactions/UnresolvedAction.d.ts +5 -0
  50. package/dist/esm/interactions/UnresolvedAction.d.ts.map +1 -0
  51. package/dist/esm/interactions/UnresolvedAction.js +2 -0
  52. package/dist/esm/interactions/UnresolvedAction.js.map +1 -0
  53. package/dist/esm/interactions/UnresolvedActionHost.d.ts +6 -0
  54. package/dist/esm/interactions/UnresolvedActionHost.d.ts.map +1 -0
  55. package/dist/esm/interactions/UnresolvedActionHost.js +51 -0
  56. package/dist/esm/interactions/UnresolvedActionHost.js.map +1 -0
  57. package/dist/esm/interactions/index.d.ts +7 -0
  58. package/dist/esm/interactions/index.d.ts.map +1 -1
  59. package/dist/esm/interactions/index.js +7 -0
  60. package/dist/esm/interactions/index.js.map +1 -1
  61. package/dist/esm/interactions/useInteractionHosts.d.ts +11 -0
  62. package/dist/esm/interactions/useInteractionHosts.d.ts.map +1 -0
  63. package/dist/esm/interactions/useInteractionHosts.js +107 -0
  64. package/dist/esm/interactions/useInteractionHosts.js.map +1 -0
  65. package/dist/esm/renderer/InteractiveComponent.js +1 -0
  66. package/dist/esm/renderer/InteractiveComponent.js.map +1 -1
  67. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  68. package/for_useInteractionHosts/when_a_document_asks_the_user_something.tsx +106 -0
  69. package/for_useInteractionHosts/when_the_host_cannot_do_what_was_asked.tsx +66 -0
  70. package/interactions/ConfirmHost.tsx +42 -0
  71. package/interactions/ConfirmRequest.ts +19 -0
  72. package/interactions/InteractionScope.tsx +22 -2
  73. package/interactions/NotificationHost.tsx +48 -0
  74. package/interactions/SceneNotification.ts +18 -0
  75. package/interactions/UnresolvedAction.ts +17 -0
  76. package/interactions/UnresolvedActionHost.tsx +33 -0
  77. package/interactions/index.ts +7 -0
  78. package/interactions/useInteractionHosts.tsx +101 -0
  79. package/package.json +5 -5
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { useMemo } from 'react';
5
+ import { InteractionActionKind, InteractionTriggerKind } from '@cratis/scene.model';
6
+ import { InteractionScope, createBrowserDispatcher, useInteractionHosts, useInteractions } from '../interactions';
7
+ const navigateSomewhere = {
8
+ name: 'GoToInvoice',
9
+ bindings: [
10
+ {
11
+ trigger: { kind: InteractionTriggerKind.Click },
12
+ actions: [{ kind: InteractionActionKind.Navigate, screen: 'InvoiceDetails' }],
13
+ },
14
+ ],
15
+ };
16
+ function Button() {
17
+ const handlers = useInteractions('element', [navigateSomewhere]);
18
+ return _jsx("button", { type: "button", ...handlers, children: "Open" });
19
+ }
20
+ function Application() {
21
+ const { host, surfaces } = useInteractionHosts();
22
+ const dispatcher = useMemo(() => createBrowserDispatcher(host), [host]);
23
+ return (_jsxs(InteractionScope, { dispatcher: dispatcher, attachments: [], children: [_jsx(Button, {}), surfaces] }));
24
+ }
25
+ describe('when the host cannot do what was asked', () => {
26
+ it('should say so on the screen rather than do nothing', async () => {
27
+ render(_jsx(Application, {}));
28
+ await userEvent.click(screen.getByRole('button', { name: 'Open' }));
29
+ screen.getByText('navigate to InvoiceDetails').textContent.should.equal('navigate to InvoiceDetails');
30
+ });
31
+ it('should report the same action once however often it is asked for', async () => {
32
+ render(_jsx(Application, {}));
33
+ await userEvent.click(screen.getByRole('button', { name: 'Open' }));
34
+ await userEvent.click(screen.getByRole('button', { name: 'Open' }));
35
+ await userEvent.click(screen.getByRole('button', { name: 'Open' }));
36
+ screen.getAllByText('navigate to InvoiceDetails').should.have.lengthOf(1);
37
+ });
38
+ it('should say nothing when nothing has failed', () => {
39
+ render(_jsx(Application, {}));
40
+ (screen.queryByText(/cannot do what the document asked/) === null).should.equal(true);
41
+ });
42
+ });
43
+ //# sourceMappingURL=when_the_host_cannot_do_what_was_asked.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"when_the_host_cannot_do_what_was_asked.js","sourceRoot":"","sources":["../../../for_useInteractionHosts/when_the_host_cannot_do_what_was_asked.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,SAAS,MAAM,6BAA6B,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAY,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElH,MAAM,iBAAiB,GAAa;IAChC,IAAI,EAAE,aAAa;IACnB,QAAQ,EAAE;QACN;YACI,OAAO,EAAE,EAAE,IAAI,EAAE,sBAAsB,CAAC,KAAK,EAAW;YACxD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAW,CAAC;SACzF;KACJ;CACJ,CAAC;AAEF,SAAS,MAAM;IACX,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACjE,OAAO,iBAAQ,IAAI,EAAC,QAAQ,KAAK,QAAQ,qBAAe,CAAC;AAC7D,CAAC;AAKD,SAAS,WAAW;IAChB,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,mBAAmB,EAAE,CAAC;IACjD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAExE,OAAO,CACH,MAAC,gBAAgB,IAAC,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,aACrD,KAAC,MAAM,KAAG,EACT,QAAQ,IACM,CACtB,CAAC;AACN,CAAC;AAED,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACpD,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,CAAC,KAAC,WAAW,KAAG,CAAC,CAAC;QAExB,MAAM,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAEpE,MAAM,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC,WAAY,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAC3G,CAAC,CAAC,CAAC;IAIH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,CAAC,KAAC,WAAW,KAAG,CAAC,CAAC;QAExB,MAAM,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QACpE,MAAM,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QACpE,MAAM,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAEpE,MAAM,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,KAAC,WAAW,KAAG,CAAC,CAAC;QAExB,CAAC,MAAM,CAAC,WAAW,CAAC,mCAAmC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
package/dist/esm/index.js CHANGED
@@ -16,4 +16,8 @@ export { SceneThemeProvider, useSceneTheme } from './theme/SceneThemeProvider.js
16
16
  export { InteractionScope, attachmentFor, useInteractionScope } from './interactions/InteractionScope.js';
17
17
  export { useInteractions } from './interactions/useInteractions.js';
18
18
  export { createBrowserDispatcher } from './interactions/createBrowserDispatcher.js';
19
+ export { ConfirmHost } from './interactions/ConfirmHost.js';
20
+ export { NotificationHost } from './interactions/NotificationHost.js';
21
+ export { UnresolvedActionHost } from './interactions/UnresolvedActionHost.js';
22
+ export { useInteractionHosts } from './interactions/useInteractionHosts.js';
19
23
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,8 @@
1
+ import { ConfirmRequest } from './ConfirmRequest';
2
+ export interface ConfirmHostProps {
3
+ readonly request?: ConfirmRequest;
4
+ readonly confirmLabel?: string;
5
+ readonly cancelLabel?: string;
6
+ }
7
+ export declare function ConfirmHost({ request, confirmLabel, cancelLabel }: ConfirmHostProps): import("react").JSX.Element | null;
8
+ //# sourceMappingURL=ConfirmHost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmHost.d.ts","sourceRoot":"","sources":["../../../interactions/ConfirmHost.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKlD,MAAM,WAAW,gBAAgB;IAE7B,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC;IAGlC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAG/B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CACjC;AAUD,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,YAAmB,EAAE,WAAsB,EAAE,EAAE,gBAAgB,sCAcrG"}
@@ -0,0 +1,69 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ /**
6
+ * Asks what a document's `confirm` asked, in the page rather than in a browser prompt.
7
+ *
8
+ * The browser's own prompt blocks the event loop and cannot be styled or tested, which is why it is the
9
+ * fallback and not this. Declining is the default action, so dismissing the question stops the sequence - a
10
+ * confirm exists to gate what follows it, and a gate that opens when ignored is not one.
11
+ * @param props The {@link ConfirmHostProps}.
12
+ */ function ConfirmHost({ request, confirmLabel = 'OK', cancelLabel = 'Cancel' }) {
13
+ if (!request) return null;
14
+ return /*#__PURE__*/ jsx("div", {
15
+ "data-scene-confirm": true,
16
+ style: {
17
+ position: 'fixed',
18
+ inset: 0,
19
+ display: 'flex',
20
+ alignItems: 'center',
21
+ justifyContent: 'center',
22
+ background: 'rgba(0,0,0,0.35)',
23
+ zIndex: 1100
24
+ },
25
+ children: /*#__PURE__*/ jsxs("div", {
26
+ role: "alertdialog",
27
+ "aria-modal": "true",
28
+ "aria-label": request.message,
29
+ style: {
30
+ minWidth: '18rem',
31
+ maxWidth: '28rem',
32
+ padding: '1rem',
33
+ borderRadius: 4,
34
+ background: '#fff',
35
+ color: '#1a1a1a'
36
+ },
37
+ children: [
38
+ /*#__PURE__*/ jsx("p", {
39
+ style: {
40
+ margin: '0 0 1rem'
41
+ },
42
+ children: request.message
43
+ }),
44
+ /*#__PURE__*/ jsxs("div", {
45
+ style: {
46
+ display: 'flex',
47
+ justifyContent: 'flex-end',
48
+ gap: '0.5rem'
49
+ },
50
+ children: [
51
+ /*#__PURE__*/ jsx("button", {
52
+ type: "button",
53
+ onClick: ()=>request.answer(false),
54
+ children: cancelLabel
55
+ }),
56
+ /*#__PURE__*/ jsx("button", {
57
+ type: "button",
58
+ onClick: ()=>request.answer(true),
59
+ children: confirmLabel
60
+ })
61
+ ]
62
+ })
63
+ ]
64
+ })
65
+ });
66
+ }
67
+
68
+ export { ConfirmHost };
69
+ //# sourceMappingURL=ConfirmHost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmHost.js","sources":["../../../interactions/ConfirmHost.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { ConfirmRequest } from './ConfirmRequest';\n\n/**\n * The properties of {@link ConfirmHost}.\n */\nexport interface ConfirmHostProps {\n /** The question waiting on an answer, or `undefined` when nothing is being asked. */\n readonly request?: ConfirmRequest;\n\n /** The label on the agreeing choice. */\n readonly confirmLabel?: string;\n\n /** The label on the declining choice. */\n readonly cancelLabel?: string;\n}\n\n/**\n * Asks what a document's `confirm` asked, in the page rather than in a browser prompt.\n *\n * The browser's own prompt blocks the event loop and cannot be styled or tested, which is why it is the\n * fallback and not this. Declining is the default action, so dismissing the question stops the sequence - a\n * confirm exists to gate what follows it, and a gate that opens when ignored is not one.\n * @param props The {@link ConfirmHostProps}.\n */\nexport function ConfirmHost({ request, confirmLabel = 'OK', cancelLabel = 'Cancel' }: ConfirmHostProps) {\n if (!request) return null;\n\n return (\n <div data-scene-confirm style={{ position: 'fixed', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(0,0,0,0.35)', zIndex: 1100 }}>\n <div role=\"alertdialog\" aria-modal=\"true\" aria-label={request.message} style={{ minWidth: '18rem', maxWidth: '28rem', padding: '1rem', borderRadius: 4, background: '#fff', color: '#1a1a1a' }}>\n <p style={{ margin: '0 0 1rem' }}>{request.message}</p>\n <div style={{ display: 'flex', justifyContent: 'flex-end', gap: '0.5rem' }}>\n <button type=\"button\" onClick={() => request.answer(false)}>{cancelLabel}</button>\n <button type=\"button\" onClick={() => request.answer(true)}>{confirmLabel}</button>\n </div>\n </div>\n </div>\n );\n}\n"],"names":["ConfirmHost","request","confirmLabel","cancelLabel","_jsx","div","data-scene-confirm","style","position","inset","display","alignItems","justifyContent","background","zIndex","_jsxs","role","aria-modal","aria-label","message","minWidth","maxWidth","padding","borderRadius","color","p","margin","gap","button","type","onClick","answer"],"mappings":";;AAAA;AACA;AAkBA;;;;;;;IAQO,SAASA,WAAAA,CAAY,EAAEC,OAAO,EAAEC,YAAAA,GAAe,IAAI,EAAEC,WAAAA,GAAc,QAAQ,EAAoB,EAAA;IAClG,IAAI,CAACF,SAAS,OAAO,IAAA;AAErB,IAAA,qBACIG,GAAA,CAACC,KAAAA,EAAAA;QAAIC,oBAAkB,EAAA,IAAA;QAACC,KAAAA,EAAO;YAAEC,QAAAA,EAAU,OAAA;YAASC,KAAAA,EAAO,CAAA;YAAGC,OAAAA,EAAS,MAAA;YAAQC,UAAAA,EAAY,QAAA;YAAUC,cAAAA,EAAgB,QAAA;YAAUC,UAAAA,EAAY,kBAAA;YAAoBC,MAAAA,EAAQ;AAAK,SAAA;AACxK,QAAA,QAAA,gBAAAC,IAAA,CAACV,KAAAA,EAAAA;YAAIW,IAAAA,EAAK,aAAA;YAAcC,YAAAA,EAAW,MAAA;AAAOC,YAAAA,YAAAA,EAAYjB,QAAQkB,OAAO;YAAEZ,KAAAA,EAAO;gBAAEa,QAAAA,EAAU,OAAA;gBAASC,QAAAA,EAAU,OAAA;gBAASC,OAAAA,EAAS,MAAA;gBAAQC,YAAAA,EAAc,CAAA;gBAAGV,UAAAA,EAAY,MAAA;gBAAQW,KAAAA,EAAO;AAAU,aAAA;;8BACzLpB,GAAA,CAACqB,GAAAA,EAAAA;oBAAElB,KAAAA,EAAO;wBAAEmB,MAAAA,EAAQ;AAAW,qBAAA;AAAIzB,oBAAAA,QAAAA,EAAAA,OAAAA,CAAQkB;;8BAC3CJ,IAAA,CAACV,KAAAA,EAAAA;oBAAIE,KAAAA,EAAO;wBAAEG,OAAAA,EAAS,MAAA;wBAAQE,cAAAA,EAAgB,UAAA;wBAAYe,GAAAA,EAAK;AAAS,qBAAA;;sCACrEvB,GAAA,CAACwB,QAAAA,EAAAA;4BAAOC,IAAAA,EAAK,QAAA;4BAASC,OAAAA,EAAS,IAAM7B,OAAAA,CAAQ8B,MAAM,CAAC,KAAA,CAAA;AAAS5B,4BAAAA,QAAAA,EAAAA;;sCAC7DC,GAAA,CAACwB,QAAAA,EAAAA;4BAAOC,IAAAA,EAAK,QAAA;4BAASC,OAAAA,EAAS,IAAM7B,OAAAA,CAAQ8B,MAAM,CAAC,IAAA,CAAA;AAAQ7B,4BAAAA,QAAAA,EAAAA;;;;;;;AAKhF;;"}
@@ -0,0 +1,5 @@
1
+ export interface ConfirmRequest {
2
+ readonly message: string;
3
+ answer(confirmed: boolean): void;
4
+ }
5
+ //# sourceMappingURL=ConfirmRequest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmRequest.d.ts","sourceRoot":"","sources":["../../../interactions/ConfirmRequest.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,cAAc;IAE3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAMzB,MAAM,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;CACpC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ConfirmRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmRequest.js","sourceRoot":"","sources":["../../../interactions/ConfirmRequest.ts"],"names":[],"mappings":""}
@@ -7,7 +7,8 @@ export interface InteractionScopeValue {
7
7
  attachments: BehaviorAttachment[];
8
8
  onFindings?: (findings: InteractionFinding[]) => void;
9
9
  }
10
- export interface InteractionScopeProps extends InteractionScopeValue {
10
+ export interface InteractionScopeProps extends Omit<InteractionScopeValue, 'context'> {
11
+ context?: InteractionContext;
11
12
  children: ReactNode;
12
13
  }
13
14
  export declare function InteractionScope({ children, dispatcher, context, attachments, onFindings }: InteractionScopeProps): import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"InteractionScope.d.ts","sourceRoot":"","sources":["../../../interactions/InteractionScope.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAsC,MAAM,OAAO,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACpH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAK/C,MAAM,WAAW,qBAAqB;IAElC,UAAU,EAAE,gBAAgB,CAAC;IAG7B,OAAO,EAAE,kBAAkB,CAAC;IAG5B,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAGlC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,EAAE,KAAK,IAAI,CAAC;CACzD;AAID,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAChE,QAAQ,EAAE,SAAS,CAAC;CACvB;AAUD,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,qBAAqB,+BAWjH;AAWD,wBAAgB,mBAAmB,IAAI,qBAAqB,GAAG,SAAS,CAEvE;AASD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,QAAQ,EAAE,GAAG,kBAAkB,EAAE,CAEzF"}
1
+ {"version":3,"file":"InteractionScope.d.ts","sourceRoot":"","sources":["../../../interactions/InteractionScope.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAsC,MAAM,OAAO,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACpH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAK/C,MAAM,WAAW,qBAAqB;IAElC,UAAU,EAAE,gBAAgB,CAAC;IAG7B,OAAO,EAAE,kBAAkB,CAAC;IAG5B,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAGlC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,EAAE,KAAK,IAAI,CAAC;CACzD;AAoBD,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,qBAAqB,EAAE,SAAS,CAAC;IAEjF,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAG7B,QAAQ,EAAE,SAAS,CAAC;CACvB;AAUD,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAyB,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,qBAAqB,+BAWnI;AAWD,wBAAgB,mBAAmB,IAAI,qBAAqB,GAAG,SAAS,CAEvE;AASD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,QAAQ,EAAE,GAAG,kBAAkB,EAAE,CAEzF"}
@@ -1,6 +1,15 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { useContext, useMemo, createContext } from 'react';
3
3
 
4
+ /**
5
+ * The context a scope uses when it was given none.
6
+ *
7
+ * A document whose messages are literal text and whose actions take no arguments resolves nothing, and that is
8
+ * an ordinary document rather than a degenerate one. Requiring a context anyway would make every host invent
9
+ * an empty resolver, and an invented one is a place for a mistake to hide.
10
+ */ const resolvesNothing = {
11
+ resolve: ()=>undefined
12
+ };
4
13
  const Scope = /*#__PURE__*/ createContext(undefined);
5
14
  /**
6
15
  * Provides the dispatcher, the resolution context and the enclosing attachments to everything beneath it.
@@ -9,7 +18,7 @@ const Scope = /*#__PURE__*/ createContext(undefined);
9
18
  * enclosing chain is assembled by the tree rather than reconstructed at each leaf. That is what keeps the
10
19
  * additive rule true in a renderer - a module's behavior is still in scope at a button six levels down,
11
20
  * without the button knowing the module exists.
12
- */ function InteractionScope({ children, dispatcher, context, attachments, onFindings }) {
21
+ */ function InteractionScope({ children, dispatcher, context = resolvesNothing, attachments, onFindings }) {
13
22
  const enclosing = useContext(Scope);
14
23
  const value = useMemo(()=>({
15
24
  dispatcher,
@@ -1 +1 @@
1
- {"version":3,"file":"InteractionScope.js","sources":["../../../interactions/InteractionScope.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\nimport { ActionDispatcher, BehaviorAttachment, InteractionContext, InteractionFinding } from '@cratis/scene.engine';\nimport { Behavior } from '@cratis/scene.model';\n\n/**\n * What the elements beneath a scope need in order to run an interaction.\n */\nexport interface InteractionScopeValue {\n /** The seam that performs the effects. */\n dispatcher: ActionDispatcher;\n\n /** How bindings and localization resolve. */\n context: InteractionContext;\n\n /** The attachments enclosing this point, outermost first. */\n attachments: BehaviorAttachment[];\n\n /** Where a finding goes. Absent means nothing is listening, which is itself worth knowing. */\n onFindings?: (findings: InteractionFinding[]) => void;\n}\n\nconst Scope = createContext<InteractionScopeValue | undefined>(undefined);\n\nexport interface InteractionScopeProps extends InteractionScopeValue {\n children: ReactNode;\n}\n\n/**\n * Provides the dispatcher, the resolution context and the enclosing attachments to everything beneath it.\n *\n * Attachments nest: a scope inside another scope appends to it rather than replacing it, so an element's\n * enclosing chain is assembled by the tree rather than reconstructed at each leaf. That is what keeps the\n * additive rule true in a renderer - a module's behavior is still in scope at a button six levels down,\n * without the button knowing the module exists.\n */\nexport function InteractionScope({ children, dispatcher, context, attachments, onFindings }: InteractionScopeProps) {\n const enclosing = useContext(Scope);\n\n const value = useMemo<InteractionScopeValue>(() => ({\n dispatcher,\n context,\n attachments: [...(enclosing?.attachments ?? []), ...attachments],\n onFindings: onFindings ?? enclosing?.onFindings,\n }), [dispatcher, context, attachments, onFindings, enclosing]);\n\n return <Scope.Provider value={value}>{children}</Scope.Provider>;\n}\n\n/**\n * Reads the enclosing interaction scope.\n *\n * @returns The scope, or `undefined` when the tree is rendered without one.\n * @remarks\n * Rendering without a scope is legitimate - a preview surface showing what a screen looks like has nothing to\n * dispatch to - so this answers `undefined` rather than throwing. What must not happen is an element silently\n * appearing interactive when nothing can run; {@link useInteractions} is where that is decided.\n */\nexport function useInteractionScope(): InteractionScopeValue | undefined {\n return useContext(Scope);\n}\n\n/**\n * Builds the attachment list for one element, so a caller does not have to know the shape.\n *\n * @param level What is being attached to, used when reporting.\n * @param behaviors The behaviors attached there.\n * @returns The attachment, or an empty list when there are none.\n */\nexport function attachmentFor(level: string, behaviors?: Behavior[]): BehaviorAttachment[] {\n return behaviors && behaviors.length > 0 ? [{ level, behaviors }] : [];\n}\n"],"names":["Scope","createContext","undefined","InteractionScope","children","dispatcher","context","attachments","onFindings","enclosing","useContext","value","useMemo","_jsx","Provider","useInteractionScope","attachmentFor","level","behaviors","length"],"mappings":";;;AAwBA,MAAMA,sBAAQC,aAAAA,CAAiDC,SAAAA,CAAAA;AAM/D;;;;;;;AAOC,IACM,SAASC,gBAAAA,CAAiB,EAAEC,QAAQ,EAAEC,UAAU,EAAEC,OAAO,EAAEC,WAAW,EAAEC,UAAU,EAAyB,EAAA;AAC9G,IAAA,MAAMC,YAAYC,UAAAA,CAAWV,KAAAA,CAAAA;IAE7B,MAAMW,KAAAA,GAAQC,OAAAA,CAA+B,KAAO;AAChDP,YAAAA,UAAAA;AACAC,YAAAA,OAAAA;YACAC,WAAAA,EAAa;AAAKE,gBAAAA,GAAAA,SAAAA,EAAWF,eAAe,EAAE;AAAMA,gBAAAA,GAAAA;AAAY,aAAA;AAChEC,YAAAA,UAAAA,EAAYA,cAAcC,SAAAA,EAAWD;AACzC,SAAA,CAAA,EAAI;AAACH,QAAAA,UAAAA;AAAYC,QAAAA,OAAAA;AAASC,QAAAA,WAAAA;AAAaC,QAAAA,UAAAA;AAAYC,QAAAA;AAAU,KAAA,CAAA;IAE7D,qBAAOI,GAAA,CAACb,MAAMc,QAAQ,EAAA;QAACH,KAAAA,EAAOA,KAAAA;AAAQP,QAAAA,QAAAA,EAAAA;;AAC1C;AAEA;;;;;;;;AAQC,IACM,SAASW,mBAAAA,GAAAA;AACZ,IAAA,OAAOL,UAAAA,CAAWV,KAAAA,CAAAA;AACtB;AAEA;;;;;;AAMC,IACM,SAASgB,aAAAA,CAAcC,KAAa,EAAEC,SAAsB,EAAA;AAC/D,IAAA,OAAOA,SAAAA,IAAaA,SAAAA,CAAUC,MAAM,GAAG,CAAA,GAAI;AAAC,QAAA;AAAEF,YAAAA,KAAAA;AAAOC,YAAAA;AAAU;AAAE,KAAA,GAAG,EAAE;AAC1E;;"}
1
+ {"version":3,"file":"InteractionScope.js","sources":["../../../interactions/InteractionScope.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { ReactNode, createContext, useContext, useMemo } from 'react';\nimport { ActionDispatcher, BehaviorAttachment, InteractionContext, InteractionFinding } from '@cratis/scene.engine';\nimport { Behavior } from '@cratis/scene.model';\n\n/**\n * What the elements beneath a scope need in order to run an interaction.\n */\nexport interface InteractionScopeValue {\n /** The seam that performs the effects. */\n dispatcher: ActionDispatcher;\n\n /** How bindings and localization resolve. */\n context: InteractionContext;\n\n /** The attachments enclosing this point, outermost first. */\n attachments: BehaviorAttachment[];\n\n /** Where a finding goes. Absent means nothing is listening, which is itself worth knowing. */\n onFindings?: (findings: InteractionFinding[]) => void;\n}\n\n/**\n * The context a scope uses when it was given none.\n *\n * A document whose messages are literal text and whose actions take no arguments resolves nothing, and that is\n * an ordinary document rather than a degenerate one. Requiring a context anyway would make every host invent\n * an empty resolver, and an invented one is a place for a mistake to hide.\n */\nconst resolvesNothing: InteractionContext = { resolve: () => undefined };\n\nconst Scope = createContext<InteractionScopeValue | undefined>(undefined);\n\n/**\n * The properties of {@link InteractionScope}.\n *\n * The context is the one thing an author may leave out, because a document whose messages are literal text and\n * whose actions take no arguments resolves nothing. Everything beneath a scope still reads a context that is\n * definitely there, so only the author is spared, not the code doing the work.\n */\nexport interface InteractionScopeProps extends Omit<InteractionScopeValue, 'context'> {\n /** How bindings and localization resolve. Omitted means nothing resolves. */\n context?: InteractionContext;\n\n /** What the scope encloses. */\n children: ReactNode;\n}\n\n/**\n * Provides the dispatcher, the resolution context and the enclosing attachments to everything beneath it.\n *\n * Attachments nest: a scope inside another scope appends to it rather than replacing it, so an element's\n * enclosing chain is assembled by the tree rather than reconstructed at each leaf. That is what keeps the\n * additive rule true in a renderer - a module's behavior is still in scope at a button six levels down,\n * without the button knowing the module exists.\n */\nexport function InteractionScope({ children, dispatcher, context = resolvesNothing, attachments, onFindings }: InteractionScopeProps) {\n const enclosing = useContext(Scope);\n\n const value = useMemo<InteractionScopeValue>(() => ({\n dispatcher,\n context,\n attachments: [...(enclosing?.attachments ?? []), ...attachments],\n onFindings: onFindings ?? enclosing?.onFindings,\n }), [dispatcher, context, attachments, onFindings, enclosing]);\n\n return <Scope.Provider value={value}>{children}</Scope.Provider>;\n}\n\n/**\n * Reads the enclosing interaction scope.\n *\n * @returns The scope, or `undefined` when the tree is rendered without one.\n * @remarks\n * Rendering without a scope is legitimate - a preview surface showing what a screen looks like has nothing to\n * dispatch to - so this answers `undefined` rather than throwing. What must not happen is an element silently\n * appearing interactive when nothing can run; {@link useInteractions} is where that is decided.\n */\nexport function useInteractionScope(): InteractionScopeValue | undefined {\n return useContext(Scope);\n}\n\n/**\n * Builds the attachment list for one element, so a caller does not have to know the shape.\n *\n * @param level What is being attached to, used when reporting.\n * @param behaviors The behaviors attached there.\n * @returns The attachment, or an empty list when there are none.\n */\nexport function attachmentFor(level: string, behaviors?: Behavior[]): BehaviorAttachment[] {\n return behaviors && behaviors.length > 0 ? [{ level, behaviors }] : [];\n}\n"],"names":["resolvesNothing","resolve","undefined","Scope","createContext","InteractionScope","children","dispatcher","context","attachments","onFindings","enclosing","useContext","value","useMemo","_jsx","Provider","useInteractionScope","attachmentFor","level","behaviors","length"],"mappings":";;;AAwBA;;;;;;AAMC,IACD,MAAMA,eAAAA,GAAsC;AAAEC,IAAAA,OAAAA,EAAS,IAAMC;AAAU,CAAA;AAEvE,MAAMC,sBAAQC,aAAAA,CAAiDF,SAAAA,CAAAA;AAiB/D;;;;;;;AAOC,IACM,SAASG,gBAAAA,CAAiB,EAAEC,QAAQ,EAAEC,UAAU,EAAEC,OAAAA,GAAUR,eAAe,EAAES,WAAW,EAAEC,UAAU,EAAyB,EAAA;AAChI,IAAA,MAAMC,YAAYC,UAAAA,CAAWT,KAAAA,CAAAA;IAE7B,MAAMU,KAAAA,GAAQC,OAAAA,CAA+B,KAAO;AAChDP,YAAAA,UAAAA;AACAC,YAAAA,OAAAA;YACAC,WAAAA,EAAa;AAAKE,gBAAAA,GAAAA,SAAAA,EAAWF,eAAe,EAAE;AAAMA,gBAAAA,GAAAA;AAAY,aAAA;AAChEC,YAAAA,UAAAA,EAAYA,cAAcC,SAAAA,EAAWD;AACzC,SAAA,CAAA,EAAI;AAACH,QAAAA,UAAAA;AAAYC,QAAAA,OAAAA;AAASC,QAAAA,WAAAA;AAAaC,QAAAA,UAAAA;AAAYC,QAAAA;AAAU,KAAA,CAAA;IAE7D,qBAAOI,GAAA,CAACZ,MAAMa,QAAQ,EAAA;QAACH,KAAAA,EAAOA,KAAAA;AAAQP,QAAAA,QAAAA,EAAAA;;AAC1C;AAEA;;;;;;;;AAQC,IACM,SAASW,mBAAAA,GAAAA;AACZ,IAAA,OAAOL,UAAAA,CAAWT,KAAAA,CAAAA;AACtB;AAEA;;;;;;AAMC,IACM,SAASe,aAAAA,CAAcC,KAAa,EAAEC,SAAsB,EAAA;AAC/D,IAAA,OAAOA,SAAAA,IAAaA,SAAAA,CAAUC,MAAM,GAAG,CAAA,GAAI;AAAC,QAAA;AAAEF,YAAAA,KAAAA;AAAOC,YAAAA;AAAU;AAAE,KAAA,GAAG,EAAE;AAC1E;;"}
@@ -0,0 +1,7 @@
1
+ import { SceneNotification } from './SceneNotification';
2
+ export interface NotificationHostProps {
3
+ readonly notifications: readonly SceneNotification[];
4
+ readonly onDismiss: (id: number) => void;
5
+ }
6
+ export declare function NotificationHost({ notifications, onDismiss }: NotificationHostProps): import("react").JSX.Element | null;
7
+ //# sourceMappingURL=NotificationHost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationHost.d.ts","sourceRoot":"","sources":["../../../interactions/NotificationHost.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAKxD,MAAM,WAAW,qBAAqB;IAElC,QAAQ,CAAC,aAAa,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAGrD,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5C;AAgBD,wBAAgB,gBAAgB,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,EAAE,qBAAqB,sCAgBnF"}
@@ -0,0 +1,71 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { NotificationLevel } from '@cratis/scene.model';
3
+
4
+ const colours = {
5
+ [NotificationLevel.Info]: '#1e6fbf',
6
+ [NotificationLevel.Warning]: '#b8860b',
7
+ [NotificationLevel.Error]: '#c0392b'
8
+ };
9
+ /**
10
+ * Shows what a document's `notify` asked to say.
11
+ *
12
+ * Deliberately plain. An application with a design system of its own passes its own `notify` to the dispatcher
13
+ * and never renders this; what this exists for is that the default is *something* rather than a console line
14
+ * nobody is looking at.
15
+ * @param props The {@link NotificationHostProps}.
16
+ */ function NotificationHost({ notifications, onDismiss }) {
17
+ if (notifications.length === 0) return null;
18
+ return /*#__PURE__*/ jsx("div", {
19
+ role: "log",
20
+ "aria-live": "polite",
21
+ "data-scene-notifications": true,
22
+ style: {
23
+ position: 'fixed',
24
+ top: '1rem',
25
+ right: '1rem',
26
+ display: 'flex',
27
+ flexDirection: 'column',
28
+ gap: '0.5rem',
29
+ zIndex: 1000
30
+ },
31
+ children: notifications.map((notification)=>/*#__PURE__*/ jsxs("div", {
32
+ "data-scene-notification": notification.level,
33
+ style: {
34
+ display: 'flex',
35
+ alignItems: 'center',
36
+ gap: '0.75rem',
37
+ maxWidth: '24rem',
38
+ padding: '0.625rem 0.75rem',
39
+ borderRadius: 4,
40
+ border: `1px solid ${colours[notification.level]}`,
41
+ borderLeftWidth: 4,
42
+ background: '#fff',
43
+ color: '#1a1a1a'
44
+ },
45
+ children: [
46
+ /*#__PURE__*/ jsx("span", {
47
+ style: {
48
+ flex: 1
49
+ },
50
+ children: notification.message
51
+ }),
52
+ /*#__PURE__*/ jsx("button", {
53
+ type: "button",
54
+ "aria-label": "Dismiss",
55
+ onClick: ()=>onDismiss(notification.id),
56
+ style: {
57
+ border: 'none',
58
+ background: 'none',
59
+ cursor: 'pointer',
60
+ fontSize: '1rem',
61
+ lineHeight: 1
62
+ },
63
+ children: "x"
64
+ })
65
+ ]
66
+ }, notification.id))
67
+ });
68
+ }
69
+
70
+ export { NotificationHost };
71
+ //# sourceMappingURL=NotificationHost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationHost.js","sources":["../../../interactions/NotificationHost.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { NotificationLevel } from '@cratis/scene.model';\nimport { SceneNotification } from './SceneNotification';\n\n/**\n * The properties of {@link NotificationHost}.\n */\nexport interface NotificationHostProps {\n /** What is currently being said, oldest first. */\n readonly notifications: readonly SceneNotification[];\n\n /** Called when one is dismissed. */\n readonly onDismiss: (id: number) => void;\n}\n\nconst colours: Record<NotificationLevel, string> = {\n [NotificationLevel.Info]: '#1e6fbf',\n [NotificationLevel.Warning]: '#b8860b',\n [NotificationLevel.Error]: '#c0392b',\n};\n\n/**\n * Shows what a document's `notify` asked to say.\n *\n * Deliberately plain. An application with a design system of its own passes its own `notify` to the dispatcher\n * and never renders this; what this exists for is that the default is *something* rather than a console line\n * nobody is looking at.\n * @param props The {@link NotificationHostProps}.\n */\nexport function NotificationHost({ notifications, onDismiss }: NotificationHostProps) {\n if (notifications.length === 0) return null;\n\n return (\n <div role=\"log\" aria-live=\"polite\" data-scene-notifications style={{ position: 'fixed', top: '1rem', right: '1rem', display: 'flex', flexDirection: 'column', gap: '0.5rem', zIndex: 1000 }}>\n {notifications.map(notification => (\n <div\n key={notification.id}\n data-scene-notification={notification.level}\n style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', maxWidth: '24rem', padding: '0.625rem 0.75rem', borderRadius: 4, border: `1px solid ${colours[notification.level]}`, borderLeftWidth: 4, background: '#fff', color: '#1a1a1a' }}>\n <span style={{ flex: 1 }}>{notification.message}</span>\n <button type=\"button\" aria-label=\"Dismiss\" onClick={() => onDismiss(notification.id)} style={{ border: 'none', background: 'none', cursor: 'pointer', fontSize: '1rem', lineHeight: 1 }}>x</button>\n </div>\n ))}\n </div>\n );\n}\n"],"names":["colours","NotificationLevel","Info","Warning","Error","NotificationHost","notifications","onDismiss","length","_jsx","div","role","aria-live","data-scene-notifications","style","position","top","right","display","flexDirection","gap","zIndex","map","notification","_jsxs","data-scene-notification","level","alignItems","maxWidth","padding","borderRadius","border","borderLeftWidth","background","color","span","flex","message","button","type","aria-label","onClick","id","cursor","fontSize","lineHeight"],"mappings":";;;AAiBA,MAAMA,OAAAA,GAA6C;IAC/C,CAACC,iBAAAA,CAAkBC,IAAI,GAAG,SAAA;IAC1B,CAACD,iBAAAA,CAAkBE,OAAO,GAAG,SAAA;IAC7B,CAACF,iBAAAA,CAAkBG,KAAK,GAAG;AAC/B,CAAA;AAEA;;;;;;;AAOC,IACM,SAASC,gBAAAA,CAAiB,EAAEC,aAAa,EAAEC,SAAS,EAAyB,EAAA;AAChF,IAAA,IAAID,aAAAA,CAAcE,MAAM,KAAK,CAAA,EAAG,OAAO,IAAA;AAEvC,IAAA,qBACIC,GAAA,CAACC,KAAAA,EAAAA;QAAIC,IAAAA,EAAK,KAAA;QAAMC,WAAAA,EAAU,QAAA;QAASC,0BAAwB,EAAA,IAAA;QAACC,KAAAA,EAAO;YAAEC,QAAAA,EAAU,OAAA;YAASC,GAAAA,EAAK,MAAA;YAAQC,KAAAA,EAAO,MAAA;YAAQC,OAAAA,EAAS,MAAA;YAAQC,aAAAA,EAAe,QAAA;YAAUC,GAAAA,EAAK,QAAA;YAAUC,MAAAA,EAAQ;AAAK,SAAA;AACrLf,QAAAA,QAAAA,EAAAA,aAAAA,CAAcgB,GAAG,CAACC,CAAAA,YAAAA,iBACfC,IAAA,CAACd,KAAAA,EAAAA;AAEGe,gBAAAA,yBAAAA,EAAyBF,aAAaG,KAAK;gBAC3CZ,KAAAA,EAAO;oBAAEI,OAAAA,EAAS,MAAA;oBAAQS,UAAAA,EAAY,QAAA;oBAAUP,GAAAA,EAAK,SAAA;oBAAWQ,QAAAA,EAAU,OAAA;oBAASC,OAAAA,EAAS,kBAAA;oBAAoBC,YAAAA,EAAc,CAAA;oBAAGC,MAAAA,EAAQ,CAAC,UAAU,EAAE/B,OAAO,CAACuB,YAAAA,CAAaG,KAAK,CAAC,CAAA,CAAE;oBAAEM,eAAAA,EAAiB,CAAA;oBAAGC,UAAAA,EAAY,MAAA;oBAAQC,KAAAA,EAAO;AAAU,iBAAA;;kCAC9OzB,GAAA,CAAC0B,MAAAA,EAAAA;wBAAKrB,KAAAA,EAAO;4BAAEsB,IAAAA,EAAM;AAAE,yBAAA;AAAIb,wBAAAA,QAAAA,EAAAA,YAAAA,CAAac;;kCACxC5B,GAAA,CAAC6B,QAAAA,EAAAA;wBAAOC,IAAAA,EAAK,QAAA;wBAASC,YAAAA,EAAW,SAAA;wBAAUC,OAAAA,EAAS,IAAMlC,SAAAA,CAAUgB,YAAAA,CAAamB,EAAE,CAAA;wBAAG5B,KAAAA,EAAO;4BAAEiB,MAAAA,EAAQ,MAAA;4BAAQE,UAAAA,EAAY,MAAA;4BAAQU,MAAAA,EAAQ,SAAA;4BAAWC,QAAAA,EAAU,MAAA;4BAAQC,UAAAA,EAAY;AAAE,yBAAA;AAAG,wBAAA,QAAA,EAAA;;;AAJpLtB,aAAAA,EAAAA,YAAAA,CAAamB,EAAE,CAAA;;AASxC;;"}
@@ -0,0 +1,7 @@
1
+ import { NotificationLevel } from '@cratis/scene.model';
2
+ export interface SceneNotification {
3
+ readonly id: number;
4
+ readonly level: NotificationLevel;
5
+ readonly message: string;
6
+ }
7
+ //# sourceMappingURL=SceneNotification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SceneNotification.d.ts","sourceRoot":"","sources":["../../../interactions/SceneNotification.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAKxD,MAAM,WAAW,iBAAiB;IAE9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAGpB,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAGlC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SceneNotification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SceneNotification.js","sourceRoot":"","sources":["../../../interactions/SceneNotification.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ export interface UnresolvedAction {
2
+ readonly id: number;
3
+ readonly action: string;
4
+ }
5
+ //# sourceMappingURL=UnresolvedAction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnresolvedAction.d.ts","sourceRoot":"","sources":["../../../interactions/UnresolvedAction.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,gBAAgB;IAE7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAGpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC3B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=UnresolvedAction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnresolvedAction.js","sourceRoot":"","sources":["../../../interactions/UnresolvedAction.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ import { UnresolvedAction } from './UnresolvedAction';
2
+ export interface UnresolvedActionHostProps {
3
+ readonly unresolved: readonly UnresolvedAction[];
4
+ }
5
+ export declare function UnresolvedActionHost({ unresolved }: UnresolvedActionHostProps): import("react").JSX.Element | null;
6
+ //# sourceMappingURL=UnresolvedActionHost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnresolvedActionHost.d.ts","sourceRoot":"","sources":["../../../interactions/UnresolvedActionHost.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAKtD,MAAM,WAAW,yBAAyB;IAEtC,QAAQ,CAAC,UAAU,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACpD;AAUD,wBAAgB,oBAAoB,CAAC,EAAE,UAAU,EAAE,EAAE,yBAAyB,sCAW7E"}
@@ -0,0 +1,51 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ /**
6
+ * Shows what a document asked for that this host cannot do.
7
+ *
8
+ * Only useful while an application is being built, which is why an application that has wired everything will
9
+ * never see it. It is rendered rather than logged because the person who would fix it is usually looking at
10
+ * the screen and not at the console.
11
+ * @param props The {@link UnresolvedActionHostProps}.
12
+ */ function UnresolvedActionHost({ unresolved }) {
13
+ if (unresolved.length === 0) return null;
14
+ return /*#__PURE__*/ jsxs("div", {
15
+ role: "status",
16
+ "data-scene-unresolved": true,
17
+ style: {
18
+ position: 'fixed',
19
+ bottom: '1rem',
20
+ left: '1rem',
21
+ maxWidth: '28rem',
22
+ padding: '0.625rem 0.75rem',
23
+ borderRadius: 4,
24
+ border: '1px solid #c0392b',
25
+ background: '#fff',
26
+ color: '#1a1a1a',
27
+ zIndex: 1000
28
+ },
29
+ children: [
30
+ /*#__PURE__*/ jsx("strong", {
31
+ style: {
32
+ display: 'block',
33
+ marginBottom: '0.25rem'
34
+ },
35
+ children: "This surface cannot do what the document asked"
36
+ }),
37
+ /*#__PURE__*/ jsx("ul", {
38
+ style: {
39
+ margin: 0,
40
+ paddingLeft: '1.25rem'
41
+ },
42
+ children: unresolved.map((action)=>/*#__PURE__*/ jsx("li", {
43
+ children: action.action
44
+ }, action.id))
45
+ })
46
+ ]
47
+ });
48
+ }
49
+
50
+ export { UnresolvedActionHost };
51
+ //# sourceMappingURL=UnresolvedActionHost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnresolvedActionHost.js","sources":["../../../interactions/UnresolvedActionHost.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { UnresolvedAction } from './UnresolvedAction';\n\n/**\n * The properties of {@link UnresolvedActionHost}.\n */\nexport interface UnresolvedActionHostProps {\n /** What has been asked for and could not be done. */\n readonly unresolved: readonly UnresolvedAction[];\n}\n\n/**\n * Shows what a document asked for that this host cannot do.\n *\n * Only useful while an application is being built, which is why an application that has wired everything will\n * never see it. It is rendered rather than logged because the person who would fix it is usually looking at\n * the screen and not at the console.\n * @param props The {@link UnresolvedActionHostProps}.\n */\nexport function UnresolvedActionHost({ unresolved }: UnresolvedActionHostProps) {\n if (unresolved.length === 0) return null;\n\n return (\n <div role=\"status\" data-scene-unresolved style={{ position: 'fixed', bottom: '1rem', left: '1rem', maxWidth: '28rem', padding: '0.625rem 0.75rem', borderRadius: 4, border: '1px solid #c0392b', background: '#fff', color: '#1a1a1a', zIndex: 1000 }}>\n <strong style={{ display: 'block', marginBottom: '0.25rem' }}>This surface cannot do what the document asked</strong>\n <ul style={{ margin: 0, paddingLeft: '1.25rem' }}>\n {unresolved.map(action => <li key={action.id}>{action.action}</li>)}\n </ul>\n </div>\n );\n}\n"],"names":["UnresolvedActionHost","unresolved","length","_jsxs","div","role","data-scene-unresolved","style","position","bottom","left","maxWidth","padding","borderRadius","border","background","color","zIndex","_jsx","strong","display","marginBottom","ul","margin","paddingLeft","map","action","li","id"],"mappings":";;AAAA;AACA;AAYA;;;;;;;AAOC,IACM,SAASA,oBAAAA,CAAqB,EAAEC,UAAU,EAA6B,EAAA;AAC1E,IAAA,IAAIA,UAAAA,CAAWC,MAAM,KAAK,CAAA,EAAG,OAAO,IAAA;AAEpC,IAAA,qBACIC,IAAA,CAACC,KAAAA,EAAAA;QAAIC,IAAAA,EAAK,QAAA;QAASC,uBAAqB,EAAA,IAAA;QAACC,KAAAA,EAAO;YAAEC,QAAAA,EAAU,OAAA;YAASC,MAAAA,EAAQ,MAAA;YAAQC,IAAAA,EAAM,MAAA;YAAQC,QAAAA,EAAU,OAAA;YAASC,OAAAA,EAAS,kBAAA;YAAoBC,YAAAA,EAAc,CAAA;YAAGC,MAAAA,EAAQ,mBAAA;YAAqBC,UAAAA,EAAY,MAAA;YAAQC,KAAAA,EAAO,SAAA;YAAWC,MAAAA,EAAQ;AAAK,SAAA;;0BAChPC,GAAA,CAACC,QAAAA,EAAAA;gBAAOZ,KAAAA,EAAO;oBAAEa,OAAAA,EAAS,OAAA;oBAASC,YAAAA,EAAc;AAAU,iBAAA;AAAG,gBAAA,QAAA,EAAA;;0BAC9DH,GAAA,CAACI,IAAAA,EAAAA;gBAAGf,KAAAA,EAAO;oBAAEgB,MAAAA,EAAQ,CAAA;oBAAGC,WAAAA,EAAa;AAAU,iBAAA;AAC1CvB,gBAAAA,QAAAA,EAAAA,UAAAA,CAAWwB,GAAG,CAACC,CAAAA,MAAAA,iBAAUR,GAAA,CAACS,IAAAA,EAAAA;AAAoBD,wBAAAA,QAAAA,EAAAA,MAAAA,CAAOA;AAAnBA,qBAAAA,EAAAA,MAAAA,CAAOE,EAAE,CAAA;;;;AAI5D;;"}
@@ -1,4 +1,11 @@
1
1
  export * from './InteractionScope';
2
2
  export * from './useInteractions';
3
3
  export * from './createBrowserDispatcher';
4
+ export * from './ConfirmHost';
5
+ export * from './ConfirmRequest';
6
+ export * from './NotificationHost';
7
+ export * from './SceneNotification';
8
+ export * from './UnresolvedAction';
9
+ export * from './UnresolvedActionHost';
10
+ export * from './useInteractionHosts';
4
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../interactions/index.ts"],"names":[],"mappings":"AAGA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../interactions/index.ts"],"names":[],"mappings":"AAGA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
@@ -1,4 +1,11 @@
1
1
  export * from './InteractionScope';
2
2
  export * from './useInteractions';
3
3
  export * from './createBrowserDispatcher';
4
+ export * from './ConfirmHost';
5
+ export * from './ConfirmRequest';
6
+ export * from './NotificationHost';
7
+ export * from './SceneNotification';
8
+ export * from './UnresolvedAction';
9
+ export * from './UnresolvedActionHost';
10
+ export * from './useInteractionHosts';
4
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../interactions/index.ts"],"names":[],"mappings":"AAGA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../interactions/index.ts"],"names":[],"mappings":"AAGA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+ import { BrowserDispatcherHost } from './createBrowserDispatcher';
3
+ export interface InteractionHosts {
4
+ readonly host: Pick<BrowserDispatcherHost, 'notify' | 'confirm' | 'onUnsupported'>;
5
+ readonly surfaces: ReactNode;
6
+ }
7
+ export interface InteractionHostOptions {
8
+ readonly dismissAfter?: number;
9
+ }
10
+ export declare function useInteractionHosts(options?: InteractionHostOptions): InteractionHosts;
11
+ //# sourceMappingURL=useInteractionHosts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInteractionHosts.d.ts","sourceRoot":"","sources":["../../../interactions/useInteractionHosts.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAA0C,MAAM,OAAO,CAAC;AAE1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAWlE,MAAM,WAAW,gBAAgB;IAE7B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,SAAS,GAAG,eAAe,CAAC,CAAC;IAGnF,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAChC;AAKD,MAAM,WAAW,sBAAsB;IAEnC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAClC;AAuBD,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,sBAA2B,GAAG,gBAAgB,CA+C1F"}
@@ -0,0 +1,107 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { useState, useRef, useCallback, useMemo } from 'react';
3
+ import { ConfirmHost } from './ConfirmHost.js';
4
+ import { NotificationHost } from './NotificationHost.js';
5
+ import { UnresolvedActionHost } from './UnresolvedActionHost.js';
6
+
7
+ /**
8
+ * Provides the default surfaces for the actions that need somewhere to appear.
9
+ *
10
+ * `notify` and `confirm` are the two actions a document can take that have no backend and no route: they are
11
+ * purely things the user sees. Without a surface, a host either invents one or the action goes to the console,
12
+ * which is why these ship with Scene rather than being every application's first chore.
13
+ *
14
+ * The three are returned as one unit because they are wired the same way and forgetting to render one of them
15
+ * is exactly the failure they exist to prevent:
16
+ *
17
+ * ```tsx
18
+ * const { host, surfaces } = useInteractionHosts();
19
+ * const dispatcher = useMemo(() => createBrowserDispatcher({ ...host, executeCommand, navigate }), [host]);
20
+ *
21
+ * return <InteractionScope dispatcher={dispatcher}>{children}{surfaces}</InteractionScope>;
22
+ * ```
23
+ *
24
+ * An application with a design system of its own passes its own `notify` after the spread and keeps the rest.
25
+ * @param options The {@link InteractionHostOptions}.
26
+ * @returns The {@link InteractionHosts}.
27
+ */ function useInteractionHosts(options = {}) {
28
+ const { dismissAfter = 6000 } = options;
29
+ const [notifications, setNotifications] = useState([]);
30
+ const [unresolved, setUnresolved] = useState([]);
31
+ const [request, setRequest] = useState(undefined);
32
+ const nextId = useRef(0);
33
+ const dismiss = useCallback((id)=>setNotifications((current)=>current.filter((_)=>_.id !== id)), []);
34
+ const notify = useCallback((level, message)=>{
35
+ const id = nextId.current++;
36
+ setNotifications((current)=>[
37
+ ...current,
38
+ {
39
+ id,
40
+ level,
41
+ message
42
+ }
43
+ ]);
44
+ if (dismissAfter > 0) {
45
+ setTimeout(()=>setNotifications((current)=>current.filter((_)=>_.id !== id)), dismissAfter);
46
+ }
47
+ }, [
48
+ dismissAfter
49
+ ]);
50
+ const confirm = useCallback((message)=>new Promise((resolve)=>{
51
+ setRequest({
52
+ message,
53
+ answer (confirmed) {
54
+ // Cleared before resolving, so the sequence that continues cannot find a question on screen
55
+ // that has already been answered.
56
+ setRequest(undefined);
57
+ resolve(confirmed);
58
+ }
59
+ });
60
+ }), []);
61
+ const onUnsupported = useCallback((action)=>{
62
+ // Reported once per distinct action. An unsupported action on a hover or an interval would otherwise
63
+ // grow the list until it covered the application it is trying to tell you about.
64
+ setUnresolved((current)=>current.some((_)=>_.action === action) ? current : [
65
+ ...current,
66
+ {
67
+ id: nextId.current++,
68
+ action
69
+ }
70
+ ]);
71
+ }, []);
72
+ const host = useMemo(()=>({
73
+ notify,
74
+ confirm,
75
+ onUnsupported
76
+ }), [
77
+ notify,
78
+ confirm,
79
+ onUnsupported
80
+ ]);
81
+ const surfaces = useMemo(()=>/*#__PURE__*/ jsxs(Fragment, {
82
+ children: [
83
+ /*#__PURE__*/ jsx(NotificationHost, {
84
+ notifications: notifications,
85
+ onDismiss: dismiss
86
+ }),
87
+ /*#__PURE__*/ jsx(ConfirmHost, {
88
+ request: request
89
+ }),
90
+ /*#__PURE__*/ jsx(UnresolvedActionHost, {
91
+ unresolved: unresolved
92
+ })
93
+ ]
94
+ }), [
95
+ notifications,
96
+ dismiss,
97
+ request,
98
+ unresolved
99
+ ]);
100
+ return {
101
+ host,
102
+ surfaces
103
+ };
104
+ }
105
+
106
+ export { useInteractionHosts };
107
+ //# sourceMappingURL=useInteractionHosts.js.map