@dxos/plugin-status-bar 0.6.14-main.f49f251 → 0.6.14-staging.e15392e

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.
@@ -66,110 +66,19 @@ var StatusBar = {
66
66
  };
67
67
 
68
68
  // packages/plugins/plugin-status-bar/src/components/StatusBarPanel.tsx
69
- import React3, { useState as useState2 } from "react";
69
+ import React3, { useState } from "react";
70
70
  import { Surface } from "@dxos/app-framework";
71
71
  import { Icon, Popover as Popover2 } from "@dxos/react-ui";
72
72
 
73
73
  // packages/plugins/plugin-status-bar/src/components/FeedbackForm.tsx
74
- import { Schema as S2 } from "@effect/schema";
75
- import { X, PaperPlaneTilt } from "@phosphor-icons/react";
76
- import React2, { useCallback as useCallback2 } from "react";
74
+ import { Schema as S } from "@effect/schema";
75
+ import { PaperPlaneTilt, X } from "@phosphor-icons/react";
76
+ import React2, { useCallback } from "react";
77
77
  import { useIntentDispatcher } from "@dxos/app-framework";
78
78
  import { Button, Input, Popover, useTranslation } from "@dxos/react-ui";
79
+ import { useForm } from "@dxos/react-ui-data";
79
80
  import { getSize } from "@dxos/react-ui-theme";
80
81
 
81
- // packages/plugins/plugin-status-bar/src/hooks/useForm.ts
82
- import { useCallback, useState } from "react";
83
- var useForm = ({ initialValues: initialValues2, validate: validate2, onSubmit }) => {
84
- const [values, setValues] = useState(initialValues2);
85
- const [errors, setErrors] = useState({});
86
- const [touched, setTouched] = useState(Object.keys(initialValues2).reduce((acc, key) => ({
87
- ...acc,
88
- [key]: false
89
- }), {}));
90
- const runValidation = useCallback((values2) => {
91
- const validationErrors = validate2(values2);
92
- setErrors(collapseErrorArray(validationErrors ?? []));
93
- return validationErrors === void 0;
94
- }, [
95
- validate2
96
- ]);
97
- const handleChange = useCallback((event) => {
98
- const { name, value } = event.target;
99
- const newValues = {
100
- ...values,
101
- [name]: value
102
- };
103
- setValues(newValues);
104
- runValidation(newValues);
105
- }, [
106
- values,
107
- runValidation
108
- ]);
109
- const touchAll = useCallback(() => setTouched(mkAllTouched(values)), [
110
- values,
111
- setTouched
112
- ]);
113
- const handleBlur = useCallback((event) => {
114
- const { name } = event.target;
115
- setTouched((touched2) => ({
116
- ...touched2,
117
- [name]: true
118
- }));
119
- if (event.relatedTarget?.getAttribute("type") === "submit") {
120
- touchAll();
121
- }
122
- runValidation(values);
123
- }, [
124
- runValidation,
125
- values,
126
- touchAll
127
- ]);
128
- const handleSubmit = useCallback(() => {
129
- if (runValidation(values)) {
130
- onSubmit(values);
131
- }
132
- }, [
133
- values,
134
- runValidation,
135
- onSubmit
136
- ]);
137
- const canSubmit = Object.keys(values).every((key) => touched[key] === false || !errors[key]);
138
- const getInputProps = useCallback((key) => ({
139
- name: key,
140
- value: values[key],
141
- onChange: handleChange,
142
- onBlur: handleBlur,
143
- "aria-invalid": errors[key] !== void 0
144
- }), [
145
- values,
146
- handleChange,
147
- handleBlur,
148
- errors
149
- ]);
150
- return {
151
- values,
152
- handleChange,
153
- handleSubmit,
154
- errors,
155
- canSubmit,
156
- touched,
157
- handleBlur,
158
- onValidate: runValidation,
159
- getInputProps
160
- };
161
- };
162
- var mkAllTouched = (values) => {
163
- return Object.keys(values).reduce((acc, key) => ({
164
- ...acc,
165
- [key]: true
166
- }), {});
167
- };
168
- var collapseErrorArray = (errors) => errors.reduce((acc, { path, message }) => {
169
- acc[path] = message;
170
- return acc;
171
- }, {});
172
-
173
82
  // packages/plugins/plugin-status-bar/src/translations.ts
