@dxos/plugin-status-bar 0.6.13 → 0.6.14-main.1366248
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/dist/lib/browser/chunk-4KDZC7WS.mjs +14 -0
- package/dist/lib/browser/chunk-4KDZC7WS.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +43 -148
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +1 -1
- package/dist/types/src/components/FeedbackForm.d.ts.map +1 -1
- package/dist/types/src/components/StatusBar.d.ts.map +1 -1
- package/dist/types/src/components/StatusBar.stories.d.ts +6 -47
- package/dist/types/src/components/StatusBar.stories.d.ts.map +1 -1
- package/dist/types/src/components/StatusBarPanel.d.ts +3 -0
- package/dist/types/src/components/StatusBarPanel.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +3 -9
- package/dist/types/src/meta.d.ts.map +1 -1
- package/package.json +20 -22
- package/src/StatusBarPlugin.tsx +2 -2
- package/src/components/FeedbackForm.tsx +15 -16
- package/src/components/StatusBar.stories.tsx +33 -28
- package/src/components/StatusBar.tsx +3 -2
- package/src/components/{StatusBarImpl.tsx → StatusBarPanel.tsx} +5 -7
- package/src/components/index.ts +1 -1
- package/src/meta.ts +14 -0
- package/dist/lib/browser/chunk-PL5XPTPX.mjs +0 -18
- package/dist/lib/browser/chunk-PL5XPTPX.mjs.map +0 -7
- package/dist/types/src/components/StatusBarImpl.d.ts +0 -3
- package/dist/types/src/components/StatusBarImpl.d.ts.map +0 -1
- package/dist/types/src/hooks/index.d.ts +0 -2
- package/dist/types/src/hooks/index.d.ts.map +0 -1
- package/dist/types/src/hooks/useForm.d.ts +0 -36
- package/dist/types/src/hooks/useForm.d.ts.map +0 -1
- package/dist/types/src/util/index.d.ts +0 -2
- package/dist/types/src/util/index.d.ts.map +0 -1
- package/dist/types/src/util/validation.d.ts +0 -7
- package/dist/types/src/util/validation.d.ts.map +0 -1
- package/src/hooks/index.ts +0 -5
- package/src/hooks/useForm.ts +0 -119
- package/src/meta.tsx +0 -18
- package/src/util/index.ts +0 -5
- package/src/util/validation.ts +0 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBar.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/StatusBar.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"StatusBar.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/StatusBar.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,eAAO,MAAM,YAAY,yBAmBxB,CAAC;AAEF,eAAO,MAAM,OAAO,IAAK,CAAC;AAE1B,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,SAAS,CAQhC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/index.ts"],"names":[],"mappings":"AAIA,cAAc,aAAa,CAAC;AAC5B,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/index.ts"],"names":[],"mappings":"AAIA,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC"}
|
package/dist/types/src/meta.d.ts
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import { type IconProps } from '@phosphor-icons/react';
|
|
2
|
-
import React from 'react';
|
|
3
1
|
export declare const STATUS_BAR_PLUGIN = "dxos.org/plugin/status-bar";
|
|
4
2
|
declare const _default: {
|
|
5
3
|
id: string;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
homePage?: string;
|
|
10
|
-
tags?: string[];
|
|
11
|
-
iconComponent?: React.FC<IconProps>;
|
|
12
|
-
iconSymbol?: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
icon: string;
|
|
13
7
|
};
|
|
14
8
|
export default _default;
|
|
15
9
|
//# sourceMappingURL=meta.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../../src/meta.
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../../src/meta.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,iBAAiB,+BAA+B,CAAC;;;;;;;AAE9D,wBAKuB"}
|
package/package.json
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-status-bar",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.14-main.1366248",
|
|
4
4
|
"description": "Status bar plugin",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"author": "DXOS.org",
|
|
9
|
+
"sideEffects": true,
|
|
9
10
|
"exports": {
|
|
10
11
|
".": {
|
|
11
|
-
"
|
|
12
|
-
"
|
|
12
|
+
"types": "./dist/types/src/index.d.ts",
|
|
13
|
+
"browser": "./dist/lib/browser/index.mjs"
|
|
13
14
|
},
|
|
14
15
|
"./meta": {
|
|
15
|
-
"
|
|
16
|
-
"
|
|
16
|
+
"types": "./dist/types/src/meta.d.ts",
|
|
17
|
+
"browser": "./dist/lib/browser/meta.mjs"
|
|
17
18
|
}
|
|
18
19
|
},
|
|
19
20
|
"types": "dist/types/src/index.d.ts",
|
|
@@ -29,19 +30,16 @@
|
|
|
29
30
|
"src"
|
|
30
31
|
],
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"@effect/schema": "^0.
|
|
33
|
+
"@effect/schema": "^0.75.1",
|
|
33
34
|
"@fluentui/react-tabster": "^9.19.0",
|
|
34
35
|
"@preact/signals-core": "^1.6.0",
|
|
35
36
|
"@radix-ui/react-slot": "^1.0.1",
|
|
36
|
-
"effect": "^3.
|
|
37
|
+
"effect": "^3.9.1",
|
|
37
38
|
"react-resize-detector": "^11.0.1",
|
|
38
|
-
"@dxos/app-framework": "0.6.
|
|
39
|
-
"@dxos/
|
|
40
|
-
"@dxos/
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/plugin-client": "0.6.13",
|
|
43
|
-
"@dxos/plugin-stack": "0.6.13",
|
|
44
|
-
"@dxos/react-client": "0.6.13"
|
|
39
|
+
"@dxos/app-framework": "0.6.14-main.1366248",
|
|
40
|
+
"@dxos/echo-schema": "0.6.14-main.1366248",
|
|
41
|
+
"@dxos/react-ui-data": "0.6.14-main.1366248",
|
|
42
|
+
"@dxos/async": "0.6.14-main.1366248"
|
|
45
43
|
},
|
|
46
44
|
"devDependencies": {
|
|
47
45
|
"@phosphor-icons/react": "^2.1.5",
|
|
@@ -49,17 +47,17 @@
|
|
|
49
47
|
"@types/react-dom": "~18.2.0",
|
|
50
48
|
"react": "~18.2.0",
|
|
51
49
|
"react-dom": "~18.2.0",
|
|
52
|
-
"vite": "
|
|
53
|
-
"@dxos/react-ui": "0.6.
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/
|
|
50
|
+
"vite": "5.4.7",
|
|
51
|
+
"@dxos/react-ui": "0.6.14-main.1366248",
|
|
52
|
+
"@dxos/react-ui-theme": "0.6.14-main.1366248",
|
|
53
|
+
"@dxos/storybook-utils": "0.6.14-main.1366248"
|
|
56
54
|
},
|
|
57
55
|
"peerDependencies": {
|
|
58
56
|
"@phosphor-icons/react": "^2.0.5",
|
|
59
|
-
"react": "
|
|
60
|
-
"react-dom": "
|
|
61
|
-
"@dxos/react-ui": "0.6.
|
|
62
|
-
"@dxos/react-ui-theme": "0.6.
|
|
57
|
+
"react": "~18.2.0",
|
|
58
|
+
"react-dom": "~18.2.0",
|
|
59
|
+
"@dxos/react-ui": "0.6.14-main.1366248",
|
|
60
|
+
"@dxos/react-ui-theme": "0.6.14-main.1366248"
|
|
63
61
|
},
|
|
64
62
|
"publishConfig": {
|
|
65
63
|
"access": "public"
|
package/src/StatusBarPlugin.tsx
CHANGED
|
@@ -6,7 +6,7 @@ import React from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { type PluginDefinition, type SurfaceProvides, type TranslationsProvides } from '@dxos/app-framework';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { StatusBarPanel } from './components';
|
|
10
10
|
import meta from './meta';
|
|
11
11
|
import translations from './translations';
|
|
12
12
|
|
|
@@ -21,7 +21,7 @@ export const StatusBarPlugin = (): PluginDefinition<StatusBarPluginProvides> =>
|
|
|
21
21
|
component: ({ role }) => {
|
|
22
22
|
switch (role) {
|
|
23
23
|
case 'status-bar': {
|
|
24
|
-
return <
|
|
24
|
+
return <StatusBarPanel />;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -2,30 +2,29 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { Schema as S } from '@effect/schema';
|
|
6
|
+
import { PaperPlaneTilt, X } from '@phosphor-icons/react';
|
|
6
7
|
import React, { useCallback } from 'react';
|
|
7
8
|
|
|
8
9
|
import { useIntentDispatcher } from '@dxos/app-framework';
|
|
9
|
-
import { S } from '@dxos/echo-schema';
|
|
10
10
|
import { Button, Input, Popover, useTranslation } from '@dxos/react-ui';
|
|
11
|
+
import { useForm } from '@dxos/react-ui-data';
|
|
11
12
|
import { getSize } from '@dxos/react-ui-theme';
|
|
12
13
|
|
|
13
|
-
import { useForm } from '../hooks';
|
|
14
14
|
import { STATUS_BAR_PLUGIN } from '../meta';
|
|
15
15
|
import { mkTranslation } from '../translations';
|
|
16
|
-
import { validate } from '../util';
|
|
17
16
|
|
|
18
17
|
const Email = S.String.pipe(
|
|
19
|
-
S.
|
|
18
|
+
S.nonEmptyString({ message: () => 'Email is required.' }),
|
|
20
19
|
S.pattern(/^(?!\.)(?!.*\.\.)([A-Z0-9_+-.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9-]*\.)+[A-Z]{2,}$/i, {
|
|
21
20
|
message: () => 'Invalid email address.',
|
|
22
21
|
}),
|
|
23
22
|
);
|
|
24
23
|
|
|
25
|
-
const nonEmpty = (field: string) => S.
|
|
24
|
+
const nonEmpty = (field: string) => S.nonEmptyString({ message: () => `${field} is required.` });
|
|
26
25
|
const maxLength = (field: string, length: number) => S.maxLength(length, { message: () => `${field} is too long.` });
|
|
27
26
|
|
|
28
|
-
//
|
|
27
|
+
// Types and validation.
|
|
29
28
|
const FeedbackFormSchema = S.Struct({
|
|
30
29
|
name: S.String.pipe(nonEmpty('Name'), maxLength('Name', 256)),
|
|
31
30
|
email: Email.pipe(maxLength('Email', 256)),
|
|
@@ -49,16 +48,16 @@ export const FeedbackForm = ({ onClose }: { onClose: () => void }) => {
|
|
|
49
48
|
[dispatch, onClose],
|
|
50
49
|
);
|
|
51
50
|
|
|
52
|
-
const {
|
|
51
|
+
const { handleSubmit, canSubmit, getInputProps, getErrorValence, getErrorMessage } = useForm<FeedbackFormState>({
|
|
53
52
|
initialValues,
|
|
54
|
-
|
|
55
|
-
onSubmit
|
|
53
|
+
schema: FeedbackFormSchema,
|
|
54
|
+
onSubmit,
|
|
56
55
|
});
|
|
57
56
|
|
|
58
57
|
return (
|
|
59
58
|
<div role='form' className='p-3 flex flex-col gap-2'>
|
|
60
59
|
<div role='none' className='space-b-1'>
|
|
61
|
-
<Input.Root validationValence={
|
|
60
|
+
<Input.Root validationValence={getErrorValence('name')}>
|
|
62
61
|
<Input.Label>{translation('name label')}</Input.Label>
|
|
63
62
|
<Input.TextInput
|
|
64
63
|
classNames={'text-sm'}
|
|
@@ -67,13 +66,13 @@ export const FeedbackForm = ({ onClose }: { onClose: () => void }) => {
|
|
|
67
66
|
{...getInputProps('name')}
|
|
68
67
|
/>
|
|
69
68
|
<Input.DescriptionAndValidation>
|
|
70
|
-
<Input.Validation>{
|
|
69
|
+
<Input.Validation>{getErrorMessage('name')}</Input.Validation>
|
|
71
70
|
</Input.DescriptionAndValidation>
|
|
72
71
|
</Input.Root>
|
|
73
72
|
</div>
|
|
74
73
|
|
|
75
74
|
<div role='none' className='space-b-1'>
|
|
76
|
-
<Input.Root validationValence={
|
|
75
|
+
<Input.Root validationValence={getErrorValence('email')}>
|
|
77
76
|
<Input.Label>{translation('email input label')}</Input.Label>
|
|
78
77
|
<Input.TextInput
|
|
79
78
|
classNames={'text-sm'}
|
|
@@ -81,13 +80,13 @@ export const FeedbackForm = ({ onClose }: { onClose: () => void }) => {
|
|
|
81
80
|
{...getInputProps('email')}
|
|
82
81
|
/>
|
|
83
82
|
<Input.DescriptionAndValidation>
|
|
84
|
-
<Input.Validation>{
|
|
83
|
+
<Input.Validation>{getErrorMessage('email')}</Input.Validation>
|
|
85
84
|
</Input.DescriptionAndValidation>
|
|
86
85
|
</Input.Root>
|
|
87
86
|
</div>
|
|
88
87
|
|
|
89
88
|
<div role='none' className='space-b-1'>
|
|
90
|
-
<Input.Root validationValence={
|
|
89
|
+
<Input.Root validationValence={getErrorValence('message')}>
|
|
91
90
|
<Input.Label>{translation('feedback text area label')}</Input.Label>
|
|
92
91
|
<Input.TextArea
|
|
93
92
|
classNames={'text-sm'}
|
|
@@ -97,7 +96,7 @@ export const FeedbackForm = ({ onClose }: { onClose: () => void }) => {
|
|
|
97
96
|
{...getInputProps('message')}
|
|
98
97
|
/>
|
|
99
98
|
<Input.DescriptionAndValidation>
|
|
100
|
-
<Input.Validation>{
|
|
99
|
+
<Input.Validation>{getErrorMessage('message')}</Input.Validation>
|
|
101
100
|
</Input.DescriptionAndValidation>
|
|
102
101
|
</Input.Root>
|
|
103
102
|
</div>
|
|
@@ -4,40 +4,45 @@
|
|
|
4
4
|
|
|
5
5
|
import '@dxos-theme';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { type Meta } from '@storybook/react';
|
|
8
8
|
import React from 'react';
|
|
9
9
|
|
|
10
|
+
import { Icon } from '@dxos/react-ui';
|
|
10
11
|
import { withTheme } from '@dxos/storybook-utils';
|
|
11
12
|
|
|
12
13
|
import { StatusBar } from './StatusBar';
|
|
13
14
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export const Normal = (_props: any) => (
|
|
23
|
-
<>
|
|
24
|
-
<StatusBar.Container>
|
|
25
|
-
<StatusBar.EndContent>
|
|
15
|
+
export const DefaultStory = () => (
|
|
16
|
+
<StatusBar.Container>
|
|
17
|
+
<StatusBar.EndContent>
|
|
18
|
+
<StatusBar.Button>
|
|
19
|
+
<Icon icon='ph--mailbox--regular' size={4} />
|
|
20
|
+
<StatusBar.Text>Quick feedback</StatusBar.Text>
|
|
21
|
+
</StatusBar.Button>
|
|
22
|
+
<a href='https://dxos.org/discord' target='_blank' rel='noopener noreferrer'>
|
|
26
23
|
<StatusBar.Button>
|
|
27
|
-
<
|
|
28
|
-
<StatusBar.Text>
|
|
24
|
+
<Icon icon='ph--discord-logo--regular' size={4} />
|
|
25
|
+
<StatusBar.Text>Join us on Discord</StatusBar.Text>
|
|
29
26
|
</StatusBar.Button>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<Lightning />
|
|
38
|
-
<StatusBar.Text>Online</StatusBar.Text>
|
|
39
|
-
</StatusBar.Item>
|
|
40
|
-
</StatusBar.EndContent>
|
|
41
|
-
</StatusBar.Container>
|
|
42
|
-
</>
|
|
27
|
+
</a>
|
|
28
|
+
<StatusBar.Item>
|
|
29
|
+
<Icon icon='ph--lightning--regular' size={4} />
|
|
30
|
+
<StatusBar.Text>Online</StatusBar.Text>
|
|
31
|
+
</StatusBar.Item>
|
|
32
|
+
</StatusBar.EndContent>
|
|
33
|
+
</StatusBar.Container>
|
|
43
34
|
);
|
|
35
|
+
|
|
36
|
+
export const Default = {};
|
|
37
|
+
|
|
38
|
+
const meta: Meta<typeof StatusBar> = {
|
|
39
|
+
title: 'plugins/plugin-status/StatusBar',
|
|
40
|
+
component: StatusBar as any,
|
|
41
|
+
render: DefaultStory,
|
|
42
|
+
decorators: [withTheme],
|
|
43
|
+
parameters: {
|
|
44
|
+
chromatic: { disableSnapshot: false },
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default meta;
|
|
@@ -57,9 +57,10 @@ const StatusBarItem = forwardRef<HTMLDivElement, StatusBarItemProps>(
|
|
|
57
57
|
</div>
|
|
58
58
|
),
|
|
59
59
|
);
|
|
60
|
+
|
|
60
61
|
type StatusBarContainerProps = ThemedClassName<{ children: ReactNode }>;
|
|
61
62
|
|
|
62
|
-
// TODO(zan): tabable group with tabster
|
|
63
|
+
// TODO(zan): tabable group with tabster.
|
|
63
64
|
const StatusBarContainer = forwardRef<HTMLDivElement, StatusBarContainerProps>(
|
|
64
65
|
({ classNames, children }, forwardedRef) => {
|
|
65
66
|
const groupAttrs = useFocusableGroup({ tabBehavior: 'limited' });
|
|
@@ -69,7 +70,7 @@ const StatusBarContainer = forwardRef<HTMLDivElement, StatusBarContainerProps>(
|
|
|
69
70
|
tabIndex={0}
|
|
70
71
|
{...groupAttrs}
|
|
71
72
|
className={mx(
|
|
72
|
-
'bs-[--statusbar-size] flex justify-end items-center gap-2
|
|
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',
|
|
73
74
|
classNames,
|
|
74
75
|
)}
|
|
75
76
|
ref={forwardedRef}
|
|
@@ -2,17 +2,15 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { DiscordLogo, PaperPlaneTilt } from '@phosphor-icons/react';
|
|
6
5
|
import React, { useState } from 'react';
|
|
7
6
|
|
|
8
7
|
import { Surface } from '@dxos/app-framework';
|
|
9
|
-
import { Popover } from '@dxos/react-ui';
|
|
8
|
+
import { Icon, Popover } from '@dxos/react-ui';
|
|
10
9
|
|
|
11
10
|
import { FeedbackForm } from './FeedbackForm';
|
|
12
11
|
import { StatusBar } from './StatusBar';
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
export const StatusBarImpl = () => {
|
|
13
|
+
export const StatusBarPanel = () => {
|
|
16
14
|
const [open, setOpen] = useState(false);
|
|
17
15
|
|
|
18
16
|
// TODO(wittjosiah): Factor out feedback and discord buttons.
|
|
@@ -20,21 +18,21 @@ export const StatusBarImpl = () => {
|
|
|
20
18
|
<Popover.Root open={open} onOpenChange={setOpen}>
|
|
21
19
|
<StatusBar.Container>
|
|
22
20
|
<StatusBar.EndContent>
|
|
21
|
+
<Surface role='status' />
|
|
23
22
|
<Popover.Trigger asChild>
|
|
24
23
|
<StatusBar.Button aria-label='Give feedback about composer' data-joyride='welcome/feedback'>
|
|
25
|
-
<
|
|
24
|
+
<Icon icon='ph--paper-plane-tilt--regular' size={4} />
|
|
26
25
|
<StatusBar.Text classNames='hidden sm:block'>Feedback</StatusBar.Text>
|
|
27
26
|
</StatusBar.Button>
|
|
28
27
|
</Popover.Trigger>
|
|
29
28
|
{/* TODO(zan): Configure this label? */}
|
|
30
29
|
<StatusBar.Button aria-label='Open DXOS Discord' asChild>
|
|
31
30
|
<a href='https://dxos.org/discord' target='_blank' rel='noopener noreferrer'>
|
|
32
|
-
<
|
|
31
|
+
<Icon icon='ph--discord-logo--regular' size={4} />
|
|
33
32
|
<StatusBar.Text classNames='hidden sm:block'>Discord</StatusBar.Text>
|
|
34
33
|
</a>
|
|
35
34
|
</StatusBar.Button>
|
|
36
35
|
</StatusBar.EndContent>
|
|
37
|
-
<Surface role='status' />
|
|
38
36
|
</StatusBar.Container>
|
|
39
37
|
<Popover.Content classNames='shadow-lg'>
|
|
40
38
|
<FeedbackForm onClose={() => setOpen(false)} />
|
package/src/components/index.ts
CHANGED
package/src/meta.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type PluginMeta } from '@dxos/app-framework';
|
|
6
|
+
|
|
7
|
+
export const STATUS_BAR_PLUGIN = 'dxos.org/plugin/status-bar';
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
id: STATUS_BAR_PLUGIN,
|
|
11
|
+
name: 'Status Bar',
|
|
12
|
+
description: 'Display a bar with status and actions.',
|
|
13
|
+
icon: 'ph--info--regular',
|
|
14
|
+
} satisfies PluginMeta;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// packages/plugins/plugin-status-bar/src/meta.tsx
|
|
2
|
-
import { Info } from "@phosphor-icons/react";
|
|
3
|
-
import React from "react";
|
|
4
|
-
import { pluginMeta } from "@dxos/app-framework";
|
|
5
|
-
var STATUS_BAR_PLUGIN = "dxos.org/plugin/status-bar";
|
|
6
|
-
var meta_default = pluginMeta({
|
|
7
|
-
id: STATUS_BAR_PLUGIN,
|
|
8
|
-
name: "Status Bar",
|
|
9
|
-
description: "Display a bar with status and actions.",
|
|
10
|
-
iconComponent: (props) => /* @__PURE__ */ React.createElement(Info, props),
|
|
11
|
-
iconSymbol: "ph--info--regular"
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
export {
|
|
15
|
-
STATUS_BAR_PLUGIN,
|
|
16
|
-
meta_default
|
|
17
|
-
};
|
|
18
|
-
//# sourceMappingURL=chunk-PL5XPTPX.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/meta.tsx"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Info, type IconProps } from '@phosphor-icons/react';\nimport React from 'react';\n\nimport { pluginMeta } from '@dxos/app-framework';\n\nexport const STATUS_BAR_PLUGIN = 'dxos.org/plugin/status-bar';\n\nexport default pluginMeta({\n id: STATUS_BAR_PLUGIN,\n name: 'Status Bar',\n description: 'Display a bar with status and actions.',\n iconComponent: (props: IconProps) => <Info {...props} />,\n iconSymbol: 'ph--info--regular',\n});\n"],
|
|
5
|
-
"mappings": ";AAIA,SAASA,YAA4B;AACrC,OAAOC,WAAW;AAElB,SAASC,kBAAkB;AAEpB,IAAMC,oBAAoB;AAEjC,IAAA,eAAeC,WAAW;EACxBC,IAAIF;EACJG,MAAM;EACNC,aAAa;EACbC,eAAe,CAACC,UAAqB,sBAAA,cAACC,MAASD,KAAAA;EAC/CE,YAAY;AACd,CAAA;",
|
|
6
|
-
"names": ["Info", "React", "pluginMeta", "STATUS_BAR_PLUGIN", "pluginMeta", "id", "name", "description", "iconComponent", "props", "Info", "iconSymbol"]
|
|
7
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBarImpl.d.ts","sourceRoot":"","sources":["../../../../src/components/StatusBarImpl.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAmB,MAAM,OAAO,CAAC;AASxC,eAAO,MAAM,aAAa,yBA8BzB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,cAAc,WAAW,CAAC"}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { type ChangeEvent } from 'react';
|
|
2
|
-
import { type ValidationError } from '../util';
|
|
3
|
-
interface FormOptions<T> {
|
|
4
|
-
initialValues: T;
|
|
5
|
-
validate: (values: any) => ValidationError[] | undefined;
|
|
6
|
-
onSubmit: (values: T) => void;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Creates a hook for managing form state, including values, validation, and submission.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* const { values, handleChange, handleSubmit, errors, canSubmit, getInputProps } = useForm({
|
|
13
|
-
* initialValues: { name: '', email: '' },
|
|
14
|
-
* validate: (values) => { yourValidationLogic(values); },
|
|
15
|
-
* onSubmit: (values) => { submissionLogic(values); },
|
|
16
|
-
* });
|
|
17
|
-
*/
|
|
18
|
-
export declare const useForm: <T extends object>({ initialValues, validate, onSubmit }: FormOptions<T>) => {
|
|
19
|
-
values: T;
|
|
20
|
-
handleChange: (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
21
|
-
handleSubmit: () => void;
|
|
22
|
-
errors: Record<keyof T, string>;
|
|
23
|
-
canSubmit: boolean;
|
|
24
|
-
touched: Record<keyof T, boolean>;
|
|
25
|
-
handleBlur: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
26
|
-
onValidate: (values: T) => boolean;
|
|
27
|
-
getInputProps: (key: keyof T) => {
|
|
28
|
-
name: keyof T;
|
|
29
|
-
value: T[keyof T];
|
|
30
|
-
onChange: (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
31
|
-
onBlur: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
32
|
-
'aria-invalid': boolean;
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
export {};
|
|
36
|
-
//# sourceMappingURL=useForm.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useForm.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAK/C,UAAU,WAAW,CAAC,CAAC;IACrB,aAAa,EAAE,CAAC,CAAC;IACjB,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,eAAe,EAAE,GAAG,SAAS,CAAC;IACzD,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC;CAC/B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,MAAM,yCAAyC,WAAW,CAAC,CAAC,CAAC;;0BAkBnF,WAAW,CAAC,gBAAgB,GAAG,mBAAmB,CAAC;;;;;wBAYnD,KAAK,CAAC,UAAU,CAAC,gBAAgB,GAAG,mBAAmB,CAAC;yBAtBvD,CAAC;yBAiDJ,MAAM,CAAC;;;0BAvCL,WAAW,CAAC,gBAAgB,GAAG,mBAAmB,CAAC;wBAYnD,KAAK,CAAC,UAAU,CAAC,gBAAgB,GAAG,mBAAmB,CAAC;;;CAgDnE,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/util/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../../src/util/validation.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAEtC,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhE,eAAO,MAAM,QAAQ,GAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,GAAG,KAAG,eAAe,EAAE,GAAG,SAWhF,CAAC"}
|
package/src/hooks/index.ts
DELETED
package/src/hooks/useForm.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
import { type ChangeEvent, useCallback, useState } from 'react';
|
|
5
|
-
|
|
6
|
-
import { type ValidationError } from '../util';
|
|
7
|
-
|
|
8
|
-
// TODO(Zan): This module will be generally useful and we should factor it out after the
|
|
9
|
-
// API crystallizes a bit more.
|
|
10
|
-
|
|
11
|
-
interface FormOptions<T> {
|
|
12
|
-
initialValues: T;
|
|
13
|
-
validate: (values: any) => ValidationError[] | undefined;
|
|
14
|
-
onSubmit: (values: T) => void;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Creates a hook for managing form state, including values, validation, and submission.
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* const { values, handleChange, handleSubmit, errors, canSubmit, getInputProps } = useForm({
|
|
22
|
-
* initialValues: { name: '', email: '' },
|
|
23
|
-
* validate: (values) => { yourValidationLogic(values); },
|
|
24
|
-
* onSubmit: (values) => { submissionLogic(values); },
|
|
25
|
-
* });
|
|
26
|
-
*/
|
|
27
|
-
export const useForm = <T extends object>({ initialValues, validate, onSubmit }: FormOptions<T>) => {
|
|
28
|
-
const [values, setValues] = useState<T>(initialValues);
|
|
29
|
-
const [errors, setErrors] = useState<Record<keyof T, string>>({} as Record<keyof T, string>);
|
|
30
|
-
const [touched, setTouched] = useState<Record<keyof T, boolean>>(
|
|
31
|
-
Object.keys(initialValues).reduce((acc, key) => ({ ...acc, [key]: false }), {} as Record<keyof T, boolean>),
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
const runValidation = useCallback(
|
|
35
|
-
(values: T) => {
|
|
36
|
-
const validationErrors = validate(values);
|
|
37
|
-
setErrors(collapseErrorArray(validationErrors ?? []));
|
|
38
|
-
|
|
39
|
-
return validationErrors === undefined;
|
|
40
|
-
},
|
|
41
|
-
[validate],
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
const handleChange = useCallback(
|
|
45
|
-
(event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
46
|
-
const { name, value } = event.target;
|
|
47
|
-
const newValues = { ...values, [name]: value };
|
|
48
|
-
setValues(newValues);
|
|
49
|
-
runValidation(newValues);
|
|
50
|
-
},
|
|
51
|
-
[values, runValidation],
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
const touchAll = useCallback(() => setTouched(mkAllTouched(values)), [values, setTouched]);
|
|
55
|
-
|
|
56
|
-
const handleBlur = useCallback(
|
|
57
|
-
(event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
58
|
-
const { name } = event.target;
|
|
59
|
-
setTouched((touched) => ({ ...touched, [name]: true }));
|
|
60
|
-
|
|
61
|
-
// TODO(Zan): This should be configurable behavior.
|
|
62
|
-
if (event.relatedTarget?.getAttribute('type') === 'submit') {
|
|
63
|
-
// NOTE: We do this here instead of onSubmit, because the blur event is triggered before the submit event
|
|
64
|
-
// and results in the submit button being disabled when the form is invalid.
|
|
65
|
-
touchAll();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
runValidation(values);
|
|
69
|
-
},
|
|
70
|
-
[runValidation, values, touchAll],
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
const handleSubmit = useCallback(() => {
|
|
74
|
-
if (runValidation(values)) {
|
|
75
|
-
onSubmit(values);
|
|
76
|
-
}
|
|
77
|
-
}, [values, runValidation, onSubmit]);
|
|
78
|
-
|
|
79
|
-
// NOTE: We can submit if there is no touched field that has an error.
|
|
80
|
-
// - Basically, if there's a validation message present in the form, submit should be disabled.
|
|
81
|
-
const canSubmit = Object.keys(values).every((key) => touched[key as keyof T] === false || !errors[key as keyof T]);
|
|
82
|
-
|
|
83
|
-
const getInputProps = useCallback(
|
|
84
|
-
(key: keyof T) => ({
|
|
85
|
-
name: key,
|
|
86
|
-
value: values[key],
|
|
87
|
-
onChange: handleChange,
|
|
88
|
-
onBlur: handleBlur,
|
|
89
|
-
'aria-invalid': errors[key] !== undefined,
|
|
90
|
-
}),
|
|
91
|
-
[values, handleChange, handleBlur, errors],
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
values,
|
|
96
|
-
handleChange,
|
|
97
|
-
handleSubmit,
|
|
98
|
-
errors,
|
|
99
|
-
canSubmit,
|
|
100
|
-
touched,
|
|
101
|
-
handleBlur,
|
|
102
|
-
onValidate: runValidation,
|
|
103
|
-
getInputProps,
|
|
104
|
-
};
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const mkAllTouched = <T extends Record<keyof T, any>>(values: T) => {
|
|
108
|
-
return Object.keys(values).reduce((acc, key) => ({ ...acc, [key]: true }), {} as Record<keyof T, boolean>);
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const collapseErrorArray = <T>(errors: ValidationError[]) =>
|
|
112
|
-
errors.reduce(
|
|
113
|
-
(acc, { path, message }) => {
|
|
114
|
-
// TODO(Zan): This won't play well with nesting.
|
|
115
|
-
acc[path as keyof T] = message;
|
|
116
|
-
return acc;
|
|
117
|
-
},
|
|
118
|
-
{} as Record<keyof T, string>,
|
|
119
|
-
);
|