@laser-ui/components 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
4
4
 
5
+ ## [0.6.1](https://github.com/laser-ui/laser-ui/compare/v0.6.0...v0.6.1) (2024-04-26)
6
+
7
+ **Note:** Version bump only for package @laser-ui/components
8
+
9
+ # [0.6.0](https://github.com/laser-ui/laser-ui/compare/v0.5.0...v0.6.0) (2024-03-06)
10
+
11
+ ### Bug Fixes
12
+
13
+ - **components:** menu init focus only pressing the tab key ([b72b64a](https://github.com/laser-ui/laser-ui/commit/b72b64a4c5d012065debba7903e40e3808c91764))
14
+
5
15
  # [0.5.0](https://github.com/laser-ui/laser-ui/compare/v0.4.1...v0.5.0) (2024-01-31)
6
16
 
7
17
  ### Features
@@ -0,0 +1,17 @@
1
+ /// <reference types="react" />
2
+ export interface DialogInstance<P extends object> {
3
+ key: string | number;
4
+ node: React.FunctionComponentElement<P>;
5
+ close: () => void;
6
+ rerender: (props: P) => void;
7
+ }
8
+ export declare class DialogService {
9
+ private _key;
10
+ private _dialogs;
11
+ private _emitChange;
12
+ constructor(emitChange: (dialogs: DialogInstance<any>[]) => void);
13
+ open<P extends object>(type: React.FC<P>, props: Omit<P, 'visible'>, key?: string | number): DialogInstance<P>;
14
+ close(key: string | number): void;
15
+ rerender(key: string | number, props: any): void;
16
+ closeAll(animation?: boolean): void;
17
+ }
@@ -0,0 +1,85 @@
1
+ import { cloneElement, createElement } from 'react';
2
+ export class DialogService {
3
+ constructor(emitChange) {
4
+ Object.defineProperty(this, "_key", {
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true,
8
+ value: -1
9
+ });
10
+ Object.defineProperty(this, "_dialogs", {
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true,
14
+ value: []
15
+ });
16
+ Object.defineProperty(this, "_emitChange", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: void 0
21
+ });
22
+ this._emitChange = () => {
23
+ emitChange([].concat(this._dialogs));
24
+ };
25
+ }
26
+ open(type, props, key) {
27
+ const dialogKey = key !== null && key !== void 0 ? key : `l_#${++this._key}`;
28
+ const dialogProps = Object.assign(Object.assign({}, props), { visible: true, skipFirstTransition: false, onClose: () => {
29
+ var _a, _b;
30
+ this.close(dialogKey);
31
+ (_b = (_a = props).onClose) === null || _b === void 0 ? void 0 : _b.call(_a);
32
+ }, afterVisibleChange: (visible) => {
33
+ var _a, _b;
34
+ (_b = (_a = props).afterVisibleChange) === null || _b === void 0 ? void 0 : _b.call(_a, visible);
35
+ if (!visible) {
36
+ const index = this._dialogs.findIndex((dialog) => dialog.key === dialogKey);
37
+ if (index !== -1) {
38
+ this._dialogs.splice(index, 1);
39
+ this._emitChange();
40
+ }
41
+ }
42
+ } });
43
+ const node = createElement(type, Object.assign({ key: dialogKey }, dialogProps));
44
+ const instance = {
45
+ key: dialogKey,
46
+ node,
47
+ close: () => {
48
+ this.close(dialogKey);
49
+ },
50
+ rerender: (props) => {
51
+ this.rerender(dialogKey, props);
52
+ },
53
+ };
54
+ this._dialogs.push(instance);
55
+ this._emitChange();
56
+ return instance;
57
+ }
58
+ close(key) {
59
+ const index = this._dialogs.findIndex((dialog) => dialog.key === key);
60
+ if (index !== -1) {
61
+ const instance = this._dialogs[index];
62
+ instance.node = cloneElement(instance.node, { visible: false });
63
+ this._emitChange();
64
+ }
65
+ }
66
+ rerender(key, props) {
67
+ const index = this._dialogs.findIndex((dialog) => dialog.key === key);
68
+ if (index !== -1) {
69
+ const instance = this._dialogs[index];
70
+ instance.node = cloneElement(instance.node, props);
71
+ this._emitChange();
72
+ }
73
+ }
74
+ closeAll(animation = true) {
75
+ if (animation) {
76
+ this._dialogs.forEach((dialog) => {
77
+ dialog.node = cloneElement(dialog.node, { visible: false });
78
+ });
79
+ }
80
+ else {
81
+ this._dialogs = [];
82
+ }
83
+ this._emitChange();
84
+ }
85
+ }
package/drawer/Drawer.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { __rest } from "tslib";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { isString, isUndefined } from 'lodash';
4
- import { cloneElement, useContext, useEffect, useId, useMemo, useRef } from 'react';
4
+ import { cloneElement, useCallback, useContext, useEffect, useId, useRef } from 'react';
5
5
  import { DrawerFooter } from './DrawerFooter';
6
6
  import { DrawerHeader } from './DrawerHeader';
7
7
  import { CLASSES, DrawerContext } from './vars';
@@ -17,6 +17,7 @@ export const Drawer = (props) => {
17
17
  const namespace = useNamespace();
18
18
  const styled = useStyled(CLASSES, { drawer: styleProvider === null || styleProvider === void 0 ? void 0 : styleProvider.drawer }, styleOverrides);
19
19
  const drawerRef = useRef(null);
20
+ const drawerContentRef = useRef(null);
20
21
  const dataRef = useRef({
21
22
  prevActiveEl: null,
22
23
  });
@@ -24,21 +25,8 @@ export const Drawer = (props) => {
24
25
  const titleId = `${namespace}-drawer-title-${uniqueId}`;
25
26
  const bodyId = `${namespace}-drawer-content-${uniqueId}`;
26
27
  const drawerContext = useContext(DrawerContext);
27
- const ancestryIds = [];
28
- if (visible) {
29
- drawerContext.forEach((ancestry) => {
30
- if (ancestry.placement === placement) {
31
- ancestryIds.push(ancestry.uniqueId);
32
- }
33
- });
34
- }
35
- const drawerContextValue = useMemo(() => drawerContext.concat({ uniqueId, placement }), [drawerContext, placement, uniqueId]);
36
- useEffect(() => {
37
- let offset = 0;
38
- document.querySelectorAll(`[data-l-drawer-ancestry~="${uniqueId}"]`).forEach((el) => {
39
- offset += placement === 'top' || placement === 'bottom' ? el.offsetHeight : el.offsetWidth;
40
- });
41
- offset = (offset / 3) * 2;
28
+ const drawerContextValue = useCallback((offsets) => {
29
+ const offset = (offsets[placement].reduce((v, r) => v + r, 0) / 3) * 2;
42
30
  if (drawerRef.current) {
43
31
  drawerRef.current.style.transform =
44
32
  placement === 'top'
@@ -49,7 +37,31 @@ export const Drawer = (props) => {
49
37
  ? `translateY(-${offset}px)`
50
38
  : `translateX(${offset}px)`;
51
39
  }
52
- });
40
+ if (drawerContentRef.current) {
41
+ drawerContext(Object.assign(Object.assign({}, offsets), { [placement]: [
42
+ placement === 'top' || placement === 'bottom' ? drawerContentRef.current.offsetHeight : drawerContentRef.current.offsetWidth,
43
+ ].concat(offsets[placement]) }));
44
+ }
45
+ }, [drawerContext, placement]);
46
+ const handleVisibleChange = (visible) => {
47
+ if (drawerContentRef.current) {
48
+ drawerContext(Object.assign({ top: [], right: [], bottom: [], left: [] }, {
49
+ [placement]: visible
50
+ ? [
51
+ placement === 'top' || placement === 'bottom'
52
+ ? drawerContentRef.current.offsetHeight
53
+ : drawerContentRef.current.offsetWidth,
54
+ ]
55
+ : [],
56
+ }));
57
+ }
58
+ };
59
+ useEffect(() => {
60
+ if (!visible) {
61
+ handleVisibleChange(false);
62
+ }
63
+ // eslint-disable-next-line react-hooks/exhaustive-deps
64
+ }, [visible]);
53
65
  const maxZIndex = useMaxIndex(visible);
54
66
  const zIndex = !isUndefined(zIndexProp)
55
67
  ? zIndexProp
@@ -98,7 +110,9 @@ export const Drawer = (props) => {
98
110
  }
99
111
  return el;
100
112
  }
101
- : container, children: _jsx(Transition, { enter: visible, during: TTANSITION_DURING_BASE, skipFirstTransition: skipFirstTransition, destroyWhenLeaved: destroyAfterClose, afterEnter: () => {
113
+ : container, children: _jsx(Transition, { enter: visible, during: TTANSITION_DURING_BASE, skipFirstTransition: skipFirstTransition, destroyWhenLeaved: destroyAfterClose, afterRender: () => {
114
+ handleVisibleChange(true);
115
+ }, afterEnter: () => {
102
116
  afterVisibleChange === null || afterVisibleChange === void 0 ? void 0 : afterVisibleChange(true);
103
117
  dataRef.current.prevActiveEl = document.activeElement;
104
118
  if (drawerRef.current) {
@@ -129,7 +143,7 @@ export const Drawer = (props) => {
129
143
  }
130
144
  } })), _jsxs("div", Object.assign({}, mergeCS(styled('drawer__content'), {
131
145
  style: Object.assign({ width: placement === 'left' || placement === 'right' ? width : undefined, height: placement === 'bottom' || placement === 'top' ? height : undefined }, transitionStyles[state]),
132
- }), { "data-l-drawer-ancestry": ancestryIds.join(' '), children: [headerNode, _jsx("div", Object.assign({}, styled('drawer__body'), { id: bodyId, children: _jsx(DrawerContext.Provider, { value: drawerContextValue, children: children }) })), footer &&
146
+ }), { ref: drawerContentRef, children: [headerNode, _jsx("div", Object.assign({}, styled('drawer__body'), { id: bodyId, children: _jsx(DrawerContext.Provider, { value: drawerContextValue, children: children }) })), footer &&
133
147
  cloneElement(footer, {
134
148
  _onClose: () => {
135
149
  onClose === null || onClose === void 0 ? void 0 : onClose();
package/drawer/types.d.ts CHANGED
@@ -34,3 +34,9 @@ export interface DrawerFooterProps extends BaseProps<'drawer', typeof CLASSES>,
34
34
  onCancelClick?: () => any | Promise<any>;
35
35
  onOkClick?: () => any | Promise<any>;
36
36
  }
37
+ export interface Offsets {
38
+ top: number[];
39
+ right: number[];
40
+ bottom: number[];
41
+ left: number[];
42
+ }
package/drawer/vars.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="react" />
2
+ import type { Offsets } from './types';
2
3
  export declare const CLASSES: {
3
4
  drawer: string;
4
5
  'drawer--top': string;
@@ -15,7 +16,4 @@ export declare const CLASSES: {
15
16
  'drawer__footer--center': string;
16
17
  'drawer__footer--right': string;
17
18
  };
18
- export declare const DrawerContext: import("react").Context<{
19
- uniqueId: string;
20
- placement: 'top' | 'right' | 'bottom' | 'left';
21
- }[]>;
19
+ export declare const DrawerContext: import("react").Context<(offsets: Offsets) => void>;
package/drawer/vars.js CHANGED
@@ -15,4 +15,4 @@ export const CLASSES = {
15
15
  'drawer__footer--center': '^drawer__footer--center',
16
16
  'drawer__footer--right': '^drawer__footer--right',
17
17
  };
18
- export const DrawerContext = createContext([]);
18
+ export const DrawerContext = createContext(() => { });
package/hooks/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { useComponentProps } from './useComponentProps';
2
2
  export { useControlled } from './useControlled';
3
3
  export { useDesign } from './useDesign';
4
+ export { useDialogService } from './useDialogService';
4
5
  export { useFocusVisible } from './useFocusVisible';
5
6
  export { useJSS } from './useJSS';
6
7
  export { useLayout } from './useLayout';
package/hooks/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { useComponentProps } from './useComponentProps';
2
2
  export { useControlled } from './useControlled';
3
3
  export { useDesign } from './useDesign';
4
+ export { useDialogService } from './useDialogService';
4
5
  export { useFocusVisible } from './useFocusVisible';
5
6
  export { useJSS } from './useJSS';
6
7
  export { useLayout } from './useLayout';
@@ -8,5 +8,5 @@ export declare function useDesign(opts: {
8
8
  }): {
9
9
  'data-l-compose-active': boolean | undefined;
10
10
  'data-l-compose-disabled': boolean | undefined;
11
- 'data-l-form-invalid': false | "error" | "warning" | undefined;
11
+ 'data-l-form-invalid': false | "warning" | "error" | undefined;
12
12
  };
@@ -0,0 +1,3 @@
1
+ import type { DialogInstance } from '../dialog-service';
2
+ import { DialogService } from '../dialog-service';
3
+ export declare function useDialogService(): readonly [DialogService, DialogInstance<any>[]];
@@ -0,0 +1,10 @@
1
+ import { useImmer } from '@laser-ui/hooks';
2
+ import { useMemo } from 'react';
3
+ import { DialogService } from '../dialog-service';
4
+ export function useDialogService() {
5
+ const [dialogs, setDialogs] = useImmer([]);
6
+ const service = useMemo(() => new DialogService((dialogs) => {
7
+ setDialogs(dialogs);
8
+ }), [setDialogs]);
9
+ return [service, dialogs];
10
+ }
package/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { useDialogService } from './hooks';
1
2
  export { Root, DialogService } from './root';
2
3
  export { ConfigProvider } from './config-provider';
3
4
  export { Accordion } from './accordion';
package/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export { useDialogService } from './hooks';
1
2
  export { Root, DialogService } from './root';
2
3
  export { ConfigProvider } from './config-provider';
3
4
  export { Accordion } from './accordion';
package/menu/Menu.js CHANGED
@@ -19,6 +19,7 @@ function MenuFC(props, ref) {
19
19
  const uniqueId = useId();
20
20
  const getItemId = (id) => `${namespace}-menu-item-${id}-${uniqueId}`;
21
21
  const dataRef = useRef({
22
+ mousedown: false,
22
23
  updatePosition: new Map(),
23
24
  });
24
25
  const [focusVisible, focusVisibleWrapper] = useFocusVisible((code) => code.startsWith('Arrow') || ['Home', 'End', 'Enter', 'Space'].includes(code));
@@ -356,7 +357,10 @@ function MenuFC(props, ref) {
356
357
  }), { ref: menuRef, tabIndex: (_a = restProps.tabIndex) !== null && _a !== void 0 ? _a : 0, role: "menubar", "aria-orientation": mode === 'horizontal' ? 'horizontal' : 'vertical', "aria-activedescendant": isUndefined(focusId) ? undefined : getItemId(focusId), onFocus: (e) => {
357
358
  var _a;
358
359
  (_a = restProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(restProps, e);
359
- initFocus();
360
+ if (!dataRef.current.mousedown) {
361
+ initFocus();
362
+ }
363
+ dataRef.current.mousedown = false;
360
364
  }, onBlur: (e) => {
361
365
  var _a;
362
366
  (_a = restProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(restProps, e);
@@ -375,6 +379,7 @@ function MenuFC(props, ref) {
375
379
  }, onMouseDown: (e) => {
376
380
  var _a;
377
381
  (_a = restProps.onMouseDown) === null || _a === void 0 ? void 0 : _a.call(restProps, e);
382
+ dataRef.current.mousedown = true;
378
383
  preventBlur(e);
379
384
  }, onMouseUp: (e) => {
380
385
  var _a;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laser-ui/components",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "React components.",
5
5
  "keywords": [
6
6
  "ui",
@@ -26,8 +26,8 @@
26
26
  "module": "./index.js",
27
27
  "types": "./index.d.ts",
28
28
  "dependencies": {
29
- "@laser-ui/hooks": "0.5.0",
30
- "@laser-ui/utils": "0.5.0",
29
+ "@laser-ui/hooks": "0.6.1",
30
+ "@laser-ui/utils": "0.6.1",
31
31
  "@material-design-icons/svg": "^0.14.12",
32
32
  "jss": "^10.10.0",
33
33
  "jss-preset-default": "^10.10.0",
@@ -36,14 +36,11 @@
36
36
  },
37
37
  "peerDependencies": {
38
38
  "dayjs": "^1.11.0",
39
- "immer": ">=2.0.0",
40
- "react": "^18.0.0",
41
- "react-dom": "^18.0.0",
42
- "tslib": "^2.0.0"
39
+ "immer": ">=2.0.0"
43
40
  },
44
41
  "publishConfig": {
45
42
  "access": "public",
46
43
  "directory": "../../dist/libs/components"
47
44
  },
48
- "gitHead": "0c9f6009f6ad197c8870046b52277485a5217747"
45
+ "gitHead": "156633eb28f7306ce633cea5bf5a094045aa4ad8"
49
46
  }
package/root/Root.js CHANGED
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useEvent, useRefExtra } from '@laser-ui/hooks';
3
3
  import { isString, set } from 'lodash';
4
4
  import { useStore } from 'rcl-store';
5
- import { createElement, useEffect, useMemo, useRef } from 'react';
5
+ import { useEffect, useMemo, useRef } from 'react';
6
6
  import { ROOT_DATA, RootContext, Store } from './vars';
7
7
  import dayjs from '../dayjs';
8
8
  import { Portal } from '../internal/portal';
@@ -84,5 +84,5 @@ export function Root(props) {
84
84
  default:
85
85
  break;
86
86
  }
87
- return (_jsxs(_Fragment, { children: [_jsxs(RootContext.Provider, { value: context, children: [children, dialogs.map(({ type, key, props }) => createElement(type, Object.assign({ key }, props)))] }), _jsx(Portal, { selector: () => document.body, children: _jsx(WindowSize, {}) })] }));
87
+ return (_jsxs(_Fragment, { children: [_jsxs(RootContext.Provider, { value: context, children: [children, dialogs.map(({ node }) => node)] }), _jsx(Portal, { selector: () => document.body, children: _jsx(WindowSize, {}) })] }));
88
88
  }
@@ -1,12 +1,2 @@
1
- /// <reference types="react" />
2
- export interface DialogInstance<P extends object> {
3
- key: string | number;
4
- close: () => void;
5
- rerender: (props: P) => void;
6
- }
7
- export declare class DialogService {
8
- static open<P extends object>(type: React.FC<P>, props: Omit<P, 'visible'>, key?: string | number): DialogInstance<P>;
9
- static close(key: string | number): void;
10
- static rerender(key: string | number, type: any, props: any): void;
11
- static closeAll(animation?: boolean): void;
12
- }
1
+ import { DialogService as InternalDialogService } from '../dialog-service';
2
+ export declare const DialogService: InternalDialogService;
@@ -1,66 +1,5 @@
1
1
  import { Store } from './vars';
2
- let _key = 0;
3
- export class DialogService {
4
- static open(type, props, key) {
5
- const dialogKey = key !== null && key !== void 0 ? key : ++_key;
6
- Store.set('dialogs', (draft) => {
7
- draft.push({
8
- key: dialogKey,
9
- type,
10
- props: Object.assign(Object.assign({}, props), { visible: true, skipFirstTransition: false, onClose: () => {
11
- var _a, _b;
12
- (_b = (_a = props).onClose) === null || _b === void 0 ? void 0 : _b.call(_a);
13
- DialogService.close(dialogKey);
14
- }, afterVisibleChange: (visible) => {
15
- var _a, _b;
16
- (_b = (_a = props).afterVisibleChange) === null || _b === void 0 ? void 0 : _b.call(_a, visible);
17
- if (!visible) {
18
- const index = Store.get('dialogs').findIndex((dialog) => dialog.key === dialogKey);
19
- if (index !== -1) {
20
- Store.set('dialogs', (draft) => {
21
- draft.splice(index, 1);
22
- });
23
- }
24
- }
25
- } }),
26
- });
27
- });
28
- return {
29
- key: dialogKey,
30
- close: () => {
31
- DialogService.close(dialogKey);
32
- },
33
- rerender: (props) => {
34
- DialogService.rerender(dialogKey, type, props);
35
- },
36
- };
37
- }
38
- static close(key) {
39
- const index = Store.get('dialogs').findIndex((dialog) => dialog.key === key);
40
- if (index !== -1) {
41
- Store.set('dialogs', (draft) => {
42
- draft[index].props.visible = false;
43
- });
44
- }
45
- }
46
- static rerender(key, type, props) {
47
- const index = Store.get('dialogs').findIndex((dialog) => dialog.key === key);
48
- if (index !== -1) {
49
- Store.set('dialogs', (draft) => {
50
- draft.splice(index, 1, { key, type, props: Object.assign(draft[index].props, props) });
51
- });
52
- }
53
- }
54
- static closeAll(animation = true) {
55
- if (animation) {
56
- Store.set('dialogs', (draft) => {
57
- draft.forEach((dialog) => {
58
- dialog.props.visible = false;
59
- });
60
- });
61
- }
62
- else {
63
- Store.set('dialogs', []);
64
- }
65
- }
66
- }
2
+ import { DialogService as InternalDialogService } from '../dialog-service';
3
+ export const DialogService = new InternalDialogService((dialogs) => {
4
+ Store.set('dialogs', dialogs);
5
+ });
package/root/vars.d.ts CHANGED
@@ -1,12 +1,9 @@
1
1
  /// <reference types="react" />
2
+ import type { DialogInstance } from '../dialog-service';
2
3
  import type { Lang } from '../types';
3
4
  import resources from '../resources.json';
4
5
  export declare const Store: import("rcl-store").Store<{
5
- dialogs: {
6
- type: any;
7
- key: string | number;
8
- props: any;
9
- }[];
6
+ dialogs: DialogInstance<any>[];
10
7
  }, "dialogs">;
11
8
  export declare const ROOT_DATA: {
12
9
  clickEvent?: {