174
83
  var entry = (translation) => ({
175
84
  [STATUS_BAR_PLUGIN]: translation
@@ -191,40 +100,22 @@ var translations_default = [
191
100
  translations
192
101
  ];
193
102
 
194
- // packages/plugins/plugin-status-bar/src/util/validation.ts
195
- import { ArrayFormatter, Schema as S } from "@effect/schema";
196
- import { Effect } from "effect";
197
- var validate = (schema, data) => {
198
- const validator = S.decodeUnknownEither(schema, {
199
- errors: "all"
200
- });
201
- const result = validator(data);
202
- if (result._tag === "Left") {
203
- const errors = Effect.runSync(ArrayFormatter.formatError(result.left));
204
- return errors.map(({ message, path }) => ({
205
- message,
206
- path: path.join(".")
207
- }));
208
- }
209
- return void 0;
210
- };
211
-
212
103
  // packages/plugins/plugin-status-bar/src/components/FeedbackForm.tsx
213
- var Email = S2.String.pipe(S2.nonEmptyString({
104
+ var Email = S.String.pipe(S.nonEmptyString({
214
105
  message: () => "Email is required."
215
- }), S2.pattern(/^(?!\.)(?!.*\.\.)([A-Z0-9_+-.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9-]*\.)+[A-Z]{2,}$/i, {
106
+ }), S.pattern(/^(?!\.)(?!.*\.\.)([A-Z0-9_+-.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9-]*\.)+[A-Z]{2,}$/i, {
216
107
  message: () => "Invalid email address."
217
108
  }));
218
- var nonEmpty = (field) => S2.nonEmptyString({
109
+ var nonEmpty = (field) => S.nonEmptyString({
219
110
  message: () => `${field} is required.`
220
111
  });
221
- var maxLength = (field, length) => S2.maxLength(length, {
112
+ var maxLength = (field, length) => S.maxLength(length, {
222
113
  message: () => `${field} is too long.`
223
114
  });
224
- var FeedbackFormSchema = S2.Struct({
225
- name: S2.String.pipe(nonEmpty("Name"), maxLength("Name", 256)),
115
+ var FeedbackFormSchema = S.Struct({
116
+ name: S.String.pipe(nonEmpty("Name"), maxLength("Name", 256)),
226
117
  email: Email.pipe(maxLength("Email", 256)),
227
- message: S2.String.pipe(nonEmpty("Feedback"), maxLength("Feedback", 32768))
118
+ message: S.String.pipe(nonEmpty("Feedback"), maxLength("Feedback", 32768))
228
119
  });
229
120
  var initialValues = {
230
121
  name: "",
@@ -235,7 +126,7 @@ var FeedbackForm = ({ onClose }) => {
235
126
  const { t } = useTranslation(STATUS_BAR_PLUGIN);
236
127
  const translation = mkTranslation(t);
237
128
  const dispatch = useIntentDispatcher();
238
- const onSubmit = useCallback2((values) => {
129
+ const onSubmit = useCallback((values) => {
239
130
  void dispatch({
240
131
  action: "dxos.org/plugin/observability/capture-feedback",
241
132
  data: values
@@ -247,8 +138,8 @@ var FeedbackForm = ({ onClose }) => {
247
138
  ]);
248
139
  const { errors, handleSubmit, canSubmit, touched, getInputProps } = useForm({
249
140
  initialValues,
250
- validate: (values) => validate(FeedbackFormSchema, values),
251
- onSubmit: (values) => onSubmit(values)
141
+ schema: FeedbackFormSchema,
142
+ onSubmit
252
143
  });
253
144
  return /* @__PURE__ */ React2.createElement("div", {
254
145
  role: "form",
@@ -311,7 +202,7 @@ var FeedbackForm = ({ onClose }) => {
311
202
 
312
203
  // packages/plugins/plugin-status-bar/src/components/StatusBarPanel.tsx
313
204
  var StatusBarPanel = () => {
314
- const [open, setOpen] = useState2(false);
205
+ const [open, setOpen] = useState(false);
315
206
  return /* @__PURE__ */ React3.createElement(Popover2.Root, {
316
207
  open,
317
208
  onOpenChange: setOpen
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../src/StatusBarPlugin.tsx", "../../../src/components/StatusBar.tsx", "../../../src/components/StatusBarPanel.tsx", "../../../src/components/FeedbackForm.tsx", "../../../src/hooks/useForm.ts", "../../../src/translations.ts", "../../../src/util/validation.ts", "../../../src/index.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport React from 'react';\n\nimport { type PluginDefinition, type SurfaceProvides, type TranslationsProvides } from '@dxos/app-framework';\n\nimport { StatusBarPanel } from './components';\nimport meta from './meta';\nimport translations from './translations';\n\nexport type StatusBarPluginProvides = SurfaceProvides & TranslationsProvides;\n\nexport const StatusBarPlugin = (): PluginDefinition<StatusBarPluginProvides> => {\n return {\n meta,\n provides: {\n translations,\n surface: {\n component: ({ role }) => {\n switch (role) {\n case 'status-bar': {\n return <StatusBarPanel />;\n }\n }\n\n return null;\n },\n },\n },\n };\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { useFocusableGroup } from '@fluentui/react-tabster';\nimport { Slot } from '@radix-ui/react-slot';\nimport React, { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\n\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { mx } from '@dxos/react-ui-theme';\n\ntype StatusBarTextProps = ThemedClassName<{ children: ReactNode }>;\n\nconst StatusBarText = forwardRef<HTMLSpanElement, StatusBarTextProps>(({ classNames, children }, forwardedRef) => (\n <span className={mx(classNames)} ref={forwardedRef}>\n {children}\n </span>\n));\n\ntype StatusBarButtonProps = ThemedClassName<{ children: ReactNode; asChild?: boolean }> &\n HTMLAttributes<HTMLButtonElement>;\n\nconst StatusBarButton = forwardRef<HTMLButtonElement, StatusBarButtonProps>(\n ({ classNames, children, asChild, ...props }, forwardedRef) => {\n const classes = mx(\n 'flex items-center gap-2 p-1 px-2 rounded-sm',\n 'select-none cursor-pointer ch-focus-ring',\n 'hover:bg-neutral-75 active:bg-neutral-150 dark:hover:bg-neutral-750 dark:active:bg-neutral-700',\n classNames,\n );\n\n return asChild ? (\n <Slot role='button' ref={forwardedRef} className={classes} {...props}>\n {children}\n </Slot>\n ) : (\n <button className={classes} ref={forwardedRef} {...props}>\n {children}\n </button>\n );\n },\n);\n\nexport default StatusBarButton;\n\ntype StatusBarItemProps = ThemedClassName<{ children: ReactNode }> & HTMLAttributes<HTMLDivElement>;\n\nconst StatusBarItem = forwardRef<HTMLDivElement, StatusBarItemProps>(\n ({ classNames, children, ...props }, forwardedRef) => (\n <div\n role='menuitem'\n className={mx('flex items-center gap-2 p-1 px-2 rounded-sm select-none', classNames)}\n ref={forwardedRef}\n {...props}\n >\n {children}\n </div>\n ),\n);\n\ntype StatusBarContainerProps = ThemedClassName<{ children: ReactNode }>;\n\n// TODO(zan): tabable group with tabster.\nconst StatusBarContainer = forwardRef<HTMLDivElement, StatusBarContainerProps>(\n ({ classNames, children }, forwardedRef) => {\n const groupAttrs = useFocusableGroup({ tabBehavior: 'limited' });\n return (\n <div\n role='menubar'\n tabIndex={0}\n {...groupAttrs}\n className={mx(\n 'bs-[--statusbar-size] flex justify-end items-center gap-2 bg-base text-description text-lg pointer-fine:text-xs ch-focus-ring-inset',\n classNames,\n )}\n ref={forwardedRef}\n >\n {children}\n </div>\n );\n },\n);\n\ntype StartContentProps = ThemedClassName<{ children: ReactNode }>;\n\nconst StartContent = forwardRef<HTMLDivElement, StartContentProps>(({ classNames, children }, forwardedRef) => (\n <div role='none' className={mx('flex-grow flex items-center space-x-2', classNames)} ref={forwardedRef}>\n {children}\n </div>\n));\n\ntype EndContentProps = ThemedClassName<{ children: ReactNode }>;\n\nconst EndContent = forwardRef<HTMLDivElement, EndContentProps>(({ classNames, children }, forwardedRef) => (\n <div role='none' className={mx('flex-grow flex items-center justify-end', classNames)} ref={forwardedRef}>\n {children}\n </div>\n));\n\nexport const StatusBar = {\n Container: StatusBarContainer,\n Text: StatusBarText,\n Item: StatusBarItem,\n Button: StatusBarButton,\n StartContent,\n EndContent,\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport React, { useState } from 'react';\n\nimport { Surface } from '@dxos/app-framework';\nimport { Icon, Popover } from '@dxos/react-ui';\n\nimport { FeedbackForm } from './FeedbackForm';\nimport { StatusBar } from './StatusBar';\n\nexport const StatusBarPanel = () => {\n const [open, setOpen] = useState(false);\n\n // TODO(wittjosiah): Factor out feedback and discord buttons.\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <StatusBar.Container>\n <StatusBar.EndContent>\n <Popover.Trigger asChild>\n <StatusBar.Button aria-label='Give feedback about composer' data-joyride='welcome/feedback'>\n <Icon icon='ph--paper-plane-tilt--regular' size={4} />\n <StatusBar.Text classNames='hidden sm:block'>Feedback</StatusBar.Text>\n </StatusBar.Button>\n </Popover.Trigger>\n {/* TODO(zan): Configure this label? */}\n <StatusBar.Button aria-label='Open DXOS Discord' asChild>\n <a href='https://dxos.org/discord' target='_blank' rel='noopener noreferrer'>\n <Icon icon='ph--discord-logo--regular' size={4} />\n <StatusBar.Text classNames='hidden sm:block'>Discord</StatusBar.Text>\n </a>\n </StatusBar.Button>\n </StatusBar.EndContent>\n <Surface role='status' />\n </StatusBar.Container>\n <Popover.Content classNames='shadow-lg'>\n <FeedbackForm onClose={() => setOpen(false)} />\n <Popover.Arrow />\n </Popover.Content>\n </Popover.Root>\n );\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { Schema as S } from '@effect/schema';\nimport { X, PaperPlaneTilt } from '@phosphor-icons/react';\nimport React, { useCallback } from 'react';\n\nimport { useIntentDispatcher } from '@dxos/app-framework';\nimport { Button, Input, Popover, useTranslation } from '@dxos/react-ui';\nimport { getSize } from '@dxos/react-ui-theme';\n\nimport { useForm } from '../hooks';\nimport { STATUS_BAR_PLUGIN } from '../meta';\nimport { mkTranslation } from '../translations';\nimport { validate } from '../util';\n\nconst Email = S.String.pipe(\n S.nonEmptyString({ message: () => 'Email is required.' }),\n S.pattern(/^(?!\\.)(?!.*\\.\\.)([A-Z0-9_+-.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9-]*\\.)+[A-Z]{2,}$/i, {\n message: () => 'Invalid email address.',\n }),\n);\n\nconst nonEmpty = (field: string) => S.nonEmptyString({ message: () => `${field} is required.` });\nconst maxLength = (field: string, length: number) => S.maxLength(length, { message: () => `${field} is too long.` });\n\n// Types and validation.\nconst FeedbackFormSchema = S.Struct({\n name: S.String.pipe(nonEmpty('Name'), maxLength('Name', 256)),\n email: Email.pipe(maxLength('Email', 256)),\n message: S.String.pipe(nonEmpty('Feedback'), maxLength('Feedback', 32_768)),\n});\n\ntype FeedbackFormState = S.Schema.Type<typeof FeedbackFormSchema>;\n\nconst initialValues: FeedbackFormState = { name: '', email: '', message: '' };\n\nexport const FeedbackForm = ({ onClose }: { onClose: () => void }) => {\n const { t } = useTranslation(STATUS_BAR_PLUGIN);\n const translation = mkTranslation(t);\n const dispatch = useIntentDispatcher();\n\n const onSubmit = useCallback(\n (values: FeedbackFormState) => {\n void dispatch({ action: 'dxos.org/plugin/observability/capture-feedback', data: values });\n onClose();\n },\n [dispatch, onClose],\n );\n\n const { errors, handleSubmit, canSubmit, touched, getInputProps } = useForm<FeedbackFormState>({\n initialValues,\n validate: (values) => validate(FeedbackFormSchema, values),\n onSubmit: (values) => onSubmit(values),\n });\n\n return (\n <div role='form' className='p-3 flex flex-col gap-2'>\n <div role='none' className='space-b-1'>\n <Input.Root validationValence={touched.name && errors.name ? 'error' : undefined}>\n <Input.Label>{translation('name label')}</Input.Label>\n <Input.TextInput\n classNames={'text-sm'}\n placeholder={translation('name placeholder')}\n autoFocus\n {...getInputProps('name')}\n />\n <Input.DescriptionAndValidation>\n <Input.Validation>{touched.name && errors.name}</Input.Validation>\n </Input.DescriptionAndValidation>\n </Input.Root>\n </div>\n\n <div role='none' className='space-b-1'>\n <Input.Root validationValence={touched.email && errors.email ? 'error' : undefined}>\n <Input.Label>{translation('email input label')}</Input.Label>\n <Input.TextInput\n classNames={'text-sm'}\n placeholder={translation('email input placeholder')}\n {...getInputProps('email')}\n />\n <Input.DescriptionAndValidation>\n <Input.Validation>{touched.email && errors.email}</Input.Validation>\n </Input.DescriptionAndValidation>\n </Input.Root>\n </div>\n\n <div role='none' className='space-b-1'>\n <Input.Root validationValence={touched.message && errors.message ? 'error' : undefined}>\n <Input.Label>{translation('feedback text area label')}</Input.Label>\n <Input.TextArea\n classNames={'text-sm'}\n rows={5}\n cols={30}\n placeholder={translation('feedback text area placeholder')}\n {...getInputProps('message')}\n />\n <Input.DescriptionAndValidation>\n <Input.Validation>{touched.message && errors.message}</Input.Validation>\n </Input.DescriptionAndValidation>\n </Input.Root>\n </div>\n\n <div role='none' className='space-b-2'>\n <Button\n type='submit'\n variant='primary'\n classNames='is-full flex gap-2'\n disabled={!canSubmit}\n onClick={handleSubmit}\n >\n <span>{translation('send feedback label')}</span>\n <div className='grow' />\n <PaperPlaneTilt className={getSize(5)} />\n </Button>\n <Popover.Close asChild>\n <Button classNames='is-full flex gap-2'>\n <span>{t('cancel label', { ns: 'os' })}</span>\n <div className='grow' />\n <X className={getSize(5)} />\n </Button>\n </Popover.Close>\n </div>\n </div>\n );\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { type ChangeEvent, type FocusEvent, useCallback, useState } from 'react';\n\nimport { type ValidationError } from '../util';\n\n// TODO(Zan): This module will be generally useful and we should factor it out after the\n// API crystallizes a bit more.\n\ninterface FormOptions<T> {\n initialValues: T;\n validate: (values: any) => ValidationError[] | undefined;\n onSubmit: (values: T) => void;\n}\n\n/**\n * Creates a hook for managing form state, including values, validation, and submission.\n *\n * @example\n * const { values, handleChange, handleSubmit, errors, canSubmit, getInputProps } = useForm({\n * initialValues: { name: '', email: '' },\n * validate: (values) => { yourValidationLogic(values); },\n * onSubmit: (values) => { submissionLogic(values); },\n * });\n */\nexport const useForm = <T extends object>({ initialValues, validate, onSubmit }: FormOptions<T>) => {\n const [values, setValues] = useState<T>(initialValues);\n const [errors, setErrors] = useState<Record<keyof T, string>>({} as Record<keyof T, string>);\n const [touched, setTouched] = useState<Record<keyof T, boolean>>(\n Object.keys(initialValues).reduce((acc, key) => ({ ...acc, [key]: false }), {} as Record<keyof T, boolean>),\n );\n\n const runValidation = useCallback(\n (values: T) => {\n const validationErrors = validate(values);\n setErrors(collapseErrorArray(validationErrors ?? []));\n\n return validationErrors === undefined;\n },\n [validate],\n );\n\n const handleChange = useCallback(\n (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n const { name, value } = event.target;\n const newValues = { ...values, [name]: value };\n setValues(newValues);\n runValidation(newValues);\n },\n [values, runValidation],\n );\n\n const touchAll = useCallback(() => setTouched(mkAllTouched(values)), [values, setTouched]);\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n const { name } = event.target;\n setTouched((touched) => ({ ...touched, [name]: true }));\n\n // TODO(Zan): This should be configurable behavior.\n if (event.relatedTarget?.getAttribute('type') === 'submit') {\n // NOTE: We do this here instead of onSubmit, because the blur event is triggered before the submit event\n // and results in the submit button being disabled when the form is invalid.\n touchAll();\n }\n\n runValidation(values);\n },\n [runValidation, values, touchAll],\n );\n\n const handleSubmit = useCallback(() => {\n if (runValidation(values)) {\n onSubmit(values);\n }\n }, [values, runValidation, onSubmit]);\n\n // NOTE: We can submit if there is no touched field that has an error.\n // - Basically, if there's a validation message present in the form, submit should be disabled.\n const canSubmit = Object.keys(values).every((key) => touched[key as keyof T] === false || !errors[key as keyof T]);\n\n const getInputProps = useCallback(\n (key: keyof T) => ({\n name: key,\n value: values[key],\n onChange: handleChange,\n onBlur: handleBlur,\n 'aria-invalid': errors[key] !== undefined,\n }),\n [values, handleChange, handleBlur, errors],\n );\n\n return {\n values,\n handleChange,\n handleSubmit,\n errors,\n canSubmit,\n touched,\n handleBlur,\n onValidate: runValidation,\n getInputProps,\n };\n};\n\nconst mkAllTouched = <T extends Record<keyof T, any>>(values: T) => {\n return Object.keys(values).reduce((acc, key) => ({ ...acc, [key]: true }), {} as Record<keyof T, boolean>);\n};\n\nconst collapseErrorArray = <T>(errors: ValidationError[]) =>\n errors.reduce(\n (acc, { path, message }) => {\n // TODO(Zan): This won't play well with nesting.\n acc[path as keyof T] = message;\n return acc;\n },\n {} as Record<keyof T, string>,\n );\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type useTranslation } from '@dxos/react-ui';\n\nimport { STATUS_BAR_PLUGIN } from './meta';\n\ntype StatusBarTranslationKeys =\n | 'plugin name'\n | 'email input label'\n | 'email input placeholder'\n | 'feedback text area label'\n | 'feedback text area placeholder'\n | 'send feedback label'\n | 'name label'\n | 'name placeholder';\n\ntype RequiredTranslation = { [key in StatusBarTranslationKeys]: string };\ntype TranslationEntry = { [STATUS_BAR_PLUGIN]: RequiredTranslation };\ntype Language = string;\n\n// -- helpers.\nconst entry = (translation: RequiredTranslation): TranslationEntry => ({ [STATUS_BAR_PLUGIN]: translation });\nexport const mkTranslation = (t: ReturnType<typeof useTranslation>['t']) => (key: StatusBarTranslationKeys) => t(key);\n\nconst translations: Record<Language, TranslationEntry> = {\n 'en-US': entry({\n 'plugin name': 'Status Bar',\n 'name label': 'Name',\n 'name placeholder': 'Preferred name',\n 'email input label': 'Email',\n 'email input placeholder': 'hello@example.com',\n 'feedback text area label': 'Feedback',\n 'feedback text area placeholder': 'Found a bug? Have a suggestion? Let us know!',\n 'send feedback label': 'Send Feedback',\n }),\n};\n\nexport default [translations];\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { ArrayFormatter, Schema as S } from '@effect/schema';\nimport { Effect } from 'effect';\n\nexport type ValidationError = { path: string; message: string };\n\nexport const validate = <T>(schema: S.Schema<T>, data: any): ValidationError[] | undefined => {\n const validator = S.decodeUnknownEither(schema, { errors: 'all' });\n const result = validator(data);\n\n if (result._tag === 'Left') {\n const errors = Effect.runSync(ArrayFormatter.formatError(result.left));\n // TODO(Zan): Path.join is an assumption...\n return errors.map(({ message, path }) => ({ message, path: path.join('.') }));\n }\n\n return undefined;\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { StatusBarPlugin } from './StatusBarPlugin';\n\nexport default StatusBarPlugin;\n\nexport * from './StatusBarPlugin';\nexport * from './components';\n"],
5
- "mappings": "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",
6
- "names": ["React", "useFocusableGroup", "Slot", "React", "forwardRef", "mx", "StatusBarText", "forwardRef", "classNames", "children", "forwardedRef", "span", "className", "mx", "ref", "StatusBarButton", "asChild", "props", "classes", "Slot", "role", "button", "StatusBarItem", "forwardRef", "classNames", "children", "props", "forwardedRef", "div", "role", "className", "mx", "ref", "StatusBarContainer", "groupAttrs", "useFocusableGroup", "tabBehavior", "tabIndex", "StartContent", "EndContent", "StatusBar", "Container", "Text", "StatusBarText", "Item", "Button", "StatusBarButton", "React", "useState", "Surface", "Icon", "Popover", "Schema", "S", "X", "PaperPlaneTilt", "React", "useCallback", "useIntentDispatcher", "Button", "Input", "Popover", "useTranslation", "getSize", "useCallback", "useState", "useForm", "initialValues", "validate", "onSubmit", "values", "setValues", "useState", "errors", "setErrors", "touched", "setTouched", "Object", "keys", "reduce", "acc", "key", "runValidation", "useCallback", "validationErrors", "collapseErrorArray", "undefined", "handleChange", "event", "name", "value", "target", "newValues", "touchAll", "mkAllTouched", "handleBlur", "relatedTarget", "getAttribute", "handleSubmit", "canSubmit", "every", "getInputProps", "onChange", "onBlur", "onValidate", "path", "message", "entry", "translation", "STATUS_BAR_PLUGIN", "mkTranslation", "t", "key", "translations", "ArrayFormatter", "Schema", "S", "Effect", "validate", "schema", "data", "validator", "S", "decodeUnknownEither", "errors", "result", "_tag", "Effect", "runSync", "ArrayFormatter", "formatError", "left", "map", "message", "path", "join", "undefined", "Email", "S", "String", "pipe", "nonEmptyString", "message", "pattern", "nonEmpty", "field", "maxLength", "length", "FeedbackFormSchema", "Struct", "name", "email", "initialValues", "FeedbackForm", "onClose", "t", "useTranslation", "STATUS_BAR_PLUGIN", "translation", "mkTranslation", "dispatch", "useIntentDispatcher", "onSubmit", "useCallback", "values", "action", "data", "errors", "handleSubmit", "canSubmit", "touched", "getInputProps", "useForm", "validate", "React", "div", "role", "className", "Input", "Root", "validationValence", "undefined", "Label", "TextInput", "classNames", "placeholder", "autoFocus", "DescriptionAndValidation", "Validation", "TextArea", "rows", "cols", "Button", "type", "variant", "disabled", "onClick", "span", "PaperPlaneTilt", "getSize", "Popover", "Close", "asChild", "ns", "X", "StatusBarPanel", "open", "setOpen", "useState", "React", "Popover", "Root", "onOpenChange", "StatusBar", "Container", "EndContent", "Trigger", "asChild", "Button", "aria-label", "data-joyride", "Icon", "icon", "size", "Text", "classNames", "a", "href", "target", "rel", "Surface", "role", "Content", "FeedbackForm", "onClose", "Arrow", "StatusBarPlugin", "meta", "provides", "translations", "surface", "component", "role", "React", "StatusBarPanel", "StatusBarPlugin"]
3
+ "sources": ["../../../src/StatusBarPlugin.tsx", "../../../src/components/StatusBar.tsx", "../../../src/components/StatusBarPanel.tsx", "../../../src/components/FeedbackForm.tsx", "../../../src/translations.ts", "../../../src/index.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport React from 'react';\n\nimport { type PluginDefinition, type SurfaceProvides, type TranslationsProvides } from '@dxos/app-framework';\n\nimport { StatusBarPanel } from './components';\nimport meta from './meta';\nimport translations from './translations';\n\nexport type StatusBarPluginProvides = SurfaceProvides & TranslationsProvides;\n\nexport const StatusBarPlugin = (): PluginDefinition<StatusBarPluginProvides> => {\n return {\n meta,\n provides: {\n translations,\n surface: {\n component: ({ role }) => {\n switch (role) {\n case 'status-bar': {\n return <StatusBarPanel />;\n }\n }\n\n return null;\n },\n },\n },\n };\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { useFocusableGroup } from '@fluentui/react-tabster';\nimport { Slot } from '@radix-ui/react-slot';\nimport React, { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\n\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { mx } from '@dxos/react-ui-theme';\n\ntype StatusBarTextProps = ThemedClassName<{ children: ReactNode }>;\n\nconst StatusBarText = forwardRef<HTMLSpanElement, StatusBarTextProps>(({ classNames, children }, forwardedRef) => (\n <span className={mx(classNames)} ref={forwardedRef}>\n {children}\n </span>\n));\n\ntype StatusBarButtonProps = ThemedClassName<{ children: ReactNode; asChild?: boolean }> &\n HTMLAttributes<HTMLButtonElement>;\n\nconst StatusBarButton = forwardRef<HTMLButtonElement, StatusBarButtonProps>(\n ({ classNames, children, asChild, ...props }, forwardedRef) => {\n const classes = mx(\n 'flex items-center gap-2 p-1 px-2 rounded-sm',\n 'select-none cursor-pointer ch-focus-ring',\n 'hover:bg-neutral-75 active:bg-neutral-150 dark:hover:bg-neutral-750 dark:active:bg-neutral-700',\n classNames,\n );\n\n return asChild ? (\n <Slot role='button' ref={forwardedRef} className={classes} {...props}>\n {children}\n </Slot>\n ) : (\n <button className={classes} ref={forwardedRef} {...props}>\n {children}\n </button>\n );\n },\n);\n\nexport default StatusBarButton;\n\ntype StatusBarItemProps = ThemedClassName<{ children: ReactNode }> & HTMLAttributes<HTMLDivElement>;\n\nconst StatusBarItem = forwardRef<HTMLDivElement, StatusBarItemProps>(\n ({ classNames, children, ...props }, forwardedRef) => (\n <div\n role='menuitem'\n className={mx('flex items-center gap-2 p-1 px-2 rounded-sm select-none', classNames)}\n ref={forwardedRef}\n {...props}\n >\n {children}\n </div>\n ),\n);\n\ntype StatusBarContainerProps = ThemedClassName<{ children: ReactNode }>;\n\n// TODO(zan): tabable group with tabster.\nconst StatusBarContainer = forwardRef<HTMLDivElement, StatusBarContainerProps>(\n ({ classNames, children }, forwardedRef) => {\n const groupAttrs = useFocusableGroup({ tabBehavior: 'limited' });\n return (\n <div\n role='menubar'\n tabIndex={0}\n {...groupAttrs}\n className={mx(\n 'bs-[--statusbar-size] flex justify-end items-center gap-2 bg-base text-description text-lg pointer-fine:text-xs ch-focus-ring-inset',\n classNames,\n )}\n ref={forwardedRef}\n >\n {children}\n </div>\n );\n },\n);\n\ntype StartContentProps = ThemedClassName<{ children: ReactNode }>;\n\nconst StartContent = forwardRef<HTMLDivElement, StartContentProps>(({ classNames, children }, forwardedRef) => (\n <div role='none' className={mx('flex-grow flex items-center space-x-2', classNames)} ref={forwardedRef}>\n {children}\n </div>\n));\n\ntype EndContentProps = ThemedClassName<{ children: ReactNode }>;\n\nconst EndContent = forwardRef<HTMLDivElement, EndContentProps>(({ classNames, children }, forwardedRef) => (\n <div role='none' className={mx('flex-grow flex items-center justify-end', classNames)} ref={forwardedRef}>\n {children}\n </div>\n));\n\nexport const StatusBar = {\n Container: StatusBarContainer,\n Text: StatusBarText,\n Item: StatusBarItem,\n Button: StatusBarButton,\n StartContent,\n EndContent,\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport React, { useState } from 'react';\n\nimport { Surface } from '@dxos/app-framework';\nimport { Icon, Popover } from '@dxos/react-ui';\n\nimport { FeedbackForm } from './FeedbackForm';\nimport { StatusBar } from './StatusBar';\n\nexport const StatusBarPanel = () => {\n const [open, setOpen] = useState(false);\n\n // TODO(wittjosiah): Factor out feedback and discord buttons.\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <StatusBar.Container>\n <StatusBar.EndContent>\n <Popover.Trigger asChild>\n <StatusBar.Button aria-label='Give feedback about composer' data-joyride='welcome/feedback'>\n <Icon icon='ph--paper-plane-tilt--regular' size={4} />\n <StatusBar.Text classNames='hidden sm:block'>Feedback</StatusBar.Text>\n </StatusBar.Button>\n </Popover.Trigger>\n {/* TODO(zan): Configure this label? */}\n <StatusBar.Button aria-label='Open DXOS Discord' asChild>\n <a href='https://dxos.org/discord' target='_blank' rel='noopener noreferrer'>\n <Icon icon='ph--discord-logo--regular' size={4} />\n <StatusBar.Text classNames='hidden sm:block'>Discord</StatusBar.Text>\n </a>\n </StatusBar.Button>\n </StatusBar.EndContent>\n <Surface role='status' />\n </StatusBar.Container>\n <Popover.Content classNames='shadow-lg'>\n <FeedbackForm onClose={() => setOpen(false)} />\n <Popover.Arrow />\n </Popover.Content>\n </Popover.Root>\n );\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { Schema as S } from '@effect/schema';\nimport { PaperPlaneTilt, X } from '@phosphor-icons/react';\nimport React, { useCallback } from 'react';\n\nimport { useIntentDispatcher } from '@dxos/app-framework';\nimport { Button, Input, Popover, useTranslation } from '@dxos/react-ui';\nimport { useForm } from '@dxos/react-ui-data';\nimport { getSize } from '@dxos/react-ui-theme';\n\nimport { STATUS_BAR_PLUGIN } from '../meta';\nimport { mkTranslation } from '../translations';\n\nconst Email = S.String.pipe(\n S.nonEmptyString({ message: () => 'Email is required.' }),\n S.pattern(/^(?!\\.)(?!.*\\.\\.)([A-Z0-9_+-.]*)[A-Z0-9_+-]@([A-Z0-9][A-Z0-9-]*\\.)+[A-Z]{2,}$/i, {\n message: () => 'Invalid email address.',\n }),\n);\n\nconst nonEmpty = (field: string) => S.nonEmptyString({ message: () => `${field} is required.` });\nconst maxLength = (field: string, length: number) => S.maxLength(length, { message: () => `${field} is too long.` });\n\n// Types and validation.\nconst FeedbackFormSchema = S.Struct({\n name: S.String.pipe(nonEmpty('Name'), maxLength('Name', 256)),\n email: Email.pipe(maxLength('Email', 256)),\n message: S.String.pipe(nonEmpty('Feedback'), maxLength('Feedback', 32_768)),\n});\n\ntype FeedbackFormState = S.Schema.Type<typeof FeedbackFormSchema>;\n\nconst initialValues: FeedbackFormState = { name: '', email: '', message: '' };\n\nexport const FeedbackForm = ({ onClose }: { onClose: () => void }) => {\n const { t } = useTranslation(STATUS_BAR_PLUGIN);\n const translation = mkTranslation(t);\n const dispatch = useIntentDispatcher();\n\n const onSubmit = useCallback(\n (values: FeedbackFormState) => {\n void dispatch({ action: 'dxos.org/plugin/observability/capture-feedback', data: values });\n onClose();\n },\n [dispatch, onClose],\n );\n\n const { errors, handleSubmit, canSubmit, touched, getInputProps } = useForm<FeedbackFormState>({\n initialValues,\n schema: FeedbackFormSchema,\n onSubmit,\n });\n\n return (\n <div role='form' className='p-3 flex flex-col gap-2'>\n <div role='none' className='space-b-1'>\n <Input.Root validationValence={touched.name && errors.name ? 'error' : undefined}>\n <Input.Label>{translation('name label')}</Input.Label>\n <Input.TextInput\n classNames={'text-sm'}\n placeholder={translation('name placeholder')}\n autoFocus\n {...getInputProps('name')}\n />\n <Input.DescriptionAndValidation>\n <Input.Validation>{touched.name && errors.name}</Input.Validation>\n </Input.DescriptionAndValidation>\n </Input.Root>\n </div>\n\n <div role='none' className='space-b-1'>\n <Input.Root validationValence={touched.email && errors.email ? 'error' : undefined}>\n <Input.Label>{translation('email input label')}</Input.Label>\n <Input.TextInput\n classNames={'text-sm'}\n placeholder={translation('email input placeholder')}\n {...getInputProps('email')}\n />\n <Input.DescriptionAndValidation>\n <Input.Validation>{touched.email && errors.email}</Input.Validation>\n </Input.DescriptionAndValidation>\n </Input.Root>\n </div>\n\n <div role='none' className='space-b-1'>\n <Input.Root validationValence={touched.message && errors.message ? 'error' : undefined}>\n <Input.Label>{translation('feedback text area label')}</Input.Label>\n <Input.TextArea\n classNames={'text-sm'}\n rows={5}\n cols={30}\n placeholder={translation('feedback text area placeholder')}\n {...getInputProps('message')}\n />\n <Input.DescriptionAndValidation>\n <Input.Validation>{touched.message && errors.message}</Input.Validation>\n </Input.DescriptionAndValidation>\n </Input.Root>\n </div>\n\n <div role='none' className='space-b-2'>\n <Button\n type='submit'\n variant='primary'\n classNames='is-full flex gap-2'\n disabled={!canSubmit}\n onClick={handleSubmit}\n >\n <span>{translation('send feedback label')}</span>\n <div className='grow' />\n <PaperPlaneTilt className={getSize(5)} />\n </Button>\n <Popover.Close asChild>\n <Button classNames='is-full flex gap-2'>\n <span>{t('cancel label', { ns: 'os' })}</span>\n <div className='grow' />\n <X className={getSize(5)} />\n </Button>\n </Popover.Close>\n </div>\n </div>\n );\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type useTranslation } from '@dxos/react-ui';\n\nimport { STATUS_BAR_PLUGIN } from './meta';\n\ntype StatusBarTranslationKeys =\n | 'plugin name'\n | 'email input label'\n | 'email input placeholder'\n | 'feedback text area label'\n | 'feedback text area placeholder'\n | 'send feedback label'\n | 'name label'\n | 'name placeholder';\n\ntype RequiredTranslation = { [key in StatusBarTranslationKeys]: string };\ntype TranslationEntry = { [STATUS_BAR_PLUGIN]: RequiredTranslation };\ntype Language = string;\n\n// -- helpers.\nconst entry = (translation: RequiredTranslation): TranslationEntry => ({ [STATUS_BAR_PLUGIN]: translation });\nexport const mkTranslation = (t: ReturnType<typeof useTranslation>['t']) => (key: StatusBarTranslationKeys) => t(key);\n\nconst translations: Record<Language, TranslationEntry> = {\n 'en-US': entry({\n 'plugin name': 'Status Bar',\n 'name label': 'Name',\n 'name placeholder': 'Preferred name',\n 'email input label': 'Email',\n 'email input placeholder': 'hello@example.com',\n 'feedback text area label': 'Feedback',\n 'feedback text area placeholder': 'Found a bug? Have a suggestion? Let us know!',\n 'send feedback label': 'Send Feedback',\n }),\n};\n\nexport default [translations];\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { StatusBarPlugin } from './StatusBarPlugin';\n\nexport default StatusBarPlugin;\n\nexport * from './StatusBarPlugin';\nexport * from './components';\n"],
5
+ "mappings": "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",
6
+ "names": ["React", "useFocusableGroup", "Slot", "React", "forwardRef", "mx", "StatusBarText", "forwardRef", "classNames", "children", "forwardedRef", "span", "className", "mx", "ref", "StatusBarButton", "asChild", "props", "classes", "Slot", "role", "button", "StatusBarItem", "forwardRef", "classNames", "children", "props", "forwardedRef", "div", "role", "className", "mx", "ref", "StatusBarContainer", "groupAttrs", "useFocusableGroup", "tabBehavior", "tabIndex", "StartContent", "EndContent", "StatusBar", "Container", "Text", "StatusBarText", "Item", "Button", "StatusBarButton", "React", "useState", "Surface", "Icon", "Popover", "Schema", "S", "PaperPlaneTilt", "X", "React", "useCallback", "useIntentDispatcher", "Button", "Input", "Popover", "useTranslation", "useForm", "getSize", "entry", "translation", "STATUS_BAR_PLUGIN", "mkTranslation", "t", "key", "translations", "Email", "S", "String", "pipe", "nonEmptyString", "message", "pattern", "nonEmpty", "field", "maxLength", "length", "FeedbackFormSchema", "Struct", "name", "email", "initialValues", "FeedbackForm", "onClose", "t", "useTranslation", "STATUS_BAR_PLUGIN", "translation", "mkTranslation", "dispatch", "useIntentDispatcher", "onSubmit", "useCallback", "values", "action", "data", "errors", "handleSubmit", "canSubmit", "touched", "getInputProps", "useForm", "schema", "React", "div", "role", "className", "Input", "Root", "validationValence", "undefined", "Label", "TextInput", "classNames", "placeholder", "autoFocus", "DescriptionAndValidation", "Validation", "TextArea", "rows", "cols", "Button", "type", "variant", "disabled", "onClick", "span", "PaperPlaneTilt", "getSize", "Popover", "Close", "asChild", "ns", "X", "StatusBarPanel", "open", "setOpen", "useState", "React", "Popover", "Root", "onOpenChange", "StatusBar", "Container", "EndContent", "Trigger", "asChild", "Button", "aria-label", "data-joyride", "Icon", "icon", "size", "Text", "classNames", "a", "href", "target", "rel", "Surface", "role", "Content", "FeedbackForm", "onClose", "Arrow", "StatusBarPlugin", "meta", "provides", "translations", "surface", "component", "role", "React", "StatusBarPanel", "StatusBarPlugin"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/plugins/plugin-status-bar/src/components/StatusBar.tsx":{"bytes":9929,"imports":[{"path":"@fluentui/react-tabster","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true}],"format":"esm"},"packages/plugins/plugin-status-bar/src/hooks/useForm.ts":{"bytes":12439,"imports":[{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"packages/plugins/plugin-status-bar/src/hooks/index.ts":{"bytes":511,"imports":[{"path":"packages/plugins/plugin-status-bar/src/hooks/useForm.ts","kind":"import-statement","original":"./useForm"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/meta.ts":{"bytes":1252,"imports":[],"format":"esm"},"packages/plugins/plugin-status-bar/src/translations.ts":{"bytes":3385,"imports":[{"path":"packages/plugins/plugin-status-bar/src/meta.ts","kind":"import-statement","original":"./meta"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/util/validation.ts":{"bytes":2755,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true}],"format":"esm"},"packages/plugins/plugin-status-bar/src/util/index.ts":{"bytes":517,"imports":[{"path":"packages/plugins/plugin-status-bar/src/util/validation.ts","kind":"import-statement","original":"./validation"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/components/FeedbackForm.tsx":{"bytes":16845,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"packages/plugins/plugin-status-bar/src/hooks/index.ts","kind":"import-statement","original":"../hooks"},{"path":"packages/plugins/plugin-status-bar/src/meta.ts","kind":"import-statement","original":"../meta"},{"path":"packages/plugins/plugin-status-bar/src/translations.ts","kind":"import-statement","original":"../translations"},{"path":"packages/plugins/plugin-status-bar/src/util/index.ts","kind":"import-statement","original":"../util"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/components/StatusBarPanel.tsx":{"bytes":6006,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"packages/plugins/plugin-status-bar/src/components/FeedbackForm.tsx","kind":"import-statement","original":"./FeedbackForm"},{"path":"packages/plugins/plugin-status-bar/src/components/StatusBar.tsx","kind":"import-statement","original":"./StatusBar"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/components/index.ts":{"bytes":624,"imports":[{"path":"packages/plugins/plugin-status-bar/src/components/StatusBar.tsx","kind":"import-statement","original":"./StatusBar"},{"path":"packages/plugins/plugin-status-bar/src/components/StatusBarPanel.tsx","kind":"import-statement","original":"./StatusBarPanel"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/StatusBarPlugin.tsx":{"bytes":2663,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"packages/plugins/plugin-status-bar/src/components/index.ts","kind":"import-statement","original":"./components"},{"path":"packages/plugins/plugin-status-bar/src/meta.ts","kind":"import-statement","original":"./meta"},{"path":"packages/plugins/plugin-status-bar/src/translations.ts","kind":"import-statement","original":"./translations"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/index.ts":{"bytes":916,"imports":[{"path":"packages/plugins/plugin-status-bar/src/StatusBarPlugin.tsx","kind":"import-statement","original":"./StatusBarPlugin"},{"path":"packages/plugins/plugin-status-bar/src/StatusBarPlugin.tsx","kind":"import-statement","original":"./StatusBarPlugin"},{"path":"packages/plugins/plugin-status-bar/src/components/index.ts","kind":"import-statement","original":"./components"}],"format":"esm"}},"outputs":{"packages/plugins/plugin-status-bar/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":28210},"packages/plugins/plugin-status-bar/dist/lib/browser/index.mjs":{"imports":[{"path":"packages/plugins/plugin-status-bar/dist/lib/browser/chunk-4KDZC7WS.mjs","kind":"import-statement"},{"path":"react","kind":"import-statement","external":true},{"path":"@fluentui/react-tabster","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"effect","kind":"import-statement","external":true}],"exports":["StatusBar","StatusBarPanel","StatusBarPlugin","default"],"entryPoint":"packages/plugins/plugin-status-bar/src/index.ts","inputs":{"packages/plugins/plugin-status-bar/src/StatusBarPlugin.tsx":{"bytesInOutput":424},"packages/plugins/plugin-status-bar/src/components/StatusBar.tsx":{"bytesInOutput":2478},"packages/plugins/plugin-status-bar/src/components/index.ts":{"bytesInOutput":0},"packages/plugins/plugin-status-bar/src/components/StatusBarPanel.tsx":{"bytesInOutput":1706},"packages/plugins/plugin-status-bar/src/components/FeedbackForm.tsx":{"bytesInOutput":4762},"packages/plugins/plugin-status-bar/src/hooks/useForm.ts":{"bytesInOutput":2228},"packages/plugins/plugin-status-bar/src/hooks/index.ts":{"bytesInOutput":0},"packages/plugins/plugin-status-bar/src/translations.ts":{"bytesInOutput":570},"packages/plugins/plugin-status-bar/src/util/validation.ts":{"bytesInOutput":471},"packages/plugins/plugin-status-bar/src/util/index.ts":{"bytesInOutput":0},"packages/plugins/plugin-status-bar/src/index.ts":{"bytesInOutput":35}},"bytes":13587},"packages/plugins/plugin-status-bar/dist/lib/browser/meta.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":93},"packages/plugins/plugin-status-bar/dist/lib/browser/meta.mjs":{"imports":[{"path":"packages/plugins/plugin-status-bar/dist/lib/browser/chunk-4KDZC7WS.mjs","kind":"import-statement"}],"exports":["STATUS_BAR_PLUGIN","default"],"entryPoint":"packages/plugins/plugin-status-bar/src/meta.ts","inputs":{},"bytes":169},"packages/plugins/plugin-status-bar/dist/lib/browser/chunk-4KDZC7WS.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":600},"packages/plugins/plugin-status-bar/dist/lib/browser/chunk-4KDZC7WS.mjs":{"imports":[],"exports":["STATUS_BAR_PLUGIN","meta_default"],"inputs":{"packages/plugins/plugin-status-bar/src/meta.ts":{"bytesInOutput":210}},"bytes":353}}}
1
+ {"inputs":{"packages/plugins/plugin-status-bar/src/components/StatusBar.tsx":{"bytes":9929,"imports":[{"path":"@fluentui/react-tabster","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true}],"format":"esm"},"packages/plugins/plugin-status-bar/src/meta.ts":{"bytes":1252,"imports":[],"format":"esm"},"packages/plugins/plugin-status-bar/src/translations.ts":{"bytes":3385,"imports":[{"path":"packages/plugins/plugin-status-bar/src/meta.ts","kind":"import-statement","original":"./meta"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/components/FeedbackForm.tsx":{"bytes":16534,"imports":[{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-data","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"packages/plugins/plugin-status-bar/src/meta.ts","kind":"import-statement","original":"../meta"},{"path":"packages/plugins/plugin-status-bar/src/translations.ts","kind":"import-statement","original":"../translations"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/components/StatusBarPanel.tsx":{"bytes":6006,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"packages/plugins/plugin-status-bar/src/components/FeedbackForm.tsx","kind":"import-statement","original":"./FeedbackForm"},{"path":"packages/plugins/plugin-status-bar/src/components/StatusBar.tsx","kind":"import-statement","original":"./StatusBar"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/components/index.ts":{"bytes":624,"imports":[{"path":"packages/plugins/plugin-status-bar/src/components/StatusBar.tsx","kind":"import-statement","original":"./StatusBar"},{"path":"packages/plugins/plugin-status-bar/src/components/StatusBarPanel.tsx","kind":"import-statement","original":"./StatusBarPanel"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/StatusBarPlugin.tsx":{"bytes":2663,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"packages/plugins/plugin-status-bar/src/components/index.ts","kind":"import-statement","original":"./components"},{"path":"packages/plugins/plugin-status-bar/src/meta.ts","kind":"import-statement","original":"./meta"},{"path":"packages/plugins/plugin-status-bar/src/translations.ts","kind":"import-statement","original":"./translations"}],"format":"esm"},"packages/plugins/plugin-status-bar/src/index.ts":{"bytes":916,"imports":[{"path":"packages/plugins/plugin-status-bar/src/StatusBarPlugin.tsx","kind":"import-statement","original":"./StatusBarPlugin"},{"path":"packages/plugins/plugin-status-bar/src/StatusBarPlugin.tsx","kind":"import-statement","original":"./StatusBarPlugin"},{"path":"packages/plugins/plugin-status-bar/src/components/index.ts","kind":"import-statement","original":"./components"}],"format":"esm"}},"outputs":{"packages/plugins/plugin-status-bar/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":20348},"packages/plugins/plugin-status-bar/dist/lib/browser/index.mjs":{"imports":[{"path":"packages/plugins/plugin-status-bar/dist/lib/browser/chunk-4KDZC7WS.mjs","kind":"import-statement"},{"path":"react","kind":"import-statement","external":true},{"path":"@fluentui/react-tabster","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@effect/schema","kind":"import-statement","external":true},{"path":"@phosphor-icons/react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-data","kind":"import-statement","external":true},{"path":"@dxos/react-ui-theme","kind":"import-statement","external":true}],"exports":["StatusBar","StatusBarPanel","StatusBarPlugin","default"],"entryPoint":"packages/plugins/plugin-status-bar/src/index.ts","inputs":{"packages/plugins/plugin-status-bar/src/StatusBarPlugin.tsx":{"bytesInOutput":424},"packages/plugins/plugin-status-bar/src/components/StatusBar.tsx":{"bytesInOutput":2478},"packages/plugins/plugin-status-bar/src/components/index.ts":{"bytesInOutput":0},"packages/plugins/plugin-status-bar/src/components/StatusBarPanel.tsx":{"bytesInOutput":1692},"packages/plugins/plugin-status-bar/src/components/FeedbackForm.tsx":{"bytesInOutput":4721},"packages/plugins/plugin-status-bar/src/translations.ts":{"bytesInOutput":570},"packages/plugins/plugin-status-bar/src/index.ts":{"bytesInOutput":35}},"bytes":10711},"packages/plugins/plugin-status-bar/dist/lib/browser/meta.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":93},"packages/plugins/plugin-status-bar/dist/lib/browser/meta.mjs":{"imports":[{"path":"packages/plugins/plugin-status-bar/dist/lib/browser/chunk-4KDZC7WS.mjs","kind":"import-statement"}],"exports":["STATUS_BAR_PLUGIN","default"],"entryPoint":"packages/plugins/plugin-status-bar/src/meta.ts","inputs":{},"bytes":169},"packages/plugins/plugin-status-bar/dist/lib/browser/chunk-4KDZC7WS.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":600},"packages/plugins/plugin-status-bar/dist/lib/browser/chunk-4KDZC7WS.mjs":{"imports":[],"exports":["STATUS_BAR_PLUGIN","meta_default"],"inputs":{"packages/plugins/plugin-status-bar/src/meta.ts":{"bytesInOutput":210}},"bytes":353}}}
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackForm.d.ts","sourceRoot":"","sources":["../../../../src/components/FeedbackForm.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAsB,MAAM,OAAO,CAAC;AAgC3C,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":"AAMA,OAAO,KAAsB,MAAM,OAAO,CAAC;AA+B3C,eAAO,MAAM,YAAY,gBAAiB;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,sBAwFhE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-status-bar",
3
- "version": "0.6.14-main.f49f251",
3
+ "version": "0.6.14-staging.e15392e",
4
4
  "description": "Status bar plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -36,9 +36,10 @@
36
36
  "@radix-ui/react-slot": "^1.0.1",
37
37
  "effect": "^3.9.1",
38
38
  "react-resize-detector": "^11.0.1",
39
- "@dxos/app-framework": "0.6.14-main.f49f251",
40
- "@dxos/async": "0.6.14-main.f49f251",
41
- "@dxos/echo-schema": "0.6.14-main.f49f251"
39
+ "@dxos/async": "0.6.14-staging.e15392e",
40
+ "@dxos/echo-schema": "0.6.14-staging.e15392e",
41
+ "@dxos/react-ui-data": "0.6.14-staging.e15392e",
42
+ "@dxos/app-framework": "0.6.14-staging.e15392e"
42
43
  },
43
44
  "devDependencies": {
44
45
  "@phosphor-icons/react": "^2.1.5",
@@ -47,16 +48,16 @@
47
48
  "react": "~18.2.0",
48
49
  "react-dom": "~18.2.0",
49
50
  "vite": "5.4.7",
50
- "@dxos/react-ui": "0.6.14-main.f49f251",
51
- "@dxos/react-ui-theme": "0.6.14-main.f49f251",
52
- "@dxos/storybook-utils": "0.6.14-main.f49f251"
51
+ "@dxos/react-ui-theme": "0.6.14-staging.e15392e",
52
+ "@dxos/react-ui": "0.6.14-staging.e15392e",
53
+ "@dxos/storybook-utils": "0.6.14-staging.e15392e"
53
54
  },
54
55
  "peerDependencies": {
55
56
  "@phosphor-icons/react": "^2.0.5",
56
57
  "react": "~18.2.0",
57
58
  "react-dom": "~18.2.0",
58
- "@dxos/react-ui-theme": "0.6.14-main.f49f251",
59
- "@dxos/react-ui": "0.6.14-main.f49f251"
59
+ "@dxos/react-ui-theme": "0.6.14-staging.e15392e",
60
+ "@dxos/react-ui": "0.6.14-staging.e15392e"
60
61
  },
61
62
  "publishConfig": {
62
63
  "access": "public"
@@ -3,17 +3,16 @@
3
3
  //
4
4
 
5
5
  import { Schema as S } from '@effect/schema';
6
- import { X, PaperPlaneTilt } from '@phosphor-icons/react';
6
+ import { PaperPlaneTilt, X } from '@phosphor-icons/react';
7
7
  import React, { useCallback } from 'react';
8
8
 
9
9
  import { useIntentDispatcher } from '@dxos/app-framework';
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
18
  S.nonEmptyString({ message: () => 'Email is required.' }),
@@ -51,8 +50,8 @@ export const FeedbackForm = ({ onClose }: { onClose: () => void }) => {
51
50
 
52
51
  const { errors, handleSubmit, canSubmit, touched, getInputProps } = useForm<FeedbackFormState>({
53
52
  initialValues,
54
- validate: (values) => validate(FeedbackFormSchema, values),
55
- onSubmit: (values) => onSubmit(values),
53
+ schema: FeedbackFormSchema,
54
+ onSubmit,
56
55
  });
57
56
 
58
57
  return (
@@ -1,2 +0,0 @@
1
- export * from './useForm';
2
- //# sourceMappingURL=index.d.ts.map
@@ -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, type FocusEvent } 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: 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: 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":"AAIA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAyB,MAAM,OAAO,CAAC;AAEjF,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,UAAU,CAAC,gBAAgB,GAAG,mBAAmB,CAAC;yBAtBjD,CAAC;yBAiDJ,MAAM,CAAC;;;0BAvCL,WAAW,CAAC,gBAAgB,GAAG,mBAAmB,CAAC;wBAYnD,UAAU,CAAC,gBAAgB,GAAG,mBAAmB,CAAC;;;CAgD7D,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './validation';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/util/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC"}
@@ -1,7 +0,0 @@
1
- import { Schema as S } from '@effect/schema';
2
- export type ValidationError = {
3
- path: string;
4
- message: string;
5
- };
6
- export declare const validate: <T>(schema: S.Schema<T>, data: any) => ValidationError[] | undefined;
7
- //# sourceMappingURL=validation.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../../src/util/validation.ts"],"names":[],"mappings":"AAIA,OAAO,EAAkB,MAAM,IAAI,CAAC,EAAE,MAAM,gBAAgB,CAAC;AAG7D,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"}
@@ -1,5 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- export * from './useForm';
@@ -1,120 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { type ChangeEvent, type FocusEvent, useCallback, useState } from 'react';
6
-
7
- import { type ValidationError } from '../util';
8
-
9
- // TODO(Zan): This module will be generally useful and we should factor it out after the
10
- // API crystallizes a bit more.
11
-
12
- interface FormOptions<T> {
13
- initialValues: T;
14
- validate: (values: any) => ValidationError[] | undefined;
15
- onSubmit: (values: T) => void;
16
- }
17
-
18
- /**
19
- * Creates a hook for managing form state, including values, validation, and submission.
20
- *
21
- * @example
22
- * const { values, handleChange, handleSubmit, errors, canSubmit, getInputProps } = useForm({
23
- * initialValues: { name: '', email: '' },
24
- * validate: (values) => { yourValidationLogic(values); },
25
- * onSubmit: (values) => { submissionLogic(values); },
26
- * });
27
- */
28
- export const useForm = <T extends object>({ initialValues, validate, onSubmit }: FormOptions<T>) => {
29
- const [values, setValues] = useState<T>(initialValues);
30
- const [errors, setErrors] = useState<Record<keyof T, string>>({} as Record<keyof T, string>);
31
- const [touched, setTouched] = useState<Record<keyof T, boolean>>(
32
- Object.keys(initialValues).reduce((acc, key) => ({ ...acc, [key]: false }), {} as Record<keyof T, boolean>),
33
- );
34
-
35
- const runValidation = useCallback(
36
- (values: T) => {
37
- const validationErrors = validate(values);
38
- setErrors(collapseErrorArray(validationErrors ?? []));
39
-
40
- return validationErrors === undefined;
41
- },
42
- [validate],
43
- );
44
-
45
- const handleChange = useCallback(
46
- (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
47
- const { name, value } = event.target;
48
- const newValues = { ...values, [name]: value };
49
- setValues(newValues);
50
- runValidation(newValues);
51
- },
52
- [values, runValidation],
53
- );
54
-
55
- const touchAll = useCallback(() => setTouched(mkAllTouched(values)), [values, setTouched]);
56
-
57
- const handleBlur = useCallback(
58
- (event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => {
59
- const { name } = event.target;
60
- setTouched((touched) => ({ ...touched, [name]: true }));
61
-
62
- // TODO(Zan): This should be configurable behavior.
63
- if (event.relatedTarget?.getAttribute('type') === 'submit') {
64
- // NOTE: We do this here instead of onSubmit, because the blur event is triggered before the submit event
65
- // and results in the submit button being disabled when the form is invalid.
66
- touchAll();
67
- }
68
-
69
- runValidation(values);
70
- },
71
- [runValidation, values, touchAll],
72
- );
73
-
74
- const handleSubmit = useCallback(() => {
75
- if (runValidation(values)) {
76
- onSubmit(values);
77
- }
78
- }, [values, runValidation, onSubmit]);
79
-
80
- // NOTE: We can submit if there is no touched field that has an error.
81
- // - Basically, if there's a validation message present in the form, submit should be disabled.
82
- const canSubmit = Object.keys(values).every((key) => touched[key as keyof T] === false || !errors[key as keyof T]);
83
-
84
- const getInputProps = useCallback(
85
- (key: keyof T) => ({
86
- name: key,
87
- value: values[key],
88
- onChange: handleChange,
89
- onBlur: handleBlur,
90
- 'aria-invalid': errors[key] !== undefined,
91
- }),
92
- [values, handleChange, handleBlur, errors],
93
- );
94
-
95
- return {
96
- values,
97
- handleChange,
98
- handleSubmit,
99
- errors,
100
- canSubmit,
101
- touched,
102
- handleBlur,
103
- onValidate: runValidation,
104
- getInputProps,
105
- };
106
- };
107
-
108
- const mkAllTouched = <T extends Record<keyof T, any>>(values: T) => {
109
- return Object.keys(values).reduce((acc, key) => ({ ...acc, [key]: true }), {} as Record<keyof T, boolean>);
110
- };
111
-
112
- const collapseErrorArray = <T>(errors: ValidationError[]) =>
113
- errors.reduce(
114
- (acc, { path, message }) => {
115
- // TODO(Zan): This won't play well with nesting.
116
- acc[path as keyof T] = message;
117
- return acc;
118
- },
119
- {} as Record<keyof T, string>,
120
- );
package/src/util/index.ts DELETED
@@ -1,5 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- export * from './validation';
@@ -1,21 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { ArrayFormatter, Schema as S } from '@effect/schema';
6
- import { Effect } from 'effect';
7
-
8
- export type ValidationError = { path: string; message: string };
9
-
10
- export const validate = <T>(schema: S.Schema<T>, data: any): ValidationError[] | undefined => {
11
- const validator = S.decodeUnknownEither(schema, { errors: 'all' });
12
- const result = validator(data);
13
-
14
- if (result._tag === 'Left') {
15
- const errors = Effect.runSync(ArrayFormatter.formatError(result.left));
16
- // TODO(Zan): Path.join is an assumption...
17
- return errors.map(({ message, path }) => ({ message, path: path.join('.') }));
18
- }
19
-
20
- return undefined;
21
- };