@dxos/plugin-status-bar 0.7.4 → 0.7.5-labs.071a3e2

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 (47) hide show
  1. package/dist/lib/browser/index.mjs +156 -91
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +186 -114
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +156 -90
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/StatusBarPlugin.d.ts +1 -3
  11. package/dist/types/src/StatusBarPlugin.d.ts.map +1 -1
  12. package/dist/types/src/components/FeedbackForm.d.ts.map +1 -1
  13. package/dist/types/src/components/StatusBar.d.ts +10 -24
  14. package/dist/types/src/components/StatusBar.d.ts.map +1 -1
  15. package/dist/types/src/components/StatusBarPanel.d.ts +1 -0
  16. package/dist/types/src/components/StatusBarPanel.d.ts.map +1 -1
  17. package/dist/types/src/components/VersionNumber.d.ts +3 -0
  18. package/dist/types/src/components/VersionNumber.d.ts.map +1 -0
  19. package/dist/types/src/index.d.ts +2 -3
  20. package/dist/types/src/index.d.ts.map +1 -1
  21. package/dist/types/src/meta.d.ts +1 -2
  22. package/dist/types/src/meta.d.ts.map +1 -1
  23. package/dist/types/src/translations.d.ts +1 -1
  24. package/dist/types/src/translations.d.ts.map +1 -1
  25. package/dist/types/tsconfig.tsbuildinfo +1 -0
  26. package/package.json +18 -24
  27. package/src/StatusBarPlugin.tsx +47 -24
  28. package/src/components/FeedbackForm.tsx +8 -27
  29. package/src/components/StatusBar.stories.tsx +2 -2
  30. package/src/components/StatusBar.tsx +8 -34
  31. package/src/components/StatusBarPanel.tsx +35 -26
  32. package/src/components/VersionNumber.tsx +86 -0
  33. package/src/index.ts +2 -5
  34. package/src/meta.ts +1 -1
  35. package/src/translations.ts +18 -2
  36. package/dist/lib/browser/chunk-4KDZC7WS.mjs +0 -14
  37. package/dist/lib/browser/chunk-4KDZC7WS.mjs.map +0 -7
  38. package/dist/lib/browser/meta.mjs +0 -9
  39. package/dist/lib/browser/meta.mjs.map +0 -7
  40. package/dist/lib/node/chunk-OGG3PMIV.cjs +0 -37
  41. package/dist/lib/node/chunk-OGG3PMIV.cjs.map +0 -7
  42. package/dist/lib/node/meta.cjs +0 -30
  43. package/dist/lib/node/meta.cjs.map +0 -7
  44. package/dist/lib/node-esm/chunk-UVUSU6KS.mjs +0 -16
  45. package/dist/lib/node-esm/chunk-UVUSU6KS.mjs.map +0 -7
  46. package/dist/lib/node-esm/meta.mjs +0 -10
  47. package/dist/lib/node-esm/meta.mjs.map +0 -7
