tycho-components 0.33.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ import { type TextareaHTMLAttributes } from 'react';
2
+ import './style.scss';
3
+ export type AppTextAreaProps = TextareaHTMLAttributes<HTMLTextAreaElement> & {
4
+ showLineNumbers?: boolean;
5
+ containerClassName?: string;
6
+ };
7
+ declare const AppTextArea: import("react").ForwardRefExoticComponent<TextareaHTMLAttributes<HTMLTextAreaElement> & {
8
+ showLineNumbers?: boolean;
9
+ containerClassName?: string;
10
+ } & import("react").RefAttributes<HTMLTextAreaElement>>;
11
+ export default AppTextArea;
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import cx from 'classnames';
3
+ import { forwardRef, useCallback, useRef, } from 'react';
4
+ import './style.scss';
5
+ const AppTextArea = forwardRef(function AppTextArea({ showLineNumbers = false, containerClassName, className, value, defaultValue, onScroll, ...rest }, ref) {
6
+ const gutterRef = useRef(null);
7
+ const setTextareaRef = useCallback((node) => {
8
+ if (typeof ref === 'function') {
9
+ ref(node);
10
+ }
11
+ else if (ref) {
12
+ ref.current = node;
13
+ }
14
+ }, [ref]);
15
+ const textValue = value !== undefined
16
+ ? String(value)
17
+ : defaultValue !== undefined
18
+ ? String(defaultValue)
19
+ : '';
20
+ const lines = Math.max(textValue.split('\n').length, 1);
21
+ const handleScroll = (e) => {
22
+ if (gutterRef.current) {
23
+ gutterRef.current.scrollTop = e.currentTarget.scrollTop;
24
+ }
25
+ onScroll?.(e);
26
+ };
27
+ return (_jsxs("div", { className: cx('app-text-area', { 'app-text-area--numbered': showLineNumbers }, containerClassName), children: [showLineNumbers && (_jsx("div", { className: "app-text-area__gutter", "aria-hidden": true, ref: gutterRef, children: Array.from({ length: lines }, (_, i) => (_jsx("div", { children: i + 1 }, i))) })), _jsx("textarea", { ref: setTextareaRef, className: cx('app-text-area__input', className), value: value, defaultValue: defaultValue, onScroll: handleScroll, ...rest })] }));
28
+ });
29
+ export default AppTextArea;
@@ -0,0 +1 @@
1
+ export { default, type AppTextAreaProps } from './AppTextArea';
@@ -0,0 +1 @@
1
+ export { default } from './AppTextArea';
@@ -0,0 +1,47 @@
1
+ .app-text-area {
2
+ display: flex;
3
+ width: 100%;
4
+ height: 100%;
5
+ box-sizing: border-box;
6
+
7
+ &__input {
8
+ box-sizing: border-box;
9
+ display: block;
10
+ width: 100%;
11
+ height: 100%;
12
+ margin: 0;
13
+ padding: var(--spacing-200);
14
+ border: 0;
15
+ outline: 0;
16
+ resize: none;
17
+ background: transparent;
18
+ @include body-medium-1;
19
+ font-family: var(--font-family);
20
+ }
21
+
22
+ &--numbered {
23
+ font-family: monospace;
24
+
25
+ .app-text-area__gutter,
26
+ .app-text-area__input {
27
+ @include body-medium-1;
28
+ font-family: monospace;
29
+ line-height: 150%;
30
+ }
31
+
32
+ .app-text-area__gutter {
33
+ flex-shrink: 0;
34
+ overflow: hidden;
35
+ padding: var(--spacing-200);
36
+ background-color: var(--layer-hover-2);
37
+ text-align: right;
38
+ user-select: none;
39
+ color: var(--text-secondary);
40
+ }
41
+
42
+ .app-text-area__input {
43
+ flex: 1;
44
+ min-width: 0;
45
+ }
46
+ }
47
+ }
@@ -30,6 +30,7 @@ export { EMPTY_GRID_PAGE, EMPTY_PAGE, isPageEmpty, } from './AppTable/types/AppP
30
30
  export type { AppPage } from './AppTable/types/AppPage';
31
31
  export { convertPageable, EMPTY_GRID_PAGEABLE, EMPTY_PAGEABLE, } from './AppTable/types/AppPageable';
32
32
  export type { AppPageable } from './AppTable/types/AppPageable';
33
+ export { default as AppTextArea, type AppTextAreaProps, } from './AppTextArea';
33
34
  export { default as AppToast } from './AppToast';
34
35
  export { default as AppCopyText } from './AppCopyText';
35
36
  export { default as AppConsent } from './AppConsent';
@@ -23,6 +23,7 @@ export { default as AppTable } from './AppTable';
23
23
  export { default as AppTableList } from './AppTable/AppTableList';
24
24
  export { EMPTY_GRID_PAGE, EMPTY_PAGE, isPageEmpty, } from './AppTable/types/AppPage';
25
25
  export { convertPageable, EMPTY_GRID_PAGEABLE, EMPTY_PAGEABLE, } from './AppTable/types/AppPageable';
26
+ export { default as AppTextArea, } from './AppTextArea';
26
27
  export { default as AppToast } from './AppToast';
27
28
  export { default as AppCopyText } from './AppCopyText';
28
29
  export { default as AppConsent } from './AppConsent';
@@ -5,6 +5,8 @@ export declare const useLoggedUtils: () => {
5
5
  isLogged: () => boolean;
6
6
  setLogged: (user: User | undefined) => void;
7
7
  isAdminOfAnyCorpus: () => boolean;
8
+ isEditorOfAnyCorpus: () => boolean;
9
+ canEditCorpus: (corpusUid: string) => boolean;
8
10
  hasLexiconAccess: (lexiconUid: string, roles?: string[]) => boolean;
9
11
  hasParserAccess: (parserUid: string, roles?: string[]) => boolean;
10
12
  hasCorpusAccess: (corpusUid: string, roles?: string[]) => boolean;
@@ -33,6 +33,14 @@ export const useLoggedUtils = () => {
33
33
  return false;
34
34
  return user.permissions.some((permission) => /^ROLE_ADMIN_CORPUS_[\w-]+$/.test(permission));
35
35
  };
36
+ const isEditorOfAnyCorpus = () => {
37
+ if (isSuper())
38
+ return true;
39
+ const user = getLogged();
40
+ if (!user || !user.permissions)
41
+ return false;
42
+ return user.permissions.some((permission) => /^ROLE_(ADMIN|EDITOR)_CORPUS_[\w-]+$/.test(permission));
43
+ };
36
44
  const hasParserAccess = (parserUid, roles) => {
37
45
  if (isSuper())
38
46
  return true;
@@ -63,6 +71,9 @@ export const useLoggedUtils = () => {
63
71
  const re = new RegExp(`^ROLE_${roleSegmentForRegex(roles)}_CORPUS_${id}$`);
64
72
  return user.permissions.some((permission) => re.test(permission));
65
73
  };
74
+ const canEditCorpus = (corpusUid) => {
75
+ return hasCorpusAccess(corpusUid, ['ADMIN', 'EDITOR']);
76
+ };
66
77
  const hasAnyParserAccess = () => {
67
78
  if (isSuper())
68
79
  return true;
@@ -93,6 +104,8 @@ export const useLoggedUtils = () => {
93
104
  isLogged,
94
105
  setLogged,
95
106
  isAdminOfAnyCorpus,
107
+ isEditorOfAnyCorpus,
108
+ canEditCorpus,
96
109
  hasLexiconAccess,
97
110
  hasParserAccess,
98
111
  hasCorpusAccess,
@@ -14,7 +14,7 @@ import "./style.scss";
14
14
  export default function HeaderApps({ navigateLogout, navigateNotLogged, hideKeyboard, notifications, keyboardLayout, helpActions, }) {
15
15
  const { t } = useTranslation("header-app");
16
16
  const { getCorpus, hasCorpus } = useCorpusUtils();
17
- const { isAdminOfAnyCorpus, isLogged } = useLoggedUtils();
17
+ const { isAdminOfAnyCorpus, isEditorOfAnyCorpus, isLogged } = useLoggedUtils();
18
18
  const [open, setOpen] = useState(false);
19
19
  const goto = (app, blank) => {
20
20
  const shouldAppendCorpusUid = app.appendCorpusUid !== false;
@@ -33,6 +33,8 @@ export default function HeaderApps({ navigateLogout, navigateNotLogged, hideKeyb
33
33
  return null;
34
34
  if (item.admin && !isAdminOfAnyCorpus())
35
35
  return null;
36
+ if (item.editor && !isEditorOfAnyCorpus())
37
+ return null;
36
38
  return (_jsxs("div", { className: "item", title: t(`${item.code}.desc`), onClick: () => goto(item, item.external ? true : false), children: [item.icon && _jsx(Icon, { name: item.icon, size: "medium" }), item.image && _jsx("img", { src: item.image }), _jsx("span", { className: "title-app", children: t(`${item.code}.name`) }), _jsxs("div", { className: "options", children: [item.visibility && (_jsx(Tag, { text: t(`common:label.${item.visibility}`), size: "small", color: "green", className: "d-none" })), _jsx(IconButton, { name: "open_in_new", size: "x-small", className: "icon-open", mode: "ghost", onClick: (e) => {
37
39
  e.stopPropagation();
38
40
  goto(item, true);
@@ -4,6 +4,7 @@ type App = {
4
4
  image?: string;
5
5
  visibility: 'public' | 'private';
6
6
  admin?: boolean;
7
+ editor?: boolean;
7
8
  lexicon?: boolean;
8
9
  parser?: boolean;
9
10
  external?: string;
@@ -33,6 +33,7 @@ export const AvailableApps = [
33
33
  code: 'io',
34
34
  icon: 'swap_vert',
35
35
  visibility: 'private',
36
+ editor: true,
36
37
  },
37
38
  {
38
39
  code: 'viewer',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tycho-components",
3
3
  "private": false,
4
- "version": "0.33.0",
4
+ "version": "0.34.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -60,7 +60,7 @@
60
60
  "file-saver": "^2.0.5",
61
61
  "html2canvas": "^1.4.1",
62
62
  "js-cookie": "^3.0.5",
63
- "react-colorful": "^5.6.1",
63
+ "react-colorful": "^5.8.0",
64
64
  "react-draggable": "^4.4.6",
65
65
  "react-dropzone": "^14.3.5",
66
66
  "react-easy-edit": "^2.0.0",
@@ -82,7 +82,7 @@
82
82
  "react-i18next": "^13.0.2",
83
83
  "react-router-dom": "^6.14.2",
84
84
  "react-toastify": "^9.1.3",
85
- "tycho-storybook": "0.10.7",
85
+ "tycho-storybook": "0.10.8",
86
86
  "wavesurfer-react": "^2.2.2",
87
87
  "wavesurfer.js": "^6.6.3"
88
88
  },