@@ -1 +1 @@
1
- {"version":3,"file":"StatusBarPlugin.d.ts","sourceRoot":"","sources":["../../../src/StatusBarPlugin.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAM7G,MAAM,MAAM,uBAAuB,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAE7E,eAAO,MAAM,eAAe,QAAO,gBAAgB,CAAC,uBAAuB,CAkB1E,CAAC"}
1
+ {"version":3,"file":"StatusBarPlugin.d.ts","sourceRoot":"","sources":["../../../src/StatusBarPlugin.tsx"],"names":[],"mappings":"AAqBA,eAAO,MAAM,eAAe,4CAkCxB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackForm.d.ts","sourceRoot":"","sources":["../../../../src/components/FeedbackForm.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAsB,MAAM,OAAO,CAAC;AA+B3C,eAAO,MAAM,YAAY,gBAAiB;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,sBAwFhE,CAAC"}
1
+ {"version":3,"file":"FeedbackForm.d.ts","sourceRoot":"","sources":["../../../../src/components/FeedbackForm.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAsB,MAAM,OAAO,CAAC;AAa3C,eAAO,MAAM,YAAY,gBAAiB;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,sBAwFhE,CAAC"}
@@ -1,40 +1,26 @@
1
- import React, { type ReactNode } from 'react';
2
- declare const StatusBarButton: React.ForwardRefExoticComponent<Omit<{
3
- children: ReactNode;
1
+ import React, { type ComponentPropsWithRef, type ReactNode } from 'react';
2
+ import { type ThemedClassName } from '@dxos/react-ui';
3
+ type StatusBarButtonProps = ThemedClassName<ComponentPropsWithRef<'button'> & {
4
4
  asChild?: boolean;
5
- }, "className"> & {
6
- classNames?: import("@dxos/react-ui").ClassNameValue;
7
- } & React.HTMLAttributes<HTMLButtonElement> & React.RefAttributes<HTMLButtonElement>>;
5
+ }>;
6
+ declare const StatusBarButton: React.ForwardRefExoticComponent<Omit<StatusBarButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
8
7
  export default StatusBarButton;
8
+ type StatusBarItemProps = ThemedClassName<ComponentPropsWithRef<'div'>>;
9
9
  export declare const StatusBar: {
10
- Container: React.ForwardRefExoticComponent<Omit<{
11
- children: ReactNode;
12
- }, "className"> & {
13
- classNames?: import("@dxos/react-ui").ClassNameValue;
14
- } & React.RefAttributes<HTMLDivElement>>;
15
10
  Text: React.ForwardRefExoticComponent<Omit<{
16
11
  children: ReactNode;
17
12
  }, "className"> & {
18
13
  classNames?: import("@dxos/react-ui").ClassNameValue;
19
14
  } & React.RefAttributes<HTMLSpanElement>>;
20
- Item: React.ForwardRefExoticComponent<Omit<{
21
- children: ReactNode;
22
- }, "className"> & {
23
- classNames?: import("@dxos/react-ui").ClassNameValue;
24
- } & React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
25
- Button: React.ForwardRefExoticComponent<Omit<{
26
- children: ReactNode;
27
- asChild?: boolean;
28
- }, "className"> & {
29
- classNames?: import("@dxos/react-ui").ClassNameValue;
30
- } & React.HTMLAttributes<HTMLButtonElement> & React.RefAttributes<HTMLButtonElement>>;
15
+ Item: React.ForwardRefExoticComponent<Omit<StatusBarItemProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
16
+ Button: React.ForwardRefExoticComponent<Omit<StatusBarButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
31
17
  StartContent: React.ForwardRefExoticComponent<Omit<{
32
- children: ReactNode;
18
+ children?: ReactNode | undefined;
33
19
  }, "className"> & {
34
20
  classNames?: import("@dxos/react-ui").ClassNameValue;
35
21
  } & React.RefAttributes<HTMLDivElement>>;
36
22
  EndContent: React.ForwardRefExoticComponent<Omit<{
37
- children: ReactNode;
23
+ children?: ReactNode | undefined;
38
24
  }, "className"> & {
39
25
  classNames?: import("@dxos/react-ui").ClassNameValue;
40
26
  } & React.RefAttributes<HTMLDivElement>>;
@@ -1 +1 @@
1
- {"version":3,"file":"StatusBar.d.ts","sourceRoot":"","sources":["../../../../src/components/StatusBar.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAmC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAgB/E,QAAA,MAAM,eAAe;cAHmC,SAAS;cAAY,OAAO;;;qFAsBnF,CAAC;AAEF,eAAe,eAAe,CAAC;AAwD/B,eAAO,MAAM,SAAS;;kBAvCqC,SAAS;;;;;kBAjDd,SAAS;;;;;kBAkCT,SAAS;;;;;kBA1BP,SAAS;kBAAY,OAAO;;;;;kBAgE/B,SAAS;;;;;kBAQX,SAAS;;;;CAe3D,CAAC"}
1
+ {"version":3,"file":"StatusBar.d.ts","sourceRoot":"","sources":["../../../../src/components/StatusBar.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,EAAE,KAAK,qBAAqB,EAAsC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE9G,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAWtD,KAAK,oBAAoB,GAAG,eAAe,CAAC,qBAAqB,CAAC,QAAQ,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAErG,QAAA,MAAM,eAAe,6GAmBpB,CAAC;AAEF,eAAe,eAAe,CAAC;AAE/B,KAAK,kBAAkB,GAAG,eAAe,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC;AA+BxE,eAAO,MAAM,SAAS;;kBAhEgC,SAAS;;;;;;;;;;;;;;;;CAsE9D,CAAC"}
@@ -1,3 +1,4 @@
1
1
  import React from 'react';
2
+ export declare const StatusBarActions: () => React.JSX.Element;
2
3
  export declare const StatusBarPanel: () => React.JSX.Element;
3
4
  //# sourceMappingURL=StatusBarPanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StatusBarPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/StatusBarPanel.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAQxC,eAAO,MAAM,cAAc,yBA8B1B,CAAC"}
1
+ {"version":3,"file":"StatusBarPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/StatusBarPanel.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAUxC,eAAO,MAAM,gBAAgB,yBA2B5B,CAAC;AAEF,eAAO,MAAM,cAAc,yBAQ1B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ export declare const VersionNumber: () => React.JSX.Element;
3
+ //# sourceMappingURL=VersionNumber.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VersionNumber.d.ts","sourceRoot":"","sources":["../../../../src/components/VersionNumber.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,OAAO,CAAC;AAY1B,eAAO,MAAM,aAAa,yBAoEzB,CAAC"}
@@ -1,5 +1,4 @@
1
- import { StatusBarPlugin } from './StatusBarPlugin';
2
- export default StatusBarPlugin;
3
- export * from './StatusBarPlugin';
4
1
  export * from './components';
2
+ export * from './meta';
3
+ export * from './StatusBarPlugin';
5
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,eAAe,eAAe,CAAC;AAE/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC;AAC7B,cAAc,QAAQ,CAAC;AACvB,cAAc,mBAAmB,CAAC"}
@@ -1,9 +1,8 @@
1
1
  export declare const STATUS_BAR_PLUGIN = "dxos.org/plugin/status-bar";
2
- declare const _default: {
2
+ export declare const meta: {
3
3
  id: string;
4
4
  name: string;
5
5
  description: string;
6
6
  icon: string;
7
7
  };
8
- export default _default;
9
8
  //# sourceMappingURL=meta.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../../src/meta.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,iBAAiB,+BAA+B,CAAC;;;;;;;AAE9D,wBAKuB"}
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../../src/meta.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,iBAAiB,+BAA+B,CAAC;AAE9D,eAAO,MAAM,IAAI;;;;;CAKK,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { type useTranslation } from '@dxos/react-ui';
2
2
  import { STATUS_BAR_PLUGIN } from './meta';
3
- type StatusBarTranslationKeys = 'plugin name' | 'email input label' | 'email input placeholder' | 'feedback text area label' | 'feedback text area placeholder' | 'send feedback label' | 'name label' | 'name placeholder';
3
+ type StatusBarTranslationKeys = 'plugin name' | 'email input label' | 'email input placeholder' | 'feedback text area label' | 'feedback text area placeholder' | 'send feedback label' | 'name label' | 'name placeholder' | 'warning title' | 'technology preview message' | 'learn more label' | 'released message' | 'see release label' | 'powered by dxos message' | 'discord label' | 'feedback label';
4
4
  type RequiredTranslation = {
5
5
  [key in StatusBarTranslationKeys]: string;
6
6
  };
@@ -1 +1 @@
1
- {"version":3,"file":"translations.d.ts","sourceRoot":"","sources":["../../../src/translations.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAE3C,KAAK,wBAAwB,GACzB,aAAa,GACb,mBAAmB,GACnB,yBAAyB,GACzB,0BAA0B,GAC1B,gCAAgC,GAChC,qBAAqB,GACrB,YAAY,GACZ,kBAAkB,CAAC;AAEvB,KAAK,mBAAmB,GAAG;KAAG,GAAG,IAAI,wBAAwB,GAAG,MAAM;CAAE,CAAC;AACzE,KAAK,gBAAgB,GAAG;IAAE,CAAC,iBAAiB,CAAC,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAKrE,eAAO,MAAM,aAAa,MAAO,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,GAAG,CAAC,WAAW,wBAAwB,WAAW,CAAC;;AAetH,wBAA8B"}
1
+ {"version":3,"file":"translations.d.ts","sourceRoot":"","sources":["../../../src/translations.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAE3C,KAAK,wBAAwB,GACzB,aAAa,GACb,mBAAmB,GACnB,yBAAyB,GACzB,0BAA0B,GAC1B,gCAAgC,GAChC,qBAAqB,GACrB,YAAY,GACZ,kBAAkB,GAClB,eAAe,GACf,4BAA4B,GAC5B,kBAAkB,GAClB,kBAAkB,GAClB,mBAAmB,GACnB,yBAAyB,GACzB,eAAe,GACf,gBAAgB,CAAC;AAErB,KAAK,mBAAmB,GAAG;KAAG,GAAG,IAAI,wBAAwB,GAAG,MAAM;CAAE,CAAC;AACzE,KAAK,gBAAgB,GAAG;IAAE,CAAC,iBAAiB,CAAC,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAKrE,eAAO,MAAM,aAAa,MAAO,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,GAAG,CAAC,WAAW,wBAAwB,WAAW,CAAC;;AAuBtH,wBAA8B"}
@@ -0,0 +1 @@
1
+ {"version":"5.7.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-status-bar",
3
- "version": "0.7.4",
3
+ "version": "0.7.5-labs.071a3e2",
4
4
  "description": "Status bar plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -12,20 +12,11 @@
12
12
  "types": "./dist/types/src/index.d.ts",
13
13
  "browser": "./dist/lib/browser/index.mjs",
14
14
  "node": "./dist/lib/node-esm/index.mjs"
15
- },
16
- "./meta": {
17
- "types": "./dist/types/src/meta.d.ts",
18
- "browser": "./dist/lib/browser/meta.mjs",
19
- "node": "./dist/lib/node-esm/meta.mjs"
20
15
  }
21
16
  },
22
17
  "types": "dist/types/src/index.d.ts",
23
18
  "typesVersions": {
24
- "*": {
25
- "meta": [
26
- "dist/types/src/meta.d.ts"
27
- ]
28
- }
19
+ "*": {}
29
20
  },
30
21
  "files": [
31
22
  "dist",
@@ -33,16 +24,19 @@
33
24
  ],
34
25
  "dependencies": {
35
26
  "@effect/schema": "^0.75.5",
36
- "@fluentui/react-tabster": "^9.19.0",
27
+ "@fluentui/react-tabster": "9.23.3",
37
28
  "@preact/signals-core": "^1.6.0",
38
- "@radix-ui/react-slot": "^1.0.1",
39
- "effect": "^3.9.2",
29
+ "@radix-ui/react-slot": "1.1.2",
30
+ "date-fns": "^3.3.1",
31
+ "effect": "^3.12.3",
40
32
  "react-resize-detector": "^11.0.1",
41
- "@dxos/app-framework": "0.7.4",
42
- "@dxos/async": "0.7.4",
43
- "@dxos/echo-schema": "0.7.4",
44
- "@dxos/react-ui-form": "0.7.4",
45
- "@dxos/schema": "0.7.4"
33
+ "@dxos/app-framework": "0.7.5-labs.071a3e2",
34
+ "@dxos/echo-schema": "0.7.5-labs.071a3e2",
35
+ "@dxos/plugin-observability": "0.7.5-labs.071a3e2",
36
+ "@dxos/react-ui-form": "0.7.5-labs.071a3e2",
37
+ "@dxos/react-client": "0.7.5-labs.071a3e2",
38
+ "@dxos/async": "0.7.5-labs.071a3e2",
39
+ "@dxos/schema": "0.7.5-labs.071a3e2"
46
40
  },
47
41
  "devDependencies": {
48
42
  "@phosphor-icons/react": "^2.1.5",
@@ -51,16 +45,16 @@
51
45
  "react": "~18.2.0",
52
46
  "react-dom": "~18.2.0",
53
47
  "vite": "5.4.7",
54
- "@dxos/react-ui": "0.7.4",
55
- "@dxos/react-ui-theme": "0.7.4",
56
- "@dxos/storybook-utils": "0.7.4"
48
+ "@dxos/react-ui": "0.7.5-labs.071a3e2",
49
+ "@dxos/storybook-utils": "0.7.5-labs.071a3e2",
50
+ "@dxos/react-ui-theme": "0.7.5-labs.071a3e2"
57
51
  },
58
52
  "peerDependencies": {
59
53
  "@phosphor-icons/react": "^2.0.5",
60
54
  "react": "~18.2.0",
61
55
  "react-dom": "~18.2.0",
62
- "@dxos/react-ui-theme": "0.7.4",
63
- "@dxos/react-ui": "0.7.4"
56
+ "@dxos/react-ui": "0.7.5-labs.071a3e2",
57
+ "@dxos/react-ui-theme": "0.7.5-labs.071a3e2"
64
58
  },
65
59
  "publishConfig": {
66
60
  "access": "public"
@@ -4,30 +4,53 @@
4
4
 
5
5
  import React from 'react';
6
6
 
7
- import { type PluginDefinition, type SurfaceProvides, type TranslationsProvides } from '@dxos/app-framework';
7
+ import {
8
+ Capabilities,
9
+ contributes,
10
+ createSurface,
11
+ defineModule,
12
+ definePlugin,
13
+ Events,
14
+ Surface,
15
+ } from '@dxos/app-framework';
8
16
 
9
- import { StatusBarPanel } from './components';
10
- import meta from './meta';
17
+ import { StatusBarActions, StatusBarPanel } from './components';
18
+ import { VersionNumber } from './components/VersionNumber';
19
+ import { meta, STATUS_BAR_PLUGIN } from './meta';
11
20
  import translations from './translations';
12
21
 
13
- export type StatusBarPluginProvides = SurfaceProvides & TranslationsProvides;
14
-
15
- export const StatusBarPlugin = (): PluginDefinition<StatusBarPluginProvides> => {
16
- return {
17
- meta,
18
- provides: {
19
- translations,
20
- surface: {
21
- component: ({ role }) => {
22
- switch (role) {
23
- case 'status-bar': {
24
- return <StatusBarPanel />;
25
- }
26
- }
27
-
28
- return null;
29
- },
30
- },
31
- },
32
- };
33
- };
22
+ export const StatusBarPlugin = () =>
23
+ definePlugin(meta, [
24
+ defineModule({
25
+ id: `${meta.id}/module/translations`,
26
+ activatesOn: Events.SetupTranslations,
27
+ activate: () => contributes(Capabilities.Translations, translations),
28
+ }),
29
+ defineModule({
30
+ id: `${meta.id}/module/react-surface`,
31
+ activatesOn: Events.SetupSurfaces,
32
+ activate: () =>
33
+ contributes(Capabilities.ReactSurface, [
34
+ createSurface({
35
+ id: meta.id,
36
+ role: 'status-bar',
37
+ component: () => <StatusBarPanel />,
38
+ }),
39
+ createSurface({
40
+ id: meta.id,
41
+ role: 'status-bar--r0-footer',
42
+ component: () => <Surface role='status' />,
43
+ }),
44
+ createSurface({
45
+ id: meta.id,
46
+ role: 'status-bar--r1-footer',
47
+ component: () => <StatusBarActions />,
48
+ }),
49
+ createSurface({
50
+ id: `${STATUS_BAR_PLUGIN}/header-end`,
51
+ role: 'header-end',
52
+ component: () => <VersionNumber />,
53
+ }),
54
+ ]),
55
+ }),
56
+ ]);
@@ -2,11 +2,11 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Schema as S } from '@effect/schema';
6
5
  import { PaperPlaneTilt, X } from '@phosphor-icons/react';
7
6
  import React, { useCallback } from 'react';
8
7
 
9
- import { useIntentDispatcher } from '@dxos/app-framework';
8
+ import { createIntent, useIntentDispatcher } from '@dxos/app-framework';
9
+ import { ObservabilityAction, UserFeedback } from '@dxos/plugin-observability/types';
10
10
  import { Button, Input, Popover, useTranslation } from '@dxos/react-ui';
11
11
  import { useForm } from '@dxos/react-ui-form';
12
12
  import { getSize } from '@dxos/react-ui-theme';
@@ -14,43 +14,24 @@ import { getSize } from '@dxos/react-ui-theme';
14
14
  import { STATUS_BAR_PLUGIN } from '../meta';
15
15
  import { mkTranslation } from '../translations';
16
16
 
17
- const Email = S.String.pipe(
18
- S.nonEmptyString({ message: () => 'Email is required.' }),
19
- S.pattern(/^(?!\.)(?!.*\.\.)([A-Z0-9_+-.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9-]*\.)+[A-Z]{2,}$/i, {
20
- message: () => 'Invalid email address.',
21
- }),
22
- );
23
-
24
- const nonEmpty = (field: string) => S.nonEmptyString({ message: () => `${field} is required.` });
25
- const maxLength = (field: string, length: number) => S.maxLength(length, { message: () => `${field} is too long.` });
26
-
27
- // Types and validation.
28
- const FeedbackFormSchema = S.Struct({
29
- name: S.String.pipe(nonEmpty('Name'), maxLength('Name', 256)),
30
- email: Email.pipe(maxLength('Email', 256)),
31
- message: S.String.pipe(nonEmpty('Feedback'), maxLength('Feedback', 32_768)),
32
- });
33
-
34
- type FeedbackFormType = S.Schema.Type<typeof FeedbackFormSchema>;
35
-
36
- const initialValues: FeedbackFormType = { name: '', email: '', message: '' };
17
+ const initialValues: UserFeedback = { name: '', email: '', message: '' };
37
18
 
38
19
  export const FeedbackForm = ({ onClose }: { onClose: () => void }) => {
39
20
  const { t } = useTranslation(STATUS_BAR_PLUGIN);
40
21
  const translation = mkTranslation(t);
41
- const dispatch = useIntentDispatcher();
22
+ const { dispatchPromise: dispatch } = useIntentDispatcher();
42
23
 
43
24
  const onSave = useCallback(
44
- (values: FeedbackFormType) => {
45
- void dispatch({ action: 'dxos.org/plugin/observability/capture-feedback', data: values });
25
+ (values: UserFeedback) => {
26
+ void dispatch(createIntent(ObservabilityAction.CaptureUserFeedback, values));
46
27
  onClose();
47
28
  },
48
29
  [dispatch, onClose],
49
30
  );
50
31
 
51
- const { handleSave, canSave, getStatus, ...inputProps } = useForm<FeedbackFormType>({
32
+ const { handleSave, canSave, getStatus, ...inputProps } = useForm<UserFeedback>({
52
33
  initialValues,
53
- schema: FeedbackFormSchema,
34
+ schema: UserFeedback,
54
35
  onSave,
55
36
  });
56
37
 
@@ -13,7 +13,7 @@ import { withTheme } from '@dxos/storybook-utils';
13
13
  import { StatusBar } from './StatusBar';
14
14
 
15
15
  export const DefaultStory = () => (
16
- <StatusBar.Container>
16
+ <div>
17
17
  <StatusBar.EndContent>
18
18
  <StatusBar.Button>
19
19
  <Icon icon='ph--mailbox--regular' size={4} />
@@ -30,7 +30,7 @@ export const DefaultStory = () => (
30
30
  <StatusBar.Text>Online</StatusBar.Text>
31
31
  </StatusBar.Item>
32
32
  </StatusBar.EndContent>
33
- </StatusBar.Container>
33
+ </div>
34
34
  );
35
35
 
36
36
  export const Default = {};
@@ -2,9 +2,8 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { useFocusableGroup } from '@fluentui/react-tabster';
6
5
  import { Slot } from '@radix-ui/react-slot';
7
- import React, { forwardRef, type HTMLAttributes, type ReactNode } from 'react';
6
+ import React, { type ComponentPropsWithRef, forwardRef, type PropsWithChildren, type ReactNode } from 'react';
8
7
 
9
8
  import { type ThemedClassName } from '@dxos/react-ui';
10
9
  import { mx } from '@dxos/react-ui-theme';
@@ -17,14 +16,13 @@ const StatusBarText = forwardRef<HTMLSpanElement, StatusBarTextProps>(({ classNa
17
16
  </span>
18
17
  ));
19
18
 
20
- type StatusBarButtonProps = ThemedClassName<{ children: ReactNode; asChild?: boolean }> &
21
- HTMLAttributes<HTMLButtonElement>;
19
+ type StatusBarButtonProps = ThemedClassName<ComponentPropsWithRef<'button'> & { asChild?: boolean }>;
22
20
 
23
21
  const StatusBarButton = forwardRef<HTMLButtonElement, StatusBarButtonProps>(
24
22
  ({ classNames, children, asChild, ...props }, forwardedRef) => {
25
23
  const classes = mx(
26
- 'flex items-center gap-2 p-1 px-2 rounded-sm',
27
- 'select-none cursor-pointer ch-focus-ring',
24
+ 'flex items-center justify-center gap-2 p-1 px-2 rounded-sm',
25
+ 'select-none cursor-pointer dx-focus-ring text-description text-xs',
28
26
  'hover:bg-neutral-75 active:bg-neutral-150 dark:hover:bg-neutral-750 dark:active:bg-neutral-700',
29
27
  classNames,
30
28
  );
@@ -43,13 +41,13 @@ const StatusBarButton = forwardRef<HTMLButtonElement, StatusBarButtonProps>(
43
41
 
44
42
  export default StatusBarButton;
45
43
 
46
- type StatusBarItemProps = ThemedClassName<{ children: ReactNode }> & HTMLAttributes<HTMLDivElement>;
44
+ type StatusBarItemProps = ThemedClassName<ComponentPropsWithRef<'div'>>;
47
45
 
48
46
  const StatusBarItem = forwardRef<HTMLDivElement, StatusBarItemProps>(
49
47
  ({ classNames, children, ...props }, forwardedRef) => (
50
48
  <div
51
49
  role='menuitem'
52
- className={mx('flex items-center gap-2 p-1 px-2 rounded-sm select-none', classNames)}
50
+ className={mx('flex items-center justify-center gap-2 p-1 px-2 rounded-sm select-none', classNames)}
53
51
  ref={forwardedRef}
54
52
  {...props}
55
53
  >
@@ -58,30 +56,7 @@ const StatusBarItem = forwardRef<HTMLDivElement, StatusBarItemProps>(
58
56
  ),
59
57
  );
60
58
 
61
- type StatusBarContainerProps = ThemedClassName<{ children: ReactNode }>;
62
-
63
- // TODO(zan): tabable group with tabster.
64
- const StatusBarContainer = forwardRef<HTMLDivElement, StatusBarContainerProps>(
65
- ({ classNames, children }, forwardedRef) => {
66
- const groupAttrs = useFocusableGroup({ tabBehavior: 'limited' });
67
- return (
68
- <div
69
- role='menubar'
70
- tabIndex={0}
71
- {...groupAttrs}
72
- className={mx(
73
- 'bs-[--statusbar-size] flex justify-end items-center gap-2 bg-base text-description text-lg pointer-fine:text-xs ch-focus-ring-inset',
74
- classNames,
75
- )}
76
- ref={forwardedRef}
77
- >
78
- {children}
79
- </div>
80
- );
81
- },
82
- );
83
-
84
- type StartContentProps = ThemedClassName<{ children: ReactNode }>;
59
+ type StartContentProps = ThemedClassName<PropsWithChildren<{}>>;
85
60
 
86
61
  const StartContent = forwardRef<HTMLDivElement, StartContentProps>(({ classNames, children }, forwardedRef) => (
87
62
  <div role='none' className={mx('flex-grow flex items-center space-x-2', classNames)} ref={forwardedRef}>
@@ -89,7 +64,7 @@ const StartContent = forwardRef<HTMLDivElement, StartContentProps>(({ classNames
89
64
  </div>
90
65
  ));
91
66
 
92
- type EndContentProps = ThemedClassName<{ children: ReactNode }>;
67
+ type EndContentProps = ThemedClassName<PropsWithChildren<{}>>;
93
68
 
94
69
  const EndContent = forwardRef<HTMLDivElement, EndContentProps>(({ classNames, children }, forwardedRef) => (
95
70
  <div role='none' className={mx('flex-grow flex items-center justify-end', classNames)} ref={forwardedRef}>
@@ -98,7 +73,6 @@ const EndContent = forwardRef<HTMLDivElement, EndContentProps>(({ classNames, ch
98
73
  ));
99
74
 
100
75
  export const StatusBar = {
101
- Container: StatusBarContainer,
102
76
  Text: StatusBarText,
103
77
  Item: StatusBarItem,
104
78
  Button: StatusBarButton,
@@ -5,39 +5,48 @@
5
5
  import React, { useState } from 'react';
6
6
 
7
7
  import { Surface } from '@dxos/app-framework';
8
- import { Icon, Popover } from '@dxos/react-ui';
8
+ import { Icon, Popover, useTranslation } from '@dxos/react-ui';
9
9
 
10
10
  import { FeedbackForm } from './FeedbackForm';
11
11
  import { StatusBar } from './StatusBar';
12
+ import { VersionNumber } from './VersionNumber';
13
+ import { STATUS_BAR_PLUGIN } from '../meta';
12
14
 
13
- export const StatusBarPanel = () => {
15
+ export const StatusBarActions = () => {
16
+ const { t } = useTranslation(STATUS_BAR_PLUGIN);
14
17
  const [open, setOpen] = useState(false);
15
-
16
- // TODO(wittjosiah): Factor out feedback and discord buttons.
17
18
  return (
18
19
  <Popover.Root open={open} onOpenChange={setOpen}>
19
- <StatusBar.Container>
20
- <StatusBar.EndContent>
21
- <Surface role='status' />
22
- <Popover.Trigger asChild>
23
- <StatusBar.Button aria-label='Give feedback about composer' data-joyride='welcome/feedback'>
24
- <Icon icon='ph--paper-plane-tilt--regular' size={4} />
25
- <StatusBar.Text classNames='hidden sm:block'>Feedback</StatusBar.Text>
26
- </StatusBar.Button>
27
- </Popover.Trigger>
28
- {/* TODO(zan): Configure this label? */}
29
- <StatusBar.Button aria-label='Open DXOS Discord' asChild>
30
- <a href='https://dxos.org/discord' target='_blank' rel='noopener noreferrer'>
31
- <Icon icon='ph--discord-logo--regular' size={4} />
32
- <StatusBar.Text classNames='hidden sm:block'>Discord</StatusBar.Text>
33
- </a>
34
- </StatusBar.Button>
35
- </StatusBar.EndContent>
36
- </StatusBar.Container>
37
- <Popover.Content classNames='shadow-lg'>
38
- <FeedbackForm onClose={() => setOpen(false)} />
39
- <Popover.Arrow />
40
- </Popover.Content>
20
+ <Popover.Trigger asChild>
21
+ <StatusBar.Button data-joyride='welcome/feedback'>
22
+ <Icon icon='ph--paper-plane-tilt--regular' size={4} />
23
+ <StatusBar.Text classNames='hidden sm:block'>{t('feedback label')}</StatusBar.Text>
24
+ </StatusBar.Button>
25
+ </Popover.Trigger>
26
+ {/* TODO(zan): Configure this label? */}
27
+ <StatusBar.Button asChild>
28
+ <a href='https://dxos.org/discord' target='_blank' rel='noopener noreferrer'>
29
+ <Icon icon='ph--discord-logo--regular' size={4} />
30
+ <StatusBar.Text classNames='hidden sm:block'>{t('discord label')}</StatusBar.Text>
31
+ </a>
32
+ </StatusBar.Button>
33
+ <VersionNumber />
34
+ <Popover.Portal>
35
+ <Popover.Content classNames='shadow-lg'>
36
+ <FeedbackForm onClose={() => setOpen(false)} />
37
+ <Popover.Arrow />
38
+ </Popover.Content>
39
+ </Popover.Portal>
41
40
  </Popover.Root>
42
41
  );
43
42
  };
43
+
44
+ export const StatusBarPanel = () => {
45
+ return (
46
+ <>
47
+ <StatusBarActions />
48
+ <span role='separator' className='grow' />
49
+ <Surface role='status' />
50
+ </>
51
+ );
52
+ };
@@ -0,0 +1,86 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { formatDistance } from 'date-fns/formatDistance';
6
+ import React from 'react';
7
+
8
+ import { useConfig } from '@dxos/react-client';
9
+ import { Link, Message, Popover, Trans, useTranslation, Icon } from '@dxos/react-ui';
10
+
11
+ import { StatusBar } from './StatusBar';
12
+ import { STATUS_BAR_PLUGIN } from '../meta';
13
+
14
+ const repo = 'https://github.com/dxos/dxos';
15
+
16
+ const VERSION_REGEX = /([\d.]+)/;
17
+
18
+ export const VersionNumber = () => {
19
+ const config = useConfig();
20
+ const { t } = useTranslation(STATUS_BAR_PLUGIN);
21
+ const { version, timestamp, commitHash } = config.values.runtime?.app?.build ?? {};
22
+ const [_, v] = version?.match(VERSION_REGEX) ?? [];
23
+
24
+ const releaseUrl =
25
+ config.values.runtime?.app?.env?.DX_ENVIRONMENT === 'production'
26
+ ? `${repo}/releases/tag/v${version}`
27
+ : `${repo}/commit/${commitHash}`;
28
+
29
+ const previewUrl = 'https://docs.dxos.org/composer#technology-preview';
30
+
31
+ return (
32
+ <Popover.Root>
33
+ <Popover.Trigger asChild>
34
+ <StatusBar.Button classNames='text-xs'>v{v}</StatusBar.Button>
35
+ </Popover.Trigger>
36
+ <Popover.Portal>
37
+ <Popover.Content
38
+ side='top'
39
+ role='message'
40
+ classNames='z-[12] bg-warning-500 max-is-[min(calc(100vw-16px),40ch)]'
41
+ >
42
+ <Message.Root valence='warning' className='rounded-be-none p-5'>
43
+ <Message.Title>
44
+ <Icon icon='ph--warning--duotone' size={6} classNames='inline mie-2' />
45
+ <span>{t('warning title')}</span>
46
+ </Message.Title>
47
+ <Message.Body>
48
+ {t('technology preview message')}
49
+ <br />
50
+ <Link href={previewUrl} target='_blank' rel='noreferrer' variant='neutral'>
51
+ {t('learn more label')}
52
+ <Icon icon='ph--arrow-square-out--bold' classNames='inline mis-1' />
53
+ </Link>
54
+ </Message.Body>
55
+ </Message.Root>
56
+ <div role='none' className='plb-4 pli-5 space-b-2 text-baseText'>
57
+ {timestamp && (
58
+ <p>
59
+ {t('released message', {
60
+ released: formatDistance(new Date(timestamp), new Date(), { addSuffix: true }),
61
+ })}
62
+ <br />
63
+ <Link href={releaseUrl} target='_blank' rel='noreferrer' variant='neutral'>
64
+ {t('see release label')}
65
+ <Icon icon='ph--arrow-square-out--bold' classNames='inline mis-1' />
66
+ </Link>
67
+ </p>
68
+ )}
69
+ <p>
70
+ <Trans
71
+ {...{
72
+ t,
73
+ i18nKey: 'powered by dxos message',
74
+ components: {
75
+ dxos: <Link href='https://dxos.org' target='_blank' rel='noreferrer' variant='neutral' />,
76
+ },
77
+ }}
78
+ />
79
+ </p>
80
+ </div>
81
+ <Popover.Arrow />
82
+ </Popover.Content>
83
+ </Popover.Portal>
84
+ </Popover.Root>
85
+ );
86
+